Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions depend
Original file line number Diff line number Diff line change
Expand Up @@ -14598,6 +14598,7 @@ ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
ruby.$(OBJEXT): $(top_srcdir)/version.h
ruby.$(OBJEXT): {$(VPATH)}assert.h
ruby.$(OBJEXT): {$(VPATH)}atomic.h
ruby.$(OBJEXT): {$(VPATH)}backward/2/assume.h
Expand Down Expand Up @@ -14781,6 +14782,7 @@ ruby.$(OBJEXT): {$(VPATH)}prism/ast.h
ruby.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
ruby.$(OBJEXT): {$(VPATH)}prism/version.h
ruby.$(OBJEXT): {$(VPATH)}prism_compile.h
ruby.$(OBJEXT): {$(VPATH)}revision.h
ruby.$(OBJEXT): {$(VPATH)}ruby.c
ruby.$(OBJEXT): {$(VPATH)}ruby_assert.h
ruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h
Expand Down
7 changes: 7 additions & 0 deletions doc/ruby/options.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
<!---
CAUTION

This page on docs.ruby-lang.org is displayed in Ruby's help message (-h and --help).
Please make sure you update the link when renaming or moving this file.
--->

# Ruby Command-Line Options

## About the Examples
Expand Down
16 changes: 11 additions & 5 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1921,7 +1921,7 @@ object_id(VALUE obj)
// in fields.
return class_object_id(obj);
case T_IMEMO:
rb_bug("T_IMEMO can't have an object_id");
RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
break;
default:
break;
Expand All @@ -1945,20 +1945,26 @@ build_id2ref_i(VALUE obj, void *data)
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
case T_MODULE:
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
if (RCLASS(obj)->object_id) {
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
st_insert(id2ref_tbl, RCLASS(obj)->object_id, obj);
}
break;
case T_IMEMO:
case T_NONE:
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
if (IMEMO_TYPE_P(obj, imemo_fields) && rb_shape_obj_has_id(obj)) {
st_insert(id2ref_tbl, rb_obj_id(obj), rb_imemo_fields_owner(obj));
}
break;
default:
case T_OBJECT:
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
if (rb_shape_obj_has_id(obj)) {
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
st_insert(id2ref_tbl, rb_obj_id(obj), obj);
}
break;
default:
// For generic_fields, the T_IMEMO/fields is responsible for populating the entry.
break;
}
}

Expand Down
72 changes: 61 additions & 11 deletions gc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,14 @@ def self.stress=(flag)
end

# call-seq:
# GC.count -> Integer
# self.count -> integer
#
# Returns the total number of times garbage collection has occurred:
#
# GC.count # => 385
# GC.start
# GC.count # => 386
#
# Returns the number of times \GC has occurred since the process started.
def self.count
Primitive.gc_count
end
Expand Down Expand Up @@ -378,11 +383,29 @@ def self.latest_gc_info hash_or_key = nil
end

# call-seq:
# GC.measure_total_time = true/false
# GC.measure_total_time = setting -> setting
#
# Enables or disables \GC total time measurement;
# returns +setting+.
# See GC.total_time.
#
# When argument +object+ is +nil+ or +false+, disables total time measurement;
# GC.measure_total_time then returns +false+:
#
# GC.measure_total_time = nil # => nil
# GC.measure_total_time # => false
# GC.measure_total_time = false # => false
# GC.measure_total_time # => false
#
# Otherwise, enables total time measurement;
# GC.measure_total_time then returns +true+:
#
# GC.measure_total_time = true # => true
# GC.measure_total_time # => true
# GC.measure_total_time = :foo # => :foo
# GC.measure_total_time # => true
#
# Enables measuring \GC time.
# You can get the result with <tt>GC.stat(:time)</tt>.
# Note that \GC time measurement can cause some performance overhead.
# Note that when enabled, total time measurement affects performance.
def self.measure_total_time=(flag)
Primitive.cstmt! %{
rb_gc_impl_set_measure_total_time(rb_gc_get_objspace(), flag);
Expand All @@ -391,20 +414,47 @@ def self.measure_total_time=(flag)
end

# call-seq:
# GC.measure_total_time -> true/false
# GC.measure_total_time -> true or false
#
# Returns the measure_total_time flag (default: +true+).
# Note that measurement can affect the application's performance.
# Returns the setting for \GC total time measurement;
# the initial setting is +true+.
# See GC.total_time.
def self.measure_total_time
Primitive.cexpr! %{
RBOOL(rb_gc_impl_get_measure_total_time(rb_gc_get_objspace()))
}
end

# call-seq:
# GC.total_time -> int
# GC.total_time -> integer
#
# Returns the \GC total time in nanoseconds:
#
# GC.total_time # => 156250
#
# Note that total time accumulates
# only when total time measurement is enabled
# (that is, when GC.measure_total_time is +true+):
#
# GC.measure_total_time # => true
# GC.total_time # => 625000
# GC.start
# GC.total_time # => 937500
# GC.start
# GC.total_time # => 1093750
#
# GC.measure_total_time = false
# GC.total_time # => 1250000
# GC.start
# GC.total_time # => 1250000
# GC.start
# GC.total_time # => 1250000
#
# GC.measure_total_time = true
# GC.total_time # => 1250000
# GC.start
# GC.total_time # => 1406250
#
# Returns the measured \GC total time in nanoseconds.
def self.total_time
Primitive.cexpr! %{
ULL2NUM(rb_gc_impl_get_total_time(rb_gc_get_objspace()))
Expand Down
26 changes: 13 additions & 13 deletions imemo.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,40 +109,40 @@ rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt)
}

