VALUE rb_ensure(VALUE (*func)(ANYARGS), VALUE arg1, VALUE (*ensure_func)(ANYARGS), VALUE arg2) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); VALUE ret = Qnil; bool exc_raised = false; ExceptionPoint ep(env); PLACE_EXCEPTION_POINT(ep); if(unlikely(ep.jumped_to())) { exc_raised = true; } else { ret = (*func)(arg1); } ep.pop(env); (*ensure_func)(arg2); if(exc_raised) { env->current_ep()->return_to(env); } return ret; }
VALUE rb_exec_recursive(VALUE (*func)(VALUE, VALUE, int), VALUE obj, VALUE arg) { VALUE hash = rb_thread_local_aref(rb_thread_current(), rb_intern("__recursive_key")); VALUE objid = rb_obj_id(obj); if(recursive_check(hash, objid)) { return (*func)(obj, arg, 1); } else { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); VALUE ret = Qnil; ExceptionPoint ep(env); PLACE_EXCEPTION_POINT(ep); bool unwinding = false; hash = recursive_push(hash, objid); if(unlikely(ep.jumped_to())) { unwinding = true; } else { ret = (*func)(obj, arg, 0); } ep.pop(env); recursive_pop(hash, objid); if(unwinding) env->current_ep()->return_to(env); return ret; } }
/** * Common implementation for rb_funcall* */ VALUE capi_funcall_backend(const char* file, int line, VALUE receiver, ID method_name, size_t arg_count, VALUE* arg_array) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); env->flush_cached_data(); Array* args = Array::create(env->state(), arg_count); for(size_t i = 0; i < arg_count; i++) { args->set(env->state(), i, env->get_object(arg_array[i])); } Object* blk = RBX_Qnil; if(VALUE blk_handle = env->outgoing_block()) { blk = env->get_object(blk_handle); env->set_outgoing_block(0); } Object* recv = env->get_object(receiver); Object* ret = recv->send(env->state(), env->current_call_frame(), reinterpret_cast<Symbol*>(method_name), args, blk); env->update_cached_data(); // An exception occurred if(!ret) env->current_ep()->return_to(env); return env->get_handle(ret); }
/** @note Shares code with rb_define_class_under, change there too. --rue */ VALUE rb_define_module_under(VALUE parent_handle, const char* name) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Module* parent = c_as<Module>(env->get_object(parent_handle)); Symbol* constant = env->state()->symbol(name); LEAVE_CAPI(env->state()); Module* module = NULL; // Create a scope so we know that the OnStack variables are popped off // before we possibly make a longjmp. Making a longjmp doesn't give // any guarantees about destructors being run { OnStack<2> os(env->state(), parent, constant); module = rubinius::Helpers::open_module(env->state(), parent, constant); } // The call above could have triggered an Autoload resolve, which may // raise an exception, so we have to check the value returned. if(!module) env->current_ep()->return_to(env); // Grab the module handle before grabbing the lock // so the Module isn't accidentally GC'ed. VALUE module_handle = env->get_handle(module); ENTER_CAPI(env->state()); return module_handle; }
VALUE rb_apply(VALUE recv, ID mid, VALUE args) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); env->flush_cached_data(); Array* ary = capi::c_as<Array>(env->get_object(args)); Object* obj = env->get_object(recv); // Unlock, we're leaving extension code. LEAVE_CAPI(env->state()); Object* ret = obj->send(env->state(), env->current_call_frame(), reinterpret_cast<Symbol*>(mid), ary, cNil); // We need to get the handle for the return value before getting // the GEL so that ret isn't accidentally GCd while we wait. VALUE ret_handle = 0; if(ret) ret_handle = env->get_handle(ret); // Re-entering extension code ENTER_CAPI(env->state()); env->update_cached_data(); // An exception occurred if(!ret) env->current_ep()->return_to(env); return ret_handle; }
void rb_jump_tag(int status) { if(!status) return; NativeMethodEnvironment* env = NativeMethodEnvironment::get(); // TODO should check if there is an ep? env->current_ep()->return_to(env); }
void capi_raise_backend(Exception* exception) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); exception->locations(env->state(), Location::from_call_stack(env->state(), env->current_call_frame())); env->state()->raise_exception(exception); env->current_ep()->return_to(env); }
VALUE rb_rescue2(VALUE (*func)(ANYARGS), VALUE arg1, VALUE (*raise_func)(ANYARGS), VALUE arg2, ...) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); VALUE ret = Qnil; ExceptionPoint ep(env); va_list exc_classes; PLACE_EXCEPTION_POINT(ep); if(unlikely(ep.jumped_to())) { ep.pop(env); if(env->state()->thread_state()->raise_reason() != cException) { env->current_ep()->return_to(env); } VALUE exc_handle = env->get_handle(env->state()->thread_state()->current_exception()); bool handle_exc = false; va_start(exc_classes, arg2); while(VALUE eclass = va_arg(exc_classes, VALUE)) { if(RTEST(rb_obj_is_kind_of(exc_handle, eclass))) { handle_exc = true; break; } } va_end(exc_classes); if(handle_exc) { ret = (*raise_func)(arg2, exc_handle); env->state()->thread_state()->clear_raise(); } else { env->current_ep()->return_to(env); } } else { ret = (*func)(arg1); ep.pop(env); } return ret; }
void rb_raise(VALUE error_handle, const char* format_string, ...) { va_list args; char reason[RB_RAISE_BUFSIZE]; va_start(args, format_string); vsnprintf(reason, RB_RAISE_BUFSIZE, format_string, args); va_end(args); NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Exception* exc = Exception::make_exception( env->state(), as<Class>(env->get_object(error_handle)), reason); env->state()->thread_state()->raise_exception(exc); env->current_ep()->return_to(env); }
VALUE rb_apply(VALUE recv, ID mid, VALUE args) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); env->flush_cached_data(); Array* ary = capi::c_as<Array>(env->get_object(args)); Object* obj = env->get_object(recv); Object* ret = obj->send(env->state(), env->current_call_frame(), reinterpret_cast<Symbol*>(mid), ary, RBX_Qnil); env->update_cached_data(); // An exception occurred if(!ret) env->current_ep()->return_to(env); return env->get_handle(ret); }
VALUE rb_protect_inspect(VALUE (*func)(VALUE a, VALUE b), VALUE h_obj, VALUE h_arg) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); STATE = env->state(); Thread* thr = Thread::current(state); LookupTable* rectbl = thr->recursive_objects(); Object* obj = env->get_object(h_obj); Object* id = obj->id(state); bool found = false; rectbl->fetch(state, id, &found); if(found) { return (*func)(h_obj, h_arg); } rectbl->store(state, id, cTrue); VALUE ret = Qnil; ExceptionPoint ep(env); PLACE_EXCEPTION_POINT(ep); bool unwinding = false; if(unlikely(ep.jumped_to())) { unwinding = true; } else { ret = (*func)(h_obj, h_arg); } ep.pop(env); // Get the thread and table again, the GC might have fun. thr = Thread::current(state); rectbl = thr->recursive_objects(); obj = env->get_object(h_obj); id = obj->id(state); rectbl->remove(state, id); if(unwinding) env->current_ep()->return_to(env); return ret; }
VALUE capi_fast_call(VALUE receiver, ID method_name, int arg_count, ...) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); va_list varargs; va_start(varargs, arg_count); Object* args[arg_count]; for(int i = 0; i < arg_count; i++) { args[i] = env->get_object(va_arg(varargs, VALUE)); } va_end(varargs); // Unlock, we're leaving extension code. LEAVE_CAPI(env->state()); Object* recv = env->get_object(receiver); Symbol* method = (Symbol*)method_name; Object* ret = cNil; // Run in block so we properly deconstruct objects allocated // on the stack if we do a longjmp because of an exception. { LookupData lookup(recv, recv->lookup_begin(env->state()), env->state()->globals().sym_private.get()); Arguments args_o(method, recv, cNil, arg_count, args); Dispatch dis(method); ret = dis.send(env->state(), env->current_call_frame(), lookup, args_o); } // We need to get the handle for the return value before getting // the GEL so that ret isn't accidentally GCd while we wait. VALUE ret_handle = 0; if(ret) ret_handle = env->get_handle(ret); // Re-entering extension code ENTER_CAPI(env->state()); // An exception occurred if(!ret) env->current_ep()->return_to(env); return ret_handle; }
/** * Common implementation for rb_funcall* */ VALUE capi_funcall_backend(const char* file, int line, VALUE receiver, ID method_name, size_t arg_count, VALUE* arg_array) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); env->flush_cached_data(); Array* args = Array::create(env->state(), arg_count); for(size_t i = 0; i < arg_count; i++) { args->set(env->state(), i, env->get_object(arg_array[i])); } Object* blk = cNil; if(VALUE blk_handle = env->outgoing_block()) { blk = env->get_object(blk_handle); env->set_outgoing_block(0); } Object* recv = env->get_object(receiver); // Unlock, we're leaving extension code. LEAVE_CAPI(env->state()); Object* ret = recv->send(env->state(), env->current_call_frame(), reinterpret_cast<Symbol*>(method_name), args, blk); // We need to get the handle for the return value before getting // the GEL so that ret isn't accidentally GCd while we wait. VALUE ret_handle = 0; if(ret) ret_handle = env->get_handle(ret); // Re-entering extension code ENTER_CAPI(env->state()); env->update_cached_data(); // An exception occurred if(!ret) env->current_ep()->return_to(env); return ret_handle; }
/** @note Shares code with rb_define_class_under, change there too. --rue */ VALUE rb_define_module_under(VALUE parent_handle, const char* name) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Module* parent = c_as<Module>(env->get_object(parent_handle)); Symbol* constant = env->state()->symbol(name); LEAVE_CAPI(env->state()); Module* module = rubinius::Helpers::open_module(env->state(), env->current_call_frame(), parent, constant); // The call above could have triggered an Autoload resolve, which may // raise an exception, so we have to check the value returned. if(!module) env->current_ep()->return_to(env); // Grab the module handle before grabbing the lock // so the Module isn't accidentally GC'ed. VALUE module_handle = env->get_handle(module); ENTER_CAPI(env->state()); return module_handle; }
/** @note Shares code with rb_define_module_under, change there too. --rue */ VALUE rb_define_class_under(VALUE outer, const char* name, VALUE super) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Module* module = c_as<Module>(env->get_object(outer)); Class* superclass = c_as<Class>(env->get_object(super ? super : rb_cObject)); Symbol* constant = env->state()->symbol(name); bool created = false; LEAVE_CAPI(env->state()); Class* opened_class = NULL; // Run in a block so OnStack is properly deallocated before we // might do a longjmp because of an exception. { GCTokenImpl gct; OnStack<3> os(env->state(), module, superclass, constant); opened_class = rubinius::Helpers::open_class(env->state(), gct, env->current_call_frame(), module, superclass, constant, &created); } // The call above could have triggered an Autoload resolve, which may // raise an exception, so we have to check the value returned. if(!opened_class) env->current_ep()->return_to(env); // We need to grab the handle before entering back into C-API // code. The problem otherwise can be that the GC runs and // the opened_class is GC'ed. VALUE klass = env->get_handle(opened_class); ENTER_CAPI(env->state()); if(super) rb_funcall(super, rb_intern("inherited"), 1, klass); return klass; }
void capi_raise_break(VALUE obj) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); env->state()->vm()->thread_state()->raise_break(env->get_object(obj), env->scope()->parent()); env->current_ep()->return_to(env); }