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; } } }
Object* const_get(STATE, Symbol* name, ConstantMissingReason* reason, Object* filter, bool replace_autoload) { LexicalScope *cur; Object* result; *reason = vNonExistent; CallFrame* frame = state->vm()->get_ruby_frame(); // Ok, this has to be explained or it will be considered black magic. // The scope chain always ends with an entry at the top that contains // a parent of nil, and a module of Object. This entry is put in // regardless of lexical scoping, it's the fallback scope (the default // scope). This is not case when deriving from BasicObject, which is // explained later. // // When looking up a constant, we don't want to consider the fallback // scope (ie, Object) initially because we need to lookup up // the superclass chain first, because falling back on the default. // // The rub comes from the fact that if a user explicitly opens up // Object in their code, we DO consider it. Like: // // class Idiot // A = 2 // end // // class ::Object // A = 1 // class Stupid < Idiot // def foo // p A // end // end // end // // In this code, when A is looked up, Object must be considering during // the scope walk, NOT during the superclass walk. // // So, in this case, foo would print "1", not "2". // // As indicated above, the fallback scope isn't used when the superclass // chain directly rooted from BasicObject. To determine this is the // case, we record whether Object is seen when looking up the superclass // chain. If Object isn't seen, this means we are directly deriving from // BasicObject. cur = frame->lexical_scope(); while(!cur->nil_p()) { // Detect the toplevel scope (the default) and get outta dodge. if(cur->top_level_p(state)) break; result = cur->module()->get_const(state, name, G(sym_private), reason, false, replace_autoload); if(*reason == vFound) { if(result != filter) return result; *reason = vNonExistent; } cur = cur->parent(); } // Now look up the superclass chain. Module *fallback = G(object); cur = frame->lexical_scope(); if(!cur->nil_p()) { bool object_seen = false; Module* mod = cur->module(); while(!mod->nil_p()) { if(mod == G(object)) { object_seen = true; } if(!object_seen && mod == G(basicobject)) { fallback = NULL; } result = mod->get_const(state, name, G(sym_private), reason, false, replace_autoload); if(*reason == vFound) { if(result != filter) return result; *reason = vNonExistent; } mod = mod->superclass(); } } // Lastly, check the fallback scope (=Object) specifically if needed if(fallback) { result = fallback->get_const(state, name, G(sym_private), reason, true, replace_autoload); if(*reason == vFound) { if(result != filter) return result; *reason = vNonExistent; } } return cNil; }