Skip to content

Commit 1500988

Browse files
committed
Marking changes
PullRequest: truffleruby/542
2 parents 34af70a + 8c1feaa commit 1500988

File tree

15 files changed

+242
-62
lines changed

15 files changed

+242
-62
lines changed

lib/cext/include/ruby/ruby.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -498,10 +498,11 @@ MUST_INLINE int RB_FLOAT_TYPE_P(VALUE obj);
498498

499499
bool RB_TYPE_P(VALUE value, int type);
500500

501-
#define HAVE_RB_GC_GUARDED_PTR_VAL 1
502-
#define rb_gc_guarded_ptr_val(ptr, val) (ptr)
503-
#define RB_GC_GUARD(v) (v)
504-
#define RB_GC_GUARD_PTR(ptr) (ptr)
501+
#define RB_GC_GUARD(v) \
502+
(*__extension__ ({ \
503+
volatile VALUE *rb_gc_guarded_ptr = rb_tr_gc_guard(&v); \
504+
rb_gc_guarded_ptr; \
505+
}))
505506

506507
#ifdef __GNUC__
507508
#define RB_UNUSED_VAR(x) x __attribute__ ((unused))

lib/cext/include/truffleruby/truffleruby-pre.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ MUST_INLINE VALUE rb_tr_unwrap(VALUE object) {
4848
return polyglot_invoke(RUBY_CEXT, "rb_tr_unwrap", object);
4949
}
5050

51+
// Needed for GC guarding
52+
53+
MUST_INLINE VALUE *rb_tr_gc_guard(VALUE *ptr) {
54+
polyglot_invoke(RUBY_CEXT, "rb_tr_gc_guard", *ptr);
55+
return ptr;
56+
}
57+
5158
#include <ruby/thread_native.h>
5259

5360
// Helpers

lib/truffle/truffle/cext.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,7 +1451,7 @@ def data_finalizer(free, data_holder)
14511451
# In a separate method to avoid capturing the object
14521452
raise unless free.respond_to?(:call)
14531453
proc {
1454-
execute_with_mutex(free, data_holder.data)
1454+
execute_with_mutex(free, data_holder.data) unless data_holder.data.nil?
14551455
}
14561456
end
14571457

@@ -1460,7 +1460,7 @@ def data_marker(mark, data_holder)
14601460
raise unless mark.respond_to?(:call)
14611461
proc { |obj|
14621462
create_mark_list
1463-
execute_with_mutex(mark, data_holder.data)
1463+
execute_with_mutex(mark, data_holder.data) unless data_holder.data.nil?
14641464
set_mark_list_on_object(obj)
14651465
}
14661466
end

