void ObjectMemory::find_referers(Object* target, ObjectArray& result) { ObjectMemory::GCInhibit inhibitor(this); ObjectWalker walker(root_state_->om); GCData gc_data(root_state_); // Seed it with the root objects. walker.seed(gc_data); Object* obj = walker.next(); RefererFinder rf(this, target); while(obj) { rf.reset(); rf.scan_object(obj); if(rf.found_p()) { result.push_back(obj); } obj = walker.next(); } }
void ObjectMemory::snapshot(STATE) { // Assign all objects an object id... ObjectMemory::GCInhibit inhibitor(root_state_->om); // Walk the heap over and over until we don't create // any more objects... size_t last_seen = 0; while(last_object_id != last_seen) { last_seen = last_object_id; ObjectWalker walker(root_state_->om); GCData gc_data(state->vm()); // Seed it with the root objects. walker.seed(gc_data); Object* obj = walker.next(); while(obj) { obj->id(state); obj = walker.next(); } } // Now, save the current value of last_object_id, since thats // so we can compare later to find all new objects. last_snapshot_id = last_object_id; std::cout << "Snapshot taken: " << last_snapshot_id << "\n"; }
void ObjectMemory::print_new_since_snapshot(STATE) { // Assign all objects an object id... ObjectMemory::GCInhibit inhibitor(root_state_->om); ObjectWalker walker(root_state_->om); GCData gc_data(root_state_); // Seed it with the root objects. walker.seed(gc_data); Object* obj = walker.next(); // All reference ids are shifted up native_int check_id = (native_int)last_snapshot_id << 1; int count = 0; int bytes = 0; while(obj) { if(!obj->has_id(state) || obj->id(state)->to_native() > check_id) { count++; bytes += obj->size_in_bytes(state->vm()); if(kind_of<String>(obj)) { std::cout << "#<String:" << obj << ">\n"; } else { std::cout << obj->to_s(state, true)->c_str(state) << "\n"; } } obj = walker.next(); } std::cout << count << " objects since snapshot.\n"; std::cout << bytes << " bytes since snapshot.\n"; }
Object* System::vm_find_object(STATE, GCToken gct, Array* arg, Object* callable, CallFrame* calling_environment) { ObjectMemory::GCInhibit inhibitor(state->memory()); // Support an aux mode, where callable is an array and we just append // objects to it rather than #call it. Array* ary = try_as<Array>(callable); if(!ary) ary = nil<Array>(); Array* args = Array::create(state, 1); int total = 0; QueryCondition* condition = create_condition(state, arg); if(!condition) return Fixnum::from(0); Object* ret = cNil; // Special case for looking for an immediate if(Object* obj = condition->immediate()) { if(Symbol* sym = try_as<Symbol>(obj)) { // Check whether this is actually a valid symbol, not // some random non existing symbol. if(!state->shared().symbols.lookup_string(state, sym)) { delete condition; std::ostringstream msg; msg << "Invalid symbol 0x" << std::hex << reinterpret_cast<uintptr_t>(sym); Exception::range_error(state, msg.str().c_str()); return 0; } } if(!ary->nil_p()) { ary->append(state, obj); } else { args->set(state, 0, obj); ret = callable->send(state, calling_environment, G(sym_call), args, cNil, false); } delete condition; if(!ret) return 0; return Fixnum::from(1); } OnStack<2> os(state, ary, args); state->set_call_frame(calling_environment); ObjectWalker walker(state->memory()); GCData gc_data(state->vm()); { StopTheWorld stw(state, gct, calling_environment); // Seed it with the root objects. walker.seed(gc_data); } Object* obj = walker.next(); while(obj) { if(condition->perform(state, obj)) { total++; if(!ary->nil_p()) { ary->append(state, obj); } else { // We call back into Ruby land here, so that might trigger a GC // This ensures we mark all the locations of the current search // queue for the walker, so we update these object references // properly. Object** stack_buf = walker.stack_buf(); size_t stack_size = walker.stack_size(); Object** variable_buffer[stack_size]; for(size_t i = 0; i < stack_size; ++i) { variable_buffer[i] = &stack_buf[i]; } VariableRootBuffer vrb(state->vm()->current_root_buffers(), variable_buffer, stack_size); args->set(state, 0, obj); ret = callable->send(state, calling_environment, G(sym_call), args, cNil, false); if(!ret) break; } } obj = walker.next(); } delete condition; if(!ret) return 0; return Integer::from(state, total); }