namespace rubinius { utilities::thread::ThreadData<ManagedThread*> _current_thread; ManagedThread::ManagedThread(uint32_t id, SharedState& ss, ManagedThread::Kind kind) : shared_(ss) , name_(kind == eRuby ? "<ruby>" : "<system>") , run_state_(eIndependent) , kind_(kind) , id_(id) { metrics_.init(metrics::eNone); } ManagedThread::~ManagedThread() { if(metrics::Metrics* metrics = shared_.metrics()) { metrics->add_historical_metrics(&metrics_); } } ManagedThread* ManagedThread::current() { return _current_thread.get(); } void ManagedThread::set_current(ManagedThread* th, std::string name) { th->os_thread_ = pthread_self(); th->set_name(name); _current_thread.set(th); } }
namespace rubinius { utilities::thread::ThreadData<ManagedThread*> _current_thread; ManagedThread::ManagedThread(uint32_t id, SharedState& ss, ManagedThread::Kind kind, const char* name) : shared_(ss) , run_state_(eIndependent) , kind_(kind) , os_thread_(pthread_self()) , id_(id) { if(name) { name_ = std::string(name); } else { std::ostringstream thread_name; thread_name << "rbx.ruby." << id_; name_ = thread_name.str(); } metrics_.init(metrics::eNone); } ManagedThread::~ManagedThread() { if(metrics::Metrics* metrics = shared_.metrics()) { metrics->add_historical_metrics(metrics_); } } ManagedThread* ManagedThread::current() { return _current_thread.get(); } void ManagedThread::set_current_thread(ManagedThread* th) { utilities::thread::Thread::set_os_name(th->name().c_str()); th->os_thread_ = pthread_self(); _current_thread.set(th); } }
void ManagedThread::set_current_thread(ManagedThread* th) { utilities::thread::Thread::set_os_name(th->name().c_str()); th->os_thread_ = pthread_self(); _current_thread.set(th); }
ManagedThread* ManagedThread::current() { return _current_thread.get(); }
void ManagedThread::set_current(ManagedThread* th, std::string name) { th->os_thread_ = pthread_self(); th->set_name(name); _current_thread.set(th); }
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; }
NativeMethodEnvironment* NativeMethodEnvironment::get() { return native_method_environment.get(); }
namespace rubinius { /** Thread-local NativeMethodEnvironment instance. */ utilities::thread::ThreadData<NativeMethodEnvironment*> native_method_environment; /* Class methods */ NativeMethodEnvironment* NativeMethodEnvironment::get() { return native_method_environment.get(); } NativeMethodFrame::~NativeMethodFrame() { flush_cached_data(); handles_.deref_all(); } void NativeMethodFrame::check_tracked_handle(capi::Handle* handle, bool need_update) { if(need_update) { check_handles_ = true; } if(handles_.add_if_absent(handle)) { // We're seeing this object for the first time in this function. // Be sure that it's updated. handle->update(NativeMethodEnvironment::get()); } } VALUE NativeMethodFrame::get_handle(STATE, Object* obj) { capi::Handle* handle = obj->handle(state); if(handle) { if(handles_.add_if_absent(handle)) { // We're seeing this object for the first time in this function. // Be sure that it's updated. handle->update(NativeMethodEnvironment::get()); } } else { handle = state->memory()->add_capi_handle(state, obj); handles_.add_if_absent(handle); } if(!handle->valid_p()) { handle->debug_print(); rubinius::abort(); } return handle->as_value(); } Object* NativeMethodFrame::get_object(VALUE val) { return capi::Handle::from(val)->object(); } void NativeMethodFrame::flush_cached_data() { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); if(check_handles_) { handles_.flush_all(env); } if(env->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)->flush(env); } } } void NativeMethodFrame::update_cached_data() { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); if(check_handles_) { handles_.update_all(env); } if(env->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); } } } VALUE NativeMethodEnvironment::get_handle(Object* obj) { if(obj->reference_p()) { if(!current_native_frame_) { rubinius::bug("Unable to create handles with no NMF"); } return current_native_frame_->get_handle(&state_, obj); } else if(obj->fixnum_p() || obj->symbol_p()) { return reinterpret_cast<VALUE>(obj); } else if(obj->nil_p()) { return Qnil; } else if(obj->false_p()) { return Qfalse; } else if(obj->true_p()) { return Qtrue; } else if(obj == cUndef) { return Qundef; } capi::capi_raise_runtime_error("NativeMethod handle requested for unknown object type"); return 0; // keep compiler happy } void NativeMethodEnvironment::delete_global(VALUE val) { rubinius::bug("NME::delete_global was used"); } Object* NativeMethodEnvironment::block() { if(!current_native_frame_) return cNil; return get_object(current_native_frame_->block()); } capi::HandleSet& NativeMethodEnvironment::handles() { if(!current_native_frame_) { rubinius::bug("Requested handles with no frame"); } return current_native_frame_->handles(); } void NativeMethodEnvironment::flush_cached_data() { if(!current_native_frame_) return; current_native_frame_->flush_cached_data(); } void NativeMethodEnvironment::check_tracked_handle(capi::Handle* hdl, bool need_update) { if(!current_native_frame_) return; current_native_frame_->check_tracked_handle(hdl, need_update); } void NativeMethodEnvironment::update_cached_data() { if(!current_native_frame_) return; current_native_frame_->update_cached_data(); } StackVariables* NativeMethodEnvironment::scope() { CallFrame* cur = current_call_frame(); while(!cur->scope) { cur = cur->previous; } return cur->scope; } void NativeMethod::init(STATE) { GO(nmethod).set(ontology::new_class(state, "NativeMethod", G(executable), G(rubinius))); G(nmethod)->set_object_type(state, NativeMethodType); init_thread(state); } void NativeMethod::init_thread(STATE) { NativeMethodEnvironment* env = new NativeMethodEnvironment(state); native_method_environment.set(env); } void NativeMethod::cleanup_thread(STATE) { delete native_method_environment.get(); native_method_environment.set(NULL); } /** * Arity -3: VALUE func(VALUE argument_array); * Arity -2: VALUE func(VALUE receiver, VALUE argument_array); * Arity -1: VALUE func(int argument_count, VALUE*, VALUE receiver); * Otherwise: VALUE func(VALUE receiver, [VALUE arg1, VALUE arg2, ...]); * * There is also a special-case arity, INIT_FUNCTION, which corresponds * to void (*)(void) and should never appear in user code. * * @note Currently supports functions with up to receiver + 15 (separate) arguments only! * Anything beyond that should use one of the special arities instead. * 15 is the limit in MRI as well. */ class ZeroArguments { public: static Object* invoke(STATE, NativeMethod* nm, NativeMethodEnvironment* env, Arguments& args) { VALUE receiver = env->current_native_frame()->receiver(); return env->get_object(nm->func()(receiver)); } }; class OneArgument { public: static Object* invoke(STATE, NativeMethod* nm, NativeMethodEnvironment* env, Arguments& args) { VALUE receiver = env->current_native_frame()->receiver(); VALUE a1 = env->get_handle(args.get_argument(0)); return env->get_object(nm->func()(receiver, a1)); } }; class TwoArguments { public: static Object* invoke(STATE, NativeMethod* nm, NativeMethodEnvironment* env, Arguments& args) { VALUE receiver = env->current_native_frame()->receiver(); VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); return env->get_object(nm->func()(receiver, a1, a2)); } }; class ThreeArguments { public: static Object* invoke(STATE, NativeMethod* nm, NativeMethodEnvironment* env, Arguments& args) { VALUE receiver = env->current_native_frame()->receiver(); VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); return env->get_object(nm->func()(receiver, a1, a2, a3)); } }; class GenericArguments { public: static Object* invoke(STATE, NativeMethod* nm, NativeMethodEnvironment* env, Arguments& args) { VALUE receiver = env->current_native_frame()->receiver(); switch(nm->arity()->to_int()) { // This one is not in MRI. case ARGS_IN_RUBY_ARRAY: { /* Braces required to create objects in a switch */ VALUE ary = env->get_handle(args.as_array(state)); VALUE ret = nm->func()(ary); return env->get_object(ret); } case RECEIVER_PLUS_ARGS_IN_RUBY_ARRAY: { VALUE ary = env->get_handle(args.as_array(state)); VALUE ret = nm->func()(receiver, ary); return env->get_object(ret); } case ARG_COUNT_ARGS_IN_C_ARRAY_PLUS_RECEIVER: { VALUE ary[args.total()]; for (std::size_t i = 0; i < args.total(); ++i) { ary[i] = env->get_handle(args.get_argument(i)); } VALUE ret = nm->func_as<ArgcFunction>()(args.total(), ary, receiver); return env->get_object(ret); } /* * Normal arg counts * */ case 0: return env->get_object(nm->func()(receiver)); case 1: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE ret = nm->func()(receiver, a1); return env->get_object(ret); } case 2: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE ret = nm->func()(receiver, a1, a2); return env->get_object(ret); } case 3: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE ret = nm->func()(receiver, a1, a2, a3); return env->get_object(ret); } case 4: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4); return env->get_object(ret); } case 5: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE a5 = env->get_handle(args.get_argument(4)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4, a5); return env->get_object(ret); } case 6: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE a5 = env->get_handle(args.get_argument(4)); VALUE a6 = env->get_handle(args.get_argument(5)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4, a5, a6); return env->get_object(ret); } case 7: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE a5 = env->get_handle(args.get_argument(4)); VALUE a6 = env->get_handle(args.get_argument(5)); VALUE a7 = env->get_handle(args.get_argument(6)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4, a5, a6, a7); return env->get_object(ret); } case 8: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE a5 = env->get_handle(args.get_argument(4)); VALUE a6 = env->get_handle(args.get_argument(5)); VALUE a7 = env->get_handle(args.get_argument(6)); VALUE a8 = env->get_handle(args.get_argument(7)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4, a5, a6, a7, a8); return env->get_object(ret); } case 9: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE a5 = env->get_handle(args.get_argument(4)); VALUE a6 = env->get_handle(args.get_argument(5)); VALUE a7 = env->get_handle(args.get_argument(6)); VALUE a8 = env->get_handle(args.get_argument(7)); VALUE a9 = env->get_handle(args.get_argument(8)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4, a5, a6, a7, a8, a9); return env->get_object(ret); } case 10: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE a5 = env->get_handle(args.get_argument(4)); VALUE a6 = env->get_handle(args.get_argument(5)); VALUE a7 = env->get_handle(args.get_argument(6)); VALUE a8 = env->get_handle(args.get_argument(7)); VALUE a9 = env->get_handle(args.get_argument(8)); VALUE a10 = env->get_handle(args.get_argument(9)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); return env->get_object(ret); } case 11: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE a5 = env->get_handle(args.get_argument(4)); VALUE a6 = env->get_handle(args.get_argument(5)); VALUE a7 = env->get_handle(args.get_argument(6)); VALUE a8 = env->get_handle(args.get_argument(7)); VALUE a9 = env->get_handle(args.get_argument(8)); VALUE a10 = env->get_handle(args.get_argument(9)); VALUE a11 = env->get_handle(args.get_argument(10)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11); return env->get_object(ret); } case 12: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE a5 = env->get_handle(args.get_argument(4)); VALUE a6 = env->get_handle(args.get_argument(5)); VALUE a7 = env->get_handle(args.get_argument(6)); VALUE a8 = env->get_handle(args.get_argument(7)); VALUE a9 = env->get_handle(args.get_argument(8)); VALUE a10 = env->get_handle(args.get_argument(9)); VALUE a11 = env->get_handle(args.get_argument(10)); VALUE a12 = env->get_handle(args.get_argument(11)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12); return env->get_object(ret); } case 13: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE a5 = env->get_handle(args.get_argument(4)); VALUE a6 = env->get_handle(args.get_argument(5)); VALUE a7 = env->get_handle(args.get_argument(6)); VALUE a8 = env->get_handle(args.get_argument(7)); VALUE a9 = env->get_handle(args.get_argument(8)); VALUE a10 = env->get_handle(args.get_argument(9)); VALUE a11 = env->get_handle(args.get_argument(10)); VALUE a12 = env->get_handle(args.get_argument(11)); VALUE a13 = env->get_handle(args.get_argument(12)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13); return env->get_object(ret); } case 14: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE a5 = env->get_handle(args.get_argument(4)); VALUE a6 = env->get_handle(args.get_argument(5)); VALUE a7 = env->get_handle(args.get_argument(6)); VALUE a8 = env->get_handle(args.get_argument(7)); VALUE a9 = env->get_handle(args.get_argument(8)); VALUE a10 = env->get_handle(args.get_argument(9)); VALUE a11 = env->get_handle(args.get_argument(10)); VALUE a12 = env->get_handle(args.get_argument(11)); VALUE a13 = env->get_handle(args.get_argument(12)); VALUE a14 = env->get_handle(args.get_argument(13)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); return env->get_object(ret); } case 15: { VALUE a1 = env->get_handle(args.get_argument(0)); VALUE a2 = env->get_handle(args.get_argument(1)); VALUE a3 = env->get_handle(args.get_argument(2)); VALUE a4 = env->get_handle(args.get_argument(3)); VALUE a5 = env->get_handle(args.get_argument(4)); VALUE a6 = env->get_handle(args.get_argument(5)); VALUE a7 = env->get_handle(args.get_argument(6)); VALUE a8 = env->get_handle(args.get_argument(7)); VALUE a9 = env->get_handle(args.get_argument(8)); VALUE a10 = env->get_handle(args.get_argument(9)); VALUE a11 = env->get_handle(args.get_argument(10)); VALUE a12 = env->get_handle(args.get_argument(11)); VALUE a13 = env->get_handle(args.get_argument(12)); VALUE a14 = env->get_handle(args.get_argument(13)); VALUE a15 = env->get_handle(args.get_argument(14)); VALUE ret = nm->func()(receiver, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15); return env->get_object(ret); } /* Extension entry point, should never occur for user code. */ case INIT_FUNCTION: { nm->func_as<InitFunction>()(); return cNil; } /* A C function being used as a block */ case ITERATE_BLOCK: { VALUE cb_data = env->get_handle(nm->get_ivar(state, state->symbol("cb_data"))); Object* ob = nm->get_ivar(state, state->symbol("original_block")); if(!ob->nil_p()) { env->current_native_frame()->set_block(env->get_handle(ob)); } VALUE val; switch(args.total()) { case 0: val = env->get_handle(cNil); break; case 1: val = env->get_handle(args.get_argument(0)); break; default: val = env->get_handle(args.as_array(state)); break; } VALUE ret = nm->func()(val, cb_data, receiver); return env->get_object(ret); } case C_BLOCK_CALL: { VALUE val; VALUE ary[args.total()]; VALUE cb_data = env->get_handle(nm->get_ivar(state, state->symbol("cb_data"))); if(args.total() > 0) { val = env->get_handle(args.get_argument(0)); } else { val = env->get_handle(cNil); } for (std::size_t i = 0; i < args.total(); ++i) { ary[i] = env->get_handle(args.get_argument(i)); } VALUE ret = nm->func()(val, cb_data, args.total(), ary); return env->get_object(ret); } case C_LAMBDA: { VALUE cb_data = env->get_handle(nm->get_ivar(state, state->symbol("cb_data"))); VALUE val = env->get_handle(args.as_array(state)); VALUE ret = nm->func()(val, cb_data); return env->get_object(ret); } case C_CALLBACK: { VALUE cb_data = env->get_handle(nm->get_ivar(state, state->symbol("cb_data"))); nm->func()(cb_data); return cNil; } default: capi::capi_raise_runtime_error("unrecognized arity for NativeMethod call"); return cNil; } } }; template <class ArgumentHandler> 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; } NativeMethod* NativeMethod::load_extension_entry_point(STATE, String* library, Symbol* name, Pointer* ptr) { void* func = ptr->pointer; return NativeMethod::create(state, library, G(rubinius), name, func, Fixnum::from(INIT_FUNCTION)); } NativeMethod* NativeMethod::create(State* state, String* file_name, Module* module, Symbol* method_name, void* func, Fixnum* arity) { NativeMethod* nmethod = state->new_object<NativeMethod>(G(nmethod)); nmethod->arity(state, arity); nmethod->file(state, file_name); nmethod->name(state, method_name); nmethod->module(state, module); nmethod->func_ = func; switch(arity->to_native()) { case 0: nmethod->set_executor(&NativeMethod::executor_implementation<ZeroArguments>); break; case 1: nmethod->set_executor(&NativeMethod::executor_implementation<OneArgument>); break; case 2: nmethod->set_executor(&NativeMethod::executor_implementation<TwoArguments>); break; case 3: nmethod->set_executor(&NativeMethod::executor_implementation<ThreeArguments>); break; default: nmethod->set_executor(&NativeMethod::executor_implementation<GenericArguments>); break; } nmethod->primitive(state, state->symbol("nativemethod_call")); nmethod->serial(state, Fixnum::from(0)); nmethod->inliners_ = 0; return nmethod; } }
void NativeMethod::cleanup_thread(STATE) { delete native_method_environment.get(); native_method_environment.set(NULL); }
void NativeMethod::init_thread(STATE) { NativeMethodEnvironment* env = new NativeMethodEnvironment(state); native_method_environment.set(env); }