2003/05/12 05:10:30
[org.ibex.core.git] / src / org / mozilla / javascript / Interpreter.java
1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
2  *\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
7  *\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
12  *\r
13  * The Original Code is Rhino code, released\r
14  * May 6, 1999.\r
15  *\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
19  * Rights Reserved.\r
20  *\r
21  * Contributor(s): \r
22  * Patrick Beard\r
23  * Norris Boyd\r
24  * Igor Bukanov\r
25  * Roger Lawrence\r
26  *\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
37  */\r
38 \r
39 package org.mozilla.javascript;\r
40 \r
41 import java.io.*;\r
42 import java.util.Vector;\r
43 import java.util.Enumeration;\r
44 \r
45 import org.mozilla.javascript.debug.*;\r
46 \r
47 public class Interpreter extends LabelTable {\r
48     \r
49     public static final boolean printICode = false;\r
50     \r
51     public IRFactory createIRFactory(TokenStream ts, \r
52                                      ClassNameHelper nameHelper, Scriptable scope) \r
53     {\r
54         return new IRFactory(ts, scope);\r
55     }\r
56     \r
57     public Node transform(Node tree, TokenStream ts, Scriptable scope) {\r
58         return (new NodeTransformer()).transform(tree, null, ts, scope);\r
59     }\r
60     \r
61     public Object compile(Context cx, Scriptable scope, Node tree, \r
62                           Object securityDomain,\r
63                           SecuritySupport securitySupport,\r
64                           ClassNameHelper nameHelper)\r
65         throws IOException\r
66     {\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
76             return result;\r
77         }\r
78         return generateScriptICode(cx, scope, tree, securityDomain);\r
79     }\r
80        \r
81     private void generateICodeFromTree(Node tree, \r
82                                        VariableTable varTable, \r
83                                        boolean needsActivation,\r
84                                        Object securityDomain)\r
85     {\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
95     }\r
96 \r
97     private Object[] generateRegExpLiterals(Context cx,\r
98                                             Scriptable scope,\r
99                                             Vector regexps)\r
100     {\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
110         }\r
111         return result;\r
112     }\r
113         \r
114     private InterpretedScript generateScriptICode(Context cx, \r
115                                                   Scriptable scope, \r
116                                                   Node tree,\r
117                                                   Object securityDomain)\r
118     {        \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
129         \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
138                                                                \r
139         String[] argNames = itsVariableTable.getAllNames();\r
140         short argCount = (short)itsVariableTable.getParameterCount();\r
141         InterpretedScript\r
142             result = new InterpretedScript(cx, itsData, argNames, argCount);\r
143         if (cx.debugger != null) {\r
144             cx.debugger.handleCompilationDone(cx, result, debugSource);\r
145         }\r
146         return result;\r
147     }\r
148     \r
149     private void generateNestedFunctions(Scriptable scope,\r
150                                          Context cx, \r
151                                          Object securityDomain)\r
152     {\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
165                                                               securityDomain);\r
166             def.putProp(Node.FUNCTION_PROP, new Short(i));\r
167         }\r
168     }        \r
169     \r
170     private InterpretedFunction \r
171     generateFunctionICode(Context cx, Scriptable scope, \r
172                           FunctionNode theFunction, Object securityDomain)\r
173     {\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
181 \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
188                               securityDomain);\r
189             \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
197             \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
204         }\r
205         return result;\r
206     }\r
207     \r
208     boolean itsInFunctionFlag;\r
209     Vector itsFunctionList;\r
210     \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
219     \r
220     private int updateLineNumber(Node node, int iCodeTop)\r
221     {\r
222         Object datum = node.getDatum();\r
223         if (datum == null || !(datum instanceof Number))\r
224             return iCodeTop;\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
230             {\r
231                 itsData.itsLineNumberTable = new UintMap();\r
232             }\r
233             if (itsData.itsLineNumberTable != null) {\r
234                 itsData.itsLineNumberTable.put(lineNumber, iCodeTop);\r
235             }\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
239             \r
240         }\r
241         \r
242         return iCodeTop;\r
243     }\r
244     \r
245     private void badTree(Node node)\r
246     {\r
247         try {\r
248             out = new PrintWriter(new FileOutputStream("icode.txt", true));\r
249             out.println("Un-handled node : " + node.toString());\r
250             out.close();\r
251         }\r
252         catch (IOException x) {}\r
253         throw new RuntimeException("Un-handled node : "\r
254                                         + node.toString());\r
255     }\r
256     \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
261         switch (type) {\r
262             \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
269                     itsStackDepth++;\r
270                     if (itsStackDepth > itsData.itsMaxStack)\r
271                         itsData.itsMaxStack = itsStackDepth;\r
272                 }\r
273                 break;\r
274 \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
281                 }\r
282                 break;\r
283 \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
290                 }\r
291                 break;\r
292                 \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
304                 }\r
305                 break;\r
306 \r
307             case TokenStream.COMMA :\r
308                 iCodeTop = generateICode(child, iCodeTop);\r
309                 iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);\r
310                 itsStackDepth--;\r
311                 child = child.getNextSibling();\r
312                 iCodeTop = generateICode(child, iCodeTop);\r
313                 break;\r
314                \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
322                     itsStackDepth--;\r
323          /*\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
328          */\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
339                         itsStackDepth++;\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
349                                            iCodeTop);\r
350                         itsStackDepth--;\r
351                     }\r
352 \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
360                                                             iCodeTop);                    \r
361                     }\r
362 \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
367                                        iCodeTop);                    \r
368                 }\r
369                 break;\r
370                                 \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
376                     }\r
377                     else {\r
378                         int label = ((Integer)lblObect).intValue();\r
379                         markLabel(label, iCodeTop);\r
380                     }\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
384                         itsStackDepth = 1;\r
385                         if (itsStackDepth > itsData.itsMaxStack)\r
386                             itsData.itsMaxStack = itsStackDepth;\r
387                     }\r
388                 }\r
389                 break;\r
390                 \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
402                     }\r
403                     iCodeTop = addByte((byte) op, iCodeTop);\r
404                     itsStackDepth--;\r
405                 }\r
406                 break;\r
407                 \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
413                     \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
423                         }\r
424                         child = child.getNextSibling();\r
425                         childCount++;\r
426                     }\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
433                     } else {\r
434                         iCodeTop = addByte((byte) type, iCodeTop);\r
435                         iCodeTop = addByte((byte)(nameIndex >> 8), iCodeTop);\r
436                         iCodeTop = addByte((byte)(nameIndex & 0xFF), iCodeTop);\r
437                     }\r
438                     \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
442                         childCount -= 1;\r
443                     else\r
444                         childCount -= 2;\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
449                     \r
450                     iCodeTop = addByte((byte)TokenStream.SOURCEFILE, iCodeTop);\r
451                 }\r
452                 break;\r
453                 \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
459                 }\r
460                 break;                \r
461                    \r
462             case TokenStream.USELOCAL : {\r
463                     if (node.getProp(Node.TARGET_PROP) != null) \r
464                         iCodeTop = addByte((byte) TokenStream.RETSUB, iCodeTop);\r
465                     else {\r
466                         iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);\r
467                         itsStackDepth++;\r
468                         if (itsStackDepth > itsData.itsMaxStack)\r
469                             itsData.itsMaxStack = itsStackDepth;\r
470                     }\r
471                     Node temp = (Node) node.getProp(Node.LOCAL_PROP);\r
472                     iCodeTop = addLocalRef(temp, iCodeTop);\r
473                 }\r
474                 break;                \r
475 \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
480                     itsStackDepth++;\r
481                     if (itsStackDepth > itsData.itsMaxStack)\r
482                         itsData.itsMaxStack = itsStackDepth;\r
483                 }\r
484                 break;                \r
485                 \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
490                     // fall thru...\r
491             case TokenStream.GOTO :\r
492                 iCodeTop = addGoto(node, (byte) type, iCodeTop);\r
493                 break;\r
494 \r
495             case TokenStream.JSR : {\r
496                 /*\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
499                     of the stack.\r
500                     !!! \r
501                     This only works if the target follows the JSR\r
502                     in the tree.\r
503                     !!!\r
504                 */\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
508                 }\r
509                 break;\r
510             \r
511             case TokenStream.AND : {            \r
512                     iCodeTop = generateICode(child, iCodeTop);\r
513                     iCodeTop = addByte((byte) TokenStream.DUP, iCodeTop);                \r
514                     itsStackDepth++;\r
515                     if (itsStackDepth > itsData.itsMaxStack)\r
516                         itsData.itsMaxStack = itsStackDepth;\r
517                     int falseTarget = acquireLabel();\r
518                     iCodeTop = addGoto(falseTarget, TokenStream.IFNE, \r
519                                                     iCodeTop);\r
520                     iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);\r
521                     itsStackDepth--;\r
522                     child = child.getNextSibling();\r
523                     iCodeTop = generateICode(child, iCodeTop);\r
524                     markLabel(falseTarget, iCodeTop);\r
525                 }\r
526                 break;\r
527 \r
528             case TokenStream.OR : {\r
529                     iCodeTop = generateICode(child, iCodeTop);\r
530                     iCodeTop = addByte((byte) TokenStream.DUP, iCodeTop);                \r
531                     itsStackDepth++;\r
532                     if (itsStackDepth > itsData.itsMaxStack)\r
533                         itsData.itsMaxStack = itsStackDepth;\r
534                     int trueTarget = acquireLabel();\r
535                     iCodeTop = addGoto(trueTarget, TokenStream.IFEQ,\r
536                                        iCodeTop);\r
537                     iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);                \r
538                     itsStackDepth--;\r
539                     child = child.getNextSibling();\r
540                     iCodeTop = generateICode(child, iCodeTop);\r
541                     markLabel(trueTarget, iCodeTop);\r
542                 }\r
543                 break;\r
544 \r
545             case TokenStream.GETPROP : {\r
546                     iCodeTop = generateICode(child, iCodeTop);\r
547                     String s = (String) node.getProp(Node.SPECIAL_PROP_PROP);\r
548                     if (s != null) {\r
549                         if (s.equals("__proto__"))\r
550                             iCodeTop = addByte((byte) TokenStream.GETPROTO, iCodeTop);\r
551                         else\r
552                             if (s.equals("__parent__"))\r
553                                 iCodeTop = addByte((byte) TokenStream.GETSCOPEPARENT, iCodeTop);\r
554                             else\r
555                                 badTree(node);\r
556                     }\r
557                     else {\r
558                         child = child.getNextSibling();\r
559                         iCodeTop = generateICode(child, iCodeTop);\r
560                         iCodeTop = addByte((byte) TokenStream.GETPROP, iCodeTop);\r
561                         itsStackDepth--;\r
562                     }\r
563                 }\r
564                 break;\r
565 \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
583                 itsStackDepth--;\r
584                 break;\r
585 \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
591                     else\r
592                         badTree(node);\r
593                 }\r
594                 break;\r
595 \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
602                         break;\r
603                     case TokenStream.NOT : {\r
604                             int trueTarget = acquireLabel();\r
605                             int beyond = acquireLabel();\r
606                             iCodeTop = addGoto(trueTarget, TokenStream.IFEQ,\r
607                                                         iCodeTop);\r
608                             iCodeTop = addByte((byte) TokenStream.TRUE, iCodeTop);\r
609                             iCodeTop = addGoto(beyond, TokenStream.GOTO, \r
610                                                         iCodeTop);\r
611                             markLabel(trueTarget, iCodeTop);\r
612                             iCodeTop = addByte((byte) TokenStream.FALSE, iCodeTop);\r
613                             markLabel(beyond, iCodeTop);\r
614                         }\r
615                         break;\r
616                     case TokenStream.BITNOT :\r
617                         iCodeTop = addByte((byte) TokenStream.BITNOT, iCodeTop);\r
618                         break;\r
619                     case TokenStream.TYPEOF :\r
620                         iCodeTop = addByte((byte) TokenStream.TYPEOF, iCodeTop);\r
621                         break;\r
622                     case TokenStream.SUB :\r
623                         iCodeTop = addByte((byte) TokenStream.NEG, iCodeTop);\r
624                         break;\r
625                     case TokenStream.ADD :\r
626                         iCodeTop = addByte((byte) TokenStream.POS, iCodeTop);\r
627                         break;\r
628                     default:\r
629                         badTree(node);\r
630                         break;\r
631                 }\r
632                 break;\r
633 \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
639                     if (s != null) {\r
640                         if (s.equals("__proto__"))\r
641                             iCodeTop = addByte((byte) TokenStream.SETPROTO, iCodeTop);\r
642                         else\r
643                             if (s.equals("__parent__"))\r
644                                 iCodeTop = addByte((byte) TokenStream.SETPARENT, iCodeTop);\r
645                             else\r
646                                 badTree(node);\r
647                     }\r
648                     else {\r
649                         child = child.getNextSibling();\r
650                         iCodeTop = generateICode(child, iCodeTop);\r
651                         iCodeTop = addByte((byte) TokenStream.SETPROP, iCodeTop);\r
652                         itsStackDepth -= 2;\r
653                     }\r
654                 }\r
655                 break;            \r
656 \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
665                 break;\r
666 \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
673                 itsStackDepth--;\r
674                 break;\r
675                 \r
676             case TokenStream.TYPEOF : {\r
677                     String name = node.getString();\r
678                     int index = -1;\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
686                     }\r
687                     else {\r
688                         iCodeTop = addByte((byte) TokenStream.GETVAR, iCodeTop);\r
689                         iCodeTop = addByte((byte) index, iCodeTop);\r
690                         iCodeTop = addByte((byte) TokenStream.TYPEOF, iCodeTop);\r
691                     }\r
692                     itsStackDepth++;\r
693                     if (itsStackDepth > itsData.itsMaxStack)\r
694                         itsData.itsMaxStack = itsStackDepth;\r
695                 }\r
696                 break;\r
697 \r
698             case TokenStream.PARENT :\r
699                 iCodeTop = generateICode(child, iCodeTop);\r
700                 iCodeTop = addByte((byte) TokenStream.GETPARENT, iCodeTop);\r
701                 break;\r
702 \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
709                 itsStackDepth++;\r
710                 if (itsStackDepth > itsData.itsMaxStack)\r
711                     itsData.itsMaxStack = itsStackDepth;\r
712                 break;\r
713 \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
731                                                  iCodeTop);\r
732                                     itsStackDepth--;                                        \r
733                                 }\r
734                                 else {\r
735                                     iCodeTop = addByte((byte)\r
736                                                 (type == TokenStream.INC\r
737                                                     ? TokenStream.VARINC\r
738                                                     : TokenStream.VARDEC),\r
739                                                 iCodeTop);\r
740                                     int i = itsVariableTable.getOrdinal(name);\r
741                                     iCodeTop = addByte((byte)i, iCodeTop);\r
742                                     itsStackDepth++;\r
743                                     if (itsStackDepth > itsData.itsMaxStack)\r
744                                         itsData.itsMaxStack = itsStackDepth;\r
745                                 }\r
746                             }\r
747                             break;\r
748                         case TokenStream.GETPROP :\r
749                         case TokenStream.GETELEM : {\r
750                                 Node getPropChild = child.getFirstChild();\r
751                                 iCodeTop = generateICode(getPropChild,\r
752                                                               iCodeTop);\r
753                                 getPropChild = getPropChild.getNextSibling();\r
754                                 iCodeTop = generateICode(getPropChild,\r
755                                                               iCodeTop);\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
761                                                     iCodeTop);\r
762                                 else                                                        \r
763                                     iCodeTop = addByte((byte)\r
764                                                     (type == TokenStream.INC\r
765                                                         ? TokenStream.ELEMINC \r
766                                                         : TokenStream.ELEMDEC),\r
767                                                     iCodeTop);\r
768                                 itsStackDepth--;                                        \r
769                             }\r
770                             break;\r
771                         default : {\r
772                                 iCodeTop = addByte((byte)\r
773                                                     (type == TokenStream.INC \r
774                                                         ? TokenStream.NAMEINC \r
775                                                         : TokenStream.NAMEDEC),\r
776                                                     iCodeTop);\r
777                                 iCodeTop = addString(child.getString(), \r
778                                                             iCodeTop);\r
779                                 itsStackDepth++;\r
780                                 if (itsStackDepth > itsData.itsMaxStack)\r
781                                     itsData.itsMaxStack = itsStackDepth;\r
782                             }\r
783                             break;\r
784                     }\r
785                 }\r
786                 break;\r
787 \r
788             case TokenStream.NUMBER : {\r
789                 double num = node.getDouble();\r
790                 if (num == 0.0) {\r
791                     iCodeTop = addByte((byte) TokenStream.ZERO, iCodeTop);\r
792                 }\r
793                 else if (num == 1.0) {\r
794                     iCodeTop = addByte((byte) TokenStream.ONE, iCodeTop);\r
795                 }\r
796                 else {\r
797                     iCodeTop = addByte((byte) TokenStream.NUMBER, iCodeTop);\r
798                     iCodeTop = addNumber(num, iCodeTop);\r
799                 }\r
800                 itsStackDepth++;\r
801                 if (itsStackDepth > itsData.itsMaxStack)\r
802                     itsData.itsMaxStack = itsStackDepth;\r
803                 break;\r
804             }\r
805 \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
812                 itsStackDepth--;\r
813                 break;\r
814 \r
815             case TokenStream.GETTHIS :\r
816                 iCodeTop = generateICode(child, iCodeTop);\r
817                 iCodeTop = addByte((byte) type, iCodeTop);\r
818                 break;\r
819                 \r
820             case TokenStream.NEWSCOPE :\r
821                 iCodeTop = addByte((byte) type, iCodeTop);\r
822                 itsStackDepth++;\r
823                 if (itsStackDepth > itsData.itsMaxStack)\r
824                     itsData.itsMaxStack = itsStackDepth;\r
825                 break;\r
826 \r
827             case TokenStream.LEAVEWITH :\r
828                 iCodeTop = addByte((byte) type, iCodeTop);\r
829                 break;\r
830 \r
831             case TokenStream.TRY : {\r
832                     itsTryDepth++;\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
841                     }\r
842                     else\r
843                         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
850                     }\r
851                     iCodeTop = addByte((byte)0, iCodeTop);\r
852                     iCodeTop = addByte((byte)0, iCodeTop);\r
853                     \r
854                     Node lastChild = null;\r
855                     /*\r
856                         when we encounter the child of the catchTarget, we\r
857                         set the stackDepth to 1 to account for the incoming\r
858                         exception object.\r
859                     */\r
860                     boolean insertedEndTry = false;\r
861                     while (child != null) {\r
862                         if (catchTarget != null && lastChild == catchTarget) {\r
863                             itsStackDepth = 1;\r
864                             if (itsStackDepth > itsData.itsMaxStack)\r
865                                 itsData.itsMaxStack = itsStackDepth;\r
866                         }\r
867                         /*\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
872                             before that goto.\r
873                         */\r
874                         Node nextSibling = child.getNextSibling();\r
875                         if (!insertedEndTry && nextSibling != null &&\r
876                             (nextSibling == catchTarget ||\r
877                              nextSibling == finallyTarget))\r
878                         {\r
879                             iCodeTop = addByte((byte) TokenStream.ENDTRY,\r
880                                                iCodeTop);\r
881                             insertedEndTry = true;\r
882                         }\r
883                         iCodeTop = generateICode(child, iCodeTop);\r
884                         lastChild = child;\r
885                         child = child.getNextSibling();\r
886                     }\r
887                     itsStackDepth = 0;\r
888                     if (finallyTarget != null) {\r
889                         // normal flow goes around the finally handler stublet\r
890                         int skippy = acquireLabel();\r
891                         iCodeTop = \r
892                             addGoto(skippy, TokenStream.GOTO, iCodeTop);\r
893                         // on entry the stack will have the exception object\r
894                         markLabel(finallyHandler, iCodeTop);\r
895                         itsStackDepth = 1;\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
909                         itsStackDepth = 0;\r
910                         markLabel(skippy, iCodeTop);\r
911                     }\r
912                     itsTryDepth--;\r
913                 }\r
914                 break;\r
915                 \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
920                 itsStackDepth--;\r
921                 break;\r
922                 \r
923             case TokenStream.ASSERT:\r
924                 iCodeTop = updateLineNumber(node, iCodeTop);\r
925                 if (child != null) \r
926                     iCodeTop = generateICode(child, iCodeTop);\r
927                 else {\r
928                     iCodeTop = addByte((byte) TokenStream.UNDEFINED, iCodeTop);\r
929                     itsStackDepth++;\r
930                     if (itsStackDepth > itsData.itsMaxStack)\r
931                         itsData.itsMaxStack = itsStackDepth;\r
932                 }\r
933                 iCodeTop = addGoto(node, TokenStream.ASSERT, iCodeTop);\r
934                 itsStackDepth--;\r
935                 break;\r
936                 \r
937             case TokenStream.RETURN :\r
938                 iCodeTop = updateLineNumber(node, iCodeTop);\r
939                 if (child != null) \r
940                     iCodeTop = generateICode(child, iCodeTop);\r
941                 else {\r
942                     iCodeTop = addByte((byte) TokenStream.UNDEFINED, iCodeTop);\r
943                     itsStackDepth++;\r
944                     if (itsStackDepth > itsData.itsMaxStack)\r
945                         itsData.itsMaxStack = itsStackDepth;\r
946                 }\r
947                 iCodeTop = addGoto(node, TokenStream.RETURN, iCodeTop);\r
948                 itsStackDepth--;\r
949                 break;\r
950                 \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
965                         itsStackDepth--;\r
966                     }\r
967                     else {\r
968                         int index = itsVariableTable.getOrdinal(name);\r
969                         iCodeTop = addByte((byte) TokenStream.GETVAR, iCodeTop);\r
970                         iCodeTop = addByte((byte)index, iCodeTop);\r
971                         itsStackDepth++;\r
972                         if (itsStackDepth > itsData.itsMaxStack)\r
973                             itsData.itsMaxStack = itsStackDepth;\r
974                     }\r
975                 }\r
976                 break;\r
977                 \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
983                     }\r
984                     else {\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
991                     }\r
992                 }\r
993                 break;\r
994                 \r
995             case TokenStream.PRIMARY:\r
996                 iCodeTop = addByte((byte) node.getInt(), iCodeTop);\r
997                 itsStackDepth++;\r
998                 if (itsStackDepth > itsData.itsMaxStack)\r
999                     itsData.itsMaxStack = itsStackDepth;\r
1000                 break;\r
1001 \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
1006                 itsStackDepth--;\r
1007                 break;\r
1008                 \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
1013                     itsStackDepth++;\r
1014                     if (itsStackDepth > itsData.itsMaxStack)\r
1015                         itsData.itsMaxStack = itsStackDepth;\r
1016                 }                        \r
1017                 break;\r
1018                 \r
1019             case TokenStream.ENUMDONE :\r
1020                 // could release the local here??\r
1021                 break;\r
1022                 \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
1030                     itsStackDepth++;\r
1031                     if (itsStackDepth > itsData.itsMaxStack)\r
1032                         itsData.itsMaxStack = itsStackDepth;\r
1033                 }\r
1034                 break;\r
1035                 \r
1036             default : \r
1037                 badTree(node);\r
1038                 break;\r
1039         }\r
1040         return iCodeTop;\r
1041     }\r
1042     \r
1043     private int addLocalRef(Node node, int iCodeTop)\r
1044     {\r
1045         int theLocalSlot;\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
1050         }\r
1051         else\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
1056         return iCodeTop;            \r
1057     }\r
1058     \r
1059     private int addGoto(Node node, int gotoOp, int iCodeTop)\r
1060     {\r
1061         int targetLabel;\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
1066         }\r
1067         else {\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
1073             }\r
1074             else\r
1075                 targetLabel = ((Integer)lblObect).intValue();\r
1076         }\r
1077         iCodeTop = addGoto(targetLabel, (byte) gotoOp, iCodeTop);\r
1078         return iCodeTop;\r
1079     }\r
1080     \r
1081     private int addGoto(int targetLabel, int gotoOp, int iCodeTop)\r
1082     {\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
1091         }\r
1092         else {\r
1093             itsLabelTable[theLabel].addFixup(gotoPC + 1);\r
1094             iCodeTop = addByte((byte)0, iCodeTop);\r
1095             iCodeTop = addByte((byte)0, iCodeTop);\r
1096         }\r
1097         return iCodeTop;\r
1098     }\r
1099     \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
1105         }\r
1106         itsData.itsICode[iCodeTop++] = b;\r
1107         return iCodeTop;\r
1108     }\r
1109     \r
1110     private final int addString(String str, int iCodeTop)\r
1111     {\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
1117         }\r
1118         itsData.itsStringTable[index] = str;\r
1119         itsData.itsStringTableIndex = index + 1;\r
1120 \r
1121         iCodeTop = addByte((byte)(index >> 8), iCodeTop);\r
1122         iCodeTop = addByte((byte)(index & 0xFF), iCodeTop);\r
1123         return iCodeTop;\r
1124     }\r
1125     \r
1126     private final int addNumber(double num, int iCodeTop)\r
1127     {\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
1133         }\r
1134         itsData.itsNumberTable[index] = num;\r
1135         itsData.itsNumberTableIndex = index + 1;\r
1136 \r
1137         iCodeTop = addByte((byte)(index >> 8), iCodeTop);\r
1138         iCodeTop = addByte((byte)(index & 0xFF), iCodeTop);\r
1139         return iCodeTop;\r
1140     }\r
1141     \r
1142     private static String getString(String[] theStringTable, byte[] iCode, \r
1143                                     int pc)\r
1144     {\r
1145         int index = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);\r
1146         return theStringTable[index];\r
1147     }\r
1148     \r
1149     private static double getNumber(double[] theNumberTable, byte[] iCode, \r
1150                                     int pc)\r
1151     {\r
1152         int index = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);\r
1153         return theNumberTable[index];\r
1154     }\r
1155     \r
1156     private static int getTarget(byte[] iCode, int pc)\r
1157     {\r
1158         int displacement = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);\r
1159         return pc - 1 + displacement;\r
1160     }\r
1161     \r
1162     static PrintWriter out;\r
1163     static {\r
1164         if (printICode) {\r
1165             try {\r
1166                 out = new PrintWriter(new FileOutputStream("icode.txt"));\r
1167                 out.close();\r
1168             }\r
1169             catch (IOException x) {\r
1170             }\r
1171         }\r
1172     }   \r
1173     \r
1174     private static void dumpICode(InterpreterData theData) {\r
1175         if (printICode) {\r
1176             try {\r
1177                 int iCodeLength = theData.itsICodeTop;\r
1178                 byte iCode[] = theData.itsICode;\r
1179                 \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
1183                 \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
1247                             break;\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
1254                                 out.println(\r
1255                                     TokenStream.tokenToName(iCode[pc] & 0xff) +\r
1256                                     " " + newPC);\r
1257                                 pc += 2;\r
1258                             }\r
1259                             break;\r
1260                         case TokenStream.TRY : {\r
1261                                 int newPC1 = getTarget(iCode, pc + 1);                    \r
1262                                 int newPC2 = getTarget(iCode, pc + 3);                    \r
1263                                 out.println(\r
1264                                     TokenStream.tokenToName(iCode[pc] & 0xff) +\r
1265                                     " " + newPC1 +\r
1266                                     " " + newPC2);\r
1267                                 pc += 4;\r
1268                             }\r
1269                             break;\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
1280                                 out.println(\r
1281                                     TokenStream.tokenToName(iCode[pc] & 0xff) +\r
1282                                     " " + slot);\r
1283                                 pc++;\r
1284                             }\r
1285                             break;\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
1290                                                                   iCode, pc + 3);\r
1291                                 int count = (iCode[pc + 5] << 8) | (iCode[pc + 6] & 0xFF);\r
1292                                 out.println(\r
1293                                     TokenStream.tokenToName(iCode[pc] & 0xff) +\r
1294                                     " " + count + " " + line + " " + name);\r
1295                                 pc += 6;\r
1296                             }\r
1297                             break;\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
1303                                 out.println(\r
1304                                     TokenStream.tokenToName(iCode[pc] & 0xff) +\r
1305                                     " " + count + " \"" + \r
1306                                     getString(theData.itsStringTable, iCode, \r
1307                                               pc + 1) + "\"");\r
1308                                 pc += 5;\r
1309                             }\r
1310                             break;\r
1311                         case TokenStream.NUMBER :\r
1312                             out.println(\r
1313                                 TokenStream.tokenToName(iCode[pc] & 0xff) + \r
1314                                 " " + getNumber(theData.itsNumberTable,\r
1315                                                 iCode, pc + 1));\r
1316                             pc += 2;\r
1317                             break;\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
1326                             out.println(\r
1327                                 TokenStream.tokenToName(iCode[pc] & 0xff) +\r
1328                                 " \"" +\r
1329                                 getString(theData.itsStringTable, iCode, pc + 1) +\r
1330                                 "\"");\r
1331                             pc += 2;\r
1332                             break;\r
1333                         case TokenStream.LINE : {\r
1334                                 int line = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);\r
1335                                 out.println(\r
1336                                     TokenStream.tokenToName(iCode[pc] & 0xff) + " : " + line);\r
1337                                 pc += 2;\r
1338                             }\r
1339                             break;\r
1340                         default :\r
1341                             out.close();\r
1342                             throw new RuntimeException("Unknown icode : "\r
1343                                                     + (iCode[pc] & 0xff)  + " @ pc : " + pc);\r
1344                     }\r
1345                     pc++;\r
1346                 }\r
1347                 out.close();\r
1348             }\r
1349             catch (IOException x) {}\r
1350         }\r
1351     }\r
1352     \r
1353     private static void createFunctionObject(InterpretedFunction fn, \r
1354                                              Scriptable scope)\r
1355     {\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
1360             return;\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
1365         {\r
1366             ScriptRuntime.setProp(scope, fn.itsData.itsName, fn, scope);\r
1367         }\r
1368     }\r
1369     \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
1375     {\r
1376         int i;\r
1377         Object lhs;\r
1378 \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
1384         \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
1388 \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
1395 \r
1396         final Object DBL_MRK = Interpreter.DBL_MRK;\r
1397         \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
1402         int pc = 0;\r
1403         int iCodeLength = theData.itsICodeTop;\r
1404         \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
1412                 }\r
1413             }\r
1414             for (i = definedArgs; i != maxVars; ++i) {\r
1415                 stack[VAR_SHFT + i] = undefined;\r
1416             }\r
1417         }\r
1418         \r
1419         if (theData.itsNestedFunctions != null) {\r
1420             for (i = 0; i < theData.itsNestedFunctions.length; i++)\r
1421                 createFunctionObject(theData.itsNestedFunctions[i], scope);\r
1422         }        \r
1423 \r
1424         Object id;\r
1425         Object rhs, val;\r
1426         double valDbl;\r
1427         boolean valBln;\r
1428 \r
1429         int count;\r
1430         int slot;\r
1431                 \r
1432         String name = null;\r
1433                \r
1434         Object[] outArgs;\r
1435 \r
1436         int lIntValue;\r
1437         long lLongValue;\r
1438         double lDbl;\r
1439         int rIntValue;\r
1440         double rDbl;\r
1441                 \r
1442         int[] catchStack = null;\r
1443         int tryStackTop = 0;\r
1444         InterpreterFrame frame = null;\r
1445         \r
1446         if (cx.debugger != null) {\r
1447             frame = new InterpreterFrame(scope, theData, fnOrScript);\r
1448             cx.pushFrame(frame);\r
1449         }\r
1450             \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
1455         }\r
1456         \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
1461          */\r
1462         Object savedSecurityDomain = cx.interpreterSecurityDomain;\r
1463         cx.interpreterSecurityDomain = theData.securityDomain;\r
1464         Object result = undefined;\r
1465         \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
1469         // adjust it\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
1474         \r
1475         while (pc < iCodeLength) {\r
1476             try {\r
1477                 switch (iCode[pc] & 0xff) {\r
1478                     case TokenStream.ENDTRY :\r
1479                         tryStackTop--;\r
1480                         break;\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
1489                         ++tryStackTop;\r
1490                         pc += 4;\r
1491                         break;\r
1492                     case TokenStream.GE :\r
1493                         --stackTop;\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
1500                                       && rDbl <= lDbl);\r
1501                         }\r
1502                         else {\r
1503                             valBln = (1 == ScriptRuntime.cmp_LE(rhs, lhs));\r
1504                         }\r
1505                         stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
1506                         break;\r
1507                     case TokenStream.LE :\r
1508                         --stackTop;\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
1515                                       && lDbl <= rDbl);\r
1516                         }\r
1517                         else {\r
1518                             valBln = (1 == ScriptRuntime.cmp_LE(lhs, rhs));\r
1519                         }\r
1520                         stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
1521                         break;\r
1522                     case TokenStream.GT :\r
1523                         --stackTop;\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
1530                                       && rDbl < lDbl);\r
1531                         }\r
1532                         else {\r
1533                             valBln = (1 == ScriptRuntime.cmp_LT(rhs, lhs));\r
1534                         }\r
1535                         stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
1536                         break;\r
1537                     case TokenStream.LT :\r
1538                         --stackTop;\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
1545                                       && lDbl < rDbl);\r
1546                         }\r
1547                         else {\r
1548                             valBln = (1 == ScriptRuntime.cmp_LT(lhs, rhs));\r
1549                         }\r
1550                         stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
1551                         break;\r
1552                     case TokenStream.IN :\r
1553                         rhs = stack[stackTop];    \r
1554                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
1555                         --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
1560                         break;\r
1561                     case TokenStream.INSTANCEOF :\r
1562                         rhs = stack[stackTop];    \r
1563                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
1564                         --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
1569                         break;\r
1570                     case TokenStream.EQ :\r
1571                         --stackTop;\r
1572                         valBln = do_eq(stack, sDbl, stackTop);\r
1573                         stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
1574                         break;\r
1575                     case TokenStream.NE :\r
1576                         --stackTop;\r
1577                         valBln = !do_eq(stack, sDbl, stackTop);\r
1578                         stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
1579                         break;\r
1580                     case TokenStream.SHEQ :\r
1581                         --stackTop;\r
1582                         valBln = do_sheq(stack, sDbl, stackTop);\r
1583                         stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
1584                         break;\r
1585                     case TokenStream.SHNE :\r
1586                         --stackTop;\r
1587                         valBln = !do_sheq(stack, sDbl, stackTop);\r
1588                         stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
1589                         break;\r
1590                     case TokenStream.IFNE :\r
1591                         val = stack[stackTop];\r
1592                         if (val != DBL_MRK) {\r
1593                             valBln = !ScriptRuntime.toBoolean(val);\r
1594                         }\r
1595                         else {\r
1596                             valDbl = sDbl[stackTop];\r
1597                             valBln = !(valDbl == valDbl && valDbl != 0.0);\r
1598                         }\r
1599                         --stackTop;\r
1600                         if (valBln) {\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
1607                                 }\r
1608                             }\r
1609                             pcPrevBranch = pc = getTarget(iCode, pc + 1);\r
1610                             continue;\r
1611                         }\r
1612                         pc += 2;\r
1613                         break;\r
1614                     case TokenStream.IFEQ :\r
1615                         val = stack[stackTop];\r
1616                         if (val != DBL_MRK) {\r
1617                             valBln = ScriptRuntime.toBoolean(val);\r
1618                         }\r
1619                         else {\r
1620                             valDbl = sDbl[stackTop];\r
1621                             valBln = (valDbl == valDbl && valDbl != 0.0);\r
1622                         }\r
1623                         --stackTop;\r
1624                         if (valBln) {\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
1631                                 }\r
1632                             }\r
1633                             pcPrevBranch = pc = getTarget(iCode, pc + 1);\r
1634                             continue;\r
1635                         }\r
1636                         pc += 2;\r
1637                         break;\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
1644                             }\r
1645                         }\r
1646                         pcPrevBranch = pc = getTarget(iCode, pc + 1);\r
1647                         continue;\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
1655                             }\r
1656                         }\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
1665                             }\r
1666                         }\r
1667                         pcPrevBranch = pc = (int)sDbl[LOCAL_SHFT + slot];\r
1668                         continue;\r
1669                     case TokenStream.POP :\r
1670                         stackTop--;\r
1671                         break;\r
1672                     case TokenStream.DUP :\r
1673                         stack[stackTop + 1] = stack[stackTop];\r
1674                         sDbl[stackTop + 1] = sDbl[stackTop];\r
1675                         stackTop++;\r
1676                         break;\r
1677                     case TokenStream.POPV :\r
1678                         result = stack[stackTop];    \r
1679                         if (result == DBL_MRK) \r
1680                             result = doubleWrap(sDbl[stackTop]);\r
1681                         --stackTop;\r
1682                         break;\r
1683                     case TokenStream.RETURN :\r
1684                         result = stack[stackTop];    \r
1685                         if (result == DBL_MRK) \r
1686                             result = doubleWrap(sDbl[stackTop]);\r
1687                         --stackTop;\r
1688                         pc = getTarget(iCode, pc + 1);\r
1689                         break;\r
1690                     case TokenStream.ASSERT :\r
1691                         val = stack[stackTop];\r
1692                         if (val != DBL_MRK) {\r
1693                             valBln = ScriptRuntime.toBoolean(val);\r
1694                         } else {\r
1695                             valDbl = sDbl[stackTop];\r
1696                             valBln = (valDbl == valDbl && valDbl != 0.0);\r
1697                         }\r
1698                         --stackTop;\r
1699                         if (!valBln) {\r
1700                             throw new Error("assertion failed");\r
1701                             //System.exit(-1);\r
1702                         }\r
1703                         pc += 2;\r
1704                         break;\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
1709                         break;\r
1710                     case TokenStream.BITAND :                \r
1711                         rIntValue = stack_int32(stack, sDbl, stackTop);\r
1712                         --stackTop;\r
1713                         lIntValue = stack_int32(stack, sDbl, stackTop);\r
1714                         stack[stackTop] = DBL_MRK;\r
1715                         sDbl[stackTop] = lIntValue & rIntValue;\r
1716                         break;\r
1717                     case TokenStream.BITOR :\r
1718                         rIntValue = stack_int32(stack, sDbl, stackTop);\r
1719                         --stackTop;\r
1720                         lIntValue = stack_int32(stack, sDbl, stackTop);\r
1721                         stack[stackTop] = DBL_MRK;\r
1722                         sDbl[stackTop] = lIntValue | rIntValue;\r
1723                         break;\r
1724                     case TokenStream.BITXOR :\r
1725                         rIntValue = stack_int32(stack, sDbl, stackTop);\r
1726                         --stackTop;\r
1727                         lIntValue = stack_int32(stack, sDbl, stackTop);\r
1728                         stack[stackTop] = DBL_MRK;\r
1729                         sDbl[stackTop] = lIntValue ^ rIntValue;\r
1730                         break;\r
1731                     case TokenStream.LSH :\r
1732                         rIntValue = stack_int32(stack, sDbl, stackTop);\r
1733                         --stackTop;\r
1734                         lIntValue = stack_int32(stack, sDbl, stackTop);\r
1735                         stack[stackTop] = DBL_MRK;\r
1736                         sDbl[stackTop] = lIntValue << rIntValue;\r
1737                         break;\r
1738                     case TokenStream.RSH :\r
1739                         rIntValue = stack_int32(stack, sDbl, stackTop);\r
1740                         --stackTop;\r
1741                         lIntValue = stack_int32(stack, sDbl, stackTop);\r
1742                         stack[stackTop] = DBL_MRK;\r
1743                         sDbl[stackTop] = lIntValue >> rIntValue;\r
1744                         break;\r
1745                     case TokenStream.URSH :\r
1746                         rIntValue = stack_int32(stack, sDbl, stackTop) & 0x1F;\r
1747                         --stackTop;\r
1748                         lLongValue = stack_uint32(stack, sDbl, stackTop);\r
1749                         stack[stackTop] = DBL_MRK;\r
1750                         sDbl[stackTop] = lLongValue >>> rIntValue;\r
1751                         break;\r
1752                     case TokenStream.ADD :\r
1753                         --stackTop;\r
1754                         do_add(stack, sDbl, stackTop);\r
1755                         break;\r
1756                     case TokenStream.SUB :\r
1757                         rDbl = stack_double(stack, sDbl, stackTop);\r
1758                         --stackTop;\r
1759                         lDbl = stack_double(stack, sDbl, stackTop);\r
1760                         stack[stackTop] = DBL_MRK;\r
1761                         sDbl[stackTop] = lDbl - rDbl;\r
1762                         break;\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
1767                         break;\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
1772                         break;\r
1773                     case TokenStream.MUL :\r
1774                         rDbl = stack_double(stack, sDbl, stackTop);\r
1775                         --stackTop;\r
1776                         lDbl = stack_double(stack, sDbl, stackTop);\r
1777                         stack[stackTop] = DBL_MRK;\r
1778                         sDbl[stackTop] = lDbl * rDbl;\r
1779                         break;\r
1780                     case TokenStream.DIV :\r
1781                         rDbl = stack_double(stack, sDbl, stackTop);\r
1782                         --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
1787                         break;\r
1788                     case TokenStream.MOD :\r
1789                         rDbl = stack_double(stack, sDbl, stackTop);\r
1790                         --stackTop;\r
1791                         lDbl = stack_double(stack, sDbl, stackTop);\r
1792                         stack[stackTop] = DBL_MRK;\r
1793                         sDbl[stackTop] = lDbl % rDbl;\r
1794                         break;\r
1795                     case TokenStream.BINDNAME :\r
1796                         stack[++stackTop] = \r
1797                                 ScriptRuntime.bind(scope, \r
1798                                          getString(theData.itsStringTable, \r
1799                                                    iCode, pc + 1));\r
1800                         pc += 2;\r
1801                         break;\r
1802                     case TokenStream.GETBASE :\r
1803                         stack[++stackTop] =\r
1804                                 ScriptRuntime.getBase(scope, \r
1805                                          getString(theData.itsStringTable,\r
1806                                                                 iCode, pc + 1));\r
1807                         pc += 2;\r
1808                         break;\r
1809                     case TokenStream.SETNAME :\r
1810                         rhs = stack[stackTop];    \r
1811                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
1812                         --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
1819                         pc += 2;\r
1820                         break;\r
1821                     case TokenStream.DELPROP :\r
1822                         rhs = stack[stackTop];    \r
1823                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
1824                         --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
1828                         break;\r
1829                     case TokenStream.GETPROP :\r
1830                         name = (String)stack[stackTop];\r
1831                         --stackTop;\r
1832                         lhs = stack[stackTop];    \r
1833                         if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
1834                         stack[stackTop] \r
1835                                 = ScriptRuntime.getProp(lhs, name, scope);\r
1836                         break;\r
1837                     case TokenStream.SETPROP :\r
1838                         rhs = stack[stackTop];    \r
1839                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
1840                         --stackTop;\r
1841                         name = (String)stack[stackTop];\r
1842                         --stackTop;\r
1843                         lhs = stack[stackTop];    \r
1844                         if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
1845                         stack[stackTop] \r
1846                                 = ScriptRuntime.setProp(lhs, name, rhs, scope);\r
1847                         break;\r
1848                     case TokenStream.GETELEM :\r
1849                         id = stack[stackTop];    \r
1850                         if (id == DBL_MRK) id = doubleWrap(sDbl[stackTop]);\r
1851                         --stackTop;\r
1852                         lhs = stack[stackTop];    \r
1853                         if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
1854                         stack[stackTop] \r
1855                                 = ScriptRuntime.getElem(lhs, id, scope);\r
1856                         break;\r
1857                     case TokenStream.SETELEM :\r
1858                         rhs = stack[stackTop];    \r
1859                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
1860                         --stackTop;\r
1861                         id = stack[stackTop];    \r
1862                         if (id == DBL_MRK) id = doubleWrap(sDbl[stackTop]);\r
1863                         --stackTop;\r
1864                         lhs = stack[stackTop];    \r
1865                         if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
1866                         stack[stackTop] \r
1867                                 = ScriptRuntime.setElem(lhs, id, rhs, scope);\r
1868                         break;\r
1869                     case TokenStream.PROPINC :\r
1870                         name = (String)stack[stackTop];\r
1871                         --stackTop;\r
1872                         lhs = stack[stackTop];    \r
1873                         if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
1874                         stack[stackTop] \r
1875                                 = ScriptRuntime.postIncrement(lhs, name, scope);\r
1876                         break;\r
1877                     case TokenStream.PROPDEC :\r
1878                         name = (String)stack[stackTop];\r
1879                         --stackTop;\r
1880                         lhs = stack[stackTop];    \r
1881                         if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
1882                         stack[stackTop] \r
1883                                 = ScriptRuntime.postDecrement(lhs, name, scope);\r
1884                         break;\r
1885                     case TokenStream.ELEMINC :\r
1886                         rhs = stack[stackTop];    \r
1887                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
1888                         --stackTop;\r
1889                         lhs = stack[stackTop];    \r
1890                         if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
1891                         stack[stackTop] \r
1892                            = ScriptRuntime.postIncrementElem(lhs, rhs, scope);\r
1893                         break;\r
1894                     case TokenStream.ELEMDEC :\r
1895                         rhs = stack[stackTop];    \r
1896                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
1897                         --stackTop;\r
1898                         lhs = stack[stackTop];    \r
1899                         if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
1900                         stack[stackTop] \r
1901                            = ScriptRuntime.postDecrementElem(lhs, rhs, scope);\r
1902                         break;\r
1903                     case TokenStream.GETTHIS :\r
1904                         lhs = stack[stackTop];    \r
1905                         if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
1906                         stack[stackTop] \r
1907                             = ScriptRuntime.getThis((Scriptable)lhs);\r
1908                         break;\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
1913                         break;\r
1914                     case TokenStream.USETEMP :\r
1915                         slot = (iCode[++pc] & 0xFF);\r
1916                         ++stackTop;\r
1917                         stack[stackTop] = stack[LOCAL_SHFT + slot];\r
1918                         sDbl[stackTop] = sDbl[LOCAL_SHFT + slot];\r
1919                         break;\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
1925                         }\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
1935                             outArgs[i] = val;\r
1936                             --stackTop;\r
1937                         }\r
1938                         rhs = stack[stackTop];    \r
1939                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
1940                         --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
1946                         pc += 6;\r
1947                         instructionCount = cx.instructionCount;\r
1948                         break;\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
1954                         }\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
1962                             outArgs[i] = val;\r
1963                             --stackTop;\r
1964                         }\r
1965                         rhs = stack[stackTop];    \r
1966                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
1967                         --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
1972                                             pc + 1);\r
1973                         }\r
1974                         Scriptable calleeScope = scope;\r
1975                         if (theData.itsNeedsActivation) {\r
1976                             calleeScope = ScriptableObject.\r
1977                                 getTopLevelScope(scope);\r
1978                         }\r
1979                         stack[stackTop] = ScriptRuntime.call(cx, lhs, rhs, \r
1980                                                              outArgs, \r
1981                                                              calleeScope);\r
1982                         pc += 4;                                                                         instructionCount = cx.instructionCount;\r
1983                         break;\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
1989                         }\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
1996                             outArgs[i] = val;\r
1997                             --stackTop;\r
1998                         }\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
2003                         {\r
2004                             // special code for better error message for call \r
2005                             //  to undefined\r
2006                             lhs = getString(theData.itsStringTable, iCode, \r
2007                                             pc + 1);\r
2008                         }\r
2009                         stack[stackTop] = ScriptRuntime.newObject(cx, lhs, \r
2010                                                                   outArgs, \r
2011                                                                   scope);\r
2012                         pc += 4;                                                                         instructionCount = cx.instructionCount;\r
2013                         break;\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
2018                         break;\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
2023                         pc += 2;\r
2024                         break;\r
2025                     case TokenStream.STRING :\r
2026                         stack[++stackTop] = getString(theData.itsStringTable,\r
2027                                                                 iCode, pc + 1);\r
2028                         pc += 2;\r
2029                         break;\r
2030                     case TokenStream.NUMBER :\r
2031                         ++stackTop;\r
2032                         stack[stackTop] = DBL_MRK;\r
2033                         sDbl[stackTop] = getNumber(theData.itsNumberTable,\r
2034                                                    iCode, pc + 1);\r
2035                         pc += 2;\r
2036                         break;\r
2037                     case TokenStream.NAME :\r
2038                         stack[++stackTop] = ScriptRuntime.name(scope,\r
2039                                        getString(theData.itsStringTable,\r
2040                                                                 iCode, pc + 1));\r
2041                         pc += 2;\r
2042                         break;\r
2043                     case TokenStream.NAMEINC :\r
2044                         stack[++stackTop] = ScriptRuntime.postIncrement(scope,\r
2045                                        getString(theData.itsStringTable,\r
2046                                                                 iCode, pc + 1));\r
2047                         pc += 2;\r
2048                         break;\r
2049                     case TokenStream.NAMEDEC :\r
2050                         stack[++stackTop] = ScriptRuntime.postDecrement(scope,\r
2051                                        getString(theData.itsStringTable,\r
2052                                                                 iCode, pc + 1));\r
2053                         pc += 2;\r
2054                         break;\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
2059                         break;\r
2060                     case TokenStream.GETVAR :\r
2061                         slot = (iCode[++pc] & 0xFF);\r
2062                         ++stackTop;\r
2063                         stack[stackTop] = stack[VAR_SHFT + slot];\r
2064                         sDbl[stackTop] = sDbl[VAR_SHFT + slot];\r
2065                         break;\r
2066                     case TokenStream.VARINC :\r
2067                         slot = (iCode[++pc] & 0xFF);\r
2068                         ++stackTop;\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
2074                         break;\r
2075                     case TokenStream.VARDEC :\r
2076                         slot = (iCode[++pc] & 0xFF);\r
2077                         ++stackTop;\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
2083                         break;\r
2084                     case TokenStream.ZERO :\r
2085                         ++stackTop;\r
2086                         stack[stackTop] = DBL_MRK;\r
2087                         sDbl[stackTop] = 0;\r
2088                         break;\r
2089                     case TokenStream.ONE :\r
2090                         ++stackTop;\r
2091                         stack[stackTop] = DBL_MRK;\r
2092                         sDbl[stackTop] = 1;\r
2093                         break;\r
2094                     case TokenStream.NULL :\r
2095                         stack[++stackTop] = null;\r
2096                         break;\r
2097                     case TokenStream.THIS :\r
2098                         stack[++stackTop] = thisObj;\r
2099                         break;\r
2100                     case TokenStream.THISFN :\r
2101                         stack[++stackTop] = fnOrScript;\r
2102                         break;\r
2103                     case TokenStream.FALSE :\r
2104                         stack[++stackTop] = Boolean.FALSE;\r
2105                         break;\r
2106                     case TokenStream.TRUE :\r
2107                         stack[++stackTop] = Boolean.TRUE;\r
2108                         break;\r
2109                     case TokenStream.UNDEFINED :\r
2110                         stack[++stackTop] = Undefined.instance;\r
2111                         break;\r
2112                     case TokenStream.THROW :\r
2113                         result = stack[stackTop];\r
2114                         if (result == DBL_MRK) \r
2115                             result = doubleWrap(sDbl[stackTop]);\r
2116                         --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
2121                         --stackTop;\r
2122                         if (result instanceof JavaScriptException)\r
2123                             throw (JavaScriptException)result;\r
2124                         else\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
2129                         --stackTop;\r
2130                         scope = ScriptRuntime.enterWith(lhs, scope);\r
2131                         break;\r
2132                     case TokenStream.LEAVEWITH :\r
2133                         scope = ScriptRuntime.leaveWith(scope);\r
2134                         break;\r
2135                     case TokenStream.NEWSCOPE :\r
2136                         stack[++stackTop] = ScriptRuntime.newScope();\r
2137                         break;\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
2142                         --stackTop;\r
2143                         stack[LOCAL_SHFT + slot] \r
2144                             = ScriptRuntime.initEnum(lhs, scope);\r
2145                         break;\r
2146                     case TokenStream.ENUMNEXT :\r
2147                         slot = (iCode[++pc] & 0xFF);\r
2148                         val = stack[LOCAL_SHFT + slot];    \r
2149                         ++stackTop;\r
2150                         stack[stackTop] = ScriptRuntime.\r
2151                             nextEnum((Enumeration)val);\r
2152                         break;\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
2157                         break;\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
2162                         break;\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
2167                         break;\r
2168                     case TokenStream.SETPROTO :\r
2169                         rhs = stack[stackTop];    \r
2170                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
2171                         --stackTop;\r
2172                         lhs = stack[stackTop];    \r
2173                         if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
2174                         stack[stackTop]\r
2175                                 = ScriptRuntime.setProto(lhs, rhs, scope);\r
2176                         break;\r
2177                     case TokenStream.SETPARENT :\r
2178                         rhs = stack[stackTop];    \r
2179                         if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
2180                         --stackTop;\r
2181                         lhs = stack[stackTop];    \r
2182                         if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
2183                         stack[stackTop]\r
2184                                 = ScriptRuntime.setParent(lhs, rhs, scope);\r
2185                         break;\r
2186                     case TokenStream.SCOPE :\r
2187                         stack[++stackTop] = scope;\r
2188                         break;\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
2194                                     scope, cx);\r
2195                         createFunctionObject(\r
2196                               (InterpretedFunction)stack[stackTop], scope);\r
2197                         pc += 2;\r
2198                         break;\r
2199                     case TokenStream.OBJECT :\r
2200                         i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);                    \r
2201                         stack[++stackTop] = theData.itsRegExpLiterals[i];\r
2202                         pc += 2;\r
2203                         break;\r
2204                     case TokenStream.SOURCEFILE :    \r
2205                         cx.interpreterSourceFile = theData.itsSourceFile;\r
2206                         break;\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
2215                         {\r
2216                             cx.getDebuggableEngine().\r
2217                                 getDebugger().handleBreakpointHit(cx);\r
2218                         }\r
2219                         pc += 2;\r
2220                         break;\r
2221                     default :\r
2222                         dumpICode(theData);\r
2223                         throw new RuntimeException("Unknown icode : "\r
2224                                      + (iCode[pc] & 0xff) + " @ pc : " + pc);\r
2225                 }\r
2226                 pc++;\r
2227             }\r
2228             catch (Throwable ex) {\r
2229                 cx.interpreterSecurityDomain = null;\r
2230             \r
2231                 if (instructionThreshold != 0) {\r
2232                     if (instructionCount < 0) {\r
2233                         // throw during function call\r
2234                         instructionCount = cx.instructionCount;\r
2235                     }\r
2236                     else {\r
2237                         // throw during any other operation\r
2238                         instructionCount += pc - pcPrevBranch;\r
2239                         cx.instructionCount = instructionCount;\r
2240                     }\r
2241                 }\r
2242 \r
2243                 final int SCRIPT_THROW = 0, ECMA = 1, RUNTIME = 2, OTHER = 3;\r
2244 \r
2245                 int exType;\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
2251                 }\r
2252                 else if (ex instanceof EcmaError) {\r
2253                     // an offical ECMA error object,\r
2254                     errObj = ((EcmaError)ex).getErrorObject();\r
2255                     exType = ECMA;\r
2256                 }\r
2257                 else if (ex instanceof RuntimeException) {\r
2258                     errObj = ex;\r
2259                     exType = RUNTIME;\r
2260                 }\r
2261                 else {\r
2262                     errObj = ex; // Error instance\r
2263                     exType = OTHER;\r
2264                 }\r
2265 \r
2266                 if (exType != OTHER && cx.debugger != null) {\r
2267                     cx.debugger.handleExceptionThrown(cx, errObj);\r
2268                 }\r
2269 \r
2270                 boolean rethrow = true;\r
2271                 if (exType != OTHER && tryStackTop > 0) {\r
2272                     --tryStackTop;\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
2277                         if (pc != 0) {\r
2278                             // Has catch block\r
2279                             rethrow = false;\r
2280                         }\r
2281                     }\r
2282                     if (rethrow) {\r
2283                         pc = catchStack[tryStackTop * 2 + 1];\r
2284                         if (pc != 0) {\r
2285                             // has finally block\r
2286                             rethrow = false;\r
2287                             errObj = ex;\r
2288                         }\r
2289                     }\r
2290                 }\r
2291 \r
2292                 if (rethrow) {\r
2293                     if (frame != null)\r
2294                         cx.popFrame();\r
2295                     \r
2296                     if (exType == SCRIPT_THROW)\r
2297                         throw (JavaScriptException)ex;\r
2298                     if (exType == ECMA || exType == RUNTIME) \r
2299                         throw (RuntimeException)ex;\r
2300                     throw (Error)ex;\r
2301                 }\r
2302             \r
2303                 // We caught an exception,\r
2304 \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
2312                     }\r
2313                 }\r
2314                 pcPrevBranch = pc;\r
2315 \r
2316                 // prepare stack and restore this function's security domain.\r
2317                 scope = (Scriptable)stack[TRY_SCOPE_SHFT + tryStackTop];\r
2318                 stackTop = 0;\r
2319                 stack[0] = errObj;\r
2320                 cx.interpreterSecurityDomain = theData.securityDomain;\r
2321             }\r
2322         }\r
2323         cx.interpreterSecurityDomain = savedSecurityDomain;\r
2324         if (frame != null)\r
2325             cx.popFrame();\r
2326 \r
2327         if (instructionThreshold != 0) {\r
2328             if (instructionCount > instructionThreshold) {\r
2329                 cx.observeInstructionCount(instructionCount);\r
2330                 instructionCount = 0;\r
2331             }\r
2332             cx.instructionCount = instructionCount;\r
2333         }\r
2334 \r
2335         return result;    \r
2336     }\r
2337     \r
2338     private static Object doubleWrap(double x) {\r
2339         return new Double(x);\r
2340     }\r
2341 \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
2347     }\r
2348     \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
2354     }\r
2355     \r
2356     private static double stack_double(Object[] stack, double[] stackDbl, \r
2357                                        int i) \r
2358     {\r
2359         Object x = stack[i];\r
2360         return (x != DBL_MRK) ? ScriptRuntime.toNumber(x) : stackDbl[i];\r
2361     }\r
2362     \r
2363     private static void do_add(Object[] stack, double[] stackDbl, int stackTop)\r
2364     {\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
2371             }\r
2372             else {\r
2373                 do_add(lhs, rDbl, stack, stackDbl, stackTop, true);\r
2374             }\r
2375         }\r
2376         else if (lhs == DBL_MRK) {\r
2377             do_add(rhs, stackDbl[stackTop], stack, stackDbl, stackTop, false);\r
2378         }\r
2379         else {\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
2387             }\r
2388             else {\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
2395             }\r
2396         }\r
2397     }\r
2398     \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
2404     {\r
2405         if (lhs instanceof Scriptable) {\r
2406             if (lhs == Undefined.instance) { lhs = ScriptRuntime.NaNobj; }\r
2407             lhs = ((Scriptable)lhs).getDefaultValue(null);\r
2408         }\r
2409         if (lhs instanceof String) {\r
2410             if (left_right_order) {\r
2411                 stack[stackTop] = (String)lhs + ScriptRuntime.toString(rDbl);\r
2412             }\r
2413             else {\r
2414                 stack[stackTop] = ScriptRuntime.toString(rDbl) + (String)lhs;\r
2415             }\r
2416         }\r
2417         else {\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
2422         }\r
2423     }\r
2424 \r
2425 \r
2426     \r
2427     private static boolean do_eq(Object[] stack, double[] stackDbl,\r
2428                                  int stackTop)\r
2429     {\r
2430         boolean result;\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
2436             }\r
2437             else {\r
2438                 result = do_eq(stackDbl[stackTop + 1], lhs);\r
2439             }\r
2440         }\r
2441         else {\r
2442             if (lhs == DBL_MRK) {\r
2443                 result = do_eq(stackDbl[stackTop], rhs);\r
2444             }\r
2445             else {\r
2446                 result = ScriptRuntime.eq(lhs, rhs);\r
2447             }\r
2448         }\r
2449         return result;\r
2450     }\r
2451     \r
2452 // Optimized version of ScriptRuntime.eq if x is a Number    \r
2453     private static boolean do_eq(double x, Object y) {\r
2454         for (;;) {\r
2455             if (y instanceof Number) {\r
2456                 return x == ((Number) y).doubleValue();\r
2457             }\r
2458             if (y instanceof String) {\r
2459                 return x == ScriptRuntime.toNumber((String)y);\r
2460             }\r
2461             if (y instanceof Boolean) {\r
2462                 return x == (((Boolean)y).booleanValue() ? 1 : 0);\r
2463             }\r
2464             if (y instanceof Scriptable) {\r
2465                 if (y == Undefined.instance) { return false; }\r
2466                 y = ScriptRuntime.toPrimitive(y);\r
2467                 continue;\r
2468             }\r
2469             return false;\r
2470         }\r
2471     }\r
2472 \r
2473     private static boolean do_sheq(Object[] stack, double[] stackDbl,\r
2474                                    int stackTop)\r
2475     {\r
2476         boolean result;\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
2483             }\r
2484             else {\r
2485                 result = (lhs instanceof Number);\r
2486                 if (result) {\r
2487                     result = (((Number)lhs).doubleValue() == rDbl);\r
2488                 }\r
2489             }\r
2490         }\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
2495             }\r
2496             else {\r
2497                 result = (lhs instanceof Number);\r
2498                 if (result) {\r
2499                     result = (((Number)lhs).doubleValue() == rDbl);\r
2500                 }\r
2501             }\r
2502         }\r
2503         else {\r
2504             result = ScriptRuntime.shallowEq(lhs, rhs);\r
2505         }\r
2506         return result;\r
2507     }\r
2508     \r
2509     private int version;\r
2510     private boolean inLineStepMode;\r
2511     private StringBuffer debugSource;\r
2512 \r
2513     private static final Object DBL_MRK = new Object();\r
2514 }\r