1111import java .io .PrintStream ;
1212import java .io .Serializable ;
1313import java .math .BigInteger ;
14- import java .util .ArrayDeque ;
1514import java .util .ArrayList ;
1615import java .util .Arrays ;
17- import java .util .Collections ;
1816import java .util .HashSet ;
1917import java .util .List ;
2018import java .util .Objects ;
@@ -111,7 +109,14 @@ private static class CallFrame implements Cloneable, Serializable {
111109 this .thisObj = thisObj ;
112110
113111 this .parentFrame = parentFrame ;
114- this .parentPC = parentFrame == null ? -1 : parentFrame .pcSourceLineStart ;
112+ if (parentFrame == null ) {
113+ this .parentPC =
114+ previousInterpreterFrame == null
115+ ? -1
116+ : previousInterpreterFrame .pcSourceLineStart ;
117+ } else {
118+ this .parentPC = parentFrame .pcSourceLineStart ;
119+ }
115120 this .previousInterpreterFrame = previousInterpreterFrame ;
116121 frameIndex = (short ) ((parentFrame == null ) ? 0 : parentFrame .frameIndex + 1 );
117122 if (frameIndex > cx .getMaximumInterpreterStackDepth ()) {
@@ -133,6 +138,8 @@ private CallFrame(CallFrame original, boolean makeOrphan) {
133138 makeOrphan ? null : original .previousInterpreterFrame );
134139 }
135140
141+ /* Copy the frame for *continuations*. Here we want to make
142+ fresh copies of the stack and everything related to it. */
136143 private CallFrame (
137144 CallFrame original , CallFrame parentFrame , CallFrame previousInterpreterFrame ) {
138145 if (!original .frozen ) Kit .codeBug ();
@@ -147,7 +154,62 @@ private CallFrame(
147154 this .previousInterpreterFrame = previousInterpreterFrame ;
148155 if (parentFrame == null ) {
149156 frameIndex = 0 ;
150- parentPC = -1 ;
157+ parentPC =
158+ previousInterpreterFrame == null
159+ ? -1
160+ : previousInterpreterFrame .pcSourceLineStart ;
161+ } else {
162+ frameIndex = original .frameIndex ;
163+ parentPC = parentFrame .pcSourceLineStart ;
164+ }
165+
166+ fnOrScript = original .fnOrScript ;
167+ idata = original .idata ;
168+
169+ varSource = original .varSource ;
170+ emptyStackTop = original .emptyStackTop ;
171+
172+ debuggerFrame = original .debuggerFrame ;
173+ useActivation = original .useActivation ;
174+ isContinuationsTopFrame = original .isContinuationsTopFrame ;
175+
176+ thisObj = original .thisObj ;
177+
178+ result = original .result ;
179+ resultDbl = original .resultDbl ;
180+ pc = original .pc ;
181+ pcPrevBranch = original .pcPrevBranch ;
182+ pcSourceLineStart = original .pcSourceLineStart ;
183+ scope = original .scope ;
184+
185+ savedStackTop = original .savedStackTop ;
186+ savedCallOp = original .savedCallOp ;
187+ throwable = original .throwable ;
188+ }
189+
190+ /* Copy the stack for running a generator. We're only doing
191+ this to maintain the correct chain of parents for exception
192+ stacks, so we'll reuse the existing stack arrays. */
193+ private CallFrame (
194+ CallFrame original ,
195+ CallFrame parentFrame ,
196+ CallFrame previousInterpreterFrame ,
197+ boolean keepFrozen ) {
198+ if (!original .frozen ) Kit .codeBug ();
199+
200+ stack = original .stack ;
201+ stackAttributes = original .stackAttributes ;
202+ sDbl = original .sDbl ;
203+
204+ frozen = keepFrozen ;
205+ this .parentFrame = parentFrame ;
206+ this .previousInterpreterFrame = previousInterpreterFrame ;
207+ if (parentFrame == null ) {
208+ frameIndex = 0 ;
209+ parentPC =
210+ previousInterpreterFrame == null
211+ ? -1
212+ : previousInterpreterFrame .pcSourceLineStart ;
151213 } else {
152214 frameIndex = original .frameIndex ;
153215 parentPC = parentFrame .pcSourceLineStart ;
@@ -241,8 +303,6 @@ void initializeArgs(
241303 }
242304 }
243305
244- final int maxFrameArray = idata .itsMaxFrameArray ;
245-
246306 int varCount = idata .getParamAndVarCount ();
247307 for (int i = 0 ; i < varCount ; i ++) {
248308 if (idata .getParamOrVarConst (i )) stackAttributes [i ] = ScriptableObject .CONST ;
@@ -293,6 +353,25 @@ CallFrame cloneFrozen() {
293353 return new CallFrame (this , false );
294354 }
295355
356+ CallFrame shallowCloneFrozen (CallFrame newPreviousInterpreeterFrame ) {
357+ return new CallFrame (this , this .parentFrame , newPreviousInterpreeterFrame , true );
358+ }
359+
360+ void syncStateToFrame (CallFrame otherFrame ) {
361+ otherFrame .frozen = frozen ;
362+ otherFrame .isContinuationsTopFrame = isContinuationsTopFrame ;
363+ otherFrame .result = result ;
364+ otherFrame .resultDbl = resultDbl ;
365+ otherFrame .pc = pc ;
366+ otherFrame .pcPrevBranch = pcPrevBranch ;
367+ otherFrame .pcSourceLineStart = pcSourceLineStart ;
368+ otherFrame .scope = scope ;
369+
370+ otherFrame .savedStackTop = savedStackTop ;
371+ otherFrame .savedCallOp = savedCallOp ;
372+ otherFrame .throwable = throwable ;
373+ }
374+
296375 @ Override
297376 public boolean equals (Object other ) {
298377 // Overridden for semantic equality comparison. These objects
@@ -967,53 +1046,9 @@ public void captureStackInfo(RhinoException ex) {
9671046 if (cx == null || cx .lastInterpreterFrame == null ) {
9681047 // No interpreter invocations
9691048 ex .interpreterStackInfo = null ;
970- ex .interpreterLineData = null ;
971- return ;
972- }
973- // has interpreter frame on the stack
974- CallFrame [] array ;
975- if (cx .previousInterpreterInvocations == null
976- || cx .previousInterpreterInvocations .size () == 0 ) {
977- array = new CallFrame [1 ];
9781049 } else {
979- int previousCount = cx .previousInterpreterInvocations .size ();
980- if (cx .previousInterpreterInvocations .peek () == cx .lastInterpreterFrame ) {
981- // It can happen if exception was generated after
982- // frame was pushed to cx.previousInterpreterInvocations
983- // but before assignment to cx.lastInterpreterFrame.
984- // In this case frames has to be ignored.
985- --previousCount ;
986- }
987- array = new CallFrame [previousCount + 1 ];
988-
989- ArrayList <Object > tempList = new ArrayList <>(cx .previousInterpreterInvocations );
990- Collections .reverse (tempList );
991- tempList .toArray (array );
992- }
993- array [array .length - 1 ] = (CallFrame ) cx .lastInterpreterFrame ;
994-
995- int interpreterFrameCount = 0 ;
996- for (int i = 0 ; i != array .length ; ++i ) {
997- interpreterFrameCount += 1 + array [i ].frameIndex ;
998- }
999-
1000- int [] linePC = new int [interpreterFrameCount ];
1001- // Fill linePC with pc positions from all interpreter frames.
1002- // Start from the most nested frame
1003- int linePCIndex = interpreterFrameCount ;
1004- for (int i = array .length ; i != 0 ; ) {
1005- --i ;
1006- CallFrame frame = array [i ];
1007- while (frame != null ) {
1008- --linePCIndex ;
1009- linePC [linePCIndex ] = frame .pcSourceLineStart ;
1010- frame = frame .parentFrame ;
1011- }
1050+ ex .interpreterStackInfo = cx .lastInterpreterFrame ;
10121051 }
1013- if (linePCIndex != 0 ) Kit .codeBug ();
1014-
1015- ex .interpreterStackInfo = array ;
1016- ex .interpreterLineData = linePC ;
10171052 }
10181053
10191054 @ Override
@@ -1034,13 +1069,11 @@ public String getPatchedStack(RhinoException ex, String nativeStackTrace) {
10341069 StringBuilder sb = new StringBuilder (nativeStackTrace .length () + 1000 );
10351070 String lineSeparator = SecurityUtilities .getSystemProperty ("line.separator" );
10361071
1037- CallFrame [] array = (CallFrame []) ex .interpreterStackInfo ;
1038- int [] linePC = ex .interpreterLineData ;
1039- int arrayIndex = array .length ;
1040- int linePCIndex = linePC .length ;
1072+ CallFrame calleeFrame = null ;
1073+ CallFrame frame = (CallFrame ) ex .interpreterStackInfo ;
10411074 int offset = 0 ;
1042- while (arrayIndex != 0 ) {
1043- -- arrayIndex ;
1075+ while (frame != null ) {
1076+ CallFrame callerFrame = frame ;
10441077 int pos = nativeStackTrace .indexOf (tag , offset );
10451078 if (pos < 0 ) {
10461079 break ;
@@ -1058,11 +1091,8 @@ public String getPatchedStack(RhinoException ex, String nativeStackTrace) {
10581091 sb .append (nativeStackTrace , offset , pos );
10591092 offset = pos ;
10601093
1061- CallFrame frame = array [arrayIndex ];
1062- while (frame != null ) {
1063- if (linePCIndex == 0 ) Kit .codeBug ();
1064- --linePCIndex ;
1065- InterpreterData idata = frame .idata ;
1094+ while (callerFrame != null ) {
1095+ InterpreterData idata = callerFrame .idata ;
10661096 sb .append (lineSeparator );
10671097 sb .append ("\t at script" );
10681098 if (idata .itsName != null && idata .itsName .length () != 0 ) {
@@ -1071,15 +1101,17 @@ public String getPatchedStack(RhinoException ex, String nativeStackTrace) {
10711101 }
10721102 sb .append ('(' );
10731103 sb .append (idata .itsSourceFile );
1074- int pc = linePC [ linePCIndex ] ;
1104+ int pc = calleeFrame == null ? callerFrame . pcSourceLineStart : calleeFrame . parentPC ;
10751105 if (pc >= 0 ) {
10761106 // Include line info only if available
10771107 sb .append (':' );
10781108 sb .append (getIndex (idata .itsICode , pc ));
10791109 }
10801110 sb .append (')' );
1081- frame = frame .parentFrame ;
1111+ calleeFrame = callerFrame ;
1112+ callerFrame = callerFrame .parentFrame ;
10821113 }
1114+ frame = calleeFrame .previousInterpreterFrame ;
10831115 }
10841116 sb .append (nativeStackTrace .substring (offset ));
10851117
@@ -1109,32 +1141,29 @@ public ScriptStackElement[][] getScriptStackElements(RhinoException ex) {
11091141
11101142 List <ScriptStackElement []> list = new ArrayList <>();
11111143
1112- CallFrame [] array = (CallFrame []) ex .interpreterStackInfo ;
1113- int [] linePC = ex .interpreterLineData ;
1114- int arrayIndex = array .length ;
1115- int linePCIndex = linePC .length ;
1116- while (arrayIndex != 0 ) {
1117- --arrayIndex ;
1118- CallFrame frame = array [arrayIndex ];
1144+ CallFrame calleeFrame = null ;
1145+ CallFrame frame = (CallFrame ) ex .interpreterStackInfo ;
1146+ while (frame != null ) {
1147+ CallFrame callerFrame = frame ;
11191148 List <ScriptStackElement > group = new ArrayList <>();
1120- while (frame != null ) {
1121- if (linePCIndex == 0 ) Kit .codeBug ();
1122- --linePCIndex ;
1123- InterpreterData idata = frame .idata ;
1149+ while (callerFrame != null ) {
1150+ InterpreterData idata = callerFrame .fnOrScript .idata ;
11241151 String fileName = idata .itsSourceFile ;
11251152 String functionName = null ;
11261153 int lineNumber = -1 ;
1127- int pc = linePC [ linePCIndex ] ;
1154+ int pc = calleeFrame == null ? callerFrame . pcSourceLineStart : calleeFrame . parentPC ;
11281155 if (pc >= 0 ) {
11291156 lineNumber = getIndex (idata .itsICode , pc );
11301157 }
11311158 if (idata .itsName != null && idata .itsName .length () != 0 ) {
11321159 functionName = idata .itsName ;
11331160 }
1134- frame = frame .parentFrame ;
1161+ calleeFrame = callerFrame ;
1162+ callerFrame = callerFrame .parentFrame ;
11351163 group .add (new ScriptStackElement (fileName , functionName , lineNumber ));
11361164 }
11371165 list .add (group .toArray (new ScriptStackElement [0 ]));
1166+ frame = calleeFrame .previousInterpreterFrame ;
11381167 }
11391168 return list .toArray (new ScriptStackElement [list .size ()][]);
11401169 }
@@ -1206,19 +1235,24 @@ static class GeneratorState {
12061235 public static Object resumeGenerator (
12071236 Context cx , Scriptable scope , int operation , Object savedState , Object value ) {
12081237 CallFrame frame = (CallFrame ) savedState ;
1209- GeneratorState generatorState = new GeneratorState (operation , value );
1210- if (operation == NativeGenerator .GENERATOR_CLOSE ) {
1211- try {
1212- return interpretLoop (cx , frame , generatorState );
1213- } catch (RuntimeException e ) {
1214- // Only propagate exceptions other than closingException
1215- if (e != value ) throw e ;
1238+ CallFrame activeFrame = frame .shallowCloneFrozen ((CallFrame ) cx .lastInterpreterFrame );
1239+ try {
1240+ GeneratorState generatorState = new GeneratorState (operation , value );
1241+ if (operation == NativeGenerator .GENERATOR_CLOSE ) {
1242+ try {
1243+ return interpretLoop (cx , activeFrame , generatorState );
1244+ } catch (RuntimeException e ) {
1245+ // Only propagate exceptions other than closingException
1246+ if (e != value ) throw e ;
1247+ }
1248+ return Undefined .instance ;
12161249 }
1217- return Undefined .instance ;
1250+ Object result = interpretLoop (cx , activeFrame , generatorState );
1251+ if (generatorState .returnedException != null ) throw generatorState .returnedException ;
1252+ return result ;
1253+ } finally {
1254+ activeFrame .syncStateToFrame (frame );
12181255 }
1219- Object result = interpretLoop (cx , frame , generatorState );
1220- if (generatorState .returnedException != null ) throw generatorState .returnedException ;
1221- return result ;
12221256 }
12231257
12241258 public static Object restartContinuation (
@@ -1283,6 +1317,15 @@ private ContinueLoop(int stackTop, int indexReg) {
12831317 }
12841318
12851319 private static Object interpretLoop (Context cx , CallFrame frame , Object throwable ) {
1320+ final Object oldFrame = cx .lastInterpreterFrame ;
1321+ try {
1322+ return interpretLoopInner (cx , frame , throwable );
1323+ } finally {
1324+ cx .lastInterpreterFrame = oldFrame ;
1325+ }
1326+ }
1327+
1328+ private static Object interpretLoopInner (Context cx , CallFrame frame , Object throwable ) {
12861329 // throwable holds exception object to rethrow or catch
12871330 // It is also used for continuation restart in which case
12881331 // it holds ContinuationJump
@@ -1295,15 +1338,6 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl
12951338 BigInteger bigIntReg = null ;
12961339 int indexReg = -1 ;
12971340
1298- if (cx .lastInterpreterFrame != null ) {
1299- // save the top frame from the previous interpretLoop
1300- // invocation on the stack
1301- if (cx .previousInterpreterInvocations == null ) {
1302- cx .previousInterpreterInvocations = new ArrayDeque <>();
1303- }
1304- cx .previousInterpreterInvocations .push (cx .lastInterpreterFrame );
1305- }
1306-
13071341 // When restarting continuation throwable is not null and to jump
13081342 // to the code that rewind continuation state indexReg should be set
13091343 // to -1.
@@ -2795,18 +2829,6 @@ private static Object interpretLoop(Context cx, CallFrame frame, Object throwabl
27952829 break StateLoop ;
27962830 } // end of StateLoop: for(;;)
27972831
2798- // Do cleanups/restorations before the final return or throw
2799-
2800- if (cx .previousInterpreterInvocations != null
2801- && cx .previousInterpreterInvocations .size () != 0 ) {
2802- cx .lastInterpreterFrame = cx .previousInterpreterInvocations .pop ();
2803- } else {
2804- // It was the last interpreter frame on the stack
2805- cx .lastInterpreterFrame = null ;
2806- // Force GC of the value cx.previousInterpreterInvocations
2807- cx .previousInterpreterInvocations = null ;
2808- }
2809-
28102832 if (throwable != null ) {
28112833 if (throwable instanceof RuntimeException ) {
28122834 throw (RuntimeException ) throwable ;
0 commit comments