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; }
void capi_define_method(const char* file, VALUE target, const char* name, CApiGenericFunction fptr, int arity, CApiMethodKind kind) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); State* state = env->state(); Symbol* method_name = state->symbol(name); Module* module = NULL; if(kind == cCApiSingletonMethod) { module = c_as<Module>(env->get_object(target)->singleton_class(env->state())); } else { module = c_as<Module>(env->get_object(target)); } NativeMethod* method = NULL; method = NativeMethod::create(state, String::create(state, file), module, method_name, (void*)fptr, Fixnum::from(arity), env->current_native_frame()->capi_lock_index()); Symbol* visibility; switch(kind) { case cCApiPrivateMethod: visibility = G(sym_private); break; case cCApiProtectedMethod: visibility = G(sym_protected); break; default: /* Also catches singletons for now. @todo Verify OK. --rue */ visibility = G(sym_public); break; } module->add_method(state, method_name, method, visibility); System::vm_reset_method_cache(env->state(), module, method_name, env->current_call_frame()); }
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 SharedState::leave_capi(STATE) { NativeMethodEnvironment* env = state->vm()->native_method_environment; if(int lock_index = env->current_native_frame()->capi_lock_index()) { capi_locks_[lock_index - 1]->unlock(state->vm()); } }
void SharedState::enter_capi(STATE, const char* file, int line) { NativeMethodEnvironment* env = state->vm()->native_method_environment; if(int lock_index = env->current_native_frame()->capi_lock_index()) { capi_locks_[lock_index - 1]->lock(state->vm(), file, line); } }
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; }