void test_enter_method() { Symbol* meth = state->symbol("meth"); CompiledMethod* cm = CompiledMethod::create(state); cm->name(state, meth); state->shared.enable_profiling(state); profiler::Profiler* prof = state->profiler(); Dispatch dis(meth, G(object), cm); Arguments args; profiler::MethodEntry* me1 = new profiler::MethodEntry(state, dis, args, cm); TS_ASSERT_EQUALS(prof->methods_.size(), 1U); TS_ASSERT_EQUALS(me1->method_, prof->methods_.find(me1->method_->id())->second); dis.module = G(object)->metaclass(state); profiler::MethodEntry* me2 = new profiler::MethodEntry(state, dis, args); TS_ASSERT_EQUALS(prof->methods_.size(), 2U); TS_ASSERT_EQUALS(me2->method_, prof->methods_.find(me2->method_->id())->second); delete me1; delete me2; }
void LLVMState::compile_callframe(STATE, CompiledMethod* start, CallFrame* call_frame, int primitive) { if(config().jit_inline_debug) { if(start) { log() << "JIT: target search from " << symbol_cstr(start->name()) << "\n"; } else { log() << "JIT: target search from primitive\n"; } } CompiledMethod* candidate = find_candidate(start, call_frame); if(!candidate) { if(config().jit_inline_debug) { log() << "JIT: unable to find candidate\n"; } return; } assert(!candidate->backend_method()->parent()); if(candidate->backend_method()->call_count < 0) { if(!start) return; // Ignore it. compile this one. candidate = start; } compile_soon(state, candidate); }
void test_enter_block() { Symbol* meth = state->symbol("meth"); CompiledMethod* cm = CompiledMethod::create(state); cm->name(state, meth); Symbol* name = state->symbol("ModName"); Module* mod = Module::create(state); mod->name(state, name); state->shared.enable_profiling(state); profiler::Profiler* prof = state->profiler(); profiler::MethodEntry* me1 = new profiler::MethodEntry(state, meth, mod, cm); TS_ASSERT_EQUALS(prof->methods_.size(), 1U); TS_ASSERT_EQUALS(me1->method_, prof->methods_.find(me1->method_->id())->second); mod = G(object)->metaclass(state); profiler::MethodEntry* me2 = new profiler::MethodEntry(state, meth, mod, cm); TS_ASSERT_EQUALS(prof->methods_.size(), 2U); TS_ASSERT_EQUALS(me2->method_, prof->methods_.find(me2->method_->id())->second); delete me1; delete me2; }
void test_specialize_transforms_ivars_to_slots() { CompiledMethod* cm = CompiledMethod::create(state); Tuple* tup = Tuple::from(state, 1, state->symbol("@blah")); cm->literals(state, tup); InstructionSequence* iseq = InstructionSequence::create(state, 3); iseq->opcodes()->put(state, 0, Fixnum::from(InstructionSequence::insn_push_ivar)); iseq->opcodes()->put(state, 1, Fixnum::from(0)); iseq->opcodes()->put(state, 2, Fixnum::from(InstructionSequence::insn_push_nil)); cm->iseq(state, iseq); VMMethod* vmm = new VMMethod(state, cm); Object::Info ti(ObjectType); ti.slots[state->symbol("@blah")->index()] = 5; ti.slot_locations.resize(6); ti.slot_locations[5] = 33; vmm->specialize(state, cm, &ti); TS_ASSERT_EQUALS(vmm->total, 3U); TS_ASSERT_EQUALS(vmm->opcodes[0], static_cast<unsigned int>(InstructionSequence::insn_push_my_offset)); TS_ASSERT_EQUALS(vmm->opcodes[1], 33U); TS_ASSERT_EQUALS(vmm->opcodes[2], static_cast<unsigned int>(InstructionSequence::insn_push_nil)); }
void Compiler::compile_method(LLVMState* ls, BackgroundCompileRequest* req) { CompiledMethod* cm = req->method(); if(ls->config().jit_inline_debug) { struct timeval tv; gettimeofday(&tv, NULL); ls->log() << "JIT: compiling " << ls->enclosure_name(cm) << "#" << ls->symbol_debug_str(cm->name()) << " (" << tv.tv_sec << "." << tv.tv_usec << ")\n"; } JITMethodInfo info(ctx_, cm, cm->backend_method()); info.is_block = false; if(Class* cls = req->receiver_class()) { info.set_self_class(cls); } ctx_.set_root(&info); jit::MethodBuilder work(ls, info); work.setup(); compile_builder(ctx_, ls, info, work); }
void CompiledMethod::Info::visit(Object* obj, ObjectVisitor& visit) { auto_visit(obj, visit); visit_inliners(obj, visit); CompiledMethod* cm = as<CompiledMethod>(obj); if(!cm->backend_method_) return; VMMethod* vmm = cm->backend_method_; #ifdef ENABLE_LLVM if(cm->jit_data()) { cm->jit_data()->visit_all(visit); } for(int i = 0; i < VMMethod::cMaxSpecializations; i++) { if(vmm->specializations[i].jit_data) { vmm->specializations[i].jit_data->visit_all(visit); } } #endif for(size_t i = 0; i < vmm->inline_cache_count(); i++) { InlineCache* cache = &vmm->caches[i]; MethodCacheEntry* mce = cache->cache_; if(mce) visit.call(mce); for(int i = 0; i < cTrackedICHits; i++) { Module* mod = cache->seen_classes_[i].klass(); if(mod) visit.call(mod); } } }
void test_set_breakpoint_flags() { CompiledMethod* cm = CompiledMethod::create(state); Tuple* tup = Tuple::from(state, 1, state->symbol("@blah")); cm->literals(state, tup); InstructionSequence* iseq = InstructionSequence::create(state, 3); iseq->opcodes()->put(state, 0, Fixnum::from(InstructionSequence::insn_push_ivar)); iseq->opcodes()->put(state, 1, Fixnum::from(0)); iseq->opcodes()->put(state, 2, Fixnum::from(InstructionSequence::insn_push_nil)); cm->iseq(state, iseq); VMMethod* vmm = new VMMethod(state, cm); vmm->set_breakpoint_flags(state, 0, 1 << 24); TS_ASSERT_EQUALS(vmm->opcodes[0], (1U << 24) | static_cast<unsigned int>(InstructionSequence::insn_push_ivar)); vmm->set_breakpoint_flags(state, 0, 7 << 24); TS_ASSERT_EQUALS(vmm->opcodes[0], (7U << 24) | static_cast<unsigned int>(InstructionSequence::insn_push_ivar)); vmm->set_breakpoint_flags(state, 0, 0); TS_ASSERT_EQUALS(vmm->opcodes[0], static_cast<unsigned int>(InstructionSequence::insn_push_ivar)); vmm->set_breakpoint_flags(state, 1, 1); TS_ASSERT_EQUALS(vmm->opcodes[1], 0U); }
void CompiledMethod::Info::mark(Object* obj, ObjectMark& mark) { auto_mark(obj, mark); mark_inliners(obj, mark); CompiledMethod* cm = as<CompiledMethod>(obj); if(!cm->backend_method_) return; VMMethod* vmm = cm->backend_method_; vmm->set_mark(); Object* tmp; #ifdef ENABLE_LLVM if(cm->jit_data()) { cm->jit_data()->set_mark(); cm->jit_data()->mark_all(cm, mark); } for(int i = 0; i < VMMethod::cMaxSpecializations; i++) { if(vmm->specializations[i].jit_data) { vmm->specializations[i].jit_data->set_mark(); vmm->specializations[i].jit_data->mark_all(cm, mark); } } #endif for(size_t i = 0; i < vmm->inline_cache_count(); i++) { InlineCache* cache = &vmm->caches[i]; MethodCacheEntry* mce = cache->cache_; if(mce) { tmp = mark.call(mce); if(tmp) { cache->cache_ = (MethodCacheEntry*)tmp; mark.just_set(obj, tmp); } } if(cache->call_unit_) { tmp = mark.call(cache->call_unit_); if(tmp) { cache->call_unit_ = (CallUnit*)tmp; mark.just_set(obj, tmp); } } for(int i = 0; i < cTrackedICHits; i++) { Module* mod = cache->seen_classes_[i].klass(); if(mod) { tmp = mark.call(mod); if(tmp) { cache->seen_classes_[i].set_klass(force_as<Class>(tmp)); mark.just_set(obj, tmp); } } } } }
Object* CompiledMethod::specialized_executor(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args) { CompiledMethod* cm = as<CompiledMethod>(exec); Class* cls = args.recv()->class_object(state); int id = cls->class_id(); VMMethod* v = cm->backend_method(); executor target = v->unspecialized; for(int i = 0; i < VMMethod::cMaxSpecializations; i++) { int c_id = v->specializations[i].class_id; executor x = v->specializations[i].execute; if(c_id == id && x != 0) { target = x; break; } } // This is a bug. We should not have this setup if there are no // specializations. FIX THIS BUG! if(!target) target = v->fallback; return target(state, call_frame, exec, mod, args); }
/* This is the execute implementation used by normal Ruby code, * as opposed to Primitives or FFI functions. * It prepares a Ruby method for execution. * Here, +exec+ is a VMMethod instance accessed via the +vmm+ slot on * CompiledMethod. */ ExecuteStatus VMMethod::execute(STATE, Task* task, Message& msg) { CompiledMethod* cm = as<CompiledMethod>(msg.method); MethodContext* ctx = MethodContext::create(state, msg.recv, cm); VMMethod* vmm = cm->backend_method_; // Copy in things we all need. ctx->module(state, msg.module); ctx->name(state, msg.name); ctx->block(state, msg.block); ctx->args = msg.args(); // If argument handling fails.. GenericArguments args; if(args.call(state, vmm, ctx, msg) == false) { // Clear the values from the caller task->active()->clear_stack(msg.stack); // TODO we've got full control here, we should just raise the exception // in the runtime here rather than throwing a C++ exception and raising // it later. Exception::argument_error(state, vmm->required_args, msg.args()); // never reached! } #if 0 if(!probe_->nil_p()) { probe_->start_method(this, msg); } #endif // Clear the values from the caller task->active()->clear_stack(msg.stack); task->make_active(ctx); if(unlikely(task->profiler)) { profiler::Method* prof_meth; if(MetaClass* mc = try_as<MetaClass>(msg.module)) { Object* attached = mc->attached_instance(); if(Module* mod = try_as<Module>(attached)) { prof_meth = task->profiler->enter_method(msg.name, mod->name(), profiler::kNormal); } else { prof_meth = task->profiler->enter_method(msg.name, attached->id(state), profiler::kNormal); } } else { prof_meth = task->profiler->enter_method(msg.name, msg.module->name(), profiler::kSingleton); } if(!prof_meth->file()) { prof_meth->set_position(cm->file(), cm->start_line(state)); } } return cExecuteRestart; }
Symbol* original_name() { if(multiple_scopes_p()) { if(block_as_method_p()) return cm->name(); return top_scope_->method()->name(); } return cm->name(); }
CompiledMethod* CompiledMethod::create(STATE) { CompiledMethod* cm = state->new_object<CompiledMethod>(G(cmethod)); cm->local_count(state, Fixnum::from(0)); cm->set_executor(CompiledMethod::default_executor); cm->backend_method_ = NULL; return cm; }
Object* CompiledMethod::default_executor(STATE, CallFrame* call_frame, Dispatch& msg, Arguments& args) { CompiledMethod* cm = as<CompiledMethod>(msg.method); cm->formalize(state, false); // Refactor cm->backend_method_->find_super_instructions(); return cm->execute(state, call_frame, msg, args); }
int CompiledRFrame::cost() const { CompiledMethod* nm = top_method()->code(); if (nm != NULL) { return nm->insts_size(); } else { return top_method()->code_size(); } }
r_mint Env::method_id(rmethod meth) { CompiledMethod* cm = i(meth); if(VMMethod* vmm = cm->backend_method()) { return (vmm->method_id() << 1) | 1; } return 0; }
CompiledMethod* CompiledMethod::dup_cm(STATE) { CompiledMethod* cm = CompiledMethod::create(state); cm->copy_object(state, this); cm->set_executor(CompiledMethod::default_executor); cm->jit_data_ = NULL; cm->backend_method_ = NULL; return cm; }
frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpreted) : _sp(sp), _younger_sp(younger_sp), _deopt_state(unknown), _sp_adjustment_by_callee(0) { if (younger_sp == NULL) { // make a deficient frame which doesn't know where its PC is _pc = NULL; _cb = NULL; } else { _pc = (address)younger_sp[I7->sp_offset_in_saved_window()] + pc_return_offset; assert( (intptr_t*)younger_sp[FP->sp_offset_in_saved_window()] == (intptr_t*)((intptr_t)sp - STACK_BIAS), "younger_sp must be valid"); // Any frame we ever build should always "safe" therefore we should not have to call // find_blob_unsafe // In case of native stubs, the pc retrieved here might be // wrong. (the _last_native_pc will have the right value) // So do not put add any asserts on the _pc here. } if (_pc != NULL) _cb = CodeCache::find_blob(_pc); // Check for MethodHandle call sites. if (_cb != NULL) { CompiledMethod* nm = _cb->as_compiled_method_or_null(); if (nm != NULL) { if (nm->is_deopt_mh_entry(_pc) || nm->is_method_handle_return(_pc)) { _sp_adjustment_by_callee = (intptr_t*) ((intptr_t) sp[L7_mh_SP_save->sp_offset_in_saved_window()] + STACK_BIAS) - sp; // The SP is already adjusted by this MH call site, don't // overwrite this value with the wrong interpreter value. younger_frame_is_interpreted = false; } } } if (younger_frame_is_interpreted) { // compute adjustment to this frame's SP made by its interpreted callee _sp_adjustment_by_callee = (intptr_t*) ((intptr_t) younger_sp[I5_savedSP->sp_offset_in_saved_window()] + STACK_BIAS) - sp; } // It is important that the frame is fully constructed when we do // this lookup as get_deopt_original_pc() needs a correct value for // unextended_sp() which uses _sp_adjustment_by_callee. if (_pc != NULL) { address original_pc = CompiledMethod::get_deopt_original_pc(this); if (original_pc != NULL) { _pc = original_pc; _deopt_state = is_deoptimized; } else { _deopt_state = not_deoptimized; } } }
Object* rbx_create_block(STATE, CallFrame* call_frame, int index) { Object* _lit = call_frame->cm->literals()->at(state, index); CompiledMethod* cm = as<CompiledMethod>(_lit); // TODO: We don't need to be doing this everytime. if(cm->scope()->nil_p()) { cm->scope(state, call_frame->static_scope()); } VMMethod* vmm = call_frame->cm->backend_method(); return BlockEnvironment::under_call_frame(state, cm, vmm, call_frame, index); }
CompiledMethod* CompiledMethod::create(STATE) { CompiledMethod* cm = state->new_object<CompiledMethod>(G(cmethod)); cm->local_count(state, Fixnum::from(0)); cm->set_executor(CompiledMethod::default_executor); cm->backend_method_ = NULL; cm->inliners_ = NULL; cm->prim_index_ = -1; #ifdef ENABLE_LLVM cm->jit_data_ = NULL; #endif return cm; }
void test_create() { CompiledMethod* cm = CompiledMethod::create(state); Tuple* tup = Tuple::from(state, 1, state->symbol("blah")); cm->literals(state, tup); InstructionSequence* iseq = InstructionSequence::create(state, 1); iseq->opcodes()->put(state, 0, Fixnum::from(0)); cm->iseq(state, iseq); VMMethod* vmm = new VMMethod(state, cm); TS_ASSERT_EQUALS(vmm->total, 1U); TS_ASSERT_EQUALS(vmm->opcodes[0], 0U); }
Object* CompiledMethod::default_executor(STATE, CallFrame* call_frame, Dispatch& msg, Arguments& args) { CompiledMethod* cm = as<CompiledMethod>(msg.method); const char* reason = 0; int ip = -1; if(!cm->internalize(state, &reason, &ip)) { Exception::bytecode_error(state, call_frame, cm, ip, reason); return 0; } // Refactor cm->backend_method_->find_super_instructions(); return cm->execute(state, call_frame, msg, args); }
CallFrame* LLVMState::find_candidate(CompiledMethod* start, CallFrame* call_frame) { if(!config_.jit_inline_generic) { return call_frame; } int depth = cInlineMaxDepth; if(!start) { start = call_frame->cm; call_frame = call_frame->previous; depth--; } if(!call_frame || start->backend_method()->total > SMALL_METHOD_SIZE) { return call_frame; } CallFrame* caller = call_frame; while(depth-- > 0) { CompiledMethod* cur = call_frame->cm; VMMethod* vmm = cur->backend_method(); /* if(call_frame->block_p() || vmm->required_args != vmm->total_args // has a splat || vmm->call_count < 200 // not called much || vmm->jitted() // already jitted || vmm->parent() // is a block ) return caller; */ if(vmm->required_args != vmm->total_args // has a splat || vmm->call_count < 200 // not called much || vmm->jitted() // already jitted || !vmm->no_inline_p() // method marked as not inlinable ) return caller; CallFrame* next = call_frame->previous; if(!next|| cur->backend_method()->total > SMALL_METHOD_SIZE) return call_frame; caller = call_frame; call_frame = next; } return caller; }
FREObject FlashRuby_eval(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) { uint32_t length = 0; const uint8_t* fl_str = NULL; FREGetObjectAsUTF8(argv[0], &length, &fl_str); InterpreterCallFrame* frame = ALLOCA_CALLFRAME(0); frame->prepare(0); frame->previous = NULL; frame->dispatch_data = NULL; frame->flags = 0; CompiledMethod* cm = CompiledMethod::create(state); cm->metadata(state, state->symbol("__script__")); cm->name(state, state->symbol("__script__")); frame->cm = cm; StackVariables* scope = ALLOCA_STACKVARIABLES(0); scope->initialize(G(main), cNil, G(object), 0); scope->on_heap_ = VariableScope::synthesize(state, cm, G(object), cNil, G(main), cNil, state->new_object<Tuple>(G(tuple))); frame->scope = scope; Arguments* arguments = new Arguments(state->symbol("script"), G(main), cNil, 0, 0); frame->arguments = arguments; state->set_call_frame(frame); String* str = String::create(state, (const char*)fl_str); Array* eval_args = Array::create(state, 1); eval_args->append(state, str); Object* result_obj = G(main)->send(state, frame, state->symbol("instance_eval"), eval_args); const char* result_c_str = result_obj->to_s(state)->c_str_null_safe(state); FREObject result_str; FRENewObjectFromUTF8(strlen(result_c_str), (const uint8_t*)result_c_str, &result_str); return result_str; }
void test_validate_ip() { CompiledMethod* cm = CompiledMethod::create(state); Tuple* tup = Tuple::from(state, 1, state->symbol("@blah")); cm->literals(state, tup); InstructionSequence* iseq = InstructionSequence::create(state, 3); iseq->opcodes()->put(state, 0, Fixnum::from(InstructionSequence::insn_push_ivar)); iseq->opcodes()->put(state, 1, Fixnum::from(0)); iseq->opcodes()->put(state, 2, Fixnum::from(InstructionSequence::insn_push_nil)); cm->iseq(state, iseq); VMMethod* vmm = new VMMethod(state, cm); TS_ASSERT_EQUALS(vmm->validate_ip(state, 0), true); TS_ASSERT_EQUALS(vmm->validate_ip(state, 1), false); TS_ASSERT_EQUALS(vmm->validate_ip(state, 2), true); }
VMMethod* CompiledMethod::internalize(STATE, GCToken gct, const char** reason, int* ip) { VMMethod* vmm = backend_method_; atomic::memory_barrier(); if(vmm) return vmm; CompiledMethod* self = this; OnStack<1> os(state, self); self->hard_lock(state, gct); vmm = self->backend_method_; if(!vmm) { { BytecodeVerification bv(self); if(!bv.verify(state)) { if(reason) *reason = bv.failure_reason(); if(ip) *ip = bv.failure_ip(); std::cerr << "Error validating bytecode: " << bv.failure_reason() << "\n"; return 0; } } vmm = new VMMethod(state, self); if(self->resolve_primitive(state)) { vmm->fallback = execute; } else { vmm->setup_argument_handler(self); } // We need to have an explicit memory barrier here, because we need to // be sure that vmm is completely initialized before it's set. // Otherwise another thread might see a partially initialized // VMMethod. atomic::memory_barrier(); backend_method_ = vmm; } self->hard_unlock(state, gct); return vmm; }
GrowableArray<MonitorInfo*>* compiledVFrame::monitors() const { // Natives has no scope if (scope() == NULL) { CompiledMethod* nm = code(); Method* method = nm->method(); assert(method->is_native() || nm->is_aot(), "Expect a native method or precompiled method"); if (!method->is_synchronized()) { return new GrowableArray<MonitorInfo*>(0); } // This monitor is really only needed for UseBiasedLocking, but // return it in all cases for now as it might be useful for stack // traces and tools as well GrowableArray<MonitorInfo*> *monitors = new GrowableArray<MonitorInfo*>(1); // Casting away const frame& fr = (frame&) _fr; MonitorInfo* info = new MonitorInfo( fr.get_native_receiver(), fr.get_native_monitor(), false, false); monitors->push(info); return monitors; } GrowableArray<MonitorValue*>* monitors = scope()->monitors(); if (monitors == NULL) { return new GrowableArray<MonitorInfo*>(0); } GrowableArray<MonitorInfo*>* result = new GrowableArray<MonitorInfo*>(monitors->length()); for (int index = 0; index < monitors->length(); index++) { MonitorValue* mv = monitors->at(index); ScopeValue* ov = mv->owner(); StackValue *owner_sv = create_stack_value(ov); // it is an oop if (ov->is_object() && owner_sv->obj_is_scalar_replaced()) { // The owner object was scalar replaced assert(mv->eliminated(), "monitor should be eliminated for scalar replaced object"); // Put klass for scalar replaced object. ScopeValue* kv = ((ObjectValue *)ov)->klass(); assert(kv->is_constant_oop(), "klass should be oop constant for scalar replaced object"); Handle k(((ConstantOopReadValue*)kv)->value()()); assert(java_lang_Class::is_instance(k()), "must be"); result->push(new MonitorInfo(k(), resolve_monitor_lock(mv->basic_lock()), mv->eliminated(), true)); } else { result->push(new MonitorInfo(owner_sv->get_obj()(), resolve_monitor_lock(mv->basic_lock()), mv->eliminated(), false)); } } return result; }
void test_get_breakpoint_flags() { CompiledMethod* cm = CompiledMethod::create(state); Tuple* tup = Tuple::from(state, 1, state->symbol("@blah")); cm->literals(state, tup); InstructionSequence* iseq = InstructionSequence::create(state, 3); iseq->opcodes()->put(state, 0, Fixnum::from(InstructionSequence::insn_push_ivar)); iseq->opcodes()->put(state, 1, Fixnum::from(0)); iseq->opcodes()->put(state, 2, Fixnum::from(4 << 24 | InstructionSequence::insn_push_nil)); cm->iseq(state, iseq); VMMethod* vmm = new VMMethod(state, cm); TS_ASSERT_EQUALS(vmm->get_breakpoint_flags(state, 0), 0U); TS_ASSERT_EQUALS(vmm->get_breakpoint_flags(state, 2), (4U << 24)); TS_ASSERT_EQUALS(vmm->get_breakpoint_flags(state, 1), 0U); }
CompiledMethod* CompiledMethod::generate_tramp(STATE, size_t stack_size) { CompiledMethod* cm = CompiledMethod::create(state); cm->stack_size(state, Fixnum::from(stack_size)); cm->required_args(state, Fixnum::from(0)); cm->total_args(state, cm->required_args()); cm->name(state, state->symbol("__halt__")); cm->iseq(state, InstructionSequence::create(state, 1)); cm->iseq()->opcodes()->put(state, 0, Fixnum::from(InstructionSequence::insn_halt)); StaticScope* ss = StaticScope::create(state); ss->module(state, G(object)); cm->scope(state, ss); cm->formalize(state, false); return cm; }
void CompiledMethodDesc::update_relative_offsets(int delta) { // Create a fake handle (only used during GC). // Note that this temporary handle will not be visited by GC. CompiledMethodDesc* cm_desc = this; CompiledMethod* cm = (CompiledMethod*) &cm_desc; // Iterate over all relative offsets to static code in generated code for (RelocationReader stream(cm); !stream.at_end(); stream.advance()) { if (stream.is_compiler_stub()) { // Relocate relative jump/call to static code. int* offset = (int*)(cm->entry() + stream.code_offset()); #ifdef AZZERT OopDesc* target = (OopDesc*)(*offset + (stream.code_offset() + (int)cm->entry())); GUARANTEE(!ObjectHeap::contains_moveable(target), "Insanity check"); #endif *offset = *offset - delta; } } }
ExecuteStatus CompiledMethod::activate(STATE, Executable* exec, Task* task, Message& msg) { CompiledMethod* meth = as<CompiledMethod>(msg.recv); Object* recv = msg.get_argument(0); Module* mod = as<Module>(msg.get_argument(1)); Array* args = as<Array>(msg.get_argument(2)); // Leave msg.block set and pass it through. msg.recv = recv; msg.method = meth; msg.module = mod; msg.set_arguments(state, args); msg.name = meth->name(); msg.priv = true; msg.method_missing = false; // NOTE even when we're activating a method_missing, we don't // push the name given, because there really isn't one. So if // this is used to call a method_missing, you have to supply all // the args. return meth->execute(state, task, msg); }