6 void factor_vm::check_frame(stack_frame *frame)
9 check_code_pointer((cell)frame->entry_point);
10 assert(frame->size != 0);
14 callstack *factor_vm::allot_callstack(cell size)
16 callstack *stack = allot<callstack>(callstack_object_size(size));
17 stack->length = tag_fixnum(size);
21 // XXX move somewhere more appropriate
22 struct entry_point_finder {
24 cell found_entry_point;
26 entry_point_finder(cell address)
27 : address(address), found_entry_point(0) {}
29 // XXX keep a map of code blocks in the code heap so we don't need this
30 void operator()(code_block *block, cell size)
32 if ((cell)block->entry_point() <= address
33 && address - (cell)block->entry_point() < block->size())
35 assert(found_entry_point == 0);
36 found_entry_point = (cell)block->entry_point();
41 static cell find_entry_point_for_address(factor_vm *vm, cell pc)
43 std::cout << "seeking " << std::hex << pc << std::endl;
44 entry_point_finder finder(pc);
45 vm->code->allocator->iterate(finder);
46 assert(finder.found_entry_point != 0);
47 return finder.found_entry_point;
50 void factor_vm::dispatch_signal_handler(cell *sp, cell *pc, cell handler)
52 if (!code->seg->in_segment_p(*pc) || *sp < ctx->callstack_seg->start + stack_reserved)
54 /* Fault came from foreign code, a callstack overflow, or we would probably
55 overflow if we tried the resumable handler. We can't resume, so cut the
56 callstack down to the shallowest Factor stack frame that leaves room for
57 the signal handler to do its thing and launch the handler without going
58 through the resumable subprimitive. */
59 signal_resumable = false;
60 stack_frame *frame = ctx->callstack_bottom - 1;
62 while((cell)frame >= *sp
63 && frame >= ctx->callstack_top
64 && (cell)frame >= ctx->callstack_seg->start + stack_reserved)
66 frame = frame_successor(frame);
69 // XXX FRAME_RETURN_ADDRESS
70 cell newsp = (cell)(frame+1);
72 ctx->callstack_top = (stack_frame*)newsp;
75 signal_resumable = true;
76 // Fault came from Factor, and we've got a good callstack. Route the signal
77 // handler through the resumable signal handler subprimitive.
78 cell offset = *sp % 16;
80 signal_handler_addr = handler;
81 tagged<word> handler_word = tagged<word>(special_objects[SIGNAL_HANDLER_WORD]);
83 /* XXX horribly x86-centric */
84 /* True stack frames are always 16-byte aligned. Leaf procedures
85 that don't create a stack frame will be out of alignment by sizeof(cell)
87 /* On architectures with a link register we would have to check for leafness
88 by matching the PC to a word. We should also use FRAME_RETURN_ADDRESS instead
89 of assuming the stack pointer is the right place to put the resume address. */
92 cell newsp = *sp - sizeof(cell);
96 else if (offset == 16 - sizeof(cell))
98 // Make a fake frame for the leaf procedure
99 cell leaf_word = find_entry_point_for_address(this, *pc);
101 // XXX get platform-appropriate stack frame size
102 cell newsp = *sp - 32;
103 *(cell*)(newsp + 32 - sizeof(cell)) = 32;
104 *(cell*)(newsp + 32 - 2*sizeof(cell)) = leaf_word;
105 *(cell*) newsp = *pc;
107 handler_word = tagged<word>(special_objects[LEAF_SIGNAL_HANDLER_WORD]);
111 fatal_error("Invalid stack frame during signal handler", *sp);
114 *pc = (cell)handler_word->code->entry_point();
118 /* We ignore the two topmost frames, the 'callstack' primitive
119 frame itself, and the frame calling the 'callstack' primitive,
120 so that set-callstack doesn't get stuck in an infinite loop.
122 This means that if 'callstack' is called in tail position, we
123 will have popped a necessary frame... however this word is only
124 called by continuation implementation, and user code shouldn't
125 be calling it at all, so we leave it as it is for now. */
126 stack_frame *factor_vm::second_from_top_stack_frame(context *ctx)
128 stack_frame *frame = ctx->callstack_bottom - 1;
129 while(frame >= ctx->callstack_top
130 && frame_successor(frame) >= ctx->callstack_top
131 && frame_successor(frame_successor(frame)) >= ctx->callstack_top)
133 frame = frame_successor(frame);
138 cell factor_vm::capture_callstack(context *ctx)
140 stack_frame *top = second_from_top_stack_frame(ctx);
141 stack_frame *bottom = ctx->callstack_bottom;
143 fixnum size = std::max((fixnum)0,(fixnum)bottom - (fixnum)top);
145 callstack *stack = allot_callstack(size);
146 memcpy(stack->top(),top,size);
147 return tag<callstack>(stack);
150 void factor_vm::primitive_callstack()
152 ctx->push(capture_callstack(ctx));
155 void factor_vm::primitive_callstack_for()
157 context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
158 ctx->push(capture_callstack(other_ctx));
161 code_block *factor_vm::frame_code(stack_frame *frame)
164 return (code_block *)frame->entry_point - 1;
167 code_block_type factor_vm::frame_type(stack_frame *frame)
169 return frame_code(frame)->type();
172 cell factor_vm::frame_executing(stack_frame *frame)
174 return frame_code(frame)->owner;
177 cell factor_vm::frame_executing_quot(stack_frame *frame)
179 tagged<object> executing(frame_executing(frame));
180 code_block *compiled = frame_code(frame);
181 if(!compiled->optimized_p() && executing->type() == WORD_TYPE)
182 executing = executing.as<word>()->def;
183 return executing.value();
186 stack_frame *factor_vm::frame_successor(stack_frame *frame)
189 return (stack_frame *)((cell)frame - frame->size);
192 cell factor_vm::frame_offset(stack_frame *frame)
194 char *entry_point = (char *)frame_code(frame)->entry_point();
195 char *return_address = (char *)FRAME_RETURN_ADDRESS(frame,this);
197 return return_address - entry_point;
202 void factor_vm::set_frame_offset(stack_frame *frame, cell offset)
204 char *entry_point = (char *)frame_code(frame)->entry_point();
205 if(offset == (cell)-1)
206 FRAME_RETURN_ADDRESS(frame,this) = NULL;
208 FRAME_RETURN_ADDRESS(frame,this) = entry_point + offset;
211 cell factor_vm::frame_scan(stack_frame *frame)
213 switch(frame_type(frame))
215 case code_block_unoptimized:
217 tagged<object> obj(frame_executing(frame));
218 if(obj.type_p(WORD_TYPE))
219 obj = obj.as<word>()->def;
221 if(obj.type_p(QUOTATION_TYPE))
222 return tag_fixnum(quot_code_offset_to_scan(obj.value(),frame_offset(frame)));
226 case code_block_optimized:
229 critical_error("Bad frame type",frame_type(frame));
234 struct stack_frame_accumulator {
236 growable_array frames;
238 explicit stack_frame_accumulator(factor_vm *parent_) : parent(parent_), frames(parent_) {}
240 void operator()(stack_frame *frame)
242 data_root<object> executing_quot(parent->frame_executing_quot(frame),parent);
243 data_root<object> executing(parent->frame_executing(frame),parent);
244 data_root<object> scan(parent->frame_scan(frame),parent);
246 frames.add(executing.value());
247 frames.add(executing_quot.value());
248 frames.add(scan.value());
252 void factor_vm::primitive_callstack_to_array()
254 data_root<callstack> callstack(ctx->pop(),this);
256 stack_frame_accumulator accum(this);
257 iterate_callstack_object(callstack.untagged(),accum);
260 ctx->push(accum.frames.elements.value());
263 stack_frame *factor_vm::innermost_stack_frame(stack_frame *bottom, stack_frame *top)
265 stack_frame *frame = bottom - 1;
267 while(frame >= top && frame_successor(frame) >= top)
268 frame = frame_successor(frame);
273 /* Some primitives implementing a limited form of callstack mutation.
274 Used by the single stepper. */
275 void factor_vm::primitive_innermost_stack_frame_executing()
277 callstack *stack = untag_check<callstack>(ctx->pop());
278 stack_frame *frame = innermost_stack_frame(stack->bottom(), stack->top());
279 ctx->push(frame_executing_quot(frame));
282 void factor_vm::primitive_innermost_stack_frame_scan()
284 callstack *stack = untag_check<callstack>(ctx->pop());
285 stack_frame *frame = innermost_stack_frame(stack->bottom(), stack->top());
286 ctx->push(frame_scan(frame));
289 void factor_vm::primitive_set_innermost_stack_frame_quot()
291 data_root<callstack> stack(ctx->pop(),this);
292 data_root<quotation> quot(ctx->pop(),this);
294 stack.untag_check(this);
295 quot.untag_check(this);
297 jit_compile_quot(quot.value(),true);
299 stack_frame *inner = innermost_stack_frame(stack->bottom(), stack->top());
300 cell offset = frame_offset(inner);
301 inner->entry_point = quot->entry_point;
302 set_frame_offset(inner,offset);
305 void factor_vm::primitive_callstack_bounds()
307 ctx->push(allot_alien((void*)ctx->callstack_seg->start));
308 ctx->push(allot_alien((void*)ctx->callstack_seg->end));