Пример #1
0
  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";
  }
Пример #2
0
  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();
    }
  }
Пример #3
0
  Object* System::vm_deoptimize_all(STATE, Object* o_disable) {
    ObjectWalker walker(state->om);
    GCData gc_data(state);

    // Seed it with the root objects.
    walker.seed(gc_data);

    Object* obj = walker.next();

    int total = 0;

    bool disable = RTEST(o_disable);

    while(obj) {
      if(CompiledMethod* cm = try_as<CompiledMethod>(obj)) {
        if(VMMethod* vmm = cm->backend_method()) {
          vmm->deoptimize(state, cm, disable);
        }
        total++;
      }

      obj = walker.next();
    }

    return Integer::from(state, total);
  }
Пример #4
0
  void VM::collect_maybe(CallFrame* call_frame) {
    this->set_call_frame(call_frame);

    // Stops all other threads, so we're only here by ourselves.
    StopTheWorld guard(this);

    GCData gc_data(this);

    if(om->collect_young_now) {
      if(shared.config.gc_show) {
        std::cout << get_current_time() << " [GC] Running young gen\n";
      }

      om->collect_young_now = false;
      om->collect_young(gc_data);
    }

    if(om->collect_mature_now) {
      if(shared.config.gc_show) {
        std::cout << get_current_time() << " [GC] Running mature gen\n";
      }

      om->collect_mature_now = false;
      om->collect_mature(gc_data);

    }
  }
Пример #5
0
  void VM::collect(CallFrame* call_frame) {
    this->set_call_frame(call_frame);

    // Stops all other threads, so we're only here by ourselves.
    StopTheWorld guard(this);

    GCData gc_data(this);

    om->collect_young(gc_data);
    om->collect_mature(gc_data);
  }
Пример #6
0
  void VM::collect(CallFrame* call_frame) {
    this->set_call_frame(call_frame);

    // Don't go any further unless we're allowed to GC.
    if(!om->can_gc()) return;

    // Stops all other threads, so we're only here by ourselves.
    StopTheWorld guard(this);

    GCData gc_data(this);

    om->collect_young(gc_data);
    om->collect_mature(gc_data);

    om->run_finalizers(this);
  }
Пример #7
0
  void Env::find_all_compiled_code(compiled_code_iterator func, void* data) {
    ObjectWalker walker(private_->state()->memory());
    GCData gc_data(private_->state()->vm());

    walker.seed(gc_data);

    Env* env = private_->state()->vm()->tooling_env();
    Object* obj = walker.next();

    while(obj) {
      if(CompiledCode* code = try_as<CompiledCode>(obj)) {
        func(env, rbxti::o(code), data);
      }

      obj = walker.next();
    }
  }
Пример #8
0
  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";
  }
Пример #9
0
  void VM::collect_maybe(CallFrame* call_frame) {
    this->set_call_frame(call_frame);

    // Don't go any further unless we're allowed to GC.
    if(!om->can_gc()) return;

    // Stops all other threads, so we're only here by ourselves.
    StopTheWorld guard(this);

    GCData gc_data(this);

    uint64_t start_time = 0;

    if(om->collect_young_now) {
      if(shared.config.gc_show) {
        start_time = get_current_time();
      }

      YoungCollectStats stats;

#ifdef RBX_PROFILER
      if(unlikely(shared.profiling())) {
        profiler::MethodEntry method(this, profiler::kYoungGC);
        om->collect_young(gc_data, &stats);
      } else {
        om->collect_young(gc_data, &stats);
      }
#else
      om->collect_young(gc_data, &stats);
#endif

      if(shared.config.gc_show) {
        uint64_t fin_time = get_current_time();
        int diff = (fin_time - start_time) / 1000000;

        fprintf(stderr, "[GC %0.1f%% %d/%d %d %2dms]\n",
                  stats.percentage_used,
                  stats.promoted_objects,
                  stats.excess_objects,
                  stats.lifetime,
                  diff);
      }
    }

    if(om->collect_mature_now) {
      int before_kb = 0;

      if(shared.config.gc_show) {
        start_time = get_current_time();
        before_kb = om->mature_bytes_allocated() / 1024;
      }

#ifdef RBX_PROFILER
      if(unlikely(shared.profiling())) {
        profiler::MethodEntry method(this, profiler::kMatureGC);
        om->collect_mature(gc_data);
      } else {
        om->collect_mature(gc_data);
      }
#else
      om->collect_mature(gc_data);
#endif

      if(shared.config.gc_show) {
        uint64_t fin_time = get_current_time();
        int diff = (fin_time - start_time) / 1000000;
        int kb = om->mature_bytes_allocated() / 1024;
        fprintf(stderr, "[Full GC %dkB => %dkB %2dms]\n",
            before_kb,
            kb,
            diff);
      }

    }

    om->run_finalizers(this);
  }
