mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Merge branch 'master' into wbcheck_proc_dup
This commit is contained in:
commit
a80f1c6c99
18 changed files with 177 additions and 58 deletions
2
depend
2
depend
|
@ -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_string.h
|
||||||
ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
|
ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
|
||||||
ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
|
ruby.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
|
||||||
|
ruby.$(OBJEXT): $(top_srcdir)/version.h
|
||||||
ruby.$(OBJEXT): {$(VPATH)}assert.h
|
ruby.$(OBJEXT): {$(VPATH)}assert.h
|
||||||
ruby.$(OBJEXT): {$(VPATH)}atomic.h
|
ruby.$(OBJEXT): {$(VPATH)}atomic.h
|
||||||
ruby.$(OBJEXT): {$(VPATH)}backward/2/assume.h
|
ruby.$(OBJEXT): {$(VPATH)}backward/2/assume.h
|
||||||
|
@ -14781,6 +14782,7 @@ ruby.$(OBJEXT): {$(VPATH)}prism/ast.h
|
||||||
ruby.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
|
ruby.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
|
||||||
ruby.$(OBJEXT): {$(VPATH)}prism/version.h
|
ruby.$(OBJEXT): {$(VPATH)}prism/version.h
|
||||||
ruby.$(OBJEXT): {$(VPATH)}prism_compile.h
|
ruby.$(OBJEXT): {$(VPATH)}prism_compile.h
|
||||||
|
ruby.$(OBJEXT): {$(VPATH)}revision.h
|
||||||
ruby.$(OBJEXT): {$(VPATH)}ruby.c
|
ruby.$(OBJEXT): {$(VPATH)}ruby.c
|
||||||
ruby.$(OBJEXT): {$(VPATH)}ruby_assert.h
|
ruby.$(OBJEXT): {$(VPATH)}ruby_assert.h
|
||||||
ruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h
|
ruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h
|
||||||
|
|
|
@ -367,11 +367,11 @@ Outstanding ones only.
|
||||||
* Fiber.blocking? tells whether the current execution context is
|
* Fiber.blocking? tells whether the current execution context is
|
||||||
blocking. [[Feature #16786]]
|
blocking. [[Feature #16786]]
|
||||||
|
|
||||||
|
* Thread
|
||||||
|
|
||||||
* Thread#join invokes the scheduler hooks `block`/`unblock` in a
|
* Thread#join invokes the scheduler hooks `block`/`unblock` in a
|
||||||
non-blocking execution context. [[Feature #16786]]
|
non-blocking execution context. [[Feature #16786]]
|
||||||
|
|
||||||
* Thread
|
|
||||||
|
|
||||||
* Thread.ignore_deadlock accessor has been added for disabling the
|
* Thread.ignore_deadlock accessor has been added for disabling the
|
||||||
default deadlock detection, allowing the use of signal handlers to
|
default deadlock detection, allowing the use of signal handlers to
|
||||||
break deadlock. [[Bug #13768]]
|
break deadlock. [[Bug #13768]]
|
||||||
|
|
|
@ -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
|
# Ruby Command-Line Options
|
||||||
|
|
||||||
## About the Examples
|
## About the Examples
|
||||||
|
|
16
gc.c
16
gc.c
|
@ -1921,7 +1921,7 @@ object_id(VALUE obj)
|
||||||
// in fields.
|
// in fields.
|
||||||
return class_object_id(obj);
|
return class_object_id(obj);
|
||||||
case T_IMEMO:
|
case T_IMEMO:
|
||||||
rb_bug("T_IMEMO can't have an object_id");
|
RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -1945,20 +1945,26 @@ build_id2ref_i(VALUE obj, void *data)
|
||||||
switch (BUILTIN_TYPE(obj)) {
|
switch (BUILTIN_TYPE(obj)) {
|
||||||
case T_CLASS:
|
case T_CLASS:
|
||||||
case T_MODULE:
|
case T_MODULE:
|
||||||
|
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
|
||||||
if (RCLASS(obj)->object_id) {
|
if (RCLASS(obj)->object_id) {
|
||||||
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
|
|
||||||
st_insert(id2ref_tbl, RCLASS(obj)->object_id, obj);
|
st_insert(id2ref_tbl, RCLASS(obj)->object_id, obj);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case T_IMEMO:
|
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;
|
break;
|
||||||
default:
|
case T_OBJECT:
|
||||||
|
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
|
||||||
if (rb_shape_obj_has_id(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);
|
st_insert(id2ref_tbl, rb_obj_id(obj), obj);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
// For generic_fields, the T_IMEMO/fields is responsible for populating the entry.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
gc.rb
9
gc.rb
|
@ -104,9 +104,14 @@ module GC
|
||||||
end
|
end
|
||||||
|
|
||||||
# call-seq:
|
# 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
|
def self.count
|
||||||
Primitive.gc_count
|
Primitive.gc_count
|
||||||
end
|
end
|
||||||
|
|
26
imemo.c
26
imemo.c
|
@ -109,16 +109,16 @@ rb_imemo_tmpbuf_parser_heap(void *buf, rb_imemo_tmpbuf_t *old_heap, size_t cnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
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);
|
size_t embedded_size = offsetof(struct rb_fields, as.embed) + capa * sizeof(VALUE);
|
||||||
if (rb_gc_size_allocatable_p(embedded_size)) {
|
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));
|
RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_fields));
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
else {
|
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);
|
FL_SET_RAW(fields, OBJ_FIELD_EXTERNAL);
|
||||||
IMEMO_OBJ_FIELDS(fields)->as.external.ptr = ALLOC_N(VALUE, capa);
|
IMEMO_OBJ_FIELDS(fields)->as.external.ptr = ALLOC_N(VALUE, capa);
|
||||||
return fields;
|
return fields;
|
||||||
|
@ -126,23 +126,23 @@ imemo_fields_new(VALUE klass, size_t capa)
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
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
|
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);
|
IMEMO_OBJ_FIELDS(fields)->as.complex.table = st_init_numtable_with_size(capa);
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
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
|
static int
|
||||||
|
@ -161,9 +161,9 @@ imemo_fields_complex_wb_i(st_data_t key, st_data_t value, st_data_t arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
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;
|
IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl;
|
||||||
st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields);
|
st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields);
|
||||||
return fields;
|
return fields;
|
||||||
|
@ -176,7 +176,7 @@ rb_imemo_fields_clone(VALUE fields_obj)
|
||||||
VALUE clone;
|
VALUE clone;
|
||||||
|
|
||||||
if (rb_shape_too_complex_p(shape_id)) {
|
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);
|
RBASIC_SET_SHAPE_ID(clone, shape_id);
|
||||||
st_table *src_table = rb_imemo_fields_complex_tbl(fields_obj);
|
st_table *src_table = rb_imemo_fields_complex_tbl(fields_obj);
|
||||||
st_table *dest_table = rb_imemo_fields_complex_tbl(clone);
|
st_table *dest_table = rb_imemo_fields_complex_tbl(clone);
|
||||||
|
@ -184,7 +184,7 @@ rb_imemo_fields_clone(VALUE fields_obj)
|
||||||
st_foreach(dest_table, imemo_fields_complex_wb_i, (st_data_t)clone);
|
st_foreach(dest_table, imemo_fields_complex_wb_i, (st_data_t)clone);
|
||||||
}
|
}
|
||||||
else {
|
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);
|
RBASIC_SET_SHAPE_ID(clone, shape_id);
|
||||||
VALUE *fields = rb_imemo_fields_ptr(clone);
|
VALUE *fields = rb_imemo_fields_ptr(clone);
|
||||||
attr_index_t fields_count = RSHAPE_LEN(shape_id);
|
attr_index_t fields_count = RSHAPE_LEN(shape_id);
|
||||||
|
|
|
@ -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));
|
RUBY_ASSERT(RB_TYPE_P(obj, RUBY_T_CLASS) || RB_TYPE_P(obj, RUBY_T_MODULE));
|
||||||
rb_classext_t *ext = RCLASS_EXT_WRITABLE(obj);
|
rb_classext_t *ext = RCLASS_EXT_WRITABLE(obj);
|
||||||
if (!ext->fields_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;
|
return ext->fields_obj;
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,12 +273,18 @@ struct rb_fields {
|
||||||
#define OBJ_FIELD_EXTERNAL IMEMO_FL_USER0
|
#define OBJ_FIELD_EXTERNAL IMEMO_FL_USER0
|
||||||
#define IMEMO_OBJ_FIELDS(fields) ((struct rb_fields *)fields)
|
#define IMEMO_OBJ_FIELDS(fields) ((struct rb_fields *)fields)
|
||||||
|
|
||||||
VALUE rb_imemo_fields_new(VALUE klass, size_t capa);
|
VALUE rb_imemo_fields_new(VALUE owner, size_t capa);
|
||||||
VALUE rb_imemo_fields_new_complex(VALUE klass, size_t capa);
|
VALUE rb_imemo_fields_new_complex(VALUE owner, size_t capa);
|
||||||
VALUE rb_imemo_fields_new_complex_tbl(VALUE klass, st_table *tbl);
|
VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl);
|
||||||
VALUE rb_imemo_fields_clone(VALUE fields_obj);
|
VALUE rb_imemo_fields_clone(VALUE fields_obj);
|
||||||
void rb_imemo_fields_clear(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 *
|
static inline VALUE *
|
||||||
rb_imemo_fields_ptr(VALUE obj_fields)
|
rb_imemo_fields_ptr(VALUE obj_fields)
|
||||||
{
|
{
|
||||||
|
|
6
ruby.c
6
ruby.c
|
@ -61,6 +61,7 @@
|
||||||
#include "ruby/util.h"
|
#include "ruby/util.h"
|
||||||
#include "ruby/version.h"
|
#include "ruby/version.h"
|
||||||
#include "ruby/internal/error.h"
|
#include "ruby/internal/error.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
#define singlebit_only_p(x) !((x) & ((x)-1))
|
#define singlebit_only_p(x) !((x) & ((x)-1))
|
||||||
STATIC_ASSERT(Qnil_1bit_from_Qfalse, singlebit_only_p(Qnil^Qfalse));
|
STATIC_ASSERT(Qnil_1bit_from_Qfalse, singlebit_only_p(Qnil^Qfalse));
|
||||||
|
@ -403,7 +404,10 @@ usage(const char *name, int help, int highlight, int columns)
|
||||||
unsigned int w = (columns > 80 ? (columns - 79) / 2 : 0) + 16;
|
unsigned int w = (columns > 80 ? (columns - 79) / 2 : 0) + 16;
|
||||||
#define SHOW(m) show_usage_line(&(m), help, highlight, w, columns)
|
#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)
|
for (i = 0; i < num; ++i)
|
||||||
SHOW(usage_msg[i]);
|
SHOW(usage_msg[i]);
|
||||||
|
|
||||||
|
|
13
shape.c
13
shape.c
|
@ -877,8 +877,17 @@ shape_get_next(rb_shape_t *shape, VALUE obj, ID id, bool emit_warnings)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VALUE klass;
|
VALUE klass;
|
||||||
if (IMEMO_TYPE_P(obj, imemo_fields)) { // HACK
|
if (IMEMO_TYPE_P(obj, imemo_fields)) {
|
||||||
klass = CLASS_OF(obj);
|
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 {
|
else {
|
||||||
klass = rb_obj_class(obj);
|
klass = rb_obj_class(obj);
|
||||||
|
|
|
@ -49,18 +49,24 @@ class TestRubyOptions < Test::Unit::TestCase
|
||||||
|
|
||||||
def test_usage
|
def test_usage
|
||||||
assert_in_out_err(%w(-h)) do |r, e|
|
assert_in_out_err(%w(-h)) do |r, e|
|
||||||
assert_operator(r.size, :<=, 25)
|
assert_operator(r.size, :<=, 26)
|
||||||
longer = r[1..-1].select {|x| x.size >= 80}
|
longer = r[3..-1].select {|x| x.size >= 80}
|
||||||
assert_equal([], longer)
|
assert_equal([], longer)
|
||||||
assert_equal([], e)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_usage_long
|
def test_usage_long
|
||||||
assert_in_out_err(%w(--help)) do |r, e|
|
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([], longer)
|
||||||
assert_equal([], e)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -149,11 +149,14 @@ class TestShapes < Test::Unit::TestCase
|
||||||
def test_too_many_ivs_on_class
|
def test_too_many_ivs_on_class
|
||||||
obj = Class.new
|
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)
|
obj.instance_variable_set(:"@a#{_1}", 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_false RubyVM::Shape.of(obj).too_complex?
|
refute_predicate RubyVM::Shape.of(obj), :too_complex?
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_removing_when_too_many_ivs_on_class
|
def test_removing_when_too_many_ivs_on_class
|
||||||
|
|
|
@ -61,6 +61,30 @@ class TestZJIT < Test::Unit::TestCase
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_setglobal
|
||||||
|
assert_compiles '1', %q{
|
||||||
|
def test
|
||||||
|
$a = 1
|
||||||
|
$a
|
||||||
|
end
|
||||||
|
|
||||||
|
test
|
||||||
|
}, insns: [:setglobal]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_setglobal_with_trace_var_exception
|
||||||
|
assert_compiles '"rescued"', %q{
|
||||||
|
def test
|
||||||
|
$a = 1
|
||||||
|
rescue
|
||||||
|
"rescued"
|
||||||
|
end
|
||||||
|
|
||||||
|
trace_var(:$a) { raise }
|
||||||
|
test
|
||||||
|
}, insns: [:setglobal]
|
||||||
|
end
|
||||||
|
|
||||||
def test_setlocal
|
def test_setlocal
|
||||||
assert_compiles '3', %q{
|
assert_compiles '3', %q{
|
||||||
def test(n)
|
def test(n)
|
||||||
|
|
65
variable.c
65
variable.c
|
@ -1245,9 +1245,19 @@ rb_obj_fields(VALUE obj, ID field_name)
|
||||||
goto generic_fields;
|
goto generic_fields;
|
||||||
default:
|
default:
|
||||||
generic_fields:
|
generic_fields:
|
||||||
RB_VM_LOCKING() {
|
{
|
||||||
if (!st_lookup(generic_fields_tbl_, (st_data_t)obj, (st_data_t *)&fields_obj)) {
|
rb_execution_context_t *ec = GET_EC();
|
||||||
rb_bug("Object is missing entry in generic_fields_tbl");
|
if (ec->gen_fields_cache.obj == obj) {
|
||||||
|
fields_obj = ec->gen_fields_cache.fields_obj;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RB_VM_LOCKING() {
|
||||||
|
if (!st_lookup(generic_fields_tbl_, (st_data_t)obj, (st_data_t *)&fields_obj)) {
|
||||||
|
rb_bug("Object is missing entry in generic_fields_tbl");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ec->gen_fields_cache.fields_obj = fields_obj;
|
||||||
|
ec->gen_fields_cache.obj = obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1275,8 +1285,15 @@ rb_free_generic_ivar(VALUE obj)
|
||||||
goto generic_fields;
|
goto generic_fields;
|
||||||
default:
|
default:
|
||||||
generic_fields:
|
generic_fields:
|
||||||
RB_VM_LOCKING() {
|
{
|
||||||
st_delete(generic_fields_tbl_no_ractor_check(), &key, &value);
|
rb_execution_context_t *ec = GET_EC();
|
||||||
|
if (ec->gen_fields_cache.obj == obj) {
|
||||||
|
ec->gen_fields_cache.obj = Qundef;
|
||||||
|
ec->gen_fields_cache.fields_obj = Qundef;
|
||||||
|
}
|
||||||
|
RB_VM_LOCKING() {
|
||||||
|
st_delete(generic_fields_tbl_no_ractor_check(), &key, &value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RBASIC_SET_SHAPE_ID(obj, ROOT_SHAPE_ID);
|
RBASIC_SET_SHAPE_ID(obj, ROOT_SHAPE_ID);
|
||||||
|
@ -1307,10 +1324,18 @@ rb_obj_set_fields(VALUE obj, VALUE fields_obj, ID field_name, VALUE original_fie
|
||||||
goto generic_fields;
|
goto generic_fields;
|
||||||
default:
|
default:
|
||||||
generic_fields:
|
generic_fields:
|
||||||
RB_VM_LOCKING() {
|
{
|
||||||
st_insert(generic_fields_tbl_, (st_data_t)obj, (st_data_t)fields_obj);
|
RB_VM_LOCKING() {
|
||||||
|
st_insert(generic_fields_tbl_, (st_data_t)obj, (st_data_t)fields_obj);
|
||||||
|
}
|
||||||
|
RB_OBJ_WRITTEN(obj, original_fields_obj, fields_obj);
|
||||||
|
|
||||||
|
rb_execution_context_t *ec = GET_EC();
|
||||||
|
if (ec->gen_fields_cache.fields_obj != fields_obj) {
|
||||||
|
ec->gen_fields_cache.obj = obj;
|
||||||
|
ec->gen_fields_cache.fields_obj = fields_obj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
RB_OBJ_WRITTEN(obj, original_fields_obj, fields_obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (original_fields_obj) {
|
if (original_fields_obj) {
|
||||||
|
@ -1687,10 +1712,10 @@ imemo_fields_complex_from_obj_i(ID key, VALUE val, st_data_t arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
imemo_fields_complex_from_obj(VALUE klass, VALUE source_fields_obj, shape_id_t shape_id)
|
imemo_fields_complex_from_obj(VALUE owner, VALUE source_fields_obj, shape_id_t shape_id)
|
||||||
{
|
{
|
||||||
attr_index_t len = source_fields_obj ? RSHAPE_LEN(RBASIC_SHAPE_ID(source_fields_obj)) : 0;
|
attr_index_t len = source_fields_obj ? RSHAPE_LEN(RBASIC_SHAPE_ID(source_fields_obj)) : 0;
|
||||||
VALUE fields_obj = rb_imemo_fields_new_complex(klass, len + 1);
|
VALUE fields_obj = rb_imemo_fields_new_complex(owner, len + 1);
|
||||||
|
|
||||||
rb_field_foreach(source_fields_obj, imemo_fields_complex_from_obj_i, (st_data_t)fields_obj, false);
|
rb_field_foreach(source_fields_obj, imemo_fields_complex_from_obj_i, (st_data_t)fields_obj, false);
|
||||||
RBASIC_SET_SHAPE_ID(fields_obj, shape_id);
|
RBASIC_SET_SHAPE_ID(fields_obj, shape_id);
|
||||||
|
@ -1699,9 +1724,9 @@ imemo_fields_complex_from_obj(VALUE klass, VALUE source_fields_obj, shape_id_t s
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
imemo_fields_copy_capa(VALUE klass, VALUE source_fields_obj, attr_index_t new_size)
|
imemo_fields_copy_capa(VALUE owner, VALUE source_fields_obj, attr_index_t new_size)
|
||||||
{
|
{
|
||||||
VALUE fields_obj = rb_imemo_fields_new(klass, new_size);
|
VALUE fields_obj = rb_imemo_fields_new(owner, new_size);
|
||||||
if (source_fields_obj) {
|
if (source_fields_obj) {
|
||||||
attr_index_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(source_fields_obj));
|
attr_index_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(source_fields_obj));
|
||||||
VALUE *fields = rb_imemo_fields_ptr(fields_obj);
|
VALUE *fields = rb_imemo_fields_ptr(fields_obj);
|
||||||
|
@ -1853,7 +1878,7 @@ general_field_set(VALUE obj, shape_id_t target_shape_id, VALUE val, void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
imemo_fields_set(VALUE klass, VALUE fields_obj, shape_id_t target_shape_id, ID field_name, VALUE val, bool concurrent)
|
imemo_fields_set(VALUE owner, VALUE fields_obj, shape_id_t target_shape_id, ID field_name, VALUE val, bool concurrent)
|
||||||
{
|
{
|
||||||
const VALUE original_fields_obj = fields_obj;
|
const VALUE original_fields_obj = fields_obj;
|
||||||
shape_id_t current_shape_id = fields_obj ? RBASIC_SHAPE_ID(fields_obj) : ROOT_SHAPE_ID;
|
shape_id_t current_shape_id = fields_obj ? RBASIC_SHAPE_ID(fields_obj) : ROOT_SHAPE_ID;
|
||||||
|
@ -1868,7 +1893,7 @@ imemo_fields_set(VALUE klass, VALUE fields_obj, shape_id_t target_shape_id, ID f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fields_obj = imemo_fields_complex_from_obj(klass, original_fields_obj, target_shape_id);
|
fields_obj = imemo_fields_complex_from_obj(owner, original_fields_obj, target_shape_id);
|
||||||
current_shape_id = target_shape_id;
|
current_shape_id = target_shape_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1882,7 +1907,7 @@ imemo_fields_set(VALUE klass, VALUE fields_obj, shape_id_t target_shape_id, ID f
|
||||||
else {
|
else {
|
||||||
attr_index_t index = RSHAPE_INDEX(target_shape_id);
|
attr_index_t index = RSHAPE_INDEX(target_shape_id);
|
||||||
if (concurrent || index >= RSHAPE_CAPACITY(current_shape_id)) {
|
if (concurrent || index >= RSHAPE_CAPACITY(current_shape_id)) {
|
||||||
fields_obj = imemo_fields_copy_capa(klass, original_fields_obj, RSHAPE_CAPACITY(target_shape_id));
|
fields_obj = imemo_fields_copy_capa(owner, original_fields_obj, RSHAPE_CAPACITY(target_shape_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE *table = rb_imemo_fields_ptr(fields_obj);
|
VALUE *table = rb_imemo_fields_ptr(fields_obj);
|
||||||
|
@ -1905,7 +1930,7 @@ generic_field_set(VALUE obj, shape_id_t target_shape_id, ID field_name, VALUE va
|
||||||
}
|
}
|
||||||
|
|
||||||
const VALUE original_fields_obj = rb_obj_fields(obj, field_name);
|
const VALUE original_fields_obj = rb_obj_fields(obj, field_name);
|
||||||
VALUE fields_obj = imemo_fields_set(rb_obj_class(obj), original_fields_obj, target_shape_id, field_name, val, false);
|
VALUE fields_obj = imemo_fields_set(obj, original_fields_obj, target_shape_id, field_name, val, false);
|
||||||
|
|
||||||
rb_obj_set_fields(obj, fields_obj, field_name, original_fields_obj);
|
rb_obj_set_fields(obj, fields_obj, field_name, original_fields_obj);
|
||||||
}
|
}
|
||||||
|
@ -2340,7 +2365,7 @@ rb_copy_generic_ivar(VALUE dest, VALUE obj)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_fields_obj = rb_imemo_fields_new(rb_obj_class(dest), RSHAPE_CAPACITY(dest_shape_id));
|
new_fields_obj = rb_imemo_fields_new(dest, RSHAPE_CAPACITY(dest_shape_id));
|
||||||
VALUE *src_buf = rb_imemo_fields_ptr(fields_obj);
|
VALUE *src_buf = rb_imemo_fields_ptr(fields_obj);
|
||||||
VALUE *dest_buf = rb_imemo_fields_ptr(new_fields_obj);
|
VALUE *dest_buf = rb_imemo_fields_ptr(new_fields_obj);
|
||||||
rb_shape_copy_fields(new_fields_obj, dest_buf, dest_shape_id, src_buf, src_shape_id);
|
rb_shape_copy_fields(new_fields_obj, dest_buf, dest_shape_id, src_buf, src_shape_id);
|
||||||
|
@ -4640,7 +4665,7 @@ class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool conc
|
||||||
{
|
{
|
||||||
bool existing = true;
|
bool existing = true;
|
||||||
const VALUE original_fields_obj = fields_obj;
|
const VALUE original_fields_obj = fields_obj;
|
||||||
fields_obj = original_fields_obj ? original_fields_obj : rb_imemo_fields_new(rb_singleton_class(klass), 1);
|
fields_obj = original_fields_obj ? original_fields_obj : rb_imemo_fields_new(klass, 1);
|
||||||
|
|
||||||
shape_id_t current_shape_id = RBASIC_SHAPE_ID(fields_obj);
|
shape_id_t current_shape_id = RBASIC_SHAPE_ID(fields_obj);
|
||||||
shape_id_t next_shape_id = current_shape_id;
|
shape_id_t next_shape_id = current_shape_id;
|
||||||
|
@ -4660,7 +4685,7 @@ class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool conc
|
||||||
|
|
||||||
next_shape_id = rb_shape_transition_add_ivar(fields_obj, id);
|
next_shape_id = rb_shape_transition_add_ivar(fields_obj, id);
|
||||||
if (UNLIKELY(rb_shape_too_complex_p(next_shape_id))) {
|
if (UNLIKELY(rb_shape_too_complex_p(next_shape_id))) {
|
||||||
fields_obj = imemo_fields_complex_from_obj(rb_singleton_class(klass), fields_obj, next_shape_id);
|
fields_obj = imemo_fields_complex_from_obj(klass, fields_obj, next_shape_id);
|
||||||
goto too_complex;
|
goto too_complex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4670,7 +4695,7 @@ class_fields_ivar_set(VALUE klass, VALUE fields_obj, ID id, VALUE val, bool conc
|
||||||
if (next_capacity > current_capacity) {
|
if (next_capacity > current_capacity) {
|
||||||
// We allocate a new fields_obj even when concurrency isn't a concern
|
// We allocate a new fields_obj even when concurrency isn't a concern
|
||||||
// so that we're embedded as long as possible.
|
// so that we're embedded as long as possible.
|
||||||
fields_obj = imemo_fields_copy_capa(rb_singleton_class(klass), fields_obj, next_capacity);
|
fields_obj = imemo_fields_copy_capa(klass, fields_obj, next_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
RUBY_ASSERT(RSHAPE(next_shape_id)->type == SHAPE_IVAR);
|
RUBY_ASSERT(RSHAPE(next_shape_id)->type == SHAPE_IVAR);
|
||||||
|
|
6
vm.c
6
vm.c
|
@ -3441,6 +3441,9 @@ rb_execution_context_update(rb_execution_context_t *ec)
|
||||||
}
|
}
|
||||||
|
|
||||||
ec->storage = rb_gc_location(ec->storage);
|
ec->storage = rb_gc_location(ec->storage);
|
||||||
|
|
||||||
|
ec->gen_fields_cache.obj = rb_gc_location(ec->gen_fields_cache.obj);
|
||||||
|
ec->gen_fields_cache.fields_obj = rb_gc_location(ec->gen_fields_cache.fields_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum rb_id_table_iterator_result
|
static enum rb_id_table_iterator_result
|
||||||
|
@ -3505,6 +3508,9 @@ rb_execution_context_mark(const rb_execution_context_t *ec)
|
||||||
rb_gc_mark(ec->private_const_reference);
|
rb_gc_mark(ec->private_const_reference);
|
||||||
|
|
||||||
rb_gc_mark_movable(ec->storage);
|
rb_gc_mark_movable(ec->storage);
|
||||||
|
|
||||||
|
rb_gc_mark_weak((VALUE *)&ec->gen_fields_cache.obj);
|
||||||
|
rb_gc_mark_weak((VALUE *)&ec->gen_fields_cache.fields_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rb_fiber_mark_self(rb_fiber_t *fib);
|
void rb_fiber_mark_self(rb_fiber_t *fib);
|
||||||
|
|
|
@ -1070,6 +1070,11 @@ struct rb_execution_context_struct {
|
||||||
|
|
||||||
VALUE private_const_reference;
|
VALUE private_const_reference;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
VALUE obj;
|
||||||
|
VALUE fields_obj;
|
||||||
|
} gen_fields_cache;
|
||||||
|
|
||||||
/* for GC */
|
/* for GC */
|
||||||
struct {
|
struct {
|
||||||
VALUE *stack_start;
|
VALUE *stack_start;
|
||||||
|
|
|
@ -367,7 +367,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
|
||||||
Insn::PatchPoint { invariant, state } => return gen_patch_point(jit, asm, invariant, &function.frame_state(*state)),
|
Insn::PatchPoint { invariant, state } => return gen_patch_point(jit, asm, invariant, &function.frame_state(*state)),
|
||||||
Insn::CCall { cfun, args, name: _, return_type: _, elidable: _ } => gen_ccall(asm, *cfun, opnds!(args))?,
|
Insn::CCall { cfun, args, name: _, return_type: _, elidable: _ } => gen_ccall(asm, *cfun, opnds!(args))?,
|
||||||
Insn::GetIvar { self_val, id, state: _ } => gen_getivar(asm, opnd!(self_val), *id),
|
Insn::GetIvar { self_val, id, state: _ } => gen_getivar(asm, opnd!(self_val), *id),
|
||||||
Insn::SetGlobal { id, val, state: _ } => return Some(gen_setglobal(asm, *id, opnd!(val))),
|
Insn::SetGlobal { id, val, state } => return gen_setglobal(jit, asm, *id, opnd!(val), &function.frame_state(*state)),
|
||||||
Insn::GetGlobal { id, state: _ } => gen_getglobal(asm, *id),
|
Insn::GetGlobal { id, state: _ } => gen_getglobal(asm, *id),
|
||||||
&Insn::GetLocal { ep_offset, level } => gen_getlocal_with_ep(asm, ep_offset, level)?,
|
&Insn::GetLocal { ep_offset, level } => gen_getlocal_with_ep(asm, ep_offset, level)?,
|
||||||
Insn::SetLocal { val, ep_offset, level } => return gen_setlocal_with_ep(asm, opnd!(val), *ep_offset, *level),
|
Insn::SetLocal { val, ep_offset, level } => return gen_setlocal_with_ep(asm, opnd!(val), *ep_offset, *level),
|
||||||
|
@ -592,8 +592,12 @@ fn gen_getglobal(asm: &mut Assembler, id: ID) -> Opnd {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set global variables
|
/// Set global variables
|
||||||
fn gen_setglobal(asm: &mut Assembler, id: ID, val: Opnd) {
|
fn gen_setglobal(jit: &mut JITState, asm: &mut Assembler, id: ID, val: Opnd, state: &FrameState) -> Option<()> {
|
||||||
|
// When trace_var is used, setting a global variable can cause exceptions
|
||||||
|
gen_prepare_non_leaf_call(jit, asm, state)?;
|
||||||
|
|
||||||
asm_ccall!(asm, rb_gvar_set, id.0.into(), val);
|
asm_ccall!(asm, rb_gvar_set, id.0.into(), val);
|
||||||
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Side-exit into the interpreter
|
/// Side-exit into the interpreter
|
||||||
|
@ -1284,6 +1288,7 @@ fn compile_iseq(iseq: IseqPtr) -> Option<Function> {
|
||||||
if !get_option!(disable_hir_opt) {
|
if !get_option!(disable_hir_opt) {
|
||||||
function.optimize();
|
function.optimize();
|
||||||
}
|
}
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
if let Err(err) = function.validate() {
|
if let Err(err) = function.validate() {
|
||||||
debug!("ZJIT: compile_iseq: {err:?}");
|
debug!("ZJIT: compile_iseq: {err:?}");
|
||||||
return None;
|
return None;
|
||||||
|
|
|
@ -604,7 +604,9 @@ impl Insn {
|
||||||
Insn::Param { .. } => false,
|
Insn::Param { .. } => false,
|
||||||
Insn::StringCopy { .. } => false,
|
Insn::StringCopy { .. } => false,
|
||||||
Insn::NewArray { .. } => false,
|
Insn::NewArray { .. } => false,
|
||||||
Insn::NewHash { .. } => false,
|
// NewHash's operands may be hashed and compared for equality, which could have
|
||||||
|
// side-effects.
|
||||||
|
Insn::NewHash { elements, .. } => elements.len() > 0,
|
||||||
Insn::NewRange { .. } => false,
|
Insn::NewRange { .. } => false,
|
||||||
Insn::ArrayDup { .. } => false,
|
Insn::ArrayDup { .. } => false,
|
||||||
Insn::HashDup { .. } => false,
|
Insn::HashDup { .. } => false,
|
||||||
|
@ -6089,7 +6091,7 @@ mod opt_tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_eliminate_new_hash_with_elements() {
|
fn test_no_eliminate_new_hash_with_elements() {
|
||||||
eval("
|
eval("
|
||||||
def test(aval, bval)
|
def test(aval, bval)
|
||||||
c = {a: aval, b: bval}
|
c = {a: aval, b: bval}
|
||||||
|
@ -6099,6 +6101,10 @@ mod opt_tests {
|
||||||
assert_optimized_method_hir("test", expect![[r#"
|
assert_optimized_method_hir("test", expect![[r#"
|
||||||
fn test@<compiled>:3:
|
fn test@<compiled>:3:
|
||||||
bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject):
|
bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject):
|
||||||
|
v3:NilClass = Const Value(nil)
|
||||||
|
v5:StaticSymbol[:a] = Const Value(VALUE(0x1000))
|
||||||
|
v6:StaticSymbol[:b] = Const Value(VALUE(0x1008))
|
||||||
|
v8:HashExact = NewHash v5: v1, v6: v2
|
||||||
v9:Fixnum[5] = Const Value(5)
|
v9:Fixnum[5] = Const Value(5)
|
||||||
Return v9
|
Return v9
|
||||||
"#]]);
|
"#]]);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue