/*
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/NPL/

 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.

 * The Original Code is Rhino code, released
 * May 6, 1999.

 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
 * Rights Reserved.

 * Contributor(s): 

 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
 * provisions of the GPL are applicable instead of those above.
 * If you wish to allow use of your version of this file only
 * under the terms of the GPL and not to allow others to use your
 * version of this file under the NPL, indicate your decision by
 * deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL.  If you do not delete
 * the provisions above, a recipient may use your version of this
 * file under either the NPL or the GPL.
 */
/* Header file */
#include <stdio.h>
#include <math.h>
#include "js-context.h"
#include "js-frame.h"
#include "js-nodetransformer.h"
#include "js-regexpproxy.h"
#include "js-scriptruntime.h"
#include "js-functionnode.h"
#include "js-ecmaerror.h"
#include "js-javascriptexception.h"
#include "js-runtimeexception.h"
#include "js-exceptionhandler.h"
#include "js-utils.h"
#include "js-interpreter.h"
#if 0
#include "ewb-sys.h"
#include "ewb-sys-if.h"
#endif

#ifdef MEASURMENT
int JSInterpreter::countiCode[148];
#endif
#ifndef SHELL   /* '03.06.27 by S.Takaoka */
#if 0
#include "ewb-dbg.h"
#else
#include "js-dbg.h"
#endif
#endif

int ewbJsDebugDetails = 0;  //ichino 20040820 debug


/* Procedures */
jsString_t JSInterpreter::getString(jsString_t * theStringTable, int8_t * iCode, int pc)
{
    int index = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);
    return theStringTable[index];
}
double JSInterpreter::getNumber(double *theNumberTable, int8_t * iCode, int pc)
{
    int index = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);
    return theNumberTable[index];
}
int JSInterpreter::getTarget(int8_t * iCode, int pc)
{
    int displacement = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);
    return pc - 1 + displacement;
}

void JSInterpreter::dumpICode(JSContext * cx, JSInterpreterData * theData)
{
    if (printICode) {
        JSException *ex;

        if ((ex = enterTry(cx)) == NULL) {
            int8_t *iCode = theData->itsICode;
            int iCodeLength = theData->itsICodeTop;
            jsString_t itsName = theData->itsName ? theData->itsName : (jsString_t) "";

            printf("ICode dump, for %s, length = %d\n", itsName, iCodeLength);
            printf("MaxStack = %d\n", theData->itsMaxStack);

            for (int pc = 0; pc < iCodeLength;) {
                printf("[%d] ", pc);

                switch ((int)(iCode[pc] & 0xff)) {
                case JSTokenStream::SCOPE:
                case JSTokenStream::GETPROTO:
                case JSTokenStream::GETPARENT:
                case JSTokenStream::GETSCOPEPARENT:
                case JSTokenStream::SETPROTO:
                case JSTokenStream::SETPARENT:
                case JSTokenStream::DELPROP:
                case JSTokenStream::TYPEOF:
                case JSTokenStream::NEWSCOPE:
                case JSTokenStream::ENTERWITH:
                case JSTokenStream::LEAVEWITH:
                case JSTokenStream::ENDTRY:
                case JSTokenStream::THROW:
                case JSTokenStream::JTHROW:
                case JSTokenStream::GETTHIS:
                case JSTokenStream::SETELEM:
                case JSTokenStream::GETELEM:
                case JSTokenStream::SETPROP:
                case JSTokenStream::GETPROP:
                case JSTokenStream::PROPINC:
                case JSTokenStream::PROPDEC:
                case JSTokenStream::ELEMINC:
                case JSTokenStream::ELEMDEC:
                case JSTokenStream::BITNOT:
                case JSTokenStream::BITAND:
                case JSTokenStream::BITOR:
                case JSTokenStream::BITXOR:
                case JSTokenStream::LSH:
                case JSTokenStream::RSH:
                case JSTokenStream::URSH:
                case JSTokenStream::NEG:
                case JSTokenStream::POS:
                case JSTokenStream::SUB:
                case JSTokenStream::MUL:
                case JSTokenStream::DIV:
                case JSTokenStream::MOD:
                case JSTokenStream::ADD:
                case JSTokenStream::POPV:
                case JSTokenStream::POP:
                case JSTokenStream::DUP:
                case JSTokenStream::LT:
                case JSTokenStream::GT:
                case JSTokenStream::LE:
                case JSTokenStream::GE:
                case JSTokenStream::IN:
                case JSTokenStream::INSTANCEOF:
                case JSTokenStream::EQ:
                case JSTokenStream::NE:
                case JSTokenStream::SHEQ:
                case JSTokenStream::SHNE:
#ifdef VX
                case JSTokenStream::_ZERO:
#else
                case JSTokenStream::ZERO:
#endif
                case JSTokenStream::ONE:
                case JSTokenStream::_NULL:
                case JSTokenStream::THIS:
                case JSTokenStream::_FALSE:
                case JSTokenStream::_TRUE:
                case JSTokenStream::UNDEFINED:
                case JSTokenStream::SOURCEFILE:
                    printf("%s\n", JSTokenStream::tokenToName(iCode[pc] & 0xff));
                    break;
                case JSTokenStream::GOSUB:
                case JSTokenStream::RETURN:
                case JSTokenStream::GOTO:
                case JSTokenStream::IFEQ:
                case JSTokenStream::IFNE:{
                        int newPC = getTarget(iCode, pc + 1);

                        printf("%s %d\n", JSTokenStream::tokenToName(iCode[pc] & 0xff), newPC);
                        pc += 2;
                        break;
                    }
                case JSTokenStream::TRY:{
                        int newPC1 = getTarget(iCode, pc + 1);
                        int newPC2 = getTarget(iCode, pc + 3);

                        printf("%s %d %d\n", JSTokenStream::tokenToName(iCode[pc] & 0xff), newPC1, newPC2);
                        pc += 4;
                        break;
                    }
                case JSTokenStream::RETSUB:
                case JSTokenStream::ENUMINIT:
                case JSTokenStream::ENUMNEXT:
                case JSTokenStream::ENUMDONE:
                case JSTokenStream::VARINC:
                case JSTokenStream::VARDEC:
                case JSTokenStream::GETVAR:
                case JSTokenStream::SETVAR:
#ifdef REUSE_LOCAL
                case JSTokenStream::DELTEMP:
#endif
                case JSTokenStream::NEWTEMP:
                case JSTokenStream::USETEMP:{
                        int slot = (iCode[pc + 1] & 0xFF);

                        printf("%s %d\n", JSTokenStream::tokenToName(iCode[pc] & 0xff), slot);
                        pc++;
                        break;
                    }

                case JSTokenStream::CALLSPECIAL:{
                        int line = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
                        jsString_t name = getString(theData->itsStringTable, iCode, pc + 3);
                        int count = (iCode[pc + 5] << 8) | (iCode[pc + 6] & 0xFF);
                        printf("%s %d %d %s\n", JSTokenStream::tokenToName(iCode[pc] & 0xff), count, line, name);
                        pc += 6;
                        break;
                    }

                case JSTokenStream::OBJECT:
                case JSTokenStream::CLOSURE:
                case JSTokenStream::NEW:
                case JSTokenStream::CALL:{
                        int count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);

                        printf("%s %d \"%s\"\n", JSTokenStream::tokenToName(iCode[pc] & 0xff), count, getString(theData->itsStringTable, iCode, pc + 1));

                        pc += 4;
                        break;
                    }

                case JSTokenStream::NUMBER:
                    printf("%s %f\n", JSTokenStream::tokenToName(iCode[pc] & 0xff), getNumber(theData->itsNumberTable, iCode, pc + 1));
                    pc += 2;
                    break;

                case JSTokenStream::TYPEOFNAME:
                case JSTokenStream::GETBASE:
                case JSTokenStream::BINDNAME:
                case JSTokenStream::SETNAME:
                case JSTokenStream::NAME:
                case JSTokenStream::NAMEINC:
                case JSTokenStream::NAMEDEC:
                case JSTokenStream::STRING:
                    printf("%s \"%s\"\n", JSTokenStream::tokenToName(iCode[pc] & 0xff), getString(theData->itsStringTable, iCode, pc + 1));
                    pc += 2;
                    break;

                case JSTokenStream::LINE:{
                        int line = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
                        printf("%s : %d\n", JSTokenStream::tokenToName(iCode[pc] & 0xff), line);
                        pc += 2;
                        break;
                    }

                default:
                    jsChar_t message[64];

                    sprintf(message, "Unknown icode : %d @ pc : %d\n", iCode[pc], pc);
                    cx->exceptionHandler->throwEx(new(cx) JSRuntimeException(message));
                }
                pc++;
            }
            cx->exceptionHandler->exitTry();
        }
    }
}
void JSInterpreter::createFunctionObject(JSContext * cx, JSInterpretedFunction * fn, JSScriptable * scope)
{
    fn->setPrototype(cx, JSScriptableObject::getClassPrototype(cx, scope, "Function"));
    fn->setParentScope(cx, scope);

    JSInterpreterData *id = fn->itsData;

    if (strlen(id->itsName) == 0) {
        return;
    }
    if ((id->itsFunctionType == JSFunctionNode::FUNCTION_STATEMENT && fn->itsClosure == NULL) || (id->itsFunctionType == JSFunctionNode::FUNCTION_EXPRESSION_STATEMENT && fn->itsClosure != NULL)) {
        JSScriptRuntime::setProp(cx, JS_OBJECT_TO_VAL(scope), fn->itsData->itsName, JS_OBJECT_TO_VAL(fn), scope);
    }
}

#ifdef TEMPVAL
jsVal_t JSInterpreter::normalizeVal(JSContext * cx, JSFrame * frame, jsVal_t val)
{
    if (JS_VAL_IS_DOUBLE(val)) {
        JSInterpreterData *theData = frame->theData;
        double *dp = JS_VAL_TO_DOUBLE(val);

        if ((dp >= frame->stackTemp)
                && (dp < frame->stackTemp + theData->itsMaxStack)) {
            return JSScriptRuntime::toValue(cx, *dp);
        }
    }
    return val;
}
void JSInterpreter::storeToStack(JSFrame * frame, int index, double d)
{
    double *dp = frame->stackTemp + index;

    *dp = d;
    frame->stack[index] = JS_DOUBLE_TO_VAL(dp);
}
void JSInterpreter::storeToStack(JSFrame * frame, int index, jsVal_t val)
{
    if (JS_VAL_IS_DOUBLE(val)) {
        JSInterpreterData *theData = frame->theData;
        double *dp = JS_VAL_TO_DOUBLE(val);

        if ((dp >= frame->stackTemp)
                && (dp < frame->stackTemp + theData->itsMaxStack)) {
            storeToStack(frame, index, *dp);
            return;
        }
    }
    frame->stack[index] = val;
}
void JSInterpreter::storeToLocal(JSFrame * frame, int index, jsVal_t val)
{
    if (JS_VAL_IS_DOUBLE(val)) {
        JSInterpreterData *theData = frame->theData;
        double *dp = JS_VAL_TO_DOUBLE(val);

        if ((dp >= frame->stackTemp)
                && (dp < frame->stackTemp + theData->itsMaxStack)) {
            double *ldp = frame->localTemp + index;

            *ldp = *dp;
            frame->local[index] = JS_DOUBLE_TO_VAL(ldp);
            return;
        }
    }
    frame->local[index] = val;
}
void JSInterpreter::storeToVars(JSFrame * frame, int index, double d)
{
    double *dp = frame->varsTemp + index;

    *dp = d;
    frame->vars[index] = JS_DOUBLE_TO_VAL(dp);
}
void JSInterpreter::storeToVars(JSFrame * frame, int index, jsVal_t val)
{
    if (JS_VAL_IS_DOUBLE(val)) {
        JSInterpreterData *theData = frame->theData;
        double *dp = JS_VAL_TO_DOUBLE(val);

        if ((dp >= frame->stackTemp)
                && (dp < frame->stackTemp + theData->itsMaxStack)) {
            storeToVars(frame, index, *dp);
            return;
        }
    }
    frame->vars[index] = val;
}
void JSInterpreter::loadFromLocal(JSFrame * frame, int stackIndex, int index)
{
    jsVal_t val = frame->local[index];

    if (JS_VAL_IS_DOUBLE(val)) {
        JSInterpreterData *theData = frame->theData;
        double *dp = JS_VAL_TO_DOUBLE(val);

        if ((dp >= frame->localTemp)
                && (dp < frame->localTemp + theData->itsMaxLocals)) {
            double *sdp = frame->stackTemp + stackIndex;

            *sdp = *dp;
            frame->stack[stackIndex] = JS_DOUBLE_TO_VAL(sdp);
            return;
        }
    }
    frame->stack[stackIndex] = val;
}
void JSInterpreter::loadFromVars(JSFrame * frame, int stackIndex, int index)
{
    jsVal_t val = frame->vars[index];

    if (JS_VAL_IS_DOUBLE(val)) {
        JSInterpreterData *theData = frame->theData;
        double *dp = JS_VAL_TO_DOUBLE(val);

        if ((dp >= frame->varsTemp)
                && (dp < frame->varsTemp + theData->itsVariableTable->size())) {
            double *sdp = frame->stackTemp + stackIndex;

            *sdp = *dp;
            frame->stack[stackIndex] = JS_DOUBLE_TO_VAL(sdp);
            return;
        }
    }
    frame->stack[stackIndex] = val;
}
#endif /* TEMPVAL */
#ifdef BRANCH
void JSInterpreter::checkBranch(JSContext * cx, int displacement)
{
    if (displacement <= 0 && cx->branch != NULL) {
        if (!(*cx->branch) ((jsContext_t) cx, (jsScript_t) ((JSNativeScript *) cx->currentScript))) {
            cx->exceptionHandler->throwEx(new(cx) JSRuntimeException("branch"));
        }
    }
}
#endif /* BRANCH */

