4848import static com .oracle .graal .python .compiler .SSTUtils .checkForbiddenArgs ;
4949import static com .oracle .graal .python .compiler .SSTUtils .checkIndex ;
5050import static com .oracle .graal .python .compiler .SSTUtils .checkSubscripter ;
51+ import static com .oracle .graal .python .compiler .SSTUtils .mayBeForbiddenName ;
5152import static com .oracle .graal .python .compiler .bytecode_dsl .BytecodeDSLCompilerUtils .COMPREHENSION_ARGS ;
5253import static com .oracle .graal .python .compiler .bytecode_dsl .BytecodeDSLCompilerUtils .NO_ARGS ;
5354import static com .oracle .graal .python .compiler .bytecode_dsl .BytecodeDSLCompilerUtils .TYPE_PARAMS_DEFAULTS ;
@@ -762,8 +763,9 @@ public void reset() {
762763 prevSaveExceptionLocal = null ;
763764 lastTracedLine = -1 ;
764765 this .inExceptStar = false ;
766+ temporaryLocals .clear ();
765767 if (ASSERTIONS_ENABLED ) {
766- temporaryLocals .clear ();
768+ temporaryLocalsTraces .clear ();
767769 }
768770 }
769771
@@ -795,14 +797,14 @@ void endRootNode(Builder b) {
795797 b .endRoot ();
796798 endRootSourceSection (b );
797799 b .endSource ();
798- if (ASSERTIONS_ENABLED && !temporaryLocals .isEmpty ()) {
800+ if (ASSERTIONS_ENABLED && !temporaryLocalsTraces .isEmpty ()) {
799801 throw new AssertionError (this .qualName + "\n \n " + formatTempLocalsStackTraces ());
800802 }
801803 }
802804
803805 private String formatTempLocalsStackTraces () {
804806 StringBuilder sb = new StringBuilder ();
805- for (Object v : temporaryLocals .values ()) {
807+ for (Object v : temporaryLocalsTraces .values ()) {
806808 if (v instanceof RuntimeException re ) {
807809 sb .append ("\n ==================\n " );
808810 StringWriter sw = new StringWriter ();
@@ -825,44 +827,59 @@ private static boolean assertionsEnabled() {
825827 return enabled ;
826828 }
827829
828- private HashMap <BytecodeLocal , Object > temporaryLocals = ASSERTIONS_ENABLED ? new HashMap <>() : null ;
830+ private HashMap <BytecodeLocal , Object > temporaryLocalsTraces = ASSERTIONS_ENABLED ? new HashMap <>() : null ;
831+ private HashSet <BytecodeLocal > temporaryLocals = new HashSet <>();
829832
830833 private BytecodeLocal beginTemporaryLocal (Builder b ) {
831834 BytecodeLocal local = b .createLocal ();
835+ temporaryLocals .add (local );
836+ assert isTemporaryLocal (local );
832837 if (ASSERTIONS_ENABLED ) {
833- Object previous = temporaryLocals .put (local , TRACK_TEMP_LOCALS ? new RuntimeException () : local );
838+ Object previous = temporaryLocalsTraces .put (local , TRACK_TEMP_LOCALS ? new RuntimeException () : local );
834839 if (previous != null ) {
835840 throw new AssertionError ();
836841 }
837842 }
838843 return local ;
839844 }
840845
846+ public BytecodeLocal beginTemporaryLocalOrGetLocal (ExprTy target , Builder b ) {
847+ if (target instanceof ExprTy .Name nameExpr ) {
848+ BytecodeLocal l = getFastLocal (nameExpr .id );
849+ if (l != null ) {
850+ return l ;
851+ }
852+ }
853+ return beginTemporaryLocal (b );
854+ }
855+
856+ public boolean isTemporaryLocal (BytecodeLocal local ) {
857+ return temporaryLocals .contains (local );
858+ }
859+
841860 private void endTemporaryLocal (BytecodeLocal local , Builder b ) {
842- markTemporaryLocalCleared (local );
843- b .emitClearLocal (local );
861+ if (isTemporaryLocal (local )) {
862+ markTemporaryLocalCleared (local );
863+ b .emitClearLocal (local );
864+ }
844865 }
845866
846867 private void loadAndEndTemporaryLocal (BytecodeLocal local , Builder b ) {
847- markTemporaryLocalCleared (local );
848- b .emitLoadAndClearTempLocal (local );
868+ if (isTemporaryLocal (local )) {
869+ markTemporaryLocalCleared (local );
870+ b .emitLoadAndClearTempLocal (local );
871+ }
849872 }
850873
851874 private void markTemporaryLocalCleared (BytecodeLocal local ) {
852- if (ASSERTIONS_ENABLED ) {
853- if (temporaryLocals .remove (local ) == null ) {
854- throw new AssertionError ();
855- }
875+ if (!temporaryLocals .remove (local )) {
876+ throw new AssertionError ();
856877 }
857- }
858-
859- private BytecodeLocal checkTemporaryLocal (BytecodeLocal local ) {
860878 if (ASSERTIONS_ENABLED ) {
861- if (local != null && ! temporaryLocals . containsKey ( local ) ) {
862- throw new AssertionError ("Temporary local was already cleared" );
879+ if (temporaryLocalsTraces . remove ( local ) == null ) {
880+ throw new AssertionError ();
863881 }
864882 }
865- return local ;
866883 }
867884
868885 void emitTraceLineChecked (SSTNode node , Builder b ) {
@@ -1382,7 +1399,7 @@ private void emitComprehension(ComprehensionTy[] generators, int index, Builder
13821399 statementCompiler .emitAsyncFor (iter , comp .target , null , true , index ,
13831400 (stmtComp , idx ) -> emitComprehensionBody (generators , idx , type , collection , accumulateProducer , stmtComp ));
13841401 } else {
1385- BytecodeLocal localValue = beginTemporaryLocal ( b );
1402+ BytecodeLocal localValue = beginTemporaryLocalOrGetLocal ( comp . target , b );
13861403
13871404 b .beginBlock ();
13881405 b .beginBindStackValue ();
@@ -1411,7 +1428,7 @@ private void emitComprehension(ComprehensionTy[] generators, int index, Builder
14111428
14121429 b .beginBlock ();
14131430
1414- comp . target . accept ( statementCompiler .new StoreVisitor (() -> b . emitLoadLocal ( localValue )) );
1431+ statementCompiler .storeTemporaryLocalToTarget ( localValue , comp . target , b );
14151432 emitComprehensionBody (generators , index , type , collection , accumulateProducer , statementCompiler );
14161433
14171434 b .endBlock ();
@@ -1851,6 +1868,25 @@ private void emitNameOperation(String name, NameOperation op, Builder b) {
18511868 emitNameSlowOperation (mangled , op , b );
18521869 }
18531870
1871+ private BytecodeLocal getFastLocal (String name ) {
1872+ if (mayBeForbiddenName (name )) {
1873+ return null ;
1874+ }
1875+ String mangled = maybeMangle (name );
1876+ EnumSet <DefUse > uses = scope .getUseOfName (mangled );
1877+ if (uses != null ) {
1878+ if (uses .contains (DefUse .Free ) || uses .contains (DefUse .Cell )) {
1879+ return null ;
1880+ } else if (uses .contains (DefUse .Local )) {
1881+ if (scope .isFunction ()) {
1882+ assert varnames .containsKey (mangled ) : String .format ("scope analysis did not mark %s as a regular variable" , mangled );
1883+ return locals .get (mangled );
1884+ }
1885+ }
1886+ }
1887+ return null ;
1888+ }
1889+
18541890 private void emitReadLocal (String name , Builder b ) {
18551891 emitNameOperation (name , NameOperation .Read , b );
18561892 }
@@ -2016,6 +2052,23 @@ private BytecodeLocal beginTemporaryLocal() {
20162052 return RootNodeCompiler .this .beginTemporaryLocal (b );
20172053 }
20182054
2055+ /**
2056+ * If the target expression is simple local variable, we can often just directly store into it.
2057+ * Otherwise, we create temporary local. {@link BytecodeLocal} instances returned by this should
2058+ * be passed to {@link #storeTemporaryLocalToTarget(BytecodeLocal, ExprTy, Builder)}.
2059+ */
2060+ public BytecodeLocal beginTemporaryLocalOrGetLocal (ExprTy target , Builder b ) {
2061+ return RootNodeCompiler .this .beginTemporaryLocalOrGetLocal (target , b );
2062+ }
2063+
2064+ private void storeTemporaryLocalToTarget (BytecodeLocal temporaryLocal , ExprTy target , Builder b ) {
2065+ if (RootNodeCompiler .this .isTemporaryLocal (temporaryLocal )) {
2066+ target .accept (new StoreVisitor (() -> {
2067+ b .emitLoadLocal (temporaryLocal );
2068+ }));
2069+ }
2070+ }
2071+
20192072 private void endTemporaryLocal (BytecodeLocal local ) {
20202073 RootNodeCompiler .this .endTemporaryLocal (local , b );
20212074 }
@@ -4328,7 +4381,7 @@ public Void visit(StmtTy.For node) {
43284381 inExceptStar = false ;
43294382 b .beginBlock ();
43304383
4331- BytecodeLocal value = beginTemporaryLocal ( );
4384+ BytecodeLocal value = beginTemporaryLocalOrGetLocal ( node . target , b );
43324385
43334386 b .beginBindStackValue ();
43344387 b .beginGetIter ();
@@ -4355,9 +4408,7 @@ public Void visit(StmtTy.For node) {
43554408 // body
43564409 b .beginBlock ();
43574410 continueLabel = b .createLabel ();
4358- node .target .accept (new StoreVisitor (() -> {
4359- b .emitLoadLocal (value );
4360- }));
4411+ storeTemporaryLocalToTarget (value , node .target , b );
43614412
43624413 visitSequence (node .body );
43634414 b .emitLabel (continueLabel );
0 commit comments