/home/andy/git/oilshell/oil/mycpp/gc_obj.h
Line | Count | Source |
1 | | #ifndef GC_OBJ_H |
2 | | #define GC_OBJ_H |
3 | | |
4 | | // Obj::heap_tag_ values. They're odd numbers to distinguish them from vtable |
5 | | // pointers. |
6 | | // |
7 | | enum Tag { |
8 | | Forwarded = 1, // For the Cheney algorithm. |
9 | | Global = 3, // Neither copy nor scan. |
10 | | Opaque = 5, // Copy but don't scan. List<int> and Str |
11 | | FixedSize = 7, // Fixed size headers: consult field_mask_ |
12 | | Scanned = 9, // Copy AND scan for non-NULL pointers. |
13 | | }; |
14 | | |
15 | | const int kZeroMask = 0; // for types with no pointers |
16 | | // no obj_len_ computed for global List/Slab/Dict |
17 | | const int kNoObjLen = 0x0eadbeef; |
18 | | |
19 | | // Why do we need this macro instead of using inheritance? |
20 | | // - Because ASDL uses multiple inheritance for first class variants, but we |
21 | | // don't want multiple IMPLEMENTATION inheritance. Instead we just generate |
22 | | // compatible layouts. |
23 | | // - Similarly, GlobalStr is layout-compatible with Str. It can't inherit from |
24 | | // Obj like Str, because of the constexpr issue with char[N]. |
25 | | |
26 | | // heap_tag_: one of Tag:: |
27 | | // type_tag_: ASDL tag (variant) |
28 | | // field_mask_: for fixed length records, so max 16 fields |
29 | | // obj_len_: number of bytes to copy |
30 | | // TODO: with a limitation of ~15 fields, we can encode obj_len_ in |
31 | | // field_mask_, and save space on many ASDL types. |
32 | | // And we can sort integers BEFORE pointers. |
33 | | |
34 | | // TODO: ./configure could detect big or little endian, and then flip the |
35 | | // fields in OBJ_HEADER? |
36 | | // |
37 | | // https://stackoverflow.com/questions/2100331/c-macro-definition-to-determine-big-endian-or-little-endian-machine |
38 | | // |
39 | | // Because we want to do (obj->heap_tag_ & 1 == 0) to distinguish it from |
40 | | // vtable pointer. We assume low bits of a pointer are 0 but not high bits. |
41 | | |
42 | | #define OBJ_HEADER() \ |
43 | | uint8_t heap_tag_; \ |
44 | | uint8_t type_tag_; \ |
45 | | uint16_t field_mask_; \ |
46 | | uint32_t obj_len_; |
47 | | |
48 | | class Obj { |
49 | | // The unit of garbage collection. It has a header describing how to find |
50 | | // the pointers within it. |
51 | | // |
52 | | // Note: Sorting ASDL fields by (non-pointer, pointer) is a good idea, but it |
53 | | // breaks down because mycpp has inheritance. Could do this later. |
54 | | |
55 | | public: |
56 | | // Note: ASDL types are layout-compatible with Obj, but don't actually |
57 | | // inherit from it because of the 'multiple inheritance of implementation' |
58 | | // issue. So they don't call this constructor. |
59 | | constexpr Obj(uint8_t heap_tag, uint16_t field_mask, int obj_len) |
60 | | : heap_tag_(heap_tag), |
61 | | type_tag_(0), |
62 | | field_mask_(field_mask), |
63 | 4.20k | obj_len_(obj_len) { |
64 | 4.20k | } |
65 | | |
66 | 2.90k | void SetObjLen(int obj_len) { |
67 | 2.90k | this->obj_len_ = obj_len; |
68 | 2.90k | } |
69 | | |
70 | | OBJ_HEADER() |
71 | | |
72 | | DISALLOW_COPY_AND_ASSIGN(Obj) |
73 | | }; |
74 | | |
75 | | // |
76 | | // Compile-time computation of GC field masks. |
77 | | // |
78 | | |
79 | | class _DummyObj { // For maskbit() |
80 | | public: |
81 | | OBJ_HEADER() |
82 | | int first_field_; |
83 | | }; |
84 | | |
85 | 574 | constexpr int maskbit(int offset) { |
86 | 574 | return 1 << ((offset - offsetof(_DummyObj, first_field_)) / sizeof(void*)); |
87 | 574 | } |
88 | | |
89 | | class _DummyObj_v { // For maskbit_v() |
90 | | public: |
91 | | void* vtable; // how the compiler does dynamic dispatch |
92 | | OBJ_HEADER() |
93 | | int first_field_; |
94 | | }; |
95 | | |
96 | 1 | constexpr int maskbit_v(int offset) { |
97 | 1 | return 1 << ((offset - offsetof(_DummyObj_v, first_field_)) / sizeof(void*)); |
98 | 1 | } |
99 | | |
100 | 47 | inline Obj* ObjHeader(Obj* obj) { |
101 | | // If we see a vtable pointer, return the Obj* header immediately following. |
102 | | // Otherwise just return Obj itself. |
103 | 47 | return (obj->heap_tag_ & 0x1) == 0 |
104 | 47 | ? reinterpret_cast<Obj*>(reinterpret_cast<char*>(obj) + |
105 | 1 | sizeof(void*)) |
106 | 47 | : obj; |
107 | 47 | } |
108 | | |
109 | | #endif |