~ubuntu-branches/ubuntu/karmic/rhino/karmic

« back to all changes in this revision

Viewing changes to src/org/mozilla/javascript/Interpreter.java

  • Committer: Bazaar Package Importer
  • Author(s): Jerry Haltom
  • Date: 2005-03-19 16:56:07 UTC
  • mto: (11.1.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20050319165607-geu3j3fnqlkpqkh1
Tags: upstream-1.6.R1
ImportĀ upstreamĀ versionĀ 1.6.R1

Show diffs side-by-side

added added

removed removed

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