Skip to content

Commit a0416fe

Browse files
committed
Implement JNI upcall for HPy_SetItem(_i)
1 parent eafb5be commit a0416fe

File tree

4 files changed

+161
-9
lines changed

4 files changed

+161
-9
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ static JNIEnv* jniEnv;
7575
UPCALL(LongFromLong, SIG_LONG, SIG_HPY) \
7676
UPCALL(Dup, SIG_HPY, SIG_HPY) \
7777
UPCALL(GetItemi, SIG_HPY SIG_SIZE_T, SIG_HPY) \
78+
UPCALL(SetItemi, SIG_HPY SIG_SIZE_T SIG_HPY, SIG_INT) \
79+
UPCALL(SetItem, SIG_HPY SIG_HPY SIG_HPY, SIG_INT) \
7880
UPCALL(NumberCheck, SIG_HPY, SIG_INT) \
7981
UPCALL(Length, SIG_HPY, SIG_SIZE_T) \
8082
UPCALL(ListCheck, SIG_HPY, SIG_INT) \
@@ -130,6 +132,14 @@ static HPy ctx_GetItemi_jni(HPyContext ctx, HPy obj, HPy_ssize_t idx) {
130132
return DO_UPCALL_HPY(CONTEXT_INSTANCE(ctx), GetItemi, HPY_UP(obj), (SIZE_T_UP) idx);
131133
}
132134

135+
static int ctx_SetItemi_jni(HPyContext ctx, HPy obj, HPy_ssize_t idx, HPy value) {
136+
return DO_UPCALL_INT(CONTEXT_INSTANCE(ctx), SetItemi, HPY_UP(obj), (SIZE_T_UP) idx, HPY_UP(value));
137+
}
138+
139+
static int ctx_SetItem_jni(HPyContext ctx, HPy obj, HPy key, HPy value) {
140+
return DO_UPCALL_INT(CONTEXT_INSTANCE(ctx), SetItem, HPY_UP(obj), HPY_UP(key), HPY_UP(value));
141+
}
142+
133143
static void ctx_Close_jni(HPyContext ctx, HPy h) {
134144
DO_UPCALL_VOID(CONTEXT_INSTANCE(ctx), Close, HPY_UP(h));
135145
}
@@ -368,6 +378,8 @@ JNIEXPORT jint JNICALL Java_com_oracle_graal_python_builtins_objects_cext_hpy_Gr
368378
context->ctx_Type_GenericNew = ctx_TypeGenericNew_jni;
369379

370380
context->ctx_GetItem_i = ctx_GetItemi_jni;
381+
context->ctx_SetItem_i = ctx_SetItemi_jni;
382+
context->ctx_SetItem = ctx_SetItem_jni;
371383

372384
context->ctx_Tracker_New = ctx_Tracker_New;
373385
context->ctx_Tracker_Add = ctx_Tracker_Add;

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

