Skip to content

Commit dce02a0

Browse files
committed
intrinsify exec() to avoid caller frame lookup in the common case
1 parent 31a301d commit dce02a0

File tree

2 files changed

+37
-11
lines changed

2 files changed

+37
-11
lines changed

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

Lines changed: 37 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;
@@ -173,6 +174,7 @@
173174
import com.oracle.truffle.api.frame.FrameSlot;
174175
import com.oracle.truffle.api.frame.VirtualFrame;
175176
import com.oracle.truffle.api.nodes.ExplodeLoop;
177+
import com.oracle.truffle.api.nodes.IndirectCallNode;
176178
import com.oracle.truffle.api.nodes.Node;
177179
import com.oracle.truffle.api.nodes.NodeUtil;
178180
import com.oracle.truffle.api.nodes.NodeVisitor;
@@ -596,31 +598,61 @@ private static Object evalNode(RootCallTarget callTarget, PythonObject globals,
596598
}
597599
}
598600

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+
599631
// compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
600632
@Builtin(name = COMPILE, fixedNumOfPositionalArgs = 3, keywordArguments = {"flags", "dont_inherit", "optimize"})
601633
@GenerateNodeFactory
602634
@TypeSystemReference(PythonArithmeticTypes.class)
603635
public abstract static class CompileNode extends PythonBuiltinNode {
604636

605-
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);
606638

607639
@Specialization
608640
@TruffleBoundary
609-
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,
610642
@Cached("create()") BytesNodes.ToBytesNode toBytesNode) {
611643
return compile(new String(toBytesNode.execute(source)), filename, mode, kwFlags, kwDontInherit, kwOptimize);
612644
}
613645

614646
@Specialization
615647
@TruffleBoundary
616-
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) {
617649
return compile(new String(source.getBytes()), filename, mode, kwFlags, kwDontInherit, kwOptimize);
618650
}
619651

620652
@SuppressWarnings("unused")
621653
@Specialization
622654
@TruffleBoundary
623-
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) {
624656
Source source = PythonLanguage.newSource(getContext(), expression, filename);
625657
ParserMode pm;
626658
if (mode.equals("exec")) {
@@ -642,7 +674,7 @@ Object compile(String expression, String filename, String mode, Object kwFlags,
642674

643675
@SuppressWarnings("unused")
644676
@Specialization
645-
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) {
646678
return code;
647679
}
648680

graalpython/lib-graalpython/functions.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,6 @@ def filter(func, iterable):
9494
return tuple(result)
9595

9696

97-
@__builtin__
98-
def exec(source, globals=None, locals=None):
99-
# compile returns the source if already a code object
100-
return eval(compile(source, "<exec>", "exec"), globals, locals)
101-
102-
10397
# This is re-defined later during bootstrap in classes.py
10498
def __build_class__(func, name, *bases, metaclass=None, **kwargs):
10599
"""

0 commit comments

Comments
 (0)