void JSInterpreter::generateICodeFromTree(JSContext * cx, JSNode * tree, JSVariableTable * varTable, jsBool_t needsActivation)
{
    int theICodeTop = 0;

    itsData->itsVariableTable = varTable;
    itsData->itsNeedsActivation = needsActivation;
    // add next line by Y.Tanaka
    theICodeTop = addByte(cx, (int8_t) JSTokenStream::SOURCEFILE, theICodeTop);

    theICodeTop = generateICode(cx, tree, theICodeTop);
    itsData->itsICodeTop = theICodeTop;
    if (itsEpilogLabel != -1) {
        markLabel(cx, itsEpilogLabel, theICodeTop);
    }
    for (int i = 0; i < itsLabelTableTop; i++) {
        itsLabelTable[i]->fixGotos(cx, itsData->itsICode);
    }
}
jsVal_t *JSInterpreter::generateRegExpLiterals(JSContext * cx, JSScriptable * scope, JSNode::Vector * regexps, int *regExpsLength)
{
    int size = regexps->size();
    JSRegExpProxy *rep = cx->getRegExpProxy();

    for (int i = 0; i < size; i++) {
        JSNode *regexp = regexps->elementAt(i);
        JSNode *left = regexp->getFirstChild();
        JSNode *right = regexp->getLastChild();

        cx->pushLocalVal(rep->newRegExp(cx, scope, left->getString(), (left != right) ? right->getString()
                        : NULL, FALSE));
        regexp->putProp(cx, JSNode::REGEXP_PROP, i);
    }
    *regExpsLength = size;

    return cx->getLocalVals(size);
}

JSInterpretedScript *JSInterpreter::generateScriptICode(JSContext * cx, JSScriptable * scope, JSNode * tree)
{
    jsBool_t ok;

    (void)tree->getProp(JSNode::SOURCENAME_PROP, &itsSourceFile);
    ok = tree->getProp(JSNode::FUNCTION_PROP, &itsFunctionList);
    if (ok) {
        generateNestedFunctions(scope, cx);
    }
    int regExpLiteralsLength = 0;
    jsVal_t *regExpLiterals = NULL;
    JSNode::Vector * regexps;

    ok = tree->getProp(JSNode::REGEXP_PROP, &regexps);
    if (ok) {
        regExpLiterals = generateRegExpLiterals(cx, scope, regexps, &regExpLiteralsLength);
    }
    JSVariableTable *varTable;

    (void)tree->getProp(JSNode::VARS_PROP, &varTable);
    // add next statement by Y.Tanaka
    if (itsSourceFile != NULL) {
        itsData->itsSourceFile = JS_NewGCString(cx, itsSourceFile);
    }
    generateICodeFromTree(cx, tree, varTable, FALSE);
    itsData->itsNestedFunctionsLength = itsNestedFunctionsLength;
    itsData->itsNestedFunctions = itsNestedFunctions;
    if (regExpLiteralsLength != 0) {
        itsData->itsRegExpLiteralsLength = regExpLiteralsLength;
        itsData->itsRegExpLiterals = (jsVal_t *) JS_NewGCObj(cx, sizeof(*itsData->itsRegExpLiterals)
                * regExpLiteralsLength);
        memcpy(itsData->itsRegExpLiterals, regExpLiterals, sizeof(*regExpLiterals) * regExpLiteralsLength);
        cx->popLocalVals(regExpLiteralsLength);
    }
    if (printICode)
        dumpICode(cx, itsData);
    JSInterpretedScript *script = new(cx) JSInterpretedScript(itsData, cx);

    return script;
}

void JSInterpreter::generateNestedFunctions(JSScriptable * scope, JSContext * cx)
{
    int size = itsFunctionList->size();

    itsNestedFunctions = (JSInterpretedFunction **) JS_NewGCObj(cx, sizeof(*itsNestedFunctions) * size);
    itsNestedFunctionsLength = size;
    memset(itsNestedFunctions, 0, sizeof(*itsNestedFunctions) * size);
    for (short i = 0; i < size; i++) {
        JSFunctionNode *def = (JSFunctionNode *) itsFunctionList->elementAt(i);
        JSInterpreter *jsi = new(cx) JSInterpreter();

        cx->addInterpreter(jsi);

        jsi->itsSourceFile = itsSourceFile;
        jsi->itsData = new(cx) JSInterpreterData(cx, 0, 0, 0, cx->hasCompileFunctionsWithDynamicScope());
        jsi->itsData->itsFunctionType = def->getFunctionType();
        jsi->itsInFunctionFlag = TRUE;
        itsNestedFunctions[i] = jsi->generateFunctionICode(cx, scope, def);
        def->putProp(cx, JSNode::FUNCTION_PROP, i);

#ifdef COMPACT_MEM
        jsi->adjustGCMemory(cx);
#endif
        //printf("JSInterpreter::generateNestedFunctions 0: %d\n", jsi->itsData->itsMaxLocals);
        if (jsi->itsData->itsVariableTable != NULL) {
            cx->delVariableTable(jsi->itsData->itsVariableTable);
        }
        cx->delInterpreter(jsi);
        jsi->destroy(cx);
    }
}
JSInterpretedFunction *JSInterpreter::generateFunctionICode(JSContext * cx, JSScriptable * scope, JSFunctionNode * theFunction)
{
    jsBool_t ok;

    ok = theFunction->getProp(JSNode::FUNCTION_PROP, &itsFunctionList);
    if (ok) {
        generateNestedFunctions(scope, cx);
    }
    int regExpLiteralsLength = 0;
    jsVal_t *regExpLiterals = NULL;
    JSNode::Vector * regexps;

    ok = theFunction->getProp(JSNode::REGEXP_PROP, &regexps);
    if (ok) {
        regExpLiterals = generateRegExpLiterals(cx, scope, regexps, &regExpLiteralsLength);
    }

    JSVariableTable *varTable = theFunction->getVariableTable();

    generateICodeFromTree(cx, theFunction->getLastChild(), varTable, theFunction->requiresActivation());

    jsString_t source;
    int sourceLength;

    itsData->itsName = JS_NewGCString(cx, theFunction->getFunctionName());
    ok = theFunction->getProp(JSNode::SOURCE_PROP, &source, &sourceLength);
    if (ok) {
        itsData->itsSource = (jsString_t) JS_NewGCObj(cx, sizeof(*source) * sourceLength);
        memcpy(itsData->itsSource, source, sizeof(*source) * sourceLength);
        itsData->itsSourceLength = sourceLength;
    }

    itsData->itsNestedFunctionsLength = itsNestedFunctionsLength;
    itsData->itsNestedFunctions = itsNestedFunctions;
    if (regExpLiteralsLength != 0) {
        itsData->itsRegExpLiteralsLength = regExpLiteralsLength;
        itsData->itsRegExpLiterals = (jsVal_t *) JS_NewGCObj(cx, sizeof(*itsData->itsRegExpLiterals)
                * regExpLiteralsLength);
        memcpy(itsData->itsRegExpLiterals, regExpLiterals, sizeof(*regExpLiterals) * regExpLiteralsLength);
        cx->popLocalVals(regExpLiteralsLength);
    }
    if (printICode)
        dumpICode(cx, itsData);
    return new(cx) JSInterpretedFunction(itsData, cx);
}
int JSInterpreter::updateLineNumber(JSContext * cx, JSNode * node, int iCodeTop)
{
    int datum;
    jsBool_t ok = node->getDatum(&datum);

    if (!ok) {
        return iCodeTop;
    }
    short lineNumber = datum;

    if (lineNumber != itsLineNumber) {
        itsLineNumber = lineNumber;
        iCodeTop = addByte(cx, (int8_t) JSTokenStream::LINE, iCodeTop);
        iCodeTop = addByte(cx, (int8_t) (lineNumber >> 8), iCodeTop);
        iCodeTop = addByte(cx, (int8_t) (lineNumber & 0xff), iCodeTop);
    }

    return iCodeTop;
}

