VariableScope* VariableScope::synthesize(STATE, CompiledMethod* method, Module* module, Object* parent, Object* self, Object* block, Tuple* locals) { VariableScope* scope = state->new_object<VariableScope>(G(variable_scope)); scope->block(state, block); scope->module(state, module); scope->method(state, method); if(VariableScope* vs = try_as<VariableScope>(parent)) { scope->parent(state, vs); } else { scope->parent(state, nil<VariableScope>()); } scope->heap_locals(state, locals); scope->last_match(state, cNil); scope->self(state, self); scope->number_of_locals_ = locals->num_fields(); scope->isolated_ = true; scope->locals_ = 0; scope->block_as_method_ = 0; return scope; }
VariableScope* StackVariables::create_heap_alias(STATE, CallFrame* call_frame, bool full) { if(on_heap_) return on_heap_; VMMethod* vmm = call_frame->cm->backend_method(); VariableScope* scope = state->new_struct<VariableScope>( G(variable_scope), vmm->number_of_locals * sizeof(Object*)); if(parent_) { scope->parent(state, parent_); } else { scope->parent(state, (VariableScope*)Qnil); } scope->self(state, self_); scope->block(state, block_); scope->module(state, module_); scope->method(state, call_frame->cm); scope->number_of_locals_ = vmm->number_of_locals; if(full) { scope->isolated_ = false; scope->point_locals_to(locals_); } else { scope->isolated_ = true; scope->point_locals_to(scope->heap_locals_); } on_heap_ = scope; return scope; }
inline bool push_local_depth(STATE, CallFrame* call_frame, intptr_t depth, intptr_t index) { if(depth == 0) { Exception::internal_error(state, "illegal push_local_depth usage"); return false; } else { VariableScope* scope = call_frame->scope->parent(); if(!scope || scope->nil_p()) { Exception::internal_error(state, "illegal push_local_depth usage, no parent"); return false; } for(int j = 1; j < depth; j++) { scope = scope->parent(); if(!scope || scope->nil_p()) { Exception::internal_error(state, "illegal push_local_depth usage, no parent"); return false; } } if(index >= scope->number_of_locals()) { Exception::internal_error(state, "illegal push_local_depth usage, bad index"); return false; } stack_push(scope->get_local(state, index)); return true; } }
Object* VariableScope::set_locked(STATE) { _flags_ |= CallFrame::cScopeLocked; VariableScope* parent = this->parent(); while(parent && !parent->nil_p()) { parent->set_locked(state); parent = parent->parent(); } return cNil; }
VariableScope* StackVariables::create_heap_alias(STATE, CallFrame* call_frame, bool full) { if(on_heap_) return on_heap_; MachineCode* mcode = call_frame->compiled_code->machine_code(); VariableScope* scope = state->memory()->new_object<VariableScope>(state, G(variable_scope)); if(parent_) { scope->parent(state, parent_); } else { scope->parent(state, nil<VariableScope>()); } scope->self(state, self_); scope->block(state, block_); scope->module(state, module_); scope->method(state, call_frame->compiled_code); scope->heap_locals(state, nil<Tuple>()); scope->last_match(state, last_match_); scope->fiber(state, state->vm()->thread()->current_fiber()); scope->number_of_locals(mcode->number_of_locals); scope->isolated(0); scope->flags(call_frame->flags); scope->_lock_.init(); if(!full) { scope->isolated(1); scope->heap_locals(state, Tuple::create(state, mcode->number_of_locals)); for(int i = 0; i < scope->number_of_locals(); i++) { scope->set_local(state, i, locals_[i]); } } scope->locals(locals_); scope->dynamic_locals(state, nil<LookupTable>()); on_heap_ = scope; return scope; }
Object* StackVariables::last_match(STATE) { // For closures, get back to the top of the chain and get that // last_match. if(parent_) { VariableScope* scope = parent_; while(RTEST(scope->parent())) { scope = scope->parent(); } return scope->last_match(); } // Otherwise, if this has a heap alias, get the last_match from there. if(on_heap_) { return on_heap_->last_match(); // Lastly, use the local one. This is where a last_match begins life. } else { return last_match_; } }
VariableScope* StackVariables::create_heap_alias(STATE, CallFrame* call_frame, bool full) { if(on_heap_) return on_heap_; MachineCode* mcode = call_frame->compiled_code->machine_code(); VariableScope* scope = state->new_object_dirty<VariableScope>(G(variable_scope)); if(parent_) { scope->parent(state, parent_); } else { scope->parent(state, nil<VariableScope>()); } scope->self(state, self_); scope->block(state, block_); scope->module(state, module_); scope->method(state, call_frame->compiled_code); scope->heap_locals(state, Tuple::create(state, mcode->number_of_locals)); scope->last_match(state, last_match_); scope->fiber(state, state->vm()->current_fiber.get()); scope->number_of_locals_ = mcode->number_of_locals; if(full) { scope->isolated_ = false; } else { scope->isolated_ = true; } scope->locals_ = locals_; scope->dynamic_locals(state, nil<LookupTable>()); scope->set_block_as_method(call_frame->block_as_method_p()); on_heap_ = scope; return scope; }
VariableScope* VariableScope::promote(STATE) { VariableScope* scope = state->new_struct<VariableScope>( G(variable_scope), number_of_locals_ * sizeof(Object*)); scope->block(state, block_); scope->method(state, method_); scope->module(state, module_); if(parent_) { scope->parent(state, parent_); } else { scope->parent(state, (VariableScope*)Qnil); } scope->self(state, self_); scope->number_of_locals_ = number_of_locals_; for(int i = 0; i < number_of_locals_; i++) { scope->set_local(state, i, locals_[i]); } return scope; }
VariableScope* VariableScope::synthesize(STATE, CompiledCode* method, Module* module, Object* parent, Object* self, Object* block, Tuple* locals) { VariableScope* scope = state->memory()->new_object<VariableScope>(state, G(variable_scope)); scope->block(state, block); scope->module(state, module); scope->method(state, method); if(VariableScope* vs = try_as<VariableScope>(parent)) { scope->parent(state, vs); } else { scope->parent(state, nil<VariableScope>()); } scope->heap_locals(state, locals); scope->self(state, self); scope->number_of_locals(locals->num_fields()); return scope; }
VariableScope* StackVariables::create_heap_alias(STATE, CallFrame* call_frame, bool full) { if(on_heap_) return on_heap_; VMMethod* vmm = call_frame->cm->backend_method(); VariableScope* scope = state->new_object<VariableScope>(G(variable_scope)); if(parent_) { scope->parent(state, parent_); } else { scope->parent(state, nil<VariableScope>()); } scope->self(state, self_); scope->block(state, block_); scope->module(state, module_); scope->method(state, call_frame->cm); scope->heap_locals(state, Tuple::create(state, vmm->number_of_locals)); scope->last_match(state, last_match_); scope->number_of_locals_ = vmm->number_of_locals; if(full) { scope->isolated_ = false; } else { scope->isolated_ = true; } scope->locals_ = locals_; scope->set_block_as_method(call_frame->block_as_method_p()); on_heap_ = scope; return scope; }
void StackVariables::set_last_match(STATE, Object* obj) { // For closures, get back to the top of the chain and set the // last_match there. This means that the last_match is shared // amongst all closures in a method, but thats how it's implemented // in ruby. if(parent_) { VariableScope* scope = parent_; while(RTEST(scope->parent())) { scope = scope->parent(); } return scope->last_match(state, obj); } // Use a heap alias if there is one. if(on_heap_) { on_heap_->last_match(state, obj); // Otherwise, use the local one. This is where a last_match usually // first appears. } else { last_match_ = obj; } }
VariableScope* CallFrame::method_scope(STATE) { VariableScope* current = promote_scope(state); if(!multiple_scopes_p()) return current; for(;;) { if(current->block_as_method_p()) return current; VariableScope* parent = current->parent(); if(!parent->nil_p()) { current = parent; } else { return current; } } assert("should not be here" && 0); }
VariableScope* CallFrame::method_scope(STATE) { VariableScope* current = promote_scope(state); if(!multiple_scopes_p()) return current; for(;;) { if(current->block_as_method_p()) return current; VariableScope* parent = current->parent(); if(!parent->nil_p()) { current = parent; } else { return current; } } // Shouldn't ever get here. return 0; }