Skip to content

Commit 5cefc25

Browse files
aardvark179gbrail
authored andcommitted
Refactor exception and stack handling to use the new fields.
1 parent 1c664b6 commit 5cefc25

3 files changed

Lines changed: 135 additions & 117 deletions

File tree

rhino/src/main/java/org/mozilla/javascript/Context.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.lang.reflect.InvocationTargetException;
2020
import java.lang.reflect.Method;
2121
import java.util.ArrayDeque;
22-
import java.util.Deque;
2322
import java.util.EnumSet;
2423
import java.util.HashMap;
2524
import java.util.HashSet;
@@ -2805,13 +2804,10 @@ public static boolean isCurrentContextStrict() {
28052804
/** This is the list of names of objects forcing the creation of function activation records. */
28062805
Set<String> activationNames;
28072806

2808-
// For the interpreter to store the last frame for error reports etc.
2807+
// For the interpreter to store the last frame for error reports
2808+
// etc. Previous frames can all be derived from this.
28092809
Object lastInterpreterFrame;
28102810

2811-
// For the interpreter to store information about previous invocations
2812-
// interpreter invocations
2813-
Deque<Object> previousInterpreterInvocations;
2814-
28152811
// For instruction counting (interpreter only)
28162812
int instructionCount;
28172813
int instructionThreshold;

rhino/src/main/java/org/mozilla/javascript/Interpreter.java

Lines changed: 131 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@
1111
import java.io.PrintStream;
1212
import java.io.Serializable;
1313
import java.math.BigInteger;
14-
import java.util.ArrayDeque;
1514
import java.util.ArrayList;
1615
import java.util.Arrays;
17-
import java.util.Collections;
1816
import java.util.HashSet;
1917
import java.util.List;
2018
import 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("\tat 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

Comments
 (0)