Ejemplo n.º 1
0
    inline ExceptionContinuation unwind(STATE, CallFrame* call_frame) {
      VMThreadState* th = state->vm()->thread_state();

      switch(th->raise_reason()) {
      case cException:
        if(UnwindSite* unwind_site = call_frame->unwind) {
          if(unwind_site->unwind_type() == UnwindSite::eRescue) {
            return cExceptionRescue;
          } else if(unwind_site->unwind_type() == UnwindSite::eEnsure) {
            return cExceptionEnsure;
          }
        }
        call_frame->scope->flush_to_heap(state);
        break;

      case cBreak:
        // If we're trying to break to here, we're done!
        if(th->destination_scope() == call_frame->scope->on_heap()) {
          stack_push(th->raise_value());
          th->clear_break();

          // Don't return here, because we want to continue running this method.
          return cExceptionBreak;
        }

        // Fall through.

      case cReturn:
      case cCatchThrow:
      case cThreadKill:
        // Nonlocal return, run ensure blocks.
        while(UnwindSite* unwind_site = call_frame->unwind) {
          if(unwind_site->unwind_type() == UnwindSite::eEnsure) {
            return cExceptionEnsure;
          } else {
            call_frame->pop_unwind();
          }
        }

        // Ok, no ensures to run.
        if(th->raise_reason() == cReturn) {
          call_frame->scope->flush_to_heap(state);

          // If we're trying to return to here, we're done!
          if(th->destination_scope() == call_frame->scope->on_heap()) {
            stack_push(th->raise_value());
            th->clear_return();
            return cExceptionReturn;
          }
        } else { // Not for us!
          call_frame->scope->flush_to_heap(state);
        }
        break;

      case cExit:
        call_frame->scope->flush_to_heap(state);
        break;
      case cFiberCancel:
        break;
      case cNone:
        Exception::interpreter_error(state, "no exception available for unwind handler");
        break;
      } // switch

      return cExceptionUnwind;
    }