void JSInterpreter::badTree(JSContext * cx, JSNode * node)
{
    jsString_t s = node->toString(cx);
    jsString_t string = s != NULL ? s : (jsString_t) "";
    jsString_t message = (jsString_t) JS_NewZoneObj(cx, sizeof(*message) * (strlen(string)
                    + TableSize("Un-handled node.") + 1));

    sprintf(message, "Un-handled node.%s", string);
    cx->exceptionHandler->throwEx(new(cx) JSRuntimeException(message));
}
int JSInterpreter::generateICode(JSContext * cx, JSNode * node, int iCodeTop)
{
    int type = node->getType();
    JSNode *child = node->getFirstChild();
    JSNode *firstChild = child;

    switch (type) {
    case JSTokenStream::FUNCTION:{
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::CLOSURE, iCodeTop);

            JSNode *fn;
            int index;

            (void)node->getProp(JSNode::FUNCTION_PROP, &fn);
            (void)fn->getProp(JSNode::FUNCTION_PROP, &index);
            iCodeTop = addByte(cx, (int8_t) (index >> 8), iCodeTop);
            iCodeTop = addByte(cx, (int8_t) (index & 0xff), iCodeTop);
            itsStackDepth++;
            if (itsStackDepth > itsData->itsMaxStack) {
                itsData->itsMaxStack = itsStackDepth;
            }
            break;
        }

    case JSTokenStream::SCRIPT:
        iCodeTop = updateLineNumber(cx, node, iCodeTop);
        while (child != NULL) {
            if (child->getType() != JSTokenStream::FUNCTION) {
                iCodeTop = generateICode(cx, child, iCodeTop);
            }
            child = child->getNextSibling();
        }
        break;

    case JSTokenStream::CASE:
        iCodeTop = updateLineNumber(cx, node, iCodeTop);
        child = child->getNextSibling();
        while (child != NULL) {
            iCodeTop = generateICode(cx, child, iCodeTop);
            child = child->getNextSibling();
        }
        break;

    case JSTokenStream::LABEL:
    case JSTokenStream::WITH:
    case JSTokenStream::LOOP:
    case JSTokenStream::DEFAULT:
    case JSTokenStream::BLOCK:
#if defined(TARGET_OS_LINUX)
    case JSTokenStream::VOIDX:
#else
    case JSTokenStream::VOID:
#endif
    case JSTokenStream::NOP:
        iCodeTop = updateLineNumber(cx, node, iCodeTop);
        while (child != NULL) {
            iCodeTop = generateICode(cx, child, iCodeTop);
            child = child->getNextSibling();
        }
        break;

    case JSTokenStream::COMMA:
        iCodeTop = generateICode(cx, child, iCodeTop);
        iCodeTop = addByte(cx, (int8_t) JSTokenStream::POP, iCodeTop);
        itsStackDepth--;
        child = child->getNextSibling();
        iCodeTop = generateICode(cx, child, iCodeTop);
        break;

    case JSTokenStream::SWITCH:{
            iCodeTop = updateLineNumber(cx, node, iCodeTop);
            iCodeTop = generateICode(cx, child, iCodeTop);
#ifdef REUSE_LOCAL
            int theLocalSlot = itsData->itsLocalTop++;

            if (itsData->itsLocalTop > itsData->itsMaxLocals) {
                itsData->itsMaxLocals = itsData->itsLocalTop;
            }
#else
            int theLocalSlot = itsData->itsMaxLocals++;
#endif
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::NEWTEMP, iCodeTop);
            iCodeTop = addByte(cx, (int8_t) theLocalSlot, iCodeTop);
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::POP, iCodeTop);
            itsStackDepth--;
            /*
               reminder - below we construct new GOTO nodes that aren't
               linked into the tree just for the purpose of having a node
               to pass to the addGoto routine. (Parallels codegen here).
               Seems unnecessary.   
             */
            JSNode::Vector * cases;

            (void)node->getProp(JSNode::CASES_PROP, &cases);
            int size = cases->size();
            for (int i = 0; i < size; i++) {
                JSNode *thisCase = cases->elementAt(i);
                JSNode *first = thisCase->getFirstChild();

                // the case expression is the firstmost child
                // the rest will be generated when the case
                // statements are encountered as siblings of
                // the switch statement.
                iCodeTop = generateICode(cx, first, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::USETEMP, iCodeTop);
                itsStackDepth++;
                if (itsStackDepth > itsData->itsMaxStack) {
                    itsData->itsMaxStack = itsStackDepth;
                }
                iCodeTop = addByte(cx, (int8_t) theLocalSlot, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::SHEQ, iCodeTop);

                JSNode *target = new(cx) JSNode(JSTokenStream::TARGET);

                thisCase->addChildAfter(target, first);

                JSNode *branch = new(cx) JSNode(JSTokenStream::IFEQ);

                branch->putProp(cx, JSNode::TARGET_PROP, target);
                iCodeTop = addGoto(cx, branch, JSTokenStream::IFEQ, iCodeTop);
                itsStackDepth--;
            }
            JSNode *defaultNode;
            jsBool_t ok;

            ok = node->getProp(JSNode::DEFAULT_PROP, &defaultNode);
            if (ok) {
                JSNode *defaultTarget = new(cx) JSNode(JSTokenStream::TARGET);

                defaultNode->getFirstChild()->addChildToFront(defaultTarget);

                JSNode *branch = new(cx) JSNode(JSTokenStream::GOTO);

                branch->putProp(cx, JSNode::TARGET_PROP, defaultTarget);
                iCodeTop = addGoto(cx, branch, JSTokenStream::GOTO, iCodeTop);
            }
            JSNode *breakTarget;

            (void)node->getProp(JSNode::BREAK_PROP, &breakTarget);

            JSNode *branch = new(cx) JSNode(JSTokenStream::GOTO);

            branch->putProp(cx, JSNode::TARGET_PROP, breakTarget);
            iCodeTop = addGoto(cx, branch, JSTokenStream::GOTO, iCodeTop);
            break;
        }

    case JSTokenStream::TARGET:{
            jsBool_t ok;
            int labelProp;

            ok = node->getProp(JSNode::LABEL_PROP, &labelProp);
            if (!ok) {
                int label = markLabel(cx, acquireLabel(cx), iCodeTop);

                node->putProp(cx, JSNode::LABEL_PROP, label);
            }
            else {
                int label = labelProp;

                markLabel(cx, label, iCodeTop);
            }
            // if this target has a FINALLY_PROP, it is a JSR target
            // and so has a PC value on the top of the stack
            JSNode *finallyTarget;

            if (node->getProp(JSNode::FINALLY_PROP, &finallyTarget)) {
                itsStackDepth = 1;
                if (itsStackDepth > itsData->itsMaxStack) {
                    itsData->itsMaxStack = itsStackDepth;
                }
            }
            break;
        }

    case JSTokenStream::EQOP:
    case JSTokenStream::RELOP:{
            iCodeTop = generateICode(cx, child, iCodeTop);
            child = child->getNextSibling();
            iCodeTop = generateICode(cx, child, iCodeTop);

            int op = node->getInt();

            if (version == JSContext::VERSION_1_2) {
                if (op == JSTokenStream::EQ) {
                    op = JSTokenStream::SHEQ;
                }
                else if (op == JSTokenStream::NE) {
                    op = JSTokenStream::SHNE;
                }
            }
            iCodeTop = addByte(cx, (int8_t) op, iCodeTop);
            itsStackDepth--;
            break;
        }

    case JSTokenStream::NEW:
    case JSTokenStream::CALL:{
            if (itsSourceFile != NULL && (itsData->itsSourceFile == NULL || strcmp(itsSourceFile, itsData->itsSourceFile) != 0)) {
                itsData->itsSourceFile = JS_NewGCString(cx, itsSourceFile);
            }
#ifndef FASTER
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::SOURCEFILE, iCodeTop);
#endif

            int childCount = 0;
            short nameIndex = -1;

            while (child != NULL) {
                iCodeTop = generateICode(cx, child, iCodeTop);
                if (nameIndex == -1) {
                    if (child->getType() == JSTokenStream::NAME) {
                        nameIndex = (short)(itsData->itsStringTableIndex - 1);
                    }
                    else if (child->getType() == JSTokenStream::GETPROP) {
                        nameIndex = (short)(itsData->itsStringTableIndex - 1);
                    }
                }
                child = child->getNextSibling();
                childCount++;
            }
            if (node->getProp(JSNode::SPECIALCALL_PROP)) {
                // embed line number and source filename
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::CALLSPECIAL, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) (itsLineNumber >> 8), iCodeTop);
                iCodeTop = addByte(cx, (int8_t) (itsLineNumber & 0xff), iCodeTop);
                iCodeTop = addString(cx, itsSourceFile, iCodeTop);
            }
            else {
                iCodeTop = addByte(cx, (int8_t) type, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) (nameIndex >> 8), iCodeTop);
                iCodeTop = addByte(cx, (int8_t) (nameIndex & 0xFF), iCodeTop);
            }

            itsStackDepth -= (childCount - 1);  // always a result value
            // subtract from child count to account for [thisObj &] fun
            if (type == JSTokenStream::NEW) {
                childCount -= 1;
            }
            else {
                childCount -= 2;
            }
            iCodeTop = addByte(cx, (int8_t) (childCount >> 8), iCodeTop);
            iCodeTop = addByte(cx, (int8_t) (childCount & 0xff), iCodeTop);
            if (childCount > itsData->itsMaxArgs) {
                itsData->itsMaxArgs = childCount;
            }

            iCodeTop = addByte(cx, (int8_t) JSTokenStream::SOURCEFILE, iCodeTop);
            break;
        }

    case JSTokenStream::NEWLOCAL:
    case JSTokenStream::NEWTEMP:{
            iCodeTop = generateICode(cx, child, iCodeTop);
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::NEWTEMP, iCodeTop);
            iCodeTop = addLocalRef(cx, node, iCodeTop);
            break;
        }

    case JSTokenStream::USELOCAL:{
            int prop;   // the magic prop that makes it output a RET

            if (node->getProp(JSNode::TARGET_PROP, &prop)) {
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::RETSUB, iCodeTop);
            }
            else {
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::USETEMP, iCodeTop);
                itsStackDepth++;
                if (itsStackDepth > itsData->itsMaxStack) {
                    itsData->itsMaxStack = itsStackDepth;
                }
            }
            JSNode *temp;

            (void)node->getProp(JSNode::LOCAL_PROP, &temp);
            iCodeTop = addLocalRef(cx, temp, iCodeTop);
            break;
        }

    case JSTokenStream::USETEMP:{
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::USETEMP, iCodeTop);
            JSNode *temp;
            (void)node->getProp(JSNode::TEMP_PROP, &temp);
            iCodeTop = addLocalRef(cx, temp, iCodeTop);
            itsStackDepth++;
            if (itsStackDepth > itsData->itsMaxStack) {
                itsData->itsMaxStack = itsStackDepth;
            }
            break;
        }
#ifdef REUSE_LOCAL
    case JSTokenStream::DELTEMP:{
            iCodeTop = generateICode(cx, child, iCodeTop);

            JSNode *temp;

            (void)node->getProp(JSNode::TEMP_PROP, &temp);
            delLocalRef(cx, temp);
            break;
        }
