gc_api.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef TOOLS_CLANG_STACK_MAPS_GC_GC_API_H_
  5. #define TOOLS_CLANG_STACK_MAPS_GC_GC_API_H_
  6. #include <assert.h>
  7. #include <map>
  8. #include <vector>
  9. #include "objects.h"
  10. using ReturnAddress = uint64_t;
  11. using FramePtr = uintptr_t*;
  12. using RBPOffset = uint32_t;
  13. using DWARF = uint16_t;
  14. using HeapAddress = long*;
  15. // The place where HeapObjects live. For simplicity, the underlying data in a
  16. // HeapObject is always a single uintptr_t. The heap layout mocks a simple
  17. // semi-space collector where objects can be moved between two heap fragments.
  18. //
  19. // Note that this is a no-op collector: unreachable objects are not reclaimed
  20. // and allocation will keep filling the heap until its limited memory is
  21. // exhausted.
  22. class Heap {
  23. public:
  24. // Allocates a HeapObject's underlying data field on the heap and returns a
  25. // pointer to it. This allocation will use the heap fragment returned from a
  26. // fromspace() call.
  27. HeapAddress AllocRaw(long value);
  28. // Moves all values from fromspace to tospace. fromspace becomes tospace and
  29. // vice versa (i.e. future allocations take place on the opposite heap
  30. // fragment). Note no objects are dropped in the process.
  31. void MoveObjects();
  32. // For an arbitrary pointer into the heap, this will return a new pointer with
  33. // a corresponding offset into the opposite heap fragment. E.g. a pointer to
  34. // an address at offset +4 into heap fragment A would return an address at
  35. // offset +4 into heap fragment B.
  36. //
  37. // This is used for relocating root pointer values across a collection during
  38. // stack walking.
  39. HeapAddress UpdatePointer(HeapAddress ptr);
  40. private:
  41. static constexpr int kHeapSize = 24;
  42. HeapAddress fromspace() {
  43. if (alloc_on_a_) {
  44. return a_frag_;
  45. } else {
  46. return b_frag_;
  47. }
  48. }
  49. HeapAddress tospace() {
  50. if (alloc_on_a_) {
  51. return b_frag_;
  52. } else {
  53. return a_frag_;
  54. }
  55. }
  56. int heap_ptr = 0;
  57. long a_frag_[kHeapSize];
  58. long b_frag_[kHeapSize];
  59. bool alloc_on_a_ = true;
  60. };
  61. // A FrameRoots object contains all the information needed to precisely identify
  62. // live roots for a given safepoint. It contains a list of registers which are
  63. // known to contain roots, and a list of offsets from the stack pointer to known
  64. // on-stack-roots.
  65. //
  66. // Each stackmap entry in .llvm_stackmaps has two parts: a base pointer (not to
  67. // be confused with EBP), which simply points to an object header; and a derived
  68. // pointer which specifies an offset (if any) into the object's interior. In the
  69. // case where only a base object pointer is desired, the derived pointer will be
  70. // 0.
  71. //
  72. // DWARF Register number mapping can be found here:
  73. // Pg.63
  74. // https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf
  75. class FrameRoots {
  76. public:
  77. FrameRoots(std::vector<DWARF> reg_roots, std::vector<RBPOffset> stack_roots)
  78. : reg_roots_(reg_roots), stack_roots_(stack_roots) {}
  79. const std::vector<DWARF>* reg_roots() { return &reg_roots_; }
  80. const std::vector<RBPOffset>* stack_roots() { return &stack_roots_; }
  81. bool empty() { return reg_roots_.empty() && stack_roots_.empty(); }
  82. void Print() const;
  83. private:
  84. std::vector<DWARF> reg_roots_;
  85. std::vector<RBPOffset> stack_roots_;
  86. };
  87. // A SafepointTable provides a runtime mapping of function return addresses to
  88. // on-stack and in-register gc root locations. Return addresses are used as a
  89. // function call site is the only place where safepoints can exist. This map is
  90. // a convenient format for the collector to use while walking a call stack
  91. // looking for the rootset.
  92. class SafepointTable {
  93. public:
  94. SafepointTable(std::map<ReturnAddress, FrameRoots> roots)
  95. : roots_(std::move(roots)) {}
  96. const std::map<ReturnAddress, FrameRoots>* roots() { return &roots_; }
  97. void Print() const;
  98. private:
  99. const std::map<ReturnAddress, FrameRoots> roots_;
  100. };
  101. SafepointTable GenSafepointTable();
  102. extern SafepointTable spt;
  103. extern Heap* heap;
  104. // During stack scanning, the GC must know when it has reached the top of the
  105. // stack so that it can hand execution back over to the mutator. This global
  106. // variable serves that purpose - it is initialised in main to be equal to
  107. // main's RBP value, and checked against each time the gc steps up into the next
  108. // stack frame. For non-main threads this could be pthread top.
  109. extern "C" void InitTopOfStack();
  110. extern uintptr_t TopOfStack;
  111. void PrintSafepointTable();
  112. // Walks the execution stack looking for live gc roots. This function should
  113. // never be called directly. Instead, the void |GC| function should be
  114. // called. |GC| is an assembly shim which jumps to this function after
  115. // placing the value of RBP in RDI (First arg slot mandated by Sys V ABI).
  116. //
  117. // Stack walking starts from the address in `fp` (assumed to be RBP's
  118. // address). The stack is traversed from bottom to top until the frame pointer
  119. // hits a terminal value (usually main's RBP value).
  120. //
  121. // This works by assuming the calling convention for each frame adheres to the
  122. // Sys V ABI, where the frame pointer is known to point to the address of last
  123. // saved frame pointer (and so on), creating a linked list of frames on the
  124. // stack (shown below).
  125. //
  126. // +--------------------+
  127. // | ... |
  128. // +--------------------+
  129. // | Saved RBP |<--+
  130. // +--------------------+ |
  131. // | | |
  132. // | ... | |
  133. // | | |
  134. // +--------------------+ |
  135. // | Return Address | |
  136. // +--------------------+ |
  137. // RBP--> | Saved RBP |---+
  138. // +--------------------+
  139. // | |
  140. // | Args |
  141. // | |
  142. // +--------------------+
  143. //
  144. // This therefore requires that the optimisation -fomit-frame-pointer is
  145. // disabled in order to guarantee that RBP will not be used as a
  146. // general-purpose register.
  147. extern "C" void StackWalkAndMoveObjects(FramePtr fp);
  148. // A very simple allocator for a HeapObject. For the purposes of this
  149. // experiment, a HeapObject's contents is simply a 64 bit integer. The data
  150. // itself is not important, what is, however, is that it can be accessed through
  151. // the rootset after the collector moves it.
  152. Handle<HeapObject> AllocateHeapObject(HeapAddress data);
  153. #endif // TOOLS_CLANG_STACK_MAPS_GC_GC_API_H_