Skip to content

Commit 17ba95e

Browse files
committed
[GR-12483] Intrinsify globals, locals, and exec
PullRequest: graalpython/270
2 parents 1c05c9a + a162f3b commit 17ba95e

File tree

10 files changed

+117
-38
lines changed

10 files changed

+117
-38
lines changed

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

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import static com.oracle.graal.python.nodes.BuiltinNames.DIR;
3737
import static com.oracle.graal.python.nodes.BuiltinNames.DIVMOD;
3838
import static com.oracle.graal.python.nodes.BuiltinNames.EVAL;
39+
import static com.oracle.graal.python.nodes.BuiltinNames.EXEC;
3940
import static com.oracle.graal.python.nodes.BuiltinNames.GETATTR;
4041
import static com.oracle.graal.python.nodes.BuiltinNames.HASH;
4142
import static com.oracle.graal.python.nodes.BuiltinNames.ID;
@@ -96,6 +97,7 @@
9697
import com.oracle.graal.python.builtins.objects.common.SequenceNodes;
9798
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
9899
import com.oracle.graal.python.builtins.objects.dict.PDict;
100+
import com.oracle.graal.python.builtins.objects.frame.PFrame;
99101
import com.oracle.graal.python.builtins.objects.function.Arity;
100102
import com.oracle.graal.python.builtins.objects.function.PArguments;
101103
import com.oracle.graal.python.builtins.objects.function.PFunction;
@@ -172,6 +174,7 @@
172174
import com.oracle.truffle.api.frame.FrameSlot;
173175
import com.oracle.truffle.api.frame.VirtualFrame;
174176
import com.oracle.truffle.api.nodes.ExplodeLoop;
177+
import com.oracle.truffle.api.nodes.IndirectCallNode;
175178
import com.oracle.truffle.api.nodes.Node;
176179
import com.oracle.truffle.api.nodes.NodeUtil;
177180
import com.oracle.truffle.api.nodes.NodeVisitor;
@@ -595,31 +598,61 @@ private static Object evalNode(RootCallTarget callTarget, PythonObject globals,
595598
}
596599
}
597600

