Skip to content

Commit 975f6c0

Browse files
committed
[GR-14298] [GR-11615] Do not cache native pointers in multi-context mode.
PullRequest: graalpython/471
2 parents e625ac5 + f720629 commit 975f6c0

File tree

8 files changed

+222
-84
lines changed

8 files changed

+222
-84
lines changed

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/advance/MultiContextTest.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -48,7 +48,7 @@
4848

4949
public class MultiContextTest extends PythonTests {
5050
@Test
51-
public void testContextReuse() {
51+
public void testSharingWithMemoryview() {
5252
Engine engine = Engine.newBuilder().build();
5353
for (int i = 0; i < 10; i++) {
5454
try (Context context = newContext(engine)) {
@@ -57,6 +57,17 @@ public void testContextReuse() {
5757
}
5858
}
5959

60+
@Test
61+
public void testSharingWithStruct() {
62+
Engine engine = Engine.newBuilder().build();
63+
for (int i = 0; i < 10; i++) {
64+
try (Context context = newContext(engine)) {
65+
context.eval("python", "import struct\n" +
66+
"n = struct.unpack('<q', struct.pack('<d', 1.1))[0]\n");
67+
}
68+
}
69+
}
70+
6071
private static Context newContext(Engine engine) {
6172
return Context.newBuilder().allowAllAccess(true).engine(engine).build();
6273
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232
import java.util.function.Supplier;
3333

3434
import com.oracle.graal.python.builtins.Python3Core;
35+
import com.oracle.graal.python.builtins.objects.PEllipsis;
3536
import com.oracle.graal.python.builtins.objects.PNone;
37+
import com.oracle.graal.python.builtins.objects.PNotImplemented;
3638
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
3739
import com.oracle.graal.python.builtins.objects.code.PCode;
3840
import com.oracle.graal.python.builtins.objects.dict.PDict;
@@ -80,6 +82,7 @@
8082
import com.oracle.truffle.api.instrumentation.ProvidedTags;
8183
import com.oracle.truffle.api.instrumentation.StandardTags;
8284
import com.oracle.truffle.api.nodes.ExecutableNode;
85+
import com.oracle.truffle.api.nodes.ExplodeLoop;
8386
import com.oracle.truffle.api.nodes.Node;
8487
import com.oracle.truffle.api.nodes.RootNode;
8588
import com.oracle.truffle.api.object.Layout;
@@ -120,6 +123,22 @@ public final class PythonLanguage extends TruffleLanguage<PythonContext> {
120123
private static final Layout objectLayout = Layout.newLayout().build();
121124
private static final Shape newShape = objectLayout.createShape(new ObjectType());
122125

126+
private static final Object[] CONTEXT_INSENSITIVE_SINGLETONS = new Object[]{PNone.NONE, PNone.NO_VALUE, PEllipsis.INSTANCE, PNotImplemented.NOT_IMPLEMENTED};
127+
128+
public static int getNumberOfSpecialSingletons() {
129+
return CONTEXT_INSENSITIVE_SINGLETONS.length;
130+
}
131+
132+
@ExplodeLoop
133+
public static int getSingletonNativePtrIdx(Object obj) {
134+
for (int i = 0; i < CONTEXT_INSENSITIVE_SINGLETONS.length; i++) {
135+
if (CONTEXT_INSENSITIVE_SINGLETONS[i] == obj) {
136+
return i;
137+
}
138+
}
139+
return -1;
140+
}
141+
123142
public PythonLanguage() {
124143
this.nodeFactory = NodeFactory.create(this);
125144
}

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

Lines changed: 97 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.DirectUpcallNodeGen;
6969
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.GetNativeClassNodeFactory.GetNativeClassCachedNodeGen;
7070
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.GetTypeMemberNodeGen;
71-
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.IsPointerNodeFactory.IsPointerCachedNodeGen;
71+
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.IsPointerNodeGen;
7272
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.ObjectUpcallNodeGen;
7373
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.PointerCompareNodeGen;
7474
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.ToJavaNodeFactory.ToJavaCachedNodeGen;
@@ -141,6 +141,7 @@
141141
import com.oracle.truffle.api.nodes.NodeUtil;
142142
import com.oracle.truffle.api.profiles.BranchProfile;
143143
import com.oracle.truffle.api.profiles.ConditionProfile;
144+
import com.oracle.truffle.api.profiles.ValueProfile;
144145

145146
public abstract class CExtNodes {
146147

@@ -543,13 +544,13 @@ public static Object doSlowPath(Object object, boolean forceNativeClass) {
543544
return ((PythonNativeWrapper) object).getDelegate();
544545
} else if (IsBuiltinClassProfile.profileClassSlowPath(GetClassNode.getUncached().execute(object), PythonBuiltinClassType.TruffleObject)) {
545546
if (forceNativeClass) {
546-
return PythonLanguage.getCore().factory().createNativeClassWrapper((TruffleObject) object);
547+
return PythonObjectFactory.getUncached().createNativeClassWrapper((TruffleObject) object);
547548
}
548-
return PythonLanguage.getCore().factory().createNativeObjectWrapper((TruffleObject) object);
549+
return PythonObjectFactory.getUncached().createNativeObjectWrapper((TruffleObject) object);
549550
} else if (object instanceof String || object instanceof Number || object instanceof Boolean || object instanceof PythonNativeNull || object instanceof PythonAbstractObject) {
550551
return object;
551552
}
552-
throw PythonLanguage.getCore().raise(PythonErrorType.SystemError, "invalid object from native: %s", object);
553+
throw PRaiseNode.getUncached().raise(PythonErrorType.SystemError, "invalid object from native: %s", object);
553554
}
554555

555556
// TODO(fa): Workaround for DSL bug: did not import factory at users
@@ -1595,42 +1596,73 @@ protected ReadArgumentNode[] getArguments() {
15951596
}
15961597

15971598
// -----------------------------------------------------------------------------------------------------------------
1599+
@GenerateUncached
15981600
public abstract static class IsPointerNode extends com.oracle.graal.python.nodes.PNodeWithContext {
15991601

16001602
public abstract boolean execute(PythonNativeWrapper obj);
16011603

1602-
abstract static class IsPointerCachedNode extends IsPointerNode {
1604+
@Specialization(assumptions = {"singleContextAssumption()", "nativeObjectsAllManagedAssumption()"})
1605+
boolean doFalse(@SuppressWarnings("unused") PythonNativeWrapper obj) {
1606+
return false;
1607+
}
16031608

1604-
@Specialization(assumptions = {"singleContextAssumption()", "nativeObjectsAllManagedAssumption()"})
1605-
boolean doFalse(@SuppressWarnings("unused") PythonNativeWrapper obj) {
1606-
return false;
1609+
@Specialization
1610+
boolean doGeneric(PythonNativeWrapper obj,
1611+
@Cached GetSpecialSingletonPtrNode getSpecialSingletonPtrNode,
1612+
@Cached("createClassProfile()") ValueProfile singletonProfile) {
1613+
if (obj.isNative()) {
1614+
return true;
16071615
}
1608-
1609-
@Specialization
1610-
boolean doGeneric(PythonNativeWrapper obj) {
1611-
return obj.isNative();
1612-
}
1613-
1614-
protected static Assumption nativeObjectsAllManagedAssumption() {
1615-
return PythonLanguage.getContextRef().get().getNativeObjectsAllManagedAssumption();
1616+
Object delegate = singletonProfile.profile(obj.getDelegate());
1617+
if (isSpecialSingleton(delegate)) {
1618+
return getSpecialSingletonPtrNode.execute(delegate) != null;
16161619
}
1620+
return false;
16171621
}
16181622

1619-
static final class IsPointerUncachedNode extends IsPointerNode {
1620-
private static final IsPointerUncachedNode INSTANCE = new IsPointerUncachedNode();
1623+
private static boolean isSpecialSingleton(Object delegate) {
1624+
return PythonLanguage.getSingletonNativePtrIdx(delegate) != -1;
1625+
}
16211626

1622-
@Override
1623-
public boolean execute(PythonNativeWrapper obj) {
1624-
return obj.isNative();
1625-
}
1627+
protected static Assumption nativeObjectsAllManagedAssumption() {
1628+
return PythonLanguage.getContextRef().get().getNativeObjectsAllManagedAssumption();
16261629
}
16271630

16281631
public static IsPointerNode create() {
1629-
return IsPointerCachedNodeGen.create();
1632+
return IsPointerNodeGen.create();
16301633
}
16311634

16321635
public static IsPointerNode getUncached() {
1633-
return IsPointerUncachedNode.INSTANCE;
1636+
return IsPointerNodeGen.getUncached();
1637+
}
1638+
}
1639+
1640+
// -----------------------------------------------------------------------------------------------------------------
1641+
@GenerateUncached
1642+
public abstract static class GetSpecialSingletonPtrNode extends Node {
1643+
1644+
public abstract Object execute(Object obj);
1645+
1646+
@Specialization
1647+
Object doGeneric(Object obj,
1648+
@CachedContext(PythonLanguage.class) PythonContext context) {
1649+
if (obj instanceof PythonAbstractObject) {
1650+
return context.getSingletonNativePtr((PythonAbstractObject) obj);
1651+
}
1652+
return null;
1653+
}
1654+
}
1655+
1656+
// -----------------------------------------------------------------------------------------------------------------
1657+
@GenerateUncached
1658+
public abstract static class SetSpecialSingletonPtrNode extends Node {
1659+
1660+
public abstract void execute(Object obj, Object ptr);
1661+
1662+
@Specialization
1663+
void doGeneric(PythonAbstractObject obj, Object ptr,
1664+
@CachedContext(PythonLanguage.class) PythonContext context) {
1665+
context.setSingletonNativePtr(obj, ptr);
16341666
}
16351667
}
16361668

@@ -1673,11 +1705,14 @@ public abstract static class GetTypeMemberNode extends CExtBaseNode {
16731705
* native context, so we can be sure that the "nativeClassStableAssumption" (which is
16741706
* per-context) is from the context in which this native object was created.
16751707
*/
1676-
@Specialization(guards = {"cachedObj.equals(obj)", "memberName == cachedMemberName"}, limit = "1", assumptions = "getNativeClassStableAssumption(cachedObj)")
1677-
public Object doCachedObj(@SuppressWarnings("unused") PythonNativeClass obj, @SuppressWarnings("unused") String memberName,
1708+
@Specialization(guards = {"isSameNativeObjectNode.execute(cachedObj, obj)", "memberName == cachedMemberName"}, //
1709+
limit = "1", //
1710+
assumptions = {"getNativeClassStableAssumption(cachedObj)", "singleContextAssumption()"})
1711+
public Object doCachedObj(@SuppressWarnings("unused") PythonAbstractNativeObject obj, @SuppressWarnings("unused") String memberName,
1712+
@SuppressWarnings("unused") @Cached IsSameNativeObjectFastNode isSameNativeObjectNode,
16781713
@SuppressWarnings("unused") @Cached("memberName") String cachedMemberName,
16791714
@SuppressWarnings("unused") @Cached("getterFuncName(memberName)") String getterFuncName,
1680-
@Cached("obj") @SuppressWarnings("unused") PythonNativeClass cachedObj,
1715+
@Cached("obj") @SuppressWarnings("unused") PythonAbstractNativeObject cachedObj,
16811716
@Cached("doSlowPath(obj, getterFuncName)") Object result) {
16821717
return result;
16831718
}
@@ -1757,4 +1792,39 @@ static Object getNativeNullWithoutModule(@SuppressWarnings("unused") Object modu
17571792
}
17581793

17591794
}
1795+
1796+
public abstract static class IsSameNativeObjectNode extends CExtBaseNode {
1797+
1798+
public abstract boolean execute(PythonAbstractNativeObject left, PythonAbstractNativeObject right);
1799+
1800+
protected static boolean doNativeFast(PythonAbstractNativeObject left, PythonAbstractNativeObject right) {
1801+
// This check is a bit dangerous since we cannot be sure about the code that is running.
1802+
// Currently, we assume that the pointer object is a Sulong pointer and for this it's
1803+
// fine.
1804+
return left.equals(right);
1805+
}
1806+
1807+
}
1808+
1809+
@GenerateUncached
1810+
public abstract static class IsSameNativeObjectFastNode extends IsSameNativeObjectNode {
1811+
1812+
@Specialization
1813+
boolean doSingleContext(PythonAbstractNativeObject left, PythonAbstractNativeObject right) {
1814+
return IsSameNativeObjectNode.doNativeFast(left, right);
1815+
}
1816+
}
1817+
1818+
@GenerateUncached
1819+
public abstract static class IsSameNativeObjectSlowNode extends IsSameNativeObjectNode {
1820+
1821+
@Specialization
1822+
boolean doSingleContext(PythonAbstractNativeObject left, PythonAbstractNativeObject right,
1823+
@Cached PointerCompareNode pointerCompareNode) {
1824+
if (IsSameNativeObjectNode.doNativeFast(left, right)) {
1825+
return true;
1826+
}
1827+
return pointerCompareNode.execute(SpecialMethodNames.__EQ__, left, right);
1828+
}
1829+
}
17601830
}

0 commit comments

Comments
 (0)