Skip to content

Commit 741ef10

Browse files
committed
add jni implementations of Long_AsDouble and TypeCheck, introduce immutable handles for context constants
1 parent 930b5cf commit 741ef10

File tree

4 files changed

+183
-36
lines changed

4 files changed

+183
-36
lines changed

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

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,14 @@ static JNIEnv* jniEnv;
7474
UPCALL(FloatFromDouble, SIG_DOUBLE, SIG_HPY) \
7575
UPCALL(FloatAsDouble, SIG_HPY, SIG_DOUBLE) \
7676
UPCALL(LongAsLong, SIG_HPY, SIG_LONG) \
77+
UPCALL(LongAsDouble, SIG_HPY, SIG_DOUBLE) \
7778
UPCALL(LongFromLong, SIG_LONG, SIG_HPY) \
7879
UPCALL(Dup, SIG_HPY, SIG_HPY) \
7980
UPCALL(GetItemi, SIG_HPY SIG_SIZE_T, SIG_HPY) \
8081
UPCALL(SetItemi, SIG_HPY SIG_SIZE_T SIG_HPY, SIG_INT) \
8182
UPCALL(SetItem, SIG_HPY SIG_HPY SIG_HPY, SIG_INT) \
8283
UPCALL(NumberCheck, SIG_HPY, SIG_INT) \
84+
UPCALL(TypeCheck, SIG_HPY SIG_HPY, SIG_INT) \
8385
UPCALL(Length, SIG_HPY, SIG_SIZE_T) \
8486
UPCALL(ListCheck, SIG_HPY, SIG_INT) \
8587
UPCALL(UnicodeFromWideChar, SIG_PTR SIG_SIZE_T, SIG_HPY) \
@@ -127,6 +129,10 @@ static long ctx_LongAsLong_jni(HPyContext *ctx, HPy h) {
127129
return DO_UPCALL_LONG(CONTEXT_INSTANCE(ctx), LongAsLong, HPY_UP(h));
128130
}
129131

132+
static double ctx_LongAsDouble_jni(HPyContext *ctx, HPy h) {
133+
return DO_UPCALL_DOUBLE(CONTEXT_INSTANCE(ctx), LongAsDouble, HPY_UP(h));
134+
}
135+
130136
static HPy ctx_LongFromLong_jni(HPyContext *ctx, long l) {
131137
return DO_UPCALL_HPY(CONTEXT_INSTANCE(ctx), LongFromLong, l);
132138
}
@@ -159,6 +165,10 @@ static int ctx_NumberCheck_jni(HPyContext *ctx, HPy obj) {
159165
return DO_UPCALL_INT(CONTEXT_INSTANCE(ctx), NumberCheck, HPY_UP(obj));
160166
}
161167

