Skip to content

Commit de01f4d

Browse files
committed
[GR-12287] Improve performance of native type checks.
PullRequest: graalpython/259
2 parents 889e96a + 35061ce commit de01f4d

File tree

11 files changed

+239
-76
lines changed

11 files changed

+239
-76
lines changed

graalpython/com.oracle.graal.python.cext/src/abstract.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,26 @@ PyObject* PySequence_Tuple(PyObject *v) {
256256
return UPCALL_CEXT_O(_jls_PySequence_Tuple, native_to_java(v));
257257
}
258258

259-
UPCALL_ID(PySequence_Fast);
259+
UPCALL_ID(PySequence_List);
260+
PyObject* PySequence_List(PyObject *v) {
261+
return UPCALL_CEXT_O(_jls_PySequence_List, native_to_java(v));
262+
}
263+
260264
PyObject * PySequence_Fast(PyObject *v, const char *m) {
261-
return UPCALL_CEXT_O(_jls_PySequence_Fast, native_to_java(v), polyglot_from_string(m, SRC_CS));
265+
if (v == NULL) {
266+
return null_error();
267+
}
268+
269+
if (PyList_CheckExact(v) || PyTuple_CheckExact(v)) {
270+
Py_INCREF(v);
271+
return v;
272+
}
273+
274+
PyObject* result = UPCALL_CEXT_O(_jls_PySequence_List, native_to_java(v));
275+
if (result == NULL) {
276+
PyErr_SetString(PyExc_TypeError, m);
277+
}
278+
return result;
262279
}
263280

264281
UPCALL_ID(PyObject_GetItem);

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

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@
4040
*/
4141
package com.oracle.graal.python.builtins.modules;
4242

43+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.IndexError;
44+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError;
45+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETITEM__;
4346
import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError;
44-
import static com.oracle.graal.python.runtime.exception.PythonErrorType.SystemError;
4547
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
4648

4749
import java.math.BigInteger;
@@ -107,6 +109,7 @@
107109
import com.oracle.graal.python.builtins.objects.function.PythonCallable;
108110
import com.oracle.graal.python.builtins.objects.ints.PInt;
109111
import com.oracle.graal.python.builtins.objects.iterator.PSequenceIterator;
112+
import com.oracle.graal.python.builtins.objects.list.PList;
110113
import com.oracle.graal.python.builtins.objects.module.PythonModule;
111114
import com.oracle.graal.python.builtins.objects.object.PythonObject;
112115
import com.oracle.graal.python.builtins.objects.slice.PSlice;
@@ -123,9 +126,11 @@
123126
import com.oracle.graal.python.nodes.argument.ReadIndexedArgumentNode;
124127
import com.oracle.graal.python.nodes.argument.ReadVarArgsNode;
125128
import com.oracle.graal.python.nodes.argument.ReadVarKeywordsNode;
129+
import com.oracle.graal.python.nodes.attributes.HasInheritedAttributeNode;
126130
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
127131
import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
128132
import com.oracle.graal.python.nodes.call.PythonCallNode;
133+
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
129134
import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
130135
import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode;
131136
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -142,6 +147,7 @@
142147
import com.oracle.graal.python.runtime.exception.PException;
143148
import com.oracle.graal.python.runtime.exception.PythonErrorType;
144149
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
150+
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
145151
import com.oracle.truffle.api.CallTarget;
146152
import com.oracle.truffle.api.CompilerDirectives;
147153
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
@@ -1330,26 +1336,6 @@ private GetClassNode getClassNode() {
13301336
}
13311337
}
13321338

