Skip to content

Commit 1c71d93

Browse files
committed
[GR-14445] Support constructing and calling methods with non-function callables
PullRequest: graalpython/443
2 parents 2e6fc06 + 40fae97 commit 1c71d93

File tree

8 files changed

+58
-21
lines changed

8 files changed

+58
-21
lines changed

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -70,3 +70,22 @@ def test_call_builtin_method():
7070
def test_call_builtin_unbound_method():
7171
x = {1: 2}
7272
assert dict.__getitem__.__call__(x, 1) == 2
73+
74+
75+
def test_make_method():
76+
method_type = type(X().foo)
77+
78+
class A():
79+
def __init__(self, *args):
80+
pass
81+
82+
def __call__(self, x, y):
83+
assert isinstance(x, str)
84+
assert isinstance(self, A)
85+
return "A" + str(x) + str(y)
86+
87+
method1 = method_type(A, A)
88+
method2 = method_type(A(), " is ")
89+
90+
assert isinstance(method1(), A)
91+
assert method2(1) == "A is 1", method2(1)

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@
140140
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
141141
import com.oracle.graal.python.nodes.control.GetIteratorNode;
142142
import com.oracle.graal.python.nodes.control.GetNextNode;
143+
import com.oracle.graal.python.nodes.datamodel.IsCallableNode;
143144
import com.oracle.graal.python.nodes.datamodel.IsIndexNode;
144145
import com.oracle.graal.python.nodes.datamodel.IsSequenceNode;
145146
import com.oracle.graal.python.nodes.expression.CastToListNode;
@@ -2378,13 +2379,23 @@ public Object generator(Object args, Object kwargs) {
23782379
@GenerateNodeFactory
23792380
public abstract static class MethodTypeNode extends PythonTernaryBuiltinNode {
23802381
@Specialization
2381-
Object method(LazyPythonClass cls, Object self, PFunction func) {
2382+
Object method(LazyPythonClass cls, PFunction func, Object self) {
23822383
return factory().createMethod(cls, self, func);
23832384
}
23842385

2385-
@Specialization(guards = "isPythonBuiltinClass(cls)")
2386-
Object methodGeneric(@SuppressWarnings("unused") LazyPythonClass cls, Object self, PBuiltinFunction func) {
2387-
return factory().createBuiltinMethod(self, func);
2386+
@Specialization
2387+
Object methodBuiltin(@SuppressWarnings("unused") LazyPythonClass cls, PBuiltinFunction func, Object self) {
2388+
return factory().createMethod(self, func);
2389+
}
2390+
2391+
@Specialization
2392+
Object methodGeneric(@SuppressWarnings("unused") LazyPythonClass cls, Object func, Object self,
2393+
@Cached("create()") IsCallableNode isCallable) {
2394+
if (isCallable.execute(func)) {
2395+
return factory().createMethod(self, func);
2396+
} else {
2397+
throw raise(TypeError, "first argument must be callable");
2398+
}
23882399
}
23892400
}
23902401

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@
6060
import com.oracle.truffle.api.interop.Resolve;
6161
import com.oracle.truffle.api.nodes.ExplodeLoop;
6262
import com.oracle.truffle.api.nodes.Node;
63-
import com.oracle.truffle.api.profiles.PrimitiveValueProfile;
6463

6564
@MessageResolution(receiverType = MethodWrapper.class)
6665
public class ManagedMethodWrappersMR {
@@ -76,8 +75,6 @@ abstract static class ExecuteNode extends Node {
7675
@Child private ExecuteKeywordStarargsNode expandKwargsNode = ExecuteKeywordStarargsNode.create();
7776
@Child private CallNode dispatch;
7877

79-
private final PrimitiveValueProfile starArgsLenProfile = PrimitiveValueProfile.createEqualityProfile();
80-
8178
public Object access(MethKeywords object, Object[] arguments) {
8279
if (arguments.length != 3) {
8380
throw ArityException.raise(3, arguments.length);
@@ -90,8 +87,7 @@ public Object access(MethKeywords object, Object[] arguments) {
9087
Object kwArgs = toJavaNode.execute(arguments[2]);
9188

9289
Object[] starArgsArray = posStarargsNode.executeWith(starArgs);
93-
int starArgsLen = starArgsLenProfile.profile(starArgsArray.length);
94-
Object[] pArgs = PositionalArgumentsNode.prependArgument(receiver, starArgsArray, starArgsLen);
90+
Object[] pArgs = PositionalArgumentsNode.prependArgument(receiver, starArgsArray);
9591
PKeyword[] kwArgsArray = expandKwargsNode.executeWith(kwArgs);
9692

9793
// execute

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/method/AbstractMethodBuiltins.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4646
import com.oracle.graal.python.builtins.objects.module.PythonModule;
4747
import com.oracle.graal.python.builtins.objects.object.PythonObject;
48+
import com.oracle.graal.python.nodes.argument.positional.PositionalArgumentsNode;
4849
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
4950
import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
5051
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
@@ -73,16 +74,26 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
7374
public abstract static class CallNode extends PythonVarargsBuiltinNode {
7475
@Child private com.oracle.graal.python.nodes.call.CallNode callNode = com.oracle.graal.python.nodes.call.CallNode.create();
7576

76-
@Specialization
77+
@Specialization(guards = "isFunction(self.getFunction())")
7778
protected Object doIt(VirtualFrame frame, PMethod self, Object[] arguments, PKeyword[] keywords) {
7879
return callNode.execute(frame, self, arguments, keywords);
7980
}
8081

81-
@Specialization
82+
@Specialization(guards = "isFunction(self.getFunction())")
8283
protected Object doIt(VirtualFrame frame, PBuiltinMethod self, Object[] arguments, PKeyword[] keywords) {
8384
return callNode.execute(frame, self, arguments, keywords);
8485
}
8586

87+
@Specialization(guards = "!isFunction(self.getFunction())")
88+
protected Object doItNonFunction(VirtualFrame frame, PMethod self, Object[] arguments, PKeyword[] keywords) {
89+
return callNode.execute(frame, self.getFunction(), PositionalArgumentsNode.prependArgument(self.getSelf(), arguments), keywords);
90+
}
91+
92+
@Specialization(guards = "!isFunction(self.getFunction())")
93+
protected Object doItNonFunction(VirtualFrame frame, PBuiltinMethod self, Object[] arguments, PKeyword[] keywords) {
94+
return callNode.execute(frame, self.getFunction(), PositionalArgumentsNode.prependArgument(self.getSelf(), arguments), keywords);
95+
}
96+
8697
@Override
8798
public Object varArgExecute(VirtualFrame frame, Object[] arguments, PKeyword[] keywords) throws VarargsBuiltinDirectInvocationNotSupported {
8899
Object[] argsWithoutSelf = new Object[arguments.length - 1];

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ private Object op(VirtualFrame frame, PythonAbstractClass self, Object[] argumen
255255
Object newMethod = lookupNew.execute(self);
256256
if (newMethod != PNone.NO_VALUE) {
257257
CompilerAsserts.partialEvaluationConstant(doCreateArgs);
258-
Object[] newArgs = doCreateArgs ? PositionalArgumentsNode.prependArgument(self, arguments, arguments.length) : arguments;
258+
Object[] newArgs = doCreateArgs ? PositionalArgumentsNode.prependArgument(self, arguments) : arguments;
259259
Object newInstance = dispatchNew.execute(frame, newMethod, newArgs, keywords);
260260
PythonAbstractClass newInstanceKlass = getClass.execute(newInstance);
261261
if (isSameType(newInstanceKlass, self)) {
@@ -268,7 +268,7 @@ private Object op(VirtualFrame frame, PythonAbstractClass self, Object[] argumen
268268
if (initMethod != PNone.NO_VALUE) {
269269
Object[] initArgs;
270270
if (doCreateArgs) {
271-
initArgs = PositionalArgumentsNode.prependArgument(newInstance, arguments, arguments.length);
271+
initArgs = PositionalArgumentsNode.prependArgument(newInstance, arguments);
272272
} else {
273273
// XXX: (tfel) is this valid? I think it should be fine...
274274
arguments[0] = newInstance;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/argument/positional/PositionalArgumentsNode.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2018, Oracle and/or its affiliates.
2+
* Copyright (c) 2017, 2019, Oracle and/or its affiliates.
33
* Copyright (c) 2014, Regents of the University of California
44
*
55
* All rights reserved.
@@ -63,10 +63,10 @@ public Object[] execute(VirtualFrame frame) {
6363
return values;
6464
}
6565

66-
public static Object[] prependArgument(Object primary, Object[] arguments, int argumentsLength) {
67-
Object[] result = new Object[argumentsLength + 1];
66+
public static Object[] prependArgument(Object primary, Object[] arguments) {
67+
Object[] result = new Object[arguments.length + 1];
6868
result[0] = primary;
69-
System.arraycopy(arguments, 0, result, 1, argumentsLength);
69+
System.arraycopy(arguments, 0, result, 1, arguments.length);
7070
return result;
7171
}
7272

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ protected Object specialCall(VirtualFrame frame, Object callableObject, Object[]
8888
CompilerDirectives.transferToInterpreter();
8989
throw raise(PythonBuiltinClassType.TypeError, "'%p' object is not callable", callableObject);
9090
}
91-
return callCallNode.execute(frame, call, PositionalArgumentsNode.prependArgument(callableObject, arguments, arguments.length), keywords);
91+
return callCallNode.execute(frame, call, PositionalArgumentsNode.prependArgument(callableObject, arguments), keywords);
9292
}
9393

9494
private CreateArgumentsNode ensureCreateArguments() {

mx.graalpython/mx_graalpython_benchmark.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,9 @@ def run(self, cwd, args):
220220
dists.append('SULONG')
221221
if mx.suite("sulong-managed", fatalIfMissing=False):
222222
dists.append('SULONG_MANAGED')
223-
extra_polyglot_args += [mx_subst.path_substitutions.substitute('--llvm.libraryPath=<path:SULONG_MANAGED_LIBS>')]
223+
extra_polyglot_args += ["--experimental-options", mx_subst.path_substitutions.substitute('--llvm.libraryPath=<path:SULONG_MANAGED_LIBS>')]
224224
else:
225-
extra_polyglot_args += [mx_subst.path_substitutions.substitute('--llvm.libraryPath=<path:SULONG_LIBS>')]
225+
extra_polyglot_args += ["--experimental-options", mx_subst.path_substitutions.substitute('--llvm.libraryPath=<path:SULONG_LIBS>')]
226226

227227

228228
vm_args = mx.get_runtime_jvm_args(dists, cp_suffix=self._cp_suffix, cp_prefix=self._cp_prefix)

0 commit comments

Comments
 (0)