601+
@Builtin(name = EXEC, fixedNumOfPositionalArgs = 1, parameterNames = {"source"}, keywordArguments = {"globals", "locals"})
602+
@GenerateNodeFactory
603+
abstract static class ExecNode extends PythonBuiltinNode {
604+
@Child CompileNode compileNode = CompileNode.create();
605+
@Child IndirectCallNode indirectCallNode = IndirectCallNode.create();
606+
607+
@Specialization(guards = {"isNoValue(globals)", "isNoValue(locals)"})
608+
PNone execDefault(VirtualFrame frame, Object source, @SuppressWarnings("unused") PNone globals, @SuppressWarnings("unused") PNone locals,
609+
@Cached("create()") ReadCallerFrameNode readCallerFrameNode) {
610+
PCode code = compileNode.execute(source, "exec", "exec", 0, false, -1);
611+
Frame callerFrame = readCallerFrameNode.executeWith(frame);
612+
Object[] args = PArguments.create();
613+
PArguments.setGlobals(args, PArguments.getGlobals(callerFrame));
614+
PArguments.setClosure(args, PArguments.getClosure(callerFrame));
615+
indirectCallNode.call(code.getRootCallTarget(), args);
616+
return PNone.NO_VALUE;
617+
}
618+
619+
@Specialization(guards = {"isNoValue(locals)"})
620+
PNone execDefault(Object source, PDict globals, @SuppressWarnings("unused") PNone locals) {
621+
PCode code = compileNode.execute(source, "exec", "exec", 0, false, -1);
622+
Object[] args = PArguments.create();
623+
PArguments.setGlobals(args, globals);
624+
// If locals are not given, they default to the globals, so we don't need the caller
625+
// frame's closure at all
626+
indirectCallNode.call(code.getRootCallTarget(), args);
627+
return PNone.NO_VALUE;
628+
}
629+
}
630+
598631
// compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
599632
@Builtin(name = COMPILE, fixedNumOfPositionalArgs = 3, keywordArguments = {"flags", "dont_inherit", "optimize"})
600633
@GenerateNodeFactory
601634
@TypeSystemReference(PythonArithmeticTypes.class)
602635
public abstract static class CompileNode extends PythonBuiltinNode {
603636

604-
public abstract Object execute(Object source, String filename, String mode, Object kwFlags, Object kwDontInherit, Object kwOptimize);
637+
public abstract PCode execute(Object source, String filename, String mode, Object kwFlags, Object kwDontInherit, Object kwOptimize);
605638

606639
@Specialization
607640
@TruffleBoundary
608-
Object compile(PBytes source, String filename, String mode, Object kwFlags, Object kwDontInherit, Object kwOptimize,
641+
PCode compile(PBytes source, String filename, String mode, Object kwFlags, Object kwDontInherit, Object kwOptimize,
609642
@Cached("create()") BytesNodes.ToBytesNode toBytesNode) {
610643
return compile(new String(toBytesNode.execute(source)), filename, mode, kwFlags, kwDontInherit, kwOptimize);
611644
}
612645

613646
@Specialization
614647
@TruffleBoundary
615-
Object compile(OpaqueBytes source, String filename, String mode, Object kwFlags, Object kwDontInherit, Object kwOptimize) {
648+
PCode compile(OpaqueBytes source, String filename, String mode, Object kwFlags, Object kwDontInherit, Object kwOptimize) {
616649
return compile(new String(source.getBytes()), filename, mode, kwFlags, kwDontInherit, kwOptimize);
617650
}
618651

619652
@SuppressWarnings("unused")
620653
@Specialization
621654
@TruffleBoundary
622-
Object compile(String expression, String filename, String mode, Object kwFlags, Object kwDontInherit, Object kwOptimize) {
655+
PCode compile(String expression, String filename, String mode, Object kwFlags, Object kwDontInherit, Object kwOptimize) {
623656
Source source = PythonLanguage.newSource(getContext(), expression, filename);
624657
ParserMode pm;
625658
if (mode.equals("exec")) {
@@ -641,7 +674,7 @@ Object compile(String expression, String filename, String mode, Object kwFlags,
641674

642675
@SuppressWarnings("unused")
643676
@Specialization
644-
Object compile(PCode code, String filename, String mode, Object flags, Object dontInherit, Object optimize) {
677+
PCode compile(PCode code, String filename, String mode, Object flags, Object dontInherit, Object optimize) {
645678
return code;
646679
}
647680

@@ -1587,4 +1620,40 @@ String inputPrompt(String prompt) {
15871620
return input(null);
15881621
}
15891622
}
1623+
1624+
@Builtin(name = "globals", fixedNumOfPositionalArgs = 0)
1625+
@GenerateNodeFactory
1626+
abstract static class GlobalsNode extends PythonBuiltinNode {
1627+
@Child ReadCallerFrameNode readCallerFrameNode = ReadCallerFrameNode.create();
1628+
private final ConditionProfile condProfile = ConditionProfile.createBinaryProfile();
1629+
1630+
@Specialization
1631+
public Object globals(VirtualFrame frame) {
1632+
Frame callerFrame = readCallerFrameNode.executeWith(frame);
1633+
PythonObject globals = PArguments.getGlobals(callerFrame);
1634+
if (condProfile.profile(globals instanceof PythonModule)) {
1635+
return factory().createDictFixedStorage(globals);
1636+
} else {
1637+
return globals;
1638+
}
1639+
}
1640+
}
1641+
1642+
@Builtin(name = "locals", fixedNumOfPositionalArgs = 0)
1643+
@GenerateNodeFactory
1644+
abstract static class LocalsNode extends PythonBuiltinNode {
1645+
@Child ReadCallerFrameNode readCallerFrameNode = ReadCallerFrameNode.create();
1646+
private final ConditionProfile condProfile = ConditionProfile.createBinaryProfile();
1647+
1648+
@Specialization
1649+
public Object locals(VirtualFrame frame) {
1650+
Frame callerFrame = readCallerFrameNode.executeWith(frame);
1651+
PFrame pFrame = PArguments.getPFrame(callerFrame);
1652+
if (condProfile.profile(pFrame == null)) {
1653+
pFrame = factory().createPFrame(callerFrame);
1654+
PArguments.setPFrame(callerFrame, pFrame);
1655+
}
1656+
return pFrame.getLocals(factory());
1657+
}
1658+
}
15901659
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,6 +1846,7 @@ abstract static class MakeMayRaiseWrapperNode extends PythonBuiltinNode {
18461846
private static final Builtin varargsBuiltin = MayRaiseNode.class.getAnnotation(Builtin.class);
18471847

18481848
@Specialization
1849+
@TruffleBoundary
18491850
Object make(PFunction func, Object errorResult) {
18501851
CompilerDirectives.transferToInterpreter();
18511852
func.getFunctionRootNode().accept(new NodeVisitor() {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/PBaseException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ public PFrame getPFrame(PythonObjectFactory factory, int index) {
209209
if (frame != null) {
210210
// we have a frame, try to get the pFrame from the magic arguments first
211211
pFrame = PArguments.getPFrame(frame);
212-
if (pFrame == null) {
212+
if (pFrame == null || pFrame.isIncomplete()) {
213213
pFrame = factory.createPFrame(this, index);
214214
PArguments.setPFrame(frame, pFrame);
215215
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/PFrame.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ public final class PFrame extends PythonBuiltinObject {
6767
private final Node location;
6868
private int line = -2;
6969

70+
public PFrame(LazyPythonClass cls, Frame frame) {
71+
super(cls);
72+
this.exception = null;
73+
this.index = -1;
74+
this.frame = frame;
75+
this.location = null;
76+
this.inClassScope = PArguments.getSpecialArgument(frame) instanceof ClassBodyRootNode;
77+
}
78+
7079
public PFrame(LazyPythonClass cls, PBaseException exception, int index) {
7180
super(cls);
7281
this.exception = exception;
@@ -145,4 +154,13 @@ public PDict getLocals(PythonObjectFactory factory) {
145154
}
146155
return factory.createDict();
147156
}
157+
158+
/**
159+
* Checks if this frame is complete in the sense that all frame accessors would work, e.g.
160+
* locals, backref etc. We optimize locals access to create a lightweight PFrame that has no
161+
* stack attached to it, which is where we check this.
162+
*/
163+
public boolean isIncomplete() {
164+
return location == null;
165+
}
148166
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/zipimporter/ZipImporterBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ public PCode doit(PZipImporter self, String fullname,
284284
if (canNotFind.profile(md == null)) {
285285
throw raise(PythonErrorType.ZipImportError, " can't find module '%s'", fullname);
286286
}
287-
PCode code = (PCode) compileNode.execute(md.code, md.path, "exec", 0, false, -1);
287+
PCode code = compileNode.execute(md.code, md.path, "exec", 0, false, -1);
288288
return code;
289289
}
290290

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import com.oracle.graal.python.nodes.PRootNode;
4343
import com.oracle.graal.python.nodes.argument.ApplyKeywordsNode;
4444
import com.oracle.graal.python.nodes.argument.ArityCheckNode;
45+
import com.oracle.graal.python.nodes.function.ClassBodyRootNode;
4546
import com.oracle.graal.python.runtime.PythonOptions;
4647
import com.oracle.truffle.api.CallTarget;
4748
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -60,6 +61,7 @@
6061
abstract class AbstractInvokeNode extends Node {
6162

6263
private final ConditionProfile needsFrameProfile = ConditionProfile.createBinaryProfile();
64+
private final ConditionProfile isClassBodyProfile = ConditionProfile.createBinaryProfile();
6365

6466
protected static boolean shouldInlineGenerators() {
6567
return PythonOptions.getOption(PythonLanguage.getContextRef().get(), PythonOptions.ForceInlineGeneratorCalls);
@@ -101,6 +103,13 @@ protected final MaterializedFrame getCallerFrame(VirtualFrame frame, CallTarget
101103
return null;
102104
}
103105

106+
protected final void optionallySetClassBodySpecial(Object[] arguments, CallTarget callTarget) {
107+
RootNode rootNode = ((RootCallTarget) callTarget).getRootNode();
108+
if (isClassBodyProfile.profile(rootNode instanceof ClassBodyRootNode)) {
109+
PArguments.setSpecialArgument(arguments, rootNode);
110+
}
111+
}
112+
104113
@TruffleBoundary
105114
protected static Arity getArity(PythonCallable callee) {
106115
if (callee instanceof PythonBuiltinClass) {
@@ -128,6 +137,7 @@ protected Object execute(VirtualFrame frame, PythonCallable callee, Object[] arg
128137
RootCallTarget callTarget = getCallTarget(callee);
129138
MaterializedFrame callerFrame = getCallerFrame(frame, callTarget);
130139
PArguments.setCallerFrame(arguments, callerFrame);
140+
optionallySetClassBodySpecial(arguments, callTarget);
131141
Arity arity = getArity(callee);
132142
if (isBuiltin(callee)) {
133143
PArguments.setKeywordArguments(arguments, keywords);
@@ -175,6 +185,7 @@ protected Object doNoKeywords(VirtualFrame frame, PythonObject globals, PCell[]
175185
PArguments.setGlobals(arguments, globals);
176186
PArguments.setClosure(arguments, closure);
177187
PArguments.setCallerFrame(arguments, getCallerFrame(frame, callNode.getCallTarget()));
188+
optionallySetClassBodySpecial(arguments, callNode.getCallTarget());
178189
arityCheck.execute(arity, arguments, keywords);
179190
return callNode.call(arguments);
180191
}
@@ -186,6 +197,7 @@ protected Object doWithKeywords(VirtualFrame frame, PythonObject globals, PCell[
186197
PArguments.setGlobals(combined, globals);
187198
PArguments.setClosure(combined, closure);
188199
PArguments.setCallerFrame(arguments, getCallerFrame(frame, callNode.getCallTarget()));
200+
optionallySetClassBodySpecial(arguments, callNode.getCallTarget());
189201
arityCheck.execute(arity, combined, PArguments.getKeywordArguments(combined));
190202
return callNode.call(combined);
191203
}
@@ -195,6 +207,7 @@ protected Object doBuiltinWithKeywords(VirtualFrame frame, @SuppressWarnings("un
195207
PKeyword[] keywords) {
196208
PArguments.setKeywordArguments(arguments, keywords);
197209
PArguments.setCallerFrame(arguments, getCallerFrame(frame, callNode.getCallTarget()));
210+
optionallySetClassBodySpecial(arguments, callNode.getCallTarget());
198211
arityCheck.execute(arity, arguments, keywords);
199212
return callNode.call(arguments);
200213
}
@@ -236,6 +249,7 @@ protected Object doNoKeywords(VirtualFrame frame, Object[] arguments, PKeyword[]
236249
PArguments.setGlobals(arguments, globals);
237250
PArguments.setClosure(arguments, closure);
238251
PArguments.setCallerFrame(arguments, getCallerFrame(frame, callNode.getCallTarget()));
252+
optionallySetClassBodySpecial(arguments, callNode.getCallTarget());
239253
arityCheck.execute(arity, arguments, keywords);
240254
return callNode.call(arguments);
241255
}
@@ -247,6 +261,7 @@ protected Object doWithKeywords(VirtualFrame frame, Object[] arguments, PKeyword
247261
PArguments.setGlobals(combined, globals);
248262
PArguments.setClosure(combined, closure);
249263
PArguments.setCallerFrame(arguments, getCallerFrame(frame, callNode.getCallTarget()));
264+
optionallySetClassBodySpecial(arguments, callNode.getCallTarget());
250265
arityCheck.execute(arity, combined, PArguments.getKeywordArguments(combined));
251266
return callNode.call(combined);
252267
}
@@ -255,6 +270,7 @@ protected Object doWithKeywords(VirtualFrame frame, Object[] arguments, PKeyword
255270
protected Object doBuiltinWithKeywords(VirtualFrame frame, Object[] arguments, PKeyword[] keywords) {
256271
PArguments.setKeywordArguments(arguments, keywords);
257272
PArguments.setCallerFrame(arguments, getCallerFrame(frame, callNode.getCallTarget()));
273+
optionallySetClassBodySpecial(arguments, callNode.getCallTarget());
258274
arityCheck.execute(arity, arguments, keywords);
259275
return callNode.call(arguments);
260276
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/parser/PythonTreeTranslator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ private ExpressionNode createComprehensionExpression(ParserRuleContext ctx, Pyth
487487

488488
private GeneratorExpressionNode createGeneratorExpressionDefinition(ExpressionNode body, int lineNum) {
489489
FrameDescriptor fd = environment.getCurrentFrame();
490-
String generatorName = "generator_exp:" + lineNum;
490+
String generatorName = source.getName() + ":generator_exp:" + lineNum;
491491
FunctionRootNode funcRoot = factory.createFunctionRoot(body.getSourceSection(), generatorName, true, fd, body, environment.getExecutionCellSlots());
492492
GeneratorTranslator gtran = new GeneratorTranslator(funcRoot, true);
493493
RootCallTarget callTarget = gtran.translate();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/object/PythonObjectFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,10 @@ public PReferenceType createReferenceType(PythonObject object, PFunction callbac
541541
* Frames, traces and exceptions
542542
*/
543543

544+
public PFrame createPFrame(Frame frame) {
545+
return trace(new PFrame(PythonBuiltinClassType.PFrame, frame));
546+
}
547+
544548
public PFrame createPFrame(PBaseException exception, int index) {
545549
return trace(new PFrame(PythonBuiltinClassType.PFrame, exception, index));
546550
}

graalpython/lib-graalpython/builtins.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def __import__(filename, module_name):
5151
content = posix.read(fd, sys.maxsize)
5252
posix.close(fd)
5353
code = compile(content, filename, "exec")
54-
eval(code, module.__dict__)
54+
exec(code, module.__dict__)
5555
return module
5656

5757

graalpython/lib-graalpython/functions.py

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -68,29 +68,6 @@ def print_f(*objects, sep=" ", end="\n", file=None, flush=False):
6868
del make_print
6969

7070

71-
# We close over the globals to avoid leaking sys to the builtins scope
72-
def make_globals_function():
73-
import sys
74-
75-
def globals_f():
76-
return sys._getframe(1).f_globals
77-
globals_f.__name__ = "globals"
78-
return globals_f
79-
globals = __builtin__(make_globals_function())
80-
del make_globals_function
81-
82-
83-
def make_locals_function():
84-
import sys
85-
86-
def locals_f():
87-
return sys._getframe(1).f_locals
88-
locals_f.__name__ = "locals"
89-
return locals_f
90-
locals = __builtin__(make_locals_function())
91-
del make_locals_function
92-
93-
9471
@__builtin__
9572
def any(iterable):
9673
for i in iterable:
@@ -117,12 +94,6 @@ def filter(func, iterable):
11794
return tuple(result)
11895

11996

120-
@__builtin__
121-
def exec(source, globals=None, locals=None):
122-
# compile returns the source if already a code object
123-
return eval(compile(source, "<exec>", "exec"), globals, locals)
124-
125-
12697
# This is re-defined later during bootstrap in classes.py
12798
def __build_class__(func, name, *bases, metaclass=None, **kwargs):
12899
"""

0 commit comments

Comments
 (0)