Skip to content

Commit 6b64d02

Browse files
committed
Changes based on review.
1 parent 91924de commit 6b64d02

File tree

6 files changed

+68
-63
lines changed

6 files changed

+68
-63
lines changed

lib/truffle/truffle/cext.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,6 +1368,7 @@ def data_finalizer(free, data_holder)
13681368
end
13691369

13701370
def data_marker(mark, data_holder)
1371+
# In a separate method to avoid capturing the object
13711372
raise unless mark.respond_to?(:call)
13721373
proc { |obj|
13731374
create_mark_list

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,9 +1349,9 @@ protected UnwrapNode createUnwrapNode() {
13491349
public abstract static class SetMarkList extends CoreMethodArrayArgumentsNode {
13501350

13511351
@Specialization
1352-
public DynamicObject setMarkList(VirtualFrame frame, DynamicObject structOnwer,
1352+
public DynamicObject setMarkList(VirtualFrame frame, DynamicObject structOwwer,
13531353
@Cached("createWriter()") WriteObjectFieldNode writeMarkedNode) {
1354-
writeMarkedNode.write(structOnwer, getArray());
1354+
writeMarkedNode.write(structOwwer, getArray());
13551355
return nil();
13561356
}
13571357

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public synchronized long createNativeHandle(DynamicObject wrapper) {
9292
}
9393
Layouts.VALUE_WRAPPER.setHandle(wrapper, handleAddress);
9494
addToHandleMap(handleAddress, wrapper);
95+
context.getMarkingService().keepObject(wrapper);
9596
addFinalizer(wrapper, handlePointer);
9697
return handleAddress;
9798
}

src/main/java/org/truffleruby/core/FinalizationService.java

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -157,27 +157,20 @@ protected String getThreadName() {
157157
protected void processReference(FinalizerReference finalizerReference) {
158158
super.processReference(finalizerReference);
159159

160-
try {
161-
while (!context.isFinalizing()) {
162-
final Finalizer finalizer;
163-
synchronized (this) {
164-
finalizer = finalizerReference.getFirstFinalizer();
165-
}
166-
if (finalizer == null) {
167-
break;
168-
}
169-
final Runnable action = finalizer.getAction();
170-
action.run();
160+
runCatchingErrors(this::processReferenceInternal, finalizerReference);
161+
}
162+
163+
protected void processReferenceInternal(FinalizerReference finalizerReference) {
164+
while (!context.isFinalizing()) {
165+
final Finalizer finalizer;
166+
synchronized (this) {
167+
finalizer = finalizerReference.getFirstFinalizer();
171168
}
172-
} catch (TerminationException e) {
173-
throw e;
174-
} catch (RaiseException e) {
175-
context.getCoreExceptions().showExceptionIfDebug(e.getException());
176-
} catch (Exception e) {
177-
// Do nothing, the finalizer thread must continue to process objects.
178-
if (context.getCoreLibrary().getDebug() == Boolean.TRUE) {
179-
e.printStackTrace();
169+
if (finalizer == null) {
170+
break;
180171
}
172+
final Runnable action = finalizer.getAction();
173+
action.run();
181174
}
182175
}
183176

src/main/java/org/truffleruby/core/MarkingService.java

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,27 @@
1616
import java.util.Deque;
1717

1818
import org.truffleruby.RubyContext;
19-
import org.truffleruby.language.control.RaiseException;
20-
import org.truffleruby.language.control.TerminationException;
2119

2220
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
2321
import com.oracle.truffle.api.object.DynamicObject;
2422

2523
/**
2624
* Class to provide GC marking and other facilities to keep objects alive for native extensions.
2725
*
28-
* Native extensions expect object on the stack to be kept alive even when they have been stored in
29-
* native structures on the stack. They also expect structs in objects with custom mark functions
30-
* keep marked objects alive.
26+
* Native extensions expect objects on the stack to be kept alive even when they have been stored in
27+
* native structures on the stack (e.g. pg keeps the VALUE of a ruby array in a structure on the
28+
* stack, and places other objects in that array to keep them alive). They also expect structs in
29+
* objects with custom mark functions to keep marked objects alive.
3130
*
32-
* Since we are not running on a VM that allows us to add custom ark functions to our garbage
31+
* Since we are not running on a VM that allows us to add custom mark functions to our garbage
3332
* collector we keep objects alive in 2 ways. Any object converted to a native handle can be kept
34-
* alive by calling keepAlive(). This will add the object to two lists, a list of all objects
35-
* converted to native during in this call to a C extension which will be popped when the we return
36-
* to Ruby code, and a fixed sized list of objects converted to native handles. When the latter of
37-
* these two lists is full all mark functions will be run.
33+
* alive by calling {@link #keepObject(Object)}. This will add the object to two lists, a list of
34+
* all objects converted to native during this call to a C extension function which will be popped
35+
* when the we return to Ruby code, and a fixed sized list of objects converted to native handles.
36+
* When the latter of these two lists is full all mark functions will be run.
3837
*
39-
* Markers only keep a week reference to their owning object to ensure they don't themselves stop
40-
* the object from being garbage collected.
38+
* Marker references only keep a week reference to their owning object to ensure they don't
39+
* themselves stop the object from being garbage collected.
4140
*
4241
*/
4342
public class MarkingService extends ReferenceProcessingService<MarkingService.MarkerReference> {
@@ -125,7 +124,7 @@ private synchronized void runAllMarkers() {
125124
nextMarker = currentMarker.next;
126125
runMarker(currentMarker);
127126
if (nextMarker == currentMarker) {
128-
throw new Error("Something went badly wrong.");
127+
throw new Error("The MarkerReference linked list structure has become broken.");
129128
}
130129
currentMarker = nextMarker;
131130
}
@@ -137,22 +136,15 @@ public void addMarker(DynamicObject object, MarkerAction action) {
137136
}
138137

139138
private void runMarker(MarkerReference markerReference) {
140-
try {
141-
if (!context.isFinalizing()) {
142-
DynamicObject owner = markerReference.get();
143-
if (owner != null) {
144-
final MarkerAction action = markerReference.action;
145-
action.mark(owner);
146-
}
147-
}
148-
} catch (TerminationException e) {
149-
throw e;
150-
} catch (RaiseException e) {
151-
context.getCoreExceptions().showExceptionIfDebug(e.getException());
152-
} catch (Exception e) {
153-
// Do nothing, the finalizer thread must continue to process objects.
154-
if (context.getCoreLibrary().getDebug() == Boolean.TRUE) {
155-
e.printStackTrace();
139+
runCatchingErrors(this::runMarkerInternal, markerReference);
140+
}
141+
142+
private void runMarkerInternal(MarkerReference markerReference) {
143+
if (!context.isFinalizing()) {
144+
DynamicObject owner = markerReference.get();
145+
if (owner != null) {
146+
final MarkerAction action = markerReference.action;
147+
action.mark(owner);
156148
}
157149
}
158150
}

src/main/java/org/truffleruby/core/ReferenceProcessingService.java

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
package org.truffleruby.core;
22

33
import java.lang.ref.ReferenceQueue;
4+
import java.util.function.Consumer;
45

56
import org.truffleruby.RubyContext;
67
import org.truffleruby.core.thread.ThreadManager;
8+
import org.truffleruby.language.control.RaiseException;
9+
import org.truffleruby.language.control.TerminationException;
710

811
import com.oracle.truffle.api.object.DynamicObject;
912

10-
public abstract class ReferenceProcessingService<T extends ReferenceProcessingService.ProcessingReference<T>> {
13+
public abstract class ReferenceProcessingService<R extends ReferenceProcessingService.ProcessingReference<R>> {
1114

12-
public static interface ProcessingReference<U extends ProcessingReference<U>> {
13-
public U getPrevious();
15+
public static interface ProcessingReference<R extends ProcessingReference<R>> {
16+
public R getPrevious();
1417

15-
public void setPrevious(U previous);
18+
public void setPrevious(R previous);
1619

17-
public U getNext();
20+
public R getNext();
1821

19-
public void setNext(U next);
22+
public void setNext(R next);
2023
}
2124

2225
/** The head of a doubly-linked list of FinalizerReference, needed to collect finalizer Procs for ObjectSpace. */
23-
private T first = null;
26+
private R first = null;
2427

2528
protected final ReferenceQueue<Object> processingQueue = new ReferenceQueue<>();
2629

@@ -34,7 +37,7 @@ public ReferenceProcessingService(RubyContext context) {
3437
protected final void drainReferenceQueue() {
3538
while (true) {
3639
@SuppressWarnings("unchecked")
37-
final T reference = (T) processingQueue.poll();
40+
final R reference = (R) processingQueue.poll();
3841

3942
if (reference == null) {
4043
break;
@@ -52,17 +55,32 @@ protected void createProcessingThread() {
5255
threadManager.initialize(processingThread, null, getThreadName(), () -> {
5356
while (true) {
5457
@SuppressWarnings("unchecked")
55-
final T reference = (T) threadManager.runUntilResult(null, processingQueue::remove);
58+
final R reference = (R) threadManager.runUntilResult(null, processingQueue::remove);
5659

5760
processReference(reference);
5861
}
5962
});
6063
}
6164

62-
protected void processReference(T reference) {
65+
protected void processReference(R reference) {
6366
remove(reference);
6467
}
6568

69+
protected void runCatchingErrors(Consumer<R> action, R reference) {
70+
try {
71+
action.accept(reference);
72+
} catch (TerminationException e) {
73+
throw e;
74+
} catch (RaiseException e) {
75+
context.getCoreExceptions().showExceptionIfDebug(e.getException());
76+
} catch (Exception e) {
77+
// Do nothing, the finalizer thread must continue to process objects.
78+
if (context.getCoreLibrary().getDebug() == Boolean.TRUE) {
79+
e.printStackTrace();
80+
}
81+
}
82+
}
83+
6684
protected abstract String getThreadName();
6785

6886
protected void processReferenceQueue() {
@@ -89,7 +107,7 @@ protected void processReferenceQueue() {
89107
}
90108
}
91109

92-
protected synchronized void remove(T ref) {
110+
protected synchronized void remove(R ref) {
93111
if (ref.getNext() == ref) {
94112
// Already removed.
95113
return;
@@ -116,15 +134,15 @@ protected synchronized void remove(T ref) {
116134
ref.setPrevious(ref);
117135
}
118136

119-
protected synchronized void add(T newRef) {
137+
protected synchronized void add(R newRef) {
120138
if (first != null) {
121139
newRef.setNext(first);
122140
first.setPrevious(newRef);
123141
}
124142
first = newRef;
125143
}
126144

127-
protected T getFirst() {
145+
protected R getFirst() {
128146
return first;
129147
}
130148
}

0 commit comments

Comments
 (0)