void ExtensionFinalizer::finalize(STATE) { ManagedPhase managed(state); NativeMethodEnvironment* env = state->vm()->native_method_environment; NativeMethodFrame nmf(env, 0, 0); ExceptionPoint ep(env); CallFrame* previous_frame = 0; CallFrame* call_frame = ALLOCA_CALL_FRAME(0); call_frame->previous = NULL; call_frame->lexical_scope_ = 0; call_frame->dispatch_data = (void*)&nmf; call_frame->compiled_code = 0; call_frame->flags = CallFrame::cNativeMethod; call_frame->top_scope_ = 0; call_frame->scope = 0; call_frame->arguments = 0; env->set_current_call_frame(0); env->set_current_native_frame(&nmf); // Register the CallFrame, because we might GC below this. if(state->vm()->push_call_frame(state, call_frame, previous_frame)) { nmf.setup(Qnil, Qnil, Qnil, Qnil); PLACE_EXCEPTION_POINT(ep); if(unlikely(ep.jumped_to())) { logger::warn( "finalizer: an exception occurred running a NativeMethod finalizer"); } else { (*finalizer_)(state, object()); } state->vm()->pop_call_frame(state, previous_frame); env->set_current_call_frame(0); env->set_current_native_frame(0); } else { logger::warn("finalizer: stack error"); } }
// Installed by default in BlockEnvironment::execute, it runs the bytecodes // for the block in the interpreter. // // Future code will detect hot blocks and queue them in the JIT, whereby the // JIT will install a newly minted machine function into ::execute. Object* BlockEnvironment::execute_interpreter(STATE, BlockEnvironment* env, Arguments& args, BlockInvocation& invocation) { // Don't use env->machine_code() because it might lock and the work should // already be done. MachineCode* const mcode = env->compiled_code()->machine_code(); if(!mcode) { Exception::internal_error(state, "invalid bytecode method"); return 0; } #ifdef ENABLE_LLVM if(mcode->call_count >= 0) { if(mcode->call_count >= state->shared().config.jit_threshold_compile) { OnStack<1> os(state, env); G(jit)->compile_soon(state, env->compiled_code(), invocation.self->direct_class(state), env, true); } else { mcode->call_count++; } } #endif StackVariables* scope = ALLOCA_STACKVARIABLES(mcode->number_of_locals); Module* mod = invocation.module; if(!mod) mod = env->module(); Object* block = cNil; if(VariableScope* vs = env->top_scope()) { if(!vs->nil_p()) block = vs->block(); } scope->initialize(invocation.self, block, mod, mcode->number_of_locals); scope->set_parent(env->scope()); if(!GenericArguments::call(state, mcode, scope, args, invocation.flags)) { if(state->vm()->thread_state()->raise_reason() == cNone) { Exception* exc = Exception::make_argument_error(state, mcode->required_args, args.total(), mcode->name()); exc->locations(state, Location::from_call_stack(state)); state->raise_exception(exc); } return NULL; } CallFrame* previous_frame = NULL; CallFrame* call_frame = ALLOCA_CALL_FRAME(mcode->stack_size); call_frame->prepare(mcode->stack_size); call_frame->constant_scope_ = invocation.constant_scope; call_frame->previous = NULL; call_frame->arguments = &args; call_frame->dispatch_data = env; call_frame->compiled_code = env->compiled_code(); call_frame->scope = scope; call_frame->optional_jit_data = NULL; call_frame->top_scope_ = env->top_scope(); call_frame->flags = invocation.flags | CallFrame::cMultipleScopes | CallFrame::cBlock; if(!state->vm()->push_call_frame(state, call_frame, previous_frame)) { return NULL; } Object* value = NULL; #ifdef RBX_PROFILER if(unlikely(state->vm()->tooling())) { Module* mod = scope->module(); if(SingletonClass* sc = try_as<SingletonClass>(mod)) { if(Module* ma = try_as<Module>(sc->singleton())) { mod = ma; } } OnStack<2> os(state, env, mod); tooling::BlockEntry method(state, env, mod); value = (*mcode->run)(state, mcode); } else { value = (*mcode->run)(state, mcode); } #else value = (*mcode->run)(state, mcode); #endif if(!state->vm()->pop_call_frame(state, previous_frame)) { return NULL; } return value; }