Skip to content

Commit 7e15bd1

Browse files
committed
[GR-13049] Allow arbitrary (callable) objects in methods.
PullRequest: graalpython/330
2 parents 9bc24c3 + d8c5cdd commit 7e15bd1

36 files changed

+510
-459
lines changed

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/runtime/PythonModuleTests.java

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,46 @@
3535
import org.junit.Test;
3636

3737
import com.oracle.graal.python.PythonLanguage;
38-
import com.oracle.graal.python.builtins.objects.function.PArguments;
39-
import com.oracle.graal.python.builtins.objects.function.PKeyword;
40-
import com.oracle.graal.python.builtins.objects.function.PythonCallable;
38+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4139
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4240
import com.oracle.graal.python.builtins.objects.module.PythonModule;
4341
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
4442
import com.oracle.graal.python.nodes.BuiltinNames;
4543
import com.oracle.graal.python.nodes.SpecialAttributeNames;
46-
import com.oracle.graal.python.nodes.call.InvokeNode;
44+
import com.oracle.graal.python.nodes.call.CallNode;
4745
import com.oracle.graal.python.runtime.PythonContext;
4846
import com.oracle.graal.python.test.PythonTests;
47+
import com.oracle.truffle.api.Truffle;
48+
import com.oracle.truffle.api.frame.VirtualFrame;
49+
import com.oracle.truffle.api.nodes.RootNode;
4950

