Skip to content

Commit 05ec2d7

Browse files
eregonansalond
authored andcommitted
Move the remaining trait-specific methods from ForeignObject to the dedicated trait classes
(cherry picked from commit 60b82ae)
1 parent c5ab7ea commit 05ec2d7

File tree

11 files changed

+356
-126
lines changed

11 files changed

+356
-126
lines changed

graalpython/com.oracle.graal.python.test/src/tests/test_interop.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1040,7 +1040,9 @@ def test_java_map(self):
10401040
h.__init__(a=1, b=2)
10411041
assert h == {'a': 1, 'b': 2}
10421042

1043-
with self.assertRaisesRegex(TypeError, 'invalid instantiation of foreign object'):
1043+
# Because it tries to call ForeignDict.__call__, but ForeignDict is not executable/instantiable,
1044+
# so it resolves to type.__call__, which cannot create a ForeignDict
1045+
with self.assertRaisesRegex(TypeError, "descriptor requires a 'dict' object but received a 'ForeignDict'"):
10441046
type(h).fromkeys(['a', 'b'], 42)
10451047

10461048
def test_java_iterator(self):

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@
5959
import java.util.ServiceLoader;
6060
import java.util.logging.Level;
6161

62+
import com.oracle.graal.python.builtins.objects.foreign.ForeignExecutableBuiltins;
63+
import com.oracle.graal.python.builtins.objects.foreign.ForeignInstantiableBuiltins;
64+
import com.oracle.graal.python.builtins.objects.foreign.ForeignIterableBuiltins;
6265
import org.graalvm.nativeimage.ImageInfo;
6366

