123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef TOOLS_CLANG_STACK_MAPS_GC_GC_API_H_
- #define TOOLS_CLANG_STACK_MAPS_GC_GC_API_H_
- #include <assert.h>
- #include <map>
- #include <vector>
- #include "objects.h"
- using ReturnAddress = uint64_t;
- using FramePtr = uintptr_t*;
- using RBPOffset = uint32_t;
- using DWARF = uint16_t;
- using HeapAddress = long*;
- // The place where HeapObjects live. For simplicity, the underlying data in a
- // HeapObject is always a single uintptr_t. The heap layout mocks a simple
- // semi-space collector where objects can be moved between two heap fragments.
- //
- // Note that this is a no-op collector: unreachable objects are not reclaimed
- // and allocation will keep filling the heap until its limited memory is
- // exhausted.
- class Heap {
- public:
- // Allocates a HeapObject's underlying data field on the heap and returns a
- // pointer to it. This allocation will use the heap fragment returned from a
- // fromspace() call.
- HeapAddress AllocRaw(long value);
- // Moves all values from fromspace to tospace. fromspace becomes tospace and
- // vice versa (i.e. future allocations take place on the opposite heap
- // fragment). Note no objects are dropped in the process.
- void MoveObjects();
- // For an arbitrary pointer into the heap, this will return a new pointer with
- // a corresponding offset into the opposite heap fragment. E.g. a pointer to
- // an address at offset +4 into heap fragment A would return an address at
- // offset +4 into heap fragment B.
- //
- // This is used for relocating root pointer values across a collection during
- // stack walking.
- HeapAddress UpdatePointer(HeapAddress ptr);
- private:
- static constexpr int kHeapSize = 24;
- HeapAddress fromspace() {
- if (alloc_on_a_) {
- return a_frag_;
- } else {
- return b_frag_;
- }
- }
- HeapAddress tospace() {
- if (alloc_on_a_) {
- return b_frag_;
- } else {
- return a_frag_;
- }
- }
- int heap_ptr = 0;
- long a_frag_[kHeapSize];
- long b_frag_[kHeapSize];
- bool alloc_on_a_ = true;
- };
- // A FrameRoots object contains all the information needed to precisely identify
- // live roots for a given safepoint. It contains a list of registers which are
- // known to contain roots, and a list of offsets from the stack pointer to known
- // on-stack-roots.
- //
- // Each stackmap entry in .llvm_stackmaps has two parts: a base pointer (not to
- // be confused with EBP), which simply points to an object header; and a derived
- // pointer which specifies an offset (if any) into the object's interior. In the
- // case where only a base object pointer is desired, the derived pointer will be
- // 0.
- //
- // DWARF Register number mapping can be found here:
- // Pg.63
- // https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf
- class FrameRoots {
- public:
- FrameRoots(std::vector<DWARF> reg_roots, std::vector<RBPOffset> stack_roots)
- : reg_roots_(reg_roots), stack_roots_(stack_roots) {}
- const std::vector<DWARF>* reg_roots() { return ®_roots_; }
- const std::vector<RBPOffset>* stack_roots() { return &stack_roots_; }
- bool empty() { return reg_roots_.empty() && stack_roots_.empty(); }
- void Print() const;
- private:
- std::vector<DWARF> reg_roots_;
- std::vector<RBPOffset> stack_roots_;
- };
- // A SafepointTable provides a runtime mapping of function return addresses to
- // on-stack and in-register gc root locations. Return addresses are used as a
- // function call site is the only place where safepoints can exist. This map is
- // a convenient format for the collector to use while walking a call stack
- // looking for the rootset.
- class SafepointTable {
- public:
- SafepointTable(std::map<ReturnAddress, FrameRoots> roots)
- : roots_(std::move(roots)) {}
- const std::map<ReturnAddress, FrameRoots>* roots() { return &roots_; }
- void Print() const;
- private:
- const std::map<ReturnAddress, FrameRoots> roots_;
- };
- SafepointTable GenSafepointTable();
- extern SafepointTable spt;
- extern Heap* heap;
- // During stack scanning, the GC must know when it has reached the top of the
- // stack so that it can hand execution back over to the mutator. This global
- // variable serves that purpose - it is initialised in main to be equal to
- // main's RBP value, and checked against each time the gc steps up into the next
- // stack frame. For non-main threads this could be pthread top.
- extern "C" void InitTopOfStack();
- extern uintptr_t TopOfStack;
- void PrintSafepointTable();
- // Walks the execution stack looking for live gc roots. This function should
- // never be called directly. Instead, the void |GC| function should be
- // called. |GC| is an assembly shim which jumps to this function after
- // placing the value of RBP in RDI (First arg slot mandated by Sys V ABI).
- //
- // Stack walking starts from the address in `fp` (assumed to be RBP's
- // address). The stack is traversed from bottom to top until the frame pointer
- // hits a terminal value (usually main's RBP value).
- //
- // This works by assuming the calling convention for each frame adheres to the
- // Sys V ABI, where the frame pointer is known to point to the address of last
- // saved frame pointer (and so on), creating a linked list of frames on the
- // stack (shown below).
- //
- // +--------------------+
- // | ... |
- // +--------------------+
- // | Saved RBP |<--+
- // +--------------------+ |
- // | | |
- // | ... | |
- // | | |
- // +--------------------+ |
- // | Return Address | |
- // +--------------------+ |
- // RBP--> | Saved RBP |---+
- // +--------------------+
- // | |
- // | Args |
- // | |
- // +--------------------+
- //
- // This therefore requires that the optimisation -fomit-frame-pointer is
- // disabled in order to guarantee that RBP will not be used as a
- // general-purpose register.
- extern "C" void StackWalkAndMoveObjects(FramePtr fp);
- // A very simple allocator for a HeapObject. For the purposes of this
- // experiment, a HeapObject's contents is simply a 64 bit integer. The data
- // itself is not important, what is, however, is that it can be accessed through
- // the rootset after the collector moves it.
- Handle<HeapObject> AllocateHeapObject(HeapAddress data);
- #endif // TOOLS_CLANG_STACK_MAPS_GC_GC_API_H_
|