Skip to content

Commit 316255e

Browse files
committed
[GR-23207] Fix special method lookup
PullRequest: graalpython/1097
2 parents f7b6a2a + 081b42f commit 316255e

File tree

17 files changed

+344
-67
lines changed

17 files changed

+344
-67
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
def test_special_descriptor():
41+
class A:
42+
@property
43+
def __eq__(self):
44+
def inner(other):
45+
return True
46+
return inner
47+
48+
assert A() == A()

graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_class.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
*graalpython.lib-python.3.test.test_class.ClassTests.testBadTypeReturned
2+
*graalpython.lib-python.3.test.test_class.ClassTests.testForExceptionsRaisedInInstanceGetattr2
23
*graalpython.lib-python.3.test.test_class.ClassTests.testGetSetAndDel
34
*graalpython.lib-python.3.test.test_class.ClassTests.testInit
45
*graalpython.lib-python.3.test.test_class.ClassTests.testMisc

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@
162162
import com.oracle.graal.python.nodes.SpecialMethodNames;
163163
import com.oracle.graal.python.nodes.attributes.GetAttributeNode;
164164
import com.oracle.graal.python.nodes.attributes.GetAttributeNode.GetAnyAttributeNode;
165-
import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode;
166165
import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode;
167166
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
168167
import com.oracle.graal.python.nodes.attributes.SetAttributeNode;
@@ -171,6 +170,7 @@
171170
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
172171
import com.oracle.graal.python.nodes.call.special.LookupAndCallTernaryNode;
173172
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
173+
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodNode;
174174
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
175175
import com.oracle.graal.python.nodes.control.GetIteratorExpressionNode.GetIteratorNode;
176176
import com.oracle.graal.python.nodes.control.GetNextNode;
@@ -856,16 +856,16 @@ public PythonObject reversed(Object cls, String value) {
856856
@Specialization(guards = {"!isString(sequence)", "!isPRange(sequence)"}, limit = "3")
857857
public Object reversed(VirtualFrame frame, Object cls, Object sequence,
858858
@CachedLibrary("sequence") PythonObjectLibrary lib,
859-
@Cached("create(__REVERSED__)") LookupAttributeInMRONode reversedNode,
859+
@Cached("create(__REVERSED__)") LookupSpecialMethodNode reversedNode,
860860
@Cached("create()") CallUnaryMethodNode callReversedNode,
861861
@Cached("create(__LEN__)") LookupAndCallUnaryNode lenNode,
862-
@Cached("create(__GETITEM__)") LookupAttributeInMRONode getItemNode,
862+
@Cached("create(__GETITEM__)") LookupSpecialMethodNode getItemNode,
863863
@Cached("createBinaryProfile()") ConditionProfile noReversedProfile,
864864
@Cached("createBinaryProfile()") ConditionProfile noGetItemProfile) {
865865
Object sequenceKlass = lib.getLazyPythonClass(sequence);
866-
Object reversed = reversedNode.execute(sequenceKlass);
866+
Object reversed = reversedNode.execute(frame, sequenceKlass, sequence);
867867
if (noReversedProfile.profile(reversed == PNone.NO_VALUE)) {
868-
Object getItem = getItemNode.execute(sequenceKlass);
868+
Object getItem = getItemNode.execute(frame, sequenceKlass, sequence);
869869
if (noGetItemProfile.profile(getItem == PNone.NO_VALUE)) {
870870
throw raise(TypeError, ErrorMessages.OBJ_ISNT_REVERSIBLE, sequence);
871871
} else {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
import com.oracle.graal.python.nodes.call.special.CallVarargsMethodNode;
100100
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
101101
import com.oracle.graal.python.nodes.call.special.LookupAndCallTernaryNode;
102+
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodNode;
102103
import com.oracle.graal.python.nodes.classes.AbstractObjectGetBasesNode;
103104
import com.oracle.graal.python.nodes.classes.AbstractObjectIsSubclassNode;
104105
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
@@ -205,7 +206,7 @@ public abstract static class CallNode extends PythonVarargsBuiltinNode {
205206
@Child private LookupAndCallTernaryNode callNewGet = LookupAndCallTernaryNode.create(__GET__);
206207
@Child private LookupAttributeInMRONode lookupNew = LookupAttributeInMRONode.create(__NEW__);
207208
@Child private CallVarargsMethodNode dispatchInit = CallVarargsMethodNode.create();
208-
@Child private LookupAttributeInMRONode lookupInit = LookupAttributeInMRONode.create(__INIT__);
209+
@Child private LookupSpecialMethodNode lookupInit = LookupSpecialMethodNode.create(__INIT__);
209210
@Child private IsSubtypeNode isSubTypeNode;
210211
@Child private TypeNodes.GetNameNode getNameNode;
211212
@Child private IsBuiltinClassProfile isClassClassProfile = IsBuiltinClassProfile.create();
@@ -360,7 +361,7 @@ private Object op(VirtualFrame frame, Object self, Object[] arguments, PKeyword[
360361
// passing keywords or more than one argument see:
361362
// https://github.com/python/cpython/blob/2102c789035ccacbac4362589402ac68baa2cd29/Objects/typeobject.c#L3538
362363
} else {
363-
Object initMethod = lookupInit.execute(newInstanceKlass);
364+
Object initMethod = lookupInit.execute(frame, newInstanceKlass, newInstance);
364365
if (initMethod != PNone.NO_VALUE) {
365366
Object[] initArgs;
366367
if (doCreateArgs) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallBinaryMethodNode.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4545
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4646
import com.oracle.graal.python.nodes.call.CallNode;
47+
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodNode.BoundDescriptor;
4748
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
4849
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
4950
import com.oracle.truffle.api.RootCallTarget;
@@ -54,6 +55,7 @@
5455
import com.oracle.truffle.api.frame.Frame;
5556
import com.oracle.truffle.api.frame.VirtualFrame;
5657
import com.oracle.truffle.api.nodes.UnexpectedResultException;
58+
import com.oracle.truffle.api.profiles.ConditionProfile;
5759

5860
@GenerateUncached
5961
@ReportPolymorphism
@@ -470,7 +472,12 @@ Object callSelfMethod(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMe
470472
"callBoolLongReverse", "callDoubleSingleReverse", "callDoubleReverse", "callBoolDoubleSingleReverse", "callBoolDoubleReverse", "callObjectSingleContextReverse",
471473
"callObjectReverse", "callMethodSingleContext", "callSelfMethodSingleContext", "callMethod", "callSelfMethod"})
472474
static Object call(VirtualFrame frame, Object func, Object arg1, Object arg2,
473-
@Cached CallNode callNode) {
474-
return callNode.execute(frame, func, new Object[]{arg1, arg2}, PKeyword.EMPTY_KEYWORDS);
475+
@Cached CallNode callNode,
476+
@Cached ConditionProfile isBoundProfile) {
477+
if (isBoundProfile.profile(func instanceof BoundDescriptor)) {
478+
return callNode.execute(frame, ((BoundDescriptor) func).descriptor, new Object[]{arg2}, PKeyword.EMPTY_KEYWORDS);
479+
} else {
480+
return callNode.execute(frame, func, new Object[]{arg1, arg2}, PKeyword.EMPTY_KEYWORDS);
481+
}
475482
}
476483
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallQuaternaryMethodNode.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,13 @@
4444
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4545
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4646
import com.oracle.graal.python.nodes.call.CallNode;
47+
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodNode.BoundDescriptor;
4748
import com.oracle.graal.python.nodes.function.builtins.PythonQuaternaryBuiltinNode;
4849
import com.oracle.truffle.api.RootCallTarget;
4950
import com.oracle.truffle.api.dsl.Cached;
5051
import com.oracle.truffle.api.dsl.Specialization;
5152
import com.oracle.truffle.api.frame.VirtualFrame;
53+
import com.oracle.truffle.api.profiles.ConditionProfile;
5254

5355
public abstract class CallQuaternaryMethodNode extends CallSpecialMethodNode {
5456
public static CallQuaternaryMethodNode create() {
@@ -94,7 +96,12 @@ Object callMethod(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMethod
9496

9597
@Specialization(replaces = {"callSingle", "call", "callMethodSingle", "callMethod"})
9698
Object generic(VirtualFrame frame, Object func, Object arg1, Object arg2, Object arg3, Object arg4,
97-
@Cached CallNode callNode) {
98-
return callNode.execute(frame, func, new Object[]{arg1, arg2, arg3, arg4}, PKeyword.EMPTY_KEYWORDS);
99+
@Cached CallNode callNode,
100+
@Cached ConditionProfile isBoundProfile) {
101+
if (isBoundProfile.profile(func instanceof BoundDescriptor)) {
102+
return callNode.execute(frame, ((BoundDescriptor) func).descriptor, new Object[]{arg2, arg3, arg4}, PKeyword.EMPTY_KEYWORDS);
103+
} else {
104+
return callNode.execute(frame, func, new Object[]{arg1, arg2, arg3, arg4}, PKeyword.EMPTY_KEYWORDS);
105+
}
99106
}
100107
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallTernaryMethodNode.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4545
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4646
import com.oracle.graal.python.nodes.call.CallNode;
47+
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodNode.BoundDescriptor;
4748
import com.oracle.graal.python.nodes.function.builtins.PythonQuaternaryBuiltinNode;
4849
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
4950
import com.oracle.truffle.api.RootCallTarget;
@@ -53,6 +54,7 @@
5354
import com.oracle.truffle.api.dsl.Specialization;
5455
import com.oracle.truffle.api.frame.Frame;
5556
import com.oracle.truffle.api.frame.VirtualFrame;
57+
import com.oracle.truffle.api.profiles.ConditionProfile;
5658

5759
@ReportPolymorphism
5860
@GenerateUncached
@@ -207,7 +209,12 @@ Object callSelfMethod(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMe
207209
"doBuiltinMethodOIOCached", "doBuiltinMethodCached", "doBuiltinMethodOIOCtCached", "doBuiltinMethodCtCached", "callSelfMethodSingleContext",
208210
"callSelfMethod"})
209211
static Object call(VirtualFrame frame, Object func, Object arg1, Object arg2, Object arg3,
210-
@Cached CallNode callNode) {
211-
return callNode.execute(frame, func, new Object[]{arg1, arg2, arg3}, PKeyword.EMPTY_KEYWORDS);
212+
@Cached CallNode callNode,
213+
@Cached ConditionProfile isBoundProfile) {
214+
if (isBoundProfile.profile(func instanceof BoundDescriptor)) {
215+
return callNode.execute(frame, ((BoundDescriptor) func).descriptor, new Object[]{arg2, arg3}, PKeyword.EMPTY_KEYWORDS);
216+
} else {
217+
return callNode.execute(frame, func, new Object[]{arg1, arg2, arg3}, PKeyword.EMPTY_KEYWORDS);
218+
}
212219
}
213220
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallUnaryMethodNode.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4545
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4646
import com.oracle.graal.python.nodes.call.CallNode;
47+
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodNode.BoundDescriptor;
4748
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
4849
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
4950
import com.oracle.truffle.api.RootCallTarget;
@@ -54,6 +55,7 @@
5455
import com.oracle.truffle.api.frame.Frame;
5556
import com.oracle.truffle.api.frame.VirtualFrame;
5657
import com.oracle.truffle.api.nodes.UnexpectedResultException;
58+
import com.oracle.truffle.api.profiles.ConditionProfile;
5759

5860
@ReportPolymorphism
5961
@GenerateUncached
@@ -220,7 +222,12 @@ Object callSelfMethod(VirtualFrame frame, @SuppressWarnings("unused") PBuiltinMe
220222
@Specialization(replaces = {"callIntSingle", "callInt", "callLongSingle", "callLong", "callDoubleSingle", "callDouble", "callBoolSingle", "callBool", "callObjectSingleContext",
221223
"callMethodSingleContext", "callSelfMethodSingleContext", "callMethod", "callSelfMethod"})
222224
static Object call(VirtualFrame frame, Object func, Object receiver,
223-
@Cached("create()") CallNode callNode) {
224-
return callNode.execute(frame, func, new Object[]{receiver}, PKeyword.EMPTY_KEYWORDS);
225+
@Cached("create()") CallNode callNode,
226+
@Cached ConditionProfile isBoundProfile) {
227+
if (isBoundProfile.profile(func instanceof BoundDescriptor)) {
228+
return callNode.execute(frame, ((BoundDescriptor) func).descriptor, new Object[0], PKeyword.EMPTY_KEYWORDS);
229+
} else {
230+
return callNode.execute(frame, func, new Object[]{receiver}, PKeyword.EMPTY_KEYWORDS);
231+
}
225232
}
226233
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/special/CallVarargsMethodNode.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,18 @@
4545
import com.oracle.graal.python.builtins.objects.function.PKeyword;
4646
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4747
import com.oracle.graal.python.nodes.call.CallNode;
48+
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodNode.BoundDescriptor;
4849
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
4950
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode.VarargsBuiltinDirectInvocationNotSupported;
51+
import com.oracle.graal.python.util.PythonUtils;
5052
import com.oracle.truffle.api.RootCallTarget;
5153
import com.oracle.truffle.api.dsl.Cached;
5254
import com.oracle.truffle.api.dsl.GenerateUncached;
5355
import com.oracle.truffle.api.dsl.ReportPolymorphism;
5456
import com.oracle.truffle.api.dsl.Specialization;
5557
import com.oracle.truffle.api.frame.Frame;
5658
import com.oracle.truffle.api.frame.VirtualFrame;
59+
import com.oracle.truffle.api.profiles.ConditionProfile;
5760

5861
@GenerateUncached
5962
@ReportPolymorphism
@@ -134,7 +137,14 @@ Object callQuaternary(VirtualFrame frame, Object callable, Object[] arguments, @
134137

135138
@Specialization(replaces = {"callVarargsDirect", "callVarargs", "callSelfMethodSingleContext", "callSelfMethod", "callUnary", "callBinary", "callTernary", "callQuaternary"})
136139
Object call(VirtualFrame frame, Object func, Object[] arguments, PKeyword[] keywords,
137-
@Cached CallNode callNode) {
138-
return callNode.execute(frame, func, arguments, keywords);
140+
@Cached CallNode callNode,
141+
@Cached ConditionProfile isBoundProfile) {
142+
if (isBoundProfile.profile(func instanceof BoundDescriptor)) {
143+
Object[] boundArguments = new Object[arguments.length - 1];
144+
PythonUtils.arraycopy(arguments, 1, boundArguments, 0, boundArguments.length);
145+
return callNode.execute(frame, ((BoundDescriptor) func).descriptor, boundArguments, keywords);
146+
} else {
147+
return callNode.execute(frame, func, arguments, keywords);
148+
}
139149
}
140150
}

0 commit comments

Comments
 (0)