5051
public class PythonModuleTests {
5152
private PythonContext context;
5253

54+
private static class PythonModuleTestRootNode extends RootNode {
55+
56+
@Child private CallNode body;
57+
58+
public PythonModuleTestRootNode(PythonLanguage language, CallNode body) {
59+
super(language);
60+
this.body = body;
61+
Truffle.getRuntime().createCallTarget(this);
62+
}
63+
64+
@Override
65+
public Object execute(VirtualFrame frame) {
66+
Object[] arguments = frame.getArguments();
67+
Object[] argsWithoutSelf = new Object[arguments.length - 1];
68+
System.arraycopy(arguments, 1, argsWithoutSelf, 0, argsWithoutSelf.length);
69+
return body.execute(frame, arguments[0], argsWithoutSelf);
70+
}
71+
}
72+
73+
private Object callBuiltin(Object... args) {
74+
PythonModuleTestRootNode rootNode = new PythonModuleTestRootNode(context.getLanguage(), CallNode.create());
75+
return rootNode.getCallTarget().call(args);
76+
}
77+
5378
@Before
5479
public void setUp() {
5580
PythonTests.enterContext();
@@ -68,17 +93,17 @@ public void pythonModuleTest() {
6893
@Test
6994
public void builtinsMinTest() {
7095
final PythonModule builtins = context.getBuiltins();
71-
PBuiltinMethod min = (PBuiltinMethod) builtins.getAttribute(BuiltinNames.MIN);
72-
Object returnValue = InvokeNode.create(min).execute(null, createWithUserArguments(builtins, 4, 2, 1), PKeyword.EMPTY_KEYWORDS);
96+
Object min = builtins.getAttribute(BuiltinNames.MIN);
97+
Object returnValue = callBuiltin(min, 4, 2, 1);
7398
assertEquals(1, returnValue);
7499
}
75100

76101
@Test
77102
public void builtinsIntTest() {
78103
final PythonModule builtins = context.getBuiltins();
79104
PythonBuiltinClass intClass = (PythonBuiltinClass) builtins.getAttribute(BuiltinNames.INT);
80-
PythonCallable intNew = (PythonCallable) intClass.getAttribute(SpecialAttributeNames.__NEW__);
81-
Object returnValue = InvokeNode.create(intNew).execute(null, createWithUserArguments(intClass, "42"), PKeyword.EMPTY_KEYWORDS);
105+
Object intNew = intClass.getAttribute(SpecialAttributeNames.__NEW__);
106+
Object returnValue = callBuiltin(intNew, PythonBuiltinClassType.PInt, "42");
82107
assertEquals(42, returnValue);
83108
}
84109

@@ -87,16 +112,7 @@ public void mainModuleTest() {
87112
PythonModule main = context.getMainModule();
88113
PythonModule builtins = (PythonModule) main.getAttribute(__BUILTINS__);
89114
PBuiltinMethod abs = (PBuiltinMethod) builtins.getAttribute(BuiltinNames.ABS);
90-
Object returned = InvokeNode.create(abs).execute(null, createWithUserArguments(builtins, -42), PKeyword.EMPTY_KEYWORDS);
115+
Object returned = callBuiltin(abs, -42);
91116
assertEquals(42, returned);
92117
}
93-
94-
private static Object[] createWithUserArguments(Object... args) {
95-
Object[] arguments = PArguments.create(args.length);
96-
for (int i = 0; i < args.length; i++) {
97-
PArguments.setArgument(arguments, i, args[i]);
98-
}
99-
return arguments;
100-
}
101-
102118
}

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
4545
import com.oracle.graal.python.builtins.objects.function.PFunction;
4646
import com.oracle.graal.python.builtins.objects.function.PKeyword;
47-
import com.oracle.graal.python.builtins.objects.function.PythonCallable;
4847
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4948
import com.oracle.graal.python.builtins.objects.method.PMethod;
5049
import com.oracle.graal.python.builtins.objects.module.PythonModule;
@@ -385,8 +384,11 @@ protected Iterable<Scope> findTopScopes(PythonContext context) {
385384
@Override
386385
@TruffleBoundary
387386
protected SourceSection findSourceLocation(PythonContext context, Object value) {
388-
if (value instanceof PFunction || value instanceof PMethod) {
389-
PythonCallable callable = (PythonCallable) value;
387+
if (value instanceof PFunction) {
388+
PFunction callable = (PFunction) value;
389+
return callable.getCallTarget().getRootNode().getSourceSection();
390+
} else if (value instanceof PMethod && ((PMethod) value).getFunction() instanceof PFunction) {
391+
PFunction callable = (PFunction) ((PMethod) value).getFunction();
390392
return callable.getCallTarget().getRootNode().getSourceSection();
391393
} else if (value instanceof PCode) {
392394
return ((PCode) value).getRootNode().getSourceSection();
@@ -408,7 +410,7 @@ protected String toString(PythonContext context, Object value) {
408410
// true during initialization
409411
return value.toString();
410412
}
411-
PBuiltinFunction reprMethod = ((PBuiltinMethod) builtins.getAttribute(BuiltinNames.REPR)).getFunction();
413+
PBuiltinFunction reprMethod = (PBuiltinFunction) ((PBuiltinMethod) builtins.getAttribute(BuiltinNames.REPR)).getFunction();
412414
Object[] userArgs = PArguments.create(2);
413415
PArguments.setArgument(userArgs, 0, PNone.NONE);
414416
PArguments.setArgument(userArgs, 1, value);

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import com.oracle.graal.python.builtins.objects.PNone;
4040
import com.oracle.graal.python.builtins.objects.function.Arity;
4141
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
42-
import com.oracle.graal.python.builtins.objects.function.PythonCallable;
4342
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
4443
import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode;
4544
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
@@ -88,8 +87,8 @@ public void initialize(PythonCore core) {
8887
BoundBuiltinCallable<?> callable = function;
8988
if (builtin.isGetter() || builtin.isSetter()) {
9089
assert !builtin.isClassmethod() && !builtin.isStaticmethod();
91-
PythonCallable get = builtin.isGetter() ? function : null;
92-
PythonCallable set = builtin.isSetter() ? function : null;
90+
PBuiltinFunction get = builtin.isGetter() ? function : null;
91+
PBuiltinFunction set = builtin.isSetter() ? function : null;
9392
callable = core.factory().createGetSetDescriptor(get, set, builtin.name(), null);
9493
} else if (builtin.isClassmethod()) {
9594
assert !builtin.isStaticmethod();

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

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@
9292
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
9393
import com.oracle.graal.python.builtins.objects.function.PFunction;
9494
import com.oracle.graal.python.builtins.objects.function.PKeyword;
95-
import com.oracle.graal.python.builtins.objects.function.PythonCallable;
9695
import com.oracle.graal.python.builtins.objects.getsetdescriptor.HiddenKeyDescriptor;
9796
import com.oracle.graal.python.builtins.objects.ints.PInt;
9897
import com.oracle.graal.python.builtins.objects.iterator.PZip;
@@ -968,12 +967,12 @@ private static BigInteger asciiToBigInteger(String str, int possibleBase, boolea
968967

969968
public abstract Object executeWith(Object cls, Object arg, Object keywordArg);
970969

971-
protected boolean isPrimitiveInt(PythonClass cls) {
970+
protected boolean isPrimitiveInt(LazyPythonClass cls) {
972971
return isPrimitiveProfile.profileClass(cls, PythonBuiltinClassType.PInt);
973972
}
974973

975974
@Specialization
976-
Object parseInt(PythonClass cls, boolean arg, @SuppressWarnings("unused") PNone keywordArg) {
975+
Object parseInt(LazyPythonClass cls, boolean arg, @SuppressWarnings("unused") PNone keywordArg) {
977976
if (isPrimitiveInt(cls)) {
978977
return arg ? 1 : 0;
979978
} else {
@@ -982,15 +981,15 @@ Object parseInt(PythonClass cls, boolean arg, @SuppressWarnings("unused") PNone
982981
}
983982

984983
@Specialization(guards = "isNoValue(keywordArg)")
985-
public Object createInt(PythonClass cls, int arg, @SuppressWarnings("unused") PNone keywordArg) {
984+
public Object createInt(LazyPythonClass cls, int arg, @SuppressWarnings("unused") PNone keywordArg) {
986985
if (isPrimitiveInt(cls)) {
987986
return arg;
988987
}
989988
return factory().createInt(cls, arg);
990989
}
991990

992991
@Specialization(guards = "isNoValue(keywordArg)")
993-
public Object createInt(PythonClass cls, long arg, @SuppressWarnings("unused") PNone keywordArg,
992+
public Object createInt(LazyPythonClass cls, long arg, @SuppressWarnings("unused") PNone keywordArg,
994993
@Cached("createBinaryProfile()") ConditionProfile isIntProfile) {
995994
if (isPrimitiveInt(cls)) {
996995
int intValue = (int) arg;
@@ -1004,7 +1003,7 @@ public Object createInt(PythonClass cls, long arg, @SuppressWarnings("unused") P
10041003
}
10051004

10061005
@Specialization(guards = "isNoValue(keywordArg)")
1007-
public Object createInt(PythonClass cls, double arg, @SuppressWarnings("unused") PNone keywordArg,
1006+
public Object createInt(LazyPythonClass cls, double arg, @SuppressWarnings("unused") PNone keywordArg,
10081007
@Cached("createBinaryProfile()") ConditionProfile isIntProfile) {
10091008
if (isPrimitiveInt(cls) && isIntProfile.profile(arg >= Integer.MIN_VALUE && arg <= Integer.MAX_VALUE)) {
10101009
return (int) arg;
@@ -1013,15 +1012,15 @@ public Object createInt(PythonClass cls, double arg, @SuppressWarnings("unused")
10131012
}
10141013

10151014
@Specialization
1016-
public Object createInt(PythonClass cls, @SuppressWarnings("unused") PNone none, @SuppressWarnings("unused") PNone keywordArg) {
1015+
public Object createInt(LazyPythonClass cls, @SuppressWarnings("unused") PNone none, @SuppressWarnings("unused") PNone keywordArg) {
10171016
if (isPrimitiveInt(cls)) {
10181017
return 0;
10191018
}
10201019
return factory().createInt(cls, 0);
10211020
}
10221021

10231022
@Specialization(guards = "isNoValue(keywordArg)")
1024-
public Object createInt(PythonClass cls, String arg, @SuppressWarnings("unused") PNone keywordArg) {
1023+
public Object createInt(LazyPythonClass cls, String arg, @SuppressWarnings("unused") PNone keywordArg) {
10251024
try {
10261025
Object value = stringToInt(arg, 10);
10271026
if (isPrimitiveInt(cls)) {
@@ -1036,18 +1035,18 @@ public Object createInt(PythonClass cls, String arg, @SuppressWarnings("unused")
10361035

10371036
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
10381037
@TruffleBoundary
1039-
int parseInt(PythonClass cls, PIBytesLike arg, int keywordArg) throws NumberFormatException {
1038+
int parseInt(LazyPythonClass cls, PIBytesLike arg, int keywordArg) throws NumberFormatException {
10401039
return parseInt(cls, toString(arg), keywordArg);
10411040
}
10421041

10431042
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
10441043
@TruffleBoundary
1045-
long parseLong(PythonClass cls, PIBytesLike arg, int keywordArg) throws NumberFormatException {
1044+
long parseLong(LazyPythonClass cls, PIBytesLike arg, int keywordArg) throws NumberFormatException {
10461045
return parseLong(cls, toString(arg), keywordArg);
10471046
}
10481047

10491048
@Specialization
1050-
Object parseBytesError(PythonClass cls, PIBytesLike arg, int base,
1049+
Object parseBytesError(LazyPythonClass cls, PIBytesLike arg, int base,
10511050
@Cached("create()") BranchProfile errorProfile) {
10521051
try {
10531052
return parsePInt(cls, toString(arg), base);
@@ -1058,46 +1057,46 @@ Object parseBytesError(PythonClass cls, PIBytesLike arg, int base,
10581057
}
10591058

10601059
@Specialization(guards = "isNoValue(base)")
1061-
Object parseBytesError(PythonClass cls, PIBytesLike arg, @SuppressWarnings("unused") PNone base,
1060+
Object parseBytesError(LazyPythonClass cls, PIBytesLike arg, @SuppressWarnings("unused") PNone base,
10621061
@Cached("create()") BranchProfile errorProfile) {
10631062
return parseBytesError(cls, arg, 10, errorProfile);
10641063
}
10651064

10661065
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
1067-
int parseInt(PythonClass cls, PString arg, int keywordArg) throws NumberFormatException {
1066+
int parseInt(LazyPythonClass cls, PString arg, int keywordArg) throws NumberFormatException {
10681067
return parseInt(cls, arg.getValue(), keywordArg);
10691068
}
10701069

10711070
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
10721071
@TruffleBoundary
1073-
long parseLong(PythonClass cls, PString arg, int keywordArg) throws NumberFormatException {
1072+
long parseLong(LazyPythonClass cls, PString arg, int keywordArg) throws NumberFormatException {
10741073
return parseLong(cls, arg.getValue(), keywordArg);
10751074
}
10761075

10771076
@Specialization
1078-
Object parsePInt(PythonClass cls, PString arg, int keywordArg) {
1077+
Object parsePInt(LazyPythonClass cls, PString arg, int keywordArg) {
10791078
return parsePInt(cls, arg.getValue(), keywordArg);
10801079
}
10811080

10821081
@Specialization(guards = "isNoValue(base)")
1083-
Object parsePInt(PythonClass cls, PString arg, PNone base) {
1082+
Object parsePInt(LazyPythonClass cls, PString arg, PNone base) {
10841083
return createInt(cls, arg.getValue(), base);
10851084
}
10861085

10871086
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
10881087
@TruffleBoundary
1089-
int parseInt(@SuppressWarnings("unused") PythonClass cls, String arg, int keywordArg) throws NumberFormatException {
1088+
int parseInt(@SuppressWarnings("unused") LazyPythonClass cls, String arg, int keywordArg) throws NumberFormatException {
10901089
return Integer.parseInt(arg, keywordArg);
10911090
}
10921091

10931092
@Specialization(guards = "isPrimitiveInt(cls)", rewriteOn = NumberFormatException.class)
10941093
@TruffleBoundary
1095-
long parseLong(@SuppressWarnings("unused") PythonClass cls, String arg, int keywordArg) throws NumberFormatException {
1094+
long parseLong(@SuppressWarnings("unused") LazyPythonClass cls, String arg, int keywordArg) throws NumberFormatException {
10961095
return Long.parseLong(arg, keywordArg);
10971096
}
10981097

10991098
@Specialization(rewriteOn = NumberFormatException.class)
1100-
Object parsePInt(PythonClass cls, String arg, int base) {
1099+
Object parsePInt(LazyPythonClass cls, String arg, int base) {
11011100
Object int2 = toInt(arg, base);
11021101
if (int2 instanceof BigInteger) {
11031102
return factory().createInt(cls, (BigInteger) int2);
@@ -1110,7 +1109,7 @@ Object parsePInt(PythonClass cls, String arg, int base) {
11101109
}
11111110

11121111
@Specialization(replaces = "parsePInt")
1113-
Object parsePIntError(PythonClass cls, String arg, int base) {
1112+
Object parsePIntError(LazyPythonClass cls, String arg, int base) {
11141113
try {
11151114
return parsePInt(cls, arg, base);
11161115
} catch (NumberFormatException e) {
@@ -1119,7 +1118,7 @@ Object parsePIntError(PythonClass cls, String arg, int base) {
11191118
}
11201119

11211120
@Specialization
1122-
public Object createInt(PythonClass cls, String arg, Object keywordArg) {
1121+
public Object createInt(LazyPythonClass cls, String arg, Object keywordArg) {
11231122
if (keywordArg instanceof PNone) {
11241123
Object value = toInt(arg);
11251124
if (value == null) {
@@ -1139,12 +1138,12 @@ public Object createInt(PythonClass cls, String arg, Object keywordArg) {
11391138

11401139
@SuppressWarnings("unused")
11411140
@Specialization(guards = {"!isString(arg)", "!isNoValue(keywordArg)"})
1142-
Object fail(PythonClass cls, Object arg, Object keywordArg) {
1141+
Object fail(LazyPythonClass cls, Object arg, Object keywordArg) {
11431142
throw raise(TypeError, "int() can't convert non-string with explicit base");
11441143
}
11451144

11461145
@Specialization(guards = {"isNoValue(keywordArg)", "!isNoValue(obj)", "!isHandledType(obj)"})
1147-
public Object createInt(PythonClass cls, Object obj, PNone keywordArg,
1146+
public Object createInt(LazyPythonClass cls, Object obj, PNone keywordArg,
11481147
@Cached("create(__INT__)") LookupAndCallUnaryNode callIntNode,
11491148
@Cached("create(__TRUNC__)") LookupAndCallUnaryNode callTruncNode,
11501149
@Cached("createBinaryProfile()") ConditionProfile isIntProfile) {
@@ -2176,33 +2175,26 @@ private void denyInstantiationAfterInitialization() {
21762175
}
21772176
}
21782177

2179-
@Specialization
2178+
@Specialization(guards = {"!isNoValue(get)", "!isNoValue(set)"})
21802179
@TruffleBoundary
2181-
Object call(PythonClass getSetClass, PythonCallable get, PythonCallable set, String name, PythonClass owner) {
2180+
Object call(PythonClass getSetClass, Object get, Object set, String name, PythonClass owner) {
21822181
denyInstantiationAfterInitialization();
21832182
return factory().createGetSetDescriptor(get, set, name, owner);
21842183
}
21852184

2186-
@Specialization
2185+
@Specialization(guards = {"!isNoValue(get)", "isNoValue(set)"})
21872186
@TruffleBoundary
2188-
Object call(PythonClass getSetClass, PythonCallable get, PNone set, String name, PythonClass owner) {
2187+
Object call(PythonClass getSetClass, Object get, PNone set, String name, PythonClass owner) {
21892188
denyInstantiationAfterInitialization();
21902189
return factory().createGetSetDescriptor(get, null, name, owner);
21912190
}
21922191

2193-
@Specialization
2192+
@Specialization(guards = {"isNoValue(get)", "isNoValue(set)"})
21942193
@TruffleBoundary
2195-
Object call(PythonClass getSetClass, PNone set, PNone get, String name, PythonClass owner) {
2194+
Object call(PythonClass getSetClass, PNone get, PNone set, String name, PythonClass owner) {
21962195
denyInstantiationAfterInitialization();
21972196
return factory().createGetSetDescriptor(null, null, name, owner);
21982197
}
2199-
2200-
@Fallback
2201-
@TruffleBoundary
2202-
Object call(Object klsas, Object set, Object get, Object name, Object owner) {
2203-
denyInstantiationAfterInitialization();
2204-
throw new RuntimeException("error in creating getset_descriptor during core initialization");
2205-
}
22062198
}
22072199

22082200
// slice(stop)

0 commit comments

Comments
 (0)