Skip to content

Commit 264c7e0

Browse files
committed
Backport [GR-18163] Fix rb_global_variable() for Float and bignum values during the Init_ function to 24.0.1
PullRequest: truffleruby/4218
2 parents a69cf90 + 1d59aa8 commit 264c7e0

File tree

12 files changed

+151
-65
lines changed

12 files changed

+151
-65
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# 24.0.1
2+
3+
Bug fixes:
4+
* Fix `rb_global_variable()` for `Float` and bignum values during the `Init_` function (#3478, @eregon).
5+
16
# 24.0.0
27

38
New features:

lib/cext/ABI_check.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
13
1+
14

lib/truffle/truffle/cext.rb

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,15 @@ def init_extension(library, library_path)
214214
function_name = "Init_#{name}"
215215

216216
init_function = library[function_name]
217-
begin
218-
Primitive.call_with_c_mutex_and_frame(VOID_TO_VOID_WRAPPER, [init_function], nil, nil)
219-
ensure
220-
resolve_registered_addresses
221-
end
217+
218+
Primitive.call_with_c_mutex_and_frame(-> {
219+
begin
220+
Primitive.interop_execute(VOID_TO_VOID_WRAPPER, [init_function])
221+
ensure
222+
# Resolve while inside the ExtensionCallStackEntry to ensure the preservedObjects are still all alive
223+
resolve_registered_addresses
224+
end
225+
}, [], nil, nil)
222226
end
223227

224228
def supported?
@@ -2238,15 +2242,19 @@ def rb_gc_register_address(address)
22382242
else
22392243
# Read it immediately if outside Init_ function.
22402244
# This assumes the value is already set when this is called and does not change after that.
2241-
GC_REGISTERED_ADDRESSES[address] = LIBTRUFFLERUBY.rb_tr_read_VALUE_pointer(address)
2245+
register_address(address)
22422246
end
22432247
end
22442248

22452249
def resolve_registered_addresses
2246-
c_global_variables = Primitive.fiber_c_global_variables
2247-
c_global_variables.each do |address|
2248-
GC_REGISTERED_ADDRESSES[address] = LIBTRUFFLERUBY.rb_tr_read_VALUE_pointer(address)
2249-
end
2250+
Primitive.fiber_c_global_variables.each { |address| register_address(address) }
2251+
end
2252+
2253+
private def register_address(address)
2254+
# We save the ValueWrapper here and not the actual value/object, this is important for primitives like double and
2255+
# not-fixnum-long, as we need to preserve the handle by preserving the ValueWrapper of that handle.
2256+
# For those cases the primitive cannot itself reference its ValueWrapper, unlike RubyDynamicObject and ImmutableRubyObject.
2257+
GC_REGISTERED_ADDRESSES[address] = Primitive.cext_to_wrapper LIBTRUFFLERUBY.rb_tr_read_VALUE_pointer(address)
22502258
end
22512259

22522260
def rb_gc_unregister_address(address)

spec/ruby/optional/capi/ext/gc_spec.c

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ extern "C" {
88
VALUE registered_tagged_value;
99
VALUE registered_reference_value;
1010
VALUE registered_before_rb_gc_register_address;
11-
VALUE registered_before_rb_global_variable;
11+
VALUE registered_before_rb_global_variable_string;
12+
VALUE registered_before_rb_global_variable_bignum;
13+
VALUE registered_before_rb_global_variable_float;
14+
VALUE registered_after_rb_global_variable_string;
15+
VALUE registered_after_rb_global_variable_bignum;
16+
VALUE registered_after_rb_global_variable_float;
1217
VALUE rb_gc_register_address_outside_init;
1318

1419
static VALUE registered_tagged_address(VALUE self) {
@@ -23,8 +28,28 @@ static VALUE get_registered_before_rb_gc_register_address(VALUE self) {
2328
return registered_before_rb_gc_register_address;
2429
}
2530

26-
static VALUE get_registered_before_rb_global_variable(VALUE self) {
27-
return registered_before_rb_global_variable;
31+
static VALUE get_registered_before_rb_global_variable_string(VALUE self) {
32+
return registered_before_rb_global_variable_string;
33+
}
34+
35+
static VALUE get_registered_before_rb_global_variable_bignum(VALUE self) {
36+
return registered_before_rb_global_variable_bignum;
37+
}
38+
39+
static VALUE get_registered_before_rb_global_variable_float(VALUE self) {
40+
return registered_before_rb_global_variable_float;
41+
}
42+
43+
static VALUE get_registered_after_rb_global_variable_string(VALUE self) {
44+
return registered_after_rb_global_variable_string;
45+
}
46+
47+
static VALUE get_registered_after_rb_global_variable_bignum(VALUE self) {
48+
return registered_after_rb_global_variable_bignum;
49+
}
50+
51+
static VALUE get_registered_after_rb_global_variable_float(VALUE self) {
52+
return registered_after_rb_global_variable_float;
2853
}
2954

3055
static VALUE gc_spec_rb_gc_register_address(VALUE self) {
@@ -71,17 +96,34 @@ void Init_gc_spec(void) {
7196
rb_gc_register_address(&registered_tagged_value);
7297
rb_gc_register_address(&registered_reference_value);
7398
rb_gc_register_address(&registered_before_rb_gc_register_address);
74-
rb_global_variable(&registered_before_rb_global_variable);
99+
rb_global_variable(&registered_before_rb_global_variable_string);
100+
rb_global_variable(&registered_before_rb_global_variable_bignum);
101+
rb_global_variable(&registered_before_rb_global_variable_float);
75102

76103
registered_tagged_value = INT2NUM(10);
77104
registered_reference_value = rb_str_new2("Globally registered data");
78105
registered_before_rb_gc_register_address = rb_str_new_cstr("registered before rb_gc_register_address()");
79-
registered_before_rb_global_variable = rb_str_new_cstr("registered before rb_global_variable()");
106+
107+
registered_before_rb_global_variable_string = rb_str_new_cstr("registered before rb_global_variable()");
108+
registered_before_rb_global_variable_bignum = LONG2NUM(INT64_MAX);
109+
registered_before_rb_global_variable_float = DBL2NUM(3.14);
110+
111+
registered_after_rb_global_variable_string = rb_str_new_cstr("registered after rb_global_variable()");
112+
rb_global_variable(&registered_after_rb_global_variable_string);
113+
registered_after_rb_global_variable_bignum = LONG2NUM(INT64_MAX);
114+
rb_global_variable(&registered_after_rb_global_variable_bignum);
115+
registered_after_rb_global_variable_float = DBL2NUM(6.28);
116+
rb_global_variable(&registered_after_rb_global_variable_float);
80117

81118
rb_define_method(cls, "registered_tagged_address", registered_tagged_address, 0);
82119
rb_define_method(cls, "registered_reference_address", registered_reference_address, 0);
83120
rb_define_method(cls, "registered_before_rb_gc_register_address", get_registered_before_rb_gc_register_address, 0);
84-
rb_define_method(cls, "registered_before_rb_global_variable", get_registered_before_rb_global_variable, 0);
121+
rb_define_method(cls, "registered_before_rb_global_variable_string", get_registered_before_rb_global_variable_string, 0);
122+
rb_define_method(cls, "registered_before_rb_global_variable_bignum", get_registered_before_rb_global_variable_bignum, 0);
123+
rb_define_method(cls, "registered_before_rb_global_variable_float", get_registered_before_rb_global_variable_float, 0);
124+
rb_define_method(cls, "registered_after_rb_global_variable_string", get_registered_after_rb_global_variable_string, 0);
125+
rb_define_method(cls, "registered_after_rb_global_variable_bignum", get_registered_after_rb_global_variable_bignum, 0);
126+
rb_define_method(cls, "registered_after_rb_global_variable_float", get_registered_after_rb_global_variable_float, 0);
85127
rb_define_method(cls, "rb_gc_register_address", gc_spec_rb_gc_register_address, 0);
86128
rb_define_method(cls, "rb_gc_unregister_address", gc_spec_rb_gc_unregister_address, 0);
87129
rb_define_method(cls, "rb_gc_enable", gc_spec_rb_gc_enable, 0);

spec/ruby/optional/capi/gc_spec.rb

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,36 @@
2727
end
2828

2929
describe "rb_global_variable" do
30-
it "keeps the value alive even if the value is assigned after rb_global_variable() is called" do
30+
before :all do
3131
GC.start
32-
@f.registered_before_rb_global_variable.should == "registered before rb_global_variable()"
32+
end
33+
34+
describe "keeps the value alive even if the value is assigned after rb_global_variable() is called" do
35+
it "for a string" do
36+
@f.registered_before_rb_global_variable_string.should == "registered before rb_global_variable()"
37+
end
38+
39+
it "for a bignum" do
40+
@f.registered_before_rb_global_variable_bignum.should == 2**63 - 1
41+
end
42+
43+
it "for a Float" do
44+
@f.registered_before_rb_global_variable_float.should == 3.14
45+
end
46+
end
47+
48+
describe "keeps the value alive when the value is assigned before rb_global_variable() is called" do
49+
it "for a string" do
50+
@f.registered_after_rb_global_variable_string.should == "registered after rb_global_variable()"
51+
end
52+
53+
it "for a bignum" do
54+
@f.registered_after_rb_global_variable_bignum.should == 2**63 - 1
55+
end
56+
57+
it "for a Float" do
58+
@f.registered_after_rb_global_variable_float.should == 6.28
59+
end
3360
end
3461
end
3562

src/main/c/cext/gc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ void rb_gc_register_mark_object(VALUE obj) {
6969
}
7070

7171
void* rb_tr_read_VALUE_pointer(VALUE *pointer) {
72-
VALUE value = *pointer;
73-
return rb_tr_unwrap(value);
72+
// No rb_tr_unwrap() here as the caller actually wants a ValueWrapper or a handle
73+
return *pointer;
7474
}
7575

7676
int rb_during_gc(void) {

src/main/java/org/truffleruby/cext/CExtNodes.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,11 +1790,10 @@ Object sym2id(RubySymbol symbol,
17901790
public abstract static class WrapValueNode extends PrimitiveArrayArgumentsNode {
17911791

17921792
@Specialization
1793-
Object wrapInt(Object value,
1793+
ValueWrapper wrap(Object value,
17941794
@Cached WrapNode wrapNode) {
17951795
return wrapNode.execute(value);
17961796
}
1797-
17981797
}
17991798

18001799
@Primitive(name = "cext_unwrap")
@@ -1819,6 +1818,21 @@ private String exceptionMessage(Object value) {
18191818
}
18201819
}
18211820

1821+
@Primitive(name = "cext_to_wrapper")
1822+
public abstract static class CExtToWrapperNode extends PrimitiveArrayArgumentsNode {
1823+
@Specialization
1824+
ValueWrapper toWrapper(Object value,
1825+
@Cached UnwrapNode.ToWrapperNode toWrapperNode) {
1826+
ValueWrapper wrapper = toWrapperNode.execute(this, value);
1827+
if (wrapper == null) {
1828+
CompilerDirectives.transferToInterpreterAndInvalidate();
1829+
throw CompilerDirectives.shouldNotReachHere("ValueWrapper not found for " + value);
1830+
}
1831+
return wrapper;
1832+
}
1833+
}
1834+
1835+
18221836
@CoreMethod(names = "create_mark_list", onSingleton = true, required = 1)
18231837
public abstract static class NewMarkerList extends CoreMethodArrayArgumentsNode {
18241838

@@ -1836,7 +1850,7 @@ Object createNewMarkList(RubyDynamicObject object,
18361850
public abstract static class AddToMarkList extends CoreMethodArrayArgumentsNode {
18371851

18381852
@Specialization
1839-
Object addToMarkList(Object markedObject,
1853+
Object rbGCMark(Object markedObject,
18401854
@Cached InlinedBranchProfile noExceptionProfile,
18411855
@Cached UnwrapNode.ToWrapperNode toWrapperNode) {
18421856
ValueWrapper wrappedValue = toWrapperNode.execute(this, markedObject);

src/main/java/org/truffleruby/cext/ValueWrapper.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,10 @@ protected Class<RubyLanguage> getLanguage() {
7474
@Override
7575
public String toString() {
7676
if (object != null) {
77-
return object.toString();
77+
return "ValueWrapper[" + object + "]";
7878
} else {
7979
assert ValueWrapperManager.isTaggedLong(handle);
80-
return Long.toString(ValueWrapperManager.untagTaggedLong(handle));
80+
return "ValueWrapper[" + ValueWrapperManager.untagTaggedLong(handle) + "]";
8181
}
8282
}
8383

@@ -92,7 +92,7 @@ protected String toDisplayString(boolean allowSideEffects) {
9292
throw TranslateInteropExceptionNode.executeUncached(e);
9393
}
9494
} else {
95-
return "VALUE: " + toString();
95+
return "VALUE: " + this;
9696
}
9797
}
9898

src/main/java/org/truffleruby/cext/ValueWrapperManager.java

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,13 @@ public final class ValueWrapperManager {
6464

6565
private volatile HandleBlockWeakReference[] blockMap = new HandleBlockWeakReference[0];
6666

67-
public static HandleBlockHolder getBlockHolder(RubyContext context, RubyLanguage language) {
67+
public static HandleBlockHolder getBlockHolder(RubyLanguage language) {
6868
return language.getCurrentFiber().handleData;
6969
}
7070

71-
/* We keep a map of long wrappers that have been generated because various C extensions assume that any given fixnum
72-
* will translate to a given VALUE. */
73-
public ValueWrapper longWrapper(long value) {
74-
return new ValueWrapper(value, UNSET_HANDLE, null);
75-
}
76-
77-
public ValueWrapper doubleWrapper(double value) {
78-
return new ValueWrapper(value, UNSET_HANDLE, null);
79-
}
80-
8171
@TruffleBoundary
82-
public synchronized HandleBlock addToBlockMap(RubyContext context, RubyLanguage language) {
83-
HandleBlock block = new HandleBlock(context, language, this);
72+
public synchronized HandleBlock addToBlockMap(RubyLanguage language) {
73+
HandleBlock block = new HandleBlock(language, this);
8474
int blockIndex = block.getIndex();
8575
HandleBlockWeakReference[] map = growMapIfRequired(blockMap, blockIndex);
8676
blockMap = map;
@@ -90,9 +80,9 @@ public synchronized HandleBlock addToBlockMap(RubyContext context, RubyLanguage
9080
}
9181

9282
@TruffleBoundary
93-
public HandleBlock addToSharedBlockMap(RubyContext context, RubyLanguage language) {
83+
public HandleBlock addToSharedBlockMap(RubyLanguage language) {
9484
synchronized (language) {
95-
HandleBlock block = new HandleBlock(context, language, this);
85+
HandleBlock block = new HandleBlock(language, this);
9686
int blockIndex = block.getIndex();
9787
HandleBlockWeakReference[] map = growMapIfRequired(language.handleBlockSharedMap, blockIndex);
9888
language.handleBlockSharedMap = map;
@@ -153,7 +143,7 @@ public void freeAllBlocksInMap() {
153143
}
154144
}
155145

156-
public void cleanup(RubyContext context, HandleBlockHolder holder) {
146+
public void cleanup(HandleBlockHolder holder) {
157147
holder.handleBlock = null;
158148
}
159149

@@ -215,7 +205,7 @@ public static final class HandleBlock {
215205

216206
@SuppressWarnings("unused") private Cleanable cleanable;
217207

218-
public HandleBlock(RubyContext context, RubyLanguage language, ValueWrapperManager manager) {
208+
public HandleBlock(RubyLanguage language, ValueWrapperManager manager) {
219209
HandleBlockAllocator allocator = language.handleBlockAllocator;
220210
long base = allocator.getFreeBlock();
221211
this.base = base;
@@ -297,7 +287,7 @@ static long allocateHandleOnKnownThread(Node node, ValueWrapper wrapper) {
297287
wrapper,
298288
getContext(node),
299289
getLanguage(node),
300-
getBlockHolder(getContext(node), getLanguage(node)),
290+
getBlockHolder(getLanguage(node)),
301291
false);
302292
}
303293

@@ -311,7 +301,7 @@ static long allocateSharedHandleOnKnownThread(Node node, ValueWrapper wrapper) {
311301
wrapper,
312302
getContext(node),
313303
getLanguage(node),
314-
getBlockHolder(getContext(node), getLanguage(node)),
304+
getBlockHolder(getLanguage(node)),
315305
true);
316306
}
317307

@@ -339,10 +329,10 @@ protected static long allocateHandle(Node node, ValueWrapper wrapper, RubyContex
339329

340330
if (block == null || block.isFull()) {
341331
if (shared) {
342-
block = context.getValueWrapperManager().addToSharedBlockMap(context, language);
332+
block = context.getValueWrapperManager().addToSharedBlockMap(language);
343333
holder.sharedHandleBlock = block;
344334
} else {
345-
block = context.getValueWrapperManager().addToBlockMap(context, language);
335+
block = context.getValueWrapperManager().addToBlockMap(language);
346336
holder.handleBlock = block;
347337
}
348338

@@ -356,10 +346,8 @@ protected static boolean isSharedObject(ValueWrapper wrapper) {
356346
}
357347

358348
public static HandleBlock allocateNewBlock(RubyContext context, RubyLanguage language) {
359-
HandleBlockHolder holder = getBlockHolder(context, language);
360-
HandleBlock block = holder.handleBlock;
361-
362-
block = context.getValueWrapperManager().addToBlockMap(context, language);
349+
HandleBlockHolder holder = getBlockHolder(language);
350+
HandleBlock block = context.getValueWrapperManager().addToBlockMap(language);
363351

364352
holder.handleBlock = block;
365353
return block;

0 commit comments

Comments
 (0)