static VALUE
imemo_fields_new(VALUE klass, size_t capa)
imemo_fields_new(VALUE owner, size_t capa)
{
size_t embedded_size = offsetof(struct rb_fields, as.embed) + capa * sizeof(VALUE);
if (rb_gc_size_allocatable_p(embedded_size)) {
VALUE fields = rb_imemo_new(imemo_fields, klass, embedded_size);
VALUE fields = rb_imemo_new(imemo_fields, owner, embedded_size);
RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_fields));
return fields;
}
else {
VALUE fields = rb_imemo_new(imemo_fields, klass, sizeof(struct rb_fields));
VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields));
FL_SET_RAW(fields, OBJ_FIELD_EXTERNAL);
IMEMO_OBJ_FIELDS(fields)->as.external.ptr = ALLOC_N(VALUE, capa);
return fields;
}
}

VALUE
rb_imemo_fields_new(VALUE klass, size_t capa)
rb_imemo_fields_new(VALUE owner, size_t capa)
{
return imemo_fields_new(klass, capa);
return imemo_fields_new(owner, capa);
}

static VALUE
imemo_fields_new_complex(VALUE klass, size_t capa)
imemo_fields_new_complex(VALUE owner, size_t capa)
{
VALUE fields = imemo_fields_new(klass, sizeof(struct rb_fields));
VALUE fields = imemo_fields_new(owner, sizeof(struct rb_fields));
IMEMO_OBJ_FIELDS(fields)->as.complex.table = st_init_numtable_with_size(capa);
return fields;
}

VALUE
rb_imemo_fields_new_complex(VALUE klass, size_t capa)
rb_imemo_fields_new_complex(VALUE owner, size_t capa)
{
return imemo_fields_new_complex(klass, capa);
return imemo_fields_new_complex(owner, capa);
}

static int
Expand All @@ -161,9 +161,9 @@ imemo_fields_complex_wb_i(st_data_t key, st_data_t value, st_data_t arg)
}

VALUE
rb_imemo_fields_new_complex_tbl(VALUE klass, st_table *tbl)
rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl)
{
VALUE fields = imemo_fields_new(klass, sizeof(struct rb_fields));
VALUE fields = imemo_fields_new(owner, sizeof(struct rb_fields));
IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl;
st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields);
return fields;
Expand All @@ -176,15 +176,15 @@ rb_imemo_fields_clone(VALUE fields_obj)
VALUE clone;

if (rb_shape_too_complex_p(shape_id)) {
clone = rb_imemo_fields_new_complex(CLASS_OF(fields_obj), 0);
clone = rb_imemo_fields_new_complex(rb_imemo_fields_owner(fields_obj), 0);
RBASIC_SET_SHAPE_ID(clone, shape_id);
st_table *src_table = rb_imemo_fields_complex_tbl(fields_obj);
st_table *dest_table = rb_imemo_fields_complex_tbl(clone);
st_replace(dest_table, src_table);
st_foreach(dest_table, imemo_fields_complex_wb_i, (st_data_t)clone);
}
else {
clone = imemo_fields_new(CLASS_OF(fields_obj), RSHAPE_CAPACITY(shape_id));
clone = imemo_fields_new(rb_imemo_fields_owner(fields_obj), RSHAPE_CAPACITY(shape_id));
RBASIC_SET_SHAPE_ID(clone, shape_id);
VALUE *fields = rb_imemo_fields_ptr(clone);
attr_index_t fields_count = RSHAPE_LEN(shape_id);
Expand Down
2 changes: 1 addition & 1 deletion internal/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ RCLASS_WRITABLE_ENSURE_FIELDS_OBJ(VALUE obj)
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
rb_classext_t *ext = RCLASS_EXT_WRITABLE(obj);
if (!ext->fields_obj) {
RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(rb_singleton_class(obj), 1));
RB_OBJ_WRITE(obj, &ext->fields_obj, rb_imemo_fields_new(obj, 1));
}
return ext->fields_obj;
}
Expand Down
12 changes: 9 additions & 3 deletions internal/imemo.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,12 +273,18 @@ struct rb_fields {
#define OBJ_FIELD_EXTERNAL IMEMO_FL_USER0
#define IMEMO_OBJ_FIELDS(fields) ((struct rb_fields *)fields)

VALUE rb_imemo_fields_new(VALUE klass, size_t capa);
VALUE rb_imemo_fields_new_complex(VALUE klass, size_t capa);
VALUE rb_imemo_fields_new_complex_tbl(VALUE klass, st_table *tbl);
VALUE rb_imemo_fields_new(VALUE owner, size_t capa);
VALUE rb_imemo_fields_new_complex(VALUE owner, size_t capa);
VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl);
VALUE rb_imemo_fields_clone(VALUE fields_obj);
void rb_imemo_fields_clear(VALUE fields_obj);