168+
static int ctx_TypeCheck_jni(HPyContext *ctx, HPy obj, HPy type) {
169+
return DO_UPCALL_INT(CONTEXT_INSTANCE(ctx), TypeCheck, HPY_UP(obj), HPY_UP(type));
170+
}
171+
162172
static int ctx_ListCheck_jni(HPyContext *ctx, HPy obj) {
163173
return DO_UPCALL_INT(CONTEXT_INSTANCE(ctx), ListCheck, HPY_UP(obj));
164174
}
@@ -191,6 +201,7 @@ static HPy ctx_ListNew_jni(HPyContext *ctx, HPy_ssize_t len) {
191201
#define NAN_BOXING_INT (0x0001000000000000llu)
192202
#define NAN_BOXING_INT_MASK (0x00000000FFFFFFFFllu)
193203
#define NAN_BOXING_MAX_HANDLE (0x000000007FFFFFFFllu)
204+
#define IMMUTABLE_HANDLES (0x0000000000000100llu)
194205

195206
static bool isBoxedDouble(uint64_t value) {
196207
return value >= NAN_BOXING_BASE;
@@ -249,9 +260,11 @@ static HPy (*original_Dup)(HPyContext *ctx, HPy h);
249260
static HPy (*original_FloatFromDouble)(HPyContext *ctx, double v);
250261
static double (*original_FloatAsDouble)(HPyContext *ctx, HPy h);
251262
static long (*original_LongAsLong)(HPyContext *ctx, HPy h);
263+
static double (*original_LongAsDouble)(HPyContext *ctx, HPy h);
252264
static HPy (*original_LongFromLong)(HPyContext *ctx, long l);
253265
static int (*original_ListCheck)(HPyContext *ctx, HPy h);
254266
static int (*original_NumberCheck)(HPyContext *ctx, HPy h);
267+
static int (*original_TypeCheck)(HPyContext *ctx, HPy h, HPy type);
255268
static void (*original_Close)(HPyContext *ctx, HPy h);
256269
static HPy (*original_UnicodeFromWideChar)(HPyContext *ctx, const wchar_t *arr, HPy_ssize_t size);
257270

@@ -289,6 +302,15 @@ static long augment_LongAsLong(HPyContext *ctx, HPy h) {
289302
}
290303
}
291304

305+
static double augment_LongAsDouble(HPyContext *ctx, HPy h) {
306+
uint64_t bits = toBits(h);
307+
if (isBoxedInt(bits)) {
308+
return unboxInt(bits);
309+
} else {
310+
return original_LongAsDouble(ctx, h);
311+
}
312+
}
313+
292314
static HPy augment_LongFromLong(HPyContext *ctx, long l) {
293315
int32_t i = (int32_t) l;
294316
if (l == i) {
@@ -308,6 +330,9 @@ static void augment_Close(HPyContext *ctx, HPy h) {
308330
static HPy augment_Dup(HPyContext *ctx, HPy h) {
309331
uint64_t bits = toBits(h);
310332
if (isBoxedHandle(bits)) {
333+
if (bits < IMMUTABLE_HANDLES) {
334+
return h;
335+
}
311336
return original_Dup(ctx, h);
312337
} else {
313338
return h;
@@ -323,6 +348,26 @@ static int augment_NumberCheck(HPyContext *ctx, HPy obj) {
323348
}
324349
}
325350

351+
static int augment_TypeCheck(HPyContext *ctx, HPy obj, HPy type) {
352+
uint64_t bits = toBits(obj);
353+
if (isBoxedInt(bits)) {
354+
if (toBits(type) == toBits(ctx->h_LongType)) {
355+
return true;
356+
}
357+
if (toBits(type) == toBits(ctx->h_FloatType)) {
358+
return false;
359+
}
360+
} else if (isBoxedDouble(bits)) {
361+
if (toBits(type) == toBits(ctx->h_FloatType)) {
362+
return true;
363+
}
364+
if (toBits(type) == toBits(ctx->h_LongType)) {
365+
return false;
366+
}
367+
}
368+
return original_TypeCheck(ctx, obj, type);
369+
}
370+
326371
static int augment_ListCheck(HPyContext *ctx, HPy obj) {
327372
uint64_t bits = toBits(obj);
328373
if (isBoxedHandle(bits)) {
@@ -390,9 +435,12 @@ void initDirectFastPaths(HPyContext *context) {
390435

391436
original_FloatAsDouble = context->ctx_Float_AsDouble;
392437
context->ctx_Float_AsDouble = augment_FloatAsDouble;
393-
438+
394439
original_LongAsLong = context->ctx_Long_AsLong;
395440
context->ctx_Long_AsLong = augment_LongAsLong;
441+
442+
original_LongAsDouble = context->ctx_Long_AsDouble;
443+
context->ctx_Long_AsDouble = augment_LongAsDouble;
396444

397445
original_LongFromLong = context->ctx_Long_FromLong;
398446
context->ctx_Long_FromLong = augment_LongFromLong;
@@ -409,6 +457,9 @@ void initDirectFastPaths(HPyContext *context) {
409457
original_NumberCheck = context->ctx_Number_Check;
410458
context->ctx_Number_Check = augment_NumberCheck;
411459

460+
original_TypeCheck = context->ctx_TypeCheck;
461+
context->ctx_TypeCheck = augment_TypeCheck;
462+
412463
original_ListCheck = context->ctx_List_Check;
413464
context->ctx_List_Check = augment_ListCheck;
414465

@@ -437,11 +488,13 @@ JNIEXPORT jint JNICALL Java_com_oracle_graal_python_builtins_objects_cext_hpy_Gr
437488
context->ctx_Float_FromDouble = ctx_FloatFromDouble_jni;
438489
context->ctx_Float_AsDouble = ctx_FloatAsDouble_jni;
439490
context->ctx_Long_AsLong = ctx_LongAsLong_jni;
491+
context->ctx_Long_AsDouble = ctx_LongAsDouble_jni;
440492
context->ctx_AsStruct = ctx_AsStruct_jni;
441493
context->ctx_Close = ctx_Close_jni;
442494

443495
context->ctx_Dup = ctx_Dup_jni;
444496
context->ctx_Number_Check = ctx_NumberCheck_jni;
497+
context->ctx_TypeCheck = ctx_TypeCheck_jni;
445498
context->ctx_List_Check = ctx_ListCheck_jni;
446499

447500
context->ctx_Length = ctx_Length_jni;

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

Lines changed: 114 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,14 @@
187187
import com.oracle.graal.python.builtins.objects.ints.PInt;
188188
import com.oracle.graal.python.builtins.objects.list.PList;
189189
import com.oracle.graal.python.builtins.objects.object.PythonObject;
190+
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
190191
import com.oracle.graal.python.builtins.objects.type.PythonClass;
191192
import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
192193
import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsTypeNode;
193194
import com.oracle.graal.python.lib.CanBeDoubleNodeGen;
194195
import com.oracle.graal.python.lib.PyFloatAsDoubleNodeGen;
195196
import com.oracle.graal.python.lib.PyIndexCheckNodeGen;
197+
import com.oracle.graal.python.lib.PyLongAsDoubleNodeGen;
196198
import com.oracle.graal.python.lib.PyObjectSizeNodeGen;
197199
import com.oracle.graal.python.nodes.BuiltinNames;
198200
import com.oracle.graal.python.nodes.ErrorMessages;
@@ -203,6 +205,7 @@
203205
import com.oracle.graal.python.nodes.call.CallTargetInvokeNode;
204206
import com.oracle.graal.python.nodes.call.GenericInvokeNode;
205207
import com.oracle.graal.python.nodes.call.special.CallTernaryMethodNode;
208+
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
206209
import com.oracle.graal.python.nodes.classes.IsSubtypeNodeGen;
207210
import com.oracle.graal.python.nodes.expression.BinaryArithmetic;
208211
import com.oracle.graal.python.nodes.expression.InplaceArithmetic;
@@ -551,10 +554,10 @@ enum HPyContextMember {
551554
CTX_LONG_ASSIZE_T("ctx_Long_AsSize_t"),
552555
CTX_LONG_ASSSIZE_T("ctx_Long_AsSsize_t"),
553556
CTX_LONG_ASVOIDPTR("ctx_Long_AsVoidPtr"),
554-
CTX_LONG_ASDOUBLE("ctx_Long_AsDouble"),
557+
CTX_LONG_ASDOUBLE("ctx_Long_AsDouble", signature(Double, HPy)),
555558
CTX_NEW("ctx_New", signature(HPy, HPy, DataPtrPtr)),
556559
CTX_TYPE("ctx_Type"),
557-
CTX_TYPECHECK("ctx_TypeCheck"),
560+
CTX_TYPECHECK("ctx_TypeCheck", signature(Long, HPy, HPy)),
558561
CTX_IS("ctx_Is"),
559562
CTX_TYPE_GENERIC_NEW("ctx_Type_GenericNew", signature(HPy, HPy)),
560563
CTX_FLOAT_FROMDOUBLE("ctx_Float_FromDouble", signature(HPy, Double)),
@@ -788,7 +791,11 @@ public static GraalHPyNativeSymbol getGetterFunctionName(LLVMType llvmType) {
788791
}
789792
}
790793

794+
private static final int IMMUTABLE_HANDLE_COUNT = 256;
795+
791796
private GraalHPyHandle[] hpyHandleTable = new GraalHPyHandle[]{GraalHPyHandle.NULL_HANDLE};
797+
private int nextHandle = 1;
798+
792799
private GraalHPyHandle[] hpyGlobalsTable = new GraalHPyHandle[]{GraalHPyHandle.NULL_HANDLE};
793800
private final HandleStack freeStack = new HandleStack(16);
794801
Object nativePointer;
@@ -831,6 +838,16 @@ public GraalHPyContext(PythonContext context, Object hpyLibrary) {
831838
super(context, hpyLibrary, GraalHPyConversionNodeSupplier.HANDLE);
832839
this.slowPathFactory = context.factory();
833840
this.hpyContextMembers = createMembers(context, getName());
841+
for (Object member : hpyContextMembers) {
842+
if (member instanceof GraalHPyHandle) {
843+
GraalHPyHandle handle = (GraalHPyHandle) member;
844+
int id = handle.getId(this, ConditionProfile.getUncached());
845+
assert id > 0 && id < IMMUTABLE_HANDLE_COUNT;
846+
847+
}
848+
}
849+
hpyHandleTable = Arrays.copyOf(hpyHandleTable, IMMUTABLE_HANDLE_COUNT * 2);
850+
nextHandle = IMMUTABLE_HANDLE_COUNT;
834851
this.useNativeFastPaths = context.getLanguage().getEngineOption(PythonOptions.HPyEnableJNIFastPaths);
835852
}
836853

@@ -1340,9 +1357,11 @@ public enum Counter {
13401357
UpcallSetItemI,
13411358
UpcallDup,
13421359
UpcallNumberCheck,
1360+
UpcallTypeCheck,
13431361
UpcallLength,
13441362
UpcallListCheck,
13451363
UpcallLongAsLong,
1364+
UpcallLongAsDouble,
13461365
UpcallLongFromLong,
13471366
UpcallFloatAsDouble,
13481367
UpcallFloatFromDouble,
@@ -1418,6 +1437,22 @@ public final long ctxLongAsLong(long handle) {
14181437
}
14191438
}
14201439

1440+
public final double ctxLongAsDouble(long handle) {
1441+
Counter.UpcallLongAsDouble.increment();
1442+
1443+
if (GraalHPyBoxing.isBoxedInt(handle)) {
1444+
return GraalHPyBoxing.unboxInt(handle);
1445+
} else {
1446+
Object object = getObjectForHPyHandle(GraalHPyBoxing.unboxHandle(handle)).getDelegate();
1447+
try {
1448+
return (double) PyLongAsDoubleNodeGen.getUncached().execute(object);
1449+
} catch (PException e) {
1450+
HPyTransformExceptionToNativeNodeGen.getUncached().execute(this, e);
1451+
return -1L;
1452+
}
1453+
}
1454+
}
1455+
14211456
public final long ctxLongFromLong(long l) {
14221457
Counter.UpcallLongFromLong.increment();
14231458

@@ -1684,6 +1719,59 @@ public final int ctxNumberCheck(long handle) {
16841719
}
16851720
}
16861721

1722+
private static PythonBuiltinClassType getBuiltinClass(Object cls) {
1723+
if (cls instanceof PythonBuiltinClassType) {
1724+
return (PythonBuiltinClassType) cls;
1725+
} else if (cls instanceof PythonBuiltinClass) {
1726+
return ((PythonBuiltinClass) cls).getType();
1727+
} else {
1728+
return null;
1729+
}
1730+
}
1731+
1732+
public final int ctxTypeCheck(long handle, long typeHandle) {
1733+
Counter.UpcallTypeCheck.increment();
1734+
Object receiver;
1735+
if (GraalHPyBoxing.isBoxedDouble(handle)) {
1736+
receiver = PythonBuiltinClassType.PFloat;
1737+
} else if (GraalHPyBoxing.isBoxedInt(handle)) {
1738+
receiver = PythonBuiltinClassType.PInt;
1739+
} else {
1740+
receiver = GetClassNode.getUncached().execute(getObjectForHPyHandle(GraalHPyBoxing.unboxHandle(handle)).getDelegate());
1741+
}
1742+
Object type = getObjectForHPyHandle(GraalHPyBoxing.unboxHandle(typeHandle)).getDelegate();
1743+
1744+
if (receiver == type) {
1745+
return 1;
1746+
}
1747+
1748+
PythonBuiltinClassType receiverBuiltin = getBuiltinClass(receiver);
1749+
if (receiverBuiltin != null) {
1750+
PythonBuiltinClassType typeBuiltin = getBuiltinClass(type);
1751+
if (typeBuiltin == null) {
1752+
// builtin type cannot be a subclass of a non-builtin type
1753+
return 0;
1754+
}
1755+
// fast path for builtin types: walk class hierarchy
1756+
while (true) {
1757+
if (receiverBuiltin == typeBuiltin) {
1758+
return 1;
1759+
}
1760+
if (receiverBuiltin == PythonBuiltinClassType.PythonObject) {
1761+
return 0;
1762+
}
1763+
receiverBuiltin = receiverBuiltin.getBase();
1764+
}
1765+
}
1766+
1767+
try {
1768+
return IsSubtypeNode.getUncached().execute(receiver, type) ? 1 : 0;
1769+
} catch (PException e) {
1770+
HPyTransformExceptionToNativeNodeGen.getUncached().execute(this, e);
1771+
return 0;
1772+
}
1773+
}
1774+
16871775
public final long ctxLength(long handle) {
16881776
Counter.UpcallLength.increment();
16891777
assert GraalHPyBoxing.isBoxedHandle(handle);
@@ -2244,36 +2332,34 @@ private synchronized int allocateHPyGlobal() {
22442332

22452333
private long nativeSpacePointers;
22462334

2247-
@TruffleBoundary(allowInlining = true)
2248-
private int allocateHandle() {
2249-
int freeItem = freeStack.pop();
2250-
if (freeItem != -1) {
2251-
assert 0 <= freeItem && freeItem < hpyHandleTable.length;
2252-
assert hpyHandleTable[freeItem] == null;
2253-
return freeItem;
2254-
}
2255-
for (int i = 1; i < hpyHandleTable.length; i++) {
2256-
if (hpyHandleTable[i] == null) {
2257-
return i;
2258-
}
2335+
private int resizeHandleTable() {
2336+
CompilerAsserts.neverPartOfCompilation();
2337+
assert nextHandle == hpyHandleTable.length;
2338+
int newSize = Math.max(16, hpyHandleTable.length * 2);
2339+
LOGGER.fine(() -> "resizing HPy handle table to " + newSize);
2340+
hpyHandleTable = Arrays.copyOf(hpyHandleTable, newSize);
2341+
if (useNativeFastPaths && isPointer()) {
2342+
reallocateNativeSpacePointersMirror();
22592343
}
2260-
return -1;
2344+
return nextHandle++;
22612345
}
22622346

2263-
public final synchronized int getHPyHandleForObject(GraalHPyHandle object) {
2347+
public final int getHPyHandleForObject(GraalHPyHandle object) {
22642348
// find free association
2265-
int handle = allocateHandle();
2349+
2350+
int handle = freeStack.pop();
22662351
if (handle == -1) {
2267-
// resize
2268-
int newSize = Math.max(16, hpyHandleTable.length * 2);
2269-
LOGGER.fine(() -> "resizing HPy handle table to " + newSize);
2270-
hpyHandleTable = Arrays.copyOf(hpyHandleTable, newSize);
2271-
if (useNativeFastPaths && isPointer()) {
2272-
reallocateNativeSpacePointersMirror();
2352+
if (nextHandle < hpyHandleTable.length) {
2353+
handle = nextHandle++;
2354+
} else {
2355+
CompilerDirectives.transferToInterpreter();
2356+
handle = resizeHandleTable();
22732357
}
2274-
handle = allocateHandle();
22752358
}
2276-
assert handle > 0;
2359+
2360+
assert 0 <= handle && handle < hpyHandleTable.length;
2361+
assert hpyHandleTable[handle] == null;
2362+
22772363
hpyHandleTable[handle] = object;
22782364
if (useNativeFastPaths && isPointer()) {
22792365
mirrorNativeSpacePointerToNative(object, handle);
@@ -2362,6 +2448,9 @@ synchronized boolean releaseHPyHandleForObject(int handle) {
23622448
if (LOGGER.isLoggable(Level.FINER)) {
23632449
LOGGER.finer(() -> "releasing HPy handle " + handle);
23642450
}
2451+
if (handle < IMMUTABLE_HANDLE_COUNT) {
2452+
return false;
2453+
}
23652454
hpyHandleTable[handle] = null;
23662455
freeStack.push(handle);
23672456
return true;

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,16 @@ public synchronized boolean releaseHPyHandleForObject(int handleId) {
166166
return false;
167167
} else {
168168
GraalHPyHandle handle = super.getObjectForHPyHandle(handleId);
169-
super.releaseHPyHandleForObject(handleId);
170-
debugHandleInfo[handleId] = -1;
171-
if (!closedHandles.isEmpty() && closedHandles.size() >= closedHandlesQueueMaxSize) {
172-
closedHandles.removeFirst();
169+
if (super.releaseHPyHandleForObject(handleId)) {
170+
debugHandleInfo[handleId] = -1;
171+
if (!closedHandles.isEmpty() && closedHandles.size() >= closedHandlesQueueMaxSize) {
172+
closedHandles.removeFirst();
173+
}
174+
closedHandles.add(handle);
175+
return true;
176+
} else {
177+
return false;
173178
}
174-
closedHandles.add(handle);
175-
return true;
176179
}
177180
}
178181

0 commit comments

Comments
 (0)