| |||
|
|
Symta Rewrite Progress typedef struct { //object's header inside the managed heap uint16_t tag_obsolete; //type tag uint16_t age_obsolete; //heap generation age uint32_t size; //size of the object (not counting this header) void *code; //point's to the closure's machine code or entity's id //during gc if age=GC_MOVED, //it points to the object's new location } __attribute__((packed)) gc_head_t; The two obsolete fields are already unused. Yet I still keep them until I merge size and code into a single 8-byte value. Because the heap and gc code deals only with 8-byte aligned units. How I got rid of these? Well, originally I used raw pointers inside the heap. But that was super inefficient, cuz all pointers were going into the heap. So I replaced the pointers with 30-bit alloc-unit indices. The 1,073,741,824 objects are more than enough! Now I have enough space for 30-bit tags, which are mandatory for entities. The gc_head_t's tag is constant inside a single GC cycle. So I can move it into the tag space I just freed for entities. What about age? Well, due I implement inter-generational references using page table. Every page can be dirty or clean. Now since each generation is page aligned. Therefore I can add a few `age` bits to that table. Woohoo! No longer need to maintain the per-object age. What about size? Well, code is a pointer too... And we can be replaced pointers with indices. These indices can be stored inside the tag space. Now I'm left with the size only. Most arrays and closures are small enough. So we can push the size into the tag space. Voila! Now need for gc_head_t or an allocation at all. What else? Well a CONS pair can be packed too.. inside a single 64-bit array. When the values are less than or equal to 30bits. Why I haven't done that initially? Well, I was a different person, blind to that. Dumb and poisoned with testosterone. So I wrote crappy code, wasting 16 bytes to hold 8-byte object. |
||||||||||||||||