Skip to content

Commit 897fb15

Browse files
committed
PythonObjectLibrary.lookupAttribute also for primitive values
1 parent 039b87b commit 897fb15

File tree

8 files changed

+209
-20
lines changed

8 files changed

+209
-20
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* Copyright (c) 2020, 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.test.objects;
42+
43+
import com.oracle.graal.python.builtins.objects.PNone;
44+
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
45+
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
46+
47+
import com.oracle.graal.python.test.PythonTests;
48+
import java.util.concurrent.Callable;
49+
50+
import org.graalvm.polyglot.Context;
51+
import org.graalvm.polyglot.Value;
52+
import org.graalvm.polyglot.proxy.ProxyExecutable;
53+
import org.junit.After;
54+
import static org.junit.Assert.assertNotNull;
55+
import static org.junit.Assert.assertNotSame;
56+
import static org.junit.Assert.assertSame;
57+
import static org.junit.Assert.fail;
58+
import org.junit.Before;
59+
import org.junit.Test;
60+
61+
public class PythonObjectLibraryTests extends PythonTests {
62+
63+
private Context context;
64+
65+
@Before
66+
public void setUpTest() {
67+
Context.Builder builder = Context.newBuilder();
68+
builder.allowExperimentalOptions(true);
69+
builder.allowAllAccess(true);
70+
context = builder.build();
71+
}
72+
73+
@After
74+
public void tearDown() {
75+
context.close();
76+
}
77+
78+
@Test
79+
public void testLookupAttribute() {
80+
lookupAttr(() -> true, "__str__", false);
81+
lookupAttr(() -> 1.1, "__str__", false);
82+
lookupAttr(() -> 1, "__str__", false);
83+
lookupAttr(() -> (long) 1, "__str__", false);
84+
lookupAttr(() -> "abc", "__str__", false);
85+
86+
lookupAttr(() -> new Object(), "__str__", true);
87+
88+
lookupAttr(() -> PythonObjectFactory.getUncached().createInt(1), "__str__", false);
89+
90+
String noSuchMethod = "__nnoossuuttschmeethod__";
91+
lookupAttr(() -> true, noSuchMethod, true);
92+
lookupAttr(() -> 1.1, noSuchMethod, true);
93+
lookupAttr(() -> 1, noSuchMethod, true);
94+
lookupAttr(() -> (long) 1, "__strt__", true);
95+
lookupAttr(() -> "abc", noSuchMethod, true);
96+
}
97+
98+
private void lookupAttr(Callable<Object> createValue, String attrName, boolean expectNoValue) {
99+
PythonObjectLibrary lib = PythonObjectLibrary.getFactory().getUncached();
100+
execInContext(() -> {
101+
Object value = createValue.call();
102+
Object attr = lib.lookupAttribute(value, attrName, false);
103+
assertAttr(attr, expectNoValue);
104+
105+
attr = lib.lookupAttribute(value, attrName, true);
106+
assertAttr(attr, expectNoValue);
107+
return null;
108+
});
109+
}
110+
111+
private static void assertAttr(Object attr, boolean expectNoValue) {
112+
assertNotNull(attr);
113+
if (expectNoValue) {
114+
assertSame(PNone.NO_VALUE, attr);
115+
} else {
116+
assertNotSame(PNone.NO_VALUE, attr);
117+
}
118+
}
119+
120+
public void execInContext(Callable<Object> c) {
121+
context.initialize("python");
122+
context.getPolyglotBindings().putMember("testSymbol", (ProxyExecutable) (Value... args) -> {
123+
try {
124+
return c.call();
125+
} catch (Exception ex) {
126+
ex.printStackTrace();
127+
fail();
128+
}
129+
return null;
130+
});
131+
context.getPolyglotBindings().getMember("testSymbol").execute();
132+
}
133+
134+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,13 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects;
4242

43-
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.AttributeError;
4443
import static com.oracle.graal.python.nodes.SpecialMethodNames.__BOOL__;
4544
import static com.oracle.graal.python.nodes.SpecialMethodNames.__CALL__;
4645
import static com.oracle.graal.python.nodes.SpecialMethodNames.__DELETE__;
4746
import static com.oracle.graal.python.nodes.SpecialMethodNames.__DELITEM__;
4847
import static com.oracle.graal.python.nodes.SpecialMethodNames.__ENTER__;
4948
import static com.oracle.graal.python.nodes.SpecialMethodNames.__EQ__;
5049
import static com.oracle.graal.python.nodes.SpecialMethodNames.__EXIT__;
51-
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETATTRIBUTE__;
5250
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETITEM__;
5351
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GET__;
5452
import static com.oracle.graal.python.nodes.SpecialMethodNames.__HASH__;
@@ -69,6 +67,7 @@
6967

7068
import com.oracle.graal.python.PythonLanguage;
7169
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
70+
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.AttributeError;
7271
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
7372
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
7473
import com.oracle.graal.python.builtins.objects.cext.CApiGuards;
@@ -101,6 +100,7 @@
101100
import com.oracle.graal.python.nodes.PRaiseNode;
102101
import com.oracle.graal.python.nodes.SpecialMethodNames;
103102
import static com.oracle.graal.python.nodes.SpecialMethodNames.__FSPATH__;
103+
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETATTRIBUTE__;
104104
import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETATTR__;
105105
import com.oracle.graal.python.nodes.attributes.HasInheritedAttributeNode;
106106
import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode;
@@ -972,24 +972,35 @@ public int asFileDescriptorWithState(ThreadState state,
972972

973973
@ExportMessage
974974
public Object lookupAttribute(String name, boolean inheritedOnly,
975-
@Exclusive @Cached LookupInheritedAttributeNode.Dynamic lookup,
976-
@Exclusive @Cached ConditionProfile isInheritedOnly,
977-
@Exclusive @Cached ConditionProfile noValue,
978-
@Exclusive @Cached CallNode callNode,
979-
@Exclusive @Cached IsBuiltinClassProfile isAttrError) {
980-
if (isInheritedOnly.profile(inheritedOnly)) {
981-
return lookup.execute(this, name);
982-
} else {
983-
Object getAttrFunc = lookup.execute(this, __GETATTRIBUTE__);
984-
try {
985-
return callNode.execute(getAttrFunc, this, name);
986-
} catch (PException pe) {
987-
pe.expect(AttributeError, isAttrError);
988-
getAttrFunc = lookup.execute(this, __GETATTR__);
989-
if (noValue.profile(getAttrFunc == PNone.NO_VALUE)) {
990-
return PNone.NO_VALUE;
975+
@Exclusive @Cached LookupAttributeNode lookup) {
976+
return lookup.execute(this, name, inheritedOnly);
977+
}
978+
979+
@GenerateUncached
980+
public abstract static class LookupAttributeNode extends Node {
981+
public abstract Object execute(Object receiver, String name, boolean inheritedOnly);
982+
983+
@Specialization
984+
public static Object lookupAttributeImpl(Object receiver, String name, boolean inheritedOnly,
985+
@Cached LookupInheritedAttributeNode.Dynamic lookup,
986+
@Cached ConditionProfile isInheritedOnlyProfile,
987+
@Cached ConditionProfile noValueProfile,
988+
@Cached CallNode callNode,
989+
@Cached IsBuiltinClassProfile isAttrErrorProfile) {
990+
if (isInheritedOnlyProfile.profile(inheritedOnly)) {
991+
return lookup.execute(receiver, name);
992+
} else {
993+
Object getAttrFunc = lookup.execute(receiver, __GETATTRIBUTE__);
994+
try {
995+
return callNode.execute(getAttrFunc, receiver, name);
996+
} catch (PException pe) {
997+
pe.expect(AttributeError, isAttrErrorProfile);
998+
getAttrFunc = lookup.execute(receiver, __GETATTR__);
999+
if (noValueProfile.profile(getAttrFunc == PNone.NO_VALUE)) {
1000+
return PNone.NO_VALUE;
1001+
}
1002+
return callNode.execute(getAttrFunc, receiver, name);
9911003
}
992-
return callNode.execute(getAttrFunc, this, name);
9931004
}
9941005
}
9951006
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/DefaultPythonBooleanExports.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import com.oracle.graal.python.PythonLanguage;
4444
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
45+
import com.oracle.graal.python.builtins.objects.PythonAbstractObject.LookupAttributeNode;
4546
import com.oracle.graal.python.builtins.objects.floats.PFloat;
4647
import com.oracle.graal.python.builtins.objects.function.PArguments.ThreadState;
4748
import com.oracle.graal.python.builtins.objects.ints.PInt;
@@ -50,6 +51,7 @@
5051
import com.oracle.graal.python.runtime.PythonContext;
5152
import com.oracle.graal.python.runtime.PythonOptions;
5253
import com.oracle.truffle.api.dsl.Cached;
54+
import com.oracle.truffle.api.dsl.Cached.Exclusive;
5355
import com.oracle.truffle.api.dsl.Cached.Shared;
5456
import com.oracle.truffle.api.dsl.CachedContext;
5557
import com.oracle.truffle.api.dsl.Fallback;
@@ -247,4 +249,10 @@ static String asPString(Boolean receiver) {
247249
static int asFileDescriptor(Boolean x) {
248250
return x ? 1 : 0;
249251
}
252+
253+
@ExportMessage
254+
public static Object lookupAttribute(Boolean x, String name, boolean inheritedOnly,
255+
@Exclusive @Cached LookupAttributeNode lookup) {
256+
return lookup.execute(x, name, inheritedOnly);
257+
}
250258
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/DefaultPythonDoubleExports.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
4444
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
45+
import com.oracle.graal.python.builtins.objects.PythonAbstractObject.LookupAttributeNode;
4546
import com.oracle.graal.python.builtins.objects.floats.PFloat;
4647
import com.oracle.graal.python.builtins.objects.function.PArguments.ThreadState;
4748
import com.oracle.graal.python.builtins.objects.ints.PInt;
@@ -52,6 +53,7 @@
5253
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
5354
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
5455
import com.oracle.truffle.api.dsl.Cached;
56+
import com.oracle.truffle.api.dsl.Cached.Exclusive;
5557
import com.oracle.truffle.api.dsl.Fallback;
5658
import com.oracle.truffle.api.dsl.Specialization;
5759
import com.oracle.truffle.api.library.CachedLibrary;
@@ -100,7 +102,7 @@ static boolean dd(Double receiver, double other) {
100102

101103
@Specialization
102104
static boolean dF(Double receiver, PFloat other,
103-
@Cached IsBuiltinClassProfile isFloat) {
105+
@Cached.Exclusive @Cached IsBuiltinClassProfile isFloat) {
104106
if (isFloat.profileObject(other, PythonBuiltinClassType.PFloat)) {
105107
return dd(receiver, other.getValue());
106108
} else {
@@ -168,4 +170,10 @@ static Object asPString(Double receiver,
168170
@Cached.Exclusive @Cached ConditionProfile gotState) {
169171
return PythonAbstractObject.asPString(receiver, lookup, gotState, null, callNode, isSubtypeNode, lib, raise);
170172
}
173+
174+
@ExportMessage
175+
public static Object lookupAttribute(Double x, String name, boolean inheritedOnly,
176+
@Exclusive @Cached LookupAttributeNode lookup) {
177+
return lookup.execute(x, name, inheritedOnly);
178+
}
171179
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/DefaultPythonIntegerExports.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
package com.oracle.graal.python.builtins.objects.object;
4242

4343
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
44+
import com.oracle.graal.python.builtins.objects.PythonAbstractObject.LookupAttributeNode;
4445
import com.oracle.graal.python.builtins.objects.floats.PFloat;
4546
import com.oracle.graal.python.builtins.objects.function.PArguments.ThreadState;
4647
import com.oracle.graal.python.builtins.objects.ints.PInt;
@@ -49,6 +50,7 @@
4950
import com.oracle.graal.python.runtime.PythonOptions;
5051
import com.oracle.truffle.api.CompilerDirectives;
5152
import com.oracle.truffle.api.dsl.Cached;
53+
import com.oracle.truffle.api.dsl.Cached.Exclusive;
5254
import com.oracle.truffle.api.dsl.Cached.Shared;
5355
import com.oracle.truffle.api.dsl.Fallback;
5456
import com.oracle.truffle.api.dsl.ImportStatic;
@@ -244,4 +246,10 @@ static String asPString(Integer receiver) {
244246
static int asFileDescriptor(Integer x) {
245247
return x;
246248
}
249+
250+
@ExportMessage
251+
public static Object lookupAttribute(Integer x, String name, boolean inheritedOnly,
252+
@Exclusive @Cached LookupAttributeNode lookup) {
253+
return lookup.execute(x, name, inheritedOnly);
254+
}
247255
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/DefaultPythonLongExports.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
package com.oracle.graal.python.builtins.objects.object;
4242

4343
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
44+
import com.oracle.graal.python.builtins.objects.PythonAbstractObject.LookupAttributeNode;
4445
import com.oracle.graal.python.builtins.objects.floats.PFloat;
4546
import com.oracle.graal.python.builtins.objects.function.PArguments.ThreadState;
4647
import com.oracle.graal.python.builtins.objects.ints.PInt;
@@ -275,4 +276,9 @@ static int asFileDescriptor(Long x,
275276
}
276277
}
277278

279+
@ExportMessage
280+
public static Object lookupAttribute(Long x, String name, boolean inheritedOnly,
281+
@Exclusive @Cached LookupAttributeNode lookup) {
282+
return lookup.execute(x, name, inheritedOnly);
283+
}
278284
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/DefaultPythonObjectExports.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import com.oracle.graal.python.PythonLanguage;
4444
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
45+
import com.oracle.graal.python.builtins.objects.PNone;
4546
import com.oracle.graal.python.builtins.objects.function.PArguments.ThreadState;
4647
import com.oracle.graal.python.builtins.objects.type.LazyPythonClass;
4748
import com.oracle.graal.python.nodes.PRaiseNode;
@@ -253,4 +254,9 @@ static Object asPString(Object receiver,
253254
}
254255
throw raise.raise(PythonBuiltinClassType.TypeError, "expected str, bytes or os.PathLike object, not %p", receiver);
255256
}
257+
258+
@ExportMessage
259+
public static Object lookupAttribute(@SuppressWarnings("unused") Object x, @SuppressWarnings("unused") String name, @SuppressWarnings("unused") boolean inheritedOnly) {
260+
return PNone.NO_VALUE;
261+
}
256262
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/object/DefaultPythonStringExports.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,15 @@
4141
package com.oracle.graal.python.builtins.objects.object;
4242

4343
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
44+
import com.oracle.graal.python.builtins.objects.PythonAbstractObject.LookupAttributeNode;
4445
import com.oracle.graal.python.builtins.objects.function.PArguments.ThreadState;
4546
import com.oracle.graal.python.builtins.objects.str.PString;
4647
import com.oracle.graal.python.builtins.objects.type.LazyPythonClass;
4748
import com.oracle.graal.python.nodes.util.CannotCastException;
4849
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
4950
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
5051
import com.oracle.truffle.api.dsl.Cached;
52+
import com.oracle.truffle.api.dsl.Cached.Exclusive;
5153
import com.oracle.truffle.api.dsl.Fallback;
5254
import com.oracle.truffle.api.dsl.Specialization;
5355
import com.oracle.truffle.api.library.ExportLibrary;
@@ -152,4 +154,10 @@ static String asPath(String value) {
152154
static String asPString(String receiver) {
153155
return receiver;
154156
}
157+
158+
@ExportMessage
159+
public static Object lookupAttribute(String x, String name, boolean inheritedOnly,
160+
@Exclusive @Cached LookupAttributeNode lookup) {
161+
return lookup.execute(x, name, inheritedOnly);
162+
}
155163
}

0 commit comments

Comments
 (0)