Skip to content

Commit 69ce824

Browse files
committed
add lib nodes PyObject_LookupAttr* PyObject_GetAttr*, PyDict_GetItem*, PyFrame_GetBuiltins, PyObject_CallMethod* and PyObject_GetMethod library nodes
1 parent 4f236f7 commit 69ce824

File tree

7 files changed

+664
-1
lines changed

7 files changed

+664
-1
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2021, 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.lib;
42+
43+
import com.oracle.graal.python.builtins.objects.common.HashingStorage;
44+
import com.oracle.graal.python.builtins.objects.common.HashingStorageLibrary;
45+
import com.oracle.graal.python.builtins.objects.dict.PDict;
46+
import com.oracle.truffle.api.dsl.Bind;
47+
import com.oracle.truffle.api.dsl.Cached;
48+
import com.oracle.truffle.api.dsl.GenerateUncached;
49+
import com.oracle.truffle.api.dsl.Specialization;
50+
import com.oracle.truffle.api.frame.Frame;
51+
import com.oracle.truffle.api.frame.VirtualFrame;
52+
import com.oracle.truffle.api.library.CachedLibrary;
53+
import com.oracle.truffle.api.nodes.Node;
54+
import com.oracle.truffle.api.profiles.ConditionProfile;
55+
56+
/**
57+
* Equivalent to use for the various PyDict_GetItem* functions available in CPython. Note that these
58+
* functions lead to places where there are hard casts to PyDictObject anyway, so we just accept
59+
* PDict.
60+
*/
61+
@GenerateUncached
62+
public abstract class PyDictGetItem extends Node {
63+
public abstract Object execute(Frame frame, PDict dict, Object item);
64+
65+
@Specialization(limit = "3")
66+
static final Object getItemCached(VirtualFrame frame, @SuppressWarnings("unused") PDict dict, Object item,
67+
@Bind("dict.getDictStorage()") HashingStorage dictStorage,
68+
@Cached ConditionProfile frameCondition,
69+
@CachedLibrary("dictStorage") HashingStorageLibrary lib) {
70+
return lib.getItemWithFrame(dictStorage, item, frameCondition, frame);
71+
}
72+
73+
@Specialization(replaces = "getItemCached")
74+
static final Object getItem(PDict dict, Object item,
75+
@CachedLibrary(limit = "3") HashingStorageLibrary lib) {
76+
return lib.getItem(dict.getDictStorage(), item);
77+
}
78+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (c) 2021, 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.lib;
42+
43+
import com.oracle.graal.python.PythonLanguage;
44+
import com.oracle.graal.python.builtins.objects.module.PythonModule;
45+
import com.oracle.graal.python.runtime.PythonContext;
46+
import com.oracle.truffle.api.dsl.CachedContext;
47+
import com.oracle.truffle.api.dsl.GenerateUncached;
48+
import com.oracle.truffle.api.dsl.Specialization;
49+
import com.oracle.truffle.api.nodes.Node;
50+
51+
/**
52+
* Equivalent to use for PyFrame_GetBuiltins. Note we ignore the actual frame and just always return
53+
* the context-global builtins module.
54+
*/
55+
@GenerateUncached
56+
public abstract class PyFrameGetBuiltins extends Node {
57+
public abstract PythonModule execute();
58+
59+
@Specialization
60+
static PythonModule getBuiltins(@CachedContext(PythonLanguage.class) PythonContext context) {
61+
return context.getCore().getBuiltins();
62+
}
63+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright (c) 2021, 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.lib;
42+
43+
import com.oracle.graal.python.builtins.objects.function.PKeyword;
44+
import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
45+
import com.oracle.graal.python.nodes.call.CallNode;
46+
import com.oracle.graal.python.nodes.call.special.CallBinaryMethodNode;
47+
import com.oracle.graal.python.nodes.call.special.CallQuaternaryMethodNode;
48+
import com.oracle.graal.python.nodes.call.special.CallTernaryMethodNode;
49+
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
50+
import com.oracle.graal.python.nodes.call.special.MaybeBindDescriptorNode.BoundDescriptor;
51+
import com.oracle.graal.python.util.PythonUtils;
52+
import com.oracle.truffle.api.dsl.Cached;
53+
import com.oracle.truffle.api.dsl.Cached.Shared;
54+
import com.oracle.truffle.api.dsl.GenerateUncached;
55+
import com.oracle.truffle.api.dsl.ImportStatic;
56+
import com.oracle.truffle.api.dsl.Specialization;
57+
import com.oracle.truffle.api.frame.Frame;
58+
import com.oracle.truffle.api.nodes.Node;
59+
import com.oracle.truffle.api.profiles.ConditionProfile;
60+
61+
/**
62+
* Equivalent to use for the various PyObject_CallMethod* functions available in CPython.
63+
*/
64+
@GenerateUncached
65+
@ImportStatic(SpecialMethodSlot.class)
66+
public abstract class PyObjectCallMethodObjArgs extends Node {
67+
public final Object execute(Frame frame, Object receiver, String name, Object... arguments) {
68+
return executeInternal(frame, receiver, name, arguments);
69+
}
70+
71+
protected abstract Object executeInternal(Frame frame, Object receiver, String name, Object[] arguments);
72+
73+
@Specialization(guards = "arguments.length == 0")
74+
static Object callUnary(Frame frame, Object receiver, String name, @SuppressWarnings("unused") Object[] arguments,
75+
@Shared("getMethod") @Cached PyObjectGetMethod getMethod,
76+
@Cached CallUnaryMethodNode callNode) {
77+
Object callable = getMethod.execute(frame, receiver, name);
78+
return callNode.executeObject(frame, callable, receiver);
79+
}
80+
81+
@Specialization(guards = "arguments.length == 1")
82+
static Object callBinary(Frame frame, Object receiver, String name, Object[] arguments,
83+
@Shared("getMethod") @Cached PyObjectGetMethod getMethod,
84+
@Cached CallBinaryMethodNode callNode) {
85+
Object callable = getMethod.execute(frame, receiver, name);
86+
return callNode.executeObject(frame, callable, receiver, arguments[0]);
87+
}
88+
89+
@Specialization(guards = "arguments.length == 2")
90+
static Object callTernary(Frame frame, Object receiver, String name, Object[] arguments,
91+
@Shared("getMethod") @Cached PyObjectGetMethod getMethod,
92+
@Cached CallTernaryMethodNode callNode) {
93+
Object callable = getMethod.execute(frame, receiver, name);
94+
return callNode.execute(frame, callable, receiver, arguments[0], arguments[1]);
95+
}
96+
97+
@Specialization(guards = "arguments.length == 3")
98+
static Object callQuad(Frame frame, Object receiver, String name, Object[] arguments,
99+
@Shared("getMethod") @Cached PyObjectGetMethod getMethod,
100+
@Cached CallQuaternaryMethodNode callNode) {
101+
Object callable = getMethod.execute(frame, receiver, name);
102+
return callNode.execute(frame, callable, receiver, arguments[0], arguments[1], arguments[2]);
103+
}
104+
105+
@Specialization(replaces = {"callUnary", "callBinary", "callTernary", "callQuad"})
106+
static Object call(Frame frame, Object receiver, String name, Object[] arguments,
107+
@Shared("getMethod") @Cached PyObjectGetMethod getMethod,
108+
@Cached CallNode callNode,
109+
@Cached ConditionProfile isBoundProfile) {
110+
Object callable = getMethod.execute(frame, receiver, name);
111+
if (isBoundProfile.profile(callable instanceof BoundDescriptor)) {
112+
return callNode.execute(frame, ((BoundDescriptor) callable).descriptor, arguments, PKeyword.EMPTY_KEYWORDS);
113+
} else {
114+
Object[] unboundArguments = new Object[arguments.length + 1];
115+
unboundArguments[0] = receiver;
116+
PythonUtils.arraycopy(arguments, 0, unboundArguments, 1, arguments.length);
117+
return callNode.execute(frame, callable, arguments, PKeyword.EMPTY_KEYWORDS);
118+
}
119+
}
120+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2021, 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.lib;
42+
43+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
44+
import com.oracle.graal.python.builtins.objects.PNone;
45+
import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot;
46+
import com.oracle.graal.python.nodes.attributes.GetAttributeNode.GetFixedAttributeNode;
47+
import com.oracle.graal.python.nodes.call.special.CallBinaryMethodNode;
48+
import com.oracle.graal.python.nodes.call.special.LookupSpecialMethodSlotNode;
49+
import com.oracle.graal.python.nodes.object.GetClassNode;
50+
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
51+
import com.oracle.graal.python.runtime.exception.PException;
52+
import com.oracle.truffle.api.dsl.Cached;
53+
import com.oracle.truffle.api.dsl.GenerateUncached;
54+
import com.oracle.truffle.api.dsl.ImportStatic;
55+
import com.oracle.truffle.api.dsl.Specialization;
56+
import com.oracle.truffle.api.frame.Frame;
57+
import com.oracle.truffle.api.frame.VirtualFrame;
58+
import com.oracle.truffle.api.nodes.Node;
59+
60+
/**
61+
* Equivalent PyObject_GetAttr*. Like Python, this method raises when the attribute doesn't exist.
62+
*/
63+
@GenerateUncached
64+
@ImportStatic(SpecialMethodSlot.class)
65+
public abstract class PyObjectGetAttr extends Node {
66+
public abstract Object execute(Frame frame, Object receiver, Object name);
67+
68+
@Specialization(guards = "name == cachedName", limit = "1")
69+
static Object getFixedAttr(VirtualFrame frame, Object receiver, @SuppressWarnings("unused") String name,
70+
@SuppressWarnings("unused") @Cached("name") String cachedName,
71+
@Cached("create(name)") GetFixedAttributeNode getAttrNode) {
72+
return getAttrNode.execute(frame, receiver);
73+
}
74+
75+
@Specialization(replaces = "getFixedAttr")
76+
static Object getDynamicAttr(Frame frame, Object receiver, Object name,
77+
@Cached GetClassNode getClass,
78+
@Cached(parameters = "GetAttribute") LookupSpecialMethodSlotNode lookupGetattribute,
79+
@Cached(parameters = "GetAttr") LookupSpecialMethodSlotNode lookupGetattr,
80+
@Cached CallBinaryMethodNode callGetattribute,
81+
@Cached CallBinaryMethodNode callGetattr,
82+
@Cached IsBuiltinClassProfile errorProfile) {
83+
Object type = getClass.execute(receiver);
84+
Object getattribute = lookupGetattribute.execute(frame, type, receiver);
85+
try {
86+
return callGetattribute.executeObject(frame, getattribute, receiver, name);
87+
} catch (PException e) {
88+
e.expect(PythonBuiltinClassType.AttributeError, errorProfile);
89+
Object getattr = lookupGetattr.execute(frame, type, receiver);
90+
if (getattr != PNone.NO_VALUE) {
91+
return callGetattr.executeObject(frame, getattr, name);
92+
} else {
93+
throw e;
94+
}
95+
}
96+
}
97+
}

0 commit comments

Comments
 (0)