Skip to content

Commit 6536392

Browse files
committed
Add support for tracking closed handles in HPy debug mode
1 parent 53cd490 commit 6536392

File tree

6 files changed

+139
-23
lines changed

6 files changed

+139
-23
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/GraalHPyDebugModuleBuiltins.java

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,17 @@
4545
import java.io.IOException;
4646
import java.util.ArrayList;
4747
import java.util.List;
48+
import java.util.Queue;
4849

4950
import com.oracle.graal.python.PythonLanguage;
51+
import com.oracle.graal.python.annotations.ArgumentClinic;
52+
import com.oracle.graal.python.annotations.ArgumentClinic.ClinicConversion;
5053
import com.oracle.graal.python.builtins.Builtin;
5154
import com.oracle.graal.python.builtins.CoreFunctions;
5255
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5356
import com.oracle.graal.python.builtins.PythonBuiltins;
57+
import com.oracle.graal.python.builtins.modules.GraalHPyDebugModuleBuiltinsClinicProviders.HPyDebugSetClosedHandlesQueueMaxSizeNodeClinicProviderGen;
58+
import com.oracle.graal.python.builtins.objects.PNone;
5459
import com.oracle.graal.python.builtins.objects.cext.common.LoadCExtException.ApiInitException;
5560
import com.oracle.graal.python.builtins.objects.cext.common.LoadCExtException.ImportException;
5661
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyContext;
@@ -63,7 +68,9 @@
6368
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
6469
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
6570
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
71+
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode;
6672
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
73+
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
6774
import com.oracle.graal.python.runtime.ExecutionContext.IndirectCallContext;
6875
import com.oracle.graal.python.runtime.PythonContext;
6976
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
@@ -118,7 +125,8 @@ int doGeneric(VirtualFrame frame) {
118125
}
119126
}
120127

121-
@Builtin(name = "get_open_handles", minNumOfPositionalArgs = 1)
128+
@Builtin(name = "get_open_handles", minNumOfPositionalArgs = 1, //
129+
doc = "Return a list containing all the open handles whose generation is >= of the given arg")
122130
@GenerateNodeFactory
123131
abstract static class HPyDebugGetOpenHandlesNode extends PythonUnaryBuiltinNode {
124132
@Specialization
@@ -142,6 +150,59 @@ private static Object[] getOpenDebugHandles(GraalHPyDebugContext debugContext, i
142150
}
143151
}
144152

