|
30 | 30 | import org.jcodings.Encoding;
|
31 | 31 | import org.jcodings.specific.UTF8Encoding;
|
32 | 32 | import org.truffleruby.Layouts;
|
| 33 | +import org.truffleruby.RubyContext; |
33 | 34 | import org.truffleruby.builtins.CoreClass;
|
34 | 35 | import org.truffleruby.builtins.CoreMethod;
|
35 | 36 | import org.truffleruby.builtins.CoreMethodArrayArgumentsNode;
|
|
75 | 76 | import org.truffleruby.language.control.JavaException;
|
76 | 77 | import org.truffleruby.language.control.RaiseException;
|
77 | 78 | import org.truffleruby.language.dispatch.CallDispatchHeadNode;
|
| 79 | +import org.truffleruby.language.dispatch.DoesRespondDispatchHeadNode; |
78 | 80 | import org.truffleruby.language.methods.DeclarationContext;
|
79 | 81 | import org.truffleruby.language.methods.InternalMethod;
|
80 | 82 | import org.truffleruby.language.objects.InitializeClassNode;
|
|
85 | 87 | import org.truffleruby.language.objects.ObjectIVarGetNodeGen;
|
86 | 88 | import org.truffleruby.language.objects.ObjectIVarSetNode;
|
87 | 89 | import org.truffleruby.language.objects.ObjectIVarSetNodeGen;
|
| 90 | +import org.truffleruby.language.objects.WriteObjectFieldNode; |
| 91 | +import org.truffleruby.language.objects.WriteObjectFieldNodeGen; |
88 | 92 | import org.truffleruby.language.supercall.CallSuperMethodNode;
|
89 | 93 | import org.truffleruby.parser.Identifiers;
|
90 | 94 |
|
@@ -1295,4 +1299,121 @@ protected UnwrapNode createUnwrapNode() {
|
1295 | 1299 | }
|
1296 | 1300 | }
|
1297 | 1301 |
|
| 1302 | + private static ThreadLocal<ArrayList<Object>> markList = new ThreadLocal<>(); |
| 1303 | + |
| 1304 | + @CoreMethod(names = "create_mark_list", onSingleton = true, required = 0) |
| 1305 | + public abstract static class NewMarkerList extends CoreMethodArrayArgumentsNode { |
| 1306 | + |
| 1307 | + @Specialization |
| 1308 | + public DynamicObject createNewMarkList(VirtualFrame frmae) { |
| 1309 | + setThreadLocal(); |
| 1310 | + return nil(); |
| 1311 | + } |
| 1312 | + |
| 1313 | + @TruffleBoundary |
| 1314 | + protected void setThreadLocal() { |
| 1315 | + markList.set(new ArrayList<>()); |
| 1316 | + } |
| 1317 | + } |
| 1318 | + |
| 1319 | + @CoreMethod(names = "rb_gc_mark", onSingleton = true, required = 1) |
| 1320 | + public abstract static class AddToMarkList extends CoreMethodArrayArgumentsNode { |
| 1321 | + |
| 1322 | + @Specialization |
| 1323 | + public DynamicObject addToMarkList(VirtualFrame frmae, Object markedObject, |
| 1324 | + @Cached("create()") BranchProfile exceptionProfile, |
| 1325 | + @Cached("create()") BranchProfile noExceptionProfile, |
| 1326 | + @Cached("createUnwrapNode()") UnwrapNode unwrapNode) { |
| 1327 | + Object unwrappedValue = unwrapNode.execute(markedObject); |
| 1328 | + if (unwrappedValue != null) { |
| 1329 | + noExceptionProfile.enter(); |
| 1330 | + getList().add(unwrappedValue); |
| 1331 | + } |
| 1332 | + // We do nothing here if the handle cannot be resolved. If we are marking an object |
| 1333 | + // which is only reachable via weak refs then the handles of objects it is iteself |
| 1334 | + // marking may have already been removed from the handle map. } |
| 1335 | + return nil(); |
| 1336 | + } |
| 1337 | + |
| 1338 | + @TruffleBoundary |
| 1339 | + protected ArrayList<Object> getList() { |
| 1340 | + return markList.get(); |
| 1341 | + } |
| 1342 | + |
| 1343 | + protected UnwrapNode createUnwrapNode() { |
| 1344 | + return UnwrapNodeGen.create(); |
| 1345 | + } |
| 1346 | + } |
| 1347 | + |
| 1348 | + @CoreMethod(names = "set_mark_list_on_object", onSingleton = true, required = 1) |
| 1349 | + public abstract static class SetMarkList extends CoreMethodArrayArgumentsNode { |
| 1350 | + |
| 1351 | + @Specialization |
| 1352 | + public DynamicObject setMarkList(VirtualFrame frame, DynamicObject structOwwer, |
| 1353 | + @Cached("createWriter()") WriteObjectFieldNode writeMarkedNode) { |
| 1354 | + writeMarkedNode.write(structOwwer, getArray()); |
| 1355 | + return nil(); |
| 1356 | + } |
| 1357 | + |
| 1358 | + @TruffleBoundary |
| 1359 | + protected Object[] getArray() { |
| 1360 | + return markList.get().toArray(); |
| 1361 | + } |
| 1362 | + |
| 1363 | + public WriteObjectFieldNode createWriter() { |
| 1364 | + return WriteObjectFieldNodeGen.create(Layouts.MARKED_OBJECTS_IDENTIFIER); |
| 1365 | + } |
| 1366 | + } |
| 1367 | + |
| 1368 | + @CoreMethod(names = "define_marker", onSingleton = true, required = 2) |
| 1369 | + public abstract static class CreateMarkerNode extends CoreMethodArrayArgumentsNode { |
| 1370 | + |
| 1371 | + @Child private DoesRespondDispatchHeadNode respondToCallNode = DoesRespondDispatchHeadNode.create(); |
| 1372 | + |
| 1373 | + @Specialization |
| 1374 | + public DynamicObject createMarker(VirtualFrame frame, DynamicObject object, DynamicObject marker, |
| 1375 | + @Cached("create()") BranchProfile errorProfile) { |
| 1376 | + if (respondToCallNode.doesRespondTo(frame, "call", marker)) { |
| 1377 | + addObjectToMarkingService(object, marker); |
| 1378 | + return nil(); |
| 1379 | + } else { |
| 1380 | + errorProfile.enter(); |
| 1381 | + throw new RaiseException(getContext(), coreExceptions().argumentErrorWrongArgumentType(marker, "callable", this)); |
| 1382 | + } |
| 1383 | + } |
| 1384 | + |
| 1385 | + @TruffleBoundary |
| 1386 | + protected void addObjectToMarkingService(DynamicObject object, DynamicObject marker) { |
| 1387 | + RubyContext aContext = getContext(); |
| 1388 | + /* |
| 1389 | + * The code here has to be a little subtle. The marker must be associated with the |
| 1390 | + * object it will act on, but the lambda must not capture the object (and prevent |
| 1391 | + * garbage collection). So the marking function is a lambda that will take the |
| 1392 | + * object as an argument 'o' which will be provided when the marking function is |
| 1393 | + * called by the marking service. |
| 1394 | + */ |
| 1395 | + getContext().getMarkingService().addMarker(object, (o) -> aContext.send(marker, "call", o)); |
| 1396 | + } |
| 1397 | + } |
| 1398 | + |
| 1399 | + @CoreMethod(names = "push_preserving_frame", onSingleton = true, required = 0) |
| 1400 | + public abstract static class PushPreservingFrame extends CoreMethodArrayArgumentsNode { |
| 1401 | + |
| 1402 | + @Specialization |
| 1403 | + public DynamicObject pushFrame(VirtualFrame frame) { |
| 1404 | + getContext().getMarkingService().pushStackPreservationFrame(); |
| 1405 | + return nil(); |
| 1406 | + } |
| 1407 | + } |
| 1408 | + |
| 1409 | + @CoreMethod(names = "pop_preserving_frame", onSingleton = true, required = 0) |
| 1410 | + public abstract static class PopPreservingFrame extends CoreMethodArrayArgumentsNode { |
| 1411 | + |
| 1412 | + @Specialization |
| 1413 | + public DynamicObject popFrame(VirtualFrame frame) { |
| 1414 | + getContext().getMarkingService().popStackPreservationFrame(); |
| 1415 | + return nil(); |
| 1416 | + } |
| 1417 | + } |
| 1418 | + |
1298 | 1419 | }
|
0 commit comments