Skip to content

Commit bd4ef72

Browse files
committed
[GR-20184] add builtin truffle_co_globals Code object attribute (returns a tuple of the global variable names referenced by the code object)
PullRequest: graalpython/763
2 parents fad312f + 95e3eba commit bd4ef72

File tree

5 files changed

+151
-3
lines changed

5 files changed

+151
-3
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ def a_function():
4444

4545
def wrapper():
4646
values = []
47+
global a_global
48+
49+
a_global = set([11, 12])
4750

4851
def my_func(arg_l, kwarg_case="empty set", kwarg_other=19):
4952
loc_1 = set(values)
@@ -64,6 +67,9 @@ def inner_func():
6467
return my_func
6568

6669

70+
a_global = 10
71+
72+
6773
def test_name():
6874
assert a_function.__code__.co_name == "a_function"
6975

@@ -94,7 +100,7 @@ def test_code_attributes():
94100
assert set(code.co_varnames) == {'arg_l', 'kwarg_case', 'kwarg_other', 'loc_1', 'loc_3', 'inner_func'}
95101
assert code.co_filename.endswith("test_code.py")
96102
assert code.co_name == "my_func"
97-
assert code.co_firstlineno == 48
103+
assert code.co_firstlineno == 51
98104
# assert code.co_lnotab == b'\x00\x01\x0c\x01\x0c\x01\x06\x02\x15\x03\x03\x01\x0e\x01\r\x01\x05\x02'
99105
assert set(code.co_freevars) == {'values'}
100106
assert set(code.co_cellvars) == {'kwarg_other', 'loc_2'}
@@ -161,3 +167,11 @@ def test_module_code():
161167
# assert code.co_lnotab == b''
162168
assert code.co_freevars == tuple()
163169
assert code.co_cellvars == tuple()
170+
171+
172+
def test_get_globals():
173+
import sys
174+
code = wrapper.__code__
175+
if sys.implementation.name == 'graalpython':
176+
from __graalpython__ import current_global_code_variables
177+
assert set(current_global_code_variables(code)) == {'a_global'}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import com.oracle.graal.python.builtins.modules.FcntlModuleBuiltins;
5757
import com.oracle.graal.python.builtins.modules.FunctoolsModuleBuiltins;
5858
import com.oracle.graal.python.builtins.modules.GcModuleBuiltins;
59+
import com.oracle.graal.python.builtins.modules.GraalPythonModuleBuiltins;
5960
import com.oracle.graal.python.builtins.modules.IOModuleBuiltins;
6061
import com.oracle.graal.python.builtins.modules.ImpModuleBuiltins;
6162
import com.oracle.graal.python.builtins.modules.ItertoolsModuleBuiltins;
@@ -371,7 +372,8 @@ private static final PythonBuiltins[] initializeBuiltins() {
371372
new LZMAModuleBuiltins(),
372373
new LZMACompressorBuiltins(),
373374
new LZMADecompressorBuiltins(),
374-
new MultiprocessingModuleBuiltins()));
375+
new MultiprocessingModuleBuiltins(),
376+
new GraalPythonModuleBuiltins()));
375377
if (!TruffleOptions.AOT) {
376378
ServiceLoader<PythonBuiltins> providers = ServiceLoader.load(PythonBuiltins.class, Python3Core.class.getClassLoader());
377379
for (PythonBuiltins builtin : providers) {

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
8888
import com.oracle.graal.python.builtins.PythonBuiltins;
8989
import com.oracle.graal.python.builtins.modules.BuiltinFunctionsFactory.GetAttrNodeFactory;
90+
import com.oracle.graal.python.builtins.modules.BuiltinFunctionsFactory.GlobalsNodeFactory;
9091
import com.oracle.graal.python.builtins.objects.PNone;
9192
import com.oracle.graal.python.builtins.objects.PNotImplemented;
9293
import com.oracle.graal.python.builtins.objects.bytes.BytesNodes;
@@ -1905,7 +1906,7 @@ String inputPrompt(String prompt) {
19051906

19061907
@Builtin(name = "globals", minNumOfPositionalArgs = 0)
19071908
@GenerateNodeFactory
1908-
abstract static class GlobalsNode extends PythonBuiltinNode {
1909+
public abstract static class GlobalsNode extends PythonBuiltinNode {
19091910
@Child private ReadCallerFrameNode readCallerFrameNode = ReadCallerFrameNode.create();
19101911

19111912
private final ConditionProfile condProfile = ConditionProfile.createBinaryProfile();
@@ -1932,6 +1933,10 @@ public Object globals(VirtualFrame frame,
19321933
return globals;
19331934
}
19341935
}
1936+
1937+
public static GlobalsNode create() {
1938+
return GlobalsNodeFactory.create(null);
1939+
}
19351940
}
19361941

19371942
@Builtin(name = "locals", minNumOfPositionalArgs = 0)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (c) 2019, 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.builtins.modules;
42+
43+
import java.util.Arrays;
44+
import java.util.List;
45+
46+
import com.oracle.graal.python.builtins.Builtin;
47+
import com.oracle.graal.python.builtins.CoreFunctions;
48+
import com.oracle.graal.python.builtins.PythonBuiltins;
49+
import com.oracle.graal.python.builtins.modules.BuiltinFunctions.GlobalsNode;
50+
import com.oracle.graal.python.builtins.objects.code.PCode;
51+
import com.oracle.graal.python.nodes.SpecialMethodNames;
52+
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
53+
import com.oracle.graal.python.nodes.expression.CastToBooleanNode;
54+
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
55+
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
56+
import com.oracle.truffle.api.dsl.Cached;
57+
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
58+
import com.oracle.truffle.api.dsl.ImportStatic;
59+
import com.oracle.truffle.api.dsl.NodeFactory;
60+
import com.oracle.truffle.api.dsl.Specialization;
61+
import com.oracle.truffle.api.frame.VirtualFrame;
62+
63+
@CoreFunctions(defineModule = "__graalpython__")
64+
public class GraalPythonModuleBuiltins extends PythonBuiltins {
65+
@Override
66+
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
67+
return GraalPythonModuleBuiltinsFactory.getFactories();
68+
}
69+
70+
@Builtin(name = "current_global_code_variables", minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 1)
71+
@GenerateNodeFactory
72+
@ImportStatic(SpecialMethodNames.class)
73+
abstract static class GetCodeGlobalVarsNode extends PythonUnaryBuiltinNode {
74+
@Specialization
75+
protected Object get(VirtualFrame frame, PCode code,
76+
@Cached GlobalsNode globalsNode,
77+
@Cached("createIfTrueNode()") CastToBooleanNode isTrue,
78+
@Cached("create(__CONTAINS__)") LookupAndCallBinaryNode containsNode) {
79+
Object[] varNames = code.getGlobalAndBuiltinVarNames();
80+
if (varNames != null) {
81+
int i = 0;
82+
Object[] globalNames = new Object[varNames.length];
83+
Object globals = globalsNode.execute(frame);
84+
for (Object name : varNames) {
85+
if (isTrue.executeBoolean(frame, containsNode.executeObject(frame, globals, name))) {
86+
globalNames[i++] = name;
87+
}
88+
}
89+
return factory().createTuple(Arrays.copyOf(globalNames, i));
90+
}
91+
return factory().createEmptyTuple();
92+
}
93+
}
94+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/code/PCode.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.util.ArrayList;
4444
import java.util.Arrays;
4545
import java.util.HashSet;
46+
import java.util.List;
4647
import java.util.Set;
4748

4849
import com.oracle.graal.python.PythonLanguage;
@@ -53,7 +54,11 @@
5354
import com.oracle.graal.python.nodes.PRootNode;
5455
import com.oracle.graal.python.nodes.argument.ReadVarArgsNode;
5556
import com.oracle.graal.python.nodes.argument.ReadVarKeywordsNode;
57+
import com.oracle.graal.python.nodes.frame.DeleteGlobalNode;
5658
import com.oracle.graal.python.nodes.frame.FrameSlotIDs;
59+
import com.oracle.graal.python.nodes.frame.GlobalNode;
60+
import com.oracle.graal.python.nodes.frame.ReadGlobalOrBuiltinNode;
61+
import com.oracle.graal.python.nodes.frame.WriteGlobalNode;
5762
import com.oracle.graal.python.nodes.function.FunctionRootNode;
5863
import com.oracle.graal.python.nodes.generator.GeneratorFunctionRootNode;
5964
import com.oracle.truffle.api.CompilerDirectives;
@@ -104,6 +109,8 @@ public final class PCode extends PythonBuiltinObject {
104109
private Object[] freevars;
105110
// tuple of names of cell variables (referenced by containing scopes)
106111
private Object[] cellvars;
112+
// is a tuple containing the names of the global variables accessed from this code object
113+
private Object[] globalAndBuiltinVarNames;
107114

108115
public PCode(LazyPythonClass cls, RootCallTarget callTarget) {
109116
super(cls);
@@ -242,6 +249,25 @@ private static Object[] extractVarnames(RootNode rootNode, String[] parameterIds
242249
return varNameList.toArray();
243250
}
244251

252+
@TruffleBoundary
253+
private static Object[] extractGlobalAndBuiltinVarnames(RootNode rootNode) {
254+
RootNode funcRootNode = (rootNode instanceof GeneratorFunctionRootNode) ? ((GeneratorFunctionRootNode) rootNode).getFunctionRootNode() : rootNode;
255+
Set<Object> varNameList = new HashSet<>();
256+
257+
List<GlobalNode> globalNodes = NodeUtil.findAllNodeInstances(funcRootNode, GlobalNode.class);
258+
for (GlobalNode node : globalNodes) {
259+
if (node instanceof ReadGlobalOrBuiltinNode) {
260+
varNameList.add(((ReadGlobalOrBuiltinNode) node).getAttributeId());
261+
} else if (node instanceof WriteGlobalNode) {
262+
varNameList.add(((WriteGlobalNode) node).getAttributeId());
263+
} else if (node instanceof DeleteGlobalNode) {
264+
varNameList.add(((DeleteGlobalNode) node).getAttributeId());
265+
}
266+
}
267+
268+
return varNameList.toArray();
269+
}
270+
245271
@TruffleBoundary
246272
private static int extractFlags(RootNode rootNode) {
247273
int flags = 0;
@@ -371,6 +397,13 @@ public byte[] getCodestring() {
371397
return codestring;
372398
}
373399

400+
public Object[] getGlobalAndBuiltinVarNames() {
401+
if (globalAndBuiltinVarNames == null) {
402+
this.globalAndBuiltinVarNames = extractGlobalAndBuiltinVarnames(getRootNode());
403+
}
404+
return globalAndBuiltinVarNames;
405+
}
406+
374407
public Object[] getConstants() {
375408
return constants;
376409
}

0 commit comments

Comments
 (0)