153+
@Builtin(name = "get_closed_handles", //
154+
doc = "Return a list of all the closed handle in the cache")
155+
@GenerateNodeFactory
156+
abstract static class HPyDebugGetClosedHandlesNode extends PythonBuiltinNode {
157+
@Specialization
158+
PList doInt(VirtualFrame frame) {
159+
GraalHPyDebugContext hpyDebugContext = getHPyDebugContext(frame, getLanguage(), this);
160+
return factory().createList(getClosedDebugHandles(hpyDebugContext));
161+
}
162+
163+
@TruffleBoundary
164+
private static Object[] getClosedDebugHandles(GraalHPyDebugContext debugContext) {
165+
Queue<GraalHPyHandle> openHandles = debugContext.getClosedHandles();
166+
int n = openHandles.size();
167+
Object[] result = new Object[n];
168+
PythonObjectFactory factory = PythonObjectFactory.getUncached();
169+
int i = 0;
170+
for (GraalHPyHandle handle : openHandles) {
171+
result[i++] = factory.createDebugHandle(handle);
172+
}
173+
return result;
174+
}
175+
}
176+
177+
@Builtin(name = "get_closed_handles_queue_max_size", //
178+
doc = "Return the maximum size of the closed handles queue")
179+
@GenerateNodeFactory
180+
abstract static class HPyDebugGetClosedHandlesQueueMaxSizeNode extends PythonBuiltinNode {
181+
@Specialization
182+
int doInt(VirtualFrame frame) {
183+
GraalHPyDebugContext hpyDebugContext = getHPyDebugContext(frame, getLanguage(), this);
184+
return hpyDebugContext.getClosedHandlesQueueMaxSize();
185+
}
186+
}
187+
188+
@Builtin(name = "set_closed_handles_queue_max_size", minNumOfPositionalArgs = 1, parameterNames = {"size"}, //
189+
doc = "Set the maximum size of the closed handles queue")
190+
@ArgumentClinic(name = "size", conversion = ClinicConversion.Int)
191+
@GenerateNodeFactory
192+
abstract static class HPyDebugSetClosedHandlesQueueMaxSizeNode extends PythonUnaryClinicBuiltinNode {
193+
@Override
194+
protected ArgumentClinicProvider getArgumentClinic() {
195+
return HPyDebugSetClosedHandlesQueueMaxSizeNodeClinicProviderGen.INSTANCE;
196+
}
197+
198+
@Specialization
199+
PNone doInt(VirtualFrame frame, int size) {
200+
GraalHPyDebugContext hpyDebugContext = getHPyDebugContext(frame, getLanguage(), this);
201+
hpyDebugContext.setClosedHandlesQueueMaxSize(size);
202+
return PNone.NONE;
203+
}
204+
}
205+
145206
@Builtin(name = "DebugHandle", minNumOfPositionalArgs = 1, constructsClass = PythonBuiltinClassType.DebugHandle, takesVarArgs = true, takesVarKeywordArgs = true)
146207
@GenerateNodeFactory
147208
abstract static class DebugHandleNode extends PythonVarargsBuiltinNode {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyDebugContext.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,20 @@
4141
package com.oracle.graal.python.builtins.objects.cext.hpy;
4242

4343
import java.util.ArrayList;
44+
import java.util.LinkedList;
45+
import java.util.Queue;
4446

4547
import com.oracle.graal.python.util.PythonUtils;
4648
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
4749
import com.oracle.truffle.api.profiles.ConditionProfile;
4850

4951
public final class GraalHPyDebugContext extends GraalHPyContext {
52+
private static final int DEFAULT_CLOSED_HANDLES_QUEUE_MAX_SIZE = 1024;
5053

5154
private int currentGeneration;
5255
private int[] generationTable = new int[]{0};
56+
private int closedHandlesQueueMaxSize = DEFAULT_CLOSED_HANDLES_QUEUE_MAX_SIZE;
57+
private final Queue<GraalHPyHandle> closedHandles = new LinkedList<>();
5358

5459
public GraalHPyDebugContext(GraalHPyContext context) {
5560
super(context.getContext(), context.getLLVMLibrary());
@@ -61,6 +66,14 @@ public GraalHPyDebugContext(GraalHPyContext context) {
6166
setWcharSize(context.getWcharSize());
6267
}
6368

69+
public int getClosedHandlesQueueMaxSize() {
70+
return closedHandlesQueueMaxSize;
71+
}
72+
73+
public void setClosedHandlesQueueMaxSize(int closedHandlesQueueMaxSize) {
74+
this.closedHandlesQueueMaxSize = closedHandlesQueueMaxSize;
75+
}
76+
6477
/**
6578
* Since the initialization of the context members cannot use {@link #createHandle(Object)}, we
6679
* track the constants of the debug mode separately here. The reason why we can't use
@@ -91,6 +104,10 @@ public ArrayList<GraalHPyHandle> getOpenHandles(int generation) {
91104
return openHandles;
92105
}
93106

107+
public Queue<GraalHPyHandle> getClosedHandles() {
108+
return closedHandles;
109+
}
110+
94111
public int getCurrentGeneration() {
95112
return currentGeneration;
96113
}
@@ -116,8 +133,14 @@ public GraalHPyHandle createHandle(Object delegate) {
116133
}
117134

118135
@Override
119-
public synchronized void releaseHPyHandleForObject(int handle) {
120-
super.releaseHPyHandleForObject(handle);
121-
generationTable[handle] = -1;
136+
@TruffleBoundary
137+
public synchronized void releaseHPyHandleForObject(int handleId) {
138+
GraalHPyHandle handle = super.getObjectForHPyHandle(handleId);
139+
super.releaseHPyHandleForObject(handleId);
140+
generationTable[handleId] = -1;
141+
if (closedHandles.size() >= closedHandlesQueueMaxSize) {
142+
closedHandles.poll();
143+
}
144+
closedHandles.add(handle);
122145
}
123146
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyDebugHandleBuiltins.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,10 @@
5858
import com.oracle.graal.python.runtime.ExecutionContext.IndirectCallContext;
5959
import com.oracle.graal.python.runtime.PythonContext;
6060
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
61-
import com.oracle.truffle.api.dsl.Cached;
6261
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
6362
import com.oracle.truffle.api.dsl.NodeFactory;
6463
import com.oracle.truffle.api.dsl.Specialization;
6564
import com.oracle.truffle.api.frame.VirtualFrame;
66-
import com.oracle.truffle.api.profiles.ConditionProfile;
6765

6866
@CoreFunctions(extendClasses = PythonBuiltinClassType.DebugHandle)
6967
public final class GraalHPyDebugHandleBuiltins extends PythonBuiltins {
@@ -79,7 +77,7 @@ public abstract static class HPyDebugHandleObjNode extends PythonUnaryBuiltinNod
7977

8078
@Specialization
8179
static Object doGeneric(PDebugHandle self) {
82-
return self.getHandle().getDelegate();
80+
return self.getObj();
8381
}
8482
}
8583

@@ -89,9 +87,8 @@ static Object doGeneric(PDebugHandle self) {
8987
public abstract static class HPyDebugHandleIdNode extends PythonUnaryBuiltinNode {
9088

9189
@Specialization
92-
Object doGeneric(PDebugHandle self,
93-
@Cached ConditionProfile profile) {
94-
return self.getHandle().getId(getContext().getHPyDebugContext(), profile);
90+
static int doGeneric(PDebugHandle self) {
91+
return self.getId();
9592
}
9693
}
9794

@@ -102,8 +99,7 @@ public abstract static class HPyDebugHandleIsClosedNode extends PythonUnaryBuilt
10299

103100
@Specialization
104101
static boolean doGeneric(PDebugHandle self) {
105-
GraalHPyHandle handle = self.getHandle();
106-
return !handle.isPointer(ConditionProfile.getUncached());
102+
return self.isClosed();
107103
}
108104
}
109105

@@ -113,7 +109,7 @@ public abstract static class HPyDebugHandleEqNode extends PythonBinaryBuiltinNod
113109

114110
@Specialization
115111
static Object doDebugHandle(PDebugHandle self, PDebugHandle other) {
116-
return self.getHandle() == other.getHandle();
112+
return self.eq(other);
117113
}
118114

119115
@Specialization(guards = "!isDebugHandle(other)")
@@ -145,10 +141,14 @@ Object doGeneric(VirtualFrame frame, PDebugHandle self) {
145141

146142
@TruffleBoundary
147143
private static Object format(GraalHPyDebugContext hpyDebugContext, PDebugHandle self) {
148-
int id = self.getHandle().getId(hpyDebugContext, ConditionProfile.getUncached());
149-
Object objRepr = LookupAndCallUnaryDynamicNode.getUncached().executeObject(self.getHandle().getDelegate(), SpecialMethodNames.__REPR__);
150-
String reprStr = CastToJavaStringNode.getUncached().execute(objRepr);
151-
return String.format("<DebugHandle 0x%s for %s>", Integer.toHexString(id), reprStr);
144+
int id = self.getId();
145+
if (self.isClosed()) {
146+
return String.format("<DebugHandle 0x%s CLOSED>", Integer.toHexString(id));
147+
} else {
148+
Object objRepr = LookupAndCallUnaryDynamicNode.getUncached().executeObject(self.getObj(), SpecialMethodNames.__REPR__);
149+
String reprStr = CastToJavaStringNode.getUncached().execute(objRepr);
150+
return String.format("<DebugHandle 0x%s for %s>", Integer.toHexString(id), reprStr);
151+
}
152152
}
153153
}
154154

@@ -158,7 +158,7 @@ public abstract static class HPyDebugHandleForceCloseNode extends PythonUnaryBui
158158

159159
@Specialization
160160
PNone doGeneric(PDebugHandle self) {
161-
self.getHandle().close(getContext().getHPyContext(), ConditionProfile.getUncached());
161+
self.close(getContext().getHPyDebugContext());
162162
return PNone.NONE;
163163
}
164164
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyHandle.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public final class GraalHPyHandle implements TruffleObject {
7272
public static final String I = "_i";
7373

7474
private final Object delegate;
75-
private int id = -1;
75+
private int id = Integer.MIN_VALUE;
7676

7777
private GraalHPyHandle() {
7878
this.delegate = PNone.NO_VALUE;
@@ -96,11 +96,21 @@ public int getId(GraalHPyContext context, ConditionProfile hasIdProfile) {
9696
}
9797
return result;
9898
}
99+
100+
int getDebugId() {
101+
if (id == Integer.MIN_VALUE) {
102+
throw CompilerDirectives.shouldNotReachHere();
103+
}
104+
if (id >= 0) {
105+
return id;
106+
}
107+
return -id;
108+
}
99109

100110
@ExportMessage
101111
boolean isPointer(
102112
@Exclusive @Cached ConditionProfile isNativeProfile) {
103-
return isNativeProfile.profile(id != -1);
113+
return isNativeProfile.profile(id >= 0);
104114
}
105115

106116
@ExportMessage
@@ -215,7 +225,7 @@ public void close(GraalHPyContext hpyContext, ConditionProfile isAllocatedProfil
215225
if (isPointer(isAllocatedProfile)) {
216226
try {
217227
hpyContext.releaseHPyHandleForObject((int) asPointer());
218-
id = -1;
228+
id = -id;
219229
} catch (UnsupportedMessageException e) {
220230
throw CompilerDirectives.shouldNotReachHere("trying to release non-native handle that claims to be native");
221231
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/PDebugHandle.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@
4141
package com.oracle.graal.python.builtins.objects.cext.hpy;
4242

4343
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
44+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
4445
import com.oracle.truffle.api.object.Shape;
46+
import com.oracle.truffle.api.profiles.ConditionProfile;
4547

4648
/**
4749
* A thin wrapper around {@link GraalHPyHandle} for exposing handles to the user space.
@@ -54,7 +56,26 @@ public PDebugHandle(Object cls, Shape instanceShape, GraalHPyHandle handle) {
5456
this.handle = handle;
5557
}
5658

57-
public GraalHPyHandle getHandle() {
58-
return handle;
59+
public boolean eq(PDebugHandle other) {
60+
return handle == other.handle;
61+
}
62+
63+
public Object getObj() {
64+
return handle.getDelegate();
65+
}
66+
67+
@TruffleBoundary
68+
public int getId() {
69+
return handle.getDebugId();
70+
}
71+
72+
@TruffleBoundary
73+
public void close(GraalHPyDebugContext debugContext) {
74+
handle.close(debugContext, ConditionProfile.getUncached());
75+
}
76+
77+
@TruffleBoundary
78+
public boolean isClosed() {
79+
return !handle.isPointer(ConditionProfile.getUncached());
5980
}
6081
}

graalpython/lib-graalpython/modules/hpy/test/debug/test_handles.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ def test_closed_handles_queue_max_size(compiler):
231231
finally:
232232
_debug.set_closed_handles_queue_max_size(old_size)
233233

234+
@pytest.mark.skip
234235
def test_reuse_closed_handles(compiler):
235236
from hpy.universal import _debug
236237
mod = compiler.make_module("""

0 commit comments

Comments
 (0)