Skip to content

Commit 0ededd5

Browse files
committed
Support HPy trace mode
1 parent cf9d2ca commit 0ededd5

File tree

19 files changed

+481
-229
lines changed

19 files changed

+481
-229
lines changed

graalpython/com.oracle.graal.python.hpy.test/src/hpytest/trace/test_trace.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
import pytest
2525
from hpy.trace import get_call_counts, get_durations, set_trace_functions
2626

27-
pytestmark = pytest.mark.skip("not yet implemented")
28-
2927
@pytest.fixture
3028
def hpy_abi():
3129
return "trace"

graalpython/com.oracle.graal.python.jni/src/hpy_jni.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "hpy_jni.h"
4343
#include "hpy_log.h"
4444
#include "hpy_native_cache.h"
45+
#include "hpy_trace.h"
4546

4647
#include <wchar.h>
4748
#include <assert.h>
@@ -454,6 +455,32 @@ JNIEXPORT jlong JNICALL JNI_HELPER(initJNIDebugModule)(JNIEnv *env, jclass clazz
454455
return PTR_UP(HPyInit__debug());
455456
}
456457

458+
JNIEXPORT jlong JNICALL JNI_HELPER(initJNITraceContext)(JNIEnv *env, jclass clazz, jlong uctxPointer) {
459+
LOG("%s", "hpy_jni.c:initJNITraceContext\n");
460+
HPyContext *uctx = (HPyContext *) uctxPointer;
461+
462+
HPyContext *tctx = (HPyContext *) malloc(sizeof(HPyContext));
463+
tctx->name = "HPy Trace Mode ABI";
464+
tctx->_private = NULL;
465+
tctx->abi_version = HPY_ABI_VERSION;
466+
467+
hpy_trace_ctx_init(tctx, uctx);
468+
return PTR_UP(tctx);
469+
}
470+
471+
JNIEXPORT jint JNICALL JNI_HELPER(finalizeJNITraceContext)(JNIEnv *env, jclass clazz, jlong tctxPointer) {
472+
LOG("%s", "hpy_jni.c:finalizeJNITraceContext\n");
473+
HPyContext *tctx = (HPyContext *) tctxPointer;
474+
hpy_trace_ctx_free(tctx);
475+
free(tctx);
476+
return 0;
477+
}
478+
479+
JNIEXPORT jlong JNICALL JNI_HELPER(initJNITraceModule)(JNIEnv *env, jclass clazz, jlong uctxPointer) {
480+
LOG("%s", "hpy_jni.c:initJNITraceModule\n");
481+
return PTR_UP(HPyInit__trace());
482+
}
483+
457484
JNIEXPORT jint JNICALL JNI_HELPER(strcmp)(JNIEnv *env, jclass clazz, jlong s1, jlong s2) {
458485
return (jint) strcmp((const char *)s1, (const char *)s2);
459486
}

graalpython/com.oracle.graal.python.jni/src/trace/_tracemod.c

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,49 @@ static int check_and_set_func(HPyContext *uctx, HPy arg, HPy *out)
170170
return 0;
171171
}
172172