1333-
@Builtin(name = "PyTruffle_Set_Ptr", fixedNumOfPositionalArgs = 2)
1334-
@GenerateNodeFactory
1335-
abstract static class PyTruffle_Set_Ptr extends NativeBuiltin {
1336-
1337-
@Specialization
1338-
int doPythonObject(PythonAbstractObject nativeWrapper, TruffleObject ptr) {
1339-
return doNativeWrapper(nativeWrapper.getNativeWrapper(), ptr);
1340-
}
1341-
1342-
@Specialization
1343-
int doNativeWrapper(PythonNativeWrapper nativeWrapper, TruffleObject ptr) {
1344-
if (nativeWrapper.isNative()) {
1345-
PythonContext.getSingleNativeContextAssumption().invalidate();
1346-
} else {
1347-
nativeWrapper.setNativePointer(ptr);
1348-
}
1349-
return 0;
1350-
}
1351-
}
1352-
13531339
@Builtin(name = "PyTruffle_Set_SulongType", fixedNumOfPositionalArgs = 2)
13541340
@GenerateNodeFactory
13551341
abstract static class PyTruffle_Set_SulongType extends NativeBuiltin {
@@ -2043,4 +2029,70 @@ long doGeneric(Object n) {
20432029
return asPrimitiveNode.executeLong(n, 0, Long.BYTES);
20442030
}
20452031
}
2032+
2033+
@Builtin(name = "PyType_IsSubtype", fixedNumOfPositionalArgs = 2)
2034+
@GenerateNodeFactory
2035+
abstract static class PyType_IsSubtype extends PythonBinaryBuiltinNode {
2036+
@Child private IsSubtypeNode isSubtypeNode = IsSubtypeNode.create();
2037+
2038+
@Specialization
2039+
int doI(PythonClass a, PythonClass b) {
2040+
if (isSubtypeNode.execute(a, b)) {
2041+
return 1;
2042+
}
2043+
return 0;
2044+
}
2045+
}
2046+
2047+
@Builtin(name = "PyTuple_GetItem", fixedNumOfPositionalArgs = 2)
2048+
@GenerateNodeFactory
2049+
abstract static class PyTuple_GetItem extends PythonBinaryBuiltinNode {
2050+
2051+
@Specialization
2052+
Object doPTuple(PTuple tuple, long key,
2053+
@Cached("create()") SequenceStorageNodes.LenNode lenNode,
2054+
@Cached("createNotNormalized()") SequenceStorageNodes.GetItemNode getItemNode) {
2055+
SequenceStorage sequenceStorage = tuple.getSequenceStorage();
2056+
// we must do a bounds-check but we must not normalize the index
2057+
if (key < 0 || key >= lenNode.execute(sequenceStorage)) {
2058+
throw raise(IndexError, NormalizeIndexNode.TUPLE_OUT_OF_BOUNDS);
2059+
}
2060+
return getItemNode.execute(sequenceStorage, key);
2061+
}
2062+
2063+
@Fallback
2064+
Object doPTuple(Object tuple, @SuppressWarnings("unused") Object key) {
2065+
// TODO(fa) To be absolutely correct, we need to do a 'isinstance' check on the object.
2066+
throw raise(SystemError, "bad argument to internal function, was '%s' (type '%p')", tuple, tuple);
2067+
}
2068+
}
2069+
2070+
@Builtin(name = "PySequence_Check", fixedNumOfPositionalArgs = 1)
2071+
@GenerateNodeFactory
2072+
abstract static class PySequence_Check extends PythonUnaryBuiltinNode {
2073+
@Child private HasInheritedAttributeNode hasInheritedAttrNode;
2074+
2075+
@Specialization(guards = "isPSequence(object)")
2076+
int doSequence(@SuppressWarnings("unused") Object object) {
2077+
return 1;
2078+
}
2079+
2080+
@Specialization
2081+
int doDict(@SuppressWarnings("unused") PDict object) {
2082+
return 0;
2083+
}
2084+
2085+
@Fallback
2086+
int doGeneric(Object object) {
2087+
if (hasInheritedAttrNode == null) {
2088+
CompilerDirectives.transferToInterpreterAndInvalidate();
2089+
hasInheritedAttrNode = insert(HasInheritedAttributeNode.create(__GETITEM__));
2090+
}
2091+
return hasInheritedAttrNode.execute(object) ? 1 : 0;
2092+
}
2093+
2094+
protected static boolean isPSequence(Object object) {
2095+
return object instanceof PList || object instanceof PTuple;
2096+
}
2097+
}
20462098
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.oracle.graal.python.builtins.objects.cext.CArrayWrappers.CByteArrayWrapper;
4646
import com.oracle.graal.python.builtins.objects.cext.CArrayWrappers.CStringWrapper;
4747
import com.oracle.graal.python.builtins.objects.cext.CExtNodes.CExtBaseNode;
48+
import com.oracle.graal.python.builtins.objects.cext.PythonObjectNativeWrapperMR.InvalidateNativeObjectsAllManagedNode;
4849
import com.oracle.graal.python.builtins.objects.ints.PInt;
4950
import com.oracle.graal.python.nodes.SpecialMethodNames;
5051
import com.oracle.truffle.api.CompilerDirectives;
@@ -159,8 +160,10 @@ int access(CByteArrayWrapper obj) {
159160

160161
@Resolve(message = "IS_POINTER")
161162
abstract static class IsPointerNode extends Node {
163+
@Child private CExtNodes.IsPointerNode pIsPointerNode = CExtNodes.IsPointerNode.create();
164+
162165
boolean access(CArrayWrapper obj) {
163-
return obj.isNative();
166+
return pIsPointerNode.execute(obj);
164167
}
165168
}
166169

@@ -190,8 +193,10 @@ long access(CArrayWrapper obj) {
190193
@Resolve(message = "TO_NATIVE")
191194
abstract static class ToNativeNode extends Node {
192195
@Child private CExtNodes.AsCharPointer asCharPointerNode;
196+
@Child private InvalidateNativeObjectsAllManagedNode invalidateNode = InvalidateNativeObjectsAllManagedNode.create();
193197

194198
Object access(CArrayWrapper obj) {
199+
invalidateNode.execute();
195200
if (!obj.isNative()) {
196201
if (asCharPointerNode == null) {
197202
CompilerDirectives.transferToInterpreterAndInvalidate();

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

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.CextUpcallNodeGen;
5757
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.DirectUpcallNodeGen;
5858
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.GetNativeClassNodeGen;
59+
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.IsPointerNodeGen;
5960
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.MaterializeDelegateNodeGen;
6061
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.ObjectUpcallNodeGen;
6162
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.ToJavaNodeGen;
@@ -105,6 +106,7 @@
105106
import com.oracle.graal.python.runtime.exception.PException;
106107
import com.oracle.graal.python.runtime.exception.PythonErrorType;
107108
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
109+
import com.oracle.truffle.api.Assumption;
108110
import com.oracle.truffle.api.CompilerDirectives;
109111
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
110112
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -377,6 +379,7 @@ public static ToSulongNode create() {
377379
*/
378380
public abstract static class AsPythonObjectNode extends CExtBaseNode {
379381
@Child private MaterializeDelegateNode materializeNode;
382+
@Child private IsPointerNode isPointerNode;
380383

381384
public abstract Object execute(Object value);
382385

@@ -385,27 +388,27 @@ boolean doBoolNativeWrapper(BoolNativeWrapper object) {
385388
return object.getValue();
386389
}
387390

388-
@Specialization(guards = "!object.isNative()")
391+
@Specialization(guards = "!isNative(object)")
389392
byte doByteNativeWrapper(ByteNativeWrapper object) {
390393
return object.getValue();
391394
}
392395

393-
@Specialization(guards = "!object.isNative()")
396+
@Specialization(guards = "!isNative(object)")
394397
int doIntNativeWrapper(IntNativeWrapper object) {
395398
return object.getValue();
396399
}
397400

398-
@Specialization(guards = "!object.isNative()")
401+
@Specialization(guards = "!isNative(object)")
399402
long doLongNativeWrapper(LongNativeWrapper object) {
400403
return object.getValue();
401404
}
402405

403-
@Specialization(guards = "!object.isNative()")
406+
@Specialization(guards = "!isNative(object)")
404407
double doDoubleNativeWrapper(DoubleNativeWrapper object) {
405408
return object.getValue();
406409
}
407410

408-
@Specialization(guards = {"!isBoolNativeWrapper(object)", "object.isNative()"})
411+
@Specialization(guards = {"!isBoolNativeWrapper(object)", "isNative(object)"})
409412
Object doPrimitiveNativeWrapper(PrimitiveNativeWrapper object) {
410413
return getMaterializeNode().execute(object);
411414
}
@@ -467,6 +470,14 @@ Object run(Object obj) {
467470
throw raise(PythonErrorType.SystemError, "invalid object from native: %s", obj);
468471
}
469472

473+
protected boolean isNative(PythonNativeWrapper object) {
474+
if (isPointerNode == null) {
475+
CompilerDirectives.transferToInterpreterAndInvalidate();
476+
isPointerNode = insert(IsPointerNode.create());
477+
}
478+
return isPointerNode.execute(object);
479+
}
480+
470481
protected static boolean isPrimitiveNativeWrapper(PythonNativeWrapper object) {
471482
return object instanceof PrimitiveNativeWrapper;
472483
}
@@ -1456,4 +1467,27 @@ protected ReadArgumentNode[] getArguments() {
14561467
throw new IllegalAccessError();
14571468
}
14581469
}
1470+
1471+
public abstract static class IsPointerNode extends PNodeWithContext {
1472+
1473+
public abstract boolean execute(PythonNativeWrapper obj);
1474+
1475+
@Specialization(assumptions = {"singleContextAssumption()", "nativeObjectsAllManagedAssumption()"})
1476+
boolean doFalse(@SuppressWarnings("unused") PythonNativeWrapper obj) {
1477+
return false;
1478+
}
1479+
1480+
@Specialization
1481+
boolean doGeneric(PythonNativeWrapper obj) {
1482+
return obj.isNative();
1483+
}
1484+
1485+
protected Assumption nativeObjectsAllManagedAssumption() {
1486+
return getContext().getNativeObjectsAllManagedAssumption();
1487+
}
1488+
1489+
public static IsPointerNode create() {
1490+
return IsPointerNodeGen.create();
1491+
}
1492+
}
14591493
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import com.oracle.graal.python.builtins.objects.cext.PySequenceArrayWrapperMRFactory.ToNativeArrayNodeGen;
5454
import com.oracle.graal.python.builtins.objects.cext.PySequenceArrayWrapperMRFactory.ToNativeStorageNodeGen;
5555
import com.oracle.graal.python.builtins.objects.cext.PySequenceArrayWrapperMRFactory.WriteArrayItemNodeGen;
56+
import com.oracle.graal.python.builtins.objects.cext.PythonObjectNativeWrapperMR.InvalidateNativeObjectsAllManagedNode;
5657
import com.oracle.graal.python.builtins.objects.common.SequenceNodes;
5758
import com.oracle.graal.python.builtins.objects.common.SequenceNodes.GetSequenceStorageNode;
5859
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
@@ -340,8 +341,10 @@ public static WriteArrayItemNode create() {
340341
@Resolve(message = "TO_NATIVE")
341342
abstract static class ToNativeNode extends Node {
342343
@Child private ToNativeArrayNode toPyObjectNode = ToNativeArrayNode.create();
344+
@Child private InvalidateNativeObjectsAllManagedNode invalidateNode = InvalidateNativeObjectsAllManagedNode.create();
343345

344346
Object access(PySequenceArrayWrapper obj) {
347+
invalidateNode.execute();
345348
if (!obj.isNative()) {
346349
obj.setNativePointer(toPyObjectNode.execute(obj));
347350
}
@@ -409,8 +412,10 @@ public static ToNativeArrayNode create() {
409412

410413
@Resolve(message = "IS_POINTER")
411414
abstract static class IsPointerNode extends Node {
415+
@Child private CExtNodes.IsPointerNode pIsPointerNode = CExtNodes.IsPointerNode.create();
416+
412417
boolean access(PySequenceArrayWrapper obj) {
413-
return obj.isNative();
418+
return pIsPointerNode.execute(obj);
414419
}
415420
}
416421

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

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import com.oracle.graal.python.builtins.objects.cext.NativeWrappers.PyUnicodeState;
5050
import com.oracle.graal.python.builtins.objects.cext.NativeWrappers.PyUnicodeWrapper;
5151
import com.oracle.graal.python.builtins.objects.cext.PyUnicodeWrapperMRFactory.PyUnicodeToNativeNodeGen;
52+
import com.oracle.graal.python.builtins.objects.cext.PythonObjectNativeWrapperMR.InvalidateNativeObjectsAllManagedNode;
5253
import com.oracle.graal.python.builtins.objects.cext.PythonObjectNativeWrapperMR.PAsPointerNode;
5354
import com.oracle.graal.python.builtins.objects.cext.PythonObjectNativeWrapperMR.ToPyObjectNode;
5455
import com.oracle.graal.python.builtins.objects.cext.UnicodeObjectNodes.UnicodeAsWideCharNode;
@@ -57,8 +58,6 @@
5758
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
5859
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5960
import com.oracle.truffle.api.dsl.Specialization;
60-
import com.oracle.truffle.api.interop.ForeignAccess;
61-
import com.oracle.truffle.api.interop.Message;
6261
import com.oracle.truffle.api.interop.MessageResolution;
6362
import com.oracle.truffle.api.interop.Resolve;
6463
import com.oracle.truffle.api.interop.TruffleObject;
@@ -145,8 +144,10 @@ private static boolean doCheck(String value, CharsetEncoder asciiEncoder) {
145144
@Resolve(message = "TO_NATIVE")
146145
abstract static class ToNativeNode extends Node {
147146
@Child private ToPyObjectNode toPyObjectNode = ToPyObjectNode.create();
147+
@Child private InvalidateNativeObjectsAllManagedNode invalidateNode = InvalidateNativeObjectsAllManagedNode.create();
148148

149149
Object access(PyUnicodeWrapper obj) {
150+
invalidateNode.execute();
150151
if (!obj.isNative()) {
151152
obj.setNativePointer(toPyObjectNode.execute(obj));
152153
}
@@ -156,18 +157,10 @@ Object access(PyUnicodeWrapper obj) {
156157

157158
@Resolve(message = "IS_POINTER")
158159
abstract static class IsPointerNode extends Node {
159-
@Child private Node isPointerNode;
160+
@Child private CExtNodes.IsPointerNode pIsPointerNode = CExtNodes.IsPointerNode.create();
160161

161162
boolean access(PyUnicodeWrapper obj) {
162-
return obj.isNative() && (!(obj.getNativePointer() instanceof TruffleObject) || ForeignAccess.sendIsPointer(getIsPointerNode(), (TruffleObject) obj.getNativePointer()));
163-
}
164-
165-
private Node getIsPointerNode() {
166-
if (isPointerNode == null) {
167-
CompilerDirectives.transferToInterpreterAndInvalidate();
168-
isPointerNode = insert(Message.IS_POINTER.createNode());
169-
}
170-
return isPointerNode;
163+
return pIsPointerNode.execute(obj);
171164
}
172165
}
173166

0 commit comments

Comments
 (0)