@@ -48,6 +48,7 @@ public class ProgramState extends State implements AutoCloseable {
4848 private final Map <String , List <ImTypeArgument >> genericArrayTypeArguments = new HashMap <>();
4949 private final IdentityHashMap <ImVar , Object2ObjectOpenHashMap <String , ILconst >> genericStaticVals = new IdentityHashMap <>();
5050 private final Object2ObjectOpenHashMap <String , ILconst > genericStaticScalarVals = new Object2ObjectOpenHashMap <>();
51+ private int untrackedWriteDepth ;
5152
5253 private static boolean containsTypeVariable (ImType type ) {
5354 return type .match (new ImType .Matcher <Boolean >() {
@@ -684,13 +685,18 @@ private static String vid(ImVar v) {
684685
685686 @ Override
686687 public void setVal (ImVar v , ILconst val ) {
687- modifiedScalars .add (v );
688+ boolean trackWrite = untrackedWriteDepth == 0 ;
689+ if (trackWrite ) {
690+ modifiedScalars .add (v );
691+ }
688692 String key = genericStaticKey (v );
689693 if (key != null ) {
690694 WLogger .trace (() -> "[GENSTATIC] set " + key + " = " + val );
691695 genericStaticScalarVals .put (key , val );
692- modifiedGenericScalars .add (key );
693- genericScalarTypeArguments .computeIfAbsent (key , ignored -> genericStaticTypeArguments (v ));
696+ if (trackWrite ) {
697+ modifiedGenericScalars .add (key );
698+ genericScalarTypeArguments .computeIfAbsent (key , ignored -> genericStaticTypeArguments (v ));
699+ }
694700 return ;
695701 }
696702 super .setVal (v , val );
@@ -719,7 +725,7 @@ public void setValUntracked(ImVar v, ILconst val) {
719725 // lazy init from global inits (e.g. foo = 1)
720726 List <ImSet > inits = prog .getGlobalInits ().get (v );
721727 if (inits != null && !inits .isEmpty ()) {
722- ILconst initVal = inits .get (inits .size () - 1 ).getRight (). evaluate ( this , EMPTY_LOCAL_STATE );
728+ ILconst initVal = evaluateUntracked ( inits .get (inits .size () - 1 ).getRight (), EMPTY_LOCAL_STATE );
723729 genericStaticScalarVals .put (key , initVal );
724730 WLogger .trace (() -> "[GENSTATIC] get " + key + " -> (init) " + initVal );
725731 return initVal ;
@@ -733,6 +739,21 @@ public void setValUntracked(ImVar v, ILconst val) {
733739 return super .getVal (v );
734740 }
735741
742+ /**
743+ * Evaluates a lazy global initializer without recording its side effects for state migration.
744+ * Runtime repeats initializer execution, so replaying those writes would duplicate them.
745+ * Compiletime-only side effects hidden inside an initializer are intentionally unsupported;
746+ * persistent mutations must be performed by an explicit compiletime function instead.
747+ */
748+ public ILconst evaluateUntracked (ImExpr expr , LocalState localState ) {
749+ untrackedWriteDepth ++;
750+ try {
751+ return expr .evaluate (this , localState );
752+ } finally {
753+ untrackedWriteDepth --;
754+ }
755+ }
756+
736757
737758 public boolean isCompiletime () {
738759 return isCompiletime ;
@@ -755,7 +776,7 @@ protected ILconstArray getArray(ImVar v) {
755776 if (inits != null && !inits .isEmpty ()) {
756777 final LocalState ls = EMPTY_LOCAL_STATE ;
757778 for (int i = 0 ; i < inits .size (); i ++) {
758- ILconst val = inits .get (i ).getRight (). evaluate ( this , ls );
779+ ILconst val = evaluateUntracked ( inits .get (i ).getRight (), ls );
759780 r .set (i , val );
760781 }
761782 }
@@ -774,7 +795,7 @@ protected ILconstArray getArray(ImVar v) {
774795 if (inits != null && !inits .isEmpty ()) {
775796 final LocalState ls = EMPTY_LOCAL_STATE ;
776797 for (int i = 0 ; i < inits .size (); i ++) {
777- ILconst val = inits .get (i ).getRight (). evaluate ( this , ls );
798+ ILconst val = evaluateUntracked ( inits .get (i ).getRight (), ls );
778799 r .set (i , val );
779800 }
780801 }
@@ -783,6 +804,10 @@ protected ILconstArray getArray(ImVar v) {
783804
784805 @ Override
785806 public void setArrayVal (ImVar v , List <Integer > indexes , ILconst val ) {
807+ if (untrackedWriteDepth > 0 ) {
808+ setArrayValUntracked (v , indexes , val );
809+ return ;
810+ }
786811 String key = genericStaticKey (v );
787812 super .setArrayVal (v , indexes , val );
788813 if (key != null ) {
0 commit comments