void test_dup() { // Create a realistic MethodContext // Is there a better way to do this? Task* task = Task::create(state); // create a target CM CompiledMethod* target = CompiledMethod::create(state); target->iseq(state, InstructionSequence::create(state, 1)); target->iseq()->opcodes()->put(state, 0, Fixnum::from(InstructionSequence::insn_ret)); target->total_args(state, Fixnum::from(0)); target->required_args(state, target->total_args()); target->stack_size(state, Fixnum::from(10)); target->formalize(state); // create a containing CM CompiledMethod* cm = CompiledMethod::create(state); cm->iseq(state, InstructionSequence::create(state, 10)); cm->stack_size(state, Fixnum::from(10)); cm->local_count(state, Fixnum::from(0)); cm->literals(state, Tuple::create(state, 10)); Symbol* name = state->symbol("blah"); G(true_class)->method_table()->store(state, name, target); SendSite* ss = SendSite::create(state, name); cm->literals()->put(state, 0, ss); cm->formalize(state); MethodContext* ctx = MethodContext::create(state, Qnil, cm); task->make_active(ctx); task->push(Qtrue); // Dup right before we run so we can compare later MethodContext* dup = ctx->dup(state); // Compare the dup'd with the original TS_ASSERT_EQUALS(ctx->sender(), dup->sender()); TS_ASSERT_EQUALS(dup, dup->home()); TS_ASSERT_EQUALS(ctx->self(), dup->self()); TS_ASSERT_EQUALS(ctx->cm(), dup->cm()); TS_ASSERT_EQUALS(ctx->module(), dup->module()); TS_ASSERT_EQUALS(ctx->block(), dup->block()); TS_ASSERT_EQUALS(ctx->name(), dup->name()); TS_ASSERT_EQUALS(ctx->vmm, dup->vmm); TS_ASSERT_EQUALS(ctx->ip, dup->ip); TS_ASSERT_EQUALS(ctx->args, dup->args); TS_ASSERT_EQUALS(ctx->stack_size, dup->stack_size); TS_ASSERT_SAME_DATA(&ctx->js, &dup->js, sizeof(dup->js)); }
/* 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; }