]> gitweb.factorcode.org Git - factor.git/blob - vm/callstack.cpp
VM: move the frame_predecessor() method to the code_heap class
[factor.git] / vm / callstack.cpp
1 #include "master.hpp"
2
3 namespace factor {
4
5 /* Allocates memory (allot) */
6 callstack* factor_vm::allot_callstack(cell size) {
7   callstack* stack = allot<callstack>(callstack_object_size(size));
8   stack->length = tag_fixnum(size);
9   return stack;
10 }
11
12 /* We ignore the two topmost frames, the 'callstack' primitive
13 frame itself, and the frame calling the 'callstack' primitive,
14 so that set-callstack doesn't get stuck in an infinite loop.
15
16 This means that if 'callstack' is called in tail position, we
17 will have popped a necessary frame... however this word is only
18 called by continuation implementation, and user code shouldn't
19 be calling it at all, so we leave it as it is for now. */
20 cell factor_vm::second_from_top_stack_frame(context* ctx) {
21   cell frame_top = ctx->callstack_top;
22   for (cell i = 0; i < 2; ++i) {
23     cell pred = code->frame_predecessor(frame_top);
24     if (pred >= ctx->callstack_bottom)
25       return frame_top;
26     frame_top = pred;
27   }
28   return frame_top;
29 }
30
31 /* Allocates memory (allot_callstack) */
32 cell factor_vm::capture_callstack(context* ctx) {
33   cell top = second_from_top_stack_frame(ctx);
34   cell bottom = ctx->callstack_bottom;
35
36   fixnum size = std::max((cell)0, bottom - top);
37
38   callstack* stack = allot_callstack(size);
39   memcpy(stack->top(), (void *)top, size);
40   return tag<callstack>(stack);
41 }
42
43 /* Allocates memory (capture_callstack) */
44 void factor_vm::primitive_callstack() { ctx->push(capture_callstack(ctx)); }
45
46 /* Allocates memory (capture_callstack) */
47 void factor_vm::primitive_callstack_for() {
48   context* other_ctx = (context*)pinned_alien_offset(ctx->peek());
49   ctx->replace(capture_callstack(other_ctx));
50 }
51
52 struct stack_frame_in_array {
53   cell cells[3];
54 };
55
56 /* Allocates memory (frames.trim()), iterate_callstack_object() */
57 void factor_vm::primitive_callstack_to_array() {
58   data_root<callstack> callstack(ctx->peek(), this);
59   /* Allocates memory here. */
60   growable_array frames(this);
61
62   auto stack_frame_accumulator = [&](cell frame_top,
63                                      cell size,
64                                      code_block* owner,
65                                      cell addr) {
66     data_root<object> executing_quot(owner->owner_quot(), this);
67     data_root<object> executing(owner->owner, this);
68     data_root<object> scan(owner->scan(this, addr), this);
69
70     frames.add(executing.value());
71     frames.add(executing_quot.value());
72     frames.add(scan.value());
73   };
74   iterate_callstack_object(callstack.untagged(), stack_frame_accumulator);
75
76   /* The callstack iterator visits frames in reverse order (top to bottom) */
77   std::reverse((stack_frame_in_array*)frames.elements->data(),
78                (stack_frame_in_array*)(frames.elements->data() +
79                                        frames.count));
80   frames.trim();
81
82   ctx->replace(frames.elements.value());
83 }
84
85 /* Some primitives implementing a limited form of callstack mutation.
86 Used by the single stepper. */
87 void factor_vm::primitive_innermost_stack_frame_executing() {
88   callstack* stack = untag_check<callstack>(ctx->peek());
89   void* frame = stack->top();
90   cell addr = *(cell*)frame;
91   ctx->replace(code->code_block_for_address(addr)->owner_quot());
92 }
93
94 void factor_vm::primitive_innermost_stack_frame_scan() {
95   callstack* stack = untag_check<callstack>(ctx->peek());
96   void* frame = stack->top();
97   cell addr = *(cell*)frame;
98   ctx->replace(code->code_block_for_address(addr)->scan(this, addr));
99 }
100
101 /* Allocates memory (jit_compile_quotation) */
102 void factor_vm::primitive_set_innermost_stack_frame_quotation() {
103   data_root<callstack> stack(ctx->pop(), this);
104   data_root<quotation> quot(ctx->pop(), this);
105
106   stack.untag_check(this);
107   quot.untag_check(this);
108
109   jit_compile_quotation(quot.value(), true);
110
111   void* inner = stack->top();
112   cell addr = *(cell*)inner;
113   code_block* block = code->code_block_for_address(addr);
114   cell offset = block->offset(addr);
115   *(cell*)inner = quot->entry_point + offset;
116 }
117
118 /* Allocates memory (allot_alien) */
119 void factor_vm::primitive_callstack_bounds() {
120   ctx->push(allot_alien((void*)ctx->callstack_seg->start));
121   ctx->push(allot_alien((void*)ctx->callstack_seg->end));
122 }
123
124 }