Lines changed: 145 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -144,16 +144,22 @@
144144
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyContextFunctions.ReturnType;
145145
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodes.HPyAttachFunctionTypeNode;
146146
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodes.PCallHPyFunction;
147+
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodesFactory.HPyAsPythonObjectNodeGen;
147148
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodesFactory.HPyGetNativeSpacePointerNodeGen;
148149
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodesFactory.HPyRaiseNodeGen;
149150
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodesFactory.HPyTransformExceptionToNativeNodeGen;
150151
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodesFactory.PCallHPyFunctionNodeGen;
151152
import com.oracle.graal.python.builtins.objects.cext.hpy.HPyExternalFunctionNodes.HPyCheckFunctionResultNode;
153+
import com.oracle.graal.python.builtins.objects.common.EmptyStorage;
154+
import com.oracle.graal.python.builtins.objects.common.HashMapStorage;
155+
import com.oracle.graal.python.builtins.objects.common.HashingStorage;
156+
import com.oracle.graal.python.builtins.objects.common.HashingStorageLibrary;
152157
import com.oracle.graal.python.builtins.objects.dict.PDict;
153158
import com.oracle.graal.python.builtins.objects.ellipsis.PEllipsis;
154159
import com.oracle.graal.python.builtins.objects.frame.PFrame;
155160
import com.oracle.graal.python.builtins.objects.function.PArguments;
156161
import com.oracle.graal.python.builtins.objects.function.Signature;
162+
import com.oracle.graal.python.builtins.objects.list.PList;
157163
import com.oracle.graal.python.builtins.objects.object.PythonObject;
158164
import com.oracle.graal.python.builtins.objects.type.PythonClass;
159165
import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
@@ -165,10 +171,13 @@
165171
import com.oracle.graal.python.lib.PyObjectSizeNodeGen;
166172
import com.oracle.graal.python.nodes.BuiltinNames;
167173
import com.oracle.graal.python.nodes.ErrorMessages;
174+
import com.oracle.graal.python.nodes.PGuards;
175+
import com.oracle.graal.python.nodes.PRaiseNode;
168176
import com.oracle.graal.python.nodes.PRootNode;
169177
import com.oracle.graal.python.nodes.attributes.LookupCallableSlotInMRONode;
170178
import com.oracle.graal.python.nodes.call.CallTargetInvokeNode;
171179
import com.oracle.graal.python.nodes.call.GenericInvokeNode;
180+
import com.oracle.graal.python.nodes.call.special.CallTernaryMethodNode;
172181
import com.oracle.graal.python.nodes.classes.IsSubtypeNodeGen;
173182
import com.oracle.graal.python.nodes.expression.BinaryArithmetic;
174183
import com.oracle.graal.python.nodes.expression.InplaceArithmetic;
@@ -185,6 +194,8 @@
185194
import com.oracle.graal.python.runtime.sequence.PSequence;
186195
import com.oracle.graal.python.runtime.sequence.storage.DoubleSequenceStorage;
187196
import com.oracle.graal.python.runtime.sequence.storage.IntSequenceStorage;
197+
import com.oracle.graal.python.runtime.sequence.storage.LongSequenceStorage;
198+
import com.oracle.graal.python.runtime.sequence.storage.ObjectSequenceStorage;
188199
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
189200
import com.oracle.graal.python.util.PythonUtils;
190201
import com.oracle.truffle.api.CallTarget;
@@ -1212,6 +1223,8 @@ public enum Counter {
12121223
UpcallClose,
12131224
UpcallTrackerNew,
12141225
UpcallGetItemI,
1226+
UpcallSetItem,
1227+
UpcallSetItemI,
12151228
UpcallDup,
12161229
UpcallNumberCheck,
12171230
UpcallLength,
@@ -1384,29 +1397,152 @@ public final long ctxDup(long handle) {
13841397
}
13851398
}
13861399

