Object* run_function(STATE) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Thread* thread = state->vm()->thread(); NativeMethod* nm = capi::c_as<NativeMethod>( thread->variable_get(state, state->symbol("function"))); Pointer* ptr = capi::c_as<Pointer>( thread->variable_get(state, state->symbol("argument"))); NativeMethodFrame nmf(env, 0, nm); CallFrame call_frame; 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(&call_frame); env->set_current_native_frame(&nmf); state->vm()->set_call_frame(&call_frame); nmf.setup( env->get_handle(thread), env->get_handle(cNil), env->get_handle(nm), env->get_handle(nm->module())); ENTER_CAPI(state); Object* value = NULL; ExceptionPoint ep(env); PLACE_EXCEPTION_POINT(ep); if(unlikely(ep.jumped_to())) { LEAVE_CAPI(state); // Set exception in thread so it's raised when joining. state->vm()->thread()->exception(state, capi::c_as<Exception>(state->vm()->thread_state()->current_exception())); } else { value = env->get_object(nm->func()(ptr->pointer)); } LEAVE_CAPI(state); env->set_current_call_frame(NULL); env->set_current_native_frame(NULL); ep.pop(env); return value; }
Object* NativeMethod::executor_implementation(STATE, CallFrame* call_frame, Dispatch& msg, Arguments& args) { NativeMethod* nm = as<NativeMethod>(msg.method); int arity = nm->arity()->to_int(); if(arity >= 0 && (size_t)arity != args.total()) { Exception* exc = Exception::make_argument_error( state, arity, args.total(), msg.name); exc->locations(state, System::vm_backtrace(state, Fixnum::from(1), call_frame)); state->thread_state()->raise_exception(exc); return NULL; } NativeMethodEnvironment* env = native_method_environment.get(); NativeMethodFrame nmf(env->current_native_frame()); CallFrame* saved_frame = env->current_call_frame(); Object* saved_block = env->block(); env->set_current_call_frame(call_frame); env->set_current_native_frame(&nmf); env->set_current_block(args.block()); Object* ret; ExceptionPoint ep(env); PLACE_EXCEPTION_POINT(ep); if(unlikely(ep.jumped_to())) { ret = NULL; } else { #ifdef RBX_PROFILER if(unlikely(state->shared.profiling())) { profiler::MethodEntry method(state, msg, args); ret = nm->call(state, env, args); } else { ret = nm->call(state, env, args); } #else ret = nm->call(state, env, args); #endif } env->set_current_block(saved_block); env->set_current_call_frame(saved_frame); env->set_current_native_frame(nmf.previous()); ep.pop(env); return ret; }
NativeMethodEnvironment* create_native_method_environment() { NativeMethodFrame* nmf = new NativeMethodFrame(NULL); CallFrame* cf = new CallFrame; NativeMethodEnvironment* nme = new NativeMethodEnvironment(state); nme->set_current_call_frame(cf); nme->set_current_native_frame(nmf); return nme; }
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"); } }
Object* NativeMethod::executor_implementation(STATE, CallFrame* call_frame, Dispatch& msg, Arguments& args) { NativeMethod* nm = as<NativeMethod>(msg.method); int arity = nm->arity()->to_int(); if(arity >= 0 && (size_t)arity != args.total()) { Exception* exc = Exception::make_argument_error( state, arity, args.total(), msg.name); exc->locations(state, Location::from_call_stack(state, call_frame)); state->thread_state()->raise_exception(exc); return NULL; } NativeMethodEnvironment* env = native_method_environment.get(); // Optionally get the handles back to the proper state. if(state->shared.config.capi_global_flush) { capi::Handles* handles = state->shared.cached_handles(); if(handles->size() > 0) { for(capi::Handles::Iterator i(*handles); i.more(); i.advance()) { i->update(env); } } } // Register the CallFrame, because we might GC below this. state->set_call_frame(call_frame); NativeMethodFrame nmf(env->current_native_frame()); CallFrame* saved_frame = env->current_call_frame(); env->set_current_call_frame(call_frame); env->set_current_native_frame(&nmf); // Be sure to do this after installing nmf as the current // native frame. nmf.setup( env->get_handle(args.recv()), env->get_handle(args.block()), env->get_handle(msg.method), env->get_handle(msg.module)); Object* ret; ExceptionPoint ep(env); PLACE_EXCEPTION_POINT(ep); if(unlikely(ep.jumped_to())) { ret = NULL; } else { #ifdef RBX_PROFILER if(unlikely(state->tooling())) { tooling::MethodEntry method(state, msg, args); ret = ArgumentHandler::invoke(state, nm, env, args); } else { ret = ArgumentHandler::invoke(state, nm, env, args); } #else ret = ArgumentHandler::invoke(state, nm, env, args); #endif } env->set_current_call_frame(saved_frame); env->set_current_native_frame(nmf.previous()); ep.pop(env); // Handle any signals that occurred while the native method // was running. if(!state->check_async(call_frame)) return NULL; return ret; }
void FinalizerHandler::finalize(STATE) { switch(process_item_kind_) { case eRuby: { if(process_item_->ruby_finalizer) { CallFrame* call_frame = 0; // Rubinius specific code. If the finalizer is cTrue, then send the // object the __finalize__ message. if(process_item_->ruby_finalizer == cTrue) { process_item_->object->send(state, call_frame, state->symbol("__finalize__")); } else { Array* ary = Array::create(state, 1); ary->set(state, 0, process_item_->object->id(state)); process_item_->ruby_finalizer->send(state, call_frame, G(sym_call), ary); } } process_item_->status = FinalizeObject::eRubyFinalized; break; } case eNative: if(process_item_->finalizer) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); NativeMethodFrame nmf(0, 0); CallFrame* call_frame = ALLOCA_CALLFRAME(0); call_frame->previous = 0; call_frame->constant_scope_ = 0; call_frame->dispatch_data = (void*)&nmf; call_frame->compiled_code = 0; call_frame->flags = CallFrame::cNativeMethod; call_frame->optional_jit_data = 0; 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. state->set_call_frame(call_frame); nmf.setup(Qnil, Qnil, Qnil, Qnil); (*process_item_->finalizer)(state, process_item_->object); state->set_call_frame(0); env->set_current_call_frame(0); env->set_current_native_frame(0); } process_item_->status = FinalizeObject::eNativeFinalized; break; case eRelease: // Unhook any handle used by fi->object so that we don't accidentally // try and mark it later (after we've finalized it) if(capi::Handle* handle = process_item_->object->handle(state)) { handle->forget_object(); process_item_->object->clear_handle(state); } // If the object was remembered, unremember it. if(process_item_->object->remembered_p()) { state->memory()->unremember_object(process_item_->object); } process_item_->status = FinalizeObject::eReleased; break; } }
Object* run_function(STATE) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Thread* self = state->vm()->thread.get(); NativeMethod* nm = capi::c_as<NativeMethod>(self->locals_aref(state, state->symbol("function"))); Pointer* ptr = capi::c_as<Pointer>(self->locals_aref(state, state->symbol("argument"))); self->locals_remove(state, state->symbol("function")); self->locals_remove(state, state->symbol("argument")); GCTokenImpl gct; NativeMethodFrame nmf(env, 0, nm); CallFrame cf; cf.previous = 0; cf.constant_scope_ = 0; cf.dispatch_data = (void*)&nmf; cf.compiled_code = 0; cf.flags = CallFrame::cNativeMethod; cf.optional_jit_data = 0; cf.top_scope_ = 0; cf.scope = 0; cf.arguments = 0; CallFrame* saved_frame = env->current_call_frame(); env->set_current_call_frame(&cf); env->set_current_native_frame(&nmf); nmf.setup( env->get_handle(self), env->get_handle(cNil), env->get_handle(nm), env->get_handle(nm->module())); { OnStack<3> os(state, self, nm, ptr); self->hard_unlock(state, gct, &cf); } ENTER_CAPI(state); Object* ret = NULL; ExceptionPoint ep(env); PLACE_EXCEPTION_POINT(ep); if(unlikely(ep.jumped_to())) { // Setup exception in thread so it's raised when joining // Reload self because it might have been moved self = state->vm()->thread.get(); CallFrame* call_frame = env->current_call_frame(); { OnStack<1> os(state, self); self->hard_lock(state, gct, call_frame, false); Exception* exc = capi::c_as<Exception>(self->current_exception(state)); self->exception(state, exc); self->alive(state, cFalse); self->hard_unlock(state, gct, call_frame); } return NULL; } else { ret = env->get_object(nm->func()(ptr->pointer)); } LEAVE_CAPI(state); env->set_current_call_frame(saved_frame); env->set_current_native_frame(nmf.previous()); ep.pop(env); self = state->vm()->thread.get(); OnStack<1> os(state, self); self->hard_lock(state, gct, &cf, false); self->alive(state, cFalse); self->hard_unlock(state, gct, &cf); return ret; }
Object* NativeMethod::executor_implementation(STATE, CallFrame* call_frame, Executable* exec, Module* mod, Arguments& args) { NativeMethod* nm = as<NativeMethod>(exec); int arity = nm->arity()->to_int(); if(arity >= 0 && (size_t)arity != args.total()) { Exception* exc = Exception::make_argument_error( state, arity, args.total(), args.name()); exc->locations(state, Location::from_call_stack(state, call_frame)); state->raise_exception(exc); return NULL; } NativeMethodEnvironment* env = native_method_environment.get(); // Optionally get the handles back to the proper state. if(state->shared().config.capi_global_flush) { capi::Handles* handles = state->shared().cached_handles(); if(handles->size() > 0) { for(capi::Handles::Iterator i(*handles); i.more(); i.advance()) { i->update(env); } } } // Register the CallFrame, because we might GC below this. state->set_call_frame(call_frame); NativeMethodFrame nmf(env->current_native_frame()); CallFrame cf; cf.previous = call_frame; cf.cm = 0; cf.scope = 0; cf.dispatch_data = (void*)&nmf; cf.flags = CallFrame::cNativeMethod; CallFrame* saved_frame = env->current_call_frame(); env->set_current_call_frame(&cf); env->set_current_native_frame(&nmf); // Be sure to do this after installing nmf as the current // native frame. nmf.setup( env->get_handle(args.recv()), env->get_handle(args.block()), env->get_handle(exec), env->get_handle(mod)); // We've got things setup (they can be GC'd properly), so we need to // wait before entering the extension code. ENTER_CAPI(state); Object* ret; ExceptionPoint ep(env); PLACE_EXCEPTION_POINT(ep); if(unlikely(ep.jumped_to())) { ret = NULL; } else { #ifdef RBX_PROFILER if(unlikely(state->vm()->tooling())) { tooling::MethodEntry method(state, exec, mod, args); ret = ArgumentHandler::invoke(state, nm, env, args); } else { ret = ArgumentHandler::invoke(state, nm, env, args); } #else ret = ArgumentHandler::invoke(state, nm, env, args); #endif } env->set_current_call_frame(saved_frame); env->set_current_native_frame(nmf.previous()); ep.pop(env); LEAVE_CAPI(state); // Handle any signals that occurred while the native method // was running. if(!state->check_async(call_frame)) return NULL; return ret; }
Object* NativeMethod::executor_implementation(STATE, CallFrame* previous, Executable* exec, Module* mod, Arguments& args) { NativeMethod* nm = as<NativeMethod>(exec); int arity = nm->arity()->to_int(); if(arity >= 0 && (size_t)arity != args.total()) { Exception* exc = Exception::make_argument_error( state, arity, args.total(), args.name()); exc->locations(state, Location::from_call_stack(state, previous)); state->raise_exception(exc); return NULL; } NativeMethodEnvironment* env = native_method_environment.get(); // Optionally get the handles back to the proper state. if(state->shared().config.capi_global_flush) { std::list<capi::Handle*>* handles = env->state()->memory()->cached_capi_handles(); for(std::list<capi::Handle*>::iterator i = handles->begin(); i != handles->end(); ++i) { (*i)->update(env); } } NativeMethodFrame nmf(env->current_native_frame()); CallFrame* call_frame = ALLOCA_CALLFRAME(0); call_frame->previous = previous; call_frame->constant_scope_ = 0; call_frame->dispatch_data = (void*)&nmf; call_frame->compiled_code = 0; call_frame->flags = CallFrame::cNativeMethod; call_frame->optional_jit_data = 0; call_frame->top_scope_ = 0; call_frame->scope = 0; call_frame->arguments = &args; CallFrame* saved_frame = env->current_call_frame(); env->set_current_call_frame(call_frame); env->set_current_native_frame(&nmf); // Register the CallFrame, because we might GC below this. state->set_call_frame(call_frame); // Be sure to do this after installing nmf as the current // native frame. nmf.setup( env->get_handle(args.recv()), env->get_handle(args.block()), env->get_handle(exec), env->get_handle(mod)); // We've got things setup (they can be GC'd properly), so we need to // wait before entering the extension code. ENTER_CAPI(state); Object* ret; ExceptionPoint ep(env); #ifdef RBX_PROFILER // This is organized like this so that we don't jump past the destructor of // MethodEntry. It's duplicated, but it's much easier to understand than // trying to de-dup it. OnStack<2> os(state, exec, mod); if(unlikely(state->vm()->tooling())) { tooling::MethodEntry method(state, exec, mod, args); RUBINIUS_METHOD_NATIVE_ENTRY_HOOK(state, mod, args.name(), call_frame); PLACE_EXCEPTION_POINT(ep); if(unlikely(ep.jumped_to())) { ret = NULL; } else { ret = ArgumentHandler::invoke(state, nm, env, args); } RUBINIUS_METHOD_NATIVE_RETURN_HOOK(state, mod, args.name(), call_frame); } else { RUBINIUS_METHOD_NATIVE_ENTRY_HOOK(state, mod, args.name(), call_frame); PLACE_EXCEPTION_POINT(ep); if(unlikely(ep.jumped_to())) { ret = NULL; } else { ret = ArgumentHandler::invoke(state, nm, env, args); } RUBINIUS_METHOD_NATIVE_RETURN_HOOK(state, mod, args.name(), call_frame); } #else RUBINIUS_METHOD_NATIVE_ENTRY_HOOK(state, mod, args.name(), call_frame); PLACE_EXCEPTION_POINT(ep); if(unlikely(ep.jumped_to())) { ret = NULL; } else { ret = ArgumentHandler::invoke(state, nm, env, args); } RUBINIUS_METHOD_NATIVE_RETURN_HOOK(state, mod, args.name(), call_frame); #endif env->set_current_call_frame(saved_frame); env->set_current_native_frame(nmf.previous()); ep.pop(env); LEAVE_CAPI(state); OnStack<1> os_ret(state, ret); // Handle any signals that occurred while the native method // was running. if(!state->check_async(call_frame)) return NULL; return ret; }