6467
import com.oracle.graal.python.PythonLanguage;
@@ -489,6 +492,9 @@ private static PythonBuiltins[] initializeBuiltins(boolean nativeAccessAllowed,
489492
new ForeignNumberBuiltins(),
490493
new ForeignBooleanBuiltins(),
491494
new ForeignAbstractClassBuiltins(),
495+
new ForeignExecutableBuiltins(),
496+
new ForeignInstantiableBuiltins(),
497+
new ForeignIterableBuiltins(),
492498
new ListBuiltins(),
493499
new DictBuiltins(),
494500
new DictReprBuiltin(),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,9 @@ public enum PythonBuiltinClassType implements TruffleObject {
305305
ForeignNumber("ForeignNumber", J_POLYGLOT, ForeignObject, Flags.PUBLIC_BASE_WDICT, FOREIGNNUMBER_M_FLAGS, ForeignNumberBuiltins.SLOTS),
306306
ForeignBoolean("ForeignBoolean", J_POLYGLOT, ForeignNumber, Flags.PUBLIC_BASE_WDICT, FOREIGNNUMBER_M_FLAGS, ForeignBooleanBuiltins.SLOTS),
307307
ForeignAbstractClass("ForeignAbstractClass", J_POLYGLOT, ForeignObject, Flags.PUBLIC_BASE_WDICT),
308+
ForeignExecutable("ForeignExecutable", J_POLYGLOT, ForeignObject, Flags.PUBLIC_BASE_WDICT),
309+
ForeignInstantiable("ForeignInstantiable", J_POLYGLOT, ForeignObject, Flags.PUBLIC_BASE_WDICT),
310+
ForeignIterable("ForeignIterable", J_POLYGLOT, ForeignObject, Flags.PUBLIC_BASE_WDICT),
308311

309312
// bz2
310313
BZ2Compressor("BZ2Compressor", "_bz2"),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignAbstractClassBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___INSTANCECHECK__;
5252

5353
/*
54-
* NOTE: We are not using IndirectCallContext here in this file (except for CallNode)
54+
* NOTE: We are not using IndirectCallContext here in this file
5555
* because it seems unlikely that these interop messages would call back to Python
5656
* and that we would also need precise frame info for that case.
5757
* Adding it shouldn't hurt peak, but might be a non-trivial overhead in interpreter.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (c) 2017, 2025, Oracle and/or its affiliates.
3+
* Copyright (c) 2014, Regents of the University of California
4+
*
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without modification, are
8+
* permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this list of
11+
* conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other materials provided
14+
* with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
17+
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19+
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21+
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
24+
* OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
package com.oracle.graal.python.builtins.objects.foreign;
28+
29+
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___CALL__;
30+
31+
import java.util.List;
32+
33+
import com.oracle.graal.python.PythonLanguage;
34+
import com.oracle.graal.python.builtins.Builtin;
35+
import com.oracle.graal.python.builtins.CoreFunctions;
36+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
37+
import com.oracle.graal.python.builtins.PythonBuiltins;
38+
import com.oracle.graal.python.builtins.objects.function.PKeyword;
39+
import com.oracle.graal.python.nodes.ErrorMessages;
40+
import com.oracle.graal.python.nodes.PRaiseNode;
41+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
42+
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
43+
import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode;
44+
import com.oracle.graal.python.nodes.object.IsForeignObjectNode;
45+
import com.oracle.graal.python.runtime.ExecutionContext.IndirectCallContext;
46+
import com.oracle.graal.python.runtime.GilNode;
47+
import com.oracle.graal.python.runtime.IndirectCallData;
48+
import com.oracle.graal.python.runtime.PythonContext;
49+
import com.oracle.graal.python.runtime.exception.PythonErrorType;
50+
import com.oracle.truffle.api.CompilerDirectives;
51+
import com.oracle.truffle.api.dsl.Bind;
52+
import com.oracle.truffle.api.dsl.Cached;
53+
import com.oracle.truffle.api.dsl.Fallback;
54+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
55+
import com.oracle.truffle.api.dsl.NodeFactory;
56+
import com.oracle.truffle.api.dsl.Specialization;
57+
import com.oracle.truffle.api.frame.VirtualFrame;
58+
import com.oracle.truffle.api.interop.ArityException;
59+
import com.oracle.truffle.api.interop.InteropLibrary;
60+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
61+
import com.oracle.truffle.api.interop.UnsupportedTypeException;
62+
import com.oracle.truffle.api.library.CachedLibrary;
63+
import com.oracle.truffle.api.nodes.Node;
64+
65+
@CoreFunctions(extendClasses = PythonBuiltinClassType.ForeignExecutable)
66+
public final class ForeignExecutableBuiltins extends PythonBuiltins {
67+
@Override
68+
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
69+
return ForeignExecutableBuiltinsFactory.getFactories();
70+
}
71+
72+
@Builtin(name = J___CALL__, minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true)
73+
@GenerateNodeFactory
74+
public abstract static class CallNode extends PythonBuiltinNode {
75+
@Specialization(guards = {"isForeignObjectNode.execute(inliningTarget, callee)", "!isNoValue(callee)", "keywords.length == 0"}, limit = "1")
76+
static Object doInteropCall(VirtualFrame frame, Object callee, Object[] arguments, @SuppressWarnings("unused") PKeyword[] keywords,
77+
@SuppressWarnings("unused") @Bind("this") Node inliningTarget,
78+
@Cached("createFor(this)") IndirectCallData indirectCallData,
79+
@SuppressWarnings("unused") @Cached IsForeignObjectNode isForeignObjectNode,
80+
@CachedLibrary(limit = "4") InteropLibrary lib,
81+
@Cached PForeignToPTypeNode toPTypeNode,
82+
@Cached GilNode gil,
83+
@Cached PRaiseNode.Lazy raiseNode) {
84+
PythonLanguage language = PythonLanguage.get(inliningTarget);
85+
PythonContext context = PythonContext.get(inliningTarget);
86+
try {
87+
Object state = IndirectCallContext.enter(frame, language, context, indirectCallData);
88+
gil.release(true);
89+
try {
90+
return toPTypeNode.executeConvert(lib.execute(callee, arguments));
91+
} finally {
92+
gil.acquire();
93+
IndirectCallContext.exit(frame, language, context, state);
94+
}
95+
} catch (ArityException | UnsupportedTypeException e) {
96+
throw raiseNode.get(inliningTarget).raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ);
97+
} catch (UnsupportedMessageException e) {
98+
throw CompilerDirectives.shouldNotReachHere(e);
99+
}
100+
}
101+
102+
@Fallback
103+
@SuppressWarnings("unused")
104+
static Object doGeneric(Object callee, Object arguments, Object keywords,
105+
@Cached PRaiseNode raiseNode) {
106+
throw raiseNode.raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ);
107+
}
108+
}
109+
110+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Copyright (c) 2017, 2025, Oracle and/or its affiliates.
3+
* Copyright (c) 2014, Regents of the University of California
4+
*
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without modification, are
8+
* permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this list of
11+
* conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other materials provided
14+
* with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
17+
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19+
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21+
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
24+
* OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
package com.oracle.graal.python.builtins.objects.foreign;
28+
29+
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___CALL__;
30+
import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEW__;
31+
32+
import java.util.List;
33+
34+
import com.oracle.graal.python.PythonLanguage;
35+
import com.oracle.graal.python.builtins.Builtin;
36+
import com.oracle.graal.python.builtins.CoreFunctions;
37+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
38+
import com.oracle.graal.python.builtins.PythonBuiltins;
39+
import com.oracle.graal.python.builtins.objects.function.PKeyword;
40+
import com.oracle.graal.python.nodes.ErrorMessages;
41+
import com.oracle.graal.python.nodes.PRaiseNode;
42+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
43+
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
44+
import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode;
45+
import com.oracle.graal.python.nodes.object.IsForeignObjectNode;
46+
import com.oracle.graal.python.runtime.ExecutionContext.IndirectCallContext;
47+
import com.oracle.graal.python.runtime.GilNode;
48+
import com.oracle.graal.python.runtime.IndirectCallData;
49+
import com.oracle.graal.python.runtime.PythonContext;
50+
import com.oracle.graal.python.runtime.exception.PythonErrorType;
51+
import com.oracle.truffle.api.CompilerDirectives;
52+
import com.oracle.truffle.api.dsl.Bind;
53+
import com.oracle.truffle.api.dsl.Cached;
54+
import com.oracle.truffle.api.dsl.Fallback;
55+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
56+
import com.oracle.truffle.api.dsl.NodeFactory;
57+
import com.oracle.truffle.api.dsl.Specialization;
58+
import com.oracle.truffle.api.frame.VirtualFrame;
59+
import com.oracle.truffle.api.interop.ArityException;
60+
import com.oracle.truffle.api.interop.InteropLibrary;
61+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
62+
import com.oracle.truffle.api.interop.UnsupportedTypeException;
63+
import com.oracle.truffle.api.library.CachedLibrary;
64+
import com.oracle.truffle.api.nodes.Node;
65+
66+
@CoreFunctions(extendClasses = PythonBuiltinClassType.ForeignInstantiable)
67+
public final class ForeignInstantiableBuiltins extends PythonBuiltins {
68+
@Override
69+
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
70+
return ForeignInstantiableBuiltinsFactory.getFactories();
71+
}
72+
73+
@Builtin(name = J___NEW__, minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true)
74+
@GenerateNodeFactory
75+
abstract static class NewNode extends PythonBuiltinNode {
76+
@Specialization(guards = {"isForeignObjectNode.execute(inliningTarget, callee)", "!isNoValue(callee)", "keywords.length == 0"}, limit = "1")
77+
static Object doInteropCall(Object callee, Object[] arguments, @SuppressWarnings("unused") PKeyword[] keywords,
78+
@SuppressWarnings("unused") @Bind("this") Node inliningTarget,
79+
@SuppressWarnings("unused") @Cached IsForeignObjectNode isForeignObjectNode,
80+
@CachedLibrary(limit = "3") InteropLibrary lib,
81+
@Cached PForeignToPTypeNode toPTypeNode,
82+
@Cached GilNode gil,
83+
@Cached PRaiseNode.Lazy raiseNode) {
84+
gil.release(true);
85+
try {
86+
Object res = lib.instantiate(callee, arguments);
87+
return toPTypeNode.executeConvert(res);
88+
} catch (ArityException | UnsupportedTypeException e) {
89+
throw raiseNode.get(inliningTarget).raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ);
90+
} catch (UnsupportedMessageException e) {
91+
throw CompilerDirectives.shouldNotReachHere(e);
92+
} finally {
93+
gil.acquire();
94+
}
95+
}
96+
97+
@Fallback
98+
@SuppressWarnings("unused")
99+
static Object doGeneric(Object callee, Object arguments, Object keywords,
100+
@Cached PRaiseNode raiseNode) {
101+
throw raiseNode.raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ);
102+
}
103+
}
104+
105+
@Builtin(name = J___CALL__, minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true)
106+
@GenerateNodeFactory
107+
public abstract static class CallNode extends PythonBuiltinNode {
108+
@Specialization(guards = {"isForeignObjectNode.execute(inliningTarget, callee)", "!isNoValue(callee)", "keywords.length == 0"}, limit = "1")
109+
static Object doInteropCall(VirtualFrame frame, Object callee, Object[] arguments, @SuppressWarnings("unused") PKeyword[] keywords,
110+
@SuppressWarnings("unused") @Bind("this") Node inliningTarget,
111+
@Cached("createFor(this)") IndirectCallData indirectCallData,
112+
@SuppressWarnings("unused") @Cached IsForeignObjectNode isForeignObjectNode,
113+
@CachedLibrary(limit = "4") InteropLibrary lib,
114+
@Cached PForeignToPTypeNode toPTypeNode,
115+
@Cached GilNode gil,
116+
@Cached PRaiseNode.Lazy raiseNode) {
117+
PythonLanguage language = PythonLanguage.get(inliningTarget);
118+
PythonContext context = PythonContext.get(inliningTarget);
119+
try {
120+
Object state = IndirectCallContext.enter(frame, language, context, indirectCallData);
121+
gil.release(true);
122+
try {
123+
return toPTypeNode.executeConvert(lib.instantiate(callee, arguments));
124+
} finally {
125+
gil.acquire();
126+
IndirectCallContext.exit(frame, language, context, state);
127+
}
128+
} catch (ArityException | UnsupportedTypeException e) {
129+
throw raiseNode.get(inliningTarget).raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ);
130+
} catch (UnsupportedMessageException e) {
131+
throw CompilerDirectives.shouldNotReachHere(e);
132+
}
133+
}
134+
135+
@Fallback
136+
@SuppressWarnings("unused")
137+
static Object doGeneric(Object callee, Object arguments, Object keywords,
138+
@Cached PRaiseNode raiseNode) {
139+
throw raiseNode.raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ);
140+
}
141+
}
142+
143+
}

0 commit comments

Comments
 (0)