Ejemplo n.º 2
0
Object* MachineCode::debugger_interpreter_continue(STATE,
                                                   MachineCode* const mcode,
                                                   CallFrame* const call_frame,
                                                   int sp,
                                                   InterpreterState& is,
                                                   UnwindInfoSet& thread_unwinds)
{

#include "vm/gen/instruction_locations.hpp"

  GCTokenImpl gct;
  opcode* stream = mcode->opcodes;

  Object** stack_ptr = call_frame->stk + sp;

  UnwindInfoSet unwinds(thread_unwinds);
continue_to_run:
  try {

#undef DISPATCH
#define DISPATCH \
    if(Object* bp = call_frame->find_breakpoint(state)) { \
      if(!Helpers::yield_debugger(state, gct, call_frame, bp)) goto exception; \
    } \
    goto *insn_locations[stream[call_frame->inc_ip()]];

#undef next_int
#undef cache_ip
#undef flush_ip

#define next_int ((opcode)(stream[call_frame->inc_ip()]))
#define cache_ip(which)
#define flush_ip()

#include "vm/gen/instruction_implementations.hpp"

  } catch(TypeError& e) {
    flush_ip();
    Exception* exc =
      Exception::make_type_error(state, e.type, e.object, e.reason);
    exc->locations(state, Location::from_call_stack(state, call_frame));

    state->raise_exception(exc);
    call_frame->scope->flush_to_heap(state);
    return NULL;
  } catch(const RubyException& exc) {
    exc.exception->locations(state,
          Location::from_call_stack(state, call_frame));
    state->raise_exception(exc.exception);
    return NULL;
  }

  // No reason to be here!
  rubinius::bug("Control flow error in interpreter");

exception:
  VMThreadState* th = state->vm()->thread_state();
  //
  switch(th->raise_reason()) {
  case cException:
    if(unwinds.has_unwinds()) {
      UnwindInfo info = unwinds.pop();
      stack_position(info.stack_depth);
      call_frame->set_ip(info.target_ip);
      cache_ip(info.target_ip);
      goto continue_to_run;
    } else {
      call_frame->scope->flush_to_heap(state);
      return NULL;
    }

  case cBreak:
    // If we're trying to break to here, we're done!
    if(th->destination_scope() == call_frame->scope->on_heap()) {
      stack_push(th->raise_value());
      th->clear_break();
      goto continue_to_run;
      // Don't return here, because we want to loop back to the top
      // and keep running this method.
    }

    // Otherwise, fall through and run the unwinds
  case cReturn:
  case cCatchThrow:
  case cThreadKill:
    // Otherwise, we're doing a long return/break unwind through
    // here. We need to run ensure blocks.
    while(unwinds.has_unwinds()) {
      UnwindInfo info = unwinds.pop();
      if(info.for_ensure()) {
        stack_position(info.stack_depth);
        call_frame->set_ip(info.target_ip);
        cache_ip(info.target_ip);

        // Don't reset ep here, we're still handling the return/break.
        goto continue_to_run;
      }
    }

    // Ok, no ensures to run.
    if(th->raise_reason() == cReturn) {
      call_frame->scope->flush_to_heap(state);

      // If we're trying to return to here, we're done!
      if(th->destination_scope() == call_frame->scope->on_heap()) {
        Object* val = th->raise_value();
        th->clear_return();
        return val;
      } else {
        // Give control of this exception to the caller.
        return NULL;
      }

    } else { // It's cBreak thats not for us!
      call_frame->scope->flush_to_heap(state);
      // Give control of this exception to the caller.
      return NULL;
    }

  case cExit:
    call_frame->scope->flush_to_heap(state);
    return NULL;
  default:
    break;
  } // switch

  rubinius::bug("Control flow error in interpreter");
  return NULL;
}
Ejemplo n.º 3
0
Object* MachineCode::interpreter(STATE,
                                 MachineCode* const mcode,
                                 InterpreterCallFrame* const call_frame)
{

#include "vm/gen/instruction_locations.hpp"

  if(unlikely(state == 0)) {
    MachineCode::instructions = const_cast<void**>(insn_locations);
    return NULL;
  }

  InterpreterState is;
  GCTokenImpl gct;

  register void** ip_ptr = mcode->addresses;

  Object** stack_ptr = call_frame->stk - 1;

  UnwindInfoSet unwinds;

continue_to_run:
  try {

#undef DISPATCH
#define DISPATCH goto **ip_ptr++

#undef next_int
#define next_int ((opcode)(*ip_ptr++))

#define cache_ip(which) ip_ptr = mcode->addresses + which
#define flush_ip() call_frame->calculate_ip(ip_ptr)

#include "vm/gen/instruction_implementations.hpp"

  } catch(TypeError& e) {
    flush_ip();
    Exception* exc =
      Exception::make_type_error(state, e.type, e.object, e.reason);
    exc->locations(state, Location::from_call_stack(state, call_frame));

    state->raise_exception(exc);
    call_frame->scope->flush_to_heap(state);
    return NULL;
  } catch(const RubyException& exc) {
    exc.exception->locations(state,
          Location::from_call_stack(state, call_frame));
    state->raise_exception(exc.exception);
    return NULL;
  }

  // There is no reason to be here. Either the bytecode loop exits,
  // or it jumps to exception;
  rubinius::bug("Control flow error in interpreter");

  // If control finds it's way down here, there is an exception.
exception:
  VMThreadState* th = state->vm()->thread_state();
  //
  switch(th->raise_reason()) {
  case cException:
    if(unwinds.has_unwinds()) {
      UnwindInfo info = unwinds.pop();
      stack_position(info.stack_depth);
      call_frame->set_ip(info.target_ip);
      cache_ip(info.target_ip);
      goto continue_to_run;
    } else {
      call_frame->scope->flush_to_heap(state);
      return NULL;
    }

  case cBreak:
    // If we're trying to break to here, we're done!
    if(th->destination_scope() == call_frame->scope->on_heap()) {
      stack_push(th->raise_value());
      th->clear_break();
      goto continue_to_run;
      // Don't return here, because we want to loop back to the top
      // and keep running this method.
    }

    // Otherwise, fall through and run the unwinds
  case cReturn:
  case cCatchThrow:
  case cThreadKill:
    // Otherwise, we're doing a long return/break unwind through
    // here. We need to run ensure blocks.
    while(unwinds.has_unwinds()) {
      UnwindInfo info = unwinds.pop();
      if(info.for_ensure()) {
        stack_position(info.stack_depth);
        call_frame->set_ip(info.target_ip);
        cache_ip(info.target_ip);

        // Don't reset ep here, we're still handling the return/break.
        goto continue_to_run;
      }
    }

    // Ok, no ensures to run.
    if(th->raise_reason() == cReturn) {
      call_frame->scope->flush_to_heap(state);

      // If we're trying to return to here, we're done!
      if(th->destination_scope() == call_frame->scope->on_heap()) {
        Object* val = th->raise_value();
        th->clear_return();
        return val;
      } else {
        // Give control of this exception to the caller.
        return NULL;
      }

    } else { // Not for us!
      call_frame->scope->flush_to_heap(state);
      // Give control of this exception to the caller.
      return NULL;
    }

  case cExit:
    call_frame->scope->flush_to_heap(state);
    return NULL;
  default:
    break;
  } // switch

  rubinius::bug("Control flow error in interpreter");
  return NULL;
}
Ejemplo n.º 4
0
Object* MachineCode::uncommon_interpreter(STATE,
                                          MachineCode* const mcode,
                                          CallFrame* const call_frame,
                                          int32_t entry_ip,
                                          native_int sp,
                                          CallFrame* const method_call_frame,
                                          jit::RuntimeDataHolder* rd,
                                          UnwindInfoSet& thread_unwinds)
{

  MachineCode* mc = method_call_frame->compiled_code->machine_code();

  if(++mc->uncommon_count > state->shared().config.jit_deoptimize_threshold) {
    if(state->shared().config.jit_uncommon_print) {
      std::cerr << "[[[ Deoptimizing uncommon method ]]]\n";
      call_frame->print_backtrace(state);

      std::cerr << "Method Call Frame:\n";
      method_call_frame->print_backtrace(state);
    }

    mc->uncommon_count = 0;
    mc->deoptimize(state, method_call_frame->compiled_code, rd);
  }

#include "vm/gen/instruction_locations.hpp"

  opcode* stream = mcode->opcodes;
  InterpreterState is;
  GCTokenImpl gct;

  Object** stack_ptr = call_frame->stk + sp;

  UnwindInfoSet unwinds(thread_unwinds);
continue_to_run:
  try {

#undef DISPATCH
#define DISPATCH goto *insn_locations[stream[call_frame->inc_ip()]];

#undef next_int
#undef cache_ip
#undef flush_ip

#define next_int ((opcode)(stream[call_frame->inc_ip()]))
#define cache_ip(which)
#define flush_ip()

#include "vm/gen/instruction_implementations.hpp"

  } catch(TypeError& e) {
    flush_ip();
    Exception* exc =
      Exception::make_type_error(state, e.type, e.object, e.reason);
    exc->locations(state, Location::from_call_stack(state, call_frame));

    state->raise_exception(exc);
    call_frame->scope->flush_to_heap(state);
    return NULL;
  } catch(const RubyException& exc) {
    exc.exception->locations(state,
          Location::from_call_stack(state, call_frame));
    state->raise_exception(exc.exception);
    return NULL;
  }

  // No reason to be here!
  rubinius::bug("Control flow error in interpreter");

exception:
  VMThreadState* th = state->vm()->thread_state();
  //
  switch(th->raise_reason()) {
  case cException:
    if(unwinds.has_unwinds()) {
      UnwindInfo info = unwinds.pop();
      stack_position(info.stack_depth);
      call_frame->set_ip(info.target_ip);
      cache_ip(info.target_ip);
      goto continue_to_run;
    } else {
      call_frame->scope->flush_to_heap(state);
      return NULL;
    }

  case cBreak:
    // If we're trying to break to here, we're done!
    if(th->destination_scope() == call_frame->scope->on_heap()) {
      stack_push(th->raise_value());
      th->clear_break();
      goto continue_to_run;
      // Don't return here, because we want to loop back to the top
      // and keep running this method.
    }

    // Otherwise, fall through and run the unwinds
  case cReturn:
  case cCatchThrow:
  case cThreadKill:
    // Otherwise, we're doing a long return/break unwind through
    // here. We need to run ensure blocks.
    while(unwinds.has_unwinds()) {
      UnwindInfo info = unwinds.pop();
      if(info.for_ensure()) {
        stack_position(info.stack_depth);
        call_frame->set_ip(info.target_ip);
        cache_ip(info.target_ip);

        // Don't reset ep here, we're still handling the return/break.
        goto continue_to_run;
      }
    }

    // Ok, no ensures to run.
    if(th->raise_reason() == cReturn) {
      call_frame->scope->flush_to_heap(state);

      // If we're trying to return to here, we're done!
      if(th->destination_scope() == call_frame->scope->on_heap()) {
        Object* val = th->raise_value();
        th->clear_return();
        return val;
      } else {
        // Give control of this exception to the caller.
        return NULL;
      }

    } else { // It's cBreak thats not for us!
      call_frame->scope->flush_to_heap(state);
      // Give control of this exception to the caller.
      return NULL;
    }

  case cExit:
    call_frame->scope->flush_to_heap(state);
    return NULL;
  default:
    break;
  } // switch

  rubinius::bug("Control flow error in interpreter");
  return NULL;
}