use builtins for GC.

Define a part of GC in gc.rb.
This commit is contained in:
Koichi Sasada 2019-11-08 15:27:32 +09:00
parent 2eb02dfd3b
commit 8fa41971c2
4 changed files with 43 additions and 214 deletions

View File

@ -14,6 +14,7 @@ rbconfig.rb
trace_point.rb
ast.rb
io.rb
gc.rb
# the lib/ directory (which has its own .document file)
lib

View File

@ -1108,6 +1108,9 @@ load_ast.inc: $(srcdir)/ast.rb $(srcdir)/tool/mk_builtin_loader.rb
load_io.inc: $(srcdir)/io.rb $(srcdir)/tool/mk_builtin_loader.rb
$(Q) $(BASERUBY) $(srcdir)/tool/mk_builtin_loader.rb $(srcdir)/io.rb
load_gc.inc: $(srcdir)/gc.rb $(srcdir)/tool/mk_builtin_loader.rb
$(Q) $(BASERUBY) $(srcdir)/tool/mk_builtin_loader.rb $(srcdir)/gc.rb
$(srcdir)/revision.h:
$(Q)$(gnumake:yes=#) $(RM) $(@F)
$(Q)$(gnumake:yes=#) exit > $@ || exit > $(@F)
@ -2090,6 +2093,7 @@ gc.$(OBJEXT): $(CCAN_DIR)/str/str.h
gc.$(OBJEXT): $(hdrdir)/ruby.h
gc.$(OBJEXT): $(hdrdir)/ruby/ruby.h
gc.$(OBJEXT): {$(VPATH)}assert.h
gc.$(OBJEXT): {$(VPATH)}builtin.h
gc.$(OBJEXT): {$(VPATH)}config.h
gc.$(OBJEXT): {$(VPATH)}constant.h
gc.$(OBJEXT): {$(VPATH)}debug.h
@ -2104,6 +2108,7 @@ gc.$(OBJEXT): {$(VPATH)}id_table.h
gc.$(OBJEXT): {$(VPATH)}intern.h
gc.$(OBJEXT): {$(VPATH)}internal.h
gc.$(OBJEXT): {$(VPATH)}io.h
gc.$(OBJEXT): {$(VPATH)}load_gc.inc
gc.$(OBJEXT): {$(VPATH)}method.h
gc.$(OBJEXT): {$(VPATH)}missing.h
gc.$(OBJEXT): {$(VPATH)}mjit.h

249
gc.c
View File

@ -24,6 +24,7 @@
#include "internal.h"
#include "eval_intern.h"
#include "vm_core.h"
#include "builtin.h"
#include "gc.h"
#include "constant.h"
#include "ruby_atomic.h"
@ -7459,61 +7460,18 @@ garbage_collect_with_gvl(rb_objspace_t *objspace, int reason)
}
}
/*
* call-seq:
* GC.start -> nil
* ObjectSpace.garbage_collect -> nil
* include GC; garbage_collect -> nil
* GC.start(full_mark: true, immediate_sweep: true) -> nil
* ObjectSpace.garbage_collect(full_mark: true, immediate_sweep: true) -> nil
* include GC; garbage_collect(full_mark: true, immediate_sweep: true) -> nil
*
* Initiates garbage collection, even if manually disabled.
*
* This method is defined with keyword arguments that default to true:
*
* def GC.start(full_mark: true, immediate_sweep: true); end
*
* Use full_mark: false to perform a minor GC.
* Use immediate_sweep: false to defer sweeping (use lazy sweep).
*
* Note: These keyword arguments are implementation and version dependent. They
* are not guaranteed to be future-compatible, and may be ignored if the
* underlying implementation does not support them.
*/
static VALUE
gc_start_internal(int argc, VALUE *argv, VALUE self)
gc_start_internal(rb_execution_context_t *ec, VALUE self, VALUE full_mark, VALUE immediate_mark, VALUE immediate_sweep)
{
rb_objspace_t *objspace = &rb_objspace;
int reason = GPR_FLAG_FULL_MARK | GPR_FLAG_IMMEDIATE_MARK |
GPR_FLAG_IMMEDIATE_SWEEP | GPR_FLAG_METHOD;
VALUE opt = Qnil;
static ID keyword_ids[3];
int reason = GPR_FLAG_FULL_MARK |
GPR_FLAG_IMMEDIATE_MARK |
GPR_FLAG_IMMEDIATE_SWEEP |
GPR_FLAG_METHOD;
rb_scan_args(argc, argv, "0:", &opt);
if (!NIL_P(opt)) {
VALUE kwvals[3];
if (!keyword_ids[0]) {
keyword_ids[0] = rb_intern("full_mark");
keyword_ids[1] = rb_intern("immediate_mark");
keyword_ids[2] = rb_intern("immediate_sweep");
}
rb_get_kwargs(opt, keyword_ids, 0, 3, kwvals);
if (kwvals[0] != Qundef && !RTEST(kwvals[0])) {
reason &= ~GPR_FLAG_FULL_MARK;
}
if (kwvals[1] != Qundef && !RTEST(kwvals[1])) {
reason &= ~GPR_FLAG_IMMEDIATE_MARK;
}
if (kwvals[2] != Qundef && !RTEST(kwvals[2])) {
reason &= ~GPR_FLAG_IMMEDIATE_SWEEP;
}
}
if (!RTEST(full_mark)) reason &= ~GPR_FLAG_FULL_MARK;
if (!RTEST(immediate_mark)) reason &= ~GPR_FLAG_IMMEDIATE_MARK;
if (!RTEST(immediate_sweep)) reason &= ~GPR_FLAG_IMMEDIATE_SWEEP;
garbage_collect(objspace, reason);
gc_finalize_deferred(objspace);
@ -8479,7 +8437,7 @@ gc_compact(rb_objspace_t *objspace, int use_toward_empty, int use_double_pages,
}
static VALUE
rb_gc_compact(VALUE mod)
rb_gc_compact(rb_execution_context_t *ec, VALUE self)
{
rb_objspace_t *objspace = &rb_objspace;
if (dont_gc) return Qnil;
@ -8728,18 +8686,8 @@ rb_gc_count(void)
return rb_objspace.profile.count;
}
/*
* call-seq:
* GC.count -> Integer
*
* The number of times GC occurred.
*
* It returns the number of times GC occurred since the process started.
*
*/
static VALUE
gc_count(VALUE self)
gc_count(rb_execution_context_t *ec, VALUE self)
{
return SIZET2NUM(rb_gc_count());
}
@ -8844,30 +8792,17 @@ rb_gc_latest_gc_info(VALUE key)
return gc_info_decode(objspace, key, 0);
}
/*
* call-seq:
* GC.latest_gc_info -> {:gc_by=>:newobj}
* GC.latest_gc_info(hash) -> hash
* GC.latest_gc_info(:major_by) -> :malloc
*
* Returns information about the most recent garbage collection.
*/
static VALUE
gc_latest_gc_info(int argc, VALUE *argv, VALUE self)
gc_latest_gc_info(rb_execution_context_t *ec, VALUE self, VALUE arg)
{
rb_objspace_t *objspace = &rb_objspace;
VALUE arg = Qnil;
if (rb_check_arity(argc, 0, 1) == 1) {
arg = argv[0];
if (!SYMBOL_P(arg) && !RB_TYPE_P(arg, T_HASH)) {
rb_raise(rb_eTypeError, "non-hash or symbol given");
}
}
else {
if (NIL_P(arg)) {
arg = rb_hash_new();
}
else if (!SYMBOL_P(arg) && !RB_TYPE_P(arg, T_HASH)) {
rb_raise(rb_eTypeError, "non-hash or symbol given");
}
return gc_info_decode(objspace, arg, 0);
}
@ -9187,69 +9122,23 @@ gc_stat_internal(VALUE hash_or_sym)
return 0;
}
/*
* call-seq:
* GC.stat -> Hash
* GC.stat(hash) -> hash
* GC.stat(:key) -> Numeric
*
* Returns a Hash containing information about the GC.
*
* The hash includes information about internal statistics about GC such as:
*
* {
* :count=>0,
* :heap_allocated_pages=>24,
* :heap_sorted_length=>24,
* :heap_allocatable_pages=>0,
* :heap_available_slots=>9783,
* :heap_live_slots=>7713,
* :heap_free_slots=>2070,
* :heap_final_slots=>0,
* :heap_marked_slots=>0,
* :heap_eden_pages=>24,
* :heap_tomb_pages=>0,
* :total_allocated_pages=>24,
* :total_freed_pages=>0,
* :total_allocated_objects=>7796,
* :total_freed_objects=>83,
* :malloc_increase_bytes=>2389312,
* :malloc_increase_bytes_limit=>16777216,
* :minor_gc_count=>0,
* :major_gc_count=>0,
* :remembered_wb_unprotected_objects=>0,
* :remembered_wb_unprotected_objects_limit=>0,
* :old_objects=>0,
* :old_objects_limit=>0,
* :oldmalloc_increase_bytes=>2389760,
* :oldmalloc_increase_bytes_limit=>16777216
* }
*
* The contents of the hash are implementation specific and may be changed in
* the future.
*
* This method is only expected to work on C Ruby.
*
*/
static VALUE
gc_stat(int argc, VALUE *argv, VALUE self)
gc_stat(rb_execution_context_t *ec, VALUE self, VALUE arg) // arg is (nil || hash || symbol)
{
VALUE arg = Qnil;
if (rb_check_arity(argc, 0, 1) == 1) {
arg = argv[0];
if (SYMBOL_P(arg)) {
size_t value = gc_stat_internal(arg);
return SIZET2NUM(value);
}
else if (!RB_TYPE_P(arg, T_HASH)) {
rb_raise(rb_eTypeError, "non-hash or symbol given");
}
}
else {
if (NIL_P(arg)) {
arg = rb_hash_new();
}
else if (SYMBOL_P(arg)) {
size_t value = gc_stat_internal(arg);
return SIZET2NUM(value);
}
else if (RB_TYPE_P(arg, T_HASH)) {
// ok
}
else {
rb_raise(rb_eTypeError, "non-hash or symbol given");
}
gc_stat_internal(arg);
return arg;
}
@ -9267,15 +9156,8 @@ rb_gc_stat(VALUE key)
}
}
/*
* call-seq:
* GC.stress -> integer, true or false
*
* Returns current status of GC stress mode.
*/
static VALUE
gc_stress_get(VALUE self)
gc_stress_get(rb_execution_context_t *ec, VALUE self)
{
rb_objspace_t *objspace = &rb_objspace;
return ruby_gc_stress_mode;
@ -9288,25 +9170,8 @@ gc_stress_set(rb_objspace_t *objspace, VALUE flag)
objspace->gc_stress_mode = flag;
}
/*
* call-seq:
* GC.stress = flag -> flag
*
* Updates the GC stress mode.
*
* When stress mode is enabled, the GC is invoked at every GC opportunity:
* all memory and object allocations.
*
* Enabling stress mode will degrade performance, it is only for debugging.
*
* flag can be true, false, or an integer bit-ORed following flags.
* 0x01:: no major GC
* 0x02:: no immediate sweep
* 0x04:: full mark after malloc/calloc/realloc
*/
static VALUE
gc_stress_set_m(VALUE self, VALUE flag)
gc_stress_set_m(rb_execution_context_t *ec, VALUE self, VALUE flag)
{
rb_objspace_t *objspace = &rb_objspace;
gc_stress_set(objspace, flag);
@ -9323,20 +9188,8 @@ rb_gc_enable(void)
return old ? Qtrue : Qfalse;
}
/*
* call-seq:
* GC.enable -> true or false
*
* Enables garbage collection, returning +true+ if garbage
* collection was previously disabled.
*
* GC.disable #=> false
* GC.enable #=> true
* GC.enable #=> false
*
*/
static VALUE
gc_enable(VALUE _)
gc_enable(rb_execution_context_t *ec, VALUE _)
{
return rb_gc_enable();
}
@ -9359,20 +9212,8 @@ rb_gc_disable(void)
return rb_gc_disable_no_rest();
}
/*
* call-seq:
* GC.disable -> true or false
*
* Disables garbage collection, returning +true+ if garbage
* collection was already disabled.
*
* GC.disable #=> false
* GC.disable #=> true
*
*/
static VALUE
gc_disable(VALUE _)
gc_disable(rb_execution_context_t *ec, VALUE _)
{
return rb_gc_disable();
}
@ -11960,16 +11801,7 @@ rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
* See also GC.count, GC.malloc_allocated_size and GC.malloc_allocations
*/
/*
* The GC module provides an interface to Ruby's mark and
* sweep garbage collection mechanism.
*
* Some of the underlying methods are also available via the ObjectSpace
* module.
*
* You may obtain information about the operation of the GC through
* GC::Profiler.
*/
#include "load_gc.inc"
void
Init_GC(void)
@ -11980,16 +11812,7 @@ Init_GC(void)
VALUE gc_constants;
rb_mGC = rb_define_module("GC");
rb_define_singleton_method(rb_mGC, "start", gc_start_internal, -1);
rb_define_singleton_method(rb_mGC, "enable", gc_enable, 0);
rb_define_singleton_method(rb_mGC, "disable", gc_disable, 0);
rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0);
rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set_m, 1);
rb_define_singleton_method(rb_mGC, "count", gc_count, 0);
rb_define_singleton_method(rb_mGC, "stat", gc_stat, -1);
rb_define_singleton_method(rb_mGC, "latest_gc_info", gc_latest_gc_info, -1);
rb_define_singleton_method(rb_mGC, "compact", rb_gc_compact, 0);
rb_define_method(rb_mGC, "garbage_collect", gc_start_internal, -1);
load_gc();
gc_constants = rb_hash_new();
rb_hash_aset(gc_constants, ID2SYM(rb_intern("RVALUE_SIZE")), SIZET2NUM(sizeof(RVALUE)));
@ -12011,8 +11834,8 @@ Init_GC(void)
rb_define_singleton_method(rb_mProfiler, "total_time", gc_profile_total_time, 0);
rb_mObjSpace = rb_define_module("ObjectSpace");
rb_define_module_function(rb_mObjSpace, "each_object", os_each_obj, -1);
rb_define_module_function(rb_mObjSpace, "garbage_collect", gc_start_internal, -1);
rb_define_module_function(rb_mObjSpace, "define_finalizer", define_final, -1);
rb_define_module_function(rb_mObjSpace, "undefine_finalizer", undefine_final, 1);

View File

@ -55,7 +55,6 @@ rb_call_inits(void)
CALL(Proc);
CALL(Binding);
CALL(Math);
CALL(GC);
CALL(Enumerator);
CALL(VM);
CALL(ISeq);
@ -70,6 +69,7 @@ rb_call_inits(void)
CALL(builtin);
CALL(GC);
CALL(IO_nonblock);
CALL(ast);
CALL(vm_trace);