#endif

    case JSTokenStream::IFEQ:
    case JSTokenStream::IFNE:
        iCodeTop = generateICode(cx, child, iCodeTop);
        itsStackDepth--;    // after the conditional GOTO, really
        // fall thru...
    case JSTokenStream::GOTO:
        iCodeTop = addGoto(cx, node, (int8_t) type, iCodeTop);
        break;

    case JSTokenStream::JSR:{
            /*
               mark the target with a FINALLY_PROP to indicate
               that it will have an incoming PC value on the top of the stack.
               !!! 
               This only works if the target follows the JSR in the tree.
               !!!
             */
            JSNode *target;

            (void)node->getProp(JSNode::TARGET_PROP, &target);
            target->putProp(cx, JSNode::FINALLY_PROP, node);
            iCodeTop = addGoto(cx, node, JSTokenStream::GOSUB, iCodeTop);
            break;
        }

    case JSTokenStream::AND:{
            iCodeTop = generateICode(cx, child, iCodeTop);
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::DUP, iCodeTop);
            itsStackDepth++;
            if (itsStackDepth > itsData->itsMaxStack) {
                itsData->itsMaxStack = itsStackDepth;
            }
            int falseTarget = acquireLabel(cx);

            iCodeTop = addGoto(cx, falseTarget, JSTokenStream::IFNE, iCodeTop);
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::POP, iCodeTop);
            itsStackDepth--;
            child = child->getNextSibling();
            iCodeTop = generateICode(cx, child, iCodeTop);
            markLabel(cx, falseTarget, iCodeTop);
            break;
        }

    case JSTokenStream::OR:{
            iCodeTop = generateICode(cx, child, iCodeTop);
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::DUP, iCodeTop);
            itsStackDepth++;
            if (itsStackDepth > itsData->itsMaxStack) {
                itsData->itsMaxStack = itsStackDepth;
            }
            int trueTarget = acquireLabel(cx);
            iCodeTop = addGoto(cx, trueTarget, JSTokenStream::IFEQ, iCodeTop);
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::POP, iCodeTop);
            itsStackDepth--;
            child = child->getNextSibling();
            iCodeTop = generateICode(cx, child, iCodeTop);
            markLabel(cx, trueTarget, iCodeTop);

            break;
        }

    case JSTokenStream::GETPROP:{
            iCodeTop = generateICode(cx, child, iCodeTop);

            jsString_t s;
            jsBool_t ok = node->getProp(JSNode::SPECIAL_PROP_PROP, &s);

            if (ok) {
                if (strcmp(s, "__proto__") == 0) {
                    iCodeTop = addByte(cx, (int8_t) JSTokenStream::GETPROTO, iCodeTop);
                }
                else if (strcmp(s, "__parent__") == 0) {
                    iCodeTop = addByte(cx, (int8_t) JSTokenStream::GETSCOPEPARENT, iCodeTop);
                }
                else {
                    badTree(cx, node);
                }
            }
            else {
                child = child->getNextSibling();
                iCodeTop = generateICode(cx, child, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::GETPROP, iCodeTop);
                itsStackDepth--;
            }
            break;
        }

    case JSTokenStream::DELPROP:
    case JSTokenStream::BITAND:
    case JSTokenStream::BITOR:
    case JSTokenStream::BITXOR:
    case JSTokenStream::LSH:
    case JSTokenStream::RSH:
    case JSTokenStream::URSH:
    case JSTokenStream::ADD:
    case JSTokenStream::SUB:
    case JSTokenStream::MOD:
    case JSTokenStream::DIV:
    case JSTokenStream::MUL:
    case JSTokenStream::GETELEM:
        iCodeTop = generateICode(cx, child, iCodeTop);
        child = child->getNextSibling();
        iCodeTop = generateICode(cx, child, iCodeTop);
        iCodeTop = addByte(cx, (int8_t) type, iCodeTop);
        itsStackDepth--;
        break;

    case JSTokenStream::CONVERT:{
            iCodeTop = generateICode(cx, child, iCodeTop);

            double d;
            jsBool_t ok = node->getProp(JSNode::TYPE_PROP, &d);

            if (ok) {
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::POS, iCodeTop);
            }
            else {
                badTree(cx, node);
            }
            break;
        }
    case JSTokenStream::UNARYOP:
        iCodeTop = generateICode(cx, child, iCodeTop);

        switch (node->getInt()) {
#if defined(TARGET_OS_LINUX)
        case JSTokenStream::VOIDX:
#else
        case JSTokenStream::VOID:
#endif
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::POP, iCodeTop);
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::UNDEFINED, iCodeTop);
            break;

        case JSTokenStream::NOT:{
                int trueTarget = acquireLabel(cx);
                int beyond = acquireLabel(cx);

                iCodeTop = addGoto(cx, trueTarget, JSTokenStream::IFEQ, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::_TRUE, iCodeTop);
                iCodeTop = addGoto(cx, beyond, JSTokenStream::GOTO, iCodeTop);
                markLabel(cx, trueTarget, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::_FALSE, iCodeTop);
                markLabel(cx, beyond, iCodeTop);

                break;
            }
        case JSTokenStream::BITNOT:
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::BITNOT, iCodeTop);
            break;
        case JSTokenStream::TYPEOF:
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::TYPEOF, iCodeTop);
            break;
        case JSTokenStream::SUB:
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::NEG, iCodeTop);
            break;
        case JSTokenStream::ADD:
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::POS, iCodeTop);
            break;
        default:
            badTree(cx, node);
            break;
        }
        break;

    case JSTokenStream::SETPROP:{
            iCodeTop = generateICode(cx, child, iCodeTop);
            child = child->getNextSibling();
            iCodeTop = generateICode(cx, child, iCodeTop);

            jsString_t s;
            jsBool_t ok = node->getProp(JSNode::SPECIAL_PROP_PROP, &s);

            if (ok) {
                if (strcmp(s, "__proto__") == 0) {
                    iCodeTop = addByte(cx, (int8_t) JSTokenStream::SETPROTO, iCodeTop);
                }
                else if (strcmp(s, "__parent__") == 0) {
                    iCodeTop = addByte(cx, (int8_t) JSTokenStream::SETPARENT, iCodeTop);
                }
                else {
                    badTree(cx, node);
                }
            }
            else {
                child = child->getNextSibling();
                iCodeTop = generateICode(cx, child, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::SETPROP, iCodeTop);
                itsStackDepth -= 2;
            }
            break;
        }

    case JSTokenStream::SETELEM:
        iCodeTop = generateICode(cx, child, iCodeTop);
        child = child->getNextSibling();
        iCodeTop = generateICode(cx, child, iCodeTop);
        child = child->getNextSibling();
        iCodeTop = generateICode(cx, child, iCodeTop);
        iCodeTop = addByte(cx, (int8_t) type, iCodeTop);
        itsStackDepth -= 2;
        break;

    case JSTokenStream::SETNAME:
        iCodeTop = generateICode(cx, child, iCodeTop);
        child = child->getNextSibling();
        iCodeTop = generateICode(cx, child, iCodeTop);
        iCodeTop = addByte(cx, (int8_t) JSTokenStream::SETNAME, iCodeTop);
        iCodeTop = addString(cx, firstChild->getString(), iCodeTop);
        itsStackDepth--;
        break;

    case JSTokenStream::TYPEOF:{
            jsString_t name = node->getString();
            int index = -1;
            // use typeofname if an activation frame exists
            // since the vars all exist there instead of in jregs
            if (itsInFunctionFlag && !itsData->itsNeedsActivation) {
                index = itsData->itsVariableTable->getOrdinal(name);
            }
            if (index == -1) {
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::TYPEOFNAME, iCodeTop);
                iCodeTop = addString(cx, name, iCodeTop);
            }
            else {
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::GETVAR, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) index, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::TYPEOF, iCodeTop);
            }
            itsStackDepth++;
            if (itsStackDepth > itsData->itsMaxStack) {
                itsData->itsMaxStack = itsStackDepth;
            }
            break;
        }

    case JSTokenStream::PARENT:
        iCodeTop = generateICode(cx, child, iCodeTop);
        iCodeTop = addByte(cx, (int8_t) JSTokenStream::GETPARENT, iCodeTop);
        break;

    case JSTokenStream::GETBASE:
    case JSTokenStream::BINDNAME:
    case JSTokenStream::NAME:
    case JSTokenStream::STRING:
        iCodeTop = addByte(cx, (int8_t) type, iCodeTop);
        iCodeTop = addString(cx, node->getString(), iCodeTop);
        itsStackDepth++;
        if (itsStackDepth > itsData->itsMaxStack) {
            itsData->itsMaxStack = itsStackDepth;
        }
        break;

    case JSTokenStream::INC:
    case JSTokenStream::DEC:{
            int childType = child->getType();

            switch (childType) {
            case JSTokenStream::GETVAR:{
                    jsString_t name = child->getString();

                    if (itsData->itsNeedsActivation) {
                        iCodeTop = addByte(cx, (int8_t) JSTokenStream::SCOPE, iCodeTop);
                        iCodeTop = addByte(cx, (int8_t) JSTokenStream::STRING, iCodeTop);
                        iCodeTop = addString(cx, name, iCodeTop);
                        itsStackDepth += 2;
                        if (itsStackDepth > itsData->itsMaxStack) {
                            itsData->itsMaxStack = itsStackDepth;
                        }
                        iCodeTop = addByte(cx, (int8_t) (type == JSTokenStream::INC ? JSTokenStream::PROPINC : JSTokenStream::PROPDEC), iCodeTop);
                        itsStackDepth--;
                    }
                    else {
                        iCodeTop = addByte(cx, (int8_t) (type == JSTokenStream::INC ? JSTokenStream::VARINC : JSTokenStream::VARDEC), iCodeTop);
                        int i = itsData->itsVariableTable->getOrdinal(name);
                        iCodeTop = addByte(cx, (int8_t) i, iCodeTop);
                        itsStackDepth++;
                        if (itsStackDepth > itsData->itsMaxStack) {
                            itsData->itsMaxStack = itsStackDepth;
                        }
                    }
                    break;
                }
            case JSTokenStream::GETPROP:
            case JSTokenStream::GETELEM:{
                    JSNode *getPropChild = child->getFirstChild();

                    iCodeTop = generateICode(cx, getPropChild, iCodeTop);
                    getPropChild = getPropChild->getNextSibling();
                    iCodeTop = generateICode(cx, getPropChild, iCodeTop);
                    if (childType == JSTokenStream::GETPROP) {
                        iCodeTop = addByte(cx, (int8_t) (type == JSTokenStream::INC ? JSTokenStream::PROPINC : JSTokenStream::PROPDEC), iCodeTop);
                    }
                    else {
                        iCodeTop = addByte(cx, (int8_t) (type == JSTokenStream::INC ? JSTokenStream::ELEMINC : JSTokenStream::ELEMDEC), iCodeTop);
                    }
                    itsStackDepth--;

                    break;
                }
            default:{
                    iCodeTop = addByte(cx, (int8_t) (type == JSTokenStream::INC ? JSTokenStream::NAMEINC : JSTokenStream::NAMEDEC), iCodeTop);
                    iCodeTop = addString(cx, child->getString(), iCodeTop);
                    itsStackDepth++;
                    if (itsStackDepth > itsData->itsMaxStack) {
                        itsData->itsMaxStack = itsStackDepth;
                    }
                    break;
                }
            }
            break;
        }

    case JSTokenStream::NUMBER:{
            double num;

            (void)node->getDatum(&num);
            if (num == 0.0) {
#ifdef VX
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::_ZERO, iCodeTop);
#else
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::ZERO, iCodeTop);
#endif
            }
            else {
                if (num == 1.0) {
                    iCodeTop = addByte(cx, (int8_t) JSTokenStream::ONE, iCodeTop);
                }
                else {
                    iCodeTop = addByte(cx, (int8_t) JSTokenStream::NUMBER, iCodeTop);
                    iCodeTop = addNumber(cx, num, iCodeTop);
                }
            }
        }
        itsStackDepth++;
        if (itsStackDepth > itsData->itsMaxStack) {
            itsData->itsMaxStack = itsStackDepth;
        }
        break;

    case JSTokenStream::POP:
    case JSTokenStream::POPV:
        iCodeTop = updateLineNumber(cx, node, iCodeTop);
    case JSTokenStream::ENTERWITH:
        iCodeTop = generateICode(cx, child, iCodeTop);
        iCodeTop = addByte(cx, (int8_t) type, iCodeTop);
        itsStackDepth--;
        break;

    case JSTokenStream::GETTHIS:
        iCodeTop = generateICode(cx, child, iCodeTop);
        iCodeTop = addByte(cx, (int8_t) type, iCodeTop);
        break;

    case JSTokenStream::NEWSCOPE:
        iCodeTop = addByte(cx, (int8_t) type, iCodeTop);
        itsStackDepth++;
        if (itsStackDepth > itsData->itsMaxStack) {
            itsData->itsMaxStack = itsStackDepth;
        }
        break;

    case JSTokenStream::LEAVEWITH:
        iCodeTop = addByte(cx, (int8_t) type, iCodeTop);
        break;

    case JSTokenStream::TRY:{
            itsTryDepth++;
            if (itsTryDepth > itsData->itsMaxTryDepth) {
                itsData->itsMaxTryDepth = itsTryDepth;
            }
            jsBool_t hasCatchs, hasFinally;
            JSNode *catchTarget, *finallyTarget;

            hasCatchs = node->getProp(JSNode::TARGET_PROP, &catchTarget);
            hasFinally = node->getProp(JSNode::FINALLY_PROP, &finallyTarget);
            if (!hasCatchs) {
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::TRY, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) 0, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) 0, iCodeTop);
            }
            else {
                iCodeTop = addGoto(cx, node, JSTokenStream::TRY, iCodeTop);
            }
            int finallyHandler = 0;

            if (hasFinally) {
                finallyHandler = acquireLabel(cx);
                int theLabel = finallyHandler & 0x7FFFFFFF;
                itsLabelTable[theLabel]->addFixup(cx, iCodeTop);
            }
            iCodeTop = addByte(cx, (int8_t) 0, iCodeTop);
            iCodeTop = addByte(cx, (int8_t) 0, iCodeTop);

            JSNode *lastChild = NULL;
            /*
               when we encounter the child of the catchTarget, we
               set the stackDepth to 1 to account for the incoming
               exception object.
             */
            while (child != NULL) {
                if (lastChild == catchTarget) {
                    itsStackDepth = 1;
                    if (itsStackDepth > itsData->itsMaxStack) {
                        itsData->itsMaxStack = itsStackDepth;
                    }
                }
                /*
                   When the following child is the catchTarget,
                   the current child is the goto at the end of
                   the try statemets, we need to emit the endtry
                   before that goto.
                 */
                if (child->getNextSibling() == catchTarget) {
                    iCodeTop = addByte(cx, (int8_t) JSTokenStream::ENDTRY, iCodeTop);
                }
                iCodeTop = generateICode(cx, child, iCodeTop);
                lastChild = child;
                child = child->getNextSibling();
            }
            itsStackDepth = 0;
            if (hasFinally) {
                // normal flow goes around the finally handler stublet
                int skippy = acquireLabel(cx);
                iCodeTop = addGoto(cx, skippy, JSTokenStream::GOTO, iCodeTop);
                // on entry the stack will have the exception object
                markLabel(cx, finallyHandler, iCodeTop);
                itsStackDepth = 1;
                if (itsStackDepth > itsData->itsMaxStack) {
                    itsData->itsMaxStack = itsStackDepth;
                }
#ifdef REUSE_LOCAL
                int theLocalSlot = itsData->itsLocalTop++;

                if (itsData->itsLocalTop > itsData->itsMaxLocals) {
                    itsData->itsMaxLocals = itsData->itsLocalTop;
                }
#else
                int theLocalSlot = itsData->itsMaxLocals++;
#endif
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::NEWTEMP, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) theLocalSlot, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::POP, iCodeTop);

                int finallyLabel;

                (void)finallyTarget->getProp(JSNode::LABEL_PROP, &finallyLabel);
                iCodeTop = addGoto(cx, finallyLabel, JSTokenStream::GOSUB, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::USETEMP, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) theLocalSlot, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::JTHROW, iCodeTop);
                itsStackDepth = 0;
                markLabel(cx, skippy, iCodeTop);
            }
            itsTryDepth--;

            break;
        }

    case JSTokenStream::THROW:
        iCodeTop = updateLineNumber(cx, node, iCodeTop);
        iCodeTop = generateICode(cx, child, iCodeTop);
        iCodeTop = addByte(cx, (int8_t) JSTokenStream::THROW, iCodeTop);
        itsStackDepth--;
        break;

    case JSTokenStream::RETURN:
        iCodeTop = updateLineNumber(cx, node, iCodeTop);
        if (child != NULL) {
            iCodeTop = generateICode(cx, child, iCodeTop);
        }
        else {
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::UNDEFINED, iCodeTop);
            itsStackDepth++;
            if (itsStackDepth > itsData->itsMaxStack) {
                itsData->itsMaxStack = itsStackDepth;
            }
        }
        iCodeTop = addGoto(cx, node, JSTokenStream::RETURN, iCodeTop);
        itsStackDepth--;
        break;

    case JSTokenStream::GETVAR:{
            jsString_t name = node->getString();
            if (itsData->itsNeedsActivation) {
                // SETVAR handled this by turning into a SETPROP, but
                // we can't do that to a GETVAR without manufacturing
                // bogus children. Instead we use a special op to
                // push the current scope.
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::SCOPE, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::STRING, iCodeTop);
                iCodeTop = addString(cx, name, iCodeTop);
                itsStackDepth += 2;
                if (itsStackDepth > itsData->itsMaxStack) {
                    itsData->itsMaxStack = itsStackDepth;
                }
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::GETPROP, iCodeTop);
                itsStackDepth--;
            }
            else {
                int index = itsData->itsVariableTable->getOrdinal(name);
                iCodeTop = addByte(cx, (int8_t) JSTokenStream::GETVAR, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) index, iCodeTop);
                itsStackDepth++;
                if (itsStackDepth > itsData->itsMaxStack) {
                    itsData->itsMaxStack = itsStackDepth;
                }
            }
            break;
        }

    case JSTokenStream::SETVAR:{
            if (itsData->itsNeedsActivation) {
                child->setType(JSTokenStream::BINDNAME);
                node->setType(JSTokenStream::SETNAME);
                iCodeTop = generateICode(cx, node, iCodeTop);
            }
            else {
                jsString_t name = child->getString();

                child = child->getNextSibling();
                iCodeTop = generateICode(cx, child, iCodeTop);

                int index = itsData->itsVariableTable->getOrdinal(name);

                iCodeTop = addByte(cx, (int8_t) JSTokenStream::SETVAR, iCodeTop);
                iCodeTop = addByte(cx, (int8_t) index, iCodeTop);
            }
            break;
        }

    case JSTokenStream::PRIMARY:
        iCodeTop = addByte(cx, (int8_t) node->getInt(), iCodeTop);
        itsStackDepth++;
        if (itsStackDepth > itsData->itsMaxStack) {
            itsData->itsMaxStack = itsStackDepth;
        }
        break;

    case JSTokenStream::ENUMINIT:
        iCodeTop = generateICode(cx, child, iCodeTop);
        iCodeTop = addByte(cx, (int8_t) JSTokenStream::ENUMINIT, iCodeTop);
        iCodeTop = addEnumRef(cx, node, iCodeTop);  // addLocalRef -> addEnumRef
        itsStackDepth--;
        break;

    case JSTokenStream::ENUMNEXT:{
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::ENUMNEXT, iCodeTop);

            JSNode *init;

            (void)node->getProp(JSNode::ENUM_PROP, &init);
            iCodeTop = addEnumRef(cx, init, iCodeTop);  // addLocalRef -> addEnumRe
            itsStackDepth++;
            if (itsStackDepth > itsData->itsMaxStack) {
                itsData->itsMaxStack = itsStackDepth;
            }
            break;
        }

    case JSTokenStream::ENUMDONE:
        // could release the local here??
        // Yes, we add code to release enums
        iCodeTop = addByte(cx, (int8_t) JSTokenStream::ENUMDONE, iCodeTop);

        JSNode *init;

        (void)node->getProp(JSNode::ENUM_PROP, &init);
        iCodeTop = addEnumRef(cx, init, iCodeTop);  // addLocalRef -> addEnumRe
        break;

    case JSTokenStream::OBJECT:{
            JSNode *regexp;

            (void)node->getProp(JSNode::REGEXP_PROP, &regexp);

            int index;

            (void)regexp->getProp(JSNode::REGEXP_PROP, &index);
            iCodeTop = addByte(cx, (int8_t) JSTokenStream::OBJECT, iCodeTop);
            iCodeTop = addByte(cx, (int8_t) (index >> 8), iCodeTop);
            iCodeTop = addByte(cx, (int8_t) (index & 0xff), iCodeTop);
            itsStackDepth++;
            if (itsStackDepth > itsData->itsMaxStack) {
                itsData->itsMaxStack = itsStackDepth;
            }
            break;
        }

    default:
        badTree(cx, node);
        break;
    }
    return iCodeTop;
}
int JSInterpreter::addLocalRef(JSContext * cx, JSNode * node, int iCodeTop)
{
    int theLocalSlot;
    int localProp;
    jsBool_t ok = node->getProp(JSNode::LOCAL_PROP, &localProp);

    if (!ok) {
#ifdef REUSE_LOCAL
        theLocalSlot = itsData->itsLocalTop++;
        if (theLocalSlot >= 255) {
            jsString_t message = JSScriptRuntime::getMessage(cx, "interpreter.local.tmp.overfrow %s\n", cx->interpreterSourceFile);

#ifdef SHELL
            printf(message);
#else
            EwbSetLog(message);
#endif
        }
        if (itsData->itsLocalTop > itsData->itsMaxLocals) {
            itsData->itsMaxLocals = itsData->itsLocalTop;
        }
#else
        theLocalSlot = itsData->itsMaxLocals++;
#endif
        node->putProp(cx, JSNode::LOCAL_PROP, theLocalSlot);
    }
    else {
        theLocalSlot = localProp;
    }
    iCodeTop = addByte(cx, (int8_t) theLocalSlot, iCodeTop);
    if (theLocalSlot >= itsData->itsMaxLocals) {
        itsData->itsMaxLocals = theLocalSlot + 1;
    }
    return iCodeTop;
}

