1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
\r
3 * The contents of this file are subject to the Netscape Public
\r
4 * License Version 1.1 (the "License"); you may not use this file
\r
5 * except in compliance with the License. You may obtain a copy of
\r
6 * the License at http://www.mozilla.org/NPL/
\r
8 * Software distributed under the License is distributed on an "AS
\r
9 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
\r
10 * implied. See the License for the specific language governing
\r
11 * rights and limitations under the License.
\r
13 * The Original Code is Rhino code, released
\r
16 * The Initial Developer of the Original Code is Netscape
\r
17 * Communications Corporation. Portions created by Netscape are
\r
18 * Copyright (C) 1997-2000 Netscape Communications Corporation. All
\r
27 * Alternatively, the contents of this file may be used under the
\r
28 * terms of the GNU Public License (the "GPL"), in which case the
\r
29 * provisions of the GPL are applicable instead of those above.
\r
30 * If you wish to allow use of your version of this file only
\r
31 * under the terms of the GPL and not to allow others to use your
\r
32 * version of this file under the NPL, indicate your decision by
\r
33 * deleting the provisions above and replace them with the notice
\r
34 * and other provisions required by the GPL. If you do not delete
\r
35 * the provisions above, a recipient may use your version of this
\r
36 * file under either the NPL or the GPL.
\r
39 package org.mozilla.javascript;
\r
42 import java.util.Vector;
\r
43 import java.util.Enumeration;
\r
45 import org.mozilla.javascript.debug.*;
\r
47 public class Interpreter extends LabelTable {
\r
49 public static final boolean printICode = false;
\r
51 public IRFactory createIRFactory(TokenStream ts,
\r
52 ClassNameHelper nameHelper, Scriptable scope)
\r
54 return new IRFactory(ts, scope);
\r
57 public Node transform(Node tree, TokenStream ts, Scriptable scope) {
\r
58 return (new NodeTransformer()).transform(tree, null, ts, scope);
\r
61 public Object compile(Context cx, Scriptable scope, Node tree,
\r
62 Object securityDomain,
\r
63 SecuritySupport securitySupport,
\r
64 ClassNameHelper nameHelper)
\r
67 version = cx.getLanguageVersion();
\r
68 itsData = new InterpreterData(0, 0, 0, securityDomain,
\r
69 cx.hasCompileFunctionsWithDynamicScope(), false);
\r
70 if (tree instanceof FunctionNode) {
\r
71 FunctionNode f = (FunctionNode) tree;
\r
72 InterpretedFunction result =
\r
73 generateFunctionICode(cx, scope, f, securityDomain);
\r
74 result.itsData.itsFunctionType = f.getFunctionType();
\r
75 createFunctionObject(result, scope);
\r
78 return generateScriptICode(cx, scope, tree, securityDomain);
\r
81 private void generateICodeFromTree(Node tree,
\r
82 VariableTable varTable,
\r
83 boolean needsActivation,
\r
84 Object securityDomain)
\r
86 int theICodeTop = 0;
\r
87 itsVariableTable = varTable;
\r
88 itsData.itsNeedsActivation = needsActivation;
\r
89 theICodeTop = generateICode(tree, theICodeTop);
\r
90 itsData.itsICodeTop = theICodeTop;
\r
91 if (itsEpilogLabel != -1)
\r
92 markLabel(itsEpilogLabel, theICodeTop);
\r
93 for (int i = 0; i < itsLabelTableTop; i++)
\r
94 itsLabelTable[i].fixGotos(itsData.itsICode);
\r
97 private Object[] generateRegExpLiterals(Context cx,
\r
101 Object[] result = new Object[regexps.size()];
\r
102 RegExpProxy rep = cx.getRegExpProxy();
\r
103 for (int i = 0; i < regexps.size(); i++) {
\r
104 Node regexp = (Node) regexps.elementAt(i);
\r
105 Node left = regexp.getFirstChild();
\r
106 Node right = regexp.getLastChild();
\r
107 result[i] = rep.newRegExp(cx, scope, left.getString(),
\r
108 (left != right) ? right.getString() : null, false);
\r
109 regexp.putProp(Node.REGEXP_PROP, new Integer(i));
\r
114 private InterpretedScript generateScriptICode(Context cx,
\r
117 Object securityDomain)
\r
119 itsSourceFile = (String) tree.getProp(Node.SOURCENAME_PROP);
\r
120 itsData.itsSourceFile = itsSourceFile;
\r
121 itsFunctionList = (Vector) tree.getProp(Node.FUNCTION_PROP);
\r
122 debugSource = (StringBuffer) tree.getProp(Node.DEBUGSOURCE_PROP);
\r
123 if (itsFunctionList != null)
\r
124 generateNestedFunctions(scope, cx, securityDomain);
\r
125 Object[] regExpLiterals = null;
\r
126 Vector regexps = (Vector)tree.getProp(Node.REGEXP_PROP);
\r
127 if (regexps != null)
\r
128 regExpLiterals = generateRegExpLiterals(cx, scope, regexps);
\r
130 VariableTable varTable = (VariableTable)tree.getProp(Node.VARS_PROP);
\r
131 // The default is not to generate debug information
\r
132 boolean activationNeeded = cx.isGeneratingDebugChanged() &&
\r
133 cx.isGeneratingDebug();
\r
134 generateICodeFromTree(tree, varTable, activationNeeded, securityDomain);
\r
135 itsData.itsNestedFunctions = itsNestedFunctions;
\r
136 itsData.itsRegExpLiterals = regExpLiterals;
\r
137 if (printICode) dumpICode(itsData);
\r
139 String[] argNames = itsVariableTable.getAllNames();
\r
140 short argCount = (short)itsVariableTable.getParameterCount();
\r
142 result = new InterpretedScript(cx, itsData, argNames, argCount);
\r
143 if (cx.debugger != null) {
\r
144 cx.debugger.handleCompilationDone(cx, result, debugSource);
\r
149 private void generateNestedFunctions(Scriptable scope,
\r
151 Object securityDomain)
\r
153 itsNestedFunctions = new InterpretedFunction[itsFunctionList.size()];
\r
154 for (short i = 0; i < itsFunctionList.size(); i++) {
\r
155 FunctionNode def = (FunctionNode)itsFunctionList.elementAt(i);
\r
156 Interpreter jsi = new Interpreter();
\r
157 jsi.itsSourceFile = itsSourceFile;
\r
158 jsi.itsData = new InterpreterData(0, 0, 0, securityDomain,
\r
159 cx.hasCompileFunctionsWithDynamicScope(),
\r
160 def.getCheckThis());
\r
161 jsi.itsData.itsFunctionType = def.getFunctionType();
\r
162 jsi.itsInFunctionFlag = true;
\r
163 jsi.debugSource = debugSource;
\r
164 itsNestedFunctions[i] = jsi.generateFunctionICode(cx, scope, def,
\r
166 def.putProp(Node.FUNCTION_PROP, new Short(i));
\r
170 private InterpretedFunction
\r
171 generateFunctionICode(Context cx, Scriptable scope,
\r
172 FunctionNode theFunction, Object securityDomain)
\r
174 itsFunctionList = (Vector) theFunction.getProp(Node.FUNCTION_PROP);
\r
175 if (itsFunctionList != null)
\r
176 generateNestedFunctions(scope, cx, securityDomain);
\r
177 Object[] regExpLiterals = null;
\r
178 Vector regexps = (Vector)theFunction.getProp(Node.REGEXP_PROP);
\r
179 if (regexps != null)
\r
180 regExpLiterals = generateRegExpLiterals(cx, scope, regexps);
\r
182 VariableTable varTable = theFunction.getVariableTable();
\r
183 boolean needsActivation = theFunction.requiresActivation() ||
\r
184 (cx.isGeneratingDebugChanged() &&
\r
185 cx.isGeneratingDebug());
\r
186 generateICodeFromTree(theFunction.getLastChild(),
\r
187 varTable, needsActivation,
\r
190 itsData.itsName = theFunction.getFunctionName();
\r
191 itsData.itsSourceFile = (String) theFunction.getProp(
\r
192 Node.SOURCENAME_PROP);
\r
193 itsData.itsSource = (String)theFunction.getProp(Node.SOURCE_PROP);
\r
194 itsData.itsNestedFunctions = itsNestedFunctions;
\r
195 itsData.itsRegExpLiterals = regExpLiterals;
\r
196 if (printICode) dumpICode(itsData);
\r
198 String[] argNames = itsVariableTable.getAllNames();
\r
199 short argCount = (short)itsVariableTable.getParameterCount();
\r
200 InterpretedFunction
\r
201 result = new InterpretedFunction(cx, itsData, argNames, argCount);
\r
202 if (cx.debugger != null) {
\r
203 cx.debugger.handleCompilationDone(cx, result, debugSource);
\r
208 boolean itsInFunctionFlag;
\r
209 Vector itsFunctionList;
\r
211 InterpreterData itsData;
\r
212 VariableTable itsVariableTable;
\r
213 int itsTryDepth = 0;
\r
214 int itsStackDepth = 0;
\r
215 int itsEpilogLabel = -1;
\r
216 String itsSourceFile;
\r
217 int itsLineNumber = 0;
\r
218 InterpretedFunction[] itsNestedFunctions = null;
\r
220 private int updateLineNumber(Node node, int iCodeTop)
\r
222 Object datum = node.getDatum();
\r
223 if (datum == null || !(datum instanceof Number))
\r
225 short lineNumber = ((Number) datum).shortValue();
\r
226 if (lineNumber != itsLineNumber) {
\r
227 itsLineNumber = lineNumber;
\r
228 if (itsData.itsLineNumberTable == null &&
\r
229 Context.getCurrentContext().isGeneratingDebug())
\r
231 itsData.itsLineNumberTable = new UintMap();
\r
233 if (itsData.itsLineNumberTable != null) {
\r
234 itsData.itsLineNumberTable.put(lineNumber, iCodeTop);
\r
236 iCodeTop = addByte((byte) TokenStream.LINE, iCodeTop);
\r
237 iCodeTop = addByte((byte)(lineNumber >> 8), iCodeTop);
\r
238 iCodeTop = addByte((byte)(lineNumber & 0xff), iCodeTop);
\r
245 private void badTree(Node node)
\r
248 out = new PrintWriter(new FileOutputStream("icode.txt", true));
\r
249 out.println("Un-handled node : " + node.toString());
\r
252 catch (IOException x) {}
\r
253 throw new RuntimeException("Un-handled node : "
\r
254 + node.toString());
\r
257 private int generateICode(Node node, int iCodeTop) {
\r
258 int type = node.getType();
\r
259 Node child = node.getFirstChild();
\r
260 Node firstChild = child;
\r
263 case TokenStream.FUNCTION : {
\r
264 iCodeTop = addByte((byte) TokenStream.CLOSURE, iCodeTop);
\r
265 Node fn = (Node) node.getProp(Node.FUNCTION_PROP);
\r
266 Short index = (Short) fn.getProp(Node.FUNCTION_PROP);
\r
267 iCodeTop = addByte((byte)(index.shortValue() >> 8), iCodeTop);
\r
268 iCodeTop = addByte((byte)(index.shortValue() & 0xff), iCodeTop);
\r
270 if (itsStackDepth > itsData.itsMaxStack)
\r
271 itsData.itsMaxStack = itsStackDepth;
\r
275 case TokenStream.SCRIPT :
\r
276 iCodeTop = updateLineNumber(node, iCodeTop);
\r
277 while (child != null) {
\r
278 if (child.getType() != TokenStream.FUNCTION)
\r
279 iCodeTop = generateICode(child, iCodeTop);
\r
280 child = child.getNextSibling();
\r
284 case TokenStream.CASE :
\r
285 iCodeTop = updateLineNumber(node, iCodeTop);
\r
286 child = child.getNextSibling();
\r
287 while (child != null) {
\r
288 iCodeTop = generateICode(child, iCodeTop);
\r
289 child = child.getNextSibling();
\r
293 case TokenStream.LABEL :
\r
294 case TokenStream.WITH :
\r
295 case TokenStream.LOOP :
\r
296 case TokenStream.DEFAULT :
\r
297 case TokenStream.BLOCK :
\r
298 case TokenStream.VOID :
\r
299 case TokenStream.NOP :
\r
300 iCodeTop = updateLineNumber(node, iCodeTop);
\r
301 while (child != null) {
\r
302 iCodeTop = generateICode(child, iCodeTop);
\r
303 child = child.getNextSibling();
\r
307 case TokenStream.COMMA :
\r
308 iCodeTop = generateICode(child, iCodeTop);
\r
309 iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
\r
311 child = child.getNextSibling();
\r
312 iCodeTop = generateICode(child, iCodeTop);
\r
315 case TokenStream.SWITCH : {
\r
316 iCodeTop = updateLineNumber(node, iCodeTop);
\r
317 iCodeTop = generateICode(child, iCodeTop);
\r
318 int theLocalSlot = itsData.itsMaxLocals++;
\r
319 iCodeTop = addByte((byte) TokenStream.NEWTEMP, iCodeTop);
\r
320 iCodeTop = addByte((byte)theLocalSlot, iCodeTop);
\r
321 iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
\r
324 reminder - below we construct new GOTO nodes that aren't
\r
325 linked into the tree just for the purpose of having a node
\r
326 to pass to the addGoto routine. (Parallels codegen here).
\r
327 Seems unnecessary.
\r
329 Vector cases = (Vector) node.getProp(Node.CASES_PROP);
\r
330 for (int i = 0; i < cases.size(); i++) {
\r
331 Node thisCase = (Node)cases.elementAt(i);
\r
332 Node first = thisCase.getFirstChild();
\r
333 // the case expression is the firstmost child
\r
334 // the rest will be generated when the case
\r
335 // statements are encountered as siblings of
\r
336 // the switch statement.
\r
337 iCodeTop = generateICode(first, iCodeTop);
\r
338 iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);
\r
340 if (itsStackDepth > itsData.itsMaxStack)
\r
341 itsData.itsMaxStack = itsStackDepth;
\r
342 iCodeTop = addByte((byte) theLocalSlot, iCodeTop);
\r
343 iCodeTop = addByte((byte) TokenStream.SHEQ, iCodeTop);
\r
344 Node target = new Node(TokenStream.TARGET);
\r
345 thisCase.addChildAfter(target, first);
\r
346 Node branch = new Node(TokenStream.IFEQ);
\r
347 branch.putProp(Node.TARGET_PROP, target);
\r
348 iCodeTop = addGoto(branch, TokenStream.IFEQ,
\r
353 Node defaultNode = (Node) node.getProp(Node.DEFAULT_PROP);
\r
354 if (defaultNode != null) {
\r
355 Node defaultTarget = new Node(TokenStream.TARGET);
\r
356 defaultNode.getFirstChild().addChildToFront(defaultTarget);
\r
357 Node branch = new Node(TokenStream.GOTO);
\r
358 branch.putProp(Node.TARGET_PROP, defaultTarget);
\r
359 iCodeTop = addGoto(branch, TokenStream.GOTO,
\r
363 Node breakTarget = (Node) node.getProp(Node.BREAK_PROP);
\r
364 Node branch = new Node(TokenStream.GOTO);
\r
365 branch.putProp(Node.TARGET_PROP, breakTarget);
\r
366 iCodeTop = addGoto(branch, TokenStream.GOTO,
\r
371 case TokenStream.TARGET : {
\r
372 Object lblObect = node.getProp(Node.LABEL_PROP);
\r
373 if (lblObect == null) {
\r
374 int label = markLabel(acquireLabel(), iCodeTop);
\r
375 node.putProp(Node.LABEL_PROP, new Integer(label));
\r
378 int label = ((Integer)lblObect).intValue();
\r
379 markLabel(label, iCodeTop);
\r
381 // if this target has a FINALLY_PROP, it is a JSR target
\r
382 // and so has a PC value on the top of the stack
\r
383 if (node.getProp(Node.FINALLY_PROP) != null) {
\r
385 if (itsStackDepth > itsData.itsMaxStack)
\r
386 itsData.itsMaxStack = itsStackDepth;
\r
391 case TokenStream.EQOP :
\r
392 case TokenStream.RELOP : {
\r
393 iCodeTop = generateICode(child, iCodeTop);
\r
394 child = child.getNextSibling();
\r
395 iCodeTop = generateICode(child, iCodeTop);
\r
396 int op = node.getInt();
\r
397 if (version == Context.VERSION_1_2) {
\r
398 if (op == TokenStream.EQ)
\r
399 op = TokenStream.SHEQ;
\r
400 else if (op == TokenStream.NE)
\r
401 op = TokenStream.SHNE;
\r
403 iCodeTop = addByte((byte) op, iCodeTop);
\r
408 case TokenStream.NEW :
\r
409 case TokenStream.CALL : {
\r
410 if (itsSourceFile != null && (itsData.itsSourceFile == null || ! itsSourceFile.equals(itsData.itsSourceFile)))
\r
411 itsData.itsSourceFile = itsSourceFile;
\r
412 iCodeTop = addByte((byte)TokenStream.SOURCEFILE, iCodeTop);
\r
414 int childCount = 0;
\r
415 short nameIndex = -1;
\r
416 while (child != null) {
\r
417 iCodeTop = generateICode(child, iCodeTop);
\r
418 if (nameIndex == -1) {
\r
419 if (child.getType() == TokenStream.NAME)
\r
420 nameIndex = (short)(itsData.itsStringTableIndex - 1);
\r
421 else if (child.getType() == TokenStream.GETPROP)
\r
422 nameIndex = (short)(itsData.itsStringTableIndex - 1);
\r
424 child = child.getNextSibling();
\r
427 if (node.getProp(Node.SPECIALCALL_PROP) != null) {
\r
428 // embed line number and source filename
\r
429 iCodeTop = addByte((byte) TokenStream.CALLSPECIAL, iCodeTop);
\r
430 iCodeTop = addByte((byte)(itsLineNumber >> 8), iCodeTop);
\r
431 iCodeTop = addByte((byte)(itsLineNumber & 0xff), iCodeTop);
\r
432 iCodeTop = addString(itsSourceFile, iCodeTop);
\r
434 iCodeTop = addByte((byte) type, iCodeTop);
\r
435 iCodeTop = addByte((byte)(nameIndex >> 8), iCodeTop);
\r
436 iCodeTop = addByte((byte)(nameIndex & 0xFF), iCodeTop);
\r
439 itsStackDepth -= (childCount - 1); // always a result value
\r
440 // subtract from child count to account for [thisObj &] fun
\r
441 if (type == TokenStream.NEW)
\r
445 iCodeTop = addByte((byte)(childCount >> 8), iCodeTop);
\r
446 iCodeTop = addByte((byte)(childCount & 0xff), iCodeTop);
\r
447 if (childCount > itsData.itsMaxArgs)
\r
448 itsData.itsMaxArgs = childCount;
\r
450 iCodeTop = addByte((byte)TokenStream.SOURCEFILE, iCodeTop);
\r
454 case TokenStream.NEWLOCAL :
\r
455 case TokenStream.NEWTEMP : {
\r
456 iCodeTop = generateICode(child, iCodeTop);
\r
457 iCodeTop = addByte((byte) TokenStream.NEWTEMP, iCodeTop);
\r
458 iCodeTop = addLocalRef(node, iCodeTop);
\r
462 case TokenStream.USELOCAL : {
\r
463 if (node.getProp(Node.TARGET_PROP) != null)
\r
464 iCodeTop = addByte((byte) TokenStream.RETSUB, iCodeTop);
\r
466 iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);
\r
468 if (itsStackDepth > itsData.itsMaxStack)
\r
469 itsData.itsMaxStack = itsStackDepth;
\r
471 Node temp = (Node) node.getProp(Node.LOCAL_PROP);
\r
472 iCodeTop = addLocalRef(temp, iCodeTop);
\r
476 case TokenStream.USETEMP : {
\r
477 iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);
\r
478 Node temp = (Node) node.getProp(Node.TEMP_PROP);
\r
479 iCodeTop = addLocalRef(temp, iCodeTop);
\r
481 if (itsStackDepth > itsData.itsMaxStack)
\r
482 itsData.itsMaxStack = itsStackDepth;
\r
486 case TokenStream.IFEQ :
\r
487 case TokenStream.IFNE :
\r
488 iCodeTop = generateICode(child, iCodeTop);
\r
489 itsStackDepth--; // after the conditional GOTO, really
\r
491 case TokenStream.GOTO :
\r
492 iCodeTop = addGoto(node, (byte) type, iCodeTop);
\r
495 case TokenStream.JSR : {
\r
497 mark the target with a FINALLY_PROP to indicate
\r
498 that it will have an incoming PC value on the top
\r
501 This only works if the target follows the JSR
\r
505 Node target = (Node)(node.getProp(Node.TARGET_PROP));
\r
506 target.putProp(Node.FINALLY_PROP, node);
\r
507 iCodeTop = addGoto(node, TokenStream.GOSUB, iCodeTop);
\r
511 case TokenStream.AND : {
\r
512 iCodeTop = generateICode(child, iCodeTop);
\r
513 iCodeTop = addByte((byte) TokenStream.DUP, iCodeTop);
\r
515 if (itsStackDepth > itsData.itsMaxStack)
\r
516 itsData.itsMaxStack = itsStackDepth;
\r
517 int falseTarget = acquireLabel();
\r
518 iCodeTop = addGoto(falseTarget, TokenStream.IFNE,
\r
520 iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
\r
522 child = child.getNextSibling();
\r
523 iCodeTop = generateICode(child, iCodeTop);
\r
524 markLabel(falseTarget, iCodeTop);
\r
528 case TokenStream.OR : {
\r
529 iCodeTop = generateICode(child, iCodeTop);
\r
530 iCodeTop = addByte((byte) TokenStream.DUP, iCodeTop);
\r
532 if (itsStackDepth > itsData.itsMaxStack)
\r
533 itsData.itsMaxStack = itsStackDepth;
\r
534 int trueTarget = acquireLabel();
\r
535 iCodeTop = addGoto(trueTarget, TokenStream.IFEQ,
\r
537 iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
\r
539 child = child.getNextSibling();
\r
540 iCodeTop = generateICode(child, iCodeTop);
\r
541 markLabel(trueTarget, iCodeTop);
\r
545 case TokenStream.GETPROP : {
\r
546 iCodeTop = generateICode(child, iCodeTop);
\r
547 String s = (String) node.getProp(Node.SPECIAL_PROP_PROP);
\r
549 if (s.equals("__proto__"))
\r
550 iCodeTop = addByte((byte) TokenStream.GETPROTO, iCodeTop);
\r
552 if (s.equals("__parent__"))
\r
553 iCodeTop = addByte((byte) TokenStream.GETSCOPEPARENT, iCodeTop);
\r
558 child = child.getNextSibling();
\r
559 iCodeTop = generateICode(child, iCodeTop);
\r
560 iCodeTop = addByte((byte) TokenStream.GETPROP, iCodeTop);
\r
566 case TokenStream.DELPROP :
\r
567 case TokenStream.BITAND :
\r
568 case TokenStream.BITOR :
\r
569 case TokenStream.BITXOR :
\r
570 case TokenStream.LSH :
\r
571 case TokenStream.RSH :
\r
572 case TokenStream.URSH :
\r
573 case TokenStream.ADD :
\r
574 case TokenStream.SUB :
\r
575 case TokenStream.MOD :
\r
576 case TokenStream.DIV :
\r
577 case TokenStream.MUL :
\r
578 case TokenStream.GETELEM :
\r
579 iCodeTop = generateICode(child, iCodeTop);
\r
580 child = child.getNextSibling();
\r
581 iCodeTop = generateICode(child, iCodeTop);
\r
582 iCodeTop = addByte((byte) type, iCodeTop);
\r
586 case TokenStream.CONVERT : {
\r
587 iCodeTop = generateICode(child, iCodeTop);
\r
588 Object toType = node.getProp(Node.TYPE_PROP);
\r
589 if (toType == ScriptRuntime.NumberClass)
\r
590 iCodeTop = addByte((byte) TokenStream.POS, iCodeTop);
\r
596 case TokenStream.UNARYOP :
\r
597 iCodeTop = generateICode(child, iCodeTop);
\r
598 switch (node.getInt()) {
\r
599 case TokenStream.VOID :
\r
600 iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
\r
601 iCodeTop = addByte((byte) TokenStream.UNDEFINED, iCodeTop);
\r
603 case TokenStream.NOT : {
\r
604 int trueTarget = acquireLabel();
\r
605 int beyond = acquireLabel();
\r
606 iCodeTop = addGoto(trueTarget, TokenStream.IFEQ,
\r
608 iCodeTop = addByte((byte) TokenStream.TRUE, iCodeTop);
\r
609 iCodeTop = addGoto(beyond, TokenStream.GOTO,
\r
611 markLabel(trueTarget, iCodeTop);
\r
612 iCodeTop = addByte((byte) TokenStream.FALSE, iCodeTop);
\r
613 markLabel(beyond, iCodeTop);
\r
616 case TokenStream.BITNOT :
\r
617 iCodeTop = addByte((byte) TokenStream.BITNOT, iCodeTop);
\r
619 case TokenStream.TYPEOF :
\r
620 iCodeTop = addByte((byte) TokenStream.TYPEOF, iCodeTop);
\r
622 case TokenStream.SUB :
\r
623 iCodeTop = addByte((byte) TokenStream.NEG, iCodeTop);
\r
625 case TokenStream.ADD :
\r
626 iCodeTop = addByte((byte) TokenStream.POS, iCodeTop);
\r
634 case TokenStream.SETPROP : {
\r
635 iCodeTop = generateICode(child, iCodeTop);
\r
636 child = child.getNextSibling();
\r
637 iCodeTop = generateICode(child, iCodeTop);
\r
638 String s = (String) node.getProp(Node.SPECIAL_PROP_PROP);
\r
640 if (s.equals("__proto__"))
\r
641 iCodeTop = addByte((byte) TokenStream.SETPROTO, iCodeTop);
\r
643 if (s.equals("__parent__"))
\r
644 iCodeTop = addByte((byte) TokenStream.SETPARENT, iCodeTop);
\r
649 child = child.getNextSibling();
\r
650 iCodeTop = generateICode(child, iCodeTop);
\r
651 iCodeTop = addByte((byte) TokenStream.SETPROP, iCodeTop);
\r
652 itsStackDepth -= 2;
\r
657 case TokenStream.SETELEM :
\r
658 iCodeTop = generateICode(child, iCodeTop);
\r
659 child = child.getNextSibling();
\r
660 iCodeTop = generateICode(child, iCodeTop);
\r
661 child = child.getNextSibling();
\r
662 iCodeTop = generateICode(child, iCodeTop);
\r
663 iCodeTop = addByte((byte) type, iCodeTop);
\r
664 itsStackDepth -= 2;
\r
667 case TokenStream.SETNAME :
\r
668 iCodeTop = generateICode(child, iCodeTop);
\r
669 child = child.getNextSibling();
\r
670 iCodeTop = generateICode(child, iCodeTop);
\r
671 iCodeTop = addByte((byte) TokenStream.SETNAME, iCodeTop);
\r
672 iCodeTop = addString(firstChild.getString(), iCodeTop);
\r
676 case TokenStream.TYPEOF : {
\r
677 String name = node.getString();
\r
679 // use typeofname if an activation frame exists
\r
680 // since the vars all exist there instead of in jregs
\r
681 if (itsInFunctionFlag && !itsData.itsNeedsActivation)
\r
682 index = itsVariableTable.getOrdinal(name);
\r
683 if (index == -1) {
\r
684 iCodeTop = addByte((byte) TokenStream.TYPEOFNAME, iCodeTop);
\r
685 iCodeTop = addString(name, iCodeTop);
\r
688 iCodeTop = addByte((byte) TokenStream.GETVAR, iCodeTop);
\r
689 iCodeTop = addByte((byte) index, iCodeTop);
\r
690 iCodeTop = addByte((byte) TokenStream.TYPEOF, iCodeTop);
\r
693 if (itsStackDepth > itsData.itsMaxStack)
\r
694 itsData.itsMaxStack = itsStackDepth;
\r
698 case TokenStream.PARENT :
\r
699 iCodeTop = generateICode(child, iCodeTop);
\r
700 iCodeTop = addByte((byte) TokenStream.GETPARENT, iCodeTop);
\r
703 case TokenStream.GETBASE :
\r
704 case TokenStream.BINDNAME :
\r
705 case TokenStream.NAME :
\r
706 case TokenStream.STRING :
\r
707 iCodeTop = addByte((byte) type, iCodeTop);
\r
708 iCodeTop = addString(node.getString(), iCodeTop);
\r
710 if (itsStackDepth > itsData.itsMaxStack)
\r
711 itsData.itsMaxStack = itsStackDepth;
\r
714 case TokenStream.INC :
\r
715 case TokenStream.DEC : {
\r
716 int childType = child.getType();
\r
717 switch (childType) {
\r
718 case TokenStream.GETVAR : {
\r
719 String name = child.getString();
\r
720 if (itsData.itsNeedsActivation) {
\r
721 iCodeTop = addByte((byte) TokenStream.SCOPE, iCodeTop);
\r
722 iCodeTop = addByte((byte) TokenStream.STRING, iCodeTop);
\r
723 iCodeTop = addString(name, iCodeTop);
\r
724 itsStackDepth += 2;
\r
725 if (itsStackDepth > itsData.itsMaxStack)
\r
726 itsData.itsMaxStack = itsStackDepth;
\r
727 iCodeTop = addByte((byte)
\r
728 (type == TokenStream.INC
\r
729 ? TokenStream.PROPINC
\r
730 : TokenStream.PROPDEC),
\r
735 iCodeTop = addByte((byte)
\r
736 (type == TokenStream.INC
\r
737 ? TokenStream.VARINC
\r
738 : TokenStream.VARDEC),
\r
740 int i = itsVariableTable.getOrdinal(name);
\r
741 iCodeTop = addByte((byte)i, iCodeTop);
\r
743 if (itsStackDepth > itsData.itsMaxStack)
\r
744 itsData.itsMaxStack = itsStackDepth;
\r
748 case TokenStream.GETPROP :
\r
749 case TokenStream.GETELEM : {
\r
750 Node getPropChild = child.getFirstChild();
\r
751 iCodeTop = generateICode(getPropChild,
\r
753 getPropChild = getPropChild.getNextSibling();
\r
754 iCodeTop = generateICode(getPropChild,
\r
756 if (childType == TokenStream.GETPROP)
\r
757 iCodeTop = addByte((byte)
\r
758 (type == TokenStream.INC
\r
759 ? TokenStream.PROPINC
\r
760 : TokenStream.PROPDEC),
\r
763 iCodeTop = addByte((byte)
\r
764 (type == TokenStream.INC
\r
765 ? TokenStream.ELEMINC
\r
766 : TokenStream.ELEMDEC),
\r
772 iCodeTop = addByte((byte)
\r
773 (type == TokenStream.INC
\r
774 ? TokenStream.NAMEINC
\r
775 : TokenStream.NAMEDEC),
\r
777 iCodeTop = addString(child.getString(),
\r
780 if (itsStackDepth > itsData.itsMaxStack)
\r
781 itsData.itsMaxStack = itsStackDepth;
\r
788 case TokenStream.NUMBER : {
\r
789 double num = node.getDouble();
\r
791 iCodeTop = addByte((byte) TokenStream.ZERO, iCodeTop);
\r
793 else if (num == 1.0) {
\r
794 iCodeTop = addByte((byte) TokenStream.ONE, iCodeTop);
\r
797 iCodeTop = addByte((byte) TokenStream.NUMBER, iCodeTop);
\r
798 iCodeTop = addNumber(num, iCodeTop);
\r
801 if (itsStackDepth > itsData.itsMaxStack)
\r
802 itsData.itsMaxStack = itsStackDepth;
\r
806 case TokenStream.POP :
\r
807 case TokenStream.POPV :
\r
808 iCodeTop = updateLineNumber(node, iCodeTop);
\r
809 case TokenStream.ENTERWITH :
\r
810 iCodeTop = generateICode(child, iCodeTop);
\r
811 iCodeTop = addByte((byte) type, iCodeTop);
\r
815 case TokenStream.GETTHIS :
\r
816 iCodeTop = generateICode(child, iCodeTop);
\r
817 iCodeTop = addByte((byte) type, iCodeTop);
\r
820 case TokenStream.NEWSCOPE :
\r
821 iCodeTop = addByte((byte) type, iCodeTop);
\r
823 if (itsStackDepth > itsData.itsMaxStack)
\r
824 itsData.itsMaxStack = itsStackDepth;
\r
827 case TokenStream.LEAVEWITH :
\r
828 iCodeTop = addByte((byte) type, iCodeTop);
\r
831 case TokenStream.TRY : {
\r
833 if (itsTryDepth > itsData.itsMaxTryDepth)
\r
834 itsData.itsMaxTryDepth = itsTryDepth;
\r
835 Node catchTarget = (Node)node.getProp(Node.TARGET_PROP);
\r
836 Node finallyTarget = (Node)node.getProp(Node.FINALLY_PROP);
\r
837 if (catchTarget == null) {
\r
838 iCodeTop = addByte((byte) TokenStream.TRY, iCodeTop);
\r
839 iCodeTop = addByte((byte)0, iCodeTop);
\r
840 iCodeTop = addByte((byte)0, iCodeTop);
\r
844 addGoto(node, TokenStream.TRY, iCodeTop);
\r
845 int finallyHandler = 0;
\r
846 if (finallyTarget != null) {
\r
847 finallyHandler = acquireLabel();
\r
848 int theLabel = finallyHandler & 0x7FFFFFFF;
\r
849 itsLabelTable[theLabel].addFixup(iCodeTop);
\r
851 iCodeTop = addByte((byte)0, iCodeTop);
\r
852 iCodeTop = addByte((byte)0, iCodeTop);
\r
854 Node lastChild = null;
\r
856 when we encounter the child of the catchTarget, we
\r
857 set the stackDepth to 1 to account for the incoming
\r
860 boolean insertedEndTry = false;
\r
861 while (child != null) {
\r
862 if (catchTarget != null && lastChild == catchTarget) {
\r
864 if (itsStackDepth > itsData.itsMaxStack)
\r
865 itsData.itsMaxStack = itsStackDepth;
\r
868 When the following child is the catchTarget
\r
869 (or the finallyTarget if there are no catches),
\r
870 the current child is the goto at the end of
\r
871 the try statemets, we need to emit the endtry
\r
874 Node nextSibling = child.getNextSibling();
\r
875 if (!insertedEndTry && nextSibling != null &&
\r
876 (nextSibling == catchTarget ||
\r
877 nextSibling == finallyTarget))
\r
879 iCodeTop = addByte((byte) TokenStream.ENDTRY,
\r
881 insertedEndTry = true;
\r
883 iCodeTop = generateICode(child, iCodeTop);
\r
885 child = child.getNextSibling();
\r
888 if (finallyTarget != null) {
\r
889 // normal flow goes around the finally handler stublet
\r
890 int skippy = acquireLabel();
\r
892 addGoto(skippy, TokenStream.GOTO, iCodeTop);
\r
893 // on entry the stack will have the exception object
\r
894 markLabel(finallyHandler, iCodeTop);
\r
896 if (itsStackDepth > itsData.itsMaxStack)
\r
897 itsData.itsMaxStack = itsStackDepth;
\r
898 int theLocalSlot = itsData.itsMaxLocals++;
\r
899 iCodeTop = addByte((byte) TokenStream.NEWTEMP, iCodeTop);
\r
900 iCodeTop = addByte((byte)theLocalSlot, iCodeTop);
\r
901 iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);
\r
902 Integer finallyLabel
\r
903 = (Integer)(finallyTarget.getProp(Node.LABEL_PROP));
\r
904 iCodeTop = addGoto(finallyLabel.intValue(),
\r
905 TokenStream.GOSUB, iCodeTop);
\r
906 iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);
\r
907 iCodeTop = addByte((byte)theLocalSlot, iCodeTop);
\r
908 iCodeTop = addByte((byte) TokenStream.JTHROW, iCodeTop);
\r
910 markLabel(skippy, iCodeTop);
\r
916 case TokenStream.THROW :
\r
917 iCodeTop = updateLineNumber(node, iCodeTop);
\r
918 iCodeTop = generateICode(child, iCodeTop);
\r
919 iCodeTop = addByte((byte) TokenStream.THROW, iCodeTop);
\r
923 case TokenStream.ASSERT:
\r
924 iCodeTop = updateLineNumber(node, iCodeTop);
\r
925 if (child != null)
\r
926 iCodeTop = generateICode(child, iCodeTop);
\r
928 iCodeTop = addByte((byte) TokenStream.UNDEFINED, iCodeTop);
\r
930 if (itsStackDepth > itsData.itsMaxStack)
\r
931 itsData.itsMaxStack = itsStackDepth;
\r
933 iCodeTop = addGoto(node, TokenStream.ASSERT, iCodeTop);
\r
937 case TokenStream.RETURN :
\r
938 iCodeTop = updateLineNumber(node, iCodeTop);
\r
939 if (child != null)
\r
940 iCodeTop = generateICode(child, iCodeTop);
\r
942 iCodeTop = addByte((byte) TokenStream.UNDEFINED, iCodeTop);
\r
944 if (itsStackDepth > itsData.itsMaxStack)
\r
945 itsData.itsMaxStack = itsStackDepth;
\r
947 iCodeTop = addGoto(node, TokenStream.RETURN, iCodeTop);
\r
951 case TokenStream.GETVAR : {
\r
952 String name = node.getString();
\r
953 if (itsData.itsNeedsActivation) {
\r
954 // SETVAR handled this by turning into a SETPROP, but
\r
955 // we can't do that to a GETVAR without manufacturing
\r
956 // bogus children. Instead we use a special op to
\r
957 // push the current scope.
\r
958 iCodeTop = addByte((byte) TokenStream.SCOPE, iCodeTop);
\r
959 iCodeTop = addByte((byte) TokenStream.STRING, iCodeTop);
\r
960 iCodeTop = addString(name, iCodeTop);
\r
961 itsStackDepth += 2;
\r
962 if (itsStackDepth > itsData.itsMaxStack)
\r
963 itsData.itsMaxStack = itsStackDepth;
\r
964 iCodeTop = addByte((byte) TokenStream.GETPROP, iCodeTop);
\r
968 int index = itsVariableTable.getOrdinal(name);
\r
969 iCodeTop = addByte((byte) TokenStream.GETVAR, iCodeTop);
\r
970 iCodeTop = addByte((byte)index, iCodeTop);
\r
972 if (itsStackDepth > itsData.itsMaxStack)
\r
973 itsData.itsMaxStack = itsStackDepth;
\r
978 case TokenStream.SETVAR : {
\r
979 if (itsData.itsNeedsActivation) {
\r
980 child.setType(TokenStream.BINDNAME);
\r
981 node.setType(TokenStream.SETNAME);
\r
982 iCodeTop = generateICode(node, iCodeTop);
\r
985 String name = child.getString();
\r
986 child = child.getNextSibling();
\r
987 iCodeTop = generateICode(child, iCodeTop);
\r
988 int index = itsVariableTable.getOrdinal(name);
\r
989 iCodeTop = addByte((byte) TokenStream.SETVAR, iCodeTop);
\r
990 iCodeTop = addByte((byte)index, iCodeTop);
\r
995 case TokenStream.PRIMARY:
\r
996 iCodeTop = addByte((byte) node.getInt(), iCodeTop);
\r
998 if (itsStackDepth > itsData.itsMaxStack)
\r
999 itsData.itsMaxStack = itsStackDepth;
\r
1002 case TokenStream.ENUMINIT :
\r
1003 iCodeTop = generateICode(child, iCodeTop);
\r
1004 iCodeTop = addByte((byte) TokenStream.ENUMINIT, iCodeTop);
\r
1005 iCodeTop = addLocalRef(node, iCodeTop);
\r
1009 case TokenStream.ENUMNEXT : {
\r
1010 iCodeTop = addByte((byte) TokenStream.ENUMNEXT, iCodeTop);
\r
1011 Node init = (Node)node.getProp(Node.ENUM_PROP);
\r
1012 iCodeTop = addLocalRef(init, iCodeTop);
\r
1014 if (itsStackDepth > itsData.itsMaxStack)
\r
1015 itsData.itsMaxStack = itsStackDepth;
\r
1019 case TokenStream.ENUMDONE :
\r
1020 // could release the local here??
\r
1023 case TokenStream.OBJECT : {
\r
1024 Node regexp = (Node) node.getProp(Node.REGEXP_PROP);
\r
1025 int index = ((Integer)(regexp.getProp(
\r
1026 Node.REGEXP_PROP))).intValue();
\r
1027 iCodeTop = addByte((byte) TokenStream.OBJECT, iCodeTop);
\r
1028 iCodeTop = addByte((byte)(index >> 8), iCodeTop);
\r
1029 iCodeTop = addByte((byte)(index & 0xff), iCodeTop);
\r
1031 if (itsStackDepth > itsData.itsMaxStack)
\r
1032 itsData.itsMaxStack = itsStackDepth;
\r
1043 private int addLocalRef(Node node, int iCodeTop)
\r
1046 Integer localProp = (Integer)node.getProp(Node.LOCAL_PROP);
\r
1047 if (localProp == null) {
\r
1048 theLocalSlot = itsData.itsMaxLocals++;
\r
1049 node.putProp(Node.LOCAL_PROP, new Integer(theLocalSlot));
\r
1052 theLocalSlot = localProp.intValue();
\r
1053 iCodeTop = addByte((byte)theLocalSlot, iCodeTop);
\r
1054 if (theLocalSlot >= itsData.itsMaxLocals)
\r
1055 itsData.itsMaxLocals = theLocalSlot + 1;
\r
1059 private int addGoto(Node node, int gotoOp, int iCodeTop)
\r
1062 if (node.getType() == TokenStream.RETURN || node.getType() == TokenStream.ASSERT) {
\r
1063 if (itsEpilogLabel == -1)
\r
1064 itsEpilogLabel = acquireLabel();
\r
1065 targetLabel = itsEpilogLabel;
\r
1068 Node target = (Node)(node.getProp(Node.TARGET_PROP));
\r
1069 Object lblObect = target.getProp(Node.LABEL_PROP);
\r
1070 if (lblObect == null) {
\r
1071 targetLabel = acquireLabel();
\r
1072 target.putProp(Node.LABEL_PROP, new Integer(targetLabel));
\r
1075 targetLabel = ((Integer)lblObect).intValue();
\r
1077 iCodeTop = addGoto(targetLabel, (byte) gotoOp, iCodeTop);
\r
1081 private int addGoto(int targetLabel, int gotoOp, int iCodeTop)
\r
1083 int gotoPC = iCodeTop;
\r
1084 iCodeTop = addByte((byte) gotoOp, iCodeTop);
\r
1085 int theLabel = targetLabel & 0x7FFFFFFF;
\r
1086 int targetPC = itsLabelTable[theLabel].getPC();
\r
1087 if (targetPC != -1) {
\r
1088 short offset = (short)(targetPC - gotoPC);
\r
1089 iCodeTop = addByte((byte)(offset >> 8), iCodeTop);
\r
1090 iCodeTop = addByte((byte)offset, iCodeTop);
\r
1093 itsLabelTable[theLabel].addFixup(gotoPC + 1);
\r
1094 iCodeTop = addByte((byte)0, iCodeTop);
\r
1095 iCodeTop = addByte((byte)0, iCodeTop);
\r
1100 private final int addByte(byte b, int iCodeTop) {
\r
1101 if (itsData.itsICode.length == iCodeTop) {
\r
1102 byte[] ba = new byte[iCodeTop * 2];
\r
1103 System.arraycopy(itsData.itsICode, 0, ba, 0, iCodeTop);
\r
1104 itsData.itsICode = ba;
\r
1106 itsData.itsICode[iCodeTop++] = b;
\r
1110 private final int addString(String str, int iCodeTop)
\r
1112 int index = itsData.itsStringTableIndex;
\r
1113 if (itsData.itsStringTable.length == index) {
\r
1114 String[] sa = new String[index * 2];
\r
1115 System.arraycopy(itsData.itsStringTable, 0, sa, 0, index);
\r
1116 itsData.itsStringTable = sa;
\r
1118 itsData.itsStringTable[index] = str;
\r
1119 itsData.itsStringTableIndex = index + 1;
\r
1121 iCodeTop = addByte((byte)(index >> 8), iCodeTop);
\r
1122 iCodeTop = addByte((byte)(index & 0xFF), iCodeTop);
\r
1126 private final int addNumber(double num, int iCodeTop)
\r
1128 int index = itsData.itsNumberTableIndex;
\r
1129 if (itsData.itsNumberTable.length == index) {
\r
1130 double[] na = new double[index * 2];
\r
1131 System.arraycopy(itsData.itsNumberTable, 0, na, 0, index);
\r
1132 itsData.itsNumberTable = na;
\r
1134 itsData.itsNumberTable[index] = num;
\r
1135 itsData.itsNumberTableIndex = index + 1;
\r
1137 iCodeTop = addByte((byte)(index >> 8), iCodeTop);
\r
1138 iCodeTop = addByte((byte)(index & 0xFF), iCodeTop);
\r
1142 private static String getString(String[] theStringTable, byte[] iCode,
\r
1145 int index = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);
\r
1146 return theStringTable[index];
\r
1149 private static double getNumber(double[] theNumberTable, byte[] iCode,
\r
1152 int index = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);
\r
1153 return theNumberTable[index];
\r
1156 private static int getTarget(byte[] iCode, int pc)
\r
1158 int displacement = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);
\r
1159 return pc - 1 + displacement;
\r
1162 static PrintWriter out;
\r
1166 out = new PrintWriter(new FileOutputStream("icode.txt"));
\r
1169 catch (IOException x) {
\r
1174 private static void dumpICode(InterpreterData theData) {
\r
1177 int iCodeLength = theData.itsICodeTop;
\r
1178 byte iCode[] = theData.itsICode;
\r
1180 out = new PrintWriter(new FileOutputStream("icode.txt", true));
\r
1181 out.println("ICode dump, for " + theData.itsName + ", length = " + iCodeLength);
\r
1182 out.println("MaxStack = " + theData.itsMaxStack);
\r
1184 for (int pc = 0; pc < iCodeLength; ) {
\r
1185 out.print("[" + pc + "] ");
\r
1186 switch ((int)(iCode[pc] & 0xff)) {
\r
1187 case TokenStream.SCOPE :
\r
1188 case TokenStream.GETPROTO :
\r
1189 case TokenStream.GETPARENT :
\r
1190 case TokenStream.GETSCOPEPARENT :
\r
1191 case TokenStream.SETPROTO :
\r
1192 case TokenStream.SETPARENT :
\r
1193 case TokenStream.DELPROP :
\r
1194 case TokenStream.TYPEOF :
\r
1195 case TokenStream.NEWSCOPE :
\r
1196 case TokenStream.ENTERWITH :
\r
1197 case TokenStream.LEAVEWITH :
\r
1198 case TokenStream.ENDTRY :
\r
1199 case TokenStream.THROW :
\r
1200 case TokenStream.JTHROW :
\r
1201 case TokenStream.GETTHIS :
\r
1202 case TokenStream.SETELEM :
\r
1203 case TokenStream.GETELEM :
\r
1204 case TokenStream.SETPROP :
\r
1205 case TokenStream.GETPROP :
\r
1206 case TokenStream.PROPINC :
\r
1207 case TokenStream.PROPDEC :
\r
1208 case TokenStream.ELEMINC :
\r
1209 case TokenStream.ELEMDEC :
\r
1210 case TokenStream.BITNOT :
\r
1211 case TokenStream.BITAND :
\r
1212 case TokenStream.BITOR :
\r
1213 case TokenStream.BITXOR :
\r
1214 case TokenStream.LSH :
\r
1215 case TokenStream.RSH :
\r
1216 case TokenStream.URSH :
\r
1217 case TokenStream.NEG :
\r
1218 case TokenStream.POS :
\r
1219 case TokenStream.SUB :
\r
1220 case TokenStream.MUL :
\r
1221 case TokenStream.DIV :
\r
1222 case TokenStream.MOD :
\r
1223 case TokenStream.ADD :
\r
1224 case TokenStream.POPV :
\r
1225 case TokenStream.POP :
\r
1226 case TokenStream.DUP :
\r
1227 case TokenStream.LT :
\r
1228 case TokenStream.GT :
\r
1229 case TokenStream.LE :
\r
1230 case TokenStream.GE :
\r
1231 case TokenStream.IN :
\r
1232 case TokenStream.INSTANCEOF :
\r
1233 case TokenStream.EQ :
\r
1234 case TokenStream.NE :
\r
1235 case TokenStream.SHEQ :
\r
1236 case TokenStream.SHNE :
\r
1237 case TokenStream.ZERO :
\r
1238 case TokenStream.ONE :
\r
1239 case TokenStream.NULL :
\r
1240 case TokenStream.THIS :
\r
1241 case TokenStream.THISFN :
\r
1242 case TokenStream.FALSE :
\r
1243 case TokenStream.TRUE :
\r
1244 case TokenStream.UNDEFINED :
\r
1245 case TokenStream.SOURCEFILE :
\r
1246 out.println(TokenStream.tokenToName(iCode[pc] & 0xff));
\r
1248 case TokenStream.GOSUB :
\r
1249 case TokenStream.RETURN :
\r
1250 case TokenStream.GOTO :
\r
1251 case TokenStream.IFEQ :
\r
1252 case TokenStream.IFNE : {
\r
1253 int newPC = getTarget(iCode, pc + 1);
\r
1255 TokenStream.tokenToName(iCode[pc] & 0xff) +
\r
1260 case TokenStream.TRY : {
\r
1261 int newPC1 = getTarget(iCode, pc + 1);
\r
1262 int newPC2 = getTarget(iCode, pc + 3);
\r
1264 TokenStream.tokenToName(iCode[pc] & 0xff) +
\r
1270 case TokenStream.RETSUB :
\r
1271 case TokenStream.ENUMINIT :
\r
1272 case TokenStream.ENUMNEXT :
\r
1273 case TokenStream.VARINC :
\r
1274 case TokenStream.VARDEC :
\r
1275 case TokenStream.GETVAR :
\r
1276 case TokenStream.SETVAR :
\r
1277 case TokenStream.NEWTEMP :
\r
1278 case TokenStream.USETEMP : {
\r
1279 int slot = (iCode[pc + 1] & 0xFF);
\r
1281 TokenStream.tokenToName(iCode[pc] & 0xff) +
\r
1286 case TokenStream.CALLSPECIAL : {
\r
1287 int line = (iCode[pc + 1] << 8)
\r
1288 | (iCode[pc + 2] & 0xFF);
\r
1289 String name = getString(theData.itsStringTable,
\r
1291 int count = (iCode[pc + 5] << 8) | (iCode[pc + 6] & 0xFF);
\r
1293 TokenStream.tokenToName(iCode[pc] & 0xff) +
\r
1294 " " + count + " " + line + " " + name);
\r
1298 case TokenStream.OBJECT :
\r
1299 case TokenStream.CLOSURE :
\r
1300 case TokenStream.NEW :
\r
1301 case TokenStream.CALL : {
\r
1302 int count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);
\r
1304 TokenStream.tokenToName(iCode[pc] & 0xff) +
\r
1305 " " + count + " \"" +
\r
1306 getString(theData.itsStringTable, iCode,
\r
1311 case TokenStream.NUMBER :
\r
1313 TokenStream.tokenToName(iCode[pc] & 0xff) +
\r
1314 " " + getNumber(theData.itsNumberTable,
\r
1318 case TokenStream.TYPEOFNAME :
\r
1319 case TokenStream.GETBASE :
\r
1320 case TokenStream.BINDNAME :
\r
1321 case TokenStream.SETNAME :
\r
1322 case TokenStream.NAME :
\r
1323 case TokenStream.NAMEINC :
\r
1324 case TokenStream.NAMEDEC :
\r
1325 case TokenStream.STRING :
\r
1327 TokenStream.tokenToName(iCode[pc] & 0xff) +
\r
1329 getString(theData.itsStringTable, iCode, pc + 1) +
\r
1333 case TokenStream.LINE : {
\r
1334 int line = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
\r
1336 TokenStream.tokenToName(iCode[pc] & 0xff) + " : " + line);
\r
1342 throw new RuntimeException("Unknown icode : "
\r
1343 + (iCode[pc] & 0xff) + " @ pc : " + pc);
\r
1349 catch (IOException x) {}
\r
1353 private static void createFunctionObject(InterpretedFunction fn,
\r
1356 fn.setPrototype(ScriptableObject.getClassPrototype(scope, "Function"));
\r
1357 fn.setParentScope(scope);
\r
1358 InterpreterData id = fn.itsData;
\r
1359 if (id.itsName.length() == 0)
\r
1361 if ((id.itsFunctionType == FunctionNode.FUNCTION_STATEMENT &&
\r
1362 fn.itsClosure == null) ||
\r
1363 (id.itsFunctionType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT &&
\r
1364 fn.itsClosure != null))
\r
1366 ScriptRuntime.setProp(scope, fn.itsData.itsName, fn, scope);
\r
1370 public static Object interpret(Context cx, Scriptable scope,
\r
1371 Scriptable thisObj, Object[] args,
\r
1372 NativeFunction fnOrScript,
\r
1373 InterpreterData theData)
\r
1374 throws JavaScriptException
\r
1379 final int maxStack = theData.itsMaxStack;
\r
1380 final int maxVars = (fnOrScript.argNames == null)
\r
1381 ? 0 : fnOrScript.argNames.length;
\r
1382 final int maxLocals = theData.itsMaxLocals;
\r
1383 final int maxTryDepth = theData.itsMaxTryDepth;
\r
1385 final int VAR_SHFT = maxStack;
\r
1386 final int LOCAL_SHFT = VAR_SHFT + maxVars;
\r
1387 final int TRY_SCOPE_SHFT = LOCAL_SHFT + maxLocals;
\r
1389 // stack[0 <= i < VAR_SHFT]: stack data
\r
1390 // stack[VAR_SHFT <= i < LOCAL_SHFT]: variables
\r
1391 // stack[LOCAL_SHFT <= i < TRY_SCOPE_SHFT]: used for newtemp/usetemp
\r
1392 // stack[TRY_SCOPE_SHFT <= i]: try scopes
\r
1393 // when 0 <= i < LOCAL_SHFT and stack[x] == DBL_MRK,
\r
1394 // sDbl[i] gives the number value
\r
1396 final Object DBL_MRK = Interpreter.DBL_MRK;
\r
1398 Object[] stack = new Object[TRY_SCOPE_SHFT + maxTryDepth];
\r
1399 double[] sDbl = new double[TRY_SCOPE_SHFT];
\r
1400 int stackTop = -1;
\r
1401 byte[] iCode = theData.itsICode;
\r
1403 int iCodeLength = theData.itsICodeTop;
\r
1405 final Scriptable undefined = Undefined.instance;
\r
1406 if (maxVars != 0) {
\r
1407 int definedArgs = fnOrScript.argCount;
\r
1408 if (definedArgs != 0) {
\r
1409 if (definedArgs > args.length) { definedArgs = args.length; }
\r
1410 for (i = 0; i != definedArgs; ++i) {
\r
1411 stack[VAR_SHFT + i] = args[i];
\r
1414 for (i = definedArgs; i != maxVars; ++i) {
\r
1415 stack[VAR_SHFT + i] = undefined;
\r
1419 if (theData.itsNestedFunctions != null) {
\r
1420 for (i = 0; i < theData.itsNestedFunctions.length; i++)
\r
1421 createFunctionObject(theData.itsNestedFunctions[i], scope);
\r
1432 String name = null;
\r
1442 int[] catchStack = null;
\r
1443 int tryStackTop = 0;
\r
1444 InterpreterFrame frame = null;
\r
1446 if (cx.debugger != null) {
\r
1447 frame = new InterpreterFrame(scope, theData, fnOrScript);
\r
1448 cx.pushFrame(frame);
\r
1451 if (maxTryDepth != 0) {
\r
1452 // catchStack[2 * i]: starting pc of catch block
\r
1453 // catchStack[2 * i + 1]: starting pc of finally block
\r
1454 catchStack = new int[maxTryDepth * 2];
\r
1457 /* Save the security domain. Must restore upon normal exit.
\r
1458 * If we exit the interpreter loop by throwing an exception,
\r
1459 * set cx.interpreterSecurityDomain to null, and require the
\r
1460 * catching function to restore it.
\r
1462 Object savedSecurityDomain = cx.interpreterSecurityDomain;
\r
1463 cx.interpreterSecurityDomain = theData.securityDomain;
\r
1464 Object result = undefined;
\r
1466 int pcPrevBranch = pc;
\r
1467 final int instructionThreshold = cx.instructionThreshold;
\r
1468 // During function call this will be set to -1 so catch can properly
\r
1470 int instructionCount = cx.instructionCount;
\r
1471 // arbitrary number to add to instructionCount when calling
\r
1472 // other functions
\r
1473 final int INVOCATION_COST = 100;
\r
1475 while (pc < iCodeLength) {
\r
1477 switch (iCode[pc] & 0xff) {
\r
1478 case TokenStream.ENDTRY :
\r
1481 case TokenStream.TRY :
\r
1482 i = getTarget(iCode, pc + 1);
\r
1483 if (i == pc) i = 0;
\r
1484 catchStack[tryStackTop * 2] = i;
\r
1485 i = getTarget(iCode, pc + 3);
\r
1486 if (i == (pc + 2)) i = 0;
\r
1487 catchStack[tryStackTop * 2 + 1] = i;
\r
1488 stack[TRY_SCOPE_SHFT + tryStackTop] = scope;
\r
1492 case TokenStream.GE :
\r
1494 rhs = stack[stackTop + 1];
\r
1495 lhs = stack[stackTop];
\r
1496 if (rhs == DBL_MRK || lhs == DBL_MRK) {
\r
1497 rDbl = stack_double(stack, sDbl, stackTop + 1);
\r
1498 lDbl = stack_double(stack, sDbl, stackTop);
\r
1499 valBln = (rDbl == rDbl && lDbl == lDbl
\r
1503 valBln = (1 == ScriptRuntime.cmp_LE(rhs, lhs));
\r
1505 stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
\r
1507 case TokenStream.LE :
\r
1509 rhs = stack[stackTop + 1];
\r
1510 lhs = stack[stackTop];
\r
1511 if (rhs == DBL_MRK || lhs == DBL_MRK) {
\r
1512 rDbl = stack_double(stack, sDbl, stackTop + 1);
\r
1513 lDbl = stack_double(stack, sDbl, stackTop);
\r
1514 valBln = (rDbl == rDbl && lDbl == lDbl
\r
1518 valBln = (1 == ScriptRuntime.cmp_LE(lhs, rhs));
\r
1520 stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
\r
1522 case TokenStream.GT :
\r
1524 rhs = stack[stackTop + 1];
\r
1525 lhs = stack[stackTop];
\r
1526 if (rhs == DBL_MRK || lhs == DBL_MRK) {
\r
1527 rDbl = stack_double(stack, sDbl, stackTop + 1);
\r
1528 lDbl = stack_double(stack, sDbl, stackTop);
\r
1529 valBln = (rDbl == rDbl && lDbl == lDbl
\r
1533 valBln = (1 == ScriptRuntime.cmp_LT(rhs, lhs));
\r
1535 stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
\r
1537 case TokenStream.LT :
\r
1539 rhs = stack[stackTop + 1];
\r
1540 lhs = stack[stackTop];
\r
1541 if (rhs == DBL_MRK || lhs == DBL_MRK) {
\r
1542 rDbl = stack_double(stack, sDbl, stackTop + 1);
\r
1543 lDbl = stack_double(stack, sDbl, stackTop);
\r
1544 valBln = (rDbl == rDbl && lDbl == lDbl
\r
1548 valBln = (1 == ScriptRuntime.cmp_LT(lhs, rhs));
\r
1550 stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
\r
1552 case TokenStream.IN :
\r
1553 rhs = stack[stackTop];
\r
1554 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
1556 lhs = stack[stackTop];
\r
1557 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1558 valBln = ScriptRuntime.in(lhs, rhs, scope);
\r
1559 stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
\r
1561 case TokenStream.INSTANCEOF :
\r
1562 rhs = stack[stackTop];
\r
1563 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
1565 lhs = stack[stackTop];
\r
1566 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1567 valBln = ScriptRuntime.instanceOf(scope, lhs, rhs);
\r
1568 stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
\r
1570 case TokenStream.EQ :
\r
1572 valBln = do_eq(stack, sDbl, stackTop);
\r
1573 stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
\r
1575 case TokenStream.NE :
\r
1577 valBln = !do_eq(stack, sDbl, stackTop);
\r
1578 stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
\r
1580 case TokenStream.SHEQ :
\r
1582 valBln = do_sheq(stack, sDbl, stackTop);
\r
1583 stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
\r
1585 case TokenStream.SHNE :
\r
1587 valBln = !do_sheq(stack, sDbl, stackTop);
\r
1588 stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;
\r
1590 case TokenStream.IFNE :
\r
1591 val = stack[stackTop];
\r
1592 if (val != DBL_MRK) {
\r
1593 valBln = !ScriptRuntime.toBoolean(val);
\r
1596 valDbl = sDbl[stackTop];
\r
1597 valBln = !(valDbl == valDbl && valDbl != 0.0);
\r
1601 if (instructionThreshold != 0) {
\r
1602 instructionCount += pc + 3 - pcPrevBranch;
\r
1603 if (instructionCount > instructionThreshold) {
\r
1604 cx.observeInstructionCount
\r
1605 (instructionCount);
\r
1606 instructionCount = 0;
\r
1609 pcPrevBranch = pc = getTarget(iCode, pc + 1);
\r
1614 case TokenStream.IFEQ :
\r
1615 val = stack[stackTop];
\r
1616 if (val != DBL_MRK) {
\r
1617 valBln = ScriptRuntime.toBoolean(val);
\r
1620 valDbl = sDbl[stackTop];
\r
1621 valBln = (valDbl == valDbl && valDbl != 0.0);
\r
1625 if (instructionThreshold != 0) {
\r
1626 instructionCount += pc + 3 - pcPrevBranch;
\r
1627 if (instructionCount > instructionThreshold) {
\r
1628 cx.observeInstructionCount
\r
1629 (instructionCount);
\r
1630 instructionCount = 0;
\r
1633 pcPrevBranch = pc = getTarget(iCode, pc + 1);
\r
1638 case TokenStream.GOTO :
\r
1639 if (instructionThreshold != 0) {
\r
1640 instructionCount += pc + 3 - pcPrevBranch;
\r
1641 if (instructionCount > instructionThreshold) {
\r
1642 cx.observeInstructionCount(instructionCount);
\r
1643 instructionCount = 0;
\r
1646 pcPrevBranch = pc = getTarget(iCode, pc + 1);
\r
1648 case TokenStream.GOSUB :
\r
1649 sDbl[++stackTop] = pc + 3;
\r
1650 if (instructionThreshold != 0) {
\r
1651 instructionCount += pc + 3 - pcPrevBranch;
\r
1652 if (instructionCount > instructionThreshold) {
\r
1653 cx.observeInstructionCount(instructionCount);
\r
1654 instructionCount = 0;
\r
1657 pcPrevBranch = pc = getTarget(iCode, pc + 1); continue;
\r
1658 case TokenStream.RETSUB :
\r
1659 slot = (iCode[pc + 1] & 0xFF);
\r
1660 if (instructionThreshold != 0) {
\r
1661 instructionCount += pc + 2 - pcPrevBranch;
\r
1662 if (instructionCount > instructionThreshold) {
\r
1663 cx.observeInstructionCount(instructionCount);
\r
1664 instructionCount = 0;
\r
1667 pcPrevBranch = pc = (int)sDbl[LOCAL_SHFT + slot];
\r
1669 case TokenStream.POP :
\r
1672 case TokenStream.DUP :
\r
1673 stack[stackTop + 1] = stack[stackTop];
\r
1674 sDbl[stackTop + 1] = sDbl[stackTop];
\r
1677 case TokenStream.POPV :
\r
1678 result = stack[stackTop];
\r
1679 if (result == DBL_MRK)
\r
1680 result = doubleWrap(sDbl[stackTop]);
\r
1683 case TokenStream.RETURN :
\r
1684 result = stack[stackTop];
\r
1685 if (result == DBL_MRK)
\r
1686 result = doubleWrap(sDbl[stackTop]);
\r
1688 pc = getTarget(iCode, pc + 1);
\r
1690 case TokenStream.ASSERT :
\r
1691 val = stack[stackTop];
\r
1692 if (val != DBL_MRK) {
\r
1693 valBln = ScriptRuntime.toBoolean(val);
\r
1695 valDbl = sDbl[stackTop];
\r
1696 valBln = (valDbl == valDbl && valDbl != 0.0);
\r
1700 throw new Error("assertion failed");
\r
1701 //System.exit(-1);
\r
1705 case TokenStream.BITNOT :
\r
1706 rIntValue = stack_int32(stack, sDbl, stackTop);
\r
1707 stack[stackTop] = DBL_MRK;
\r
1708 sDbl[stackTop] = ~rIntValue;
\r
1710 case TokenStream.BITAND :
\r
1711 rIntValue = stack_int32(stack, sDbl, stackTop);
\r
1713 lIntValue = stack_int32(stack, sDbl, stackTop);
\r
1714 stack[stackTop] = DBL_MRK;
\r
1715 sDbl[stackTop] = lIntValue & rIntValue;
\r
1717 case TokenStream.BITOR :
\r
1718 rIntValue = stack_int32(stack, sDbl, stackTop);
\r
1720 lIntValue = stack_int32(stack, sDbl, stackTop);
\r
1721 stack[stackTop] = DBL_MRK;
\r
1722 sDbl[stackTop] = lIntValue | rIntValue;
\r
1724 case TokenStream.BITXOR :
\r
1725 rIntValue = stack_int32(stack, sDbl, stackTop);
\r
1727 lIntValue = stack_int32(stack, sDbl, stackTop);
\r
1728 stack[stackTop] = DBL_MRK;
\r
1729 sDbl[stackTop] = lIntValue ^ rIntValue;
\r
1731 case TokenStream.LSH :
\r
1732 rIntValue = stack_int32(stack, sDbl, stackTop);
\r
1734 lIntValue = stack_int32(stack, sDbl, stackTop);
\r
1735 stack[stackTop] = DBL_MRK;
\r
1736 sDbl[stackTop] = lIntValue << rIntValue;
\r
1738 case TokenStream.RSH :
\r
1739 rIntValue = stack_int32(stack, sDbl, stackTop);
\r
1741 lIntValue = stack_int32(stack, sDbl, stackTop);
\r
1742 stack[stackTop] = DBL_MRK;
\r
1743 sDbl[stackTop] = lIntValue >> rIntValue;
\r
1745 case TokenStream.URSH :
\r
1746 rIntValue = stack_int32(stack, sDbl, stackTop) & 0x1F;
\r
1748 lLongValue = stack_uint32(stack, sDbl, stackTop);
\r
1749 stack[stackTop] = DBL_MRK;
\r
1750 sDbl[stackTop] = lLongValue >>> rIntValue;
\r
1752 case TokenStream.ADD :
\r
1754 do_add(stack, sDbl, stackTop);
\r
1756 case TokenStream.SUB :
\r
1757 rDbl = stack_double(stack, sDbl, stackTop);
\r
1759 lDbl = stack_double(stack, sDbl, stackTop);
\r
1760 stack[stackTop] = DBL_MRK;
\r
1761 sDbl[stackTop] = lDbl - rDbl;
\r
1763 case TokenStream.NEG :
\r
1764 rDbl = stack_double(stack, sDbl, stackTop);
\r
1765 stack[stackTop] = DBL_MRK;
\r
1766 sDbl[stackTop] = -rDbl;
\r
1768 case TokenStream.POS :
\r
1769 rDbl = stack_double(stack, sDbl, stackTop);
\r
1770 stack[stackTop] = DBL_MRK;
\r
1771 sDbl[stackTop] = rDbl;
\r
1773 case TokenStream.MUL :
\r
1774 rDbl = stack_double(stack, sDbl, stackTop);
\r
1776 lDbl = stack_double(stack, sDbl, stackTop);
\r
1777 stack[stackTop] = DBL_MRK;
\r
1778 sDbl[stackTop] = lDbl * rDbl;
\r
1780 case TokenStream.DIV :
\r
1781 rDbl = stack_double(stack, sDbl, stackTop);
\r
1783 lDbl = stack_double(stack, sDbl, stackTop);
\r
1784 stack[stackTop] = DBL_MRK;
\r
1785 // Detect the divide by zero or let Java do it ?
\r
1786 sDbl[stackTop] = lDbl / rDbl;
\r
1788 case TokenStream.MOD :
\r
1789 rDbl = stack_double(stack, sDbl, stackTop);
\r
1791 lDbl = stack_double(stack, sDbl, stackTop);
\r
1792 stack[stackTop] = DBL_MRK;
\r
1793 sDbl[stackTop] = lDbl % rDbl;
\r
1795 case TokenStream.BINDNAME :
\r
1796 stack[++stackTop] =
\r
1797 ScriptRuntime.bind(scope,
\r
1798 getString(theData.itsStringTable,
\r
1802 case TokenStream.GETBASE :
\r
1803 stack[++stackTop] =
\r
1804 ScriptRuntime.getBase(scope,
\r
1805 getString(theData.itsStringTable,
\r
1809 case TokenStream.SETNAME :
\r
1810 rhs = stack[stackTop];
\r
1811 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
1813 lhs = stack[stackTop];
\r
1814 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1815 // what about class cast exception here ?
\r
1816 stack[stackTop] = ScriptRuntime.setName
\r
1817 ((Scriptable)lhs, rhs, scope,
\r
1818 getString(theData.itsStringTable, iCode, pc + 1));
\r
1821 case TokenStream.DELPROP :
\r
1822 rhs = stack[stackTop];
\r
1823 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
1825 lhs = stack[stackTop];
\r
1826 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1827 stack[stackTop] = ScriptRuntime.delete(lhs, rhs);
\r
1829 case TokenStream.GETPROP :
\r
1830 name = (String)stack[stackTop];
\r
1832 lhs = stack[stackTop];
\r
1833 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1835 = ScriptRuntime.getProp(lhs, name, scope);
\r
1837 case TokenStream.SETPROP :
\r
1838 rhs = stack[stackTop];
\r
1839 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
1841 name = (String)stack[stackTop];
\r
1843 lhs = stack[stackTop];
\r
1844 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1846 = ScriptRuntime.setProp(lhs, name, rhs, scope);
\r
1848 case TokenStream.GETELEM :
\r
1849 id = stack[stackTop];
\r
1850 if (id == DBL_MRK) id = doubleWrap(sDbl[stackTop]);
\r
1852 lhs = stack[stackTop];
\r
1853 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1855 = ScriptRuntime.getElem(lhs, id, scope);
\r
1857 case TokenStream.SETELEM :
\r
1858 rhs = stack[stackTop];
\r
1859 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
1861 id = stack[stackTop];
\r
1862 if (id == DBL_MRK) id = doubleWrap(sDbl[stackTop]);
\r
1864 lhs = stack[stackTop];
\r
1865 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1867 = ScriptRuntime.setElem(lhs, id, rhs, scope);
\r
1869 case TokenStream.PROPINC :
\r
1870 name = (String)stack[stackTop];
\r
1872 lhs = stack[stackTop];
\r
1873 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1875 = ScriptRuntime.postIncrement(lhs, name, scope);
\r
1877 case TokenStream.PROPDEC :
\r
1878 name = (String)stack[stackTop];
\r
1880 lhs = stack[stackTop];
\r
1881 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1883 = ScriptRuntime.postDecrement(lhs, name, scope);
\r
1885 case TokenStream.ELEMINC :
\r
1886 rhs = stack[stackTop];
\r
1887 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
1889 lhs = stack[stackTop];
\r
1890 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1892 = ScriptRuntime.postIncrementElem(lhs, rhs, scope);
\r
1894 case TokenStream.ELEMDEC :
\r
1895 rhs = stack[stackTop];
\r
1896 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
1898 lhs = stack[stackTop];
\r
1899 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1901 = ScriptRuntime.postDecrementElem(lhs, rhs, scope);
\r
1903 case TokenStream.GETTHIS :
\r
1904 lhs = stack[stackTop];
\r
1905 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1907 = ScriptRuntime.getThis((Scriptable)lhs);
\r
1909 case TokenStream.NEWTEMP :
\r
1910 slot = (iCode[++pc] & 0xFF);
\r
1911 stack[LOCAL_SHFT + slot] = stack[stackTop];
\r
1912 sDbl[LOCAL_SHFT + slot] = sDbl[stackTop];
\r
1914 case TokenStream.USETEMP :
\r
1915 slot = (iCode[++pc] & 0xFF);
\r
1917 stack[stackTop] = stack[LOCAL_SHFT + slot];
\r
1918 sDbl[stackTop] = sDbl[LOCAL_SHFT + slot];
\r
1920 case TokenStream.CALLSPECIAL :
\r
1921 if (instructionThreshold != 0) {
\r
1922 instructionCount += INVOCATION_COST;
\r
1923 cx.instructionCount = instructionCount;
\r
1924 instructionCount = -1;
\r
1926 int lineNum = (iCode[pc + 1] << 8)
\r
1927 | (iCode[pc + 2] & 0xFF);
\r
1928 name = getString(theData.itsStringTable, iCode, pc + 3);
\r
1929 count = (iCode[pc + 5] << 8) | (iCode[pc + 6] & 0xFF);
\r
1930 outArgs = new Object[count];
\r
1931 for (i = count - 1; i >= 0; i--) {
\r
1932 val = stack[stackTop];
\r
1933 if (val == DBL_MRK)
\r
1934 val = doubleWrap(sDbl[stackTop]);
\r
1938 rhs = stack[stackTop];
\r
1939 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
1941 lhs = stack[stackTop];
\r
1942 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1943 stack[stackTop] = ScriptRuntime.callSpecial(
\r
1944 cx, lhs, rhs, outArgs,
\r
1945 thisObj, scope, name, lineNum);
\r
1947 instructionCount = cx.instructionCount;
\r
1949 case TokenStream.CALL :
\r
1950 if (instructionThreshold != 0) {
\r
1951 instructionCount += INVOCATION_COST;
\r
1952 cx.instructionCount = instructionCount;
\r
1953 instructionCount = -1;
\r
1955 cx.instructionCount = instructionCount;
\r
1956 count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);
\r
1957 outArgs = new Object[count];
\r
1958 for (i = count - 1; i >= 0; i--) {
\r
1959 val = stack[stackTop];
\r
1960 if (val == DBL_MRK)
\r
1961 val = doubleWrap(sDbl[stackTop]);
\r
1965 rhs = stack[stackTop];
\r
1966 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
1968 lhs = stack[stackTop];
\r
1969 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
1970 if (lhs == undefined) {
\r
1971 lhs = getString(theData.itsStringTable, iCode,
\r
1974 Scriptable calleeScope = scope;
\r
1975 if (theData.itsNeedsActivation) {
\r
1976 calleeScope = ScriptableObject.
\r
1977 getTopLevelScope(scope);
\r
1979 stack[stackTop] = ScriptRuntime.call(cx, lhs, rhs,
\r
1982 pc += 4; instructionCount = cx.instructionCount;
\r
1984 case TokenStream.NEW :
\r
1985 if (instructionThreshold != 0) {
\r
1986 instructionCount += INVOCATION_COST;
\r
1987 cx.instructionCount = instructionCount;
\r
1988 instructionCount = -1;
\r
1990 count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);
\r
1991 outArgs = new Object[count];
\r
1992 for (i = count - 1; i >= 0; i--) {
\r
1993 val = stack[stackTop];
\r
1994 if (val == DBL_MRK)
\r
1995 val = doubleWrap(sDbl[stackTop]);
\r
1999 lhs = stack[stackTop];
\r
2000 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
2001 if (lhs == undefined &&
\r
2002 (iCode[pc+1] << 8) + (iCode[pc+2] & 0xFF) != -1)
\r
2004 // special code for better error message for call
\r
2006 lhs = getString(theData.itsStringTable, iCode,
\r
2009 stack[stackTop] = ScriptRuntime.newObject(cx, lhs,
\r
2012 pc += 4; instructionCount = cx.instructionCount;
\r
2014 case TokenStream.TYPEOF :
\r
2015 lhs = stack[stackTop];
\r
2016 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
2017 stack[stackTop] = ScriptRuntime.typeof(lhs);
\r
2019 case TokenStream.TYPEOFNAME :
\r
2020 name = getString(theData.itsStringTable, iCode, pc + 1);
\r
2021 stack[++stackTop]
\r
2022 = ScriptRuntime.typeofName(scope, name);
\r
2025 case TokenStream.STRING :
\r
2026 stack[++stackTop] = getString(theData.itsStringTable,
\r
2030 case TokenStream.NUMBER :
\r
2032 stack[stackTop] = DBL_MRK;
\r
2033 sDbl[stackTop] = getNumber(theData.itsNumberTable,
\r
2037 case TokenStream.NAME :
\r
2038 stack[++stackTop] = ScriptRuntime.name(scope,
\r
2039 getString(theData.itsStringTable,
\r
2043 case TokenStream.NAMEINC :
\r
2044 stack[++stackTop] = ScriptRuntime.postIncrement(scope,
\r
2045 getString(theData.itsStringTable,
\r
2049 case TokenStream.NAMEDEC :
\r
2050 stack[++stackTop] = ScriptRuntime.postDecrement(scope,
\r
2051 getString(theData.itsStringTable,
\r
2055 case TokenStream.SETVAR :
\r
2056 slot = (iCode[++pc] & 0xFF);
\r
2057 stack[VAR_SHFT + slot] = stack[stackTop];
\r
2058 sDbl[VAR_SHFT + slot] = sDbl[stackTop];
\r
2060 case TokenStream.GETVAR :
\r
2061 slot = (iCode[++pc] & 0xFF);
\r
2063 stack[stackTop] = stack[VAR_SHFT + slot];
\r
2064 sDbl[stackTop] = sDbl[VAR_SHFT + slot];
\r
2066 case TokenStream.VARINC :
\r
2067 slot = (iCode[++pc] & 0xFF);
\r
2069 stack[stackTop] = stack[VAR_SHFT + slot];
\r
2070 sDbl[stackTop] = sDbl[VAR_SHFT + slot];
\r
2071 stack[VAR_SHFT + slot] = DBL_MRK;
\r
2072 sDbl[VAR_SHFT + slot]
\r
2073 = stack_double(stack, sDbl, stackTop) + 1.0;
\r
2075 case TokenStream.VARDEC :
\r
2076 slot = (iCode[++pc] & 0xFF);
\r
2078 stack[stackTop] = stack[VAR_SHFT + slot];
\r
2079 sDbl[stackTop] = sDbl[VAR_SHFT + slot];
\r
2080 stack[VAR_SHFT + slot] = DBL_MRK;
\r
2081 sDbl[VAR_SHFT + slot]
\r
2082 = stack_double(stack, sDbl, stackTop) - 1.0;
\r
2084 case TokenStream.ZERO :
\r
2086 stack[stackTop] = DBL_MRK;
\r
2087 sDbl[stackTop] = 0;
\r
2089 case TokenStream.ONE :
\r
2091 stack[stackTop] = DBL_MRK;
\r
2092 sDbl[stackTop] = 1;
\r
2094 case TokenStream.NULL :
\r
2095 stack[++stackTop] = null;
\r
2097 case TokenStream.THIS :
\r
2098 stack[++stackTop] = thisObj;
\r
2100 case TokenStream.THISFN :
\r
2101 stack[++stackTop] = fnOrScript;
\r
2103 case TokenStream.FALSE :
\r
2104 stack[++stackTop] = Boolean.FALSE;
\r
2106 case TokenStream.TRUE :
\r
2107 stack[++stackTop] = Boolean.TRUE;
\r
2109 case TokenStream.UNDEFINED :
\r
2110 stack[++stackTop] = Undefined.instance;
\r
2112 case TokenStream.THROW :
\r
2113 result = stack[stackTop];
\r
2114 if (result == DBL_MRK)
\r
2115 result = doubleWrap(sDbl[stackTop]);
\r
2117 throw new JavaScriptException(result);
\r
2118 case TokenStream.JTHROW :
\r
2119 result = stack[stackTop];
\r
2120 // No need to check for DBL_MRK: result is Exception
\r
2122 if (result instanceof JavaScriptException)
\r
2123 throw (JavaScriptException)result;
\r
2125 throw (RuntimeException)result;
\r
2126 case TokenStream.ENTERWITH :
\r
2127 lhs = stack[stackTop];
\r
2128 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
2130 scope = ScriptRuntime.enterWith(lhs, scope);
\r
2132 case TokenStream.LEAVEWITH :
\r
2133 scope = ScriptRuntime.leaveWith(scope);
\r
2135 case TokenStream.NEWSCOPE :
\r
2136 stack[++stackTop] = ScriptRuntime.newScope();
\r
2138 case TokenStream.ENUMINIT :
\r
2139 slot = (iCode[++pc] & 0xFF);
\r
2140 lhs = stack[stackTop];
\r
2141 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
2143 stack[LOCAL_SHFT + slot]
\r
2144 = ScriptRuntime.initEnum(lhs, scope);
\r
2146 case TokenStream.ENUMNEXT :
\r
2147 slot = (iCode[++pc] & 0xFF);
\r
2148 val = stack[LOCAL_SHFT + slot];
\r
2150 stack[stackTop] = ScriptRuntime.
\r
2151 nextEnum((Enumeration)val);
\r
2153 case TokenStream.GETPROTO :
\r
2154 lhs = stack[stackTop];
\r
2155 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
2156 stack[stackTop] = ScriptRuntime.getProto(lhs, scope);
\r
2158 case TokenStream.GETPARENT :
\r
2159 lhs = stack[stackTop];
\r
2160 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
2161 stack[stackTop] = ScriptRuntime.getParent(lhs);
\r
2163 case TokenStream.GETSCOPEPARENT :
\r
2164 lhs = stack[stackTop];
\r
2165 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
2166 stack[stackTop] = ScriptRuntime.getParent(lhs, scope);
\r
2168 case TokenStream.SETPROTO :
\r
2169 rhs = stack[stackTop];
\r
2170 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
2172 lhs = stack[stackTop];
\r
2173 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
2175 = ScriptRuntime.setProto(lhs, rhs, scope);
\r
2177 case TokenStream.SETPARENT :
\r
2178 rhs = stack[stackTop];
\r
2179 if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
\r
2181 lhs = stack[stackTop];
\r
2182 if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
\r
2184 = ScriptRuntime.setParent(lhs, rhs, scope);
\r
2186 case TokenStream.SCOPE :
\r
2187 stack[++stackTop] = scope;
\r
2189 case TokenStream.CLOSURE :
\r
2190 i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
\r
2191 stack[++stackTop]
\r
2192 = new InterpretedFunction(
\r
2193 theData.itsNestedFunctions[i],
\r
2195 createFunctionObject(
\r
2196 (InterpretedFunction)stack[stackTop], scope);
\r
2199 case TokenStream.OBJECT :
\r
2200 i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
\r
2201 stack[++stackTop] = theData.itsRegExpLiterals[i];
\r
2204 case TokenStream.SOURCEFILE :
\r
2205 cx.interpreterSourceFile = theData.itsSourceFile;
\r
2207 case TokenStream.LINE :
\r
2208 case TokenStream.BREAKPOINT :
\r
2209 i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
\r
2210 cx.interpreterLine = i;
\r
2211 if (frame != null)
\r
2212 frame.setLineNumber(i);
\r
2213 if ((iCode[pc] & 0xff) == TokenStream.BREAKPOINT ||
\r
2214 cx.inLineStepMode)
\r
2216 cx.getDebuggableEngine().
\r
2217 getDebugger().handleBreakpointHit(cx);
\r
2222 dumpICode(theData);
\r
2223 throw new RuntimeException("Unknown icode : "
\r
2224 + (iCode[pc] & 0xff) + " @ pc : " + pc);
\r
2228 catch (Throwable ex) {
\r
2229 cx.interpreterSecurityDomain = null;
\r
2231 if (instructionThreshold != 0) {
\r
2232 if (instructionCount < 0) {
\r
2233 // throw during function call
\r
2234 instructionCount = cx.instructionCount;
\r
2237 // throw during any other operation
\r
2238 instructionCount += pc - pcPrevBranch;
\r
2239 cx.instructionCount = instructionCount;
\r
2243 final int SCRIPT_THROW = 0, ECMA = 1, RUNTIME = 2, OTHER = 3;
\r
2246 Object errObj; // Object seen by catch
\r
2247 if (ex instanceof JavaScriptException) {
\r
2248 errObj = ScriptRuntime.
\r
2249 unwrapJavaScriptException((JavaScriptException)ex);
\r
2250 exType = SCRIPT_THROW;
\r
2252 else if (ex instanceof EcmaError) {
\r
2253 // an offical ECMA error object,
\r
2254 errObj = ((EcmaError)ex).getErrorObject();
\r
2257 else if (ex instanceof RuntimeException) {
\r
2262 errObj = ex; // Error instance
\r
2266 if (exType != OTHER && cx.debugger != null) {
\r
2267 cx.debugger.handleExceptionThrown(cx, errObj);
\r
2270 boolean rethrow = true;
\r
2271 if (exType != OTHER && tryStackTop > 0) {
\r
2273 if (exType == SCRIPT_THROW || exType == ECMA) {
\r
2274 // Check for catch only for
\r
2275 // JavaScriptException and EcmaError
\r
2276 pc = catchStack[tryStackTop * 2];
\r
2278 // Has catch block
\r
2283 pc = catchStack[tryStackTop * 2 + 1];
\r
2285 // has finally block
\r
2293 if (frame != null)
\r
2296 if (exType == SCRIPT_THROW)
\r
2297 throw (JavaScriptException)ex;
\r
2298 if (exType == ECMA || exType == RUNTIME)
\r
2299 throw (RuntimeException)ex;
\r
2303 // We caught an exception,
\r
2305 // Notify instruction observer if necessary
\r
2306 // and point pcPrevBranch to start of catch/finally block
\r
2307 if (instructionThreshold != 0) {
\r
2308 if (instructionCount > instructionThreshold) {
\r
2309 // Note: this can throw Error
\r
2310 cx.observeInstructionCount(instructionCount);
\r
2311 instructionCount = 0;
\r
2314 pcPrevBranch = pc;
\r
2316 // prepare stack and restore this function's security domain.
\r
2317 scope = (Scriptable)stack[TRY_SCOPE_SHFT + tryStackTop];
\r
2319 stack[0] = errObj;
\r
2320 cx.interpreterSecurityDomain = theData.securityDomain;
\r
2323 cx.interpreterSecurityDomain = savedSecurityDomain;
\r
2324 if (frame != null)
\r
2327 if (instructionThreshold != 0) {
\r
2328 if (instructionCount > instructionThreshold) {
\r
2329 cx.observeInstructionCount(instructionCount);
\r
2330 instructionCount = 0;
\r
2332 cx.instructionCount = instructionCount;
\r
2338 private static Object doubleWrap(double x) {
\r
2339 return new Double(x);
\r
2342 private static int stack_int32(Object[] stack, double[] stackDbl, int i) {
\r
2343 Object x = stack[i];
\r
2344 return (x != DBL_MRK)
\r
2345 ? ScriptRuntime.toInt32(x)
\r
2346 : ScriptRuntime.toInt32(stackDbl[i]);
\r
2349 private static long stack_uint32(Object[] stack, double[] stackDbl, int i) {
\r
2350 Object x = stack[i];
\r
2351 return (x != DBL_MRK)
\r
2352 ? ScriptRuntime.toUint32(x)
\r
2353 : ScriptRuntime.toUint32(stackDbl[i]);
\r
2356 private static double stack_double(Object[] stack, double[] stackDbl,
\r
2359 Object x = stack[i];
\r
2360 return (x != DBL_MRK) ? ScriptRuntime.toNumber(x) : stackDbl[i];
\r
2363 private static void do_add(Object[] stack, double[] stackDbl, int stackTop)
\r
2365 Object rhs = stack[stackTop + 1];
\r
2366 Object lhs = stack[stackTop];
\r
2367 if (rhs == DBL_MRK) {
\r
2368 double rDbl = stackDbl[stackTop + 1];
\r
2369 if (lhs == DBL_MRK) {
\r
2370 stackDbl[stackTop] += rDbl;
\r
2373 do_add(lhs, rDbl, stack, stackDbl, stackTop, true);
\r
2376 else if (lhs == DBL_MRK) {
\r
2377 do_add(rhs, stackDbl[stackTop], stack, stackDbl, stackTop, false);
\r
2380 if (lhs instanceof Scriptable)
\r
2381 lhs = ((Scriptable) lhs).getDefaultValue(null);
\r
2382 if (rhs instanceof Scriptable)
\r
2383 rhs = ((Scriptable) rhs).getDefaultValue(null);
\r
2384 if (lhs instanceof String || rhs instanceof String) {
\r
2385 stack[stackTop] = ScriptRuntime.toString(lhs)
\r
2386 + ScriptRuntime.toString(rhs);
\r
2389 double lDbl = (lhs instanceof Number)
\r
2390 ? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);
\r
2391 double rDbl = (rhs instanceof Number)
\r
2392 ? ((Number)rhs).doubleValue() : ScriptRuntime.toNumber(rhs);
\r
2393 stack[stackTop] = DBL_MRK;
\r
2394 stackDbl[stackTop] = lDbl + rDbl;
\r
2399 // x + y when x is Number, see
\r
2400 private static void do_add
\r
2401 (Object lhs, double rDbl,
\r
2402 Object[] stack, double[] stackDbl, int stackTop,
\r
2403 boolean left_right_order)
\r
2405 if (lhs instanceof Scriptable) {
\r
2406 if (lhs == Undefined.instance) { lhs = ScriptRuntime.NaNobj; }
\r
2407 lhs = ((Scriptable)lhs).getDefaultValue(null);
\r
2409 if (lhs instanceof String) {
\r
2410 if (left_right_order) {
\r
2411 stack[stackTop] = (String)lhs + ScriptRuntime.toString(rDbl);
\r
2414 stack[stackTop] = ScriptRuntime.toString(rDbl) + (String)lhs;
\r
2418 double lDbl = (lhs instanceof Number)
\r
2419 ? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);
\r
2420 stack[stackTop] = DBL_MRK;
\r
2421 stackDbl[stackTop] = lDbl + rDbl;
\r
2427 private static boolean do_eq(Object[] stack, double[] stackDbl,
\r
2431 Object rhs = stack[stackTop + 1];
\r
2432 Object lhs = stack[stackTop];
\r
2433 if (rhs == DBL_MRK) {
\r
2434 if (lhs == DBL_MRK) {
\r
2435 result = (stackDbl[stackTop] == stackDbl[stackTop + 1]);
\r
2438 result = do_eq(stackDbl[stackTop + 1], lhs);
\r
2442 if (lhs == DBL_MRK) {
\r
2443 result = do_eq(stackDbl[stackTop], rhs);
\r
2446 result = ScriptRuntime.eq(lhs, rhs);
\r
2452 // Optimized version of ScriptRuntime.eq if x is a Number
\r
2453 private static boolean do_eq(double x, Object y) {
\r
2455 if (y instanceof Number) {
\r
2456 return x == ((Number) y).doubleValue();
\r
2458 if (y instanceof String) {
\r
2459 return x == ScriptRuntime.toNumber((String)y);
\r
2461 if (y instanceof Boolean) {
\r
2462 return x == (((Boolean)y).booleanValue() ? 1 : 0);
\r
2464 if (y instanceof Scriptable) {
\r
2465 if (y == Undefined.instance) { return false; }
\r
2466 y = ScriptRuntime.toPrimitive(y);
\r
2473 private static boolean do_sheq(Object[] stack, double[] stackDbl,
\r
2477 Object rhs = stack[stackTop + 1];
\r
2478 Object lhs = stack[stackTop];
\r
2479 if (rhs == DBL_MRK) {
\r
2480 double rDbl = stackDbl[stackTop + 1];
\r
2481 if (lhs == DBL_MRK) {
\r
2482 result = (stackDbl[stackTop] == rDbl);
\r
2485 result = (lhs instanceof Number);
\r
2487 result = (((Number)lhs).doubleValue() == rDbl);
\r
2491 else if (rhs instanceof Number) {
\r
2492 double rDbl = ((Number)rhs).doubleValue();
\r
2493 if (lhs == DBL_MRK) {
\r
2494 result = (stackDbl[stackTop] == rDbl);
\r
2497 result = (lhs instanceof Number);
\r
2499 result = (((Number)lhs).doubleValue() == rDbl);
\r
2504 result = ScriptRuntime.shallowEq(lhs, rhs);
\r
2509 private int version;
\r
2510 private boolean inLineStepMode;
\r
2511 private StringBuffer debugSource;
\r
2513 private static final Object DBL_MRK = new Object();
\r