1387-
public final long ctxGetItemi(long handle, long idx) {
1400+
public final long ctxGetItemi(long handle, long lidx) {
13881401
Counter.UpcallGetItemI.increment();
1389-
assert GraalHPyBoxing.isBoxedHandle(handle);
13901402
try {
1403+
// If handle 'hSequence' is a boxed int or double, the object is not subscriptable.
1404+
if (!GraalHPyBoxing.isBoxedHandle(handle)) {
1405+
throw PRaiseNode.raiseUncached(null, PythonBuiltinClassType.TypeError, ErrorMessages.OBJ_NOT_SUBSCRIPTABLE, 0);
1406+
}
13911407
Object receiver = getObjectForHPyHandle(GraalHPyBoxing.unboxHandle(handle)).getDelegate();
13921408
Object clazz = GetClassNode.getUncached().execute(receiver);
13931409
if (clazz == PythonBuiltinClassType.PList || clazz == PythonBuiltinClassType.PTuple) {
1410+
int idx = 0;
1411+
if (!com.oracle.graal.python.builtins.objects.ints.PInt.isIntRange(lidx)) {
1412+
throw PRaiseNode.raiseUncached(null, PythonBuiltinClassType.IndexError, ErrorMessages.CANNOT_FIT_P_INTO_INDEXSIZED_INT, lidx);
1413+
}
13941414
PSequence sequence = (PSequence) receiver;
13951415
SequenceStorage storage = sequence.getSequenceStorage();
13961416
if (storage instanceof IntSequenceStorage) {
1397-
return GraalHPyBoxing.boxInt(((IntSequenceStorage) storage).getIntItemNormalized((int) idx));
1417+
return GraalHPyBoxing.boxInt(((IntSequenceStorage) storage).getIntItemNormalized(idx));
13981418
} else if (storage instanceof DoubleSequenceStorage) {
1399-
return GraalHPyBoxing.boxDouble(((DoubleSequenceStorage) storage).getDoubleItemNormalized((int) idx));
1419+
return GraalHPyBoxing.boxDouble(((DoubleSequenceStorage) storage).getDoubleItemNormalized(idx));
1420+
} else if (storage instanceof LongSequenceStorage) {
1421+
long lresult = ((LongSequenceStorage) storage).getLongItemNormalized(idx);
1422+
if (com.oracle.graal.python.builtins.objects.ints.PInt.isIntRange(lresult)) {
1423+
return GraalHPyBoxing.boxInt((int) lresult);
1424+
}
1425+
return GraalHPyBoxing.boxHandle(createHandle(lresult).getId(this, ConditionProfile.getUncached()));
1426+
} else if (storage instanceof ObjectSequenceStorage) {
1427+
Object result = ((ObjectSequenceStorage) storage).getItemNormalized(idx);
1428+
return GraalHPyBoxing.boxHandle(createHandle(result).getId(this, ConditionProfile.getUncached()));
14001429
}
14011430
// TODO: other storages...
14021431
}
1403-
Object result = PInteropSubscriptNode.getUncached().execute(receiver, idx);
1432+
Object result = PInteropSubscriptNode.getUncached().execute(receiver, lidx);
14041433
return GraalHPyBoxing.boxHandle(createHandle(result).getId(this, ConditionProfile.getUncached()));
1405-
} catch (Throwable t) {
1406-
t.printStackTrace();
1407-
System.exit(-1);
1408-
throw CompilerDirectives.shouldNotReachHere();
1434+
} catch (PException e) {
1435+
HPyTransformExceptionToNativeNodeGen.getUncached().execute(this, e);
1436+
// NULL handle
1437+
return 0;
1438+
}
1439+
}
1440+
1441+
/**
1442+
* HPy signature: {@code HPy_SetItem(HPyContext ctx, HPy obj, HPy key, HPy value)}
1443+
*
1444+
* @param hSequence
1445+
* @param hKey
1446+
* @param hValue
1447+
* @return {@code 0} on success; {@code -1} on error
1448+
*/
1449+
public final int ctxSetItem(long hSequence, long hKey, long hValue) {
1450+
Counter.UpcallSetItem.increment();
1451+
try {
1452+
// If handle 'hSequence' is a boxed int or double, the object is not a sequence.
1453+
if (!GraalHPyBoxing.isBoxedHandle(hSequence)) {
1454+
throw PRaiseNode.raiseUncached(null, PythonBuiltinClassType.TypeError, ErrorMessages.OBJ_DOES_NOT_SUPPORT_ITEM_ASSIGMENT, 0);
1455+
}
1456+
Object receiver = getObjectForHPyHandle(GraalHPyBoxing.unboxHandle(hSequence)).getDelegate();
1457+
Object clazz = GetClassNode.getUncached().execute(receiver);
1458+
Object key = HPyAsPythonObjectNodeGen.getUncached().execute(this, hKey);
1459+
Object value = HPyAsPythonObjectNodeGen.getUncached().execute(this, hValue);
1460+
1461+
// fast path
1462+
if (clazz == PythonBuiltinClassType.PDict) {
1463+
PDict dict = (PDict) receiver;
1464+
HashingStorage dictStorage = dict.getDictStorage();
1465+
1466+
// super-fast path for string keys
1467+
if (key instanceof String) {
1468+
if (dictStorage instanceof EmptyStorage) {
1469+
dictStorage = PDict.createNewStorage(true, 1);
1470+
dict.setDictStorage(dictStorage);
1471+
}
1472+
1473+
if (dictStorage instanceof HashMapStorage) {
1474+
((HashMapStorage) dictStorage).put((String) key, null);
1475+
}
1476+
} else {
1477+
dict.setDictStorage(HashingStorageLibrary.getUncached().setItem(dictStorage, key, value));
1478+
}
1479+
return 0;
1480+
} else if (clazz == PythonBuiltinClassType.PList && PGuards.isInteger(key) && ctxListSetItem(receiver, ((Number) key).longValue(), hValue)) {
1481+
return 0;
1482+
}
1483+
return setItemGeneric(receiver, clazz, key, value);
1484+
} catch (PException e) {
1485+
HPyTransformExceptionToNativeNodeGen.getUncached().execute(this, e);
1486+
// non-null value indicates an error
1487+
return -1;
1488+
}
1489+
}
1490+
1491+
public final int ctxSetItemi(long hSequence, long lidx, long hValue) {
1492+
Counter.UpcallSetItemI.increment();
1493+
try {
1494+
// If handle 'hSequence' is a boxed int or double, the object is not a sequence.
1495+
if (!GraalHPyBoxing.isBoxedHandle(hSequence)) {
1496+
throw PRaiseNode.raiseUncached(null, PythonBuiltinClassType.TypeError, ErrorMessages.OBJ_DOES_NOT_SUPPORT_ITEM_ASSIGMENT, 0);
1497+
}
1498+
Object receiver = getObjectForHPyHandle(GraalHPyBoxing.unboxHandle(hSequence)).getDelegate();
1499+
Object clazz = GetClassNode.getUncached().execute(receiver);
1500+
1501+
if (clazz == PythonBuiltinClassType.PList && ctxListSetItem(receiver, lidx, hValue)) {
1502+
return 0;
1503+
}
1504+
Object value = HPyAsPythonObjectNodeGen.getUncached().execute(this, hValue);
1505+
return setItemGeneric(receiver, clazz, lidx, value);
1506+
} catch (PException e) {
1507+
HPyTransformExceptionToNativeNodeGen.getUncached().execute(this, e);
1508+
// non-null value indicates an error
1509+
return -1;
1510+
}
1511+
}
1512+
1513+
private boolean ctxListSetItem(Object receiver, long lidx, long hValue) {
1514+
// fast path for list
1515+
int idx = 0;
1516+
if (!com.oracle.graal.python.builtins.objects.ints.PInt.isIntRange(lidx)) {
1517+
throw PRaiseNode.raiseUncached(null, PythonBuiltinClassType.IndexError, ErrorMessages.CANNOT_FIT_P_INTO_INDEXSIZED_INT, lidx);
1518+
}
1519+
com.oracle.graal.python.builtins.objects.list.PList sequence = (PList) receiver;
1520+
SequenceStorage storage = sequence.getSequenceStorage();
1521+
if (storage instanceof IntSequenceStorage && GraalHPyBoxing.isBoxedInt(hValue)) {
1522+
((IntSequenceStorage) storage).setIntItemNormalized(idx, GraalHPyBoxing.unboxInt(hValue));
1523+
return true;
1524+
} else if (storage instanceof DoubleSequenceStorage && GraalHPyBoxing.isBoxedDouble(hValue)) {
1525+
((DoubleSequenceStorage) storage).setDoubleItemNormalized(idx, GraalHPyBoxing.unboxDouble(hValue));
1526+
return true;
1527+
} else if (storage instanceof LongSequenceStorage && GraalHPyBoxing.isBoxedInt(hValue)) {
1528+
((LongSequenceStorage) storage).setLongItemNormalized(idx, GraalHPyBoxing.unboxInt(hValue));
1529+
return true;
1530+
} else if (storage instanceof ObjectSequenceStorage) {
1531+
Object value = getObjectForHPyHandle(GraalHPyBoxing.unboxHandle(hValue)).getDelegate();
1532+
((ObjectSequenceStorage) storage).setItemNormalized(idx, value);
1533+
return true;
1534+
}
1535+
// TODO: other storages...
1536+
return false;
1537+
}
1538+
1539+
private static int setItemGeneric(Object receiver, Object clazz, Object key, Object value) {
1540+
Object setItemAttribute = LookupCallableSlotInMRONode.getUncached(SpecialMethodSlot.SetItem).execute(clazz);
1541+
if (setItemAttribute == PNone.NO_VALUE) {
1542+
throw PRaiseNode.raiseUncached(null, PythonBuiltinClassType.TypeError, ErrorMessages.OBJ_NOT_SUBSCRIPTABLE, receiver);
14091543
}
1544+
CallTernaryMethodNode.getUncached().execute(null, setItemAttribute, receiver, key, value);
1545+
return 0;
14101546
}
14111547

14121548
public final int ctxNumberCheck(long handle) {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,8 @@ protected final GraalHPyContext ensureContext(GraalHPyContext hpyContext) {
12561256
return hpyContext;
12571257
}
12581258
}
1259+
1260+
public abstract Object execute(GraalHPyContext hpyContext, long bits);
12591261

12601262
@Specialization
12611263
static Object doHandle(@SuppressWarnings("unused") GraalHPyContext hpyContext, GraalHPyHandle handle) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/resources/jni-config.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
{"name":"ctxFloatAsDouble","parameterTypes":["long"] },
99
{"name":"ctxFloatFromDouble","parameterTypes":["double"] },
1010
{"name":"ctxGetItemi","parameterTypes":["long","long"] },
11+
{"name":"ctxSetItem","parameterTypes":["long","long","long"] },
12+
{"name":"ctxSetItemi","parameterTypes":["long","long","long"] },
1113
{"name":"ctxLength","parameterTypes":["long"] },
1214
{"name":"ctxListCheck","parameterTypes":["long"] },
1315
{"name":"ctxLongAsLong","parameterTypes":["long"] },

0 commit comments

Comments
 (0)