Example #1
0
  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));
  }
Example #2
0
  /* 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;
  }