void VariableScope::Info::visit(Object* obj, ObjectVisitor& visit) { auto_visit(obj, visit); VariableScope* vs = as<VariableScope>(obj); if(!vs->isolated()) { Object** ary = vs->stack_locals(); if(Fiber* fib = try_as<Fiber>(vs->fiber())) { FiberData* data = fib->data(); AddressDisplacement dis(data->data_offset(), data->data_lower_bound(), data->data_upper_bound()); ary = dis.displace(ary); } size_t locals = vs->number_of_locals(); for(size_t i = 0; i < locals; i++) { visit.call(ary[i]); } } }
void VariableScope::Info::mark(Object* obj, ObjectMark& mark) { auto_mark(obj, mark); VariableScope* vs = as<VariableScope>(obj); if(!vs->isolated()) { Object** ary = vs->locals_; if(Fiber* fib = try_as<Fiber>(vs->fiber())) { FiberData* data = fib->data(); if(data) { AddressDisplacement dis(data->data_offset(), data->data_lower_bound(), data->data_upper_bound()); ary = dis.displace(ary); } } size_t locals = vs->number_of_locals(); for(size_t i = 0; i < locals; i++) { if(Object* tmp = mark.call(ary[i])) { ary[i] = tmp; } } } }
void GarbageCollector::visit_variable_scope(CallFrame* call_frame, StackVariables* scope, ObjectVisitor& visit) { scope->self_ = visit.call(scope->self()); scope->block_ = visit.call(scope->block()); scope->module_ = (Module*)visit.call(scope->module()); int locals = call_frame->cm->backend_method()->number_of_locals; for(int i = 0; i < locals; i++) { Object* local = scope->get_local(i); if(local->reference_p()) { scope->set_local(i, visit.call(local)); } } VariableScope* parent = scope->parent(); if(parent && parent->reference_p()) { scope->parent_ = ((VariableScope*)visit.call(parent)); } VariableScope* on_heap = scope->on_heap(); if(on_heap) { scope->on_heap_ = ((VariableScope*)visit.call(on_heap)); } }
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; }
void VariableScope::Info::visit(Object* obj, ObjectVisitor& visit) { auto_visit(obj, visit); VariableScope* vs = as<VariableScope>(obj); size_t locals = vs->number_of_locals(); for(size_t i = 0; i < locals; i++) { visit.call(vs->get_local(i)); } }
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; }
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; }
/** * Walks the chain of objects accessible from the specified CallFrame. */ void GarbageCollector::verify_call_frame(CallFrame* top_call_frame, AddressDisplacement* offset) { CallFrame* call_frame = top_call_frame; while(call_frame) { call_frame = displace(call_frame, offset); if(call_frame->constant_scope_) { call_frame->constant_scope_->validate(); } if(call_frame->compiled_code) { call_frame->compiled_code->validate(); } if(call_frame->compiled_code) { native_int stack_size = call_frame->compiled_code->stack_size()->to_native(); for(native_int i = 0; i < stack_size; i++) { Object* obj = call_frame->stk[i]; obj->validate(); } } VariableScope* scope = call_frame->top_scope_; if(call_frame->multiple_scopes_p() && scope && !scope->nil_p()) { scope->validate(); } if(BlockEnvironment* env = call_frame->block_env()) { env->validate(); } Arguments* args = displace(call_frame->arguments, offset); if(!call_frame->inline_method_p() && args) { args->recv()->validate(); args->block()->validate(); Object** ary = displace(args->arguments(), offset); for(uint32_t i = 0; i < args->total(); i++) { ary[i]->validate(); } } if(call_frame->scope && call_frame->compiled_code) { verify_variable_scope(call_frame, displace(call_frame->scope, offset)); } call_frame = call_frame->previous; } }
void VariableScope::Info::visit(Object* obj, ObjectVisitor& visit) { auto_visit(obj, visit); VariableScope* vs = as<VariableScope>(obj); if(!vs->isolated()) { Object** ary = vs->stack_locals(); size_t locals = vs->number_of_locals(); for(size_t i = 0; i < locals; i++) { visit.call(ary[i]); } } }
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); }
void VariableScope::Info::mark(Object* obj, ObjectMark& mark) { auto_mark(obj, mark); VariableScope* vs = as<VariableScope>(obj); vs->fixup(); Object* tmp; size_t locals = vs->number_of_locals(); for(size_t i = 0; i < locals; i++) { tmp = mark.call(vs->get_local(i)); if(tmp) vs->set_local(mark.state(), i, tmp); } }
Module* module() { if(multiple_scopes_p()) { return top_scope_->module(); } else { return scope->module(); } }
std::string DocumentImpl::vardump( VariableScope& vscope) { std::ostringstream rt; VariableScope::const_iterator vi = vscope.begin(), ve = vscope.end(); while (vi != ve) { if (vi != vscope.begin()) { rt << ", "; } rt << variableName( vi->first) << " = '" << vscope.getValue( vi->second) << "'"; ++vi; } return rt.str(); }
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; }
Symbol* original_name() { if(multiple_scopes_p()) { if(block_as_method_p()) return cm->name(); return top_scope_->method()->name(); } return cm->name(); }
void VariableScope::Info::mark(Object* obj, memory::ObjectMark& mark) { auto_mark(obj, mark); VariableScope* vs = as<VariableScope>(obj); if(!vs->isolated_p()) { Object** ary = vs->locals(); size_t locals = vs->number_of_locals(); for(size_t i = 0; i < locals; i++) { if(Object* tmp = mark.call(ary[i])) { ary[i] = tmp; } } } }
Object* rbx_zsuper_send(STATE, CallFrame* call_frame, Symbol* name, Object* block) { Object* const recv = call_frame->self(); VariableScope* scope = call_frame->method_scope(state); assert(scope); VMMethod* v = scope->method()->backend_method(); Object* splat_obj = 0; Array* splat = 0; size_t arg_count = v->total_args; if(v->splat_position >= 0) { splat_obj = scope->get_local(state, v->splat_position); splat = try_as<Array>(splat_obj); if(splat) { arg_count += splat->size(); } else { arg_count++; } } Tuple* tup = Tuple::create(state, arg_count); for(int i = 0; i < v->total_args; i++) { tup->put(state, i, scope->get_local(state, i)); } if(splat) { for(size_t i = 0; i < splat->size(); i++) { tup->put(state, i + v->total_args, splat->get(state, i)); } } else if(splat_obj) { tup->put(state, v->total_args, splat_obj); } Arguments out_args(name, recv, block, arg_count, 0); out_args.use_tuple(tup, arg_count); LookupData lookup(recv, call_frame->module()->superclass(), G(sym_private)); Dispatch dis(name); return dis.send(state, call_frame, lookup, out_args, eSuper); }
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_; } }
Object* rbx_zsuper_send(STATE, CallFrame* call_frame, CallSite* call_site, Object* block) { Object* const recv = call_frame->self(); VariableScope* scope = call_frame->method_scope(state); assert(scope); MachineCode* v = scope->method()->machine_code(); Object* splat_obj = 0; Array* splat = 0; size_t arg_count = v->total_args; if(v->splat_position >= 0) { splat_obj = scope->get_local(state, v->splat_position); splat = try_as<Array>(splat_obj); if(splat) { arg_count += splat->size(); } else { arg_count++; } } Tuple* tup = Tuple::create_dirty(state, arg_count); for(int i = 0; i < v->total_args; i++) { tup->put(state, i, scope->get_local(state, i)); } if(splat) { for(native_int i = 0; i < splat->size(); i++) { tup->put(state, i + v->total_args, splat->get(state, i)); } } else if(splat_obj) { tup->put(state, v->total_args, splat_obj); } Arguments out_args(call_site->name(), recv, block, arg_count, 0); out_args.use_tuple(tup, arg_count); return call_site->execute(state, call_frame, out_args); }
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; } }
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* 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* 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; }
inline bool zsuper(STATE, CallFrame* call_frame, intptr_t literal) { Object* block = stack_pop(); Object* const recv = call_frame->self(); VariableScope* scope = call_frame->method_scope(state); interp_assert(scope); MachineCode* mc = scope->method()->machine_code(); Object* splat_obj = 0; Array* splat = 0; size_t arg_count = mc->total_args; if(mc->splat_position >= 0) { splat_obj = scope->get_local(state, mc->splat_position); splat = try_as<Array>(splat_obj); if(splat) { arg_count += splat->size(); } else { arg_count++; } } Tuple* tup = Tuple::create(state, arg_count); native_int tup_index = 0; native_int fixed_args; if(splat) { fixed_args = mc->splat_position; } else if(mc->keywords) { fixed_args = mc->total_args - 1; } else { fixed_args = mc->total_args; } for(native_int i = 0; i < fixed_args; i++) { tup->put(state, tup_index++, scope->get_local(state, i)); } if(splat) { for(native_int i = 0; i < splat->size(); i++) { tup->put(state, tup_index++, splat->get(state, i)); } } else if(splat_obj) { tup->put(state, tup_index++, splat_obj); } if(mc->post_args) { native_int post_position = mc->splat_position + 1; for(native_int i = post_position; i < post_position + mc->post_args; i++) { tup->put(state, tup_index++, scope->get_local(state, i)); } } if(mc->keywords) { native_int placeholder_position = splat_obj ? mc->total_args : mc->total_args - 1; native_int keywords_position = placeholder_position + 1; Object* placeholder = scope->get_local(state, placeholder_position); Array* ary = Array::create(state, 2); for(native_int i = keywords_position; i <= mc->keywords_count; i++) { ary->set(state, 0, as<Symbol>(call_frame->compiled_code->local_names()->at(state, i))); ary->set(state, 1, scope->get_local(state, i)); placeholder->send(state, state->symbol("[]="), ary); } tup->put(state, tup_index++, scope->get_local(state, placeholder_position)); } CallSite* call_site = reinterpret_cast<CallSite*>(literal); Arguments new_args(call_site->name(), recv, block, arg_count, 0); new_args.use_tuple(tup, arg_count); Object* ret; Symbol* current_name = call_frame->original_name(); if(call_site->name() != current_name) { call_site->name(state, current_name); } ret = call_site->execute(state, new_args); state->vm()->checkpoint(state); CHECK_AND_PUSH(ret); }
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* 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; }