Skip to content

Commit e689e10

Browse files
committed
Extract common C extension call node.
1 parent 3ded661 commit e689e10

File tree

2 files changed

+151
-41
lines changed

2 files changed

+151
-41
lines changed

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

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
import com.oracle.graal.python.builtins.objects.cext.CExtNodesFactory.TransformExceptionToNativeNodeGen;
7171
import com.oracle.graal.python.builtins.objects.cext.DynamicObjectNativeWrapper.PrimitiveNativeWrapper;
7272
import com.oracle.graal.python.builtins.objects.cext.common.CExtAsPythonObjectNode;
73+
import com.oracle.graal.python.builtins.objects.cext.common.CExtCommonNodes.ImportCExtSymbolNode;
7374
import com.oracle.graal.python.builtins.objects.cext.common.CExtContext;
7475
import com.oracle.graal.python.builtins.objects.cext.common.CExtToJavaNode;
7576
import com.oracle.graal.python.builtins.objects.cext.common.CExtToNativeNode;
@@ -176,48 +177,16 @@ abstract static class ImportCAPISymbolNode extends PNodeWithContext {
176177

177178
public abstract Object execute(String name);
178179

179-
@Specialization(guards = "cachedName == name", limit = "1", assumptions = "singleContextAssumption()")
180-
Object doReceiverCachedIdentity(@SuppressWarnings("unused") String name,
181-
@Cached("name") @SuppressWarnings("unused") String cachedName,
182-
@Shared("context") @CachedContext(PythonLanguage.class) @SuppressWarnings("unused") PythonContext context,
183-
@Cached("importCAPISymbolUncached(context, name)") Object sym) {
184-
return sym;
185-
}
186-
187-
@Specialization(guards = "cachedName.equals(name)", limit = "1", assumptions = "singleContextAssumption()", replaces = "doReceiverCachedIdentity")
188-
Object doReceiverCached(@SuppressWarnings("unused") String name,
189-
@Cached("name") @SuppressWarnings("unused") String cachedName,
190-
@Shared("context") @CachedContext(PythonLanguage.class) @SuppressWarnings("unused") PythonContext context,
191-
@Cached("importCAPISymbolUncached(context, name)") Object sym) {
192-
return sym;
193-
}
194-
195-
@Specialization(replaces = {"doReceiverCached", "doReceiverCachedIdentity"})
196-
Object doGeneric(String name,
197-
@CachedLibrary(limit = "1") @SuppressWarnings("unused") InteropLibrary interopLib,
198-
@Shared("context") @CachedContext(PythonLanguage.class) @SuppressWarnings("unused") PythonContext context,
199-
@Cached PRaiseNode raiseNode) {
200-
return importCAPISymbol(raiseNode, interopLib, context.getCApiContext(), name);
201-
}
202-
203-
protected static Object importCAPISymbolUncached(PythonContext context, String name) {
204-
Object capiLibrary = context.getCApiContext().getLLVMLibrary();
205-
return importCAPISymbol(PRaiseNode.getUncached(), InteropLibrary.getFactory().getUncached(capiLibrary), capiLibrary, name);
206-
}
207-
208-
private static Object importCAPISymbol(PRaiseNode raiseNode, InteropLibrary library, Object capiLibrary, String name) {
209-
try {
210-
return library.readMember(capiLibrary, name);
211-
} catch (UnknownIdentifierException e) {
212-
throw raiseNode.raise(PythonBuiltinClassType.SystemError, "invalid C API function: %s", name);
213-
} catch (UnsupportedMessageException e) {
214-
throw raiseNode.raise(PythonBuiltinClassType.SystemError, "corrupted C API library object: %s", capiLibrary);
215-
}
180+
@Specialization
181+
static Object doGeneric(String name,
182+
@CachedContext(PythonLanguage.class) PythonContext context,
183+
@Cached ImportCExtSymbolNode importCExtSymbolNode) {
184+
return importCExtSymbolNode.execute(context.getCApiContext(), name);
216185
}
217-
218186
}
219187

220188
// -----------------------------------------------------------------------------------------------------------------
189+
221190
/**
222191
* For some builtin classes, the CPython approach to creating a subclass instance is to just
223192
* call the alloc function and then assign some fields. This needs to be done in C. This node
@@ -1778,13 +1747,14 @@ public final Object call(String name, Object... args) {
17781747
public abstract Object execute(String name, Object[] args);
17791748

17801749
@Specialization
1781-
Object doIt(String name, Object[] args,
1750+
static Object doIt(String name, Object[] args,
1751+
@Cached ImportCExtSymbolNode importCExtSymbolNode,
1752+
@CachedContext(PythonLanguage.class) PythonContext context,
17821753
@CachedLibrary(limit = "1") InteropLibrary interopLibrary,
1783-
@Cached ImportCAPISymbolNode importCAPISymbolNode,
17841754
@Cached BranchProfile profile,
17851755
@Cached PRaiseNode raiseNode) {
17861756
try {
1787-
return interopLibrary.execute(importCAPISymbolNode.execute(name), args);
1757+
return interopLibrary.execute(importCExtSymbolNode.execute(context.getCApiContext(), name), args);
17881758
} catch (UnsupportedTypeException | ArityException e) {
17891759
profile.enter();
17901760
throw raiseNode.raise(PythonBuiltinClassType.TypeError, e);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright (c) 2019, 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.cext.common;
42+
43+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
44+
import com.oracle.graal.python.nodes.PNodeWithContext;
45+
import com.oracle.graal.python.nodes.PRaiseNode;
46+
import com.oracle.truffle.api.dsl.Cached;
47+
import com.oracle.truffle.api.dsl.GenerateUncached;
48+
import com.oracle.truffle.api.dsl.Specialization;
49+
import com.oracle.truffle.api.interop.ArityException;
50+
import com.oracle.truffle.api.interop.InteropLibrary;
51+
import com.oracle.truffle.api.interop.UnknownIdentifierException;
52+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
53+
import com.oracle.truffle.api.interop.UnsupportedTypeException;
54+
import com.oracle.truffle.api.library.CachedLibrary;
55+
import com.oracle.truffle.api.profiles.BranchProfile;
56+
57+
public abstract class CExtCommonNodes {
58+
59+
@GenerateUncached
60+
public abstract static class ImportCExtSymbolNode extends PNodeWithContext {
61+
62+
public abstract Object execute(CExtContext nativeContext, String name);
63+
64+
// n.b. if 'singleContextAssumption' is valid, we may also cache the native context
65+
@Specialization(guards = {"nativeContext == cachedNativeContext", "cachedName == name"}, //
66+
limit = "1", //
67+
assumptions = "singleContextAssumption()")
68+
@SuppressWarnings("unused")
69+
static Object doReceiverCachedIdentity(CExtContext nativeContext, String name,
70+
@Cached("nativeContext") CExtContext cachedNativeContext,
71+
@Cached("name") String cachedName,
72+
@Cached("importCAPISymbolUncached(nativeContext, name)") Object sym) {
73+
return sym;
74+
}
75+
76+
// n.b. if 'singleContextAssumption' is valid, we may also cache the native context
77+
@Specialization(guards = {"nativeContext == cachedNativeContext", "cachedName.equals(name)"}, //
78+
limit = "1", //
79+
assumptions = "singleContextAssumption()", //
80+
replaces = "doReceiverCachedIdentity")
81+
@SuppressWarnings("unused")
82+
static Object doReceiverCached(CExtContext nativeContext, String name,
83+
@Cached("nativeContext") CExtContext cachedNativeContext,
84+
@Cached("name") String cachedName,
85+
@Cached("importCAPISymbolUncached(nativeContext, name)") Object sym) {
86+
return sym;
87+
}
88+
89+
@Specialization(replaces = {"doReceiverCachedIdentity", "doReceiverCached"}, //
90+
limit = "1")
91+
static Object doWithContext(CExtContext nativeContext, String name,
92+
@CachedLibrary("nativeContext.getLLVMLibrary()") @SuppressWarnings("unused") InteropLibrary interopLib,
93+
@Cached PRaiseNode raiseNode) {
94+
return importCAPISymbol(raiseNode, interopLib, nativeContext.getLLVMLibrary(), name);
95+
}
96+
97+
protected static Object importCAPISymbolUncached(CExtContext nativeContext, String name) {
98+
Object capiLibrary = nativeContext.getLLVMLibrary();
99+
return importCAPISymbol(PRaiseNode.getUncached(), InteropLibrary.getFactory().getUncached(capiLibrary), capiLibrary, name);
100+
}
101+
102+
private static Object importCAPISymbol(PRaiseNode raiseNode, InteropLibrary library, Object capiLibrary, String name) {
103+
try {
104+
return library.readMember(capiLibrary, name);
105+
} catch (UnknownIdentifierException e) {
106+
throw raiseNode.raise(PythonBuiltinClassType.SystemError, "invalid C API function: %s", name);
107+
} catch (UnsupportedMessageException e) {
108+
throw raiseNode.raise(PythonBuiltinClassType.SystemError, "corrupted C API library object: %s", capiLibrary);
109+
}
110+
}
111+
}
112+
113+
@GenerateUncached
114+
public abstract static class PCallCExtFunction extends PNodeWithContext {
115+
116+
public final Object call(CExtContext nativeContext, String name, Object... args) {
117+
return execute(nativeContext, name, args);
118+
}
119+
120+
public abstract Object execute(CExtContext nativeContext, String name, Object[] args);
121+
122+
@Specialization
123+
static Object doIt(CExtContext nativeContext, String name, Object[] args,
124+
@CachedLibrary(limit = "1") InteropLibrary interopLibrary,
125+
@Cached ImportCExtSymbolNode importCExtSymbolNode,
126+
@Cached BranchProfile profile,
127+
@Cached PRaiseNode raiseNode) {
128+
try {
129+
return interopLibrary.execute(importCExtSymbolNode.execute(nativeContext, name), args);
130+
} catch (UnsupportedTypeException | ArityException e) {
131+
profile.enter();
132+
throw raiseNode.raise(PythonBuiltinClassType.TypeError, e);
133+
} catch (UnsupportedMessageException e) {
134+
profile.enter();
135+
throw raiseNode.raise(PythonBuiltinClassType.TypeError, "C API symbol %s is not callable", name);
136+
}
137+
}
138+
}
139+
140+
}

0 commit comments

Comments
 (0)