1
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3
* The contents of this file are subject to the Netscape Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/NPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is Rhino code, released
16
* The Initial Developer of the Original Code is Netscape
17
* Communications Corporation. Portions created by Netscape are
18
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
27
* Alternatively, the contents of this file may be used under the
28
* terms of the GNU Public License (the "GPL"), in which case the
29
* provisions of the GPL are applicable instead of those above.
30
* If you wish to allow use of your version of this file only
31
* under the terms of the GPL and not to allow others to use your
32
* version of this file under the NPL, indicate your decision by
33
* deleting the provisions above and replace them with the notice
34
* and other provisions required by the GPL. If you do not delete
35
* the provisions above, a recipient may use your version of this
36
* file under either the NPL or the GPL.
39
package org.mozilla.javascript;
42
import java.util.Vector;
43
import java.util.Enumeration;
45
import org.mozilla.javascript.debug.*;
47
public class Interpreter extends LabelTable {
49
public static final boolean printICode = false;
51
public IRFactory createIRFactory(TokenStream ts,
52
ClassNameHelper nameHelper, Scriptable scope)
54
return new IRFactory(ts, scope);
57
public Node transform(Node tree, TokenStream ts, Scriptable scope) {
58
return (new NodeTransformer()).transform(tree, null, ts, scope);
61
public Object compile(Context cx, Scriptable scope, Node tree,
62
Object securityDomain,
63
SecuritySupport securitySupport,
64
ClassNameHelper nameHelper)
67
version = cx.getLanguageVersion();
68
itsData = new InterpreterData(0, 0, 0, securityDomain,
69
cx.hasCompileFunctionsWithDynamicScope(), false);
70
if (tree instanceof FunctionNode) {
71
FunctionNode f = (FunctionNode) tree;
72
InterpretedFunction result =
73
generateFunctionICode(cx, scope, f, securityDomain);
74
result.itsData.itsFunctionType = f.getFunctionType();
75
createFunctionObject(result, scope);
78
return generateScriptICode(cx, scope, tree, securityDomain);
81
private void generateICodeFromTree(Node tree,
82
VariableTable varTable,
83
boolean needsActivation,
84
Object securityDomain)
87
itsVariableTable = varTable;
88
itsData.itsNeedsActivation = needsActivation;
89
theICodeTop = generateICode(tree, theICodeTop);
90
itsData.itsICodeTop = theICodeTop;
91
if (itsEpilogLabel != -1)
92
markLabel(itsEpilogLabel, theICodeTop);
93
for (int i = 0; i < itsLabelTableTop; i++)
94
itsLabelTable[i].fixGotos(itsData.itsICode);
97
private Object[] generateRegExpLiterals(Context cx,
101
Object[] result = new Object[regexps.size()];
102
RegExpProxy rep = cx.getRegExpProxy();
103
for (int i = 0; i < regexps.size(); i++) {
104
Node regexp = (Node) regexps.elementAt(i);
105
Node left = regexp.getFirstChild();
106
Node right = regexp.getLastChild();
107
result[i] = rep.newRegExp(cx, scope, left.getString(),
108
(left != right) ? right.getString() : null, false);
109
regexp.putProp(Node.REGEXP_PROP, new Integer(i));
114
private InterpretedScript generateScriptICode(Context cx,
117
Object securityDomain)
119
itsSourceFile = (String) tree.getProp(Node.SOURCENAME_PROP);
120
itsData.itsSourceFile = itsSourceFile;
121
itsFunctionList = (Vector) tree.getProp(Node.FUNCTION_PROP);
122
debugSource = (StringBuffer) tree.getProp(Node.DEBUGSOURCE_PROP);
123
if (itsFunctionList != null)
124
generateNestedFunctions(scope, cx, securityDomain);
125
Object[] regExpLiterals = null;
126
Vector regexps = (Vector)tree.getProp(Node.REGEXP_PROP);
128
regExpLiterals = generateRegExpLiterals(cx, scope, regexps);
130
VariableTable varTable = (VariableTable)tree.getProp(Node.VARS_PROP);
131
// The default is not to generate debug information
132
boolean activationNeeded = cx.isGeneratingDebugChanged() &&
133
cx.isGeneratingDebug();
134
generateICodeFromTree(tree, varTable, activationNeeded, securityDomain);
135
itsData.itsNestedFunctions = itsNestedFunctions;
136
itsData.itsRegExpLiterals = regExpLiterals;
137
if (printICode) dumpICode(itsData);
139
String[] argNames = itsVariableTable.getAllNames();
140
short argCount = (short)itsVariableTable.getParameterCount();
142
result = new InterpretedScript(cx, itsData, argNames, argCount);
143
if (cx.debugger != null) {
144
cx.debugger.handleCompilationDone(cx, result, debugSource);
149
private void generateNestedFunctions(Scriptable scope,
151
Object securityDomain)
153
itsNestedFunctions = new InterpretedFunction[itsFunctionList.size()];
154
for (short i = 0; i < itsFunctionList.size(); i++) {
155
FunctionNode def = (FunctionNode)itsFunctionList.elementAt(i);
156
Interpreter jsi = new Interpreter();
157
jsi.itsSourceFile = itsSourceFile;
158
jsi.itsData = new InterpreterData(0, 0, 0, securityDomain,
159
cx.hasCompileFunctionsWithDynamicScope(),
161
jsi.itsData.itsFunctionType = def.getFunctionType();
162
jsi.itsInFunctionFlag = true;
163
jsi.debugSource = debugSource;
164
itsNestedFunctions[i] = jsi.generateFunctionICode(cx, scope, def,
166
def.putProp(Node.FUNCTION_PROP, new Short(i));
170
private InterpretedFunction
171
generateFunctionICode(Context cx, Scriptable scope,
172
FunctionNode theFunction, Object securityDomain)
174
itsFunctionList = (Vector) theFunction.getProp(Node.FUNCTION_PROP);
175
if (itsFunctionList != null)
176
generateNestedFunctions(scope, cx, securityDomain);
177
Object[] regExpLiterals = null;
178
Vector regexps = (Vector)theFunction.getProp(Node.REGEXP_PROP);
180
regExpLiterals = generateRegExpLiterals(cx, scope, regexps);
182
VariableTable varTable = theFunction.getVariableTable();
183
boolean needsActivation = theFunction.requiresActivation() ||
184
(cx.isGeneratingDebugChanged() &&
185
cx.isGeneratingDebug());
186
generateICodeFromTree(theFunction.getLastChild(),
187
varTable, needsActivation,
190
itsData.itsName = theFunction.getFunctionName();
191
itsData.itsSourceFile = (String) theFunction.getProp(
192
Node.SOURCENAME_PROP);
193
itsData.itsSource = (String)theFunction.getProp(Node.SOURCE_PROP);
194
itsData.itsNestedFunctions = itsNestedFunctions;
195
itsData.itsRegExpLiterals = regExpLiterals;
196
if (printICode) dumpICode(itsData);
198
String[] argNames = itsVariableTable.getAllNames();
199
short argCount = (short)itsVariableTable.getParameterCount();
201
result = new InterpretedFunction(cx, itsData, argNames, argCount);
202
if (cx.debugger != null) {
203
cx.debugger.handleCompilationDone(cx, result, debugSource);
208
boolean itsInFunctionFlag;
209
Vector itsFunctionList;
211
InterpreterData itsData;
212
VariableTable itsVariableTable;
214
int itsStackDepth = 0;
215
int itsEpilogLabel = -1;
216
String itsSourceFile;
217
int itsLineNumber = 0;
218
InterpretedFunction[] itsNestedFunctions = null;
220
private int updateLineNumber(Node node, int iCodeTop)
222
Object datum = node.getDatum();
223
if (datum == null || !(datum instanceof Number))
225
short lineNumber = ((Number) datum).shortValue();
226
if (lineNumber != itsLineNumber) {
227
itsLineNumber = lineNumber;
228
if (itsData.itsLineNumberTable == null &&
229
Context.getCurrentContext().isGeneratingDebug())
231
itsData.itsLineNumberTable = new UintMap();
233
if (itsData.itsLineNumberTable != null) {
234
itsData.itsLineNumberTable.put(lineNumber, iCodeTop);
236
iCodeTop = addByte((byte) TokenStream.LINE, iCodeTop);
237
iCodeTop = addByte((byte)(lineNumber >> 8), iCodeTop);
238
iCodeTop = addByte((byte)(lineNumber & 0xff), iCodeTop);
245
private void badTree(Node node)
248
out = new PrintWriter(new FileOutputStream("icode.txt", true));
249
out.println("Un-handled node : " + node.toString());
252
catch (IOException x) {}
253
throw new RuntimeException("Un-handled node : "
257
private int generateICode(Node node, int iCodeTop) {
258
int type = node.getType();
259
Node child = node.getFirstChild();
260
Node firstChild = child;
263
case TokenStream.FUNCTION : {
264
iCodeTop = addByte((byte) TokenStream.CLOSURE, iCodeTop);
265
Node fn = (Node) node.getProp(Node.FUNCTION_PROP);
266
Short index = (Short) fn.getProp(Node.FUNCTION_PROP);
267
iCodeTop = addByte((byte)(index.shortValue() >> 8), iCodeTop);
268
iCodeTop = addByte((byte)(index.shortValue() & 0xff), iCodeTop);
270
if (itsStackDepth > itsData.itsMaxStack)
271
itsData.itsMaxStack = itsStackDepth;
275
case TokenStream.SCRIPT :
276
iCodeTop = updateLineNumber(node, iCodeTop);
277
while (child != null) {
278
if (child.getType() != TokenStream.FUNCTION)
279
iCodeTop = generateICode(child, iCodeTop);
280
child = child.getNextSibling();
284
case TokenStream.CASE :
285
iCodeTop = updateLineNumber(node, iCodeTop);
286
child = child.getNextSibling();
287
while (child != null) {
288
iCodeTop = generateICode(child, iCodeTop);
289
child = child.getNextSibling();
293
case TokenStream.LABEL :
294
case TokenStream.WITH :
295
case TokenStream.LOOP :
296
case TokenStream.DEFAULT :
297
case TokenStream.BLOCK :
298
case TokenStream.VOID :
299
case TokenStream.NOP :
300
iCodeTop = updateLineNumber(node, iCodeTop);
301
while (child != null) {
302
iCodeTop = generateICode(child, iCodeTop);
303
child = child.getNextSibling();
307
case TokenStream.COMMA :
308
iCodeTop = generateICode(child, iCodeTop);
309
iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
311
child = child.getNextSibling();
312
iCodeTop = generateICode(child, iCodeTop);
315
case TokenStream.SWITCH : {
316
iCodeTop = updateLineNumber(node, iCodeTop);
317
iCodeTop = generateICode(child, iCodeTop);
318
int theLocalSlot = itsData.itsMaxLocals++;
319
iCodeTop = addByte((byte) TokenStream.NEWTEMP, iCodeTop);
320
iCodeTop = addByte((byte)theLocalSlot, iCodeTop);
321
iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
324
reminder - below we construct new GOTO nodes that aren't
325
linked into the tree just for the purpose of having a node
326
to pass to the addGoto routine. (Parallels codegen here).
329
Vector cases = (Vector) node.getProp(Node.CASES_PROP);
330
for (int i = 0; i < cases.size(); i++) {
331
Node thisCase = (Node)cases.elementAt(i);
332
Node first = thisCase.getFirstChild();
333
// the case expression is the firstmost child
334
// the rest will be generated when the case
335
// statements are encountered as siblings of
336
// the switch statement.
337
iCodeTop = generateICode(first, iCodeTop);
338
iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);
340
if (itsStackDepth > itsData.itsMaxStack)
341
itsData.itsMaxStack = itsStackDepth;
342
iCodeTop = addByte((byte) theLocalSlot, iCodeTop);
343
iCodeTop = addByte((byte) TokenStream.SHEQ, iCodeTop);
344
Node target = new Node(TokenStream.TARGET);
345
thisCase.addChildAfter(target, first);
346
Node branch = new Node(TokenStream.IFEQ);
347
branch.putProp(Node.TARGET_PROP, target);
348
iCodeTop = addGoto(branch, TokenStream.IFEQ,
353
Node defaultNode = (Node) node.getProp(Node.DEFAULT_PROP);
354
if (defaultNode != null) {
355
Node defaultTarget = new Node(TokenStream.TARGET);
356
defaultNode.getFirstChild().addChildToFront(defaultTarget);
357
Node branch = new Node(TokenStream.GOTO);
358
branch.putProp(Node.TARGET_PROP, defaultTarget);
359
iCodeTop = addGoto(branch, TokenStream.GOTO,
363
Node breakTarget = (Node) node.getProp(Node.BREAK_PROP);
364
Node branch = new Node(TokenStream.GOTO);
365
branch.putProp(Node.TARGET_PROP, breakTarget);
366
iCodeTop = addGoto(branch, TokenStream.GOTO,
371
case TokenStream.TARGET : {
372
Object lblObect = node.getProp(Node.LABEL_PROP);
373
if (lblObect == null) {
374
int label = markLabel(acquireLabel(), iCodeTop);
375
node.putProp(Node.LABEL_PROP, new Integer(label));
378
int label = ((Integer)lblObect).intValue();
379
markLabel(label, iCodeTop);
381
// if this target has a FINALLY_PROP, it is a JSR target
382
// and so has a PC value on the top of the stack
383
if (node.getProp(Node.FINALLY_PROP) != null) {
385
if (itsStackDepth > itsData.itsMaxStack)
386
itsData.itsMaxStack = itsStackDepth;
391
case TokenStream.EQOP :
392
case TokenStream.RELOP : {
393
iCodeTop = generateICode(child, iCodeTop);
394
child = child.getNextSibling();
395
iCodeTop = generateICode(child, iCodeTop);
396
int op = node.getInt();
397
if (version == Context.VERSION_1_2) {
398
if (op == TokenStream.EQ)
399
op = TokenStream.SHEQ;
400
else if (op == TokenStream.NE)
401
op = TokenStream.SHNE;
403
iCodeTop = addByte((byte) op, iCodeTop);
408
case TokenStream.NEW :
409
case TokenStream.CALL : {
410
if (itsSourceFile != null && (itsData.itsSourceFile == null || ! itsSourceFile.equals(itsData.itsSourceFile)))
411
itsData.itsSourceFile = itsSourceFile;
412
iCodeTop = addByte((byte)TokenStream.SOURCEFILE, iCodeTop);
415
short nameIndex = -1;
416
while (child != null) {
417
iCodeTop = generateICode(child, iCodeTop);
418
if (nameIndex == -1) {
419
if (child.getType() == TokenStream.NAME)
420
nameIndex = (short)(itsData.itsStringTableIndex - 1);
421
else if (child.getType() == TokenStream.GETPROP)
422
nameIndex = (short)(itsData.itsStringTableIndex - 1);
424
child = child.getNextSibling();
427
if (node.getProp(Node.SPECIALCALL_PROP) != null) {
428
// embed line number and source filename
429
iCodeTop = addByte((byte) TokenStream.CALLSPECIAL, iCodeTop);
430
iCodeTop = addByte((byte)(itsLineNumber >> 8), iCodeTop);
431
iCodeTop = addByte((byte)(itsLineNumber & 0xff), iCodeTop);
432
iCodeTop = addString(itsSourceFile, iCodeTop);
434
iCodeTop = addByte((byte) type, iCodeTop);
435
iCodeTop = addByte((byte)(nameIndex >> 8), iCodeTop);
436
iCodeTop = addByte((byte)(nameIndex & 0xFF), iCodeTop);
439
itsStackDepth -= (childCount - 1); // always a result value
440
// subtract from child count to account for [thisObj &] fun
441
if (type == TokenStream.NEW)
445
iCodeTop = addByte((byte)(childCount >> 8), iCodeTop);
446
iCodeTop = addByte((byte)(childCount & 0xff), iCodeTop);
447
if (childCount > itsData.itsMaxArgs)
448
itsData.itsMaxArgs = childCount;
450
iCodeTop = addByte((byte)TokenStream.SOURCEFILE, iCodeTop);
454
case TokenStream.NEWLOCAL :
455
case TokenStream.NEWTEMP : {
456
iCodeTop = generateICode(child, iCodeTop);
457
iCodeTop = addByte((byte) TokenStream.NEWTEMP, iCodeTop);
458
iCodeTop = addLocalRef(node, iCodeTop);
462
case TokenStream.USELOCAL : {
463
if (node.getProp(Node.TARGET_PROP) != null)
464
iCodeTop = addByte((byte) TokenStream.RETSUB, iCodeTop);
466
iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);
468
if (itsStackDepth > itsData.itsMaxStack)
469
itsData.itsMaxStack = itsStackDepth;
471
Node temp = (Node) node.getProp(Node.LOCAL_PROP);
472
iCodeTop = addLocalRef(temp, iCodeTop);
476
case TokenStream.USETEMP : {
477
iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);
478
Node temp = (Node) node.getProp(Node.TEMP_PROP);
479
iCodeTop = addLocalRef(temp, iCodeTop);
481
if (itsStackDepth > itsData.itsMaxStack)
482
itsData.itsMaxStack = itsStackDepth;
486
case TokenStream.IFEQ :
487
case TokenStream.IFNE :
488
iCodeTop = generateICode(child, iCodeTop);
489
itsStackDepth--; // after the conditional GOTO, really
491
case TokenStream.GOTO :
492
iCodeTop = addGoto(node, (byte) type, iCodeTop);
495
case TokenStream.JSR : {
497
mark the target with a FINALLY_PROP to indicate
498
that it will have an incoming PC value on the top
501
This only works if the target follows the JSR
505
Node target = (Node)(node.getProp(Node.TARGET_PROP));
506
target.putProp(Node.FINALLY_PROP, node);
507
iCodeTop = addGoto(node, TokenStream.GOSUB, iCodeTop);
511
case TokenStream.AND : {
512
iCodeTop = generateICode(child, iCodeTop);
513
iCodeTop = addByte((byte) TokenStream.DUP, iCodeTop);
515
if (itsStackDepth > itsData.itsMaxStack)
516
itsData.itsMaxStack = itsStackDepth;
517
int falseTarget = acquireLabel();
518
iCodeTop = addGoto(falseTarget, TokenStream.IFNE,
520
iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
522
child = child.getNextSibling();
523
iCodeTop = generateICode(child, iCodeTop);
524
markLabel(falseTarget, iCodeTop);
528
case TokenStream.OR : {
529
iCodeTop = generateICode(child, iCodeTop);
530
iCodeTop = addByte((byte) TokenStream.DUP, iCodeTop);
532
if (itsStackDepth > itsData.itsMaxStack)
533
itsData.itsMaxStack = itsStackDepth;
534
int trueTarget = acquireLabel();
535
iCodeTop = addGoto(trueTarget, TokenStream.IFEQ,
537
iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
539
child = child.getNextSibling();
540
iCodeTop = generateICode(child, iCodeTop);
541
markLabel(trueTarget, iCodeTop);
545
case TokenStream.GETPROP : {
546
iCodeTop = generateICode(child, iCodeTop);
547
String s = (String) node.getProp(Node.SPECIAL_PROP_PROP);
549
if (s.equals("__proto__"))
550
iCodeTop = addByte((byte) TokenStream.GETPROTO, iCodeTop);
552
if (s.equals("__parent__"))
553
iCodeTop = addByte((byte) TokenStream.GETSCOPEPARENT, iCodeTop);
558
child = child.getNextSibling();
559
iCodeTop = generateICode(child, iCodeTop);
560
iCodeTop = addByte((byte) TokenStream.GETPROP, iCodeTop);
566
case TokenStream.DELPROP :
567
case TokenStream.BITAND :
568
case TokenStream.BITOR :
569
case TokenStream.BITXOR :
570
case TokenStream.LSH :
571
case TokenStream.RSH :
572
case TokenStream.URSH :
573
case TokenStream.ADD :
574
case TokenStream.SUB :
575
case TokenStream.MOD :
576
case TokenStream.DIV :
577
case TokenStream.MUL :
578
case TokenStream.GETELEM :
579
iCodeTop = generateICode(child, iCodeTop);
580
child = child.getNextSibling();
581
iCodeTop = generateICode(child, iCodeTop);
582
iCodeTop = addByte((byte) type, iCodeTop);
586
case TokenStream.CONVERT : {
587
iCodeTop = generateICode(child, iCodeTop);
588
Object toType = node.getProp(Node.TYPE_PROP);
589
if (toType == ScriptRuntime.NumberClass)
590
iCodeTop = addByte((byte) TokenStream.POS, iCodeTop);
596
case TokenStream.UNARYOP :
597
iCodeTop = generateICode(child, iCodeTop);
598
switch (node.getInt()) {
599
case TokenStream.VOID :
600
iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
601
iCodeTop = addByte((byte) TokenStream.UNDEFINED, iCodeTop);
603
case TokenStream.NOT : {
604
int trueTarget = acquireLabel();
605
int beyond = acquireLabel();
606
iCodeTop = addGoto(trueTarget, TokenStream.IFEQ,
608
iCodeTop = addByte((byte) TokenStream.TRUE, iCodeTop);
609
iCodeTop = addGoto(beyond, TokenStream.GOTO,
611
markLabel(trueTarget, iCodeTop);
612
iCodeTop = addByte((byte) TokenStream.FALSE, iCodeTop);
613
markLabel(beyond, iCodeTop);
616
case TokenStream.BITNOT :
617
iCodeTop = addByte((byte) TokenStream.BITNOT, iCodeTop);
619
case TokenStream.TYPEOF :
620
iCodeTop = addByte((byte) TokenStream.TYPEOF, iCodeTop);
622
case TokenStream.SUB :
623
iCodeTop = addByte((byte) TokenStream.NEG, iCodeTop);
625
case TokenStream.ADD :
626
iCodeTop = addByte((byte) TokenStream.POS, iCodeTop);
634
case TokenStream.SETPROP : {
635
iCodeTop = generateICode(child, iCodeTop);
636
child = child.getNextSibling();
637
iCodeTop = generateICode(child, iCodeTop);
638
String s = (String) node.getProp(Node.SPECIAL_PROP_PROP);
640
if (s.equals("__proto__"))
641
iCodeTop = addByte((byte) TokenStream.SETPROTO, iCodeTop);
643
if (s.equals("__parent__"))
644
iCodeTop = addByte((byte) TokenStream.SETPARENT, iCodeTop);
649
child = child.getNextSibling();
650
iCodeTop = generateICode(child, iCodeTop);
651
iCodeTop = addByte((byte) TokenStream.SETPROP, iCodeTop);
657
case TokenStream.SETELEM :
658
iCodeTop = generateICode(child, iCodeTop);
659
child = child.getNextSibling();
660
iCodeTop = generateICode(child, iCodeTop);
661
child = child.getNextSibling();
662
iCodeTop = generateICode(child, iCodeTop);
663
iCodeTop = addByte((byte) type, iCodeTop);
667
case TokenStream.SETNAME :
668
iCodeTop = generateICode(child, iCodeTop);
669
child = child.getNextSibling();
670
iCodeTop = generateICode(child, iCodeTop);
671
iCodeTop = addByte((byte) TokenStream.SETNAME, iCodeTop);
672
iCodeTop = addString(firstChild.getString(), iCodeTop);
676
case TokenStream.TYPEOF : {
677
String name = node.getString();
679
// use typeofname if an activation frame exists
680
// since the vars all exist there instead of in jregs
681
if (itsInFunctionFlag && !itsData.itsNeedsActivation)
682
index = itsVariableTable.getOrdinal(name);
684
iCodeTop = addByte((byte) TokenStream.TYPEOFNAME, iCodeTop);
685
iCodeTop = addString(name, iCodeTop);
688
iCodeTop = addByte((byte) TokenStream.GETVAR, iCodeTop);
689
iCodeTop = addByte((byte) index, iCodeTop);
690
iCodeTop = addByte((byte) TokenStream.TYPEOF, iCodeTop);
693
if (itsStackDepth > itsData.itsMaxStack)
694
itsData.itsMaxStack = itsStackDepth;
698
case TokenStream.PARENT :
699
iCodeTop = generateICode(child, iCodeTop);
700
iCodeTop = addByte((byte) TokenStream.GETPARENT, iCodeTop);
703
case TokenStream.GETBASE :
704
case TokenStream.BINDNAME :
705
case TokenStream.NAME :
706
case TokenStream.STRING :
707
iCodeTop = addByte((byte) type, iCodeTop);
708
iCodeTop = addString(node.getString(), iCodeTop);
710
if (itsStackDepth > itsData.itsMaxStack)
711
itsData.itsMaxStack = itsStackDepth;
714
case TokenStream.INC :
715
case TokenStream.DEC : {
716
int childType = child.getType();
718
case TokenStream.GETVAR : {
719
String name = child.getString();
720
if (itsData.itsNeedsActivation) {
721
iCodeTop = addByte((byte) TokenStream.SCOPE, iCodeTop);
722
iCodeTop = addByte((byte) TokenStream.STRING, iCodeTop);
723
iCodeTop = addString(name, iCodeTop);
725
if (itsStackDepth > itsData.itsMaxStack)
726
itsData.itsMaxStack = itsStackDepth;
727
iCodeTop = addByte((byte)
728
(type == TokenStream.INC
729
? TokenStream.PROPINC
730
: TokenStream.PROPDEC),
735
iCodeTop = addByte((byte)
736
(type == TokenStream.INC
738
: TokenStream.VARDEC),
740
int i = itsVariableTable.getOrdinal(name);
741
iCodeTop = addByte((byte)i, iCodeTop);
743
if (itsStackDepth > itsData.itsMaxStack)
744
itsData.itsMaxStack = itsStackDepth;
748
case TokenStream.GETPROP :
749
case TokenStream.GETELEM : {
750
Node getPropChild = child.getFirstChild();
751
iCodeTop = generateICode(getPropChild,
753
getPropChild = getPropChild.getNextSibling();
754
iCodeTop = generateICode(getPropChild,
756
if (childType == TokenStream.GETPROP)
757
iCodeTop = addByte((byte)
758
(type == TokenStream.INC
759
? TokenStream.PROPINC
760
: TokenStream.PROPDEC),
763
iCodeTop = addByte((byte)
764
(type == TokenStream.INC
765
? TokenStream.ELEMINC
766
: TokenStream.ELEMDEC),
772
iCodeTop = addByte((byte)
773
(type == TokenStream.INC
774
? TokenStream.NAMEINC
775
: TokenStream.NAMEDEC),
777
iCodeTop = addString(child.getString(),
780
if (itsStackDepth > itsData.itsMaxStack)
781
itsData.itsMaxStack = itsStackDepth;
788
case TokenStream.NUMBER : {
789
double num = node.getDouble();
791
iCodeTop = addByte((byte) TokenStream.ZERO, iCodeTop);
793
else if (num == 1.0) {
794
iCodeTop = addByte((byte) TokenStream.ONE, iCodeTop);
797
iCodeTop = addByte((byte) TokenStream.NUMBER, iCodeTop);
798
iCodeTop = addNumber(num, iCodeTop);
801
if (itsStackDepth > itsData.itsMaxStack)
802
itsData.itsMaxStack = itsStackDepth;
806
case TokenStream.POP :
807
case TokenStream.POPV :
808
iCodeTop = updateLineNumber(node, iCodeTop);
809
case TokenStream.ENTERWITH :
810
iCodeTop = generateICode(child, iCodeTop);
811
iCodeTop = addByte((byte) type, iCodeTop);
815
case TokenStream.GETTHIS :
816
iCodeTop = generateICode(child, iCodeTop);
817
iCodeTop = addByte((byte) type, iCodeTop);
820
case TokenStream.NEWSCOPE :
821
iCodeTop = addByte((byte) type, iCodeTop);
823
if (itsStackDepth > itsData.itsMaxStack)
824
itsData.itsMaxStack = itsStackDepth;
827
case TokenStream.LEAVEWITH :
828
iCodeTop = addByte((byte) type, iCodeTop);
831
case TokenStream.TRY : {
833
if (itsTryDepth > itsData.itsMaxTryDepth)
834
itsData.itsMaxTryDepth = itsTryDepth;
835
Node catchTarget = (Node)node.getProp(Node.TARGET_PROP);
836
Node finallyTarget = (Node)node.getProp(Node.FINALLY_PROP);
837
if (catchTarget == null) {
838
iCodeTop = addByte((byte) TokenStream.TRY, iCodeTop);
839
iCodeTop = addByte((byte)0, iCodeTop);
840
iCodeTop = addByte((byte)0, iCodeTop);
844
addGoto(node, TokenStream.TRY, iCodeTop);
845
int finallyHandler = 0;
846
if (finallyTarget != null) {
847
finallyHandler = acquireLabel();
848
int theLabel = finallyHandler & 0x7FFFFFFF;
849
itsLabelTable[theLabel].addFixup(iCodeTop);
851
iCodeTop = addByte((byte)0, iCodeTop);
852
iCodeTop = addByte((byte)0, iCodeTop);
854
Node lastChild = null;
856
when we encounter the child of the catchTarget, we
857
set the stackDepth to 1 to account for the incoming
860
boolean insertedEndTry = false;
861
while (child != null) {
862
if (catchTarget != null && lastChild == catchTarget) {
864
if (itsStackDepth > itsData.itsMaxStack)
865
itsData.itsMaxStack = itsStackDepth;
868
When the following child is the catchTarget
869
(or the finallyTarget if there are no catches),
870
the current child is the goto at the end of
871
the try statemets, we need to emit the endtry
874
Node nextSibling = child.getNextSibling();
875
if (!insertedEndTry && nextSibling != null &&
876
(nextSibling == catchTarget ||
877
nextSibling == finallyTarget))
879
iCodeTop = addByte((byte) TokenStream.ENDTRY,
881
insertedEndTry = true;
883
iCodeTop = generateICode(child, iCodeTop);
885
child = child.getNextSibling();
888
if (finallyTarget != null) {
889
// normal flow goes around the finally handler stublet
890
int skippy = acquireLabel();
892
addGoto(skippy, TokenStream.GOTO, iCodeTop);
893
// on entry the stack will have the exception object
894
markLabel(finallyHandler, iCodeTop);
896
if (itsStackDepth > itsData.itsMaxStack)
897
itsData.itsMaxStack = itsStackDepth;
898
int theLocalSlot = itsData.itsMaxLocals++;
899
iCodeTop = addByte((byte) TokenStream.NEWTEMP, iCodeTop);
900
iCodeTop = addByte((byte)theLocalSlot, iCodeTop);
901
iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
903
= (Integer)(finallyTarget.getProp(Node.LABEL_PROP));
904
iCodeTop = addGoto(finallyLabel.intValue(),
905
TokenStream.GOSUB, iCodeTop);
906
iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);
907
iCodeTop = addByte((byte)theLocalSlot, iCodeTop);
908
iCodeTop = addByte((byte) TokenStream.JTHROW, iCodeTop);
910
markLabel(skippy, iCodeTop);
916
case TokenStream.THROW :
917
iCodeTop = updateLineNumber(node, iCodeTop);
918
iCodeTop = generateICode(child, iCodeTop);
919
iCodeTop = addByte((byte) TokenStream.THROW, iCodeTop);
923
case TokenStream.RETURN :
924
iCodeTop = updateLineNumber(node, iCodeTop);
926
iCodeTop = generateICode(child, iCodeTop);
928
iCodeTop = addByte((byte) TokenStream.UNDEFINED, iCodeTop);
930
if (itsStackDepth > itsData.itsMaxStack)
931
itsData.itsMaxStack = itsStackDepth;
933
iCodeTop = addGoto(node, TokenStream.RETURN, iCodeTop);
937
case TokenStream.GETVAR : {
938
String name = node.getString();
939
if (itsData.itsNeedsActivation) {
940
// SETVAR handled this by turning into a SETPROP, but
941
// we can't do that to a GETVAR without manufacturing
942
// bogus children. Instead we use a special op to
943
// push the current scope.
944
iCodeTop = addByte((byte) TokenStream.SCOPE, iCodeTop);
945
iCodeTop = addByte((byte) TokenStream.STRING, iCodeTop);
946
iCodeTop = addString(name, iCodeTop);
948
if (itsStackDepth > itsData.itsMaxStack)
949
itsData.itsMaxStack = itsStackDepth;
950
iCodeTop = addByte((byte) TokenStream.GETPROP, iCodeTop);
954
int index = itsVariableTable.getOrdinal(name);
955
iCodeTop = addByte((byte) TokenStream.GETVAR, iCodeTop);
956
iCodeTop = addByte((byte)index, iCodeTop);
958
if (itsStackDepth > itsData.itsMaxStack)
959
itsData.itsMaxStack = itsStackDepth;
964
case TokenStream.SETVAR : {
965
if (itsData.itsNeedsActivation) {
966
child.setType(TokenStream.BINDNAME);
967
node.setType(TokenStream.SETNAME);
968
iCodeTop = generateICode(node, iCodeTop);
971
String name = child.getString();
972
child = child.getNextSibling();
973
iCodeTop = generateICode(child, iCodeTop);
974
int index = itsVariableTable.getOrdinal(name);
975
iCodeTop = addByte((byte) TokenStream.SETVAR, iCodeTop);
976
iCodeTop = addByte((byte)index, iCodeTop);
981
case TokenStream.PRIMARY:
982
iCodeTop = addByte((byte) node.getInt(), iCodeTop);
984
if (itsStackDepth > itsData.itsMaxStack)
985
itsData.itsMaxStack = itsStackDepth;
988
case TokenStream.ENUMINIT :
989
iCodeTop = generateICode(child, iCodeTop);
990
iCodeTop = addByte((byte) TokenStream.ENUMINIT, iCodeTop);
991
iCodeTop = addLocalRef(node, iCodeTop);
995
case TokenStream.ENUMNEXT : {
996
iCodeTop = addByte((byte) TokenStream.ENUMNEXT, iCodeTop);
997
Node init = (Node)node.getProp(Node.ENUM_PROP);
998
iCodeTop = addLocalRef(init, iCodeTop);
1000
if (itsStackDepth > itsData.itsMaxStack)
1001
itsData.itsMaxStack = itsStackDepth;
1005
case TokenStream.ENUMDONE :
1006
// could release the local here??
1009
case TokenStream.OBJECT : {
1010
Node regexp = (Node) node.getProp(Node.REGEXP_PROP);
1011
int index = ((Integer)(regexp.getProp(
1012
Node.REGEXP_PROP))).intValue();
1013
iCodeTop = addByte((byte) TokenStream.OBJECT, iCodeTop);
1014
iCodeTop = addByte((byte)(index >> 8), iCodeTop);
1015
iCodeTop = addByte((byte)(index & 0xff), iCodeTop);
1017
if (itsStackDepth > itsData.itsMaxStack)
1018
itsData.itsMaxStack = itsStackDepth;
1029
private int addLocalRef(Node node, int iCodeTop)
1032
Integer localProp = (Integer)node.getProp(Node.LOCAL_PROP);
1033
if (localProp == null) {
1034
theLocalSlot = itsData.itsMaxLocals++;
1035
node.putProp(Node.LOCAL_PROP, new Integer(theLocalSlot));
1038
theLocalSlot = localProp.intValue();
1039
iCodeTop = addByte((byte)theLocalSlot, iCodeTop);
1040
if (theLocalSlot >= itsData.itsMaxLocals)
1041
itsData.itsMaxLocals = theLocalSlot + 1;
1045
private int addGoto(Node node, int gotoOp, int iCodeTop)
1048
if (node.getType() == TokenStream.RETURN) {
1049
if (itsEpilogLabel == -1)
1050
itsEpilogLabel = acquireLabel();
1051
targetLabel = itsEpilogLabel;
1054
Node target = (Node)(node.getProp(Node.TARGET_PROP));
1055
Object lblObect = target.getProp(Node.LABEL_PROP);
1056
if (lblObect == null) {
1057
targetLabel = acquireLabel();
1058
target.putProp(Node.LABEL_PROP, new Integer(targetLabel));
1061
targetLabel = ((Integer)lblObect).intValue();
1063
iCodeTop = addGoto(targetLabel, (byte) gotoOp, iCodeTop);
1067
private int addGoto(int targetLabel, int gotoOp, int iCodeTop)
1069
int gotoPC = iCodeTop;
1070
iCodeTop = addByte((byte) gotoOp, iCodeTop);
1071
int theLabel = targetLabel & 0x7FFFFFFF;
1072
int targetPC = itsLabelTable[theLabel].getPC();
1073
if (targetPC != -1) {
1074
short offset = (short)(targetPC - gotoPC);
1075
iCodeTop = addByte((byte)(offset >> 8), iCodeTop);
1076
iCodeTop = addByte((byte)offset, iCodeTop);
1079
itsLabelTable[theLabel].addFixup(gotoPC + 1);
1080
iCodeTop = addByte((byte)0, iCodeTop);
1081
iCodeTop = addByte((byte)0, iCodeTop);
1086
private final int addByte(byte b, int iCodeTop) {
1087
if (itsData.itsICode.length == iCodeTop) {
1088
byte[] ba = new byte[iCodeTop * 2];
1089
System.arraycopy(itsData.itsICode, 0, ba, 0, iCodeTop);
1090
itsData.itsICode = ba;
1092
itsData.itsICode[iCodeTop++] = b;
1096
private final int addString(String str, int iCodeTop)
1098
int index = itsData.itsStringTableIndex;
1099
if (itsData.itsStringTable.length == index) {
1100
String[] sa = new String[index * 2];
1101
System.arraycopy(itsData.itsStringTable, 0, sa, 0, index);
1102
itsData.itsStringTable = sa;
1104
itsData.itsStringTable[index] = str;
1105
itsData.itsStringTableIndex = index + 1;
1107
iCodeTop = addByte((byte)(index >> 8), iCodeTop);
1108
iCodeTop = addByte((byte)(index & 0xFF), iCodeTop);
1112
private final int addNumber(double num, int iCodeTop)
1114
int index = itsData.itsNumberTableIndex;
1115
if (itsData.itsNumberTable.length == index) {
1116
double[] na = new double[index * 2];
1117
System.arraycopy(itsData.itsNumberTable, 0, na, 0, index);
1118
itsData.itsNumberTable = na;
1120
itsData.itsNumberTable[index] = num;
1121
itsData.itsNumberTableIndex = index + 1;
1123
iCodeTop = addByte((byte)(index >> 8), iCodeTop);
1124
iCodeTop = addByte((byte)(index & 0xFF), iCodeTop);
1128
private static String getString(String[] theStringTable, byte[] iCode,
1131
int index = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);
1132
return theStringTable[index];
1135
private static double getNumber(double[] theNumberTable, byte[] iCode,
1138
int index = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);
1139
return theNumberTable[index];
1142
private static int getTarget(byte[] iCode, int pc)
1144
int displacement = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);
1145
return pc - 1 + displacement;
1148
static PrintWriter out;
1152
out = new PrintWriter(new FileOutputStream("icode.txt"));
1155
catch (IOException x) {
1160
private static void dumpICode(InterpreterData theData) {
1163
int iCodeLength = theData.itsICodeTop;
1164
byte iCode[] = theData.itsICode;
1166
out = new PrintWriter(new FileOutputStream("icode.txt", true));
1167
out.println("ICode dump, for " + theData.itsName + ", length = " + iCodeLength);
1168
out.println("MaxStack = " + theData.itsMaxStack);
1170
for (int pc = 0; pc < iCodeLength; ) {
1171
out.print("[" + pc + "] ");
1172
switch ((int)(iCode[pc] & 0xff)) {
1173
case TokenStream.SCOPE :
1174
case TokenStream.GETPROTO :
1175
case TokenStream.GETPARENT :
1176
case TokenStream.GETSCOPEPARENT :
1177
case TokenStream.SETPROTO :
1178
case TokenStream.SETPARENT :
1179
case TokenStream.DELPROP :
1180
case TokenStream.TYPEOF :
1181
case TokenStream.NEWSCOPE :
1182
case TokenStream.ENTERWITH :
1183
case TokenStream.LEAVEWITH :
1184
case TokenStream.ENDTRY :
1185
case TokenStream.THROW :
1186
case TokenStream.JTHROW :
1187
case TokenStream.GETTHIS :
1188
case TokenStream.SETELEM :
1189
case TokenStream.GETELEM :
1190
case TokenStream.SETPROP :
1191
case TokenStream.GETPROP :
1192
case TokenStream.PROPINC :
1193
case TokenStream.PROPDEC :
1194
case TokenStream.ELEMINC :
1195
case TokenStream.ELEMDEC :
1196
case TokenStream.BITNOT :
1197
case TokenStream.BITAND :
1198
case TokenStream.BITOR :
1199
case TokenStream.BITXOR :
1200
case TokenStream.LSH :
1201
case TokenStream.RSH :
1202
case TokenStream.URSH :
1203
case TokenStream.NEG :
1204
case TokenStream.POS :
1205
case TokenStream.SUB :
1206
case TokenStream.MUL :
1207
case TokenStream.DIV :
1208
case TokenStream.MOD :
1209
case TokenStream.ADD :
1210
case TokenStream.POPV :
1211
case TokenStream.POP :
1212
case TokenStream.DUP :
1213
case TokenStream.LT :
1214
case TokenStream.GT :
1215
case TokenStream.LE :
1216
case TokenStream.GE :
1217
case TokenStream.IN :
1218
case TokenStream.INSTANCEOF :
1219
case TokenStream.EQ :
1220
case TokenStream.NE :
1221
case TokenStream.SHEQ :
1222
case TokenStream.SHNE :
1223
case TokenStream.ZERO :
1224
case TokenStream.ONE :
1225
case TokenStream.NULL :
1226
case TokenStream.THIS :
1227
case TokenStream.THISFN :
1228
case TokenStream.FALSE :
1229
case TokenStream.TRUE :
1230
case TokenStream.UNDEFINED :
1231
case TokenStream.SOURCEFILE :
1232
out.println(TokenStream.tokenToName(iCode[pc] & 0xff));
1234
case TokenStream.GOSUB :
1235
case TokenStream.RETURN :
1236
case TokenStream.GOTO :
1237
case TokenStream.IFEQ :
1238
case TokenStream.IFNE : {
1239
int newPC = getTarget(iCode, pc + 1);
1241
TokenStream.tokenToName(iCode[pc] & 0xff) +
1246
case TokenStream.TRY : {
1247
int newPC1 = getTarget(iCode, pc + 1);
1248
int newPC2 = getTarget(iCode, pc + 3);
1250
TokenStream.tokenToName(iCode[pc] & 0xff) +
1256
case TokenStream.RETSUB :
1257
case TokenStream.ENUMINIT :
1258
case TokenStream.ENUMNEXT :
1259
case TokenStream.VARINC :
1260
case TokenStream.VARDEC :
1261
case TokenStream.GETVAR :
1262
case TokenStream.SETVAR :
1263
case TokenStream.NEWTEMP :
1264
case TokenStream.USETEMP : {
1265
int slot = (iCode[pc + 1] & 0xFF);
1267
TokenStream.tokenToName(iCode[pc] & 0xff) +
1272
case TokenStream.CALLSPECIAL : {
1273
int line = (iCode[pc + 1] << 8)
1274
| (iCode[pc + 2] & 0xFF);
1275
String name = getString(theData.itsStringTable,
1277
int count = (iCode[pc + 5] << 8) | (iCode[pc + 6] & 0xFF);
1279
TokenStream.tokenToName(iCode[pc] & 0xff) +
1280
" " + count + " " + line + " " + name);
1284
case TokenStream.OBJECT :
1285
case TokenStream.CLOSURE :
1286
case TokenStream.NEW :
1287
case TokenStream.CALL : {
1288
int count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);
1290
TokenStream.tokenToName(iCode[pc] & 0xff) +
1291
" " + count + " \"" +
1292
getString(theData.itsStringTable, iCode,
1297
case TokenStream.NUMBER :
1299
TokenStream.tokenToName(iCode[pc] & 0xff) +
1300
" " + getNumber(theData.itsNumberTable,
1304
case TokenStream.TYPEOFNAME :
1305
case TokenStream.GETBASE :
1306
case TokenStream.BINDNAME :
1307
case TokenStream.SETNAME :
1308
case TokenStream.NAME :
1309
case TokenStream.NAMEINC :
1310
case TokenStream.NAMEDEC :
1311
case TokenStream.STRING :
1313
TokenStream.tokenToName(iCode[pc] & 0xff) +
1315
getString(theData.itsStringTable, iCode, pc + 1) +
1319
case TokenStream.LINE : {
1320
int line = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
1322
TokenStream.tokenToName(iCode[pc] & 0xff) + " : " + line);
1328
throw new RuntimeException("Unknown icode : "
1329
+ (iCode[pc] & 0xff) + " @ pc : " + pc);
1335
catch (IOException x) {}
1339
private static void createFunctionObject(InterpretedFunction fn,
1342
fn.setPrototype(ScriptableObject.getClassPrototype(scope, "Function"));
1343
fn.setParentScope(scope);
1344
InterpreterData id = fn.itsData;
1345
if (id.itsName.length() == 0)
1347
if ((id.itsFunctionType == FunctionNode.FUNCTION_STATEMENT &&
1348
fn.itsClosure == null) ||
1349
(id.itsFunctionType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT &&
1350
fn.itsClosure != null))
1352
ScriptRuntime.setProp(scope, fn.itsData.itsName, fn, scope);
1356
public static Object interpret(Context cx, Scriptable scope,
1357
Scriptable thisObj, Object[] args,
1358
NativeFunction fnOrScript,
1359
InterpreterData theData)
1360
throws JavaScriptException
1365
final int maxStack = theData.itsMaxStack;
1366
final int maxVars = (fnOrScript.argNames == null)
1367
? 0 : fnOrScript.argNames.length;
1368
final int maxLocals = theData.itsMaxLocals;
1369
final int maxTryDepth = theData.itsMaxTryDepth;
1371
final int VAR_SHFT = maxStack;
1372
final int LOCAL_SHFT = VAR_SHFT + maxVars;
1373
final int TRY_SCOPE_SHFT = LOCAL_SHFT + maxLocals;
1375
// stack[0 <= i < VAR_SHFT]: stack data
1376
// stack[VAR_SHFT <= i < LOCAL_SHFT]: variables
1377
// stack[LOCAL_SHFT <= i < TRY_SCOPE_SHFT]: used for newtemp/usetemp
1378
// stack[TRY_SCOPE_SHFT <= i]: try scopes
1379
// when 0 <= i < LOCAL_SHFT and stack[x] == DBL_MRK,
1380
// sDbl[i] gives the number value
1382
final Object DBL_MRK = Interpreter.DBL_MRK;
1384
Object[] stack = new Object[TRY_SCOPE_SHFT + maxTryDepth];
1385
double[] sDbl = new double[TRY_SCOPE_SHFT];
1387
byte[] iCode = theData.itsICode;
1389
int iCodeLength = theData.itsICodeTop;
1391
final Scriptable undefined = Undefined.instance;
1393
int definedArgs = fnOrScript.argCount;
1394
if (definedArgs != 0) {
1395
if (definedArgs > args.length) { definedArgs = args.length; }
1396
for (i = 0; i != definedArgs; ++i) {
1397
stack[VAR_SHFT + i] = args[i];
1400
for (i = definedArgs; i != maxVars; ++i) {
1401
stack[VAR_SHFT + i] = undefined;
1405
if (theData.itsNestedFunctions != null) {
1406
for (i = 0; i < theData.itsNestedFunctions.length; i++)
1407
createFunctionObject(theData.itsNestedFunctions[i], scope);
1428
int[] catchStack = null;
1429
int tryStackTop = 0;
1430
InterpreterFrame frame = null;
1432
if (cx.debugger != null) {
1433
frame = new InterpreterFrame(scope, theData, fnOrScript);
1434
cx.pushFrame(frame);
1437
if (maxTryDepth != 0) {
1438
// catchStack[2 * i]: starting pc of catch block
1439
// catchStack[2 * i + 1]: starting pc of finally block
1440
catchStack = new int[maxTryDepth * 2];
1443
/* Save the security domain. Must restore upon normal exit.
1444
* If we exit the interpreter loop by throwing an exception,
1445
* set cx.interpreterSecurityDomain to null, and require the
1446
* catching function to restore it.
1448
Object savedSecurityDomain = cx.interpreterSecurityDomain;
1449
cx.interpreterSecurityDomain = theData.securityDomain;
1450
Object result = undefined;
1452
int pcPrevBranch = pc;
1453
final int instructionThreshold = cx.instructionThreshold;
1454
// During function call this will be set to -1 so catch can properly
1456
int instructionCount = cx.instructionCount;
1457
// arbitrary number to add to instructionCount when calling
1459
final int INVOCATION_COST = 100;
1461
while (pc < iCodeLength) {
1463
switch (iCode[pc] & 0xff) {
1464
case TokenStream.ENDTRY :
1467
case TokenStream.TRY :
1468
i = getTarget(iCode, pc + 1);
1470
catchStack[tryStackTop * 2] = i;
1471
i = getTarget(iCode, pc + 3);
1472
if (i == (pc + 2)) i = 0;
1473
catchStack[tryStackTop * 2 + 1] = i;
1474
stack[TRY_SCOPE_SHFT + tryStackTop] = scope;
1478
case TokenStream.GE :
1480
rhs = stack[stackTop + 1];
1481
lhs = stack[stackTop];
1482
if (rhs == DBL_MRK || lhs == DBL_MRK) {
1483
rDbl = stack_double(stack, sDbl, stackTop + 1);
1484
lDbl = stack_double(stack, sDbl, stackTop);
1485
valBln = (rDbl == rDbl && lDbl == lDbl
1489
valBln = (1 == ScriptRuntime.cmp_LE(rhs, lhs));
1491
stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
1493
case TokenStream.LE :
1495
rhs = stack[stackTop + 1];
1496
lhs = stack[stackTop];
1497
if (rhs == DBL_MRK || lhs == DBL_MRK) {
1498
rDbl = stack_double(stack, sDbl, stackTop + 1);
1499
lDbl = stack_double(stack, sDbl, stackTop);
1500
valBln = (rDbl == rDbl && lDbl == lDbl
1504
valBln = (1 == ScriptRuntime.cmp_LE(lhs, rhs));
1506
stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
1508
case TokenStream.GT :
1510
rhs = stack[stackTop + 1];
1511
lhs = stack[stackTop];
1512
if (rhs == DBL_MRK || lhs == DBL_MRK) {
1513
rDbl = stack_double(stack, sDbl, stackTop + 1);
1514
lDbl = stack_double(stack, sDbl, stackTop);
1515
valBln = (rDbl == rDbl && lDbl == lDbl
1519
valBln = (1 == ScriptRuntime.cmp_LT(rhs, lhs));
1521
stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
1523
case TokenStream.LT :
1525
rhs = stack[stackTop + 1];
1526
lhs = stack[stackTop];
1527
if (rhs == DBL_MRK || lhs == DBL_MRK) {
1528
rDbl = stack_double(stack, sDbl, stackTop + 1);
1529
lDbl = stack_double(stack, sDbl, stackTop);
1530
valBln = (rDbl == rDbl && lDbl == lDbl
1534
valBln = (1 == ScriptRuntime.cmp_LT(lhs, rhs));
1536
stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
1538
case TokenStream.IN :
1539
rhs = stack[stackTop];
1540
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
1542
lhs = stack[stackTop];
1543
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1544
valBln = ScriptRuntime.in(lhs, rhs, scope);
1545
stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
1547
case TokenStream.INSTANCEOF :
1548
rhs = stack[stackTop];
1549
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
1551
lhs = stack[stackTop];
1552
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1553
valBln = ScriptRuntime.instanceOf(scope, lhs, rhs);
1554
stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
1556
case TokenStream.EQ :
1558
valBln = do_eq(stack, sDbl, stackTop);
1559
stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
1561
case TokenStream.NE :
1563
valBln = !do_eq(stack, sDbl, stackTop);
1564
stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
1566
case TokenStream.SHEQ :
1568
valBln = do_sheq(stack, sDbl, stackTop);
1569
stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
1571
case TokenStream.SHNE :
1573
valBln = !do_sheq(stack, sDbl, stackTop);
1574
stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
1576
case TokenStream.IFNE :
1577
val = stack[stackTop];
1578
if (val != DBL_MRK) {
1579
valBln = !ScriptRuntime.toBoolean(val);
1582
valDbl = sDbl[stackTop];
1583
valBln = !(valDbl == valDbl && valDbl != 0.0);
1587
if (instructionThreshold != 0) {
1588
instructionCount += pc + 3 - pcPrevBranch;
1589
if (instructionCount > instructionThreshold) {
1590
cx.observeInstructionCount
1592
instructionCount = 0;
1595
pcPrevBranch = pc = getTarget(iCode, pc + 1);
1600
case TokenStream.IFEQ :
1601
val = stack[stackTop];
1602
if (val != DBL_MRK) {
1603
valBln = ScriptRuntime.toBoolean(val);
1606
valDbl = sDbl[stackTop];
1607
valBln = (valDbl == valDbl && valDbl != 0.0);
1611
if (instructionThreshold != 0) {
1612
instructionCount += pc + 3 - pcPrevBranch;
1613
if (instructionCount > instructionThreshold) {
1614
cx.observeInstructionCount
1616
instructionCount = 0;
1619
pcPrevBranch = pc = getTarget(iCode, pc + 1);
1624
case TokenStream.GOTO :
1625
if (instructionThreshold != 0) {
1626
instructionCount += pc + 3 - pcPrevBranch;
1627
if (instructionCount > instructionThreshold) {
1628
cx.observeInstructionCount(instructionCount);
1629
instructionCount = 0;
1632
pcPrevBranch = pc = getTarget(iCode, pc + 1);
1634
case TokenStream.GOSUB :
1635
sDbl[++stackTop] = pc + 3;
1636
if (instructionThreshold != 0) {
1637
instructionCount += pc + 3 - pcPrevBranch;
1638
if (instructionCount > instructionThreshold) {
1639
cx.observeInstructionCount(instructionCount);
1640
instructionCount = 0;
1643
pcPrevBranch = pc = getTarget(iCode, pc + 1); continue;
1644
case TokenStream.RETSUB :
1645
slot = (iCode[pc + 1] & 0xFF);
1646
if (instructionThreshold != 0) {
1647
instructionCount += pc + 2 - pcPrevBranch;
1648
if (instructionCount > instructionThreshold) {
1649
cx.observeInstructionCount(instructionCount);
1650
instructionCount = 0;
1653
pcPrevBranch = pc = (int)sDbl[LOCAL_SHFT + slot];
1655
case TokenStream.POP :
1658
case TokenStream.DUP :
1659
stack[stackTop + 1] = stack[stackTop];
1660
sDbl[stackTop + 1] = sDbl[stackTop];
1663
case TokenStream.POPV :
1664
result = stack[stackTop];
1665
if (result == DBL_MRK)
1666
result = doubleWrap(sDbl[stackTop]);
1669
case TokenStream.RETURN :
1670
result = stack[stackTop];
1671
if (result == DBL_MRK)
1672
result = doubleWrap(sDbl[stackTop]);
1674
pc = getTarget(iCode, pc + 1);
1676
case TokenStream.BITNOT :
1677
rIntValue = stack_int32(stack, sDbl, stackTop);
1678
stack[stackTop] = DBL_MRK;
1679
sDbl[stackTop] = ~rIntValue;
1681
case TokenStream.BITAND :
1682
rIntValue = stack_int32(stack, sDbl, stackTop);
1684
lIntValue = stack_int32(stack, sDbl, stackTop);
1685
stack[stackTop] = DBL_MRK;
1686
sDbl[stackTop] = lIntValue & rIntValue;
1688
case TokenStream.BITOR :
1689
rIntValue = stack_int32(stack, sDbl, stackTop);
1691
lIntValue = stack_int32(stack, sDbl, stackTop);
1692
stack[stackTop] = DBL_MRK;
1693
sDbl[stackTop] = lIntValue | rIntValue;
1695
case TokenStream.BITXOR :
1696
rIntValue = stack_int32(stack, sDbl, stackTop);
1698
lIntValue = stack_int32(stack, sDbl, stackTop);
1699
stack[stackTop] = DBL_MRK;
1700
sDbl[stackTop] = lIntValue ^ rIntValue;
1702
case TokenStream.LSH :
1703
rIntValue = stack_int32(stack, sDbl, stackTop);
1705
lIntValue = stack_int32(stack, sDbl, stackTop);
1706
stack[stackTop] = DBL_MRK;
1707
sDbl[stackTop] = lIntValue << rIntValue;
1709
case TokenStream.RSH :
1710
rIntValue = stack_int32(stack, sDbl, stackTop);
1712
lIntValue = stack_int32(stack, sDbl, stackTop);
1713
stack[stackTop] = DBL_MRK;
1714
sDbl[stackTop] = lIntValue >> rIntValue;
1716
case TokenStream.URSH :
1717
rIntValue = stack_int32(stack, sDbl, stackTop) & 0x1F;
1719
lLongValue = stack_uint32(stack, sDbl, stackTop);
1720
stack[stackTop] = DBL_MRK;
1721
sDbl[stackTop] = lLongValue >>> rIntValue;
1723
case TokenStream.ADD :
1725
do_add(stack, sDbl, stackTop);
1727
case TokenStream.SUB :
1728
rDbl = stack_double(stack, sDbl, stackTop);
1730
lDbl = stack_double(stack, sDbl, stackTop);
1731
stack[stackTop] = DBL_MRK;
1732
sDbl[stackTop] = lDbl - rDbl;
1734
case TokenStream.NEG :
1735
rDbl = stack_double(stack, sDbl, stackTop);
1736
stack[stackTop] = DBL_MRK;
1737
sDbl[stackTop] = -rDbl;
1739
case TokenStream.POS :
1740
rDbl = stack_double(stack, sDbl, stackTop);
1741
stack[stackTop] = DBL_MRK;
1742
sDbl[stackTop] = rDbl;
1744
case TokenStream.MUL :
1745
rDbl = stack_double(stack, sDbl, stackTop);
1747
lDbl = stack_double(stack, sDbl, stackTop);
1748
stack[stackTop] = DBL_MRK;
1749
sDbl[stackTop] = lDbl * rDbl;
1751
case TokenStream.DIV :
1752
rDbl = stack_double(stack, sDbl, stackTop);
1754
lDbl = stack_double(stack, sDbl, stackTop);
1755
stack[stackTop] = DBL_MRK;
1756
// Detect the divide by zero or let Java do it ?
1757
sDbl[stackTop] = lDbl / rDbl;
1759
case TokenStream.MOD :
1760
rDbl = stack_double(stack, sDbl, stackTop);
1762
lDbl = stack_double(stack, sDbl, stackTop);
1763
stack[stackTop] = DBL_MRK;
1764
sDbl[stackTop] = lDbl % rDbl;
1766
case TokenStream.BINDNAME :
1768
ScriptRuntime.bind(scope,
1769
getString(theData.itsStringTable,
1773
case TokenStream.GETBASE :
1775
ScriptRuntime.getBase(scope,
1776
getString(theData.itsStringTable,
1780
case TokenStream.SETNAME :
1781
rhs = stack[stackTop];
1782
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
1784
lhs = stack[stackTop];
1785
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1786
// what about class cast exception here ?
1787
stack[stackTop] = ScriptRuntime.setName
1788
((Scriptable)lhs, rhs, scope,
1789
getString(theData.itsStringTable, iCode, pc + 1));
1792
case TokenStream.DELPROP :
1793
rhs = stack[stackTop];
1794
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
1796
lhs = stack[stackTop];
1797
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1798
stack[stackTop] = ScriptRuntime.delete(lhs, rhs);
1800
case TokenStream.GETPROP :
1801
name = (String)stack[stackTop];
1803
lhs = stack[stackTop];
1804
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1806
= ScriptRuntime.getProp(lhs, name, scope);
1808
case TokenStream.SETPROP :
1809
rhs = stack[stackTop];
1810
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
1812
name = (String)stack[stackTop];
1814
lhs = stack[stackTop];
1815
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1817
= ScriptRuntime.setProp(lhs, name, rhs, scope);
1819
case TokenStream.GETELEM :
1820
id = stack[stackTop];
1821
if (id == DBL_MRK) id = doubleWrap(sDbl[stackTop]);
1823
lhs = stack[stackTop];
1824
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1826
= ScriptRuntime.getElem(lhs, id, scope);
1828
case TokenStream.SETELEM :
1829
rhs = stack[stackTop];
1830
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
1832
id = stack[stackTop];
1833
if (id == DBL_MRK) id = doubleWrap(sDbl[stackTop]);
1835
lhs = stack[stackTop];
1836
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1838
= ScriptRuntime.setElem(lhs, id, rhs, scope);
1840
case TokenStream.PROPINC :
1841
name = (String)stack[stackTop];
1843
lhs = stack[stackTop];
1844
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1846
= ScriptRuntime.postIncrement(lhs, name, scope);
1848
case TokenStream.PROPDEC :
1849
name = (String)stack[stackTop];
1851
lhs = stack[stackTop];
1852
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1854
= ScriptRuntime.postDecrement(lhs, name, scope);
1856
case TokenStream.ELEMINC :
1857
rhs = stack[stackTop];
1858
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
1860
lhs = stack[stackTop];
1861
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1863
= ScriptRuntime.postIncrementElem(lhs, rhs, scope);
1865
case TokenStream.ELEMDEC :
1866
rhs = stack[stackTop];
1867
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
1869
lhs = stack[stackTop];
1870
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1872
= ScriptRuntime.postDecrementElem(lhs, rhs, scope);
1874
case TokenStream.GETTHIS :
1875
lhs = stack[stackTop];
1876
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1878
= ScriptRuntime.getThis((Scriptable)lhs);
1880
case TokenStream.NEWTEMP :
1881
slot = (iCode[++pc] & 0xFF);
1882
stack[LOCAL_SHFT + slot] = stack[stackTop];
1883
sDbl[LOCAL_SHFT + slot] = sDbl[stackTop];
1885
case TokenStream.USETEMP :
1886
slot = (iCode[++pc] & 0xFF);
1888
stack[stackTop] = stack[LOCAL_SHFT + slot];
1889
sDbl[stackTop] = sDbl[LOCAL_SHFT + slot];
1891
case TokenStream.CALLSPECIAL :
1892
if (instructionThreshold != 0) {
1893
instructionCount += INVOCATION_COST;
1894
cx.instructionCount = instructionCount;
1895
instructionCount = -1;
1897
int lineNum = (iCode[pc + 1] << 8)
1898
| (iCode[pc + 2] & 0xFF);
1899
name = getString(theData.itsStringTable, iCode, pc + 3);
1900
count = (iCode[pc + 5] << 8) | (iCode[pc + 6] & 0xFF);
1901
outArgs = new Object[count];
1902
for (i = count - 1; i >= 0; i--) {
1903
val = stack[stackTop];
1905
val = doubleWrap(sDbl[stackTop]);
1909
rhs = stack[stackTop];
1910
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
1912
lhs = stack[stackTop];
1913
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1914
stack[stackTop] = ScriptRuntime.callSpecial(
1915
cx, lhs, rhs, outArgs,
1916
thisObj, scope, name, lineNum);
1918
instructionCount = cx.instructionCount;
1920
case TokenStream.CALL :
1921
if (instructionThreshold != 0) {
1922
instructionCount += INVOCATION_COST;
1923
cx.instructionCount = instructionCount;
1924
instructionCount = -1;
1926
cx.instructionCount = instructionCount;
1927
count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);
1928
outArgs = new Object[count];
1929
for (i = count - 1; i >= 0; i--) {
1930
val = stack[stackTop];
1932
val = doubleWrap(sDbl[stackTop]);
1936
rhs = stack[stackTop];
1937
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
1939
lhs = stack[stackTop];
1940
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1941
if (lhs == undefined) {
1942
lhs = getString(theData.itsStringTable, iCode,
1945
Scriptable calleeScope = scope;
1946
if (theData.itsNeedsActivation) {
1947
calleeScope = ScriptableObject.
1948
getTopLevelScope(scope);
1950
stack[stackTop] = ScriptRuntime.call(cx, lhs, rhs,
1953
pc += 4; instructionCount = cx.instructionCount;
1955
case TokenStream.NEW :
1956
if (instructionThreshold != 0) {
1957
instructionCount += INVOCATION_COST;
1958
cx.instructionCount = instructionCount;
1959
instructionCount = -1;
1961
count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);
1962
outArgs = new Object[count];
1963
for (i = count - 1; i >= 0; i--) {
1964
val = stack[stackTop];
1966
val = doubleWrap(sDbl[stackTop]);
1970
lhs = stack[stackTop];
1971
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1972
if (lhs == undefined &&
1973
(iCode[pc+1] << 8) + (iCode[pc+2] & 0xFF) != -1)
1975
// special code for better error message for call
1977
lhs = getString(theData.itsStringTable, iCode,
1980
stack[stackTop] = ScriptRuntime.newObject(cx, lhs,
1983
pc += 4; instructionCount = cx.instructionCount;
1985
case TokenStream.TYPEOF :
1986
lhs = stack[stackTop];
1987
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
1988
stack[stackTop] = ScriptRuntime.typeof(lhs);
1990
case TokenStream.TYPEOFNAME :
1991
name = getString(theData.itsStringTable, iCode, pc + 1);
1993
= ScriptRuntime.typeofName(scope, name);
1996
case TokenStream.STRING :
1997
stack[++stackTop] = getString(theData.itsStringTable,
2001
case TokenStream.NUMBER :
2003
stack[stackTop] = DBL_MRK;
2004
sDbl[stackTop] = getNumber(theData.itsNumberTable,
2008
case TokenStream.NAME :
2009
stack[++stackTop] = ScriptRuntime.name(scope,
2010
getString(theData.itsStringTable,
2014
case TokenStream.NAMEINC :
2015
stack[++stackTop] = ScriptRuntime.postIncrement(scope,
2016
getString(theData.itsStringTable,
2020
case TokenStream.NAMEDEC :
2021
stack[++stackTop] = ScriptRuntime.postDecrement(scope,
2022
getString(theData.itsStringTable,
2026
case TokenStream.SETVAR :
2027
slot = (iCode[++pc] & 0xFF);
2028
stack[VAR_SHFT + slot] = stack[stackTop];
2029
sDbl[VAR_SHFT + slot] = sDbl[stackTop];
2031
case TokenStream.GETVAR :
2032
slot = (iCode[++pc] & 0xFF);
2034
stack[stackTop] = stack[VAR_SHFT + slot];
2035
sDbl[stackTop] = sDbl[VAR_SHFT + slot];
2037
case TokenStream.VARINC :
2038
slot = (iCode[++pc] & 0xFF);
2040
stack[stackTop] = stack[VAR_SHFT + slot];
2041
sDbl[stackTop] = sDbl[VAR_SHFT + slot];
2042
stack[VAR_SHFT + slot] = DBL_MRK;
2043
sDbl[VAR_SHFT + slot]
2044
= stack_double(stack, sDbl, stackTop) + 1.0;
2046
case TokenStream.VARDEC :
2047
slot = (iCode[++pc] & 0xFF);
2049
stack[stackTop] = stack[VAR_SHFT + slot];
2050
sDbl[stackTop] = sDbl[VAR_SHFT + slot];
2051
stack[VAR_SHFT + slot] = DBL_MRK;
2052
sDbl[VAR_SHFT + slot]
2053
= stack_double(stack, sDbl, stackTop) - 1.0;
2055
case TokenStream.ZERO :
2057
stack[stackTop] = DBL_MRK;
2060
case TokenStream.ONE :
2062
stack[stackTop] = DBL_MRK;
2065
case TokenStream.NULL :
2066
stack[++stackTop] = null;
2068
case TokenStream.THIS :
2069
stack[++stackTop] = thisObj;
2071
case TokenStream.THISFN :
2072
stack[++stackTop] = fnOrScript;
2074
case TokenStream.FALSE :
2075
stack[++stackTop] = Boolean.FALSE;
2077
case TokenStream.TRUE :
2078
stack[++stackTop] = Boolean.TRUE;
2080
case TokenStream.UNDEFINED :
2081
stack[++stackTop] = Undefined.instance;
2083
case TokenStream.THROW :
2084
result = stack[stackTop];
2085
if (result == DBL_MRK)
2086
result = doubleWrap(sDbl[stackTop]);
2088
throw new JavaScriptException(result);
2089
case TokenStream.JTHROW :
2090
result = stack[stackTop];
2091
// No need to check for DBL_MRK: result is Exception
2093
if (result instanceof JavaScriptException)
2094
throw (JavaScriptException)result;
2096
throw (RuntimeException)result;
2097
case TokenStream.ENTERWITH :
2098
lhs = stack[stackTop];
2099
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
2101
scope = ScriptRuntime.enterWith(lhs, scope);
2103
case TokenStream.LEAVEWITH :
2104
scope = ScriptRuntime.leaveWith(scope);
2106
case TokenStream.NEWSCOPE :
2107
stack[++stackTop] = ScriptRuntime.newScope();
2109
case TokenStream.ENUMINIT :
2110
slot = (iCode[++pc] & 0xFF);
2111
lhs = stack[stackTop];
2112
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
2114
stack[LOCAL_SHFT + slot]
2115
= ScriptRuntime.initEnum(lhs, scope);
2117
case TokenStream.ENUMNEXT :
2118
slot = (iCode[++pc] & 0xFF);
2119
val = stack[LOCAL_SHFT + slot];
2121
stack[stackTop] = ScriptRuntime.
2122
nextEnum((Enumeration)val);
2124
case TokenStream.GETPROTO :
2125
lhs = stack[stackTop];
2126
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
2127
stack[stackTop] = ScriptRuntime.getProto(lhs, scope);
2129
case TokenStream.GETPARENT :
2130
lhs = stack[stackTop];
2131
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
2132
stack[stackTop] = ScriptRuntime.getParent(lhs);
2134
case TokenStream.GETSCOPEPARENT :
2135
lhs = stack[stackTop];
2136
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
2137
stack[stackTop] = ScriptRuntime.getParent(lhs, scope);
2139
case TokenStream.SETPROTO :
2140
rhs = stack[stackTop];
2141
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
2143
lhs = stack[stackTop];
2144
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
2146
= ScriptRuntime.setProto(lhs, rhs, scope);
2148
case TokenStream.SETPARENT :
2149
rhs = stack[stackTop];
2150
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
2152
lhs = stack[stackTop];
2153
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
2155
= ScriptRuntime.setParent(lhs, rhs, scope);
2157
case TokenStream.SCOPE :
2158
stack[++stackTop] = scope;
2160
case TokenStream.CLOSURE :
2161
i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
2163
= new InterpretedFunction(
2164
theData.itsNestedFunctions[i],
2166
createFunctionObject(
2167
(InterpretedFunction)stack[stackTop], scope);
2170
case TokenStream.OBJECT :
2171
i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
2172
stack[++stackTop] = theData.itsRegExpLiterals[i];
2175
case TokenStream.SOURCEFILE :
2176
cx.interpreterSourceFile = theData.itsSourceFile;
2178
case TokenStream.LINE :
2179
case TokenStream.BREAKPOINT :
2180
i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
2181
cx.interpreterLine = i;
2183
frame.setLineNumber(i);
2184
if ((iCode[pc] & 0xff) == TokenStream.BREAKPOINT ||
2187
cx.getDebuggableEngine().
2188
getDebugger().handleBreakpointHit(cx);
2194
throw new RuntimeException("Unknown icode : "
2195
+ (iCode[pc] & 0xff) + " @ pc : " + pc);
2199
catch (Throwable ex) {
2200
cx.interpreterSecurityDomain = null;
2202
if (instructionThreshold != 0) {
2203
if (instructionCount < 0) {
2204
// throw during function call
2205
instructionCount = cx.instructionCount;
2208
// throw during any other operation
2209
instructionCount += pc - pcPrevBranch;
2210
cx.instructionCount = instructionCount;
2214
final int SCRIPT_THROW = 0, ECMA = 1, RUNTIME = 2, OTHER = 3;
2217
Object errObj; // Object seen by catch
2218
if (ex instanceof JavaScriptException) {
2219
errObj = ScriptRuntime.
2220
unwrapJavaScriptException((JavaScriptException)ex);
2221
exType = SCRIPT_THROW;
2223
else if (ex instanceof EcmaError) {
2224
// an offical ECMA error object,
2225
errObj = ((EcmaError)ex).getErrorObject();
2228
else if (ex instanceof RuntimeException) {
2233
errObj = ex; // Error instance
2237
if (exType != OTHER && cx.debugger != null) {
2238
cx.debugger.handleExceptionThrown(cx, errObj);
2241
boolean rethrow = true;
2242
if (exType != OTHER && tryStackTop > 0) {
2244
if (exType == SCRIPT_THROW || exType == ECMA) {
2245
// Check for catch only for
2246
// JavaScriptException and EcmaError
2247
pc = catchStack[tryStackTop * 2];
2254
pc = catchStack[tryStackTop * 2 + 1];
2256
// has finally block
2267
if (exType == SCRIPT_THROW)
2268
throw (JavaScriptException)ex;
2269
if (exType == ECMA || exType == RUNTIME)
2270
throw (RuntimeException)ex;
2274
// We caught an exception,
2276
// Notify instruction observer if necessary
2277
// and point pcPrevBranch to start of catch/finally block
2278
if (instructionThreshold != 0) {
2279
if (instructionCount > instructionThreshold) {
2280
// Note: this can throw Error
2281
cx.observeInstructionCount(instructionCount);
2282
instructionCount = 0;
2287
// prepare stack and restore this function's security domain.
2288
scope = (Scriptable)stack[TRY_SCOPE_SHFT + tryStackTop];
2291
cx.interpreterSecurityDomain = theData.securityDomain;
2294
cx.interpreterSecurityDomain = savedSecurityDomain;
2298
if (instructionThreshold != 0) {
2299
if (instructionCount > instructionThreshold) {
2300
cx.observeInstructionCount(instructionCount);
2301
instructionCount = 0;
2303
cx.instructionCount = instructionCount;
2309
private static Object doubleWrap(double x) {
2310
return new Double(x);
2313
private static int stack_int32(Object[] stack, double[] stackDbl, int i) {
2314
Object x = stack[i];
2315
return (x != DBL_MRK)
2316
? ScriptRuntime.toInt32(x)
2317
: ScriptRuntime.toInt32(stackDbl[i]);
2320
private static long stack_uint32(Object[] stack, double[] stackDbl, int i) {
2321
Object x = stack[i];
2322
return (x != DBL_MRK)
2323
? ScriptRuntime.toUint32(x)
2324
: ScriptRuntime.toUint32(stackDbl[i]);
2327
private static double stack_double(Object[] stack, double[] stackDbl,
2330
Object x = stack[i];
2331
return (x != DBL_MRK) ? ScriptRuntime.toNumber(x) : stackDbl[i];
2334
private static void do_add(Object[] stack, double[] stackDbl, int stackTop)
2336
Object rhs = stack[stackTop + 1];
2337
Object lhs = stack[stackTop];
2338
if (rhs == DBL_MRK) {
2339
double rDbl = stackDbl[stackTop + 1];
2340
if (lhs == DBL_MRK) {
2341
stackDbl[stackTop] += rDbl;
2344
do_add(lhs, rDbl, stack, stackDbl, stackTop, true);
2347
else if (lhs == DBL_MRK) {
2348
do_add(rhs, stackDbl[stackTop], stack, stackDbl, stackTop, false);
2351
if (lhs instanceof Scriptable)
2352
lhs = ((Scriptable) lhs).getDefaultValue(null);
2353
if (rhs instanceof Scriptable)
2354
rhs = ((Scriptable) rhs).getDefaultValue(null);
2355
if (lhs instanceof String || rhs instanceof String) {
2356
stack[stackTop] = ScriptRuntime.toString(lhs)
2357
+ ScriptRuntime.toString(rhs);
2360
double lDbl = (lhs instanceof Number)
2361
? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);
2362
double rDbl = (rhs instanceof Number)
2363
? ((Number)rhs).doubleValue() : ScriptRuntime.toNumber(rhs);
2364
stack[stackTop] = DBL_MRK;
2365
stackDbl[stackTop] = lDbl + rDbl;
2370
// x + y when x is Number, see
2371
private static void do_add
2372
(Object lhs, double rDbl,
2373
Object[] stack, double[] stackDbl, int stackTop,
2374
boolean left_right_order)
2376
if (lhs instanceof Scriptable) {
2377
if (lhs == Undefined.instance) { lhs = ScriptRuntime.NaNobj; }
2378
lhs = ((Scriptable)lhs).getDefaultValue(null);
2380
if (lhs instanceof String) {
2381
if (left_right_order) {
2382
stack[stackTop] = (String)lhs + ScriptRuntime.toString(rDbl);
2385
stack[stackTop] = ScriptRuntime.toString(rDbl) + (String)lhs;
2389
double lDbl = (lhs instanceof Number)
2390
? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);
2391
stack[stackTop] = DBL_MRK;
2392
stackDbl[stackTop] = lDbl + rDbl;
2398
private static boolean do_eq(Object[] stack, double[] stackDbl,
2402
Object rhs = stack[stackTop + 1];
2403
Object lhs = stack[stackTop];
2404
if (rhs == DBL_MRK) {
2405
if (lhs == DBL_MRK) {
2406
result = (stackDbl[stackTop] == stackDbl[stackTop + 1]);
2409
result = do_eq(stackDbl[stackTop + 1], lhs);
2413
if (lhs == DBL_MRK) {
2414
result = do_eq(stackDbl[stackTop], rhs);
2417
result = ScriptRuntime.eq(lhs, rhs);
2423
// Optimized version of ScriptRuntime.eq if x is a Number
2424
private static boolean do_eq(double x, Object y) {
2426
if (y instanceof Number) {
2427
return x == ((Number) y).doubleValue();
2429
if (y instanceof String) {
2430
return x == ScriptRuntime.toNumber((String)y);
2432
if (y instanceof Boolean) {
2433
return x == (((Boolean)y).booleanValue() ? 1 : 0);
2435
if (y instanceof Scriptable) {
2436
if (y == Undefined.instance) { return false; }
2437
y = ScriptRuntime.toPrimitive(y);
2444
private static boolean do_sheq(Object[] stack, double[] stackDbl,
2448
Object rhs = stack[stackTop + 1];
2449
Object lhs = stack[stackTop];
2450
if (rhs == DBL_MRK) {
2451
double rDbl = stackDbl[stackTop + 1];
2452
if (lhs == DBL_MRK) {
2453
result = (stackDbl[stackTop] == rDbl);
2456
result = (lhs instanceof Number);
2458
result = (((Number)lhs).doubleValue() == rDbl);
2462
else if (rhs instanceof Number) {
2463
double rDbl = ((Number)rhs).doubleValue();
2464
if (lhs == DBL_MRK) {
2465
result = (stackDbl[stackTop] == rDbl);
2468
result = (lhs instanceof Number);
2470
result = (((Number)lhs).doubleValue() == rDbl);
2475
result = ScriptRuntime.shallowEq(lhs, rhs);
2480
private int version;
2481
private boolean inLineStepMode;
2482
private StringBuffer debugSource;
2484
private static final Object DBL_MRK = new Object();
1
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3
* The contents of this file are subject to the Netscape Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/NPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is Rhino code, released
16
* The Initial Developer of the Original Code is Netscape
17
* Communications Corporation. Portions created by Netscape are
18
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
30
* Alternatively, the contents of this file may be used under the
31
* terms of the GNU Public License (the "GPL"), in which case the
32
* provisions of the GPL are applicable instead of those above.
33
* If you wish to allow use of your version of this file only
34
* under the terms of the GPL and not to allow others to use your
35
* version of this file under the NPL, indicate your decision by
36
* deleting the provisions above and replace them with the notice
37
* and other provisions required by the GPL. If you do not delete
38
* the provisions above, a recipient may use your version of this
39
* file under either the NPL or the GPL.
42
package org.mozilla.javascript;
46
import org.mozilla.javascript.debug.*;
47
import org.mozilla.javascript.continuations.Continuation;
49
public class Interpreter
52
// Additional interpreter-specific codes
54
private static final int
56
// Stack: ... value1 -> ... value1 value1
59
// Stack: ... value2 value1 -> ... value2 value1 value2 value1
62
// Stack: ... value2 value1 -> ... value1 value2
65
// Stack: ... value1 -> ...
68
// Store stack top into return register and then pop it
69
Icode_POP_RESULT = -5,
71
// To jump conditionally and pop additional stack value
74
// various types of ++/--
75
Icode_VAR_INC_DEC = -7,
76
Icode_NAME_INC_DEC = -8,
77
Icode_PROP_INC_DEC = -9,
78
Icode_ELEM_INC_DEC = -10,
79
Icode_REF_INC_DEC = -11,
81
// helper codes to deal with activation
84
// load/save scope from/to local
85
Icode_SCOPE_LOAD = -13,
86
Icode_SCOPE_SAVE = -14,
88
Icode_TYPEOFNAME = -15,
90
// helper for function calls
91
Icode_NAME_AND_THIS = -16,
92
Icode_PROP_AND_THIS = -17,
93
Icode_ELEM_AND_THIS = -18,
94
Icode_VALUE_AND_THIS = -19,
96
// Create closure object for nested functions
97
Icode_CLOSURE_EXPR = -20,
98
Icode_CLOSURE_STMT = -21,
101
Icode_CALLSPECIAL = -22,
103
// To return undefined value
104
Icode_RETUNDEF = -23,
106
// Exception handling implementation
108
Icode_STARTSUB = -25,
111
// To indicating a line number change in icodes.
114
// To store shorts and ints inline
115
Icode_SHORTNUMBER = -28,
116
Icode_INTNUMBER = -29,
118
// To create and populate array to hold values for [] and {} literals
119
Icode_LITERAL_NEW = -30,
120
Icode_LITERAL_SET = -31,
122
// Array literal with skipped index like [1,,2]
123
Icode_SPARE_ARRAYLIT = -32,
125
// Load index register to prepare for the following index operation
126
Icode_REG_IND_C0 = -33,
127
Icode_REG_IND_C1 = -34,
128
Icode_REG_IND_C2 = -35,
129
Icode_REG_IND_C3 = -36,
130
Icode_REG_IND_C4 = -37,
131
Icode_REG_IND_C5 = -38,
132
Icode_REG_IND1 = -39,
133
Icode_REG_IND2 = -40,
134
Icode_REG_IND4 = -41,
136
// Load string register to prepare for the following string operation
137
Icode_REG_STR_C0 = -42,
138
Icode_REG_STR_C1 = -43,
139
Icode_REG_STR_C2 = -44,
140
Icode_REG_STR_C3 = -45,
141
Icode_REG_STR1 = -46,
142
Icode_REG_STR2 = -47,
143
Icode_REG_STR4 = -48,
145
// Version of getvar/setvar that read var index directly from bytecode
154
// entrance and exit from .()
158
Icode_TAIL_CALL = -56,
160
// Clear local to allow GC its context
161
Icode_LOCAL_CLEAR = -57,
168
private CompilerEnvirons compilerEnv;
170
private boolean itsInFunctionFlag;
172
private InterpreterData itsData;
173
private ScriptOrFnNode scriptOrFn;
174
private int itsICodeTop;
175
private int itsStackDepth;
176
private int itsLineNumber;
177
private int itsDoubleTableTop;
178
private ObjToIntMap itsStrings = new ObjToIntMap(20);
179
private int itsLocalTop;
181
private static final int MIN_LABEL_TABLE_SIZE = 32;
182
private static final int MIN_FIXUP_TABLE_SIZE = 40;
183
private int[] itsLabelTable;
184
private int itsLabelTableTop;
185
// itsFixupTable[i] = (label_index << 32) | fixup_site
186
private long[] itsFixupTable;
187
private int itsFixupTableTop;
188
private ObjArray itsLiteralIds = new ObjArray();
190
private int itsExceptionTableTop;
191
private static final int EXCEPTION_TRY_START_SLOT = 0;
192
private static final int EXCEPTION_TRY_END_SLOT = 1;
193
private static final int EXCEPTION_HANDLER_SLOT = 2;
194
private static final int EXCEPTION_TYPE_SLOT = 3;
195
private static final int EXCEPTION_LOCAL_SLOT = 4;
196
private static final int EXCEPTION_SCOPE_SLOT = 5;
197
// SLOT_SIZE: space for try start/end, handler, start, handler type,
198
// exception local and scope local
199
private static final int EXCEPTION_SLOT_SIZE = 6;
201
// ECF_ or Expression Context Flags constants: for now only TAIL is available
202
private static final int ECF_TAIL = 1 << 0;
205
* Class to hold data corresponding to one interpreted call stack frame.
207
private static class CallFrame implements Cloneable, Serializable
209
CallFrame parentFrame;
210
// amount of stack frames before this one on the interpretation stack
212
// If true indicates read-only frame that is a part of continuation
215
InterpretedFunction fnOrScript;
216
InterpreterData idata;
219
// stack[0 <= i < localShift]: arguments and local variables
220
// stack[localShift <= i <= emptyStackTop]: used for local temporaries
221
// stack[emptyStackTop < i < stack.length]: stack data
222
// sDbl[i]: if stack[i] is UniqueTag.DOUBLE_MARK, sDbl[i] holds the number value
226
CallFrame varSource; // defaults to this unless continuation frame
230
DebugFrame debuggerFrame;
231
boolean useActivation;
234
Scriptable[] scriptRegExps;
236
// The values that change during interpretation
242
int pcSourceLineStart;
248
CallFrame cloneFrozen()
250
if (!frozen) Kit.codeBug();
254
copy = (CallFrame)clone();
255
} catch (CloneNotSupportedException ex) {
256
throw new IllegalStateException();
259
// clone stack but keep varSource to point to values
260
// from this frame to share variables.
262
copy.stack = (Object[])stack.clone();
263
copy.sDbl = (double[])sDbl.clone();
270
private static final class ContinuationJump implements Serializable
272
CallFrame capturedFrame;
273
CallFrame branchFrame;
277
ContinuationJump(Continuation c, CallFrame current)
279
this.capturedFrame = (CallFrame)c.getImplementation();
280
if (this.capturedFrame == null || current == null) {
281
// Continuation and current execution does not share
282
// any frames if there is nothing to capture or
283
// if there is no currently executed frames
284
this.branchFrame = null;
286
// Search for branch frame where parent frame chains starting
287
// from captured and current meet.
288
CallFrame chain1 = this.capturedFrame;
289
CallFrame chain2 = current;
291
// First work parents of chain1 or chain2 until the same
293
int diff = chain1.frameIndex - chain2.frameIndex;
296
// swap to make sure that
297
// chain1.frameIndex > chain2.frameIndex and diff > 0
299
chain2 = this.capturedFrame;
303
chain1 = chain1.parentFrame;
304
} while (--diff != 0);
305
if (chain1.frameIndex != chain2.frameIndex) Kit.codeBug();
308
// Now walk parents in parallel until a shared frame is found
309
// or until the root is reached.
310
while (chain1 != chain2 && chain1 != null) {
311
chain1 = chain1.parentFrame;
312
chain2 = chain2.parentFrame;
315
this.branchFrame = chain1;
316
if (this.branchFrame != null && !this.branchFrame.frozen)
324
// Checks for byte code consistencies, good compiler can eliminate them
326
if (Token.LAST_BYTECODE_TOKEN > 127) {
327
String str = "Violation of Token.LAST_BYTECODE_TOKEN <= 127";
328
System.err.println(str);
329
throw new IllegalStateException(str);
331
if (MIN_ICODE < -128) {
332
String str = "Violation of Interpreter.MIN_ICODE >= -128";
333
System.err.println(str);
334
throw new IllegalStateException(str);
338
private static String bytecodeName(int bytecode)
340
if (!validBytecode(bytecode)) {
341
throw new IllegalArgumentException(String.valueOf(bytecode));
344
if (!Token.printICode) {
345
return String.valueOf(bytecode);
348
if (validTokenCode(bytecode)) {
349
return Token.name(bytecode);
353
case Icode_DUP: return "DUP";
354
case Icode_DUP2: return "DUP2";
355
case Icode_SWAP: return "SWAP";
356
case Icode_POP: return "POP";
357
case Icode_POP_RESULT: return "POP_RESULT";
358
case Icode_IFEQ_POP: return "IFEQ_POP";
359
case Icode_VAR_INC_DEC: return "VAR_INC_DEC";
360
case Icode_NAME_INC_DEC: return "NAME_INC_DEC";
361
case Icode_PROP_INC_DEC: return "PROP_INC_DEC";
362
case Icode_ELEM_INC_DEC: return "ELEM_INC_DEC";
363
case Icode_REF_INC_DEC: return "REF_INC_DEC";
364
case Icode_SCOPE: return "SCOPE";
365
case Icode_SCOPE_LOAD: return "SCOPE_LOAD";
366
case Icode_SCOPE_SAVE: return "SCOPE_SAVE";
367
case Icode_TYPEOFNAME: return "TYPEOFNAME";
368
case Icode_NAME_AND_THIS: return "NAME_AND_THIS";
369
case Icode_PROP_AND_THIS: return "PROP_AND_THIS";
370
case Icode_ELEM_AND_THIS: return "ELEM_AND_THIS";
371
case Icode_VALUE_AND_THIS: return "VALUE_AND_THIS";
372
case Icode_CLOSURE_EXPR: return "CLOSURE_EXPR";
373
case Icode_CLOSURE_STMT: return "CLOSURE_STMT";
374
case Icode_CALLSPECIAL: return "CALLSPECIAL";
375
case Icode_RETUNDEF: return "RETUNDEF";
376
case Icode_GOSUB: return "GOSUB";
377
case Icode_STARTSUB: return "STARTSUB";
378
case Icode_RETSUB: return "RETSUB";
379
case Icode_LINE: return "LINE";
380
case Icode_SHORTNUMBER: return "SHORTNUMBER";
381
case Icode_INTNUMBER: return "INTNUMBER";
382
case Icode_LITERAL_NEW: return "LITERAL_NEW";
383
case Icode_LITERAL_SET: return "LITERAL_SET";
384
case Icode_SPARE_ARRAYLIT: return "SPARE_ARRAYLIT";
385
case Icode_REG_IND_C0: return "REG_IND_C0";
386
case Icode_REG_IND_C1: return "REG_IND_C1";
387
case Icode_REG_IND_C2: return "REG_IND_C2";
388
case Icode_REG_IND_C3: return "REG_IND_C3";
389
case Icode_REG_IND_C4: return "REG_IND_C4";
390
case Icode_REG_IND_C5: return "REG_IND_C5";
391
case Icode_REG_IND1: return "LOAD_IND1";
392
case Icode_REG_IND2: return "LOAD_IND2";
393
case Icode_REG_IND4: return "LOAD_IND4";
394
case Icode_REG_STR_C0: return "REG_STR_C0";
395
case Icode_REG_STR_C1: return "REG_STR_C1";
396
case Icode_REG_STR_C2: return "REG_STR_C2";
397
case Icode_REG_STR_C3: return "REG_STR_C3";
398
case Icode_REG_STR1: return "LOAD_STR1";
399
case Icode_REG_STR2: return "LOAD_STR2";
400
case Icode_REG_STR4: return "LOAD_STR4";
401
case Icode_GETVAR1: return "GETVAR1";
402
case Icode_SETVAR1: return "SETVAR1";
403
case Icode_UNDEF: return "UNDEF";
404
case Icode_ZERO: return "ZERO";
405
case Icode_ONE: return "ONE";
406
case Icode_ENTERDQ: return "ENTERDQ";
407
case Icode_LEAVEDQ: return "LEAVEDQ";
408
case Icode_TAIL_CALL: return "TAIL_CALL";
409
case Icode_LOCAL_CLEAR: return "LOCAL_CLEAR";
412
// icode without name
413
throw new IllegalStateException(String.valueOf(bytecode));
416
private static boolean validIcode(int icode)
418
return MIN_ICODE <= icode && icode <= -1;
421
private static boolean validTokenCode(int token)
423
return Token.FIRST_BYTECODE_TOKEN <= token
424
&& token <= Token.LAST_BYTECODE_TOKEN;
427
private static boolean validBytecode(int bytecode)
429
return validIcode(bytecode) || validTokenCode(bytecode);
432
public Object compile(CompilerEnvirons compilerEnv,
434
String encodedSource,
435
boolean returnFunction)
437
this.compilerEnv = compilerEnv;
438
new NodeTransformer().transform(tree);
440
if (Token.printTrees) {
441
System.out.println(tree.toStringTree(tree));
444
if (returnFunction) {
445
tree = tree.getFunctionNode(0);
449
itsData = new InterpreterData(compilerEnv.getLanguageVersion(),
450
scriptOrFn.getSourceName(),
452
itsData.topLevel = true;
454
if (returnFunction) {
455
generateFunctionICode();
457
generateICodeFromTree(scriptOrFn);
463
public Script createScriptObject(Object bytecode,
464
Object staticSecurityDomain)
466
InterpreterData idata = (InterpreterData)bytecode;
467
return InterpretedFunction.createScript(itsData,
468
staticSecurityDomain);
471
public Function createFunctionObject(Context cx, Scriptable scope,
473
Object staticSecurityDomain)
475
InterpreterData idata = (InterpreterData)bytecode;
476
return InterpretedFunction.createFunction(cx, scope, itsData,
477
staticSecurityDomain);
480
private void generateFunctionICode()
482
itsInFunctionFlag = true;
484
FunctionNode theFunction = (FunctionNode)scriptOrFn;
486
itsData.itsFunctionType = theFunction.getFunctionType();
487
itsData.itsNeedsActivation = theFunction.requiresActivation();
488
itsData.itsName = theFunction.getFunctionName();
489
if (!theFunction.getIgnoreDynamicScope()) {
490
if (compilerEnv.isUseDynamicScope()) {
491
itsData.useDynamicScope = true;
495
generateICodeFromTree(theFunction.getLastChild());
498
private void generateICodeFromTree(Node tree)
500
generateNestedFunctions();
502
generateRegExpLiterals();
504
visitStatement(tree);
506
// add RETURN_RESULT only to scripts as function always ends with RETURN
507
if (itsData.itsFunctionType == 0) {
508
addToken(Token.RETURN_RESULT);
511
if (itsData.itsICode.length != itsICodeTop) {
512
// Make itsData.itsICode length exactly itsICodeTop to save memory
513
// and catch bugs with jumps beyound icode as early as possible
514
byte[] tmp = new byte[itsICodeTop];
515
System.arraycopy(itsData.itsICode, 0, tmp, 0, itsICodeTop);
516
itsData.itsICode = tmp;
518
if (itsStrings.size() == 0) {
519
itsData.itsStringTable = null;
521
itsData.itsStringTable = new String[itsStrings.size()];
522
ObjToIntMap.Iterator iter = itsStrings.newIterator();
523
for (iter.start(); !iter.done(); iter.next()) {
524
String str = (String)iter.getKey();
525
int index = iter.getValue();
526
if (itsData.itsStringTable[index] != null) Kit.codeBug();
527
itsData.itsStringTable[index] = str;
530
if (itsDoubleTableTop == 0) {
531
itsData.itsDoubleTable = null;
532
} else if (itsData.itsDoubleTable.length != itsDoubleTableTop) {
533
double[] tmp = new double[itsDoubleTableTop];
534
System.arraycopy(itsData.itsDoubleTable, 0, tmp, 0,
536
itsData.itsDoubleTable = tmp;
538
if (itsExceptionTableTop != 0
539
&& itsData.itsExceptionTable.length != itsExceptionTableTop)
541
int[] tmp = new int[itsExceptionTableTop];
542
System.arraycopy(itsData.itsExceptionTable, 0, tmp, 0,
543
itsExceptionTableTop);
544
itsData.itsExceptionTable = tmp;
547
itsData.itsMaxVars = scriptOrFn.getParamAndVarCount();
548
// itsMaxFrameArray: interpret method needs this amount for its
549
// stack and sDbl arrays
550
itsData.itsMaxFrameArray = itsData.itsMaxVars
551
+ itsData.itsMaxLocals
552
+ itsData.itsMaxStack;
554
itsData.argNames = scriptOrFn.getParamAndVarNames();
555
itsData.argCount = scriptOrFn.getParamCount();
557
itsData.encodedSourceStart = scriptOrFn.getEncodedSourceStart();
558
itsData.encodedSourceEnd = scriptOrFn.getEncodedSourceEnd();
560
if (itsLiteralIds.size() != 0) {
561
itsData.literalIds = itsLiteralIds.toArray();
564
if (Token.printICode) dumpICode(itsData);
567
private void generateNestedFunctions()
569
int functionCount = scriptOrFn.getFunctionCount();
570
if (functionCount == 0) return;
572
InterpreterData[] array = new InterpreterData[functionCount];
573
for (int i = 0; i != functionCount; i++) {
574
FunctionNode def = scriptOrFn.getFunctionNode(i);
575
Interpreter jsi = new Interpreter();
576
jsi.compilerEnv = compilerEnv;
577
jsi.scriptOrFn = def;
578
jsi.itsData = new InterpreterData(itsData);
579
jsi.generateFunctionICode();
580
array[i] = jsi.itsData;
582
itsData.itsNestedFunctions = array;
585
private void generateRegExpLiterals()
587
int N = scriptOrFn.getRegexpCount();
590
Context cx = Context.getContext();
591
RegExpProxy rep = ScriptRuntime.checkRegExpProxy(cx);
592
Object[] array = new Object[N];
593
for (int i = 0; i != N; i++) {
594
String string = scriptOrFn.getRegexpString(i);
595
String flags = scriptOrFn.getRegexpFlags(i);
596
array[i] = rep.compileRegExp(cx, string, flags);
598
itsData.itsRegExpLiterals = array;
601
private void updateLineNumber(Node node)
603
int lineno = node.getLineno();
604
if (lineno != itsLineNumber && lineno >= 0) {
605
if (itsData.firstLinePC < 0) {
606
itsData.firstLinePC = lineno;
608
itsLineNumber = lineno;
609
addIcode(Icode_LINE);
610
addUint16(lineno & 0xFFFF);
614
private RuntimeException badTree(Node node)
616
throw new RuntimeException(node.toString());
619
private void visitStatement(Node node)
621
int type = node.getType();
622
Node child = node.getFirstChild();
627
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
628
int fnType = scriptOrFn.getFunctionNode(fnIndex).
630
// Only function expressions or function expression
631
// statements needs closure code creating new function
632
// object on stack as function statements are initialized
633
// at script/function start
634
// In addition function expression can not present here
635
// at statement level, they must only present as expressions.
636
if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
637
addIndexOp(Icode_CLOSURE_STMT, fnIndex);
639
if (fnType != FunctionNode.FUNCTION_STATEMENT) {
652
updateLineNumber(node);
653
while (child != null) {
654
visitStatement(child);
655
child = child.getNext();
659
case Token.ENTERWITH:
660
visitExpression(child, 0);
661
addToken(Token.ENTERWITH);
665
case Token.LEAVEWITH:
666
addToken(Token.LEAVEWITH);
669
case Token.LOCAL_BLOCK:
671
int local = allocLocal();
672
node.putIntProp(Node.LOCAL_PROP, local);
673
updateLineNumber(node);
674
while (child != null) {
675
visitStatement(child);
676
child = child.getNext();
678
addIndexOp(Icode_LOCAL_CLEAR, local);
684
updateLineNumber(node);
685
// See comments in IRFactory.createSwitch() for description
688
Node switchNode = (Node.Jump)node;
689
visitExpression(child, 0);
690
for (Node.Jump caseNode = (Node.Jump)child.getNext();
692
caseNode = (Node.Jump)caseNode.getNext())
694
if (caseNode.getType() != Token.CASE)
695
throw badTree(caseNode);
696
Node test = caseNode.getFirstChild();
699
visitExpression(test, 0);
700
addToken(Token.SHEQ);
702
// If true, Icode_IFEQ_POP will jump and remove case
704
addGoto(caseNode.target, Icode_IFEQ_POP);
713
markTargetLabel(node);
719
Node target = ((Node.Jump)node).target;
720
visitExpression(child, 0);
721
addGoto(target, type);
728
Node target = ((Node.Jump)node).target;
729
addGoto(target, type);
735
Node target = ((Node.Jump)node).target;
736
addGoto(target, Icode_GOSUB);
742
// Account for incomming GOTOSUB address
744
int finallyRegister = getLocalBlockRef(node);
745
addIndexOp(Icode_STARTSUB, finallyRegister);
747
while (child != null) {
748
visitStatement(child);
749
child = child.getNext();
751
addIndexOp(Icode_RETSUB, finallyRegister);
755
case Token.EXPR_VOID:
756
case Token.EXPR_RESULT:
757
updateLineNumber(node);
758
visitExpression(child, 0);
759
addIcode((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT);
765
Node.Jump tryNode = (Node.Jump)node;
766
int exceptionObjectLocal = getLocalBlockRef(tryNode);
767
int scopeLocal = allocLocal();
769
addIndexOp(Icode_SCOPE_SAVE, scopeLocal);
771
int tryStart = itsICodeTop;
772
while (child != null) {
773
visitStatement(child);
774
child = child.getNext();
777
Node catchTarget = tryNode.target;
778
if (catchTarget != null) {
780
= itsLabelTable[getTargetLabel(catchTarget)];
782
tryStart, catchStartPC, catchStartPC,
783
false, exceptionObjectLocal, scopeLocal);
785
Node finallyTarget = tryNode.getFinally();
786
if (finallyTarget != null) {
788
= itsLabelTable[getTargetLabel(finallyTarget)];
790
tryStart, finallyStartPC, finallyStartPC,
791
true, exceptionObjectLocal, scopeLocal);
794
addIndexOp(Icode_LOCAL_CLEAR, scopeLocal);
795
releaseLocal(scopeLocal);
799
case Token.CATCH_SCOPE:
801
int localIndex = getLocalBlockRef(node);
802
int scopeIndex = node.getExistingIntProp(Node.CATCH_SCOPE_PROP);
803
String name = child.getString();
804
child = child.getNext();
805
visitExpression(child, 0); // load expression object
806
addStringPrefix(name);
807
addIndexPrefix(localIndex);
808
addToken(Token.CATCH_SCOPE);
809
addUint8(scopeIndex != 0 ? 1 : 0);
815
updateLineNumber(node);
816
visitExpression(child, 0);
817
addToken(Token.THROW);
818
addUint16(itsLineNumber & 0xFFFF);
823
updateLineNumber(node);
824
addIndexOp(Token.RETHROW, getLocalBlockRef(node));
828
updateLineNumber(node);
830
visitExpression(child, ECF_TAIL);
831
addToken(Token.RETURN);
834
addIcode(Icode_RETUNDEF);
838
case Token.RETURN_RESULT:
839
updateLineNumber(node);
840
addToken(Token.RETURN_RESULT);
843
case Token.ENUM_INIT_KEYS:
844
case Token.ENUM_INIT_VALUES :
845
visitExpression(child, 0);
846
addIndexOp(type, getLocalBlockRef(node));
854
if (itsStackDepth != 0) {
859
private void visitExpression(Node node, int contextFlags)
861
int type = node.getType();
862
Node child = node.getFirstChild();
863
int savedStackDepth = itsStackDepth;
864
int expectedStackDelta = 1;
869
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
870
FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
871
// See comments in visitStatement for Token.FUNCTION case
872
if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION) {
875
addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
880
case Token.LOCAL_LOAD:
882
int localIndex = getLocalBlockRef(node);
883
addIndexOp(Token.LOCAL_LOAD, localIndex);
890
Node lastChild = node.getLastChild();
891
while (child != lastChild) {
892
visitExpression(child, 0);
895
child = child.getNext();
897
// Preserve tail context flag if any
898
visitExpression(child, contextFlags & ECF_TAIL);
902
case Token.USE_STACK:
903
// Indicates that stack was modified externally,
904
// like placed catch object
909
// account for the reference represented as pair (ref, target)
910
expectedStackDelta = 2;
915
if (type == Token.NEW) {
916
visitExpression(child, 0);
918
generateCallFunAndThis(child);
921
while ((child = child.getNext()) != null) {
922
visitExpression(child, 0);
925
int callType = node.getIntProp(Node.SPECIALCALL_PROP,
926
Node.NON_SPECIALCALL);
927
if (callType != Node.NON_SPECIALCALL) {
928
// embed line number and source filename
929
addIndexOp(Icode_CALLSPECIAL, argCount);
931
addUint8(type == Token.NEW ? 1 : 0);
932
addUint16(itsLineNumber & 0xFFFF);
934
if (type == Token.CALL) {
935
if ((contextFlags & ECF_TAIL) != 0) {
936
type = Icode_TAIL_CALL;
939
addIndexOp(type, argCount);
942
if (type == Token.NEW || type == Token.REF_CALL) {
943
// new: f, args -> result
944
// ref_call: f, thisObj, args -> ref ref_target
945
stackChange(-argCount);
947
// f, thisObj, args -> result
948
stackChange(-1 - argCount);
950
if (argCount > itsData.itsMaxCalleeArgs) {
951
itsData.itsMaxCalleeArgs = argCount;
959
visitExpression(child, 0);
962
int afterSecondJumpStart = itsICodeTop;
963
int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ;
964
addForwardGoto(jump);
968
child = child.getNext();
969
// Preserve tail context flag if any
970
visitExpression(child, contextFlags & ECF_TAIL);
971
resolveForwardGoto(afterSecondJumpStart);
977
Node ifThen = child.getNext();
978
Node ifElse = ifThen.getNext();
979
visitExpression(child, 0);
980
int elseJumpStart = itsICodeTop;
981
addForwardGoto(Token.IFNE);
983
// Preserve tail context flag if any
984
visitExpression(ifThen, contextFlags & ECF_TAIL);
985
int afterElseJumpStart = itsICodeTop;
986
addForwardGoto(Token.GOTO);
987
resolveForwardGoto(elseJumpStart);
988
itsStackDepth = savedStackDepth;
989
// Preserve tail context flag if any
990
visitExpression(ifElse, contextFlags & ECF_TAIL);
991
resolveForwardGoto(afterElseJumpStart);
996
visitExpression(child, 0);
997
child = child.getNext();
998
addStringOp(Token.GETPROP, child.getString());
1019
case Token.INSTANCEOF:
1024
visitExpression(child, 0);
1025
child = child.getNext();
1026
visitExpression(child, 0);
1037
visitExpression(child, 0);
1038
if (type == Token.VOID) {
1039
addIcode(Icode_POP);
1040
addIcode(Icode_UNDEF);
1048
visitExpression(child, 0);
1054
case Token.SETPROP_OP:
1056
visitExpression(child, 0);
1057
child = child.getNext();
1058
String property = child.getString();
1059
child = child.getNext();
1060
if (type == Token.SETPROP_OP) {
1061
addIcode(Icode_DUP);
1063
addStringOp(Token.GETPROP, property);
1064
// Compensate for the following USE_STACK
1067
visitExpression(child, 0);
1068
addStringOp(Token.SETPROP, property);
1074
case Token.SETELEM_OP:
1075
visitExpression(child, 0);
1076
child = child.getNext();
1077
visitExpression(child, 0);
1078
child = child.getNext();
1079
if (type == Token.SETELEM_OP) {
1080
addIcode(Icode_DUP2);
1082
addToken(Token.GETELEM);
1084
// Compensate for the following USE_STACK
1087
visitExpression(child, 0);
1088
addToken(Token.SETELEM);
1093
case Token.SET_REF_OP:
1094
visitExpression(child, 0);
1095
child = child.getNext();
1096
if (type == Token.SET_REF_OP) {
1097
addIcode(Icode_DUP2);
1099
addToken(Token.GET_REF);
1101
// Compensate for the following USE_STACK
1104
visitExpression(child, 0);
1105
addToken(Token.SET_REF);
1111
String name = child.getString();
1112
visitExpression(child, 0);
1113
child = child.getNext();
1114
visitExpression(child, 0);
1115
addStringOp(Token.SETNAME, name);
1120
case Token.TYPEOFNAME:
1122
String name = node.getString();
1124
// use typeofname if an activation frame exists
1125
// since the vars all exist there instead of in jregs
1126
if (itsInFunctionFlag && !itsData.itsNeedsActivation)
1127
index = scriptOrFn.getParamOrVarIndex(name);
1129
addStringOp(Icode_TYPEOFNAME, name);
1132
addVarOp(Token.GETVAR, index);
1134
addToken(Token.TYPEOF);
1139
case Token.BINDNAME:
1142
addStringOp(type, node.getString());
1148
visitIncDec(node, child);
1153
double num = node.getDouble();
1154
int inum = (int)num;
1157
addIcode(Icode_ZERO);
1158
// Check for negative zero
1159
if (1.0 / num < 0.0) {
1160
addToken(Token.NEG);
1162
} else if (inum == 1) {
1163
addIcode(Icode_ONE);
1164
} else if ((short)inum == inum) {
1165
addIcode(Icode_SHORTNUMBER);
1166
// write short as uin16 bit pattern
1167
addUint16(inum & 0xFFFF);
1169
addIcode(Icode_INTNUMBER);
1173
int index = getDoubleIndex(num);
1174
addIndexOp(Token.NUMBER, index);
1182
String name = node.getString();
1183
if (itsData.itsNeedsActivation) {
1184
// SETVAR handled this by turning into a SETPROP, but
1185
// we can't do that to a GETVAR without manufacturing
1186
// bogus children. Instead we use a special op to
1187
// push the current scope.
1188
addIcode(Icode_SCOPE);
1190
addStringOp(Token.GETPROP, name);
1192
int index = scriptOrFn.getParamOrVarIndex(name);
1193
addVarOp(Token.GETVAR, index);
1201
if (itsData.itsNeedsActivation) {
1202
child.setType(Token.BINDNAME);
1203
node.setType(Token.SETNAME);
1204
visitExpression(node, 0);
1206
String name = child.getString();
1207
child = child.getNext();
1208
visitExpression(child, 0);
1209
int index = scriptOrFn.getParamOrVarIndex(name);
1210
addVarOp(Token.SETVAR, index);
1224
case Token.ENUM_NEXT:
1226
addIndexOp(type, getLocalBlockRef(node));
1232
int index = node.getExistingIntProp(Node.REGEXP_PROP);
1233
addIndexOp(Token.REGEXP, index);
1238
case Token.ARRAYLIT:
1239
case Token.OBJECTLIT:
1240
visitLiteral(node, child);
1243
case Token.REF_SPECIAL:
1244
visitExpression(child, 0);
1245
addStringOp(type, (String)node.getProp(Node.NAME_PROP));
1247
expectedStackDelta = 2;
1250
case Token.REF_MEMBER:
1251
case Token.REF_NS_MEMBER:
1252
case Token.REF_NAME:
1253
case Token.REF_NS_NAME:
1255
int memberTypeFlags = node.getIntProp(Node.MEMBER_TYPE_PROP, 0);
1256
// generate possible target, possible namespace and member
1259
visitExpression(child, 0);
1261
child = child.getNext();
1262
} while (child != null);
1263
addIndexOp(type, memberTypeFlags);
1264
stackChange(2 - childCount);
1265
expectedStackDelta = 2;
1269
case Token.DOTQUERY:
1272
updateLineNumber(node);
1273
visitExpression(child, 0);
1274
addIcode(Icode_ENTERDQ);
1276
queryPC = itsICodeTop;
1277
visitExpression(child.getNext(), 0);
1278
addBackwardGoto(Icode_LEAVEDQ, queryPC);
1282
case Token.DEFAULTNAMESPACE :
1283
case Token.ESCXMLATTR :
1284
case Token.ESCXMLTEXT :
1285
visitExpression(child, 0);
1290
throw badTree(node);
1292
if (savedStackDepth + expectedStackDelta != itsStackDepth) {
1297
private void generateCallFunAndThis(Node left)
1299
// Generate code to place on stack function and thisObj
1300
int type = left.getType();
1303
String name = left.getString();
1304
// stack: ... -> ... function thisObj
1305
addStringOp(Icode_NAME_AND_THIS, name);
1310
case Token.GETELEM: {
1311
Node target = left.getFirstChild();
1312
visitExpression(target, 0);
1313
Node id = target.getNext();
1314
if (type == Token.GETPROP) {
1315
String property = id.getString();
1316
// stack: ... target -> ... function thisObj
1317
addStringOp(Icode_PROP_AND_THIS, property);
1320
visitExpression(id, 0);
1321
// stack: ... target id -> ... function thisObj
1322
addIcode(Icode_ELEM_AND_THIS);
1327
// Including Token.GETVAR
1328
visitExpression(left, 0);
1329
// stack: ... value -> ... function thisObj
1330
addIcode(Icode_VALUE_AND_THIS);
1336
private void visitIncDec(Node node, Node child)
1338
int incrDecrMask = node.getExistingIntProp(Node.INCRDECR_PROP);
1339
int childType = child.getType();
1340
switch (childType) {
1341
case Token.GETVAR : {
1342
String name = child.getString();
1343
if (itsData.itsNeedsActivation) {
1344
addIcode(Icode_SCOPE);
1346
addStringOp(Icode_PROP_INC_DEC, name);
1347
addUint8(incrDecrMask);
1349
int i = scriptOrFn.getParamOrVarIndex(name);
1350
addVarOp(Icode_VAR_INC_DEC, i);
1351
addUint8(incrDecrMask);
1357
String name = child.getString();
1358
addStringOp(Icode_NAME_INC_DEC, name);
1359
addUint8(incrDecrMask);
1363
case Token.GETPROP : {
1364
Node object = child.getFirstChild();
1365
visitExpression(object, 0);
1366
String property = object.getNext().getString();
1367
addStringOp(Icode_PROP_INC_DEC, property);
1368
addUint8(incrDecrMask);
1371
case Token.GETELEM : {
1372
Node object = child.getFirstChild();
1373
visitExpression(object, 0);
1374
Node index = object.getNext();
1375
visitExpression(index, 0);
1376
addIcode(Icode_ELEM_INC_DEC);
1377
addUint8(incrDecrMask);
1381
case Token.GET_REF : {
1382
Node ref = child.getFirstChild();
1383
visitExpression(ref, 0);
1384
addIcode(Icode_REF_INC_DEC);
1385
addUint8(incrDecrMask);
1390
throw badTree(node);
1395
private void visitLiteral(Node node, Node child)
1397
int type = node.getType();
1399
Object[] propertyIds = null;
1400
if (type == Token.ARRAYLIT) {
1402
for (Node n = child; n != null; n = n.getNext()) {
1405
} else if (type == Token.OBJECTLIT) {
1406
propertyIds = (Object[])node.getProp(Node.OBJECT_IDS_PROP);
1407
count = propertyIds.length;
1409
throw badTree(node);
1411
addIndexOp(Icode_LITERAL_NEW, count);
1413
while (child != null) {
1414
visitExpression(child, 0);
1415
addIcode(Icode_LITERAL_SET);
1417
child = child.getNext();
1419
if (type == Token.ARRAYLIT) {
1420
int[] skipIndexes = (int[])node.getProp(Node.SKIP_INDEXES_PROP);
1421
if (skipIndexes == null) {
1422
addToken(Token.ARRAYLIT);
1424
int index = itsLiteralIds.size();
1425
itsLiteralIds.add(skipIndexes);
1426
addIndexOp(Icode_SPARE_ARRAYLIT, index);
1429
int index = itsLiteralIds.size();
1430
itsLiteralIds.add(propertyIds);
1431
addIndexOp(Token.OBJECTLIT, index);
1435
private int getLocalBlockRef(Node node)
1437
Node localBlock = (Node)node.getProp(Node.LOCAL_BLOCK_PROP);
1438
return localBlock.getExistingIntProp(Node.LOCAL_PROP);
1441
private int getTargetLabel(Node target)
1443
int label = target.labelId();
1447
label = itsLabelTableTop;
1448
if (itsLabelTable == null || label == itsLabelTable.length) {
1449
if (itsLabelTable == null) {
1450
itsLabelTable = new int[MIN_LABEL_TABLE_SIZE];
1452
int[] tmp = new int[itsLabelTable.length * 2];
1453
System.arraycopy(itsLabelTable, 0, tmp, 0, label);
1454
itsLabelTable = tmp;
1457
itsLabelTableTop = label + 1;
1458
itsLabelTable[label] = -1;
1460
target.labelId(label);
1464
private void markTargetLabel(Node target)
1466
int label = getTargetLabel(target);
1467
if (itsLabelTable[label] != -1) {
1468
// Can mark label only once
1471
itsLabelTable[label] = itsICodeTop;
1474
private void addGoto(Node target, int gotoOp)
1476
int label = getTargetLabel(target);
1477
if (!(label < itsLabelTableTop)) Kit.codeBug();
1478
int targetPC = itsLabelTable[label];
1480
int gotoPC = itsICodeTop;
1481
if (validIcode(gotoOp)) {
1487
if (targetPC != -1) {
1488
recordJump(gotoPC, targetPC);
1492
int top = itsFixupTableTop;
1493
if (itsFixupTable == null || top == itsFixupTable.length) {
1494
if (itsFixupTable == null) {
1495
itsFixupTable = new long[MIN_FIXUP_TABLE_SIZE];
1497
long[] tmp = new long[itsFixupTable.length * 2];
1498
System.arraycopy(itsFixupTable, 0, tmp, 0, top);
1499
itsFixupTable = tmp;
1502
itsFixupTableTop = top + 1;
1503
itsFixupTable[top] = ((long)label << 32) | gotoPC;
1507
private void fixLabelGotos()
1509
for (int i = 0; i < itsFixupTableTop; i++) {
1510
long fixup = itsFixupTable[i];
1511
int label = (int)(fixup >> 32);
1512
int jumpSource = (int)fixup;
1513
int pc = itsLabelTable[label];
1516
throw Kit.codeBug();
1518
recordJump(jumpSource, pc);
1520
itsFixupTableTop = 0;
1523
private void addBackwardGoto(int gotoOp, int jumpPC)
1525
if (jumpPC >= itsICodeTop) throw Kit.codeBug();
1526
int fromPC = itsICodeTop;
1528
recordJump(fromPC, jumpPC);
1532
private void addForwardGoto(int gotoOp)
1538
private void resolveForwardGoto(int fromPC)
1540
if (fromPC + 3 > itsICodeTop) throw Kit.codeBug();
1541
recordJump(fromPC, itsICodeTop);
1544
private void recordJump(int jumpSource, int jumpDestination)
1546
if (jumpSource == jumpDestination) throw Kit.codeBug();
1547
int offsetSite = jumpSource + 1;
1548
int offset = jumpDestination - jumpSource;
1549
if (offset != (short)offset) {
1550
if (itsData.longJumps == null) {
1551
itsData.longJumps = new UintMap();
1553
itsData.longJumps.put(offsetSite, jumpDestination);
1556
itsData.itsICode[offsetSite] = (byte)(offset >> 8);
1557
itsData.itsICode[offsetSite + 1] = (byte)offset;
1560
private void addToken(int token)
1562
if (!validTokenCode(token)) throw Kit.codeBug();
1566
private void addIcode(int icode)
1568
if (!validIcode(icode)) throw Kit.codeBug();
1569
// Write negative icode as uint8 bits
1570
addUint8(icode & 0xFF);
1573
private void addUint8(int value)
1575
if ((value & ~0xFF) != 0) throw Kit.codeBug();
1576
byte[] array = itsData.itsICode;
1577
int top = itsICodeTop;
1578
if (top == array.length) {
1579
array = increaseICodeCapasity(1);
1581
array[top] = (byte)value;
1582
itsICodeTop = top + 1;
1585
private void addUint16(int value)
1587
if ((value & ~0xFFFF) != 0) throw Kit.codeBug();
1588
byte[] array = itsData.itsICode;
1589
int top = itsICodeTop;
1590
if (top + 2 > array.length) {
1591
array = increaseICodeCapasity(2);
1593
array[top] = (byte)(value >>> 8);
1594
array[top + 1] = (byte)value;
1595
itsICodeTop = top + 2;
1598
private void addInt(int i)
1600
byte[] array = itsData.itsICode;
1601
int top = itsICodeTop;
1602
if (top + 4 > array.length) {
1603
array = increaseICodeCapasity(4);
1605
array[top] = (byte)(i >>> 24);
1606
array[top + 1] = (byte)(i >>> 16);
1607
array[top + 2] = (byte)(i >>> 8);
1608
array[top + 3] = (byte)i;
1609
itsICodeTop = top + 4;
1612
private int getDoubleIndex(double num)
1614
int index = itsDoubleTableTop;
1616
itsData.itsDoubleTable = new double[64];
1617
} else if (itsData.itsDoubleTable.length == index) {
1618
double[] na = new double[index * 2];
1619
System.arraycopy(itsData.itsDoubleTable, 0, na, 0, index);
1620
itsData.itsDoubleTable = na;
1622
itsData.itsDoubleTable[index] = num;
1623
itsDoubleTableTop = index + 1;
1627
private void addVarOp(int op, int varIndex)
1632
if (varIndex < 128) {
1633
addIcode(op == Token.GETVAR ? Icode_GETVAR1 : Icode_SETVAR1);
1638
case Icode_VAR_INC_DEC:
1639
addIndexOp(op, varIndex);
1642
throw Kit.codeBug();
1645
private void addStringOp(int op, String str)
1647
addStringPrefix(str);
1648
if (validIcode(op)) {
1655
private void addIndexOp(int op, int index)
1657
addIndexPrefix(index);
1658
if (validIcode(op)) {
1665
private void addStringPrefix(String str)
1667
int index = itsStrings.get(str, -1);
1669
index = itsStrings.size();
1670
itsStrings.put(str, index);
1673
addIcode(Icode_REG_STR_C0 - index);
1674
} else if (index <= 0xFF) {
1675
addIcode(Icode_REG_STR1);
1677
} else if (index <= 0xFFFF) {
1678
addIcode(Icode_REG_STR2);
1681
addIcode(Icode_REG_STR4);
1686
private void addIndexPrefix(int index)
1688
if (index < 0) Kit.codeBug();
1690
addIcode(Icode_REG_IND_C0 - index);
1691
} else if (index <= 0xFF) {
1692
addIcode(Icode_REG_IND1);
1694
} else if (index <= 0xFFFF) {
1695
addIcode(Icode_REG_IND2);
1698
addIcode(Icode_REG_IND4);
1703
private void addExceptionHandler(int icodeStart, int icodeEnd,
1704
int handlerStart, boolean isFinally,
1705
int exceptionObjectLocal, int scopeLocal)
1707
int top = itsExceptionTableTop;
1708
int[] table = itsData.itsExceptionTable;
1709
if (table == null) {
1710
if (top != 0) Kit.codeBug();
1711
table = new int[EXCEPTION_SLOT_SIZE * 2];
1712
itsData.itsExceptionTable = table;
1713
} else if (table.length == top) {
1714
table = new int[table.length * 2];
1715
System.arraycopy(itsData.itsExceptionTable, 0, table, 0, top);
1716
itsData.itsExceptionTable = table;
1718
table[top + EXCEPTION_TRY_START_SLOT] = icodeStart;
1719
table[top + EXCEPTION_TRY_END_SLOT] = icodeEnd;
1720
table[top + EXCEPTION_HANDLER_SLOT] = handlerStart;
1721
table[top + EXCEPTION_TYPE_SLOT] = isFinally ? 1 : 0;
1722
table[top + EXCEPTION_LOCAL_SLOT] = exceptionObjectLocal;
1723
table[top + EXCEPTION_SCOPE_SLOT] = scopeLocal;
1725
itsExceptionTableTop = top + EXCEPTION_SLOT_SIZE;
1728
private byte[] increaseICodeCapasity(int extraSize)
1730
int capacity = itsData.itsICode.length;
1731
int top = itsICodeTop;
1732
if (top + extraSize <= capacity) throw Kit.codeBug();
1734
if (top + extraSize > capacity) {
1735
capacity = top + extraSize;
1737
byte[] array = new byte[capacity];
1738
System.arraycopy(itsData.itsICode, 0, array, 0, top);
1739
itsData.itsICode = array;
1743
private void stackChange(int change)
1746
itsStackDepth += change;
1748
int newDepth = itsStackDepth + change;
1749
if (newDepth > itsData.itsMaxStack) {
1750
itsData.itsMaxStack = newDepth;
1752
itsStackDepth = newDepth;
1756
private int allocLocal()
1758
int localSlot = itsLocalTop;
1760
if (itsLocalTop > itsData.itsMaxLocals) {
1761
itsData.itsMaxLocals = itsLocalTop;
1766
private void releaseLocal(int localSlot)
1769
if (localSlot != itsLocalTop) Kit.codeBug();
1772
private static int getShort(byte[] iCode, int pc) {
1773
return (iCode[pc] << 8) | (iCode[pc + 1] & 0xFF);
1776
private static int getIndex(byte[] iCode, int pc) {
1777
return ((iCode[pc] & 0xFF) << 8) | (iCode[pc + 1] & 0xFF);
1780
private static int getInt(byte[] iCode, int pc) {
1781
return (iCode[pc] << 24) | ((iCode[pc + 1] & 0xFF) << 16)
1782
| ((iCode[pc + 2] & 0xFF) << 8) | (iCode[pc + 3] & 0xFF);
1785
private static int getExceptionHandler(CallFrame frame,
1786
boolean onlyFinally)
1788
int[] exceptionTable = frame.idata.itsExceptionTable;
1789
if (exceptionTable == null) {
1790
// No exception handlers
1794
// Icode switch in the interpreter increments PC immediately
1795
// and it is necessary to subtract 1 from the saved PC
1796
// to point it before the start of the next instruction.
1797
int pc = frame.pc - 1;
1799
// OPT: use binary search
1800
int best = -1, bestStart = 0, bestEnd = 0;
1801
for (int i = 0; i != exceptionTable.length; i += EXCEPTION_SLOT_SIZE) {
1802
int start = exceptionTable[i + EXCEPTION_TRY_START_SLOT];
1803
int end = exceptionTable[i + EXCEPTION_TRY_END_SLOT];
1804
if (!(start <= pc && pc < end)) {
1807
if (onlyFinally && exceptionTable[i + EXCEPTION_TYPE_SLOT] != 1) {
1811
// Since handlers always nest and they never have shared end
1812
// although they can share start it is sufficient to compare
1814
if (bestEnd < end) {
1817
// Check the above assumption
1818
if (bestStart > start) Kit.codeBug(); // should be nested
1819
if (bestEnd == end) Kit.codeBug(); // no ens sharing
1828
private static void dumpICode(InterpreterData idata)
1830
if (!Token.printICode) {
1834
byte iCode[] = idata.itsICode;
1835
int iCodeLength = iCode.length;
1836
String[] strings = idata.itsStringTable;
1837
PrintStream out = System.out;
1838
out.println("ICode dump, for " + idata.itsName
1839
+ ", length = " + iCodeLength);
1840
out.println("MaxStack = " + idata.itsMaxStack);
1843
for (int pc = 0; pc < iCodeLength; ) {
1845
out.print(" [" + pc + "] ");
1846
int token = iCode[pc];
1847
int icodeLength = bytecodeSpan(token);
1848
String tname = bytecodeName(token);
1853
if (icodeLength != 1) Kit.codeBug();
1861
case Icode_IFEQ_POP :
1862
case Icode_LEAVEDQ : {
1863
int newPC = pc + getShort(iCode, pc) - 1;
1864
out.println(tname + " " + newPC);
1868
case Icode_VAR_INC_DEC :
1869
case Icode_NAME_INC_DEC :
1870
case Icode_PROP_INC_DEC :
1871
case Icode_ELEM_INC_DEC :
1872
case Icode_REF_INC_DEC: {
1873
int incrDecrType = iCode[pc];
1874
out.println(tname + " " + incrDecrType);
1879
case Icode_CALLSPECIAL : {
1880
int callType = iCode[pc] & 0xFF;
1881
boolean isNew = (iCode[pc + 1] != 0);
1882
int line = getIndex(iCode, pc+2);
1883
out.println(tname+" "+callType+" "+isNew+" "+indexReg+" "+line);
1888
case Token.CATCH_SCOPE:
1890
boolean afterFisrtFlag = (iCode[pc] != 0);
1891
out.println(tname+" "+afterFisrtFlag);
1896
out.println(tname+" "+idata.itsRegExpLiterals[indexReg]);
1898
case Token.OBJECTLIT :
1899
case Icode_SPARE_ARRAYLIT :
1900
out.println(tname+" "+idata.literalIds[indexReg]);
1902
case Icode_CLOSURE_EXPR :
1903
case Icode_CLOSURE_STMT :
1904
out.println(tname+" "+idata.itsNestedFunctions[indexReg]);
1907
case Icode_TAIL_CALL :
1908
case Token.REF_CALL :
1910
out.println(tname+' '+indexReg);
1912
case Token.THROW : {
1913
int line = getIndex(iCode, pc);
1914
out.println(tname + " : " + line);
1918
case Icode_SHORTNUMBER : {
1919
int value = getShort(iCode, pc);
1920
out.println(tname + " " + value);
1924
case Icode_INTNUMBER : {
1925
int value = getInt(iCode, pc);
1926
out.println(tname + " " + value);
1930
case Token.NUMBER : {
1931
double value = idata.itsDoubleTable[indexReg];
1932
out.println(tname + " " + value);
1937
int line = getIndex(iCode, pc);
1938
out.println(tname + " : " + line);
1942
case Icode_REG_STR1: {
1943
String str = strings[0xFF & iCode[pc]];
1944
out.println(tname + " \"" + str + '"');
1948
case Icode_REG_STR2: {
1949
String str = strings[getIndex(iCode, pc)];
1950
out.println(tname + " \"" + str + '"');
1954
case Icode_REG_STR4: {
1955
String str = strings[getInt(iCode, pc)];
1956
out.println(tname + " \"" + str + '"');
1960
case Icode_REG_IND1: {
1961
indexReg = 0xFF & iCode[pc];
1962
out.println(tname+" "+indexReg);
1966
case Icode_REG_IND2: {
1967
indexReg = getIndex(iCode, pc);
1968
out.println(tname+" "+indexReg);
1972
case Icode_REG_IND4: {
1973
indexReg = getInt(iCode, pc);
1974
out.println(tname+" "+indexReg);
1980
indexReg = iCode[pc];
1981
out.println(tname+" "+indexReg);
1985
if (old_pc + icodeLength != pc) Kit.codeBug();
1988
int[] table = idata.itsExceptionTable;
1989
if (table != null) {
1990
out.println("Exception handlers: "
1991
+table.length / EXCEPTION_SLOT_SIZE);
1992
for (int i = 0; i != table.length;
1993
i += EXCEPTION_SLOT_SIZE)
1995
int tryStart = table[i + EXCEPTION_TRY_START_SLOT];
1996
int tryEnd = table[i + EXCEPTION_TRY_END_SLOT];
1997
int handlerStart = table[i + EXCEPTION_HANDLER_SLOT];
1998
int type = table[i + EXCEPTION_TYPE_SLOT];
1999
int exceptionLocal = table[i + EXCEPTION_LOCAL_SLOT];
2000
int scopeLocal = table[i + EXCEPTION_SCOPE_SLOT];
2002
out.println(" tryStart="+tryStart+" tryEnd="+tryEnd
2003
+" handlerStart="+handlerStart
2004
+" type="+(type == 0 ? "catch" : "finally")
2005
+" exceptionLocal="+exceptionLocal);
2011
private static int bytecodeSpan(int bytecode)
2022
case Icode_IFEQ_POP :
2023
case Icode_LEAVEDQ :
2027
case Icode_CALLSPECIAL :
2031
return 1 + 1 + 1 + 2;
2033
case Token.CATCH_SCOPE:
2037
case Icode_VAR_INC_DEC:
2038
case Icode_NAME_INC_DEC:
2039
case Icode_PROP_INC_DEC:
2040
case Icode_ELEM_INC_DEC:
2041
case Icode_REF_INC_DEC:
2045
case Icode_SHORTNUMBER :
2049
case Icode_INTNUMBER :
2053
case Icode_REG_IND1:
2057
case Icode_REG_IND2:
2061
case Icode_REG_IND4:
2065
case Icode_REG_STR1:
2066
// ubyte string index
2069
case Icode_REG_STR2:
2070
// ushort string index
2073
case Icode_REG_STR4:
2086
if (!validBytecode(bytecode)) throw Kit.codeBug();
2090
static int[] getLineNumbers(InterpreterData data)
2092
UintMap presentLines = new UintMap();
2094
byte[] iCode = data.itsICode;
2095
int iCodeLength = iCode.length;
2096
for (int pc = 0; pc != iCodeLength;) {
2097
int bytecode = iCode[pc];
2098
int span = bytecodeSpan(bytecode);
2099
if (bytecode == Icode_LINE) {
2100
if (span != 3) Kit.codeBug();
2101
int line = getIndex(iCode, pc + 1);
2102
presentLines.put(line, 0);
2107
return presentLines.getKeys();
2110
static String getSourcePositionFromStack(Context cx, int[] linep)
2112
CallFrame frame = (CallFrame)cx.interpreterLineCounting;
2113
InterpreterData idata = frame.idata;
2114
if (frame.pcSourceLineStart >= 0) {
2115
linep[0] = getIndex(idata.itsICode, frame.pcSourceLineStart);
2119
return idata.itsSourceFile;
2122
static String getEncodedSource(InterpreterData idata)
2124
if (idata.encodedSource == null) {
2127
return idata.encodedSource.substring(idata.encodedSourceStart,
2128
idata.encodedSourceEnd);
2131
private static void initFunction(Context cx, Scriptable scope,
2132
InterpretedFunction parent, int index)
2134
InterpretedFunction fn;
2135
fn = InterpretedFunction.createFunction(cx, scope, parent, index);
2136
ScriptRuntime.initFunction(cx, scope, fn, fn.idata.itsFunctionType,
2137
parent.idata.evalScriptFlag);
2140
static Object interpret(InterpretedFunction ifun,
2141
Context cx, Scriptable scope,
2142
Scriptable thisObj, Object[] args)
2144
if (!ScriptRuntime.hasTopCall(cx)) {
2145
return ScriptRuntime.doTopCall(ifun, cx, scope, thisObj, args);
2147
if (cx.interpreterSecurityDomain != ifun.securityDomain) {
2148
Object savedDomain = cx.interpreterSecurityDomain;
2149
cx.interpreterSecurityDomain = ifun.securityDomain;
2151
return ifun.securityController.callWithDomain(
2152
ifun.securityDomain, cx, ifun, scope, thisObj, args);
2154
cx.interpreterSecurityDomain = savedDomain;
2158
CallFrame frame = new CallFrame();
2159
initFrame(cx, scope, thisObj, args, null, 0, args.length,
2164
result = interpret(cx, frame, null);
2166
// Always clenup interpreterLineCounting to avoid memory leaks
2167
// throgh stored in Context frame
2168
cx.interpreterLineCounting = null;
2173
public static Object restartContinuation(Continuation c, Context cx,
2174
Scriptable scope, Object[] args)
2176
if (!ScriptRuntime.hasTopCall(cx)) {
2177
return ScriptRuntime.doTopCall(c, cx, scope, null, args);
2181
if (args.length == 0) {
2182
arg = Undefined.instance;
2187
CallFrame capturedFrame = (CallFrame)c.getImplementation();
2188
if (capturedFrame == null) {
2189
// No frames to restart
2193
ContinuationJump cjump = new ContinuationJump(c, null);
2196
return interpret(cx, null, cjump);
2199
private static Object interpret(Context cx, CallFrame frame,
2202
// throwable holds exception object to rethrow or catch
2203
// It is also used for continuation restart in which case
2204
// it holds ContinuationJump
2206
final Object DBL_MRK = UniqueTag.DOUBLE_MARK;
2207
final Scriptable undefined = Undefined.instance;
2209
final boolean instructionCounting = (cx.instructionThreshold != 0);
2210
// arbitrary number to add to instructionCount when calling
2212
final int INVOCATION_COST = 100;
2213
// arbitrary exception cost for instruction counting
2214
final int EXCEPTION_COST = 100;
2216
String stringReg = null;
2219
// When restarting continuation throwable is not null and to jump
2220
// to the code that rewind continuation state indexReg should be set
2222
// With the normal call throable == null and indexReg == -1 allows to
2223
// catch bugs with using indeReg to access array eleemnts before
2224
// initializing indexReg.
2226
if (throwable != null) {
2227
// Assert assumptions
2228
if (!(throwable instanceof ContinuationJump)) {
2229
// It should be continuation
2234
StateLoop: for (;;) {
2235
withoutExceptions: try {
2237
if (throwable != null) {
2238
// Recovering from exception, indexReg contains
2239
// the index of handler
2241
if (indexReg >= 0) {
2242
// Normal excepton handler, transfer
2243
// control appropriately
2246
// XXX Deal with exceptios!!!
2247
frame = frame.cloneFrozen();
2250
int[] table = frame.idata.itsExceptionTable;
2252
frame.pc = table[indexReg + EXCEPTION_HANDLER_SLOT];
2253
if (instructionCounting) {
2254
frame.pcPrevBranch = frame.pc;
2257
frame.savedStackTop = frame.emptyStackTop;
2258
int scopeLocal = frame.localShift
2260
+ EXCEPTION_SCOPE_SLOT];
2261
int exLocal = frame.localShift
2263
+ EXCEPTION_LOCAL_SLOT];
2264
frame.scope = (Scriptable)frame.stack[scopeLocal];
2265
frame.stack[exLocal] = throwable;
2269
// Continuation restoration
2270
ContinuationJump cjump = (ContinuationJump)throwable;
2272
// Clear throwable to indicate that execptions are OK
2275
if (cjump.branchFrame != frame) Kit.codeBug();
2277
// Check that we have at least one frozen frame
2278
// in the case of detached continuation restoration:
2279
// unwind code ensure that
2280
if (cjump.capturedFrame == null) Kit.codeBug();
2282
// Need to rewind branchFrame, capturedFrame
2283
// and all frames in between
2284
int rewindCount = cjump.capturedFrame.frameIndex + 1;
2285
if (cjump.branchFrame != null) {
2286
rewindCount -= cjump.branchFrame.frameIndex;
2290
CallFrame[] enterFrames = null;
2292
CallFrame x = cjump.capturedFrame;
2293
for (int i = 0; i != rewindCount; ++i) {
2294
if (!x.frozen) Kit.codeBug();
2295
if (isFrameEnterExitRequired(x)) {
2296
if (enterFrames == null) {
2297
// Allocate enough space to store the rest
2298
// of rewind frames in case all of them
2299
// would require to enter
2300
enterFrames = new CallFrame[rewindCount
2303
enterFrames[enterCount] = x;
2309
while (enterCount != 0) {
2310
// execute enter: walk enterFrames in the reverse
2311
// order since they were stored starting from
2312
// the capturedFrame, not branchFrame
2314
x = enterFrames[enterCount];
2315
enterFrame(cx, x, ScriptRuntime.emptyArgs);
2318
// Continuation jump is almost done: capturedFrame
2319
// points to the call to the function that captured
2320
// continuation, so clone capturedFrame and
2321
// emulate return that function with the suplied result
2322
frame = cjump.capturedFrame.cloneFrozen();
2323
setCallResult(frame, cjump.result, cjump.resultDbl);
2324
// restart the execution
2327
if (frame.frozen) Kit.codeBug();
2330
// Use local variables for constant values in frame
2331
// for faster access
2332
Object[] stack = frame.stack;
2333
double[] sDbl = frame.sDbl;
2334
Object[] vars = frame.varSource.stack;
2335
double[] varDbls = frame.varSource.sDbl;
2336
byte[] iCode = frame.idata.itsICode;
2337
String[] strings = frame.idata.itsStringTable;
2339
// Use local for stackTop as well. Since execption handlers
2340
// can only exist at statement level where stack is empty,
2341
// it is necessary to save/restore stackTop only accross
2342
// function calls and normal returns.
2343
int stackTop = frame.savedStackTop;
2345
// Point line counting to the new frame
2346
cx.interpreterLineCounting = frame;
2350
// Exception handler assumes that PC is already incremented
2351
// pass the instruction start when it searches the
2352
// exception handler
2353
int op = iCode[frame.pc++];
2356
// Back indent to ease imlementation reading
2359
Object value = stack[stackTop];
2360
if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2363
int sourceLine = getIndex(iCode, frame.pc);
2364
throwable = new JavaScriptException(value,
2365
frame.idata.itsSourceFile,
2367
break withoutExceptions;
2369
case Token.RETHROW: {
2370
indexReg += frame.localShift;
2371
throwable = stack[indexReg];
2372
break withoutExceptions;
2379
Object rhs = stack[stackTop + 1];
2380
Object lhs = stack[stackTop];
2387
if (rhs == DBL_MRK) {
2388
rDbl = sDbl[stackTop + 1];
2389
lDbl = stack_double(frame, stackTop);
2390
} else if (lhs == DBL_MRK) {
2391
rDbl = ScriptRuntime.toNumber(rhs);
2392
lDbl = sDbl[stackTop];
2394
break number_compare;
2398
valBln = (lDbl >= rDbl);
2399
break object_compare;
2401
valBln = (lDbl <= rDbl);
2402
break object_compare;
2404
valBln = (lDbl > rDbl);
2405
break object_compare;
2407
valBln = (lDbl < rDbl);
2408
break object_compare;
2410
throw Kit.codeBug();
2415
valBln = ScriptRuntime.cmp_LE(rhs, lhs);
2418
valBln = ScriptRuntime.cmp_LE(lhs, rhs);
2421
valBln = ScriptRuntime.cmp_LT(rhs, lhs);
2424
valBln = ScriptRuntime.cmp_LT(lhs, rhs);
2427
throw Kit.codeBug();
2430
stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
2434
Object rhs = stack[stackTop];
2435
if (rhs == DBL_MRK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2437
Object lhs = stack[stackTop];
2438
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2439
boolean valBln = ScriptRuntime.in(lhs, rhs, cx, frame.scope);
2440
stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
2443
case Token.INSTANCEOF : {
2444
Object rhs = stack[stackTop];
2445
if (rhs == DBL_MRK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2447
Object lhs = stack[stackTop];
2448
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2449
boolean valBln = ScriptRuntime.instanceOf(lhs, rhs, cx, frame.scope);
2450
stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
2457
Object rhs = stack[stackTop + 1];
2458
Object lhs = stack[stackTop];
2459
if (rhs == DBL_MRK) {
2460
if (lhs == DBL_MRK) {
2461
valBln = (sDbl[stackTop] == sDbl[stackTop + 1]);
2463
valBln = ScriptRuntime.eqNumber(sDbl[stackTop + 1], lhs);
2466
if (lhs == DBL_MRK) {
2467
valBln = ScriptRuntime.eqNumber(sDbl[stackTop], rhs);
2469
valBln = ScriptRuntime.eq(lhs, rhs);
2472
valBln ^= (op == Token.NE);
2473
stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
2479
Object rhs = stack[stackTop + 1];
2480
Object lhs = stack[stackTop];
2484
if (rhs == DBL_MRK) {
2485
rdbl = sDbl[stackTop + 1];
2486
if (lhs == DBL_MRK) {
2487
ldbl = sDbl[stackTop];
2488
} else if (lhs instanceof Number) {
2489
ldbl = ((Number)lhs).doubleValue();
2492
break shallow_compare;
2494
} else if (lhs == DBL_MRK) {
2495
ldbl = sDbl[stackTop];
2496
if (rhs == DBL_MRK) {
2497
rdbl = sDbl[stackTop + 1];
2498
} else if (rhs instanceof Number) {
2499
rdbl = ((Number)rhs).doubleValue();
2502
break shallow_compare;
2505
valBln = ScriptRuntime.shallowEq(lhs, rhs);
2506
break shallow_compare;
2508
valBln = (ldbl == rdbl);
2510
valBln ^= (op == Token.SHNE);
2511
stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
2515
if (stack_boolean(frame, stackTop--)) {
2521
if (!stack_boolean(frame, stackTop--)) {
2526
case Icode_IFEQ_POP :
2527
if (!stack_boolean(frame, stackTop--)) {
2531
stack[stackTop--] = null;
2537
stack[stackTop] = DBL_MRK;
2538
sDbl[stackTop] = frame.pc + 2;
2540
case Icode_STARTSUB :
2541
if (stackTop == frame.emptyStackTop + 1) {
2542
// Call from Icode_GOSUB: store return PC address in the local
2543
indexReg += frame.localShift;
2544
stack[indexReg] = stack[stackTop];
2545
sDbl[indexReg] = sDbl[stackTop];
2548
// Call from exception handler: exception object is already stored
2550
if (stackTop != frame.emptyStackTop) Kit.codeBug();
2553
case Icode_RETSUB : {
2554
// indexReg: local to store return address
2555
if (instructionCounting) {
2556
addInstructionCount(cx, frame, 0);
2558
indexReg += frame.localShift;
2559
Object value = stack[indexReg];
2560
if (value != DBL_MRK) {
2561
// Invocation from exception handler, restore object to rethrow
2563
break withoutExceptions;
2565
// Normal return from GOSUB
2566
frame.pc = (int)sDbl[indexReg];
2567
if (instructionCounting) {
2568
frame.pcPrevBranch = frame.pc;
2573
stack[stackTop] = null;
2576
case Icode_POP_RESULT :
2577
frame.result = stack[stackTop];
2578
frame.resultDbl = sDbl[stackTop];
2579
stack[stackTop] = null;
2583
stack[stackTop + 1] = stack[stackTop];
2584
sDbl[stackTop + 1] = sDbl[stackTop];
2588
stack[stackTop + 1] = stack[stackTop - 1];
2589
sDbl[stackTop + 1] = sDbl[stackTop - 1];
2590
stack[stackTop + 2] = stack[stackTop];
2591
sDbl[stackTop + 2] = sDbl[stackTop];
2595
Object o = stack[stackTop];
2596
stack[stackTop] = stack[stackTop - 1];
2597
stack[stackTop - 1] = o;
2598
double d = sDbl[stackTop];
2599
sDbl[stackTop] = sDbl[stackTop - 1];
2600
sDbl[stackTop - 1] = d;
2604
frame.result = stack[stackTop];
2605
frame.resultDbl = sDbl[stackTop];
2608
case Token.RETURN_RESULT :
2610
case Icode_RETUNDEF :
2611
frame.result = undefined;
2613
case Token.BITNOT : {
2614
int rIntValue = stack_int32(frame, stackTop);
2615
stack[stackTop] = DBL_MRK;
2616
sDbl[stackTop] = ~rIntValue;
2619
case Token.BITAND : {
2620
int rIntValue = stack_int32(frame, stackTop);
2622
int lIntValue = stack_int32(frame, stackTop);
2623
stack[stackTop] = DBL_MRK;
2624
sDbl[stackTop] = lIntValue & rIntValue;
2627
case Token.BITOR : {
2628
int rIntValue = stack_int32(frame, stackTop);
2630
int lIntValue = stack_int32(frame, stackTop);
2631
stack[stackTop] = DBL_MRK;
2632
sDbl[stackTop] = lIntValue | rIntValue;
2635
case Token.BITXOR : {
2636
int rIntValue = stack_int32(frame, stackTop);
2638
int lIntValue = stack_int32(frame, stackTop);
2639
stack[stackTop] = DBL_MRK;
2640
sDbl[stackTop] = lIntValue ^ rIntValue;
2644
int rIntValue = stack_int32(frame, stackTop);
2646
int lIntValue = stack_int32(frame, stackTop);
2647
stack[stackTop] = DBL_MRK;
2648
sDbl[stackTop] = lIntValue << rIntValue;
2652
int rIntValue = stack_int32(frame, stackTop);
2654
int lIntValue = stack_int32(frame, stackTop);
2655
stack[stackTop] = DBL_MRK;
2656
sDbl[stackTop] = lIntValue >> rIntValue;
2660
int rIntValue = stack_int32(frame, stackTop) & 0x1F;
2662
double lDbl = stack_double(frame, stackTop);
2663
stack[stackTop] = DBL_MRK;
2664
sDbl[stackTop] = ScriptRuntime.toUint32(lDbl) >>> rIntValue;
2668
double rDbl = stack_double(frame, stackTop);
2669
stack[stackTop] = DBL_MRK;
2670
sDbl[stackTop] = -rDbl;
2674
double rDbl = stack_double(frame, stackTop);
2675
stack[stackTop] = DBL_MRK;
2676
sDbl[stackTop] = rDbl;
2681
do_add(stack, sDbl, stackTop, cx);
2684
double rDbl = stack_double(frame, stackTop);
2686
double lDbl = stack_double(frame, stackTop);
2687
stack[stackTop] = DBL_MRK;
2688
sDbl[stackTop] = lDbl - rDbl;
2692
double rDbl = stack_double(frame, stackTop);
2694
double lDbl = stack_double(frame, stackTop);
2695
stack[stackTop] = DBL_MRK;
2696
sDbl[stackTop] = lDbl * rDbl;
2700
double rDbl = stack_double(frame, stackTop);
2702
double lDbl = stack_double(frame, stackTop);
2703
stack[stackTop] = DBL_MRK;
2704
// Detect the divide by zero or let Java do it ?
2705
sDbl[stackTop] = lDbl / rDbl;
2709
double rDbl = stack_double(frame, stackTop);
2711
double lDbl = stack_double(frame, stackTop);
2712
stack[stackTop] = DBL_MRK;
2713
sDbl[stackTop] = lDbl % rDbl;
2717
stack[stackTop] = ScriptRuntime.wrapBoolean(
2718
!stack_boolean(frame, stackTop));
2720
case Token.BINDNAME :
2721
stack[++stackTop] = ScriptRuntime.bind(cx, frame.scope, stringReg);
2723
case Token.SETNAME : {
2724
Object rhs = stack[stackTop];
2725
if (rhs == DBL_MRK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2727
Scriptable lhs = (Scriptable)stack[stackTop];
2728
stack[stackTop] = ScriptRuntime.setName(lhs, rhs, cx,
2729
frame.scope, stringReg);
2732
case Token.DELPROP : {
2733
Object rhs = stack[stackTop];
2734
if (rhs == DBL_MRK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2736
Object lhs = stack[stackTop];
2737
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2738
stack[stackTop] = ScriptRuntime.delete(lhs, rhs, cx);
2741
case Token.GETPROP : {
2742
Object lhs = stack[stackTop];
2743
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2744
stack[stackTop] = ScriptRuntime.getObjectProp(lhs, stringReg, cx);
2747
case Token.SETPROP : {
2748
Object rhs = stack[stackTop];
2749
if (rhs == DBL_MRK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2751
Object lhs = stack[stackTop];
2752
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2753
stack[stackTop] = ScriptRuntime.setObjectProp(lhs, stringReg, rhs,
2757
case Icode_PROP_INC_DEC : {
2758
Object lhs = stack[stackTop];
2759
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2760
stack[stackTop] = ScriptRuntime.propIncrDecr(lhs, stringReg,
2761
cx, iCode[frame.pc]);
2765
case Token.GETELEM : {
2767
Object lhs = stack[stackTop];
2768
if (lhs == DBL_MRK) {
2769
lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2772
Object id = stack[stackTop + 1];
2773
if (id != DBL_MRK) {
2774
value = ScriptRuntime.getObjectElem(lhs, id, cx);
2776
double d = sDbl[stackTop + 1];
2777
value = ScriptRuntime.getObjectIndex(lhs, d, cx);
2779
stack[stackTop] = value;
2782
case Token.SETELEM : {
2784
Object rhs = stack[stackTop + 2];
2785
if (rhs == DBL_MRK) {
2786
rhs = ScriptRuntime.wrapNumber(sDbl[stackTop + 2]);
2788
Object lhs = stack[stackTop];
2789
if (lhs == DBL_MRK) {
2790
lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2793
Object id = stack[stackTop + 1];
2794
if (id != DBL_MRK) {
2795
value = ScriptRuntime.setObjectElem(lhs, id, rhs, cx);
2797
double d = sDbl[stackTop + 1];
2798
value = ScriptRuntime.setObjectIndex(lhs, d, rhs, cx);
2800
stack[stackTop] = value;
2803
case Icode_ELEM_INC_DEC: {
2804
Object rhs = stack[stackTop];
2805
if (rhs == DBL_MRK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2807
Object lhs = stack[stackTop];
2808
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2809
stack[stackTop] = ScriptRuntime.elemIncrDecr(lhs, rhs, cx,
2814
case Token.GET_REF : {
2815
Scriptable target = (Scriptable)stack[stackTop];
2817
Ref ref = (Ref)stack[stackTop];
2818
stack[stackTop] = ScriptRuntime.refGet(ref, target, cx);
2821
case Token.SET_REF : {
2822
Object value = stack[stackTop];
2823
if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2825
Scriptable target = (Scriptable)stack[stackTop];
2827
Ref ref = (Ref)stack[stackTop];
2828
stack[stackTop] = ScriptRuntime.refSet(ref, target, value, cx);
2831
case Token.DEL_REF : {
2832
Scriptable target = (Scriptable)stack[stackTop];
2834
Ref ref = (Ref)stack[stackTop];
2835
stack[stackTop] = ScriptRuntime.refDel(ref, target, cx);
2838
case Icode_REF_INC_DEC : {
2839
Scriptable target = (Scriptable)stack[stackTop];
2841
Ref ref = (Ref)stack[stackTop];
2842
stack[stackTop] = ScriptRuntime.refIncrDecr(ref, target, cx,
2847
case Token.LOCAL_LOAD :
2849
indexReg += frame.localShift;
2850
stack[stackTop] = stack[indexReg];
2851
sDbl[stackTop] = sDbl[indexReg];
2853
case Icode_LOCAL_CLEAR :
2854
indexReg += frame.localShift;
2855
stack[indexReg] = null;
2857
case Icode_NAME_AND_THIS :
2860
stack[stackTop] = ScriptRuntime.getNameFunctionAndThis(stringReg,
2863
stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
2865
case Icode_PROP_AND_THIS: {
2866
Object obj = stack[stackTop];
2867
if (obj == DBL_MRK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2868
// stringReg: property
2869
stack[stackTop] = ScriptRuntime.getPropFunctionAndThis(obj, stringReg,
2872
stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
2875
case Icode_ELEM_AND_THIS: {
2876
Object obj = stack[stackTop - 1];
2877
if (obj == DBL_MRK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop - 1]);
2878
Object id = stack[stackTop];
2879
if (id == DBL_MRK) id = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2880
stack[stackTop - 1] = ScriptRuntime.getElemFunctionAndThis(obj, id, cx);
2881
stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
2884
case Icode_VALUE_AND_THIS : {
2885
Object value = stack[stackTop];
2886
if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2887
stack[stackTop] = ScriptRuntime.getValueFunctionAndThis(value, cx);
2889
stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
2892
case Icode_CALLSPECIAL : {
2893
if (instructionCounting) {
2894
cx.instructionCount += INVOCATION_COST;
2896
int callType = iCode[frame.pc] & 0xFF;
2897
boolean isNew = (iCode[frame.pc + 1] != 0);
2898
int sourceLine = getIndex(iCode, frame.pc + 2);
2900
// indexReg: number of arguments
2902
// stack change: function arg0 .. argN -> newResult
2903
stackTop -= indexReg;
2905
Object function = stack[stackTop];
2906
if (function == DBL_MRK)
2907
function = ScriptRuntime.wrapNumber(sDbl[stackTop]);
2908
Object[] outArgs = getArgsArray(
2909
stack, sDbl, stackTop + 1, indexReg);
2910
stack[stackTop] = ScriptRuntime.newSpecial(
2911
cx, function, outArgs, frame.scope, callType);
2913
// stack change: function thisObj arg0 .. argN -> result
2914
stackTop -= 1 + indexReg;
2916
// Call code generation ensure that stack here
2917
// is ... Function Scriptable
2918
Scriptable functionThis = (Scriptable)stack[stackTop + 1];
2919
Function function = (Function)stack[stackTop];
2920
Object[] outArgs = getArgsArray(
2921
stack, sDbl, stackTop + 2, indexReg);
2922
stack[stackTop] = ScriptRuntime.callSpecial(
2923
cx, function, functionThis, outArgs,
2924
frame.scope, frame.thisObj, callType,
2925
frame.idata.itsSourceFile, sourceLine);
2931
case Icode_TAIL_CALL :
2932
case Token.REF_CALL : {
2933
if (instructionCounting) {
2934
cx.instructionCount += INVOCATION_COST;
2936
// stack change: function thisObj arg0 .. argN -> result
2937
// indexReg: number of arguments
2938
stackTop -= 1 + indexReg;
2940
// CALL generation ensures that fun and funThisObj
2941
// are already Scriptable and Function objects respectively
2942
Function fun = (Function)stack[stackTop];
2943
Scriptable funThisObj = (Scriptable)stack[stackTop + 1];
2944
Scriptable calleeScope = frame.scope;
2945
if (frame.useActivation) {
2946
calleeScope = ScriptableObject.getTopLevelScope(frame.scope);
2949
if (op == Token.REF_CALL) {
2950
Object[] outArgs = getArgsArray(stack, sDbl, stackTop + 2,
2952
stack[stackTop] = ScriptRuntime.callRef(fun, funThisObj, outArgs,
2955
stack[stackTop] = Ref.popTarget(cx);
2959
if (fun instanceof InterpretedFunction) {
2960
InterpretedFunction ifun = (InterpretedFunction)fun;
2961
if (frame.fnOrScript.securityDomain == ifun.securityDomain) {
2962
CallFrame callParentFrame = frame;
2963
CallFrame calleeFrame = new CallFrame();
2964
if (op == Icode_TAIL_CALL) {
2965
// In principle tail call can re-use the current
2966
// frame and its stack arrays but it is hard to
2967
// do properly. Any exceptions that can legally
2968
// happen during frame re-initialization including
2969
// StackOverflowException during innocent looking
2970
// System.arraycopy may leave the current frame
2971
// data corrupted leading to undefined behaviour
2972
// in the catch code bellow that unwinds JS stack
2973
// on exceptions. Then there is issue about frame release
2974
// end exceptions there.
2975
// To avoid frame allocation a released frame
2976
// can be cached for re-use which would also benefit
2977
// non-tail calls but it is not clear that this caching
2978
// would gain in performance due to potentially
2979
// bad iteraction with GC.
2980
callParentFrame = frame.parentFrame;
2982
initFrame(cx, calleeScope, funThisObj, stack, sDbl,
2983
stackTop + 2, indexReg, ifun, callParentFrame,
2985
if (op == Icode_TAIL_CALL) {
2986
// Release the parent
2987
exitFrame(cx, frame, null);
2989
frame.savedStackTop = stackTop;
2990
frame.savedCallOp = op;
2992
frame = calleeFrame;
2997
if (fun instanceof Continuation) {
2998
// Jump to the captured continuation
2999
ContinuationJump cjump;
3000
cjump = new ContinuationJump((Continuation)fun, frame);
3002
// continuation result is the first argument if any
3003
// of contination call
3004
if (indexReg == 0) {
3005
cjump.result = undefined;
3007
cjump.result = stack[stackTop + 2];
3008
cjump.resultDbl = sDbl[stackTop + 2];
3011
// Start the real unwind job
3013
break withoutExceptions;
3016
if (fun instanceof IdFunctionObject) {
3017
IdFunctionObject ifun = (IdFunctionObject)fun;
3018
if (Continuation.isContinuationConstructor(ifun)) {
3019
captureContinuation(cx, frame, stackTop);
3024
Object[] outArgs = getArgsArray(stack, sDbl, stackTop + 2,
3026
stack[stackTop] = fun.call(cx, calleeScope, funThisObj, outArgs);
3031
if (instructionCounting) {
3032
cx.instructionCount += INVOCATION_COST;
3034
// stack change: function arg0 .. argN -> newResult
3035
// indexReg: number of arguments
3036
stackTop -= indexReg;
3038
Object lhs = stack[stackTop];
3039
if (lhs instanceof InterpretedFunction) {
3040
InterpretedFunction f = (InterpretedFunction)lhs;
3041
if (frame.fnOrScript.securityDomain == f.securityDomain) {
3042
Scriptable newInstance = f.createObject(cx, frame.scope);
3043
CallFrame calleeFrame = new CallFrame();
3044
initFrame(cx, frame.scope, newInstance, stack, sDbl,
3045
stackTop + 1, indexReg, f, frame,
3048
stack[stackTop] = newInstance;
3049
frame.savedStackTop = stackTop;
3050
frame.savedCallOp = op;
3051
frame = calleeFrame;
3055
if (!(lhs instanceof Function)) {
3056
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3057
throw ScriptRuntime.notFunctionError(lhs);
3059
Function fun = (Function)lhs;
3061
if (fun instanceof IdFunctionObject) {
3062
IdFunctionObject ifun = (IdFunctionObject)fun;
3063
if (Continuation.isContinuationConstructor(ifun)) {
3064
captureContinuation(cx, frame, stackTop);
3069
Object[] outArgs = getArgsArray(stack, sDbl, stackTop + 1, indexReg);
3070
stack[stackTop] = fun.construct(cx, frame.scope, outArgs);
3073
case Token.TYPEOF : {
3074
Object lhs = stack[stackTop];
3075
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3076
stack[stackTop] = ScriptRuntime.typeof(lhs);
3079
case Icode_TYPEOFNAME :
3080
stack[++stackTop] = ScriptRuntime.typeofName(frame.scope, stringReg);
3083
stack[++stackTop] = stringReg;
3085
case Icode_SHORTNUMBER :
3087
stack[stackTop] = DBL_MRK;
3088
sDbl[stackTop] = getShort(iCode, frame.pc);
3091
case Icode_INTNUMBER :
3093
stack[stackTop] = DBL_MRK;
3094
sDbl[stackTop] = getInt(iCode, frame.pc);
3099
stack[stackTop] = DBL_MRK;
3100
sDbl[stackTop] = frame.idata.itsDoubleTable[indexReg];
3103
stack[++stackTop] = ScriptRuntime.name(cx, frame.scope, stringReg);
3105
case Icode_NAME_INC_DEC :
3106
stack[++stackTop] = ScriptRuntime.nameIncrDecr(frame.scope, stringReg,
3111
indexReg = iCode[frame.pc++];
3114
if (!frame.useActivation) {
3115
vars[indexReg] = stack[stackTop];
3116
varDbls[indexReg] = sDbl[stackTop];
3118
Object val = stack[stackTop];
3119
if (val == DBL_MRK) val = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3120
stringReg = frame.idata.argNames[indexReg];
3121
frame.scope.put(stringReg, frame.scope, val);
3125
indexReg = iCode[frame.pc++];
3129
if (!frame.useActivation) {
3130
stack[stackTop] = vars[indexReg];
3131
sDbl[stackTop] = varDbls[indexReg];
3133
stringReg = frame.idata.argNames[indexReg];
3134
stack[stackTop] = frame.scope.get(stringReg, frame.scope);
3137
case Icode_VAR_INC_DEC : {
3138
// indexReg : varindex
3140
int incrDecrMask = iCode[frame.pc];
3141
if (!frame.useActivation) {
3142
stack[stackTop] = DBL_MRK;
3143
Object varValue = vars[indexReg];
3145
if (varValue == DBL_MRK) {
3146
d = varDbls[indexReg];
3148
d = ScriptRuntime.toNumber(varValue);
3149
vars[indexReg] = DBL_MRK;
3151
double d2 = ((incrDecrMask & Node.DECR_FLAG) == 0)
3152
? d + 1.0 : d - 1.0;
3153
varDbls[indexReg] = d2;
3154
sDbl[stackTop] = ((incrDecrMask & Node.POST_FLAG) == 0) ? d2 : d;
3156
String varName = frame.idata.argNames[indexReg];
3157
stack[stackTop] = ScriptRuntime.nameIncrDecr(frame.scope, varName,
3165
stack[stackTop] = DBL_MRK;
3170
stack[stackTop] = DBL_MRK;
3174
stack[++stackTop] = null;
3177
stack[++stackTop] = frame.thisObj;
3180
stack[++stackTop] = frame.fnOrScript;
3183
stack[++stackTop] = Boolean.FALSE;
3186
stack[++stackTop] = Boolean.TRUE;
3189
stack[++stackTop] = undefined;
3191
case Token.ENTERWITH : {
3192
Object lhs = stack[stackTop];
3193
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3195
frame.scope = ScriptRuntime.enterWith(lhs, cx, frame.scope);
3198
case Token.LEAVEWITH :
3199
frame.scope = ScriptRuntime.leaveWith(frame.scope);
3201
case Token.CATCH_SCOPE : {
3202
// stack top: exception object
3203
// stringReg: name of exception variable
3204
// indexReg: local for exception scope
3206
indexReg += frame.localShift;
3208
boolean afterFirstScope = (frame.idata.itsICode[frame.pc] != 0);
3209
Throwable caughtException = (Throwable)stack[stackTop + 1];
3210
Scriptable lastCatchScope;
3211
if (!afterFirstScope) {
3212
lastCatchScope = null;
3214
lastCatchScope = (Scriptable)stack[indexReg];
3216
stack[indexReg] = ScriptRuntime.newCatchScope(caughtException,
3217
lastCatchScope, stringReg,
3222
case Token.ENUM_INIT_KEYS :
3223
case Token.ENUM_INIT_VALUES : {
3224
Object lhs = stack[stackTop];
3225
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3227
indexReg += frame.localShift;
3228
stack[indexReg] = ScriptRuntime.enumInit(
3229
lhs, cx, (op == Token.ENUM_INIT_VALUES));
3232
case Token.ENUM_NEXT :
3233
case Token.ENUM_ID : {
3234
indexReg += frame.localShift;
3235
Object val = stack[indexReg];
3237
stack[stackTop] = (op == Token.ENUM_NEXT)
3238
? (Object)ScriptRuntime.enumNext(val)
3239
: (Object)ScriptRuntime.enumId(val, cx);
3242
case Token.REF_SPECIAL : {
3243
//stringReg: name of special property
3244
Object obj = stack[stackTop];
3245
if (obj == DBL_MRK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3246
stack[stackTop] = ScriptRuntime.specialRef(obj, stringReg, cx);
3248
stack[stackTop] = Ref.popTarget(cx);
3251
case Token.REF_MEMBER: {
3253
Object elem = stack[stackTop];
3254
if (elem == DBL_MRK) elem = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3256
Object obj = stack[stackTop];
3257
if (obj == DBL_MRK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3258
stack[stackTop] = ScriptRuntime.memberRef(obj, elem, cx, indexReg);
3260
stack[stackTop] = Ref.popTarget(cx);
3263
case Token.REF_NS_MEMBER: {
3265
Object elem = stack[stackTop];
3266
if (elem == DBL_MRK) elem = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3268
Object ns = stack[stackTop];
3269
if (ns == DBL_MRK) ns = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3271
Object obj = stack[stackTop];
3272
if (obj == DBL_MRK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3273
stack[stackTop] = ScriptRuntime.memberRef(obj, ns, elem, cx, indexReg);
3275
stack[stackTop] = Ref.popTarget(cx);
3278
case Token.REF_NAME: {
3280
Object name = stack[stackTop];
3281
if (name == DBL_MRK) name = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3282
stack[stackTop] = ScriptRuntime.nameRef(name, cx, frame.scope,
3285
stack[stackTop] = Ref.popTarget(cx);
3288
case Token.REF_NS_NAME: {
3290
Object name = stack[stackTop];
3291
if (name == DBL_MRK) name = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3293
Object ns = stack[stackTop];
3294
if (ns == DBL_MRK) ns = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3295
stack[stackTop] = ScriptRuntime.nameRef(ns, name, cx, frame.scope,
3298
stack[stackTop] = Ref.popTarget(cx);
3302
stack[++stackTop] = frame.scope;
3304
case Icode_SCOPE_LOAD :
3305
indexReg += frame.localShift;
3306
frame.scope = (Scriptable)stack[indexReg];
3308
case Icode_SCOPE_SAVE :
3309
indexReg += frame.localShift;
3310
stack[indexReg] = frame.scope;
3312
case Icode_CLOSURE_EXPR :
3313
stack[++stackTop] = InterpretedFunction.createFunction(cx, frame.scope,
3317
case Icode_CLOSURE_STMT :
3318
initFunction(cx, frame.scope, frame.fnOrScript, indexReg);
3321
stack[++stackTop] = frame.scriptRegExps[indexReg];
3323
case Icode_LITERAL_NEW :
3324
// indexReg: number of values in the literal
3326
stack[stackTop] = new Object[indexReg];
3329
case Icode_LITERAL_SET : {
3330
Object value = stack[stackTop];
3331
if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3333
int i = (int)sDbl[stackTop];
3334
((Object[])stack[stackTop])[i] = value;
3335
sDbl[stackTop] = i + 1;
3338
case Token.ARRAYLIT :
3339
case Icode_SPARE_ARRAYLIT :
3340
case Token.OBJECTLIT : {
3341
Object[] data = (Object[])stack[stackTop];
3343
if (op == Token.OBJECTLIT) {
3344
Object[] ids = (Object[])frame.idata.literalIds[indexReg];
3345
val = ScriptRuntime.newObjectLiteral(ids, data, cx, frame.scope);
3347
int[] skipIndexces = null;
3348
if (op == Icode_SPARE_ARRAYLIT) {
3349
skipIndexces = (int[])frame.idata.literalIds[indexReg];
3351
val = ScriptRuntime.newArrayLiteral(data, skipIndexces, cx,
3354
stack[stackTop] = val;
3357
case Icode_ENTERDQ : {
3358
Object lhs = stack[stackTop];
3359
if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3361
frame.scope = ScriptRuntime.enterDotQuery(lhs, frame.scope);
3364
case Icode_LEAVEDQ : {
3365
boolean valBln = stack_boolean(frame, stackTop);
3366
Object x = ScriptRuntime.updateDotQuery(valBln, frame.scope);
3368
stack[stackTop] = x;
3369
frame.scope = ScriptRuntime.leaveDotQuery(frame.scope);
3373
// reset stack and PC to code after ENTERDQ
3377
case Token.DEFAULTNAMESPACE : {
3378
Object value = stack[stackTop];
3379
if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
3380
stack[stackTop] = ScriptRuntime.setDefaultNamespace(value, cx);
3383
case Token.ESCXMLATTR : {
3384
Object value = stack[stackTop];
3385
if (value != DBL_MRK) {
3386
stack[stackTop] = ScriptRuntime.escapeAttributeValue(value, cx);
3390
case Token.ESCXMLTEXT : {
3391
Object value = stack[stackTop];
3392
if (value != DBL_MRK) {
3393
stack[stackTop] = ScriptRuntime.escapeTextValue(value, cx);
3398
frame.pcSourceLineStart = frame.pc;
3399
if (frame.debuggerFrame != null) {
3400
int line = getIndex(iCode, frame.pc);
3401
frame.debuggerFrame.onLineChange(cx, line);
3405
case Icode_REG_IND_C0:
3408
case Icode_REG_IND_C1:
3411
case Icode_REG_IND_C2:
3414
case Icode_REG_IND_C3:
3417
case Icode_REG_IND_C4:
3420
case Icode_REG_IND_C5:
3423
case Icode_REG_IND1:
3424
indexReg = 0xFF & iCode[frame.pc];
3427
case Icode_REG_IND2:
3428
indexReg = getIndex(iCode, frame.pc);
3431
case Icode_REG_IND4:
3432
indexReg = getInt(iCode, frame.pc);
3435
case Icode_REG_STR_C0:
3436
stringReg = strings[0];
3438
case Icode_REG_STR_C1:
3439
stringReg = strings[1];
3441
case Icode_REG_STR_C2:
3442
stringReg = strings[2];
3444
case Icode_REG_STR_C3:
3445
stringReg = strings[3];
3447
case Icode_REG_STR1:
3448
stringReg = strings[0xFF & iCode[frame.pc]];
3451
case Icode_REG_STR2:
3452
stringReg = strings[getIndex(iCode, frame.pc)];
3455
case Icode_REG_STR4:
3456
stringReg = strings[getInt(iCode, frame.pc)];
3460
dumpICode(frame.idata);
3461
throw new RuntimeException(
3462
"Unknown icode : "+op+" @ pc : "+(frame.pc-1));
3463
} // end of interpreter switch
3465
} // end of jumplessRun label block
3467
// This should be reachable only for jump implementation
3468
// when pc points to encoded target offset
3469
if (instructionCounting) {
3470
addInstructionCount(cx, frame, 2);
3472
int offset = getShort(iCode, frame.pc);
3474
// -1 accounts for pc pointing to jump opcode + 1
3475
frame.pc += offset - 1;
3477
frame.pc = frame.idata.longJumps.
3478
getExistingInt(frame.pc);
3480
if (instructionCounting) {
3481
frame.pcPrevBranch = frame.pc;
3485
} // end of Loop: for
3487
exitFrame(cx, frame, null);
3488
Object callResult = frame.result;
3489
double callResultDbl = frame.resultDbl;
3490
if (frame.parentFrame != null) {
3491
frame = frame.parentFrame;
3493
frame = frame.cloneFrozen();
3495
setCallResult(frame, callResult, callResultDbl);
3499
return (callResult != DBL_MRK)
3500
? callResult : ScriptRuntime.wrapNumber(callResultDbl);
3502
} // end of interpreter withoutExceptions: try
3503
catch (Throwable ex) {
3504
if (throwable != null) {
3505
// This is serious bug and it is better to track it ASAP
3506
ex.printStackTrace(System.err);
3507
throw new IllegalStateException();
3512
// This should be reachable only after above catch or from
3513
// finally when it needs to propagate exception or from
3515
if (throwable == null) Kit.codeBug();
3518
final int EX_CATCH_STATE = 2; // Can execute JS catch
3519
final int EX_FINALLY_STATE = 1; // Can execute JS finally
3520
final int EX_NO_JS_STATE = 0; // Terminate JS execution
3523
ContinuationJump cjump = null;
3525
if (throwable instanceof JavaScriptException) {
3526
exState = EX_CATCH_STATE;
3527
} else if (throwable instanceof EcmaError) {
3528
// an offical ECMA error object,
3529
exState = EX_CATCH_STATE;
3530
} else if (throwable instanceof EvaluatorException) {
3531
exState = EX_CATCH_STATE;
3532
} else if (throwable instanceof RuntimeException) {
3533
exState = EX_FINALLY_STATE;
3534
} else if (throwable instanceof Error) {
3535
exState = EX_NO_JS_STATE;
3537
// It must be ContinuationJump
3538
exState = EX_FINALLY_STATE;
3539
cjump = (ContinuationJump)throwable;
3542
if (instructionCounting) {
3544
addInstructionCount(cx, frame, EXCEPTION_COST);
3545
} catch (RuntimeException ex) {
3547
exState = EX_FINALLY_STATE;
3548
} catch (Error ex) {
3549
// Error from instruction counting
3550
// => unconditionally terminate JS
3553
exState = EX_NO_JS_STATE;
3556
if (frame.debuggerFrame != null
3557
&& throwable instanceof RuntimeException)
3559
// Call debugger only for RuntimeException
3560
RuntimeException rex = (RuntimeException)throwable;
3562
frame.debuggerFrame.onExceptionThrown(cx, rex);
3563
} catch (Throwable ex) {
3564
// Any exception from debugger
3565
// => unconditionally terminate JS
3568
exState = EX_NO_JS_STATE;
3573
if (exState != EX_NO_JS_STATE) {
3574
boolean onlyFinally = (exState != EX_CATCH_STATE);
3575
indexReg = getExceptionHandler(frame, onlyFinally);
3576
if (indexReg >= 0) {
3577
// We caught an exception, restart the loop
3578
// with exception pending the processing at the loop
3583
// No allowed execption handlers in this frame, unwind
3584
// to parent and try to look there
3586
exitFrame(cx, frame, throwable);
3588
frame = frame.parentFrame;
3589
if (frame == null) { break; }
3590
if (cjump != null && cjump.branchFrame == frame) {
3591
// Continuation branch point was hit,
3592
// restart the state loop to reenter continuation
3598
// No more frames, rethrow the exception or deal with continuation
3599
if (cjump != null) {
3600
if (cjump.branchFrame != null) {
3601
// The above loop should locate the top frame
3604
if (cjump.capturedFrame != null) {
3605
// Restarting detached continuation
3609
// Return continuation result to the caller
3610
return (cjump.result != DBL_MRK)
3611
? cjump.result : ScriptRuntime.wrapNumber(cjump.resultDbl);
3613
if (throwable instanceof RuntimeException) {
3614
throw (RuntimeException)throwable;
3616
// Must be instance of Error or code bug
3617
throw (Error)throwable;
3620
} // end of StateLoop: for(;;)
3623
private static void initFrame(Context cx, Scriptable callerScope,
3625
Object[] args, double[] argsDbl,
3626
int argShift, int argCount,
3627
InterpretedFunction fnOrScript,
3628
CallFrame parentFrame, CallFrame frame)
3630
InterpreterData idata = fnOrScript.idata;
3632
boolean useActivation = idata.itsNeedsActivation;
3633
DebugFrame debuggerFrame = null;
3634
if (cx.debugger != null) {
3635
debuggerFrame = cx.debugger.getFrame(cx, idata);
3636
if (debuggerFrame != null) {
3637
useActivation = true;
3641
if (useActivation) {
3642
// Copy args to new array to pass to enterActivationFunction
3643
// or debuggerFrame.onEnter
3644
if (argsDbl != null) {
3645
args = getArgsArray(args, argsDbl, argShift, argCount);
3652
if (idata.itsFunctionType != 0) {
3653
if (!idata.useDynamicScope) {
3654
scope = fnOrScript.getParentScope();
3656
scope = callerScope;
3659
if (useActivation) {
3660
scope = ScriptRuntime.createFunctionActivation(
3661
fnOrScript, scope, args);
3664
scope = callerScope;
3665
ScriptRuntime.initScript(fnOrScript, thisObj, cx, scope,
3666
fnOrScript.idata.evalScriptFlag);
3669
if (idata.itsNestedFunctions != null) {
3670
if (idata.itsFunctionType != 0 && !idata.itsNeedsActivation)
3672
for (int i = 0; i < idata.itsNestedFunctions.length; i++) {
3673
InterpreterData fdata = idata.itsNestedFunctions[i];
3674
if (fdata.itsFunctionType == FunctionNode.FUNCTION_STATEMENT) {
3675
initFunction(cx, scope, fnOrScript, i);
3680
Scriptable[] scriptRegExps = null;
3681
if (idata.itsRegExpLiterals != null) {
3682
// Wrapped regexps for functions are stored in
3683
// InterpretedFunction
3684
// but for script which should not contain references to scope
3685
// the regexps re-wrapped during each script execution
3686
if (idata.itsFunctionType != 0) {
3687
scriptRegExps = fnOrScript.functionRegExps;
3689
scriptRegExps = fnOrScript.createRegExpWraps(cx, scope);
3693
// Initialize args, vars, locals and stack
3695
int emptyStackTop = idata.itsMaxVars + idata.itsMaxLocals - 1;
3696
int maxFrameArray = idata.itsMaxFrameArray;
3697
if (maxFrameArray != emptyStackTop + idata.itsMaxStack + 1)
3703
if (frame.stack != null && maxFrameArray <= frame.stack.length) {
3704
// Reuse stacks from old frame
3706
stack = frame.stack;
3710
stack = new Object[maxFrameArray];
3711
sDbl = new double[maxFrameArray];
3714
int definedArgs = idata.argCount;
3715
if (definedArgs > argCount) { definedArgs = argCount; }
3717
// Fill the frame structure
3719
frame.parentFrame = parentFrame;
3720
frame.frameIndex = (parentFrame == null)
3721
? 0 : parentFrame.frameIndex + 1;
3722
frame.frozen = false;
3724
frame.fnOrScript = fnOrScript;
3725
frame.idata = idata;
3727
frame.stack = stack;
3729
frame.varSource = frame;
3730
frame.localShift = idata.itsMaxVars;
3731
frame.emptyStackTop = emptyStackTop;
3733
frame.debuggerFrame = debuggerFrame;
3734
frame.useActivation = useActivation;
3736
frame.thisObj = thisObj;
3737
frame.scriptRegExps = scriptRegExps;
3739
// Initialize initial values of variables that change during
3741
frame.result = Undefined.instance;
3743
frame.pcPrevBranch = 0;
3744
frame.pcSourceLineStart = idata.firstLinePC;
3745
frame.scope = scope;
3747
frame.savedStackTop = emptyStackTop;
3748
frame.savedCallOp = 0;
3750
System.arraycopy(args, argShift, stack, 0, definedArgs);
3751
if (argsDbl != null) {
3752
System.arraycopy(argsDbl, argShift, sDbl, 0, definedArgs);
3754
for (int i = definedArgs; i != idata.itsMaxVars; ++i) {
3755
stack[i] = Undefined.instance;
3758
// Clean the stack part and space beyond stack if any
3759
// of the old array to allow to GC objects there
3760
for (int i = emptyStackTop + 1; i != stack.length; ++i) {
3765
enterFrame(cx, frame, args);
3768
private static boolean isFrameEnterExitRequired(CallFrame frame)
3770
return frame.debuggerFrame != null || frame.idata.itsNeedsActivation;
3773
private static void enterFrame(Context cx, CallFrame frame, Object[] args)
3775
if (frame.debuggerFrame != null) {
3776
frame.debuggerFrame.onEnter(cx, frame.scope, frame.thisObj, args);
3778
if (frame.idata.itsNeedsActivation) {
3779
// Enter activation only when itsNeedsActivation true, not when
3780
// useActivation holds since debugger should not interfere
3781
// with activation chaining
3782
ScriptRuntime.enterActivationFunction(cx, frame.scope);
3786
private static void exitFrame(Context cx, CallFrame frame,
3789
if (frame.idata.itsNeedsActivation) {
3790
ScriptRuntime.exitActivationFunction(cx);
3793
if (frame.debuggerFrame != null) {
3795
if (throwable instanceof Throwable) {
3796
frame.debuggerFrame.onExit(cx, true, (Throwable)throwable);
3799
ContinuationJump cjump = (ContinuationJump)throwable;
3800
if (cjump == null) {
3801
result = frame.result;
3803
result = cjump.result;
3805
if (result == UniqueTag.DOUBLE_MARK) {
3807
if (cjump == null) {
3808
resultDbl = frame.resultDbl;
3810
resultDbl = cjump.resultDbl;
3812
result = ScriptRuntime.wrapNumber(resultDbl);
3814
frame.debuggerFrame.onExit(cx, false, result);
3816
} catch (Throwable ex) {
3818
"RHINO USAGE WARNING: onExit terminated with exception");
3819
ex.printStackTrace(System.err);
3824
private static void setCallResult(CallFrame frame,
3826
double callResultDbl)
3828
if (frame.savedCallOp == Token.CALL) {
3829
frame.stack[frame.savedStackTop] = callResult;
3830
frame.sDbl[frame.savedStackTop] = callResultDbl;
3831
} else if (frame.savedCallOp == Token.NEW) {
3832
// If construct returns scriptable,
3833
// then it replaces on stack top saved original instance
3835
if (callResult instanceof Scriptable
3836
&& callResult != Undefined.instance)
3838
frame.stack[frame.savedStackTop] = callResult;
3843
frame.savedCallOp = 0;
3846
private static void captureContinuation(Context cx, CallFrame frame,
3849
Continuation c = new Continuation();
3850
ScriptRuntime.setObjectProtoAndParent(
3851
c, ScriptRuntime.getTopCallScope(cx));
3853
// Make sure that all frames upstack frames are frozen
3854
CallFrame x = frame.parentFrame;
3855
while (x != null && !x.frozen) {
3857
// Allow to GC unused stack space
3858
for (int i = x.savedStackTop + 1; i != x.stack.length; ++i) {
3859
// Allow to GC unused stack space
3862
if (x.savedCallOp == Token.CALL) {
3863
// the call will always overwrite the stack top with the result
3864
x.stack[x.savedStackTop] = null;
3866
if (x.savedCallOp != Token.NEW) Kit.codeBug();
3867
// the new operator uses stack top to store the constructed
3868
// object so it shall not be cleared: see comments in
3874
c.initImplementation(frame.parentFrame);
3875
frame.stack[stackTop] = c;
3878
private static int stack_int32(CallFrame frame, int i)
3880
Object x = frame.stack[i];
3882
if (x == UniqueTag.DOUBLE_MARK) {
3883
value = frame.sDbl[i];
3885
value = ScriptRuntime.toNumber(x);
3887
return ScriptRuntime.toInt32(value);
3890
private static double stack_double(CallFrame frame, int i)
3892
Object x = frame.stack[i];
3893
if (x != UniqueTag.DOUBLE_MARK) {
3894
return ScriptRuntime.toNumber(x);
3896
return frame.sDbl[i];
3900
private static boolean stack_boolean(CallFrame frame, int i)
3902
Object x = frame.stack[i];
3903
if (x == Boolean.TRUE) {
3905
} else if (x == Boolean.FALSE) {
3907
} else if (x == UniqueTag.DOUBLE_MARK) {
3908
double d = frame.sDbl[i];
3909
return d == d && d != 0.0;
3910
} else if (x == null || x == Undefined.instance) {
3912
} else if (x instanceof Number) {
3913
double d = ((Number)x).doubleValue();
3914
return (d == d && d != 0.0);
3915
} else if (x instanceof Boolean) {
3916
return ((Boolean)x).booleanValue();
3918
return ScriptRuntime.toBoolean(x);
3922
private static void do_add(Object[] stack, double[] sDbl, int stackTop,
3925
Object rhs = stack[stackTop + 1];
3926
Object lhs = stack[stackTop];
3928
boolean leftRightOrder;
3929
if (rhs == UniqueTag.DOUBLE_MARK) {
3930
d = sDbl[stackTop + 1];
3931
if (lhs == UniqueTag.DOUBLE_MARK) {
3932
sDbl[stackTop] += d;
3935
leftRightOrder = true;
3936
// fallthrough to object + number code
3937
} else if (lhs == UniqueTag.DOUBLE_MARK) {
3940
leftRightOrder = false;
3941
// fallthrough to object + number code
3943
if (lhs instanceof Scriptable || rhs instanceof Scriptable) {
3944
stack[stackTop] = ScriptRuntime.add(lhs, rhs, cx);
3945
} else if (lhs instanceof String) {
3946
String lstr = (String)lhs;
3947
String rstr = ScriptRuntime.toString(rhs);
3948
stack[stackTop] = lstr.concat(rstr);
3949
} else if (rhs instanceof String) {
3950
String lstr = ScriptRuntime.toString(lhs);
3951
String rstr = (String)rhs;
3952
stack[stackTop] = lstr.concat(rstr);
3954
double lDbl = (lhs instanceof Number)
3955
? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);
3956
double rDbl = (rhs instanceof Number)
3957
? ((Number)rhs).doubleValue() : ScriptRuntime.toNumber(rhs);
3958
stack[stackTop] = UniqueTag.DOUBLE_MARK;
3959
sDbl[stackTop] = lDbl + rDbl;
3964
// handle object(lhs) + number(d) code
3965
if (lhs instanceof Scriptable) {
3966
rhs = ScriptRuntime.wrapNumber(d);
3967
if (!leftRightOrder) {
3972
stack[stackTop] = ScriptRuntime.add(lhs, rhs, cx);
3973
} else if (lhs instanceof String) {
3974
String lstr = (String)lhs;
3975
String rstr = ScriptRuntime.toString(d);
3976
if (leftRightOrder) {
3977
stack[stackTop] = lstr.concat(rstr);
3979
stack[stackTop] = rstr.concat(lstr);
3982
double lDbl = (lhs instanceof Number)
3983
? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);
3984
stack[stackTop] = UniqueTag.DOUBLE_MARK;
3985
sDbl[stackTop] = lDbl + d;
3989
private static Object[] getArgsArray(Object[] stack, double[] sDbl,
3990
int shift, int count)
3993
return ScriptRuntime.emptyArgs;
3995
Object[] args = new Object[count];
3996
for (int i = 0; i != count; ++i, ++shift) {
3997
Object val = stack[shift];
3998
if (val == UniqueTag.DOUBLE_MARK) {
3999
val = ScriptRuntime.wrapNumber(sDbl[shift]);
4006
private static void addInstructionCount(Context cx, CallFrame frame,
4009
cx.instructionCount += frame.pc - frame.pcPrevBranch + extra;
4010
if (cx.instructionCount > cx.instructionThreshold) {
4011
cx.observeInstructionCount(cx.instructionCount);
4012
cx.instructionCount = 0;