#ifdef REUSE_LOCAL
void JSInterpreter::delLocalRef(JSContext * cx, JSNode * node)
{
    int localProp;
    jsBool_t ok = node->getProp(JSNode::LOCAL_PROP, &localProp);

    if (ok) {
        if (localProp == itsData->itsLocalTop - 1) {
            itsData->itsLocalTop -= 1;
        }
        else {
            JSContext::reportWarning(cx, "msg.local.delete");
        }
        return;
    }
    cx->exceptionHandler->throwEx(new(cx) JSRuntimeException("msg.local.noassn"));
}
#endif /* REUSE_LOCAL */
int JSInterpreter::addEnumRef(JSContext * cx, JSNode * node, int iCodeTop)
{
    int theEnumSlot;
    int enumProp;
    jsBool_t ok = node->getProp(JSNode::LOCAL_PROP, &enumProp);

    if (!ok) {
        theEnumSlot = itsData->itsMaxEnums++;
        if (theEnumSlot >= 255) {
            jsString_t message = JSScriptRuntime::getMessage(cx, "<warning>interpreter.local.enum.overfrow %s\n", cx->interpreterSourceFile);
#ifdef SHELL
            printf(message);
#else
            EwbSetLog(message);
#endif
        }
        node->putProp(cx, JSNode::LOCAL_PROP, theEnumSlot);
    }
    else {
        theEnumSlot = enumProp;
    }
    iCodeTop = addByte(cx, (int8_t) theEnumSlot, iCodeTop);
    if (theEnumSlot >= itsData->itsMaxEnums) {
        itsData->itsMaxEnums = theEnumSlot + 1;
    }
    return iCodeTop;
}
int JSInterpreter::addGoto(JSContext * cx, JSNode * node, int gotoOp, int iCodeTop)
{
    int targetLabel;

    if (node->getType() == JSTokenStream::RETURN) {
        if (itsEpilogLabel == -1) {
            itsEpilogLabel = acquireLabel(cx);
        }
        targetLabel = itsEpilogLabel;
    }
    else {
        JSNode *target;

        (void)node->getProp(JSNode::TARGET_PROP, &target);

        int labelProp;
        jsBool_t ok = target->getProp(JSNode::LABEL_PROP, &labelProp);

        if (!ok) {
            targetLabel = acquireLabel(cx);
            target->putProp(cx, JSNode::LABEL_PROP, targetLabel);
        }
        else {
            targetLabel = labelProp;
        }
    }
    iCodeTop = addGoto(cx, targetLabel, (int8_t) gotoOp, iCodeTop);
    return iCodeTop;
}

int JSInterpreter::addGoto(JSContext * cx, int targetLabel, int gotoOp, int iCodeTop)
{
    int gotoPC = iCodeTop;

    iCodeTop = addByte(cx, (int8_t) gotoOp, iCodeTop);

    int theLabel = targetLabel & 0x7FFFFFFF;
    int targetPC = itsLabelTable[theLabel]->getPC();

    if (targetPC != -1) {
        short offset = (short)(targetPC - gotoPC);

        iCodeTop = addByte(cx, (int8_t) (offset >> 8), iCodeTop);
        iCodeTop = addByte(cx, (int8_t) offset, iCodeTop);
    }
    else {
        itsLabelTable[theLabel]->addFixup(cx, gotoPC + 1);
        iCodeTop = addByte(cx, (int8_t) 0, iCodeTop);
        iCodeTop = addByte(cx, (int8_t) 0, iCodeTop);
    }
    return iCodeTop;
}
int JSInterpreter::addByte(JSContext * cx, int8_t b, int iCodeTop)
{
    if (itsData->itsICodeLength == iCodeTop) {
/* itsICode is allocated from runtime memory to avoid gc fragmentation
	int8_t *ba = (int8_t *) JS_NewGCObj(cx, sizeof (*ba) * iCodeTop * 2);

	memcpy(ba, itsData->itsICode, iCodeTop);
*/
        int8_t *ba = (int8_t *) JS_NewRuntimeObj(cx->runtime,
                sizeof(*ba) * iCodeTop * 2);

        memcpy(ba, itsData->itsICode, iCodeTop);
        JS_DeleteRuntimeObj(cx->runtime, itsData->itsICode);
        itsData->itsICodeLength = iCodeTop * 2;
        itsData->itsICode = ba;
    }
    if (itsData->itsICode) {
        itsData->itsICode[iCodeTop++] = b;
    }
    return iCodeTop;
}
int JSInterpreter::addString(JSContext * cx, jsString_t str, int iCodeTop)
{
    iCodeTop = addByte(cx, (int8_t) (itsData->itsStringTableIndex >> 8), iCodeTop);
    iCodeTop = addByte(cx, (int8_t) (itsData->itsStringTableIndex & 0xFF), iCodeTop);
    if (itsData->itsStringTableLength == itsData->itsStringTableIndex) {
/* itsStringTable is allocated from runtime memory to avoid gc fragmentation
	jsString_t *sa
		= (jsString_t *) JS_NewGCObj(cx, sizeof (*sa)
					* itsData->itsStringTableIndex * 2);
*/
        jsString_t *sa = (jsString_t *) JS_NewRuntimeObj(cx->runtime, sizeof(*sa)
                * itsData->itsStringTableIndex * 2);

        memcpy(sa, itsData->itsStringTable, sizeof(*sa) * itsData->itsStringTableIndex);
        JS_DeleteRuntimeObj(cx->runtime, itsData->itsStringTable);
        itsData->itsStringTableLength = itsData->itsStringTableIndex * 2;
        itsData->itsStringTable = sa;
    }
    if (itsData->itsStringTable) {
        itsData->itsStringTable[itsData->itsStringTableIndex]
            = str != NULL ? JS_NewGCString(cx, str) : NULL;
    }
    itsData->itsStringTableIndex++; // gc safe
    return iCodeTop;
}
int JSInterpreter::addNumber(JSContext * cx, double num, int iCodeTop)
{
    iCodeTop = addByte(cx, (int8_t) (itsData->itsNumberTableIndex >> 8), iCodeTop);
    iCodeTop = addByte(cx, (int8_t) (itsData->itsNumberTableIndex & 0xFF), iCodeTop);
    if (itsData->itsNumberTableLength == itsData->itsNumberTableIndex) {
        double *na = (double *)JS_NewGCObj(cx, sizeof(*na)
                * itsData->itsNumberTableIndex * 2);

        memcpy(na, itsData->itsNumberTable, sizeof(*na) * itsData->itsNumberTableIndex);
        itsData->itsNumberTableLength = itsData->itsNumberTableIndex * 2;
        itsData->itsNumberTable = na;
    }
    itsData->itsNumberTable[itsData->itsNumberTableIndex++] = num;
    return iCodeTop;
}

