inline bool cast_array(STATE, CallFrame* call_frame) { // Use stack_top and not stack_pop because we may need // to preserve and reread the value from the stack below. Object* t1 = stack_top(); if(t1->nil_p()) { t1 = Array::create(state, 0); } else if(Tuple* tup = try_as<Tuple>(t1)) { t1 = Array::from_tuple(state, tup); } else if(!rubinius::kind_of<Array>(t1)) { Object* recv = G(type); Arguments args(G(sym_coerce_to_array), recv, 1, &t1); Dispatch dispatch(G(sym_coerce_to_array)); Object* res = dispatch.send(state, args); // If the send still doesn't produce an array, wrap // the value in one. if(res && !rubinius::kind_of<Array>(res)) { Array* ary = Array::create(state, 1); // Don't read t1 here, it's not GC safe because we called // a method. ary->set(state, 0, stack_top()); t1 = ary; } else { t1 = res; } } (void)stack_pop(); // Remove original value CHECK_AND_PUSH(t1); }
inline bool find_const(STATE, CallFrame* call_frame, intptr_t literal) { Module* under = as<Module>(stack_pop()); ConstantCache* cache = reinterpret_cast<ConstantCache*>(literal); Object* res = cache->retrieve(state, under, call_frame->lexical_scope()); if(!res) { ConstantMissingReason reason; Symbol* sym = cache->name(); res = Helpers::const_get_under(state, under, sym, &reason); if(reason == vFound) { OnStack<3> os(state, cache, under, res); if(Autoload* autoload = try_as<Autoload>(res)) { res = autoload->resolve(state, under); } if(res) { ConstantCache* update = ConstantCache::create(state, cache, res, under, call_frame->lexical_scope()); cache->update_constant_cache(state, update); } } else { res = Helpers::const_missing_under(state, under, sym); } } CHECK_AND_PUSH(res); }
inline bool yield_splat(STATE, CallFrame* call_frame, intptr_t count) { Object* ary = stack_pop(); Object* t1 = call_frame->scope->block(); Arguments args(G(sym_call), t1, count, stack_back_position(count)); if(!ary->nil_p()) { args.append(state, as<Array>(ary)); } if(BlockEnvironment *env = try_as<BlockEnvironment>(t1)) { call_frame->return_value = env->call(state, args); } else if(Proc* proc = try_as<Proc>(t1)) { call_frame->return_value = proc->yield(state, args); } else if(t1->nil_p()) { state->raise_exception(Exception::make_lje(state)); call_frame->return_value = NULL; } else { Dispatch dispatch(G(sym_call)); call_frame->return_value = dispatch.send(state, args); } stack_clear(count); state->vm()->checkpoint(state); CHECK_AND_PUSH(call_frame->return_value); }
inline bool create_block(STATE, CallFrame* call_frame, intptr_t literal) { Object* code_or_id = reinterpret_cast<Object*>(literal); CompiledCode* code = 0; if(!(code = try_as<CompiledCode>(code_or_id))) { code = CodeDB::load(state, as<String>(code_or_id)); // TODO: instructions // store_literal(reinterpret_cast<opcode>(code)); } Object* be = BlockEnvironment::under_call_frame(state, code, call_frame->machine_code); CHECK_AND_PUSH(be); }
inline bool send_stack(STATE, CallFrame* call_frame, intptr_t literal, intptr_t count) { Object* recv = stack_back(count); CallSite* call_site = reinterpret_cast<CallSite*>(literal); Arguments args(call_site->name(), recv, cNil, count, stack_back_position(count)); stack_clear(count + 1); call_frame->return_value = call_site->execute(state, args); state->vm()->checkpoint(state); CHECK_AND_PUSH(call_frame->return_value); }
inline bool push_ivar(STATE, CallFrame* call_frame, intptr_t literal) { Symbol* sym = reinterpret_cast<Symbol*>(literal); Object* ret = call_frame->self()->get_ivar(state, sym); CHECK_AND_PUSH(ret); }
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); }