static inline VALUE
rb_imemo_fields_owner(VALUE fields_obj)
{
return CLASS_OF(fields_obj);
}

static inline VALUE *
rb_imemo_fields_ptr(VALUE obj_fields)
{
Expand Down
6 changes: 5 additions & 1 deletion ruby.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
#include "ruby/util.h"
#include "ruby/version.h"
#include "ruby/internal/error.h"
#include "version.h"

#define singlebit_only_p(x) !((x) & ((x)-1))
STATIC_ASSERT(Qnil_1bit_from_Qfalse, singlebit_only_p(Qnil^Qfalse));
Expand Down Expand Up @@ -403,7 +404,10 @@ usage(const char *name, int help, int highlight, int columns)
unsigned int w = (columns > 80 ? (columns - 79) / 2 : 0) + 16;
#define SHOW(m) show_usage_line(&(m), help, highlight, w, columns)

printf("%sUsage:%s %s [options] [--] [filepath] [arguments]\n", sb, se, name);
printf("%sUsage:%s %s [options] [--] [filepath] [arguments]\n\n", sb, se, name);
printf("Details and examples at https://docs.ruby-lang.org/en/%s/ruby/options_md.html\n",
RUBY_PATCHLEVEL == -1 ? "master" : STRINGIZE(RUBY_VERSION_MAJOR) "." STRINGIZE(RUBY_VERSION_MINOR));

for (i = 0; i < num; ++i)
SHOW(usage_msg[i]);

Expand Down
13 changes: 11 additions & 2 deletions shape.c
Original file line number Diff line number Diff line change
Expand Up @@ -877,8 +877,17 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
#endif

VALUE klass;
if (IMEMO_TYPE_P(obj, imemo_fields)) { // HACK
klass = CLASS_OF(obj);
if (IMEMO_TYPE_P(obj, imemo_fields)) {
VALUE owner = rb_imemo_fields_owner(obj);
switch (BUILTIN_TYPE(owner)) {
case T_CLASS:
case T_MODULE:
klass = rb_singleton_class(owner);
break;
default:
klass = rb_obj_class(owner);
break;
}
}
else {
klass = rb_obj_class(obj);
Expand Down
12 changes: 9 additions & 3 deletions test/ruby/test_rubyoptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,24 @@ def test_source_file

def test_usage
assert_in_out_err(%w(-h)) do |r, e|
assert_operator(r.size, :<=, 25)
longer = r[1..-1].select {|x| x.size >= 80}
assert_operator(r.size, :<=, 26)
longer = r[3..-1].select {|x| x.size >= 80}
assert_equal([], longer)
assert_equal([], e)

version = RUBY_PATCHLEVEL == -1 ? "master" : "#{RUBY_VERSION_MAJOR}.#{RUBY_VERSION_MINOR}"
assert_include(r, "Details and examples at https://docs.ruby-lang.org/en/#{version}/ruby/options_md.html")
end
end

def test_usage_long
assert_in_out_err(%w(--help)) do |r, e|
longer = r[1..-1].select {|x| x.size > 80}
longer = r[3..-1].select {|x| x.size > 80}
assert_equal([], longer)
assert_equal([], e)

version = RUBY_PATCHLEVEL == -1 ? "master" : "#{RUBY_VERSION_MAJOR}.#{RUBY_VERSION_MINOR}"
assert_include(r, "Details and examples at https://docs.ruby-lang.org/en/#{version}/ruby/options_md.html")
end
end

Expand Down
7 changes: 5 additions & 2 deletions test/ruby/test_shapes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,14 @@ class Hi; end
def test_too_many_ivs_on_class
obj = Class.new

(MANY_IVS + 1).times do
obj.instance_variable_set(:@test_too_many_ivs_on_class, 1)
refute_predicate RubyVM::Shape.of(obj), :too_complex?

MANY_IVS.times do
obj.instance_variable_set(:"@a#{_1}", 1)
end

assert_false RubyVM::Shape.of(obj).too_complex?
refute_predicate RubyVM::Shape.of(obj), :too_complex?
end

def test_removing_when_too_many_ivs_on_class
Expand Down
Loading