src/main/java/org/truffleruby/RubyContext.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ public class RubyContext {
108108
private final CodeLoader codeLoader = new CodeLoader(this);
109109
private final FeatureLoader featureLoader = new FeatureLoader(this);
110110
private final TraceManager traceManager;
111-
private final ReferenceProcessor referenceProcessor = new ReferenceProcessor(this);
112-
private final FinalizationService finalizationService = new FinalizationService(this, referenceProcessor);
113-
private final MarkingService markingService = new MarkingService(this, referenceProcessor);
111+
private final ReferenceProcessor referenceProcessor;
112+
private final FinalizationService finalizationService;
113+
private final MarkingService markingService;
114114
private final ObjectSpaceManager objectSpaceManager = new ObjectSpaceManager(this);
115115
private final SharedObjects sharedObjects = new SharedObjects(this);
116116
private final AtExitManager atExitManager = new AtExitManager(this);
@@ -174,6 +174,10 @@ public RubyContext(RubyLanguage language, TruffleLanguage.Env env) {
174174

175175
options = createOptions(env);
176176

177+
referenceProcessor = new ReferenceProcessor(this);
178+
finalizationService = new FinalizationService(this, referenceProcessor);
179+
markingService = new MarkingService(this, referenceProcessor);
180+
177181
// We need to construct this at runtime
178182
random = createRandomInstance();
179183

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

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import com.oracle.truffle.api.Truffle;
1515
import com.oracle.truffle.api.dsl.Cached;
1616
import com.oracle.truffle.api.dsl.CreateCast;
17+
import com.oracle.truffle.api.dsl.Fallback;
1718
import com.oracle.truffle.api.dsl.NodeChild;
1819
import com.oracle.truffle.api.dsl.NodeChildren;
1920
import com.oracle.truffle.api.dsl.Specialization;
@@ -1316,24 +1317,29 @@ protected WrapNode createWrapNode() {
13161317
public abstract static class UnwrapValueNode extends CoreMethodArrayArgumentsNode {
13171318

13181319
@Specialization
1319-
public Object unwrap(Object value,
1320+
public Object unwrap(TruffleObject value,
13201321
@Cached("create()") BranchProfile exceptionProfile,
13211322
@Cached("createUnwrapNode()") UnwrapNode unwrapNode) {
13221323
Object object = unwrapNode.execute(value);
13231324
if (object == null) {
13241325
exceptionProfile.enter();
1325-
throw new RaiseException(getContext(), coreExceptions().runtimeError("native handle not found", this));
1326+
throw new RaiseException(getContext(), coreExceptions().runtimeError(exceptionMessage(value), this));
13261327
} else {
13271328
return object;
13281329
}
13291330
}
13301331

1332+
@TruffleBoundary
1333+
private String exceptionMessage(Object value) {
1334+
return String.format("native handle not found (%s)", value);
1335+
}
1336+
13311337
protected UnwrapNode createUnwrapNode() {
13321338
return UnwrapNodeGen.create();
13331339
}
13341340
}
13351341

1336-
private static ThreadLocal<ArrayList<Object>> markList = new ThreadLocal<>();
1342+
private static final ThreadLocal<ArrayList<Object>> markList = new ThreadLocal<>();
13371343

13381344
@CoreMethod(names = "create_mark_list", onSingleton = true, required = 0)
13391345
public abstract static class NewMarkerList extends CoreMethodArrayArgumentsNode {
@@ -1354,14 +1360,14 @@ protected void setThreadLocal() {
13541360
public abstract static class AddToMarkList extends CoreMethodArrayArgumentsNode {
13551361

13561362
@Specialization
1357-
public DynamicObject addToMarkList(VirtualFrame frmae, Object markedObject,
1363+
public DynamicObject addToMarkList(VirtualFrame frmae, TruffleObject markedObject,
13581364
@Cached("create()") BranchProfile exceptionProfile,
13591365
@Cached("create()") BranchProfile noExceptionProfile,
1360-
@Cached("createUnwrapNode()") UnwrapNode unwrapNode) {
1361-
Object unwrappedValue = unwrapNode.execute(markedObject);
1362-
if (unwrappedValue != null) {
1366+
@Cached("create()") UnwrapNode.ToWrapperNode toWrapperNode) {
1367+
ValueWrapper wrappedValue = toWrapperNode.execute(markedObject);
1368+
if (wrappedValue != null) {
13631369
noExceptionProfile.enter();
1364-
getList().add(unwrappedValue);
1370+
getList().add(wrappedValue);
13651371
}
13661372
// We do nothing here if the handle cannot be resolved. If we are marking an object
13671373
// which is only reachable via weak refs then the handles of objects it is iteself
@@ -1379,6 +1385,33 @@ protected UnwrapNode createUnwrapNode() {
13791385
}
13801386
}
13811387

1388+
@CoreMethod(names = "rb_tr_gc_guard", onSingleton = true, required = 1)
1389+
public abstract static class GCGuardNode extends CoreMethodArrayArgumentsNode {
1390+
1391+
@Specialization
1392+
public DynamicObject addToMarkList(VirtualFrame frmae, TruffleObject guardedObject,
1393+
@Cached("create()") BranchProfile noExceptionProfile,
1394+
@Cached("create()") UnwrapNode.ToWrapperNode toWrapperNode) {
1395+
ValueWrapper wrappedValue = toWrapperNode.execute(guardedObject);
1396+
if (wrappedValue != null) {
1397+
noExceptionProfile.enter();
1398+
getContext().getMarkingService().keepObject(guardedObject);
1399+
}
1400+
return nil();
1401+
}
1402+
1403+
@Fallback
1404+
public DynamicObject addToMarkList(VirtualFrame frmae, Object guardedObject) {
1405+
// Do nothing for unexpected objects, no matter how unexpected. This can occur inside
1406+
// macros that guard a variable which may not have been initialized.
1407+
return nil();
1408+
}
1409+
1410+
protected UnwrapNode createUnwrapNode() {
1411+
return UnwrapNodeGen.create();
1412+
}
1413+
}
1414+
13821415
@CoreMethod(names = "set_mark_list_on_object", onSingleton = true, required = 1)
13831416
public abstract static class SetMarkList extends CoreMethodArrayArgumentsNode {
13841417

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

Lines changed: 97 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@
99
*/
1010
package org.truffleruby.cext;
1111

12-
import static org.truffleruby.cext.ValueWrapperManager.TAG_MASK;
13-
import static org.truffleruby.cext.ValueWrapperManager.LONG_TAG;
14-
import static org.truffleruby.cext.ValueWrapperManager.OBJECT_TAG;
12+
import static org.truffleruby.cext.ValueWrapperManager.TRUE_HANDLE;
13+
import static org.truffleruby.cext.ValueWrapperManager.UNDEF_HANDLE;
14+
import static org.truffleruby.cext.ValueWrapperManager.NIL_HANDLE;
1515
import static org.truffleruby.cext.ValueWrapperManager.FALSE_HANDLE;
1616

17+
import org.truffleruby.cext.UnwrapNodeGen.NativeToWrapperNodeGen;
18+
import org.truffleruby.cext.UnwrapNodeGen.ToWrapperNodeGen;
1719
import org.truffleruby.cext.UnwrapNodeGen.UnwrapNativeNodeGen;
1820
import org.truffleruby.language.NotProvided;
1921
import org.truffleruby.language.RubyBaseNode;
2022
import org.truffleruby.language.control.RaiseException;
2123

2224
import com.oracle.truffle.api.dsl.Cached;
25+
import com.oracle.truffle.api.dsl.Fallback;
2326
import com.oracle.truffle.api.dsl.ImportStatic;
2427
import com.oracle.truffle.api.dsl.Specialization;
2528
import com.oracle.truffle.api.interop.ForeignAccess;
@@ -30,7 +33,7 @@
3033
import com.oracle.truffle.api.object.DynamicObject;
3134
import com.oracle.truffle.api.profiles.BranchProfile;
3235

33-
@ImportStatic(Message.class)
36+
@ImportStatic({ Message.class, ValueWrapperManager.class })
3437
public abstract class UnwrapNode extends RubyBaseNode {
3538

3639
@ImportStatic(ValueWrapperManager.class)
@@ -68,20 +71,103 @@ public Object unwrapTaggedObject(long handle) {
6871
return getContext().getValueWrapperManager().getFromHandleMap(handle);
6972
}
7073

71-
public boolean isTaggedLong(long handle) {
72-
return (handle & LONG_TAG) == LONG_TAG;
73-
}
74-
75-
public boolean isTaggedObject(long handle) {
76-
return handle != FALSE_HANDLE && (handle & TAG_MASK) == OBJECT_TAG;
74+
@Fallback
75+
public ValueWrapper unWrapUnexpectedHandle(long handle) {
76+
// Avoid throwing a specialization exception when given an uninitialized or corrupt
77+
// handle.
78+
return null;
7779
}
7880

7981
public static UnwrapNativeNode create() {
8082
return UnwrapNativeNodeGen.create();
8183
}
8284
}
8385

84-
public abstract Object execute(Object value);
86+
@ImportStatic(ValueWrapperManager.class)
87+
public static abstract class NativeToWrapperNode extends RubyBaseNode {
88+
89+
public abstract ValueWrapper execute(long handle);
90+
91+
@Specialization(guards = "handle == FALSE_HANDLE")
92+
public ValueWrapper unwrapFalse(long handle) {
93+
return new ValueWrapper(false, FALSE_HANDLE);
94+
}
95+
96+
@Specialization(guards = "handle == TRUE_HANDLE")
97+
public ValueWrapper unwrapTrue(long handle) {
98+
return new ValueWrapper(true, TRUE_HANDLE);
99+
}
100+
101+
@Specialization(guards = "handle == UNDEF_HANDLE")
102+
public ValueWrapper unwrapUndef(long handle) {
103+
return new ValueWrapper(NotProvided.INSTANCE, UNDEF_HANDLE);
104+
}
105+
106+
@Specialization(guards = "handle == NIL_HANDLE")
107+
public ValueWrapper unwrapNil(long handle) {
108+
return new ValueWrapper(nil(), NIL_HANDLE);
109+
}
110+
111+
@Specialization(guards = "isTaggedLong(handle)")
112+
public ValueWrapper unwrapTaggedLong(long handle) {
113+
return new ValueWrapper(handle >> 1, handle);
114+
}
115+
116+
@Specialization(guards = "isTaggedObject(handle)")
117+
public ValueWrapper unwrapTaggedObject(long handle) {
118+
return getContext().getValueWrapperManager().getWrapperFromHandleMap(handle);
119+
}
120+
121+
@Fallback
122+
public ValueWrapper unWrapUnexpectedHandle(long handle) {
123+
// Avoid throwing a specialization exception when given an uninitialized or corrupt
124+
// handle.
125+
return null;
126+
}
127+
128+
public static NativeToWrapperNode create() {
129+
return NativeToWrapperNodeGen.create();
130+
}
131+
}
132+
133+
@ImportStatic({ Message.class, ValueWrapperManager.class })
134+
public static abstract class ToWrapperNode extends RubyBaseNode {
135+
136+
public abstract ValueWrapper execute(TruffleObject value);
137+
138+
@Specialization
139+
public ValueWrapper wrappedValueWrapper(ValueWrapper value) {
140+
return value;
141+
}
142+
143+
@Specialization(guards = "!isWrapper(value)")
144+
public ValueWrapper unwrapTypeCastObject(TruffleObject value,
145+
@Cached("IS_POINTER.createNode()") Node isPointerNode,
146+
@Cached("AS_POINTER.createNode()") Node asPointerNode,
147+
@Cached("create()") NativeToWrapperNode nativeToWrapperNode,
148+
@Cached("create()") BranchProfile unsupportedProfile,
149+
@Cached("create()") BranchProfile nonPointerProfile) {
150+
if (ForeignAccess.sendIsPointer(isPointerNode, value)) {
151+
long handle = 0;
152+
try {
153+
handle = ForeignAccess.sendAsPointer(asPointerNode, value);
154+
} catch (UnsupportedMessageException e) {
155+
unsupportedProfile.enter();
156+
throw new RaiseException(getContext(), coreExceptions().argumentError(e.getMessage(), this, e));
157+
}
158+
return nativeToWrapperNode.execute(handle);
159+
} else {
160+
nonPointerProfile.enter();
161+
return null;
162+
}
163+
}
164+
165+
public static ToWrapperNode create() {
166+
return ToWrapperNodeGen.create();
167+
}
168+
}
169+
170+
public abstract Object execute(TruffleObject value);
85171

86172
@Specialization
87173
public Object unwrapValue(ValueWrapper value) {
@@ -109,8 +195,4 @@ public Object unwrapTypeCastObject(TruffleObject value,
109195
throw new RaiseException(getContext(), coreExceptions().argumentError("Not a handle or a pointer", this));
110196
}
111197
}
112-
113-
public static boolean isWrapper(TruffleObject value) {
114-
return value instanceof ValueWrapper;
115-
}
116198
}

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

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
import org.truffleruby.RubyContext;
1515
import org.truffleruby.collections.LongHashMap;
1616
import org.truffleruby.extra.ffi.Pointer;
17+
1718
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
19+
import com.oracle.truffle.api.interop.TruffleObject;
1820

1921
public class ValueWrapperManager {
2022

@@ -49,8 +51,7 @@ public ValueWrapperManager(RubyContext context) {
4951
* We keep a map of long wrappers that have been generated because various C extensions assume
5052
* that any given fixnum will translate to a given VALUE.
5153
*/
52-
@TruffleBoundary
53-
public synchronized ValueWrapper longWrapper(long value) {
54+
public ValueWrapper longWrapper(long value) {
5455
return new ValueWrapper(value, UNSET_HANDLE);
5556
}
5657

@@ -76,6 +77,19 @@ public synchronized Object getFromHandleMap(long handle) {
7677
return wrapper.getObject();
7778
}
7879

80+
@TruffleBoundary
81+
public synchronized ValueWrapper getWrapperFromHandleMap(long handle) {
82+
WeakReference<ValueWrapper> ref = handleMap.get(handle);
83+
ValueWrapper wrapper;
84+
if (ref == null) {
85+
return null;
86+
}
87+
if ((wrapper = ref.get()) == null) {
88+
return null;
89+
}
90+
return wrapper;
91+
}
92+
7993
@TruffleBoundary
8094
public synchronized void removeFromHandleMap(long handle) {
8195
handleMap.remove(handle);
@@ -90,7 +104,6 @@ public synchronized long createNativeHandle(ValueWrapper wrapper) {
90104
}
91105
wrapper.setHandle(handleAddress);
92106
addToHandleMap(handleAddress, wrapper);
93-
context.getMarkingService().keepObject(wrapper);
94107
addFinalizer(wrapper, handlePointer);
95108
return handleAddress;
96109
}
@@ -108,4 +121,16 @@ private Runnable createFinalizer(Pointer handle) {
108121
};
109122

110123
}
124+
125+
public static boolean isTaggedLong(long handle) {
126+
return (handle & LONG_TAG) == LONG_TAG;
127+
}
128+
129+
public static boolean isTaggedObject(long handle) {
130+
return handle != FALSE_HANDLE && (handle & TAG_MASK) == OBJECT_TAG;
131+
}
132+
133+
public static boolean isWrapper(TruffleObject value) {
134+
return value instanceof ValueWrapper;
135+
}
111136
}

0 commit comments

Comments
 (0)