#ifdef COMPACT_MEM
void JSInterpreter::adjustGCMemory(JSContext * cx)
{
#define Roundup(a, u)	   ((((a) + ((u) - 1)) / (u)) * (u))
    int itsICodeLength = Roundup(itsData->itsICodeTop,
            16 / sizeof(*itsData->itsICode));

    if (itsICodeLength < itsData->itsICodeLength) {
/* itsICode is allocated from runtime memory to avoid gc fragmentation
	int8_t *ba = (int8_t *) JS_NewGCObj(cx,
					sizeof (*ba) * itsData->itsICodeTop);
 
	memcpy(ba, itsData->itsICode, itsData->itsICodeTop);
*/
        int8_t *ba = (int8_t *) JS_NewRuntimeObj(cx->runtime,
                sizeof(*ba) * itsData->itsICodeTop);

        memcpy(ba, itsData->itsICode, itsData->itsICodeTop);
        JS_DeleteRuntimeObj(cx->runtime, itsData->itsICode);
        itsData->itsICode = ba;
        itsData->itsICodeLength = itsData->itsICodeTop;
    }

    int itsStringTableLength = Roundup(itsData->itsStringTableIndex,
            16 / sizeof(*itsData->itsStringTable));

    if (itsStringTableLength < itsData->itsStringTableLength) {
/* itsStringTable is allocated from runtime memory to avoid gc fragmentation
	jsString_t *sa
		= (jsString_t *) JS_NewGCObj(cx, sizeof (*sa)
					* itsData->itsStringTableIndex);
*/
        jsString_t *sa = (jsString_t *) JS_NewRuntimeObj(cx->runtime, sizeof(*sa)
                * itsData->itsStringTableIndex);

        memcpy(sa, itsData->itsStringTable, sizeof(*sa) * itsData->itsStringTableIndex);
        JS_DeleteRuntimeObj(cx->runtime, itsData->itsStringTable);
        itsData->itsStringTable = sa;
        itsData->itsStringTableLength = itsData->itsStringTableIndex;
    }

    int itsNumberTableLength = Roundup(itsData->itsNumberTableIndex,
            16 / sizeof(*itsData->itsNumberTable));

    if (itsNumberTableLength < itsData->itsNumberTableLength) {
        if (itsNumberTableLength > 0) {
            double *na = (double *)JS_NewGCObj(cx, sizeof(*na)
                    * itsData->itsNumberTableIndex);

            memcpy(na, itsData->itsNumberTable, sizeof(*na) * itsData->itsNumberTableIndex);
            itsData->itsNumberTable = na;
            itsData->itsNumberTableLength = itsData->itsNumberTableIndex;
        }
        else {
            itsData->itsNumberTable = NULL;
            itsData->itsNumberTableLength = 0;
        }
    }
#undef Roundup
}
#endif /* COMPACT_MEM */

jsVal_t JSInterpreter::interpret(JSContext * cx, JSScriptable * scope, JSScriptable * thisObj, int numArgs, jsVal_t * args, JSInterpreterData * theData)
{
    JSFrame *frame = cx->pushFrame(scope, thisObj, numArgs, args, theData);
    jsVal_t *stack = frame->stack;
    int stackTop = -1;
    int pc = 0;
    int8_t *iCode = theData->itsICode;
    int iCodeLength = theData->itsICodeTop;
    jsVal_t lhs;

    jsVal_t *local = frame->local;  // used for newtemp/usetemp etc.
    JSIdEnumeration **enums = frame->enums; // used for enuminit etc

    jsVal_t *vars = frame->vars;
    int i = theData->itsVariableTable->size();
#ifdef BRANCH
    int npc;
#endif

    if (i > 0) {
        int count = theData->itsVariableTable->getParameterCount();
        for (i = 0; i < count; i++) {
            if (i >= numArgs) {
                vars[i] = JS_VAL_VOID;
            }
            else {
                vars[i] = args[i];
            }
        }
        int size = theData->itsVariableTable->size();
        for (; i < size; i++) {
            vars[i] = JS_VAL_VOID;
        }
    }

    if (theData->itsNestedFunctions != NULL) {
        for (i = 0; i < theData->itsNestedFunctionsLength; i++) {
            createFunctionObject(cx, theData->itsNestedFunctions[i], scope);
        }
    }

    jsVal_t id;
    jsVal_t rhs;

    int count;
    int slot;

    jsString_t name = NULL;

    jsVal_t *outArgs;

    int lIntValue;
    int64_t lLongValue;
    int rIntValue;

    int *catchStack = frame->catchStack;
    int *finallyStack = frame->finallyStack;
    JSScriptable **scopeStack = frame->scopeStack;
    int tryStackTop = 0;

    jsVal_t result = JS_VAL_VOID;
    JSException *ex;

    //20040820 ichino. for Debug.
    static int line_t;
    static char *source_t;
    if (ewbJsDebugDetails >= 1) {
        if (theData->itsName != NULL && source_t != NULL) {
            printf("%s:%d CallFunc:%s()\n", source_t, line_t, theData->itsName);
        }
        else if (theData->itsName != NULL && source_t == NULL) {
            printf("line:%d CallFunc:%s()\n", line_t, theData->itsName);
        }
    }

  again:
    frame->tryStackTop = tryStackTop;
    if ((ex = enterTry(cx)) == NULL) {
        // for better performance, we avoid setjmp on every loop
        while (pc < iCodeLength) {

#ifdef MEASURMENT
            int typeiCode = iCode[pc] & 0xff;
            if (typeiCode >= 0 && typeiCode <= TableSize(countiCode)) {
                countiCode[typeiCode]++;
            }
#endif

            switch ((int)(iCode[pc] & 0xff)) {
            case JSTokenStream::ENDTRY:
                tryStackTop--;
                frame->tryStackTop = tryStackTop;
                break;
            case JSTokenStream::TRY:
                i = getTarget(iCode, pc + 1);
                if (i == pc)
                    i = 0;
                catchStack[tryStackTop] = i;
                i = getTarget(iCode, pc + 3);
                if (i == (pc + 2))
                    i = 0;
                finallyStack[tryStackTop] = i;
                scopeStack[tryStackTop++] = scope;
                frame->tryStackTop = tryStackTop;
                pc += 4;
                break;
            case JSTokenStream::GE:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop] = JSScriptRuntime::cmp_LEB(cx, rhs, lhs);
                break;
            case JSTokenStream::LE:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop] = JSScriptRuntime::cmp_LEB(cx, lhs, rhs);
                break;
            case JSTokenStream::GT:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop] = JSScriptRuntime::cmp_LTB(cx, rhs, lhs);
                break;
            case JSTokenStream::LT:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop] = JSScriptRuntime::cmp_LTB(cx, lhs, rhs);
                break;
            case JSTokenStream::IN:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop] = JS_BOOLEAN_TO_VAL(JSScriptRuntime::in(cx, lhs, rhs, scope));
                break;
            case JSTokenStream::INSTANCEOF:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop] = JS_BOOLEAN_TO_VAL(JSScriptRuntime::instanceOf(cx, scope, lhs, rhs));
                break;
            case JSTokenStream::EQ:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop] = JSScriptRuntime::eqB(cx, lhs, rhs);
                break;
            case JSTokenStream::NE:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop] = JSScriptRuntime::neB(cx, lhs, rhs);
                break;
            case JSTokenStream::SHEQ:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop] = JSScriptRuntime::seqB(lhs, rhs);
                break;
            case JSTokenStream::SHNE:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop] = JSScriptRuntime::sneB(lhs, rhs);
                break;
            case JSTokenStream::IFNE:
                if (!JSScriptRuntime::toBoolean(cx, stack[stackTop--])) {
#ifdef BRANCH
                    npc = getTarget(iCode, pc + 1);
                    checkBranch(cx, npc - pc);
                    pc = npc;
#else
                    pc = getTarget(iCode, pc + 1);
#endif
                    continue;
                }
                pc += 2;
                break;
            case JSTokenStream::IFEQ:
                if (JSScriptRuntime::toBoolean(cx, stack[stackTop--])) {
#ifdef BRANCH
                    npc = getTarget(iCode, pc + 1);
                    checkBranch(cx, npc - pc);
                    pc = npc;
#else
                    pc = getTarget(iCode, pc + 1);
#endif
                    continue;
                }
                pc += 2;
                break;
            case JSTokenStream::GOTO:
#ifdef BRANCH
                npc = getTarget(iCode, pc + 1);
                checkBranch(cx, npc - pc);
                pc = npc;
#else
                pc = getTarget(iCode, pc + 1);
#endif
                continue;
            case JSTokenStream::GOSUB:
                stack[++stackTop] = JS_INT_TO_VAL(pc + 3);
                pc = getTarget(iCode, pc + 1);
                continue;
            case JSTokenStream::RETSUB:
                slot = (iCode[++pc] & 0xFF);
                pc = JSScriptRuntime::toInt32(cx, local[slot]);
                continue;
            case JSTokenStream::POP:
                stackTop--;
                break;
            case JSTokenStream::DUP:
#ifdef TEMPVAL
                storeToStack(frame, stackTop + 1, stack[stackTop]);
#else
                stack[stackTop + 1] = stack[stackTop];
#endif
                stackTop++;
                break;
            case JSTokenStream::POPV:
#ifdef TEMPVAL
                result = normalizeVal(cx, frame, stack[stackTop--]);
#else
                result = stack[stackTop--];
#endif
                break;
            case JSTokenStream::RETURN:
#ifdef TEMPVAL
                result = normalizeVal(cx, frame, stack[stackTop--]);
#else
                result = stack[stackTop--];
#endif
                pc = getTarget(iCode, pc + 1);
#ifdef BRANCH
                // checkBranch(cx, -1);
#endif
                break;
            case JSTokenStream::BITNOT:
                rIntValue = JSScriptRuntime::toInt32(cx, stack[stackTop]);
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, ~rIntValue);
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx, (double) ~rIntValue));
                break;
            case JSTokenStream::BITAND:
                rIntValue = JSScriptRuntime::toInt32(cx, stack[stackTop--]);
                lIntValue = JSScriptRuntime::toInt32(cx, stack[stackTop]);
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, lIntValue & rIntValue);
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      (double) (lIntValue & rIntValue)));
                break;
            case JSTokenStream::BITOR:
                rIntValue = JSScriptRuntime::toInt32(cx, stack[stackTop--]);
                lIntValue = JSScriptRuntime::toInt32(cx, stack[stackTop]);
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, lIntValue | rIntValue);
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      (double) (lIntValue | rIntValue)));
                break;
            case JSTokenStream::BITXOR:
                rIntValue = JSScriptRuntime::toInt32(cx, stack[stackTop--]);
                lIntValue = JSScriptRuntime::toInt32(cx, stack[stackTop]);
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, lIntValue ^ rIntValue);
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      (double) (lIntValue ^ rIntValue)));
                break;
            case JSTokenStream::LSH:
                rIntValue = JSScriptRuntime::toInt32(cx, stack[stackTop--]);
                lIntValue = JSScriptRuntime::toInt32(cx, stack[stackTop]);
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, lIntValue << rIntValue);
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      (double) (lIntValue << rIntValue)));
                break;
            case JSTokenStream::RSH:
                rIntValue = JSScriptRuntime::toInt32(cx, stack[stackTop--]);
                lIntValue = JSScriptRuntime::toInt32(cx, stack[stackTop]);
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, lIntValue >> rIntValue);
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      (double) (lIntValue >> rIntValue)));
                break;
            case JSTokenStream::URSH:
                rIntValue = (JSScriptRuntime::toInt32(cx, stack[stackTop--])
                        & 0x1F);
                lLongValue = JSScriptRuntime::toUint32(cx, stack[stackTop]);
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, (double)(((uint64_t) lLongValue)
                                >> ((uint64_t) rIntValue)));
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      (double) (((uint64_t) lLongValue)
                //          >> ((uint64_t) rIntValue))));
                break;
            case JSTokenStream::ADD:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
#ifdef TEMPVAL
                if (JS_VAL_IS_NUMBER(rhs) && JS_VAL_IS_NUMBER(lhs)) {
                    storeToStack(frame, stackTop, JS_VAL_TO_NUMBER(rhs) + JS_VAL_TO_NUMBER(lhs));
                    break;
                }
#endif
                stack[stackTop] = JSScriptRuntime::add(cx, lhs, rhs);
                break;
            case JSTokenStream::SUB:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
#ifdef TEMPVAL
                storeToStack(frame, stackTop, JSScriptRuntime::toNumber(cx, lhs)
                        - JSScriptRuntime::toNumber(cx, rhs));
#else
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, JSScriptRuntime::toNumber(cx, lhs)
                        - JSScriptRuntime::toNumber(cx, rhs));
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      JSScriptRuntime::toNumber(cx, lhs)
                //      - JSScriptRuntime::toNumber(cx, rhs)));
#endif
                break;
            case JSTokenStream::NEG:
                rhs = stack[stackTop];
#ifdef TEMPVAL
                storeToStack(frame, stackTop, -JSScriptRuntime::toNumber(cx, rhs));
