Skip to content

Commit d2d7576

Browse files
committed
[GR-12287] Improve performance of native instance checks (part 2).
PullRequest: graalpython/273
2 parents 39c0ba2 + 5674cc4 commit d2d7576

File tree

6 files changed

+132
-13
lines changed

6 files changed

+132
-13
lines changed

graalpython/com.oracle.graal.python.cext/src/capi.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,16 @@ inline void* native_to_java(PyObject* obj) {
183183
}
184184
}
185185

186+
__attribute__((always_inline))
187+
inline void* native_type_to_java(PyTypeObject* type) {
188+
if (IS_POINTER(((PyObject*)type)->ob_refcnt)) {
189+
return (void*)((PyObject*)type)->ob_refcnt;
190+
} else if (!truffle_cannot_be_handle(((PyObject*)type)->ob_refcnt)) {
191+
return resolve_handle(cache, ((PyObject*)type)->ob_refcnt);
192+
}
193+
return (void*)type;
194+
}
195+
186196
extern void* to_java(PyObject* obj);
187197
extern void* to_java_type(PyTypeObject* cls);
188198
extern PyObject* to_sulong(void *o);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ PyTypeObject PySuper_Type = PY_TRUFFLE_TYPE("super", &PyType_Type, Py_TPFLAGS_DE
5454

5555
UPCALL_ID(PyType_IsSubtype);
5656
int PyType_IsSubtype(PyTypeObject* a, PyTypeObject* b) {
57-
return UPCALL_CEXT_I(_jls_PyType_IsSubtype, native_to_java((PyObject*)a), native_to_java((PyObject*)b));
57+
return ((int (*)(void* a, void* b))_jls_PyType_IsSubtype)(native_type_to_java(a), native_type_to_java(b));
5858
}
5959

6060
static int add_subclass(PyTypeObject *base, PyTypeObject *type) {

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

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
import com.oracle.graal.python.builtins.objects.str.PString;
118118
import com.oracle.graal.python.builtins.objects.traceback.PTraceback;
119119
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
120+
import com.oracle.graal.python.builtins.objects.type.GetTypeFlagsNode;
120121
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
121122
import com.oracle.graal.python.builtins.objects.type.PythonClass;
122123
import com.oracle.graal.python.nodes.PGuards;
@@ -1313,18 +1314,19 @@ Object tbHere(PTraceback next, PFrame frame) {
13131314
@GenerateNodeFactory
13141315
abstract static class PyTruffle_GetTpFlags extends NativeBuiltin {
13151316

1317+
@Child private GetTypeFlagsNode getTypeFlagsNode;
13161318
@Child private GetClassNode getClassNode;
13171319

13181320
@Specialization
13191321
long doPythonObject(PythonNativeWrapper nativeWrapper) {
13201322
PythonClass pclass = getClassNode().execute(nativeWrapper.getDelegate());
1321-
return pclass.getFlags();
1323+
return getTypeFlagsNode().execute(pclass);
13221324
}
13231325

13241326
@Specialization
13251327
long doPythonObject(PythonAbstractObject object) {
13261328
PythonClass pclass = getClassNode().execute(object);
1327-
return pclass.getFlags();
1329+
return getTypeFlagsNode().execute(pclass);
13281330
}
13291331

13301332
private GetClassNode getClassNode() {
@@ -1334,6 +1336,14 @@ private GetClassNode getClassNode() {
13341336
}
13351337
return getClassNode;
13361338
}
1339+
1340+
private GetTypeFlagsNode getTypeFlagsNode() {
1341+
if (getTypeFlagsNode == null) {
1342+
CompilerDirectives.transferToInterpreterAndInvalidate();
1343+
getTypeFlagsNode = insert(GetTypeFlagsNode.create());
1344+
}
1345+
return getTypeFlagsNode;
1346+
}
13371347
}
13381348

13391349
@Builtin(name = "PyTruffle_Set_SulongType", fixedNumOfPositionalArgs = 2)
@@ -2029,14 +2039,37 @@ long doGeneric(Object n) {
20292039
@Builtin(name = "PyType_IsSubtype", fixedNumOfPositionalArgs = 2)
20302040
@GenerateNodeFactory
20312041
abstract static class PyType_IsSubtype extends PythonBinaryBuiltinNode {
2042+
20322043
@Child private IsSubtypeNode isSubtypeNode = IsSubtypeNode.create();
2044+
@Child private CExtNodes.AsPythonObjectNode asPythonObjectNode = CExtNodes.AsPythonObjectNode.create();
2045+
@Child private CExtNodes.ToJavaNode toJavaNode;
2046+
2047+
@Specialization(guards = {"a == cachedA", "b == cachedB"})
2048+
int doCached(@SuppressWarnings("unused") PythonNativeWrapper a, @SuppressWarnings("unused") PythonNativeWrapper b,
2049+
@Cached("a") @SuppressWarnings("unused") PythonNativeWrapper cachedA,
2050+
@Cached("b") @SuppressWarnings("unused") PythonNativeWrapper cachedB,
2051+
@Cached("isNativeSubtype(a, b)") int result) {
2052+
return result;
2053+
}
20332054

2034-
@Specialization
2035-
int doI(PythonClass a, PythonClass b) {
2036-
if (isSubtypeNode.execute(a, b)) {
2037-
return 1;
2055+
@Specialization(replaces = "doCached")
2056+
int doUncached(PythonNativeWrapper a, PythonNativeWrapper b) {
2057+
return isNativeSubtype(a, b);
2058+
}
2059+
2060+
@Fallback
2061+
int doGeneric(Object a, Object b) {
2062+
if (toJavaNode == null) {
2063+
CompilerDirectives.transferToInterpreterAndInvalidate();
2064+
toJavaNode = insert(CExtNodes.ToJavaNode.create());
20382065
}
2039-
return 0;
2066+
return isSubtypeNode.execute(toJavaNode.execute(a), toJavaNode.execute(b)) ? 1 : 0;
2067+
}
2068+
2069+
protected int isNativeSubtype(PythonNativeWrapper a, PythonNativeWrapper b) {
2070+
assert a instanceof PythonClassNativeWrapper || a instanceof PythonClassInitNativeWrapper;
2071+
assert b instanceof PythonClassNativeWrapper || b instanceof PythonClassInitNativeWrapper;
2072+
return isSubtypeNode.execute(asPythonObjectNode.execute(a), asPythonObjectNode.execute(b)) ? 1 : 0;
20402073
}
20412074
}
20422075

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
import com.oracle.graal.python.builtins.objects.object.PythonObject;
8787
import com.oracle.graal.python.builtins.objects.slice.PSlice;
8888
import com.oracle.graal.python.builtins.objects.str.PString;
89+
import com.oracle.graal.python.builtins.objects.type.GetTypeFlagsNode;
8990
import com.oracle.graal.python.builtins.objects.type.LazyPythonClass;
9091
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
9192
import com.oracle.graal.python.builtins.objects.type.PythonClass;
@@ -329,8 +330,9 @@ Object doObFval(Object object, @SuppressWarnings("unused") String key,
329330
}
330331

331332
@Specialization(guards = "eq(TP_FLAGS, key)")
332-
long doTpFlags(PythonClass object, @SuppressWarnings("unused") String key) {
333-
return object.getFlags();
333+
long doTpFlags(PythonClass object, @SuppressWarnings("unused") String key,
334+
@Cached("create()") GetTypeFlagsNode getTypeFlagsNode) {
335+
return getTypeFlagsNode.execute(object);
334336
}
335337

336338
@Specialization(guards = "eq(TP_NAME, key)")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins.objects.type;
42+
43+
import com.oracle.graal.python.nodes.PNodeWithContext;
44+
import com.oracle.truffle.api.dsl.Specialization;
45+
46+
public abstract class GetTypeFlagsNode extends PNodeWithContext {
47+
48+
public abstract long execute(PythonClass clazz);
49+
50+
@Specialization(guards = "isInitialized(clazz)")
51+
long doInitialized(PythonClass clazz) {
52+
return clazz.getFlagsContainer().flags;
53+
}
54+
55+
@Specialization
56+
long doGeneric(PythonClass clazz) {
57+
if (!isInitialized(clazz)) {
58+
return clazz.getFlags();
59+
}
60+
return clazz.getFlagsContainer().flags;
61+
}
62+
63+
protected static boolean isInitialized(PythonClass clazz) {
64+
return clazz.getFlagsContainer().initialDominantBase == null;
65+
}
66+
67+
public static GetTypeFlagsNode create() {
68+
return GetTypeFlagsNodeGen.create();
69+
}
70+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/PythonClass.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -299,13 +299,17 @@ public void setFlags(long flags) {
299299
this.flags.setValue(flags);
300300
}
301301

302+
FlagsContainer getFlagsContainer() {
303+
return flags;
304+
}
305+
302306
/**
303307
* Flags are copied from the initial dominant base class. However, classes may already be
304308
* created before the C API was initialized, i.e., flags were not set.
305309
*/
306-
private static final class FlagsContainer {
307-
private PythonClass initialDominantBase;
308-
private long flags;
310+
static final class FlagsContainer {
311+
PythonClass initialDominantBase;
312+
long flags;
309313

310314
public FlagsContainer(PythonClass superClass) {
311315
this.initialDominantBase = superClass;

0 commit comments

Comments
 (0)