Пример #10
0
  void ObjectMemory::collect_maybe(STATE, GCToken gct, CallFrame* call_frame) {
    // Don't go any further unless we're allowed to GC.
    if(!can_gc()) return;

    while(!state->stop_the_world()) {
      state->checkpoint(gct, call_frame);

      // Someone else got to the GC before we did! No problem, all done!
      if(!collect_young_now && !collect_mature_now) return;
    }

    // Ok, everyone in stopped! LET'S GC!
    SYNC(state);

    state->shared().finalizer_handler()->start_collection(state);

    if(cDebugThreading) {
      std::cerr << std::endl << "[" << state
                << " WORLD beginning GC.]" << std::endl;
    }


    if(collect_young_now) {
      GCData gc_data(state->vm());
      YoungCollectStats stats;

      RUBINIUS_GC_BEGIN(0);
#ifdef RBX_PROFILER
      if(unlikely(state->vm()->tooling())) {
        tooling::GCEntry method(state, tooling::GCYoung);
        collect_young(state, &gc_data, &stats);
      } else {
        collect_young(state, &gc_data, &stats);
      }
#else
      collect_young(state, &gc_data, &stats);
#endif
      RUBINIUS_GC_END(0);
      print_young_stats(state, &gc_data, &stats);
    }

    if(collect_mature_now) {
      GCData* gc_data = new GCData(state->vm());
      RUBINIUS_GC_BEGIN(1);
#ifdef RBX_PROFILER
      if(unlikely(state->vm()->tooling())) {
        tooling::GCEntry method(state, tooling::GCMature);
        collect_mature(state, gc_data);
      } else {
        collect_mature(state, gc_data);
      }
#else
      collect_mature(state, gc_data);
#endif
      if(!mature_mark_concurrent_) {
        collect_mature_finish(state, gc_data);
        print_mature_stats(state, gc_data);
      }
    }

    state->restart_world();

    UNSYNC;
  }
Пример #11
0
  void ObjectMemory::collect_maybe(STATE, GCToken gct, CallFrame* call_frame) {
    // Don't go any further unless we're allowed to GC.
    if(!can_gc()) return;

    while(!state->stop_the_world()) {
      state->checkpoint(gct, call_frame);

      // Someone else got to the GC before we did! No problem, all done!
      if(!collect_young_now && !collect_mature_now) return;
    }

    // Ok, everyone in stopped! LET'S GC!

    SYNC(state);

    state->shared().finalizer_handler()->start_collection(state);

    if(cDebugThreading) {
      std::cerr << std::endl << "[" << state
                << " WORLD beginning GC.]" << std::endl;
    }

    GCData gc_data(state->vm(), gct);

    uint64_t start_time = 0;

    if(collect_young_now) {
      if(state->shared().config.gc_show) {
        start_time = get_current_time();
      }

      YoungCollectStats stats;

#ifdef RBX_PROFILER
      if(unlikely(state->vm()->tooling())) {
        tooling::GCEntry method(state, tooling::GCYoung);
        collect_young(gc_data, &stats);
      } else {
        collect_young(gc_data, &stats);
      }
#else
      collect_young(gc_data, &stats);
#endif

      if(state->shared().config.gc_show) {
        uint64_t fin_time = get_current_time();
        int diff = (fin_time - start_time) / 1000000;

        std::cerr << "[GC " << std::fixed << std::setprecision(1) << stats.percentage_used << "% "
                  << stats.promoted_objects << "/" << stats.excess_objects << " "
                  << stats.lifetime << " " << diff << "ms]" << std::endl;

        if(state->shared().config.gc_noisy) {
          std::cerr << "\a" << std::flush;
        }
      }
    }

    if(collect_mature_now) {
      size_t before_kb = 0;

      if(state->shared().config.gc_show) {
        start_time = get_current_time();
        before_kb = mature_bytes_allocated() / 1024;
      }

#ifdef RBX_PROFILER
      if(unlikely(state->vm()->tooling())) {
        tooling::GCEntry method(state, tooling::GCMature);
        collect_mature(gc_data);
      } else {
        collect_mature(gc_data);
      }
#else
      collect_mature(gc_data);
#endif

      if(state->shared().config.gc_show) {
        uint64_t fin_time = get_current_time();
        int diff = (fin_time - start_time) / 1000000;
        size_t kb = mature_bytes_allocated() / 1024;
        std::cerr << "[Full GC " << before_kb << "kB => " << kb << "kB " << diff << "ms]" << std::endl;

        if(state->shared().config.gc_noisy) {
          std::cerr << "\a\a" << std::flush;
        }
      }
    }

    state->shared().finalizer_handler()->finish_collection(state);
    state->restart_world();

    UNSYNC;
  }
Пример #12
0
  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);
  }