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
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ Note: We're only listing outstanding class updates.
* `MatchData#integer_at` is added. It converts the matched substring to
integer and return the result. [[Feature #21932]]

* ObjectSpace

* `ObjectSpace._id2ref` was removed. [[Feature #22135]]

* Regexp

* All instances of `Regexp` are now frozen, not just literals.
Expand Down
24 changes: 0 additions & 24 deletions bootstraptest/test_objectspace.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
assert_normal_exit %q{
eval("", TOPLEVEL_BINDING)
minobj = ObjectSpace.to_enum(:each_object).min_by {|a| a.object_id }
maxobj = ObjectSpace.to_enum(:each_object).max_by {|a| a.object_id }
(((minobj.object_id-100)..(minobj.object_id+100))+
((maxobj.object_id-100)..(maxobj.object_id+100))).each {|id|
begin
o = ObjectSpace._id2ref(id)
rescue RangeError
next
end
o.inspect if defined?(o.inspect)
}
}, '[ruby-dev:31911]'

assert_normal_exit %q{
ary = (1..10).to_a
ary.permutation(2) {|x|
Expand Down Expand Up @@ -44,12 +29,3 @@
Thread.new {}
end
}, '[ruby-core:37858]'

assert_equal 'ok', %q{
objects_and_ids = 1000.times.map { o = Object.new; [o, o.object_id] }
objects_and_ids.each { |expected, id|
actual = ObjectSpace._id2ref(id)
raise "expected #{expected.inspect}, got #{actual.inspect}" unless actual.equal?(expected)
}
'ok'
}
44 changes: 0 additions & 44 deletions bootstraptest/test_ractor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1256,37 +1256,6 @@ class C
}.value
}

# ObjectSpace._id2ref can not handle unshareable objects with Ractors
assert_equal 'ok', <<~'RUBY', frozen_string_literal: false
s = 'hello'

Ractor.new s.object_id do |id ;s|
begin
s = ObjectSpace._id2ref(id)
rescue => e
:ok
end
end.value
RUBY

# Inserting into the id2ref table should be Ractor-safe
assert_equal 'ok', <<~'RUBY'
# Force all calls to Kernel#object_id to insert into the id2ref table
obj = Object.new
ObjectSpace._id2ref(obj.object_id) rescue nil

10.times.map do
Ractor.new do
10_000.times do
a = Object.new
a.object_id
end
end
end.map(&:value)

:ok
RUBY

# Ractor.make_shareable(obj)
assert_equal 'true', <<~'RUBY', frozen_string_literal: false
class C
Expand Down Expand Up @@ -2175,19 +2144,6 @@ def ==(o)
roundtripped_obj.instance_variable_get(:@array1) == [1] ? :ok : roundtripped_obj
}

# move object with generic ivars and existing id2ref table
# [Bug #21664]
assert_equal 'ok', %q{
obj = [1]
obj.instance_variable_set("@field", :ok)
ObjectSpace._id2ref(obj.object_id) # build id2ref table

ractor = Ractor.new { Ractor.receive }
ractor.send(obj, move: true)
obj = ractor.value
obj.instance_variable_get("@field")
}

# copy object with complex generic ivars
assert_equal 'ok', %q{
# Make Array complex
Expand Down
16 changes: 13 additions & 3 deletions ext/json/parser/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1457,7 +1457,7 @@ static inline int json_parse_digits(JSON_ParserState *state, uint64_t *accumulat
return (int)(state->cursor - start);
}

static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig *config, bool negative, const char *start)
static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig *config, bool negative, const char *start, bool resumable)
{
bool integer = true;
const char first_digit = *state->cursor;
Expand Down Expand Up @@ -1514,6 +1514,16 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig
}
}

// A number touching the end of the buffer may still grow in a later chunk,
// so the caller will rewind and wait. Decoding it now would build a value
// -- for a long run of digits, an expensive bignum -- only to discard it,
// and repeating that on every resumed chunk is quadratic in the number's
// length. The digit scan above already advanced the cursor, which is all
// the caller needs to detect the incomplete number.
if (RB_UNLIKELY(resumable && eos(state))) {
return Qundef;
}

if (integer) {
return json_decode_integer(mantissa, mantissa_digits, negative, start, state->cursor);
}
Expand Down Expand Up @@ -1638,7 +1648,7 @@ ALWAYS_INLINE(static) bool json_parse_any(JSON_ParserState *state, JSON_ParserCo
case '-': {
state->cursor++;

value = json_parse_number(state, config, true, value_start);
value = json_parse_number(state, config, true, value_start, resumable);

if (RB_UNLIKELY(UNDEF_P(value) && config->allow_nan && peek(state) == 'I')) {
state->cursor = value_start;
Expand All @@ -1661,7 +1671,7 @@ ALWAYS_INLINE(static) bool json_parse_any(JSON_ParserState *state, JSON_ParserCo
}

case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': {
value = json_parse_number(state, config, false, value_start);
value = json_parse_number(state, config, false, value_start, resumable);

// Top level numbers are ambiguous when parsing streams, we can't
// know if we parsed all the digits if we hit EOS.
Expand Down
Loading