#else
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, -JSScriptRuntime::toNumber(cx, rhs));
#endif
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx, 
                //      -JSScriptRuntime::toNumber(cx, rhs)));
                break;
            case JSTokenStream::POS:
                rhs = stack[stackTop];
#ifdef TEMPVAL
                storeToStack(frame, stackTop, JSScriptRuntime::toNumber(cx, rhs));
#else
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, JSScriptRuntime::toNumber(cx, rhs));
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      JSScriptRuntime::toNumber(cx, rhs)));
#endif
                break;
            case JSTokenStream::MUL:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
#ifdef TEMPVAL
                storeToStack(frame, stackTop, JSScriptRuntime::toNumber(cx, lhs)
                        * JSScriptRuntime::toNumber(cx, rhs));
#else
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, JSScriptRuntime::toNumber(cx, lhs)
                        * JSScriptRuntime::toNumber(cx, rhs));
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      JSScriptRuntime::toNumber(cx, lhs)
                //      * JSScriptRuntime::toNumber(cx, rhs)));
#endif
                break;
            case JSTokenStream::DIV:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                // Detect the divide by zero or let Java do it ?
#ifdef TEMPVAL
                storeToStack(frame, stackTop, JSScriptRuntime::toNumber(cx, lhs)
                        / JSScriptRuntime::toNumber(cx, rhs));
#else
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, JSScriptRuntime::toNumber(cx, lhs)
                        / JSScriptRuntime::toNumber(cx, rhs));
                // was = JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      JSScriptRuntime::toNumber(cx, lhs)
                //      / JSScriptRuntime::toNumber(cx, rhs)));
#endif
                break;
            case JSTokenStream::MOD:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
#ifdef TEMPVAL
                storeToStack(frame, stackTop, fmod(JSScriptRuntime::toNumber(cx, lhs), JSScriptRuntime::toNumber(cx, rhs)));
#else
                stack[stackTop]
                        = JSScriptRuntime::toValue(cx, fmod(JSScriptRuntime::toNumber(cx, lhs), JSScriptRuntime::toNumber(cx, rhs)));
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      fmod(JSScriptRuntime::toNumber(cx, lhs),
                //      JSScriptRuntime::toNumber(cx, rhs))));
#endif
                break;
            case JSTokenStream::BINDNAME:
                stack[++stackTop]
                        = JS_OBJECT_TO_VAL(JSScriptRuntime::bind(cx, scope, getString(theData->itsStringTable, iCode, pc + 1)));
                pc += 2;
                break;
            case JSTokenStream::GETBASE:
                stack[++stackTop]
                        = JS_OBJECT_TO_VAL(JSScriptRuntime::getBase(cx, scope, getString(theData->itsStringTable, iCode, pc + 1)));
                pc += 2;
                break;
            case JSTokenStream::SETNAME:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                // what about class cast exception here ?
#ifdef TEMPVAL
                stack[stackTop]
                        = JSScriptRuntime::setName(cx, JS_VAL_TO_OBJECT(lhs), normalizeVal(cx, frame, rhs), scope, getString(theData->itsStringTable, iCode, pc + 1));
#else
                stack[stackTop]
                        = JSScriptRuntime::setName(cx, JS_VAL_TO_OBJECT(lhs), rhs, scope, getString(theData->itsStringTable, iCode, pc + 1));
#endif
                pc += 2;
                break;
            case JSTokenStream::DELPROP:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop] = JSScriptRuntime::del(cx, lhs, rhs);
                break;
            case JSTokenStream::GETPROP:
                name = JS_VAL_TO_STRING(stack[stackTop--]);
                lhs = stack[stackTop];
                stack[stackTop]
                        = JSScriptRuntime::getProp(cx, lhs, name, scope);
                break;
            case JSTokenStream::SETPROP:
                rhs = stack[stackTop--];
                name = JS_VAL_TO_STRING(stack[stackTop--]);
                lhs = stack[stackTop];
#ifdef TEMPVAL
                stack[stackTop]
                        = JSScriptRuntime::setProp(cx, lhs, name, normalizeVal(cx, frame, rhs), scope);
#else
                stack[stackTop]
                        = JSScriptRuntime::setProp(cx, lhs, name, rhs, scope);
#endif
                break;
            case JSTokenStream::GETELEM:
                id = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop]
                        = JSScriptRuntime::getElem(cx, lhs, id, scope);
                break;
            case JSTokenStream::SETELEM:
                rhs = stack[stackTop--];
                id = stack[stackTop--];
                lhs = stack[stackTop];
#ifdef TEMPVAL
                stack[stackTop]
                        = JSScriptRuntime::setElem(cx, lhs, id, normalizeVal(cx, frame, rhs), scope);
#else
                stack[stackTop]
                        = JSScriptRuntime::setElem(cx, lhs, id, rhs, scope);
#endif
                break;
            case JSTokenStream::PROPINC:
                name = JS_VAL_TO_STRING(stack[stackTop--]);
                lhs = stack[stackTop];
                stack[stackTop]
                        = JSScriptRuntime::postIncrement(cx, lhs, name, scope);
                break;
            case JSTokenStream::PROPDEC:
                name = JS_VAL_TO_STRING(stack[stackTop--]);
                lhs = stack[stackTop];
                stack[stackTop]
                        = JSScriptRuntime::postDecrement(cx, lhs, name, scope);
                break;
            case JSTokenStream::ELEMINC:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop]
                        = JSScriptRuntime::postIncrementElem(cx, lhs, rhs, scope);
                break;
            case JSTokenStream::ELEMDEC:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop]
                        = JSScriptRuntime::postDecrementElem(cx, lhs, rhs, scope);
                break;
            case JSTokenStream::GETTHIS:
                lhs = stack[stackTop];
                stack[stackTop]
                        = JS_OBJECT_TO_VAL(JSScriptRuntime::getThis(cx, JS_VAL_TO_OBJECT(lhs)));
                break;
            case JSTokenStream::NEWTEMP:
                lhs = stack[stackTop];
                slot = (iCode[++pc] & 0xFF);
#ifdef TEMPVAL
                storeToLocal(frame, slot, lhs);
#else
                local[slot] = lhs;
#endif
                break;
            case JSTokenStream::USETEMP:
                slot = (iCode[++pc] & 0xFF);
#ifdef TEMPVAL
                loadFromLocal(frame, ++stackTop, slot);
#else
                stack[++stackTop] = local[slot];
#endif
                break;
            case JSTokenStream::CALLSPECIAL:{
                    int lineNum = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
                    name = getString(theData->itsStringTable, iCode, pc + 3);

                    count = (iCode[pc + 5] << 8) | (iCode[pc + 6] & 0xFF);
                    outArgs = (jsVal_t *) JS_NewZoneObj(cx, sizeof(*outArgs) * count);
#ifdef TEMPVAL
                    frame->outArgsCount = 0;
                    frame->numOutArgs = count;
                    frame->outArgs = outArgs;
#endif
                    for (i = count - 1; i >= 0; i--) {
#ifdef TEMPVAL
                        outArgs[i] = normalizeVal(cx, frame, stack[stackTop--]);
                        frame->outArgsCount += 1;
#else
                        outArgs[i] = stack[stackTop--];
#endif
                    }
                    rhs = stack[stackTop--];
                    lhs = stack[stackTop];
                    stack[stackTop]
                            = JSScriptRuntime::callSpecial(cx, lhs, rhs, count, outArgs, thisObj, scope, name, lineNum);
#ifdef TEMPVAL
                    frame->outArgsCount = 0;
#endif
                    JS_DeleteZoneObj(cx, outArgs);
                    pc += 6;
                    break;
                }
            case JSTokenStream::CALL:{
                    count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);
                    outArgs = (jsVal_t *) JS_NewZoneObj(cx, sizeof(*outArgs) * count);
#ifdef TEMPVAL
                    frame->outArgsCount = 0;
                    frame->numOutArgs = count;
                    frame->outArgs = outArgs;
#endif
                    for (i = count - 1; i >= 0; i--) {
#ifdef TEMPVAL
                        outArgs[i] = normalizeVal(cx, frame, stack[stackTop--]);
                        frame->outArgsCount += 1;
#else
                        outArgs[i] = stack[stackTop--];
#endif
                    }
                    rhs = stack[stackTop--];
                    lhs = stack[stackTop];
                    if (lhs == JS_VAL_VOID) {
                        lhs = JS_STRING_TO_VAL(getString(theData->itsStringTable, iCode, pc + 1));
                    }
                    JSScriptable *calleeScope = scope;

                    if (theData->itsNeedsActivation) {
                        calleeScope = JSScriptableObject::getTopLevelScope(cx, scope);
                    }
                    stack[stackTop]
                            = JSScriptRuntime::call(cx, lhs, rhs, count, outArgs, calleeScope);
#ifdef TEMPVAL
                    frame->outArgsCount = 0;
#endif
                    JS_DeleteZoneObj(cx, outArgs);
                    pc += 4;
                    break;
                }
            case JSTokenStream::NEW:
                count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);
                outArgs = (jsVal_t *) JS_NewZoneObj(cx, sizeof(*outArgs) * count);
#ifdef TEMPVAL
                frame->outArgsCount = 0;
                frame->numOutArgs = count;
                frame->outArgs = outArgs;
#endif
                for (i = count - 1; i >= 0; i--) {
#ifdef TEMPVAL
                    outArgs[i] = normalizeVal(cx, frame, stack[stackTop--]);
                    frame->outArgsCount += 1;
#else
                    outArgs[i] = stack[stackTop--];
#endif
                }
                lhs = stack[stackTop];
                if (lhs == JS_VAL_VOID) {
                    lhs = JS_STRING_TO_VAL(getString(theData->itsStringTable, iCode, pc + 1));
                }
                stack[stackTop]
                        = JS_OBJECT_TO_VAL(JSScriptRuntime::newObject(cx, lhs, count, outArgs, scope));
#ifdef TEMPVAL
                frame->outArgsCount = 0;
#endif
                JS_DeleteZoneObj(cx, outArgs);
                pc += 4;
                break;
            case JSTokenStream::TYPEOF:
                lhs = stack[stackTop];
                stack[stackTop]
                        = JS_STRING_TO_VAL(JS_NewGCString(cx, JSScriptRuntime::doTypeof(cx, lhs)));
                break;
            case JSTokenStream::TYPEOFNAME:
                name = getString(theData->itsStringTable, iCode, pc + 1);
                stack[++stackTop]
                        = JS_STRING_TO_VAL(JS_NewGCString(cx, JSScriptRuntime::typeofName(cx, scope, name)));
                pc += 2;
                break;
            case JSTokenStream::STRING:
                stack[++stackTop]
                        = JS_STRING_TO_VAL(getString(theData->itsStringTable, iCode, pc + 1));
                pc += 2;
                break;
            case JSTokenStream::NUMBER:
#ifdef TEMPVAL
                storeToStack(frame, ++stackTop, getNumber(theData->itsNumberTable, iCode, pc + 1));
#else
                stack[++stackTop]
                        = JSScriptRuntime::toValue(cx, getNumber(theData->itsNumberTable, iCode, pc + 1));
                // was JS_DOUBLE_TO_VAL(
                //  JS_NewGCDouble(cx,
                //      getNumber(theData->itsNumberTable,
                //          iCode, pc + 1)));
#endif
                pc += 2;
                break;
            case JSTokenStream::NAME:
                stack[++stackTop]
                        = JSScriptRuntime::name(cx, scope, getString(theData->itsStringTable, iCode, pc + 1));
                pc += 2;
                break;
            case JSTokenStream::NAMEINC:
                stack[++stackTop]
                        = JSScriptRuntime::postIncrement(cx, scope, getString(theData->itsStringTable, iCode, pc + 1));
                pc += 2;
                break;
            case JSTokenStream::NAMEDEC:
                stack[++stackTop]
                        = JSScriptRuntime::postDecrement(cx, scope, getString(theData->itsStringTable, iCode, pc + 1));
                pc += 2;
                break;
            case JSTokenStream::SETVAR:
                lhs = stack[stackTop];
                slot = (iCode[++pc] & 0xFF);
#ifdef TEMPVAL
                storeToVars(frame, slot, lhs);
#else
                vars[slot] = lhs;
#endif
                break;
            case JSTokenStream::GETVAR:
                slot = (iCode[++pc] & 0xFF);
#ifdef TEMPVAL
                loadFromVars(frame, ++stackTop, slot);
#else
                stack[++stackTop] = vars[slot];
