VALUE rb_iterate(VALUE(*ifunc)(VALUE), VALUE ary, VALUE(*cb)(ANYARGS), VALUE cb_data) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); // Minor optimization. if(ifunc == rb_each && kind_of<Array>(env->get_object(ary))) { for(size_t i = 0; i < rb_ary_size(ary); i++) { (*cb)(rb_ary_entry(ary, i), cb_data, Qnil); } return ary; } NativeMethod* nm = NativeMethod::create(env->state(), (String*)Qnil, env->state()->shared.globals.rubinius.get(), env->state()->symbol("call"), (void*)cb, Fixnum::from(ITERATE_BLOCK)); nm->set_ivar(env->state(), env->state()->symbol("cb_data"), env->get_object(cb_data)); Proc* prc = Proc::create(env->state(), env->state()->shared.globals.proc.get()); prc->bound_method(env->state(), nm); env->set_outgoing_block(env->get_handle(prc)); return (*ifunc)(ary); }
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; }
/*static*/ Atom NativeMethod::verifyEnter(MethodEnv* env, int argc, uint32 *ap) { NativeMethod* f = (NativeMethod*) env->method; f->verify(env->vtable->toplevel); #ifdef AVMPLUS_VERIFYALL f->flags |= VERIFIED; f->core()->processVerifyQueue(env->toplevel()); #endif env->impl32 = f->impl32; return f->impl32(env, argc, ap); }
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; }
Proc* wrap_c_function(void* cb, VALUE cb_data, int arity) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); NativeMethod* nm = NativeMethod::create(env->state(), (String*)Qnil, env->state()->shared.globals.rubinius.get(), env->state()->symbol("call"), cb, Fixnum::from(arity)); nm->set_ivar(env->state(), env->state()->symbol("cb_data"), env->get_object(cb_data)); Proc* prc = Proc::create(env->state(), env->state()->shared.globals.proc.get()); prc->bound_method(env->state(), nm); return prc; }
Location* Location::create(STATE, NativeMethodFrame* nmf) { NativeMethod* nm = try_as<NativeMethod>(nmf->get_object(nmf->method())); if(!nm) return 0; Location* loc = state->new_object<Location>(G(location)); if(Module* mod = try_as<Module>(nmf->get_object(nmf->module()))) { loc->method_module(state, mod); } loc->receiver(state, nmf->get_object(nmf->receiver())); loc->method(state, nm); loc->ip(state, Fixnum::from(-1)); loc->flags(state, Fixnum::from(2)); loc->name(state, nm->name()); return loc; }
Proc* wrap_c_function(void* cb, VALUE cb_data, int arity) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); NativeMethod* nm = NativeMethod::create(env->state(), nil<String>(), env->state()->vm()->shared.globals.rubinius.get(), env->state()->symbol("call"), cb, Fixnum::from(arity), 0); nm->set_ivar(env->state(), env->state()->symbol("cb_data"), env->get_object(cb_data)); Object* current_block = env->block(); if(!current_block->nil_p()) { nm->set_ivar(env->state(), env->state()->symbol("original_block"), current_block); } Proc* prc = Proc::create(env->state(), env->state()->vm()->shared.globals.proc.get()); prc->bound_method(env->state(), nm); return prc; }
static NativeMethod* create(VM* state, String* file_name = as<String>(Qnil), Module* module = as<Module>(Qnil), Symbol* method_name = as<Symbol>(Qnil), FunctorType functor = static_cast<GenericFunctor>(NULL), Fixnum* arity = as<Fixnum>(Qnil)) { NativeMethod* nmethod = state->new_object<NativeMethod>(G(nmethod)); nmethod->arity(state, arity); nmethod->file_name(state, file_name); nmethod->method_name(state, method_name); nmethod->module(state, module); nmethod->functor(state, MemoryPointer::create(state, reinterpret_cast<void*>(functor))); nmethod->set_executor(&NativeMethod::executor_implementation); nmethod->primitive(state, state->symbol("nativemethod_call")); nmethod->serial(state, Fixnum::from(0)); return nmethod; }
NativeMethod* NativeMethod::create(VM* 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)); return nmethod; }
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 SignalThread::print_backtraces() { STATE = shared_.env()->state; ThreadList* threads = shared_.thread_nexus()->threads(); for(ThreadList::iterator i = threads->begin(); i != threads->end(); ++i) { VM* vm = (*i)->as_vm(); if(!vm) continue; bool first = true; CallFrame* frame = vm->call_frame(); while(frame) { if(first) { logger::fatal("--- %s %d backtrace ---", vm->kind_name(), vm->thread_id()); first = false; } std::ostringstream stream; if(NativeMethodFrame* nmf = frame->native_method_frame()) { stream << static_cast<void*>(frame) << ": "; NativeMethod* nm = try_as<NativeMethod>(nmf->get_object(nmf->method())); if(nm && nm->name()->symbol_p()) { stream << "capi:" << nm->name()->debug_str(state) << " at "; stream << nm->file()->c_str(state); } else { stream << "unknown capi"; } } else if(frame->compiled_code) { if(frame->is_block_p(state)) { stream << "__block__"; } else { if(SingletonClass* sc = try_as<SingletonClass>(frame->module())) { Object* obj = sc->singleton(); if(Module* mod = try_as<Module>(obj)) { stream << mod->debug_str(state) << "."; } else { if(obj == G(main)) { stream << "MAIN."; } else { stream << "#<" << obj->class_object(state)->debug_str(state) << ":" << (void*)obj->id(state)->to_native() << ">."; } } } else if(IncludedModule* im = try_as<IncludedModule>(frame->module())) { stream << im->module()->debug_str(state) << "#"; } else { Symbol* name; std::string mod_name; if(frame->module()->nil_p()) { mod_name = frame->lexical_scope()->module()->debug_str(state); } else { if((name = try_as<Symbol>(frame->module()->module_name()))) { mod_name = name->debug_str(state); } else if((name = try_as<Symbol>( frame->lexical_scope()->module()->module_name()))) { mod_name = name->debug_str(state); } else { mod_name = "<anonymous module>"; } } stream << mod_name << "#"; } Symbol* name = try_as<Symbol>(frame->name()); if(name) { stream << name->debug_str(state); } else { stream << frame->compiled_code->name()->debug_str(state); } } stream << " in "; if(Symbol* file_sym = try_as<Symbol>(frame->compiled_code->file())) { stream << file_sym->debug_str(state) << ":" << frame->line(state); } else { stream << "<unknown>"; } stream << " (+" << frame->ip(); if(frame->is_inline_frame()) { stream << " inline"; } else if(frame->jitted_p()) { stream << " jit"; } stream << ")"; } logger::fatal(stream.str().c_str()); frame = frame->previous; } } }
void CallFrame::print_backtrace(STATE, std::ostream& stream, int total, bool filter) { CallFrame* cf = this; int i = -1; while(cf) { i++; if(total > 0 && i == total) return; if(NativeMethodFrame* nmf = cf->native_method_frame()) { stream << static_cast<void*>(cf) << ": "; NativeMethod* nm = try_as<NativeMethod>(nmf->get_object(nmf->method())); if(nm && nm->name()->symbol_p()) { stream << "capi:" << nm->name()->debug_str(state) << " at "; stream << nm->file()->c_str(state); } else { stream << "unknown capi"; } stream << std::endl; cf = cf->previous; continue; } if(!cf->compiled_code) { cf = cf->previous; continue; } if(filter && cf->compiled_code->kernel_method(state)) { cf = cf->previous; continue; } stream << static_cast<void*>(cf) << ": "; if(cf->is_block_p(state)) { stream << "__block__"; } else { if(SingletonClass* sc = try_as<SingletonClass>(cf->module())) { Object* obj = sc->attached_instance(); if(Module* mod = try_as<Module>(obj)) { stream << mod->debug_str(state) << "."; } else { if(obj == G(main)) { stream << "MAIN."; } else { stream << "#<" << obj->class_object(state)->debug_str(state) << ":" << (void*)obj->id(state)->to_native() << ">."; } } } else if(IncludedModule* im = try_as<IncludedModule>(cf->module())) { stream << im->module()->debug_str(state) << "#"; } else { Symbol* name; std::string mod_name; if(cf->module()->nil_p()) { mod_name = cf->constant_scope()->module()->debug_str(state); } else { if((name = try_as<Symbol>(cf->module()->module_name()))) { mod_name = name->debug_str(state); } else if((name = try_as<Symbol>( cf->constant_scope()->module()->module_name()))) { mod_name = name->debug_str(state); } else { mod_name = "<anonymous module>"; } } stream << mod_name << "#"; } Symbol* name = try_as<Symbol>(cf->name()); if(name) { stream << name->debug_str(state); } else { stream << cf->compiled_code->name()->debug_str(state); } } stream << " in "; if(Symbol* file_sym = try_as<Symbol>(cf->compiled_code->file())) { stream << file_sym->debug_str(state) << ":" << cf->line(state); } else { stream << "<unknown>"; } stream << " (+" << cf->ip(); if(cf->is_inline_frame()) { stream << " inline"; } else if(cf->jitted_p()) { stream << " jit"; } stream << ")"; stream << std::endl; cf = cf->previous; } }
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; }