]> gitweb.factorcode.org Git - factor.git/blob - vm/code_blocks.hpp
scryfall: make decks better, import from moxfield
[factor.git] / vm / code_blocks.hpp
1 namespace factor {
2
3 // The compiled code heap is structured into blocks.
4 struct code_block {
5   // header format (bits indexed with least significant as zero):
6   // bit   0  : free?
7   // bits  1-2: type (as a code_block_type)
8   // if not free:
9   //   bits  3-23: code size / 8
10   //   bits 24-31: stack frame size / 16
11   // if free:
12   //   bits  3-end: code size / 8
13   cell header;
14   cell owner;      // tagged pointer to word, quotation or f
15   cell parameters; // tagged pointer to array or f
16   cell relocation; // tagged pointer to byte-array or f
17
18   bool free_p() const { return (header & 1) == 1; }
19
20   code_block_type type() const {
21     return (code_block_type)((header >> 1) & 0x3);
22   }
23
24   void set_type(code_block_type type) {
25     header = ((header & ~0x7) | (type << 1));
26   }
27
28   bool pic_p() const { return type() == CODE_BLOCK_PIC; }
29
30   cell size() const {
31     cell size;
32     if (free_p())
33       size = header & ~7;
34     else
35       size = header & 0xFFFFF8;
36     FACTOR_ASSERT(size > 0);
37     return size;
38   }
39
40   cell stack_frame_size() const {
41     if (free_p())
42       return 0;
43     return (header >> 20) & 0xFF0;
44   }
45
46   cell stack_frame_size_for_address(cell addr) const {
47     cell natural_frame_size = stack_frame_size();
48     // The first instruction in a code block is the prolog safepoint,
49     // and a leaf procedure code block will record a frame size of zero.
50     // If we're seeing a stack frame in either of these cases, it's a
51     // fake "leaf frame" set up by the signal handler.
52     if (natural_frame_size == 0 || addr == entry_point())
53       return LEAF_FRAME_SIZE;
54     return natural_frame_size;
55   }
56
57   void set_stack_frame_size(cell frame_size) {
58     FACTOR_ASSERT(size() < 0xFFFFFF);
59     FACTOR_ASSERT(!free_p());
60     FACTOR_ASSERT(frame_size % 16 == 0);
61     FACTOR_ASSERT(frame_size <= 0xFF0);
62     header = (header & 0xFFFFFF) | (frame_size << 20);
63   }
64
65   template <typename Fixup> cell size(Fixup fixup) const { (void)fixup; return size(); }
66
67   cell entry_point() const { return (cell)(this + 1); }
68
69   // GC info is stored at the end of the block
70   gc_info* block_gc_info() const {
71     return (gc_info*)((uint8_t*)this + size() - sizeof(gc_info));
72   }
73
74   void flush_icache() { factor::flush_icache((cell)this, size()); }
75
76   template <typename Iterator> void each_instruction_operand(Iterator& iter) {
77     if (!to_boolean(relocation))
78       return;
79
80     byte_array* rels = untag<byte_array>(relocation);
81
82     cell index = 0;
83     cell length = untag_fixnum(rels->capacity) / sizeof(relocation_entry);
84
85     for (cell i = 0; i < length; i++) {
86       relocation_entry rel = rels->data<relocation_entry>()[i];
87       iter(instruction_operand(rel, this, index));
88       index += rel.number_of_parameters();
89     }
90   }
91
92   cell offset(cell addr) const { return addr - entry_point(); }
93
94   cell address_for_offset(cell offset) const {
95     return entry_point() + offset;
96   }
97
98   cell scan(factor_vm* vm, cell addr) const;
99   cell owner_quot() const;
100 };
101
102 VM_C_API void undefined_symbol(void);
103
104 inline code_block* word::code() const {
105   FACTOR_ASSERT(entry_point != 0);
106   return (code_block*)entry_point - 1;
107 }
108
109 inline code_block* quotation::code() const {
110   FACTOR_ASSERT(entry_point != 0);
111   return (code_block*)entry_point - 1;
112 }
113
114 }