Object* run_instance(STATE) { /* These are all referenced, so OnStack is not necessary. Additionally, * thread is pinned, so we do not need to worry about it moving. */ Thread* thread = state->vm()->thread.get(); Array* args = thread->args(); Object* block = thread->block(); if(thread->initialized()->false_p() || args->nil_p() || block->nil_p()) { return cNil; } Object* value = block->send(state, G(sym_call), args, block); /* We explicitly set the current CallFrame reference to NULL because we * are at the top of the stack in terms of managed code. */ state->vm()->set_call_frame(NULL); thread->exception(state, state->vm()->thread_state()->current_exception()); if(state->vm()->thread_state()->raise_reason() == cThreadKill) { thread->value(state, cNil); } else if(value) { thread->value(state, value); } Object* mirror = G(mirror)->send(state, state->symbol("reflect"), Array::from_tuple(state, Tuple::from(state, 1, thread))); mirror->send(state, state->symbol("finish")); return value; }
Object* rbx_cast_for_splat_block_arg(STATE, CallFrame* call_frame, Arguments& args) { if(args.total() == 1) { Object* obj = args.get_argument(0); if(!kind_of<Array>(obj)) { /* Yes, you are reading this code correctly: In Ruby 1.8, calling a * block with these forms { |*| } and { |*a| } with a single argument * that is not an Array and which responds to #to_ary will cause #to_ary * to be called and its return value ignored. Ultimately, the original * object itself is wrapped in an Array and passed to the block. */ if(CBOOL(obj->respond_to(state, state->symbol("to_ary"), cFalse))) { OnStack<1> os(state, obj); Object* ignored = obj->send(state, call_frame, state->symbol("to_ary")); if(!ignored->nil_p() && !kind_of<Array>(ignored)) { Exception::type_error(state, "to_ary must return an Array", call_frame); return 0; } } } Array* ary = Array::create(state, 1); ary->set(state, 0, obj); return ary; } else { Array* ary = Array::create(state, args.total()); for(size_t i = 0; i < args.total(); i++) { ary->set(state, i, args.get_argument(i)); } return ary; } }
unsigned long rb_big2ulong(VALUE obj) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Object* object = env->get_object(obj); if(object->nil_p()) { rb_raise(rb_eTypeError, "no implicit conversion from nil to unsigned long"); } else if(Bignum* big = try_as<Bignum>(object)) { size_t bits = (size_t)mp_count_bits(big->mp_val()); size_t bound = sizeof(long) * CHAR_BIT; unsigned long val = big->to_ulong(); if(big->mp_val()->sign == MP_NEG) { if(bits < bound) { return -val; } else if (bits == bound && val == 1+(unsigned long)(-(LONG_MIN+1))) { return LONG_MIN; } } else if(bits <= bound) { return val; } rb_raise(rb_eRangeError, "bignum out of range of unsigned long"); } rb_raise(rb_eArgError, "parameter is not a Bignum"); return 0; }
Class* open_class(STATE, GCToken gct, CallFrame* call_frame, Module* under, Object* super, Symbol* name, bool* created) { bool found; *created = false; Object* obj = under->get_const(state, name, &found); OnStack<4> os(state, under, super, name, obj); if(found) { TypedRoot<Object*> sup(state, super); if(Autoload* autoload = try_as<Autoload>(obj)) { obj = autoload->resolve(state, gct, call_frame, true); // Check if an exception occurred if(!obj) return NULL; } // Autoload::resolve will return nil if code loading failed, in which // case we ignore the autoload. if(!obj->nil_p()) { return check_superclass(state, call_frame, as<Class>(obj), sup.get()); } } *created = true; return add_class(state, under, super, name); }
Object* rbx_check_keyword(STATE, CallFrame* call_frame, Object* obj) { Object* cls = G(object)->get_const(state, "Hash"); if(!cls->nil_p()) { if(obj->kind_of_p(state, cls)) { return obj; } else { OnStack<1> os(state, cls); Symbol* name = state->symbol("to_hash"); Arguments args(name, obj, 0, 0); Dispatch dis(name); obj = dis.send(state, call_frame, args); if(obj) { if(obj->kind_of_p(state, cls)) { return obj; } else if(!obj->nil_p()) { Exception::type_error(state, "to_hash must return a Hash", call_frame); return NULL; } } else { state->vm()->thread_state()->clear_raise(); } } } return NULL; }
Class* open_class(STATE, GCToken gct, CallFrame* call_frame, Module* under, Object* super, Symbol* name, bool* created) { ConstantMissingReason reason; *created = false; Object* obj = under->get_const(state, name, G(sym_public), &reason); if(reason == vFound) { OnStack<4> os(state, under, super, name, obj); if(Autoload* autoload = try_as<Autoload>(obj)) { obj = autoload->resolve(state, gct, call_frame, under, true); // Check if an exception occurred if(!obj) return NULL; } // Autoload::resolve will return nil if code loading failed, in which // case we ignore the autoload. if(!obj->nil_p()) { return check_superclass(state, call_frame, as<Class>(obj), super); } } *created = true; return add_class(state, under, super, name); }
Module* open_module(STATE, GCToken gct, CallFrame* call_frame, Module* under, Symbol* name) { Module* module; bool found; Object* obj = under->get_const(state, name, &found); OnStack<3> os(state, under, name, obj); if(found) { if(Autoload* autoload = try_as<Autoload>(obj)) { obj = autoload->resolve(state, gct, call_frame, true); } // Check if an exception occurred if(!obj) return NULL; // Autoload::resolve will return nil if code loading failed, in which // case we ignore the autoload. if(!obj->nil_p()) { return as<Module>(obj); } } module = Module::create(state); module->set_name(state, name, under); under->set_const(state, name, module); return module; }
Module* open_module(STATE, Module* under, Symbol* name) { Module* module; ConstantMissingReason reason; Object* obj = under->get_const(state, name, G(sym_public), &reason); if(reason == vFound) { OnStack<3> os(state, under, name, obj); if(Autoload* autoload = try_as<Autoload>(obj)) { obj = autoload->resolve(state, under, true); } // Check if an exception occurred if(!obj) return NULL; // Autoload::resolve will return nil if code loading failed, in which // case we ignore the autoload. if(!obj->nil_p()) { return as<Module>(obj); } } module = Module::create(state); module->set_name(state, name, under); under->set_const(state, name, module); return module; }
Array* Array::to_ary(STATE, Object* value, CallFrame* call_frame) { if(Tuple* tup = try_as<Tuple>(value)) { return Array::from_tuple(state, tup); } if(CBOOL(value->respond_to(state, G(sym_to_ary), cTrue))) { Object* res = value->send(state, call_frame, G(sym_to_ary)); if(!res) return 0; if(Array* ary = try_as<Array>(res)) { return ary; } if(LANGUAGE_18_ENABLED || !res->nil_p()) { Exception::type_error(state, "to_ary should return an Array", call_frame); return 0; } // NOTE: On >= 1.9, if res is nil just fall through and return [value] } Array* ary = Array::create(state, 1); ary->set(state, 0, value); return ary; }
inline bool yield_splat(STATE, CallFrame* call_frame, intptr_t count) { Object* ary = stack_pop(); Object* t1 = call_frame->scope->block(); Arguments args(G(sym_call), t1, count, stack_back_position(count)); if(!ary->nil_p()) { args.append(state, as<Array>(ary)); } if(BlockEnvironment *env = try_as<BlockEnvironment>(t1)) { call_frame->return_value = env->call(state, args); } else if(Proc* proc = try_as<Proc>(t1)) { call_frame->return_value = proc->yield(state, args); } else if(t1->nil_p()) { state->raise_exception(Exception::make_lje(state)); call_frame->return_value = NULL; } else { Dispatch dispatch(G(sym_call)); call_frame->return_value = dispatch.send(state, args); } stack_clear(count); state->vm()->checkpoint(state); CHECK_AND_PUSH(call_frame->return_value); }
void Console::process_requests(STATE) { GCTokenImpl gct; RBX_DTRACE_CONST char* thread_name = const_cast<RBX_DTRACE_CONST char*>("rbx.console.request"); request_vm_->set_name(thread_name); RUBINIUS_THREAD_START(const_cast<RBX_DTRACE_CONST char*>(thread_name), state->vm()->thread_id(), 1); state->vm()->thread->hard_unlock(state, gct, 0); state->gc_independent(gct, 0); while(!request_exit_) { Object* status = fsevent_.get()->wait_for_event(state); if(request_exit_) break; if(status->nil_p()) continue; char* request = read_request(state); if(request) { utilities::thread::Mutex::LockGuard lg(list_lock_); request_list_->push_back(request); response_cond_.signal(); } } state->gc_dependent(gct, 0); RUBINIUS_THREAD_STOP(const_cast<RBX_DTRACE_CONST char*>(thread_name), state->vm()->thread_id(), 1); }
long rb_num2long(VALUE obj) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Object* object = env->get_object(obj); if(object->nil_p()) { rb_raise(rb_eTypeError, "no implicit conversion from nil to Integer"); } else if(Fixnum* fix = try_as<Fixnum>(object)) { return fix->to_long(); } else if(try_as<Bignum>(object)) { return rb_big2long(obj); } else if(try_as<Float>(object)) { return (long)capi_get_float(env, obj)->val; } else if(object->true_p()) { rb_raise(rb_eTypeError, "can't convert true to Integer"); } else if(object->false_p()) { rb_raise(rb_eTypeError, "can't convert false to Integer"); } ID to_int_id = rb_intern("to_int"); if(!rb_respond_to(obj, to_int_id)) { rb_raise(rb_eTypeError, "can't convert %s into Integer", rb_obj_classname(obj)); } obj = rb_funcall(obj, to_int_id, 0); return rb_num2long(obj); }
void MachineCode::fill_opcodes(STATE, CompiledCode* original) { Tuple* ops = original->iseq()->opcodes(); int sends = 0; int constants = 0; for(size_t index = 0; index < total;) { Object* val = ops->at(state, index); if(val->nil_p()) { opcodes[index++] = 0; } else { opcodes[index] = as<Fixnum>(val)->to_native(); size_t width = InstructionSequence::instruction_width(opcodes[index]); switch(width) { case 2: opcodes[index + 1] = as<Fixnum>(ops->at(state, index + 1))->to_native(); break; case 3: opcodes[index + 1] = as<Fixnum>(ops->at(state, index + 1))->to_native(); opcodes[index + 2] = as<Fixnum>(ops->at(state, index + 2))->to_native(); break; } switch(opcodes[index]) { case InstructionSequence::insn_send_method: case InstructionSequence::insn_send_stack: case InstructionSequence::insn_send_stack_with_block: case InstructionSequence::insn_send_stack_with_splat: case InstructionSequence::insn_send_super_stack_with_block: case InstructionSequence::insn_send_super_stack_with_splat: case InstructionSequence::insn_zsuper: case InstructionSequence::insn_meta_send_call: case InstructionSequence::insn_meta_send_op_plus: case InstructionSequence::insn_meta_send_op_minus: case InstructionSequence::insn_meta_send_op_equal: case InstructionSequence::insn_meta_send_op_tequal: case InstructionSequence::insn_meta_send_op_lt: case InstructionSequence::insn_meta_send_op_gt: case InstructionSequence::insn_meta_to_s: case InstructionSequence::insn_check_serial: case InstructionSequence::insn_check_serial_private: case InstructionSequence::insn_call_custom: sends++; break; case InstructionSequence::insn_push_const_fast: case InstructionSequence::insn_find_const_fast: constants++; break; } index += width; } } initialize_call_sites(state, original, sends); initialize_constant_caches(state, original, constants); }
inline void restore_exception_state(STATE, CallFrame* call_frame) { Object* top = stack_pop(); if(top->nil_p()) { state->vm()->thread_state()->clear(); } else { state->vm()->thread_state()->set_state(state, as<ThreadState>(top)); } }
Array* CompactLookupTable::filtered_keys(STATE, ObjectMatcher& match) { Array* ary = Array::create(state, COMPACTLOOKUPTABLE_SIZE / 2); for(unsigned int i = 0; i < COMPACTLOOKUPTABLE_SIZE; i += 2) { Object* key = at(state, i); if(!key->nil_p() && match.match_p(state, key)) ary->append(state, key); } return ary; }
LookupTable* CompactLookupTable::to_lookuptable(STATE) { LookupTable* tbl = (LookupTable*)LookupTable::create(state); for(unsigned int i = 0; i < COMPACTLOOKUPTABLE_SIZE; i += 2) { Object* key = at(state, i); if(!key->nil_p()) tbl->store(state, key, at(state, i + 1)); } return tbl; }
Array* CompactLookupTable::values(STATE) { Array* ary = Array::create(state, COMPACTLOOKUPTABLE_SIZE / 2); for(unsigned int i = 0; i < COMPACTLOOKUPTABLE_SIZE; i += 2) { Object* key = at(state, i); if(!key->nil_p()) ary->append(state, at(state, i + 1)); } return ary; }
Object* MatchData::last_capture(STATE) { if(region_->num_fields() == 0) return cNil; native_int captures = region_->num_fields(); while(captures--) { Object* capture = nth_capture(state, captures); if(!capture->nil_p()) { return capture; } } return cNil; }
Integer* ObjectMemory::assign_object_id_ivar(STATE, Object* obj) { SYNC(state); Object* id = obj->get_ivar(state, G(sym_object_id)); if(id->nil_p()) { /* All references have an even object_id. last_object_id starts out at 0 * but we don't want to use 0 as an object_id, so we just add before using */ id = Integer::from(state, ++state->memory()->last_object_id << TAG_REF_WIDTH); obj->set_ivar(state, G(sym_object_id), id); } return as<Integer>(id); }
/** * Runs rbx from the filesystem. Searches for the Rubinius runtime files * according to the algorithm in find_runtime(). */ void Environment::run_from_filesystem() { int i = 0; state->vm()->set_root_stack(reinterpret_cast<uintptr_t>(&i), VM::cStackDepthMax); std::string runtime = system_prefix() + RBX_RUNTIME_PATH; load_platform_conf(runtime); boot_vm(); start_finalizer(); load_argv(argc_, argv_); start_signals(); state->vm()->initialize_config(); load_tool(); G(rubinius)->set_const(state, "Signature", Integer::from(state, signature_)); if(LANGUAGE_20_ENABLED(state)) { runtime += "/20"; } else if(LANGUAGE_19_ENABLED(state)) { runtime += "/19"; } else { runtime += "/18"; } G(rubinius)->set_const(state, "RUNTIME_PATH", String::create(state, runtime.c_str(), runtime.size())); load_kernel(runtime); shared->finalizer_handler()->start_thread(state); run_file(runtime + "/loader.rbc"); state->vm()->thread_state()->clear(); Object* loader = G(rubinius)->get_const(state, state->symbol("Loader")); if(loader->nil_p()) { rubinius::bug("Unable to find loader"); } OnStack<1> os(state, loader); Object* inst = loader->send(state, 0, state->symbol("new")); if(inst) { OnStack<1> os2(state, inst); inst->send(state, 0, state->symbol("main")); } else { rubinius::bug("Unable to instantiate loader"); } }
Object* CompactLookupTable::store(STATE, Object* key, Object* val) { for(unsigned int i = 0; i < COMPACTLOOKUPTABLE_SIZE; i += 2) { Object* tmp = at(state, i); if(tmp == key || tmp->nil_p()) { put(state, i, key); put(state, i + 1, val); return Qtrue; } } return Qfalse; }
void Transcoding::declare(STATE, const char* from, const char* to, const char* lib) { LookupTable* map = Encoding::transcoding_map(state); Object* obj = map->fetch(state, encoding_symbol(state, from)); LookupTable* table; if(obj->nil_p()) { table = LookupTable::create(state); map->store(state, encoding_symbol(state, from), table); } else { table = as<LookupTable>(obj); } table->store(state, encoding_symbol(state, to), String::create(state, lib)); }
double rb_num2dbl(VALUE val) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Object* object = env->get_object(val); if(object->nil_p()) { rb_raise(rb_eTypeError, "no implicit conversion from nil to Float"); } else if(try_as<String>(object)) { rb_raise(rb_eTypeError, "no implicit conversion from String to Float"); } else if(!try_as<Float>(object)) { val = rb_Float(val); } return capi_get_float(env, val)->val; }
void Transcoding::define(STATE, OnigTranscodingType* tr) { LookupTable* map = Encoding::transcoding_map(state); Object* obj = map->fetch(state, encoding_symbol(state, tr->src_encoding)); LookupTable* table; if(obj->nil_p()) { table = LookupTable::create(state); map->store(state, encoding_symbol(state, tr->src_encoding), table); } else { table = as<LookupTable>(obj); } Transcoding* t = Transcoding::create(state, tr); table->store(state, encoding_symbol(state, tr->dst_encoding), t); }
Object* Thread::main_thread(STATE) { GCTokenImpl gct; state->vm()->thread->hard_unlock(state, gct, 0); std::string& runtime = state->shared().env()->runtime_path(); G(rubinius)->set_const(state, "Signature", Integer::from(state, state->shared().env()->signature())); G(rubinius)->set_const(state, "RUNTIME_PATH", String::create(state, runtime.c_str(), runtime.size())); state->vm()->thread->pid(state, Fixnum::from(gettid())); state->shared().env()->load_core(state, runtime); state->vm()->thread->alive(state, cTrue); state->vm()->thread_state()->clear(); state->shared().start_console(state); state->shared().start_metrics(state); Object* klass = G(rubinius)->get_const(state, state->symbol("Loader")); if(klass->nil_p()) { rubinius::bug("unable to find class Rubinius::Loader"); } Object* instance = 0; OnStack<1> os(state, instance); instance = klass->send(state, 0, state->symbol("new")); if(instance) { state->shared().env()->set_loader(instance); } else { rubinius::bug("unable to instantiate Rubinius::Loader"); } // Enable the JIT after the core library has loaded G(jit)->enable(state); Object* exit = instance->send(state, 0, state->symbol("main")); state->shared().signals()->system_exit(state->vm()->thread_state()->raise_value()); return exit; }
long rb_num2long(VALUE obj) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Object* object = env->get_object(obj); if(object->nil_p()) { rb_raise(rb_eTypeError, "no implicit conversion from nil to Integer"); } else if(Fixnum* fix = try_as<Fixnum>(object)) { return fix->to_long(); } else if(Bignum* big = try_as<Bignum>(object)) { return big->to_long(); } else if(try_as<Float>(object)) { return (long)capi_get_float(env, obj)->val; } obj = rb_funcall(obj, rb_intern("to_int"), 0); return rb_num2long(obj); }
VALUE rb_Integer(VALUE object_handle) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Object* object = env->get_object(object_handle); if(kind_of<Fixnum>(object) || kind_of<Bignum>(object)) { return object_handle; } else if(String* str = try_as<String>(object)) { Object* ret = str->to_i(env->state(), Fixnum::from(0), cTrue); if(ret->nil_p()) { rb_raise(rb_eArgError, "invalid value for Integer"); } return env->get_handle(ret); } return rb_convert_type(object_handle, 0, "Integer", "to_i"); }
bool VM::wakeup(STATE, GCToken gct, CallFrame* call_frame) { SYNC(state); set_check_local_interrupts(); Object* wait = waiting_object_.get(); if(park_->parked_p()) { park_->unpark(); return true; } else if(vm_jit_.interrupt_with_signal_) { #ifdef RBX_WINDOWS // TODO: wake up the thread #else pthread_kill(os_thread_, SIGVTALRM); #endif UNSYNC; // Wakeup any locks hanging around with contention om->release_contention(state, gct, call_frame); return true; } else if(!wait->nil_p()) { // We shouldn't hold the VM lock and the IH lock at the same time, // other threads can grab them and deadlock. InflatedHeader* ih = wait->inflated_header(state); UNSYNC; ih->wakeup(state, gct, call_frame, wait); return true; } else { Channel* chan = waiting_channel_.get(); if(!chan->nil_p()) { UNSYNC; om->release_contention(state, gct, call_frame); chan->send(state, gct, cNil, call_frame); return true; } else if(custom_wakeup_) { UNSYNC; om->release_contention(state, gct, call_frame); (*custom_wakeup_)(custom_wakeup_data_); return true; } return false; } }
bool VM::wakeup(STATE) { utilities::thread::SpinLock::LockGuard guard(interrupt_lock_); set_check_local_interrupts(); Object* wait = waiting_object_.get(); if(park_->parked_p()) { park_->unpark(); return true; } else if(interrupt_with_signal_) { #ifdef RBX_WINDOWS // TODO: wake up the thread #else pthread_kill(os_thread_, SIGVTALRM); #endif interrupt_lock_.unlock(); // Wakeup any locks hanging around with contention memory()->release_contention(state); return true; } else if(!wait->nil_p()) { // We shouldn't hold the VM lock and the IH lock at the same time, // other threads can grab them and deadlock. InflatedHeader* ih = wait->inflated_header(state); interrupt_lock_.unlock(); ih->wakeup(state, wait); return true; } else { Channel* chan = waiting_channel_.get(); if(!chan->nil_p()) { interrupt_lock_.unlock(); memory()->release_contention(state); chan->send(state, cNil); return true; } else if(custom_wakeup_) { interrupt_lock_.unlock(); memory()->release_contention(state); (*custom_wakeup_)(custom_wakeup_data_); return true; } return false; } }
long long rb_big2ll(VALUE obj) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); Object* object = env->get_object(obj); if(object->nil_p()) { rb_raise(rb_eTypeError, "no implicit conversion from nil to unsigned long"); } else if(Bignum* big = try_as<Bignum>(object)) { if((size_t)mp_count_bits(big->mp_val()) > sizeof(long long) * CHAR_BIT) rb_raise(rb_eRangeError, "bignum too big to convert into long long"); long long val = big->to_ulong_long(); if(big->mp_val()->sign == MP_NEG) return -val; return val; } rb_raise(rb_eArgError, "parameter is not a Bignum"); return 0; }