173+
static const char *set_trace_funcs_kwlist[] = { "on_enter", "on_exit", NULL };
174+
175+
static int
176+
get_optional_arg(HPyContext *ctx, const HPy *args, size_t nargs, HPy kwnames,
177+
HPy_ssize_t i, const char *kwname, HPy *out)
178+
{
179+
HPy_ssize_t nkw, j;
180+
HPy h_kwname, h_item;
181+
// if given as positional arg
182+
if (i < nargs) {
183+
*out = args[i];
184+
return 0;
185+
}
186+
187+
if (HPy_IsNull(kwnames)) {
188+
return 0;
189+
}
190+
191+
nkw = HPy_Length(ctx, kwnames);
192+
if (nkw < 0) {
193+
return -1;
194+
}
195+
h_kwname = HPyUnicode_FromString(ctx, kwname);
196+
if (HPy_IsNull(h_kwname)) {
197+
return -1;
198+
}
199+
for (j=0; j < nkw; j++) {
200+
h_item = HPy_GetItem_i(ctx, kwnames, j);
201+
if (HPy_IsNull(h_item)) {
202+
HPy_Close(ctx, h_kwname);
203+
return -1;
204+
}
205+
if (HPy_RichCompareBool(ctx, h_kwname, h_item, HPy_EQ)) {
206+
HPy_Close(ctx, h_kwname);
207+
HPy_Close(ctx, h_item);
208+
*out = args[nargs + j];
209+
return 0;
210+
}
211+
HPy_Close(ctx, h_item);
212+
}
213+
return 0;
214+
}
215+
173216
HPyDef_METH(set_trace_functions, "set_trace_functions", HPyFunc_KEYWORDS,
174217
.doc="Set the functions to call if an HPy API is entered/exited.")
175218
static HPy set_trace_functions_impl(HPyContext *uctx, HPy self, const HPy *args,
@@ -179,17 +222,18 @@ static HPy set_trace_functions_impl(HPyContext *uctx, HPy self, const HPy *args,
179222
HPy h_on_exit = HPy_NULL;
180223
HPyContext *dctx = hpy_trace_get_ctx(uctx);
181224
HPyTraceInfo *info = get_info(dctx);
182-
HPyTracker ht;
183225

184-
static const char *kwlist[] = { "on_enter", "on_exit", NULL };
185-
if (!HPyArg_ParseKeywords(uctx, &ht, args, nargs, kwnames, "|OO", kwlist,
186-
&h_on_enter, &h_on_exit)) {
226+
// GraalPy change: avoid usage of HPyArg_ParseKeywords
227+
if (get_optional_arg(uctx, args, nargs, kwnames, 0,
228+
set_trace_funcs_kwlist[0], &h_on_enter) < 0
229+
|| get_optional_arg(uctx, args, nargs, kwnames, 1,
230+
set_trace_funcs_kwlist[1], &h_on_exit) < 0)
231+
{
187232
return HPy_NULL;
188233
}
189234

190235
int r = check_and_set_func(uctx, h_on_enter, &info->on_enter_func) < 0 ||
191236
check_and_set_func(uctx, h_on_exit, &info->on_exit_func) < 0;
192-
HPyTracker_Close(uctx, ht);
193237
if (r) {
194238
return HPy_NULL;
195239
}

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
*/
4141
package com.oracle.graal.python.builtins.modules;
4242

43+
import static com.oracle.graal.python.nodes.StringLiterals.J_DEBUG;
4344
import static com.oracle.graal.python.util.PythonUtils.tsLiteral;
4445

4546
import java.io.IOException;
@@ -59,7 +60,6 @@
5960
import com.oracle.graal.python.builtins.objects.module.PythonModule;
6061
import com.oracle.graal.python.nodes.ErrorMessages;
6162
import com.oracle.graal.python.nodes.PRaiseNode;
62-
import com.oracle.graal.python.nodes.argument.ReadArgumentNode;
6363
import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode;
6464
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
6565
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
@@ -121,11 +121,9 @@ public void postInitialize(Python3Core core) {
121121

122122
@Builtin(name = J_NOT_AVAILABLE, takesVarArgs = true, takesVarKeywordArgs = true)
123123
static final class NotAvailable extends PythonBuiltinNode {
124-
private static final ReadArgumentNode[] EMPTY_ARGS = new ReadArgumentNode[0];
125-
126124
@Override
127125
public Object execute(VirtualFrame frame) {
128-
throw PRaiseNode.raiseUncached(this, PythonBuiltinClassType.RuntimeError, ErrorMessages.HPY_DEBUG_MODE_NOT_AVAILABLE);
126+
throw PRaiseNode.raiseUncached(this, PythonBuiltinClassType.RuntimeError, ErrorMessages.HPY_S_MODE_NOT_AVAILABLE, J_DEBUG);
129127
}
130128
}
131129

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,14 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
8080

8181
@Override
8282
public void postInitialize(Python3Core core) {
83-
PythonModule hpyDebugModule = core.lookupBuiltinModule(PythonUtils.tsLiteral(J_HPY_TRACE));
83+
PythonModule hpyTraceModule = core.lookupBuiltinModule(PythonUtils.tsLiteral(J_HPY_TRACE));
8484
TruffleString[] keys = new TruffleString[]{T_GET_DURATIONS, T_GET_CALL_COUNTS, T_SET_TRACE_FUNCTIONS, T_GET_FREQUENCY};
8585
try {
8686
GraalHPyContext hpyContext = GraalHPyContext.ensureHPyWasLoaded(null, core.getContext(), null, null);
87-
PythonModule nativeDebugModule = hpyContext.getHPyDebugModule();
88-
PDict nativeDebugDict = GetDictIfExistsNode.getUncached().execute(nativeDebugModule);
87+
PythonModule nativeTraceModule = hpyContext.getHPyTraceModule();
88+
PDict nativeTraceDict = GetDictIfExistsNode.getUncached().execute(nativeTraceModule);
8989
for (TruffleString tkey : keys) {
90-
hpyDebugModule.setAttribute(tkey, nativeDebugDict.getItem(tkey));
90+
hpyTraceModule.setAttribute(tkey, nativeTraceDict.getItem(tkey));
9191
}
9292
} catch (IOException | ApiInitException | ImportException e) {
9393
/*
@@ -96,7 +96,7 @@ public void postInitialize(Python3Core core) {
9696
*/
9797
PBuiltinFunction notAvailableObj = GraalHPyDebugModuleBuiltins.createFunction(core);
9898
for (TruffleString tkey : keys) {
99-
hpyDebugModule.setAttribute(tkey, notAvailableObj);
99+
hpyTraceModule.setAttribute(tkey, notAvailableObj);
100100
}
101101
}
102102
}

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

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,10 @@ public static Object loadHPyModule(Node location, PythonContext context, Truffle
213213
// Sanity check of the tag in the shared object filename
214214
validateABITag(location, basename, path.toJavaStringUncached(), abiVersion);
215215

216-
boolean debug = mode == HPyMode.MODE_DEBUG;
217-
boolean saved = hpyUniversalContext.debugMode;
218-
hpyUniversalContext.debugMode = debug;
216+
HPyMode saved = hpyUniversalContext.currentMode;
217+
hpyUniversalContext.currentMode = mode;
219218
try {
220-
Object hpyModuleDefPtr = backend.initHPyModule(llvmLibrary, hpyInitFuncName, name, path, debug);
219+
Object hpyModuleDefPtr = backend.initHPyModule(llvmLibrary, hpyInitFuncName, name, path, mode);
221220
// HPy only supports multi-phase extension module initialization.
222221
assert !(hpyModuleDefPtr instanceof PythonModule);
223222
if (InteropLibrary.getUncached().isNull(hpyModuleDefPtr)) {
@@ -232,7 +231,7 @@ public static Object loadHPyModule(Node location, PythonContext context, Truffle
232231
} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
233232
throw new ImportException(CExtContext.wrapJavaException(e, location), name, path, ErrorMessages.CANNOT_INITIALIZE_WITH, path, basename, "");
234233
} finally {
235-
hpyUniversalContext.debugMode = saved;
234+
hpyUniversalContext.currentMode = saved;
236235
}
237236
}
238237

@@ -377,12 +376,12 @@ public enum LLVMType {
377376
final boolean useNativeFastPaths;
378377

379378
/**
380-
* This is set to {@code true} if an HPy extension is initialized (i.e. {@code HPyInit_*} is
381-
* called) in debug mode. The value is then used to create the right closures for down calls
382-
* during module ({@code HPyModule_Create}) and type creation ({@code HPyType_FromSpec}). We
383-
* need this because the debug context is just a wrapper around the universal context, so the
384-
* module and type creation will look as normal. For reference on how other implementations do
385-
* it:
379+
* This is set to the appropriate mode if an HPy extension is initialized (i.e.
380+
* {@code HPyInit_*} is called) in, e.g., debug mode. The value is then used to create the right
381+
* closures for down calls during module ({@code HPyModule_Create}) and type creation
382+
* ({@code HPyType_FromSpec}). We need this because the debug context is just a wrapper around
383+
* the universal context, so the module and type creation will look as normal. For reference on
384+
* how other implementations do it:
386385
* <p>
387386
* CPython stores the HPy context into global C variable {@code _ctx_for_trampolines} defined by
388387
* {@code HPy_MODINIT}. This variable belongs to the HPy extension and the context is loaded
@@ -395,7 +394,7 @@ public enum LLVMType {
395394
* trampolines pick the appropriate context.
396395
* </p>
397396
*/
398-
private boolean debugMode;
397+
private HPyMode currentMode = HPyMode.MODE_UNIVERSAL;
399398

400399
/**
401400
* Few well known Python objects that are also HPyContext constants are guaranteed to always get
@@ -730,8 +729,12 @@ public PythonModule getHPyDebugModule() throws ImportException {
730729
return backend.getHPyDebugModule();
731730
}
732731

733-
boolean isDebugMode() {
734-
return debugMode;
732+
public PythonModule getHPyTraceModule() throws ImportException {
733+
return backend.getHPyTraceModule();
734+
}
735+
736+
HPyMode getCurrentMode() {
737+
return currentMode;
735738
}
736739

737740
public GraalHPyNativeContext getBackend() {

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,11 @@ protected final PythonContext getContext() {
106106
* @param initFuncName The HPy extension's init function name (e.g. {@code HPyInit_poc}).
107107
* @param name The HPy extension's name as requested by the user.
108108
* @param path The HPy extension's shared library path.
109-
* @param debug Flags indicating if the HPy extension should be initialized in debug mode.
109+
* @param mode An enum indicating which mode should be used to initialize the HPy extension.
110110
* @return The bare (unconverted) result of the HPy extension's init function. This will be a
111111
* handle that was created with the given {@code hpyContext}.
112112
*/
113-
protected abstract Object initHPyModule(Object extLib, String initFuncName, TruffleString name, TruffleString path, boolean debug)
113+
protected abstract Object initHPyModule(Object extLib, String initFuncName, TruffleString name, TruffleString path, HPyMode mode)
114114
throws UnsupportedMessageException, ArityException, UnsupportedTypeException, ImportException, ApiInitException;
115115

116116
protected abstract HPyUpcall[] getUpcalls();
@@ -119,8 +119,12 @@ protected abstract Object initHPyModule(Object extLib, String initFuncName, Truf
119119

120120
public abstract void initHPyDebugContext() throws ApiInitException;
121121

122+
public abstract void initHPyTraceContext() throws ApiInitException;
123+
122124
public abstract PythonModule getHPyDebugModule() throws ImportException;
123125

126+
public abstract PythonModule getHPyTraceModule() throws ImportException;
127+
124128
protected abstract void setNativeCache(long cachePtr);
125129

126130
protected abstract long getWcharSize();

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNativeSymbol.GRAAL_HPY_TYPE_SPEC_GET_BUILTIN_SHAPE;
6565
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNativeSymbol.GRAAL_HPY_TYPE_SPEC_PARAM_GET_KIND;
6666
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNativeSymbol.GRAAL_HPY_TYPE_SPEC_PARAM_GET_OBJECT;
67+
import static com.oracle.graal.python.builtins.objects.cext.hpy.HPyMode.MODE_UNIVERSAL;
6768
import static com.oracle.graal.python.builtins.objects.cext.structs.CFields.PyTypeObject__tp_basicsize;
6869
import static com.oracle.graal.python.nodes.StringLiterals.T_DOT;
6970
import static com.oracle.graal.python.nodes.StringLiterals.T_EXEC;
@@ -754,7 +755,7 @@ static PBuiltinFunction doIt(GraalHPyContext context, Object enclosingType, Obje
754755
}
755756

756757
methodFunctionPointer = interopLibrary.readMember(methodDef, "impl");
757-
if (context.isDebugMode() || !resultLib.isExecutable(methodFunctionPointer)) {
758+
if (context.getCurrentMode() != MODE_UNIVERSAL || !resultLib.isExecutable(methodFunctionPointer)) {
758759
methodFunctionPointer = attachFunctionTypeNode.execute(context, methodFunctionPointer, signature.getLLVMFunctionType());
759760
}
760761
} catch (UnknownIdentifierException e) {
@@ -1141,14 +1142,14 @@ static GetSetDescriptor doIt(GraalHPyContext context, Object type, Object member
11411142
// signature: self, closure
11421143
Object getterFunctionPtr = memberDefLib.readMember(memberDef, "getter_impl");
11431144
boolean hasGetter = !valueLib.isNull(getterFunctionPtr);
1144-
if (hasGetter && (context.isDebugMode() || !valueLib.isExecutable(getterFunctionPtr))) {
1145+
if (hasGetter && (context.getCurrentMode() != MODE_UNIVERSAL || !valueLib.isExecutable(getterFunctionPtr))) {
11451146
getterFunctionPtr = attachFunctionTypeNode.execute(context, getterFunctionPtr, LLVMType.HPyFunc_getter);
11461147
}
11471148

11481149
// signature: self, value, closure
11491150
Object setterFunctionPtr = memberDefLib.readMember(memberDef, "setter_impl");
11501151
boolean hasSetter = !valueLib.isNull(setterFunctionPtr);
1151-
if (hasSetter && (context.isDebugMode() || !valueLib.isExecutable(setterFunctionPtr))) {
1152+
if (hasSetter && (context.getCurrentMode() != MODE_UNIVERSAL || !valueLib.isExecutable(setterFunctionPtr))) {
11521153
setterFunctionPtr = attachFunctionTypeNode.execute(context, setterFunctionPtr, LLVMType.HPyFunc_setter);
11531154
}
11541155

@@ -1226,7 +1227,7 @@ static HPySlotData doIt(Node inliningTarget, GraalHPyContext context, Object slo
12261227
Object methodFunctionPointer;
12271228
try {
12281229
methodFunctionPointer = interopLibrary.readMember(slotDef, "impl");
1229-
if (context.isDebugMode() || !resultLib.isExecutable(methodFunctionPointer)) {
1230+
if (context.getCurrentMode() != MODE_UNIVERSAL || !resultLib.isExecutable(methodFunctionPointer)) {
12301231
methodFunctionPointer = attachFunctionTypeNode.execute(context, methodFunctionPointer, slot.getSignatures()[0].getLLVMFunctionType());
12311232
}
12321233
} catch (UnknownIdentifierException e) {
@@ -2976,7 +2977,7 @@ static GraalHPyJNIFunctionPointer doGeneric(GraalHPyContext hpyContext, Object p
29762977
interopLibrary.toNative(pointerObject);
29772978
}
29782979
try {
2979-
return new GraalHPyJNIFunctionPointer(interopLibrary.asPointer(pointerObject), llvmFunctionType, hpyContext.isDebugMode());
2980+
return new GraalHPyJNIFunctionPointer(interopLibrary.asPointer(pointerObject), llvmFunctionType, hpyContext.getCurrentMode());
29802981
} catch (UnsupportedMessageException e) {
29812982
throw CompilerDirectives.shouldNotReachHere();
29822983
}
@@ -3239,7 +3240,7 @@ static Object doIt(GraalHPyContext context, Object def,
32393240
if (resultLib.isNull(methodFunctionPointer)) {
32403241
return null;
32413242
}
3242-
if (context.isDebugMode() || !resultLib.isExecutable(methodFunctionPointer)) {
3243+
if (context.getCurrentMode() != MODE_UNIVERSAL || !resultLib.isExecutable(methodFunctionPointer)) {
32433244
HPySlotWrapper slotWrapper = HPY_TP_CALL.getSignatures()[0];
32443245
methodFunctionPointer = attachFunctionTypeNode.execute(context, methodFunctionPointer, slotWrapper.getLLVMFunctionType());
32453246
}

0 commit comments

Comments
 (0)