#endif
                break;
            case JSTokenStream::VARINC:
                slot = (iCode[++pc] & 0xFF);
#ifdef TEMPVAL
                loadFromVars(frame, ++stackTop, slot);
#else
                stack[++stackTop] = vars[slot];
#endif
                frame->setStackTop(stackTop);
#ifdef TEMPVAL
                if (JS_VAL_IS_NUMBER(vars[slot])) {
                    double d = JS_VAL_TO_NUMBER(vars[slot]);

                    storeToVars(frame, slot, d + 1.0);
                    break;
                }
#endif
                vars[slot] = JSScriptRuntime::postIncrement(cx, vars[slot]);
                break;
            case JSTokenStream::VARDEC:
                slot = (iCode[++pc] & 0xFF);
#ifdef TEMPVAL
                loadFromVars(frame, ++stackTop, slot);
#else
                stack[++stackTop] = vars[slot];
#endif
                frame->setStackTop(stackTop);
#ifdef TEMPVAL
                if (JS_VAL_IS_NUMBER(vars[slot])) {
                    double d = JS_VAL_TO_NUMBER(vars[slot]);

                    storeToVars(frame, slot, d - 1.0);
                    break;
                }
#endif
                vars[slot] = JSScriptRuntime::postDecrement(cx, vars[slot]);
                break;
#ifdef VX
            case JSTokenStream::_ZERO:
#else
            case JSTokenStream::ZERO:
#endif
                stack[++stackTop] = zero;
                break;
            case JSTokenStream::ONE:
                stack[++stackTop] = one;
                break;
            case JSTokenStream::_NULL:
                stack[++stackTop] = JS_VAL_NULL;
                break;
            case JSTokenStream::THIS:
                stack[++stackTop] = JS_OBJECT_TO_VAL(thisObj);
                break;
            case JSTokenStream::_FALSE:
                stack[++stackTop] = JS_VAL_FALSE;
                break;
            case JSTokenStream::_TRUE:
                stack[++stackTop] = JS_VAL_TRUE;
                break;
            case JSTokenStream::UNDEFINED:
                stack[++stackTop] = JS_VAL_VOID;
                break;
            case JSTokenStream::THROW:
                cx->exceptionHandler->throwEx(new(cx) JSJavaScriptException(cx, stack[stackTop--]));
                /* NOT REACHED */
            case JSTokenStream::JTHROW:
                cx->exceptionHandler->throwEx(frame->ex);
                /* NOT REACHED */
            case JSTokenStream::ENTERWITH:
                lhs = stack[stackTop--];
                frame->scope = scope = JSScriptRuntime::enterWith(cx, lhs, scope);
                break;
            case JSTokenStream::LEAVEWITH:
                frame->scope = scope = JSScriptRuntime::leaveWith(cx, scope);
                break;
            case JSTokenStream::NEWSCOPE:
                stack[++stackTop]
                        = JS_OBJECT_TO_VAL(JSScriptRuntime::newScope(cx));
                break;
            case JSTokenStream::ENUMINIT:
                slot = (iCode[++pc] & 0xFF);
                lhs = stack[stackTop--];
                enums[slot] = JSScriptRuntime::initEnum(cx, lhs, scope);
                break;
            case JSTokenStream::ENUMNEXT:
                slot = (iCode[++pc] & 0xFF);
                stack[++stackTop]
                        = JSScriptRuntime::nextEnum(enums[slot]);
                break;
            case JSTokenStream::ENUMDONE:
                slot = (iCode[++pc] & 0xFF);
                enums[slot]->destroy(cx);
                enums[slot] = NULL;
                break;
            case JSTokenStream::GETPROTO:
                lhs = stack[stackTop];
                stack[stackTop]
                        = JS_OBJECT_TO_VAL(JSScriptRuntime::getProto(cx, lhs, scope));
                break;
            case JSTokenStream::GETPARENT:
                lhs = stack[stackTop];
                stack[stackTop]
                        = JS_OBJECT_TO_VAL(JSScriptRuntime::getParent(cx, lhs));
                break;
            case JSTokenStream::GETSCOPEPARENT:
                lhs = stack[stackTop];
                stack[stackTop]
                        = JS_OBJECT_TO_VAL(JSScriptRuntime::getParent(cx, lhs, scope));
                break;
            case JSTokenStream::SETPROTO:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop]
                        = JSScriptRuntime::setProto(cx, lhs, rhs, scope);
                break;
            case JSTokenStream::SETPARENT:
                rhs = stack[stackTop--];
                lhs = stack[stackTop];
                stack[stackTop]
                        = JSScriptRuntime::setParent(cx, lhs, rhs, scope);
                break;
            case JSTokenStream::SCOPE:
                stack[++stackTop] = JS_OBJECT_TO_VAL(scope);
                break;
            case JSTokenStream::CLOSURE:
                i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
                if (theData->itsNestedFunctions != NULL) {
                    stack[++stackTop]
                        = JS_OBJECT_TO_VAL(new(cx) JSInterpretedFunction(theData->itsNestedFunctions[i], scope, cx));
                }
                else {
                    stack[++stackTop]
                        = JS_OBJECT_TO_VAL(new(cx) JSInterpretedFunction(NULL, scope, cx));
                }
                frame->stackTop = stackTop;
                createFunctionObject(cx, (JSInterpretedFunction *)
                        JS_VAL_TO_OBJECT(stack[stackTop]), scope);
                pc += 2;
                break;
            case JSTokenStream::OBJECT:
                i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
                stack[++stackTop] = theData->itsRegExpLiterals[i];
                pc += 2;
                break;
            case JSTokenStream::LINE:
                i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);
                cx->interpreterLine = i;
                if (ewbJsDebugDetails >= 1) {
                    //printf("L:%d\n",cx->interpreterLine);
                    line_t = cx->interpreterLine;
                }
                pc += 2;
                break;
            case JSTokenStream::SOURCEFILE:
                cx->interpreterSourceFile = theData->itsSourceFile;
                if (ewbJsDebugDetails >= 1) {
                    if (cx->interpreterSourceFile != NULL) {
                        //printf("Source:%s\n",cx->interpreterSourceFile);
                        source_t = cx->interpreterSourceFile;
                    }
                    else {
                        //printf("Source:NULL\n");
                    }
                }
                break;
            default:
                dumpICode(cx, theData);

                jsChar_t buf[64];

                sprintf(buf, "Unknown icode : %d @ pc : %d\n", (iCode[pc] & 0xff), pc);
                cx->exceptionHandler->throwEx(new(cx) JSRuntimeException(buf));
            }
            pc++;
            frame->stackTop = stackTop;
        }
        cx->exceptionHandler->exitTry();
    }
    else if (ex->isInstanceOf(JSEcmaError::className)) {
        // an offical ECMA error object, 
        // handle as if it were a JavaScriptException
        JSEcmaError *ee = (JSEcmaError *) ex;

        stackTop = 0;
        tryStackTop = frame->tryStackTop;   // necessery because we don't
        // call enterTry everytime.
        if (tryStackTop > 0) {
            pc = catchStack[--tryStackTop];
            scope = scopeStack[tryStackTop];
            if (pc == 0) {
                pc = finallyStack[tryStackTop];
                if (pc == 0) {
                    cx->popFrame();
                    cx->exceptionHandler->throwEx(ex);
                }
                stack[0] = JS_OBJECT_TO_VAL(ee->getErrorObject());
            }
            else {
                stack[0] = JS_OBJECT_TO_VAL(ee->getErrorObject());
            }
        }
        else {
            cx->popFrame();
            cx->exceptionHandler->throwEx(ex);
        }
        goto again;
    }
    else if (ex->isInstanceOf(JSJavaScriptException::className)) {
        JSJavaScriptException *jsx = (JSJavaScriptException *) ex;

        stackTop = 0;
        tryStackTop = frame->tryStackTop;   // necessery because we don't
        // call enterTry everytime.
        if (tryStackTop > 0) {
            pc = catchStack[--tryStackTop];
            scope = scopeStack[tryStackTop];
            if (pc == 0) {
                pc = finallyStack[tryStackTop];
                if (pc == 0) {
                    cx->popFrame();
                    cx->exceptionHandler->throwEx(ex);
                }
                stackTop = -1;
                frame->ex = ex;
            }
            else {
                stack[0] = JSScriptRuntime::unwrapJavaScriptException(jsx);
            }
        }
        else {
            cx->popFrame();
            cx->exceptionHandler->throwEx(ex);
        }
        goto again;
    }
    else if (ex->isInstanceOf(JSRuntimeException::className)) {
        tryStackTop = frame->tryStackTop;   // necessery because we don't
        // call enterTry everytime.
        if (tryStackTop > 0) {
            stackTop = -1;
            frame->ex = ex;
            pc = finallyStack[--tryStackTop];
            scope = scopeStack[tryStackTop];
            if (pc == 0) {
                cx->popFrame();
                cx->exceptionHandler->throwEx(ex);
            }
        }
        else {
            cx->popFrame();
            cx->exceptionHandler->throwEx(ex);
        }
        goto again;
    }
    else {  // uncaught
        cx->popFrame();
        cx->exceptionHandler->throwEx(ex);
    }
    cx->popFrame();

    return result;
}

JSIRFactory *JSInterpreter::createIRFactory(JSContext * cx, JSTokenStream * ts, JSScriptable * scope)
{
    return new(cx) JSIRFactory(ts, scope);
}

JSNode *JSInterpreter::transform(JSContext * cx, JSNode * tree, JSTokenStream * ts, JSScriptable * scope)
{
    JSNodeTransformer *nodeTransformer = new(cx) JSNodeTransformer(cx);
    JSNode *transformed = nodeTransformer->transform(cx, tree, NULL, ts, scope);

    nodeTransformer->destroy(cx);
    return transformed;
}

JSNativeFunction *JSInterpreter::compile(JSContext * cx, JSScriptable * scope, JSNode * tree)
{
    version = cx->getLanguageVersion();
    itsData = new(cx) JSInterpreterData(cx, 0, 0, 0, cx->hasCompileFunctionsWithDynamicScope());
    if (tree->isInstanceOf(JSFunctionNode::className)) {
        JSFunctionNode *f = (JSFunctionNode *) tree;

        JSInterpretedFunction *result = generateFunctionICode(cx, scope, f);
        cx->pushLocalVal(JS_OBJECT_TO_VAL(result));
        result->itsData->itsFunctionType = f->getFunctionType();
        createFunctionObject(cx, result, scope);
        if (itsData->itsVariableTable != NULL) {
            cx->delVariableTable(itsData->itsVariableTable);
        }
        cx->popLocalVals(1);
        return result;
    }
    JSInterpretedScript *result = generateScriptICode(cx, scope, tree);
    cx->pushLocalVal(JS_OBJECT_TO_VAL(result));

#ifdef COMPACT_MEM
    adjustGCMemory(cx);
#endif
    //printf("JSInterpreter::compile 0: %d\n", itsData->itsMaxLocals);
    if (itsData->itsVariableTable != NULL) {
        cx->delVariableTable(itsData->itsVariableTable);
    }
    cx->popLocalVals(1);
    return result;
}

void JSInterpreter::mark(JSContext * cx)
{
    JSGCHeap *gcHeap = &cx->runtime->gcHeap;

    if (itsData != NULL)
        itsData->mark(cx);
    if (itsNestedFunctions != NULL) {
        gcHeap->markObj(itsNestedFunctions);
        for (int i = 0; i < itsNestedFunctionsLength; ++i) {
            if (itsNestedFunctions[i] != NULL) {
                itsNestedFunctions[i]->mark(cx);
            }
        }
    }
}

#ifdef MEASURMENT
void JSInterpreter::bytecodeCountShow()
{
    printf(" name  times\n");
    printf("--------------\n");
    for (int i = 0; i < 148; i++) {
        printf(" %s", JSTokenStream::tokenToName(i));
        printf(" %d \n", countiCode[i]);
    }
    printf("--------------\n");
}

void JSInterpreter::bytecodeCountReset()
{
    for (int i = 0; i < 148; i++) {
        countiCode[i] = 0;
    }
}
#endif


int JSInterpreter::getIcodeMemSize()
{
    return this->itsData->itsICodeLength;

}


JSInterpreter::JSInterpreter()
{
    itsInFunctionFlag = FALSE;
    itsFunctionList = NULL;

    itsData = NULL;
    itsTryDepth = 0;
    itsStackDepth = 0;
    itsEpilogLabel = -1;
    itsSourceFile = NULL;
    itsLineNumber = 0;
    itsNestedFunctionsLength = 0;
    itsNestedFunctions = NULL;
    version = 0;
}
