|
89 | 89 | import com.oracle.graal.python.builtins.objects.bytes.BytesNodes;
|
90 | 90 | import com.oracle.graal.python.builtins.objects.bytes.OpaqueBytes;
|
91 | 91 | import com.oracle.graal.python.builtins.objects.bytes.PBytes;
|
92 |
| -import com.oracle.graal.python.builtins.objects.bytes.PIBytesLike; |
93 |
| -import com.oracle.graal.python.builtins.objects.cell.PCell; |
94 | 92 | import com.oracle.graal.python.builtins.objects.code.PCode;
|
95 | 93 | import com.oracle.graal.python.builtins.objects.common.HashingCollectionNodes;
|
96 | 94 | import com.oracle.graal.python.builtins.objects.common.PHashingCollection;
|
|
123 | 121 | import com.oracle.graal.python.nodes.argument.ReadIndexedArgumentNode;
|
124 | 122 | import com.oracle.graal.python.nodes.argument.ReadVarArgsNode;
|
125 | 123 | import com.oracle.graal.python.nodes.attributes.DeleteAttributeNode;
|
| 124 | +import com.oracle.graal.python.nodes.attributes.HasInheritedAttributeNode; |
126 | 125 | import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode;
|
127 | 126 | import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
|
128 | 127 | import com.oracle.graal.python.nodes.attributes.SetAttributeNode;
|
|
136 | 135 | import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
|
137 | 136 | import com.oracle.graal.python.nodes.control.GetIteratorNode;
|
138 | 137 | import com.oracle.graal.python.nodes.control.GetNextNode;
|
139 |
| -import com.oracle.graal.python.nodes.datamodel.IsMappingNode; |
140 | 138 | import com.oracle.graal.python.nodes.expression.BinaryArithmetic;
|
141 | 139 | import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
|
142 | 140 | import com.oracle.graal.python.nodes.expression.CastToBooleanNode;
|
|
156 | 154 | import com.oracle.graal.python.runtime.PythonContext;
|
157 | 155 | import com.oracle.graal.python.runtime.PythonCore;
|
158 | 156 | import com.oracle.graal.python.runtime.PythonOptions;
|
159 |
| -import com.oracle.graal.python.runtime.PythonParser; |
160 | 157 | import com.oracle.graal.python.runtime.PythonParser.ParserMode;
|
161 | 158 | import com.oracle.graal.python.runtime.exception.PException;
|
162 | 159 | import com.oracle.graal.python.runtime.exception.PythonErrorType;
|
163 | 160 | import com.oracle.graal.python.runtime.sequence.PSequence;
|
164 | 161 | import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
|
165 | 162 | import com.oracle.truffle.api.CompilerDirectives;
|
166 | 163 | import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
167 |
| -import com.oracle.truffle.api.RootCallTarget; |
168 | 164 | import com.oracle.truffle.api.Truffle;
|
169 | 165 | import com.oracle.truffle.api.dsl.Cached;
|
170 | 166 | import com.oracle.truffle.api.dsl.Fallback;
|
|
184 | 180 | import com.oracle.truffle.api.nodes.UnexpectedResultException;
|
185 | 181 | import com.oracle.truffle.api.profiles.BranchProfile;
|
186 | 182 | import com.oracle.truffle.api.profiles.ConditionProfile;
|
187 |
| -import com.oracle.truffle.api.profiles.ValueProfile; |
188 | 183 | import com.oracle.truffle.api.source.Source;
|
189 | 184 |
|
190 | 185 | @CoreFunctions(defineModule = "builtins")
|
@@ -475,169 +470,46 @@ private static BigInteger[] divideAndRemainder(PInt a, PInt b) {
|
475 | 470 | @Builtin(name = EVAL, fixedNumOfPositionalArgs = 1, keywordArguments = {"globals", "locals"})
|
476 | 471 | @GenerateNodeFactory
|
477 | 472 | public abstract static class EvalNode extends PythonBuiltinNode {
|
478 |
| - @Child private GetItemNode getNameNode = GetItemNode.create(); |
479 |
| - @Child private ReadCallerFrameNode readCallerFrameNode = ReadCallerFrameNode.create(); |
480 |
| - @Child private SequenceStorageNodes.ToByteArrayNode toByteArrayNode; |
481 |
| - |
482 |
| - @Specialization |
483 |
| - public Object eval(VirtualFrame frame, String expression, @SuppressWarnings("unused") PNone globals, @SuppressWarnings("unused") PNone locals) { |
484 |
| - Frame callerFrame = readCallerFrameNode.executeWith(frame); |
485 |
| - PythonObject callerGlobals = PArguments.getGlobals(callerFrame); |
486 |
| - PCell[] callerClosure = PArguments.getClosure(callerFrame); |
487 |
| - return evalExpression(expression, callerGlobals, callerGlobals, callerClosure, callerFrame, "<string>"); |
488 |
| - } |
489 |
| - |
490 |
| - @Specialization |
491 |
| - public Object eval(VirtualFrame frame, String expression, PythonObject globals, @SuppressWarnings("unused") PNone locals) { |
492 |
| - Frame callerFrame = readCallerFrameNode.executeWith(frame); |
493 |
| - return evalExpression(expression, globals, globals, null, callerFrame, null); |
494 |
| - } |
495 |
| - |
496 |
| - @Specialization |
497 |
| - public Object eval(VirtualFrame frame, String expression, PythonObject globals, PythonObject locals) { |
498 |
| - Frame callerFrame = readCallerFrameNode.executeWith(frame); |
499 |
| - return evalExpression(expression, globals, locals, null, callerFrame, null); |
500 |
| - } |
501 |
| - |
502 |
| - @Specialization |
503 |
| - public Object eval(VirtualFrame frame, String expression, @SuppressWarnings("unused") PNone globals, PythonObject locals) { |
504 |
| - Frame callerFrame = readCallerFrameNode.executeWith(frame); |
505 |
| - PythonObject callerGlobals = PArguments.getGlobals(callerFrame); |
506 |
| - PCell[] callerClosure = PArguments.getClosure(callerFrame); |
507 |
| - return evalExpression(expression, callerGlobals, locals, callerClosure, callerFrame, null); |
508 |
| - } |
509 |
| - |
510 |
| - @Specialization |
511 |
| - public Object eval(VirtualFrame frame, PCode code, @SuppressWarnings("unused") PNone globals, @SuppressWarnings("unused") PNone locals, |
512 |
| - @Cached("createIdentityProfile()") ValueProfile constantCt) { |
513 |
| - Frame callerFrame = readCallerFrameNode.executeWith(frame); |
514 |
| - PythonObject callerGlobals = PArguments.getGlobals(callerFrame); |
515 |
| - PCell[] callerClosure = PArguments.getClosure(callerFrame); |
516 |
| - return evalExpression(constantCt.profile(code.getRootCallTarget()), callerGlobals, callerGlobals, callerClosure); |
517 |
| - } |
518 |
| - |
519 |
| - @Specialization |
520 |
| - public Object eval(VirtualFrame frame, PCode code, PythonObject globals, @SuppressWarnings("unused") PNone locals, |
521 |
| - @Cached("createIdentityProfile()") ValueProfile constantCt) { |
522 |
| - Frame callerFrame = readCallerFrameNode.executeWith(frame); |
523 |
| - PCell[] callerClosure = PArguments.getClosure(callerFrame); |
524 |
| - return evalExpression(constantCt.profile(code.getRootCallTarget()), globals, globals, callerClosure); |
525 |
| - } |
526 |
| - |
527 |
| - @Specialization |
528 |
| - public Object eval(VirtualFrame frame, PCode code, PythonObject globals, PythonObject locals, |
529 |
| - @Cached("createIdentityProfile()") ValueProfile constantCt) { |
530 |
| - Frame callerFrame = readCallerFrameNode.executeWith(frame); |
531 |
| - PCell[] callerClosure = PArguments.getClosure(callerFrame); |
532 |
| - return evalExpression(constantCt.profile(code.getRootCallTarget()), globals, locals, callerClosure); |
533 |
| - } |
534 |
| - |
535 |
| - @Specialization |
536 |
| - public Object eval(VirtualFrame frame, PCode code, @SuppressWarnings("unused") PNone globals, PythonObject locals, |
537 |
| - @Cached("createIdentityProfile()") ValueProfile constantCt) { |
538 |
| - Frame callerFrame = readCallerFrameNode.executeWith(frame); |
539 |
| - PythonObject callerGlobals = PArguments.getGlobals(callerFrame); |
540 |
| - PCell[] callerClosure = PArguments.getClosure(callerFrame); |
541 |
| - return evalExpression(constantCt.profile(code.getRootCallTarget()), callerGlobals, locals, callerClosure); |
542 |
| - } |
543 |
| - |
544 |
| - @Specialization |
545 |
| - public Object eval(VirtualFrame frame, PBytes expression, PNone globals, PNone locals) { |
546 |
| - return eval(frame, getString(expression), globals, locals); |
547 |
| - } |
548 |
| - |
549 |
| - @Specialization |
550 |
| - public Object eval(VirtualFrame frame, PBytes expression, PythonObject globals, PNone locals) { |
551 |
| - return eval(frame, getString(expression), globals, locals); |
552 |
| - } |
553 |
| - |
554 |
| - @Specialization |
555 |
| - public Object eval(VirtualFrame frame, PBytes expression, PythonObject globals, PythonObject locals) { |
556 |
| - return eval(frame, getString(expression), globals, locals); |
557 |
| - } |
558 |
| - |
559 |
| - @Specialization |
560 |
| - public Object eval(VirtualFrame frame, PBytes expression, PNone globals, PythonObject locals) { |
561 |
| - return eval(frame, getString(expression), globals, locals); |
562 |
| - } |
563 |
| - |
564 |
| - @TruffleBoundary |
565 |
| - private String getString(PBytes expression) { |
566 |
| - return new String(getByteArray(expression)); |
567 |
| - } |
| 473 | + protected final String funcname = "eval"; |
| 474 | + @Child protected CompileNode compileNode = CompileNode.create(); |
| 475 | + @Child private IndirectCallNode indirectCallNode = IndirectCallNode.create(); |
| 476 | + @Child private HasInheritedAttributeNode hasGetItemNode; |
| 477 | + @Child private HasInheritedAttributeNode hasSetItemNode; |
568 | 478 |
|
569 |
| - private byte[] getByteArray(PIBytesLike pByteArray) { |
570 |
| - if (toByteArrayNode == null) { |
| 479 | + private HasInheritedAttributeNode getHasGetItemNode() { |
| 480 | + if (hasGetItemNode == null) { |
571 | 481 | CompilerDirectives.transferToInterpreterAndInvalidate();
|
572 |
| - toByteArrayNode = insert(SequenceStorageNodes.ToByteArrayNode.create()); |
| 482 | + hasGetItemNode = insert(HasInheritedAttributeNode.create(SpecialMethodNames.__GETITEM__)); |
573 | 483 | }
|
574 |
| - return toByteArrayNode.execute(pByteArray.getSequenceStorage()); |
575 |
| - } |
576 |
| - |
577 |
| - @TruffleBoundary |
578 |
| - private static Object evalExpression(RootCallTarget ct, PythonObject globals, PythonObject locals, PCell[] closure) { |
579 |
| - return evalNode(ct, globals, locals, closure); |
| 484 | + return hasGetItemNode; |
580 | 485 | }
|
581 | 486 |
|
582 |
| - @TruffleBoundary |
583 |
| - private Object evalExpression(String expression, PythonObject globals, PythonObject locals, PCell[] closure, Frame callerFrame, String desiredName) { |
584 |
| - String name = desiredName; |
585 |
| - if (name == null) { |
586 |
| - name = "<eval>"; |
587 |
| - if (globals instanceof PDict) { |
588 |
| - Object nameObject = getNameNode.execute(globals, __NAME__); |
589 |
| - if (nameObject instanceof String) { |
590 |
| - name = (String) nameObject; |
591 |
| - } |
592 |
| - } |
| 487 | + private HasInheritedAttributeNode getHasSetItemNode() { |
| 488 | + if (hasSetItemNode == null) { |
| 489 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 490 | + hasSetItemNode = insert(HasInheritedAttributeNode.create(SpecialMethodNames.__SETITEM__)); |
593 | 491 | }
|
594 |
| - PythonParser parser = getCore().getParser(); |
595 |
| - Source source = PythonLanguage.newSource(getContext(), expression, name); |
596 |
| - RootCallTarget parsed = Truffle.getRuntime().createCallTarget((RootNode) parser.parse(ParserMode.Eval, getCore(), source, callerFrame)); |
597 |
| - return evalNode(parsed, globals, locals, closure); |
| 492 | + return hasSetItemNode; |
598 | 493 | }
|
599 | 494 |
|
600 |
| - /** |
601 |
| - * @param locals TODO: support the locals dictionary in execution |
602 |
| - */ |
603 |
| - @TruffleBoundary |
604 |
| - private static Object evalNode(RootCallTarget callTarget, PythonObject globals, PythonObject locals, PCell[] closure) { |
605 |
| - Object[] args = PArguments.create(); |
606 |
| - PArguments.setGlobals(args, globals); |
607 |
| - PArguments.setClosure(args, closure); |
608 |
| - // TODO: cache code and CallTargets and use Direct/IndirectCallNode |
609 |
| - return callTarget.call(args); |
610 |
| - } |
611 |
| - } |
612 |
| - |
613 |
| - @Builtin(name = EXEC, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 3, parameterNames = {"source"}) |
614 |
| - @GenerateNodeFactory |
615 |
| - abstract static class ExecNode extends PythonBuiltinNode { |
616 |
| - private final BranchProfile hasFreeVars = BranchProfile.create(); |
617 |
| - @Child private CompileNode compileNode = CompileNode.create(); |
618 |
| - @Child private IndirectCallNode indirectCallNode = IndirectCallNode.create(); |
619 |
| - @Child private IsMappingNode isMapping = IsMappingNode.create(); |
620 |
| - |
621 | 495 | protected boolean isMapping(Object object) {
|
622 |
| - return isMapping.execute(object); |
| 496 | + // tfel: it seems that CPython only checks that there is __getitem__ and __setitem__ |
| 497 | + if (object instanceof PDict) { |
| 498 | + return true; |
| 499 | + } else { |
| 500 | + if (getHasGetItemNode().execute(object)) { |
| 501 | + return getHasSetItemNode().execute(object); |
| 502 | + } |
| 503 | + } |
| 504 | + return false; |
623 | 505 | }
|
624 | 506 |
|
625 | 507 | protected boolean isAnyNone(Object object) {
|
626 | 508 | return object instanceof PNone;
|
627 | 509 | }
|
628 | 510 |
|
629 |
| - private void assertNoFreeVars(PCode code) { |
630 |
| - RootNode rootNode = code.getRootNode(); |
631 |
| - if (rootNode instanceof PClosureRootNode && ((PClosureRootNode) rootNode).hasFreeVars()) { |
632 |
| - hasFreeVars.enter(); |
633 |
| - throw raise(PythonBuiltinClassType.TypeError, "code object passed to exec() may not contain free variables"); |
634 |
| - } |
635 |
| - } |
636 |
| - |
637 |
| - private PCode createAndCheckCode(Object source) { |
638 |
| - PCode code = compileNode.execute(source, "<string>", "exec", 0, false, -1); |
639 |
| - assertNoFreeVars(code); |
640 |
| - return code; |
| 511 | + protected PCode createAndCheckCode(Object source) { |
| 512 | + return compileNode.execute(source, "<string>", "eval", 0, false, -1); |
641 | 513 | }
|
642 | 514 |
|
643 | 515 | private static void inheritGlobals(Frame callerFrame, Object[] args) {
|
@@ -722,12 +594,33 @@ PNone execCustomGlobalsCustomLocals(Object source, PDict globals, Object locals,
|
722 | 594 |
|
723 | 595 | @Specialization(guards = {"!isAnyNone(globals)", "!isDict(globals)"})
|
724 | 596 | PNone badGlobals(@SuppressWarnings("unused") Object source, Object globals, @SuppressWarnings("unused") Object locals) {
|
725 |
| - throw raise(TypeError, "exec() globals must be a dict, not %p", globals); |
| 597 | + throw raise(TypeError, "%s() globals must be a dict, not %p", funcname, globals); |
726 | 598 | }
|
727 | 599 |
|
728 | 600 | @Specialization(guards = {"isAnyNone(globals) || isDict(globals)", "!isAnyNone(locals)", "!isMapping(locals)"})
|
729 | 601 | PNone badLocals(@SuppressWarnings("unused") Object source, @SuppressWarnings("unused") PDict globals, Object locals) {
|
730 |
| - throw raise(TypeError, "exec() locals must be a mapping or None, not %p", locals); |
| 602 | + throw raise(TypeError, "%s() locals must be a mapping or None, not %p", funcname, locals); |
| 603 | + } |
| 604 | + } |
| 605 | + |
| 606 | + @Builtin(name = EXEC, minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 3, parameterNames = {"source"}) |
| 607 | + @GenerateNodeFactory |
| 608 | + abstract static class ExecNode extends EvalNode { |
| 609 | + private final BranchProfile hasFreeVars = BranchProfile.create(); |
| 610 | + |
| 611 | + private void assertNoFreeVars(PCode code) { |
| 612 | + RootNode rootNode = code.getRootNode(); |
| 613 | + if (rootNode instanceof PClosureRootNode && ((PClosureRootNode) rootNode).hasFreeVars()) { |
| 614 | + hasFreeVars.enter(); |
| 615 | + throw raise(PythonBuiltinClassType.TypeError, "code object passed to exec() may not contain free variables"); |
| 616 | + } |
| 617 | + } |
| 618 | + |
| 619 | + @Override |
| 620 | + protected PCode createAndCheckCode(Object source) { |
| 621 | + PCode code = compileNode.execute(source, "<string>", "exec", 0, false, -1); |
| 622 | + assertNoFreeVars(code); |
| 623 | + return code; |
731 | 624 | }
|
732 | 625 | }
|
733 | 626 |
|
|
0 commit comments