/*
 * 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>
#ifdef VX
#include <taskLib.h>
#endif
#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"
#include "ewb-sys.h"
#include "ewb-sys-if.h"
#ifdef MEASURMENT
int JSInterpreter::countiCode[148];
#endif
#ifndef SHELL	/* '03.06.27 by S.Takaoka */
#include "ewb-dbg.h"
#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 :
#if defined(CYGWIN)
		case JSTokenStream::__NULL :
#else /* !defined(CYGWIN) */
		case JSTokenStream::_NULL :
#endif /* !defined(CYGWIN) */
		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(
                            cx,
                            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(
                    cx,
                    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(cx, 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 :
    case JSTokenStream::VOID :
    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);
	    branch->release( cx );
	    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);
            branch->release( cx );
	}
	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);
	branch->release( cx );
	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()) {
	case JSTokenStream::VOID :
	    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++;
#else
        theLocalSlot = itsData->itsMaxLocals++;
#endif
	if(theLocalSlot == 256 /* theLocalSlot > 255 */ ){
            // print only once
            jsString_t message
                        = JSScriptRuntime::getMessage(cx,
                                "interpreter.local.tmp.overflow %s\n",
                                cx->interpreterSourceFile != NULL ?
                                        cx->interpreterSourceFile : "" );
#ifdef SHELL
	    printf(message);
#else
	    EwbSetLog(message);
#endif
#if 0 /* Temporary for AR102802 */
            cx->exceptionHandler->throwEx(
                    cx,
                    new (cx) JSRuntimeException( message ));
            /* NOT REACHED */
#endif
	}
#ifdef REUSE_LOCAL
	if (itsData->itsLocalTop > itsData->itsMaxLocals) {
	    itsData->itsMaxLocals = itsData->itsLocalTop;
	}
#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(
            cx,
            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 == 256 /* theEnumSlot > 255 */ ){
            // print only once
            jsString_t message
                = JSScriptRuntime::getMessage(cx,
                        "<warning>interpreter.local.enum.overflow %s\n",
                        cx->interpreterSourceFile != NULL ?
                                cx->interpreterSourceFile : "" );
#ifdef SHELL
	    printf(message);
#else
	    EwbSetLog(message);
#endif
#if 0 /* Temporary for AR102802 */
            cx->exceptionHandler->throwEx(
                    cx,
                    new (cx) JSRuntimeException( message ));
            /* NOT REACHED */
#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;
    }
    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;
    }
    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) {
/* itsNumberTableIndex is allocated from runtime memory to avoid gc fragmentation
	double *na
		= (double *) JS_NewGCObj(cx, sizeof (*na)
					* itsData->itsNumberTableIndex * 2);
	double *na
		= (double *) JS_NewRuntimeObj(cx, sizeof (*na)
					* itsData->itsNumberTableIndex * 2);
*/
	double *na
		= (double *) JS_NewRuntimeObj(cx->runtime, sizeof (*na)
					* itsData->itsNumberTableIndex * 2);

	memcpy(na, itsData->itsNumberTable,
		sizeof (*na) * itsData->itsNumberTableIndex);
	JS_DeleteRuntimeObj(cx->runtime, itsData->itsNumberTable);
	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;
#if defined(CYGWIN)
	    case JSTokenStream::__NULL :
#else /* !defined(CYGWIN) */
	    case JSTokenStream::_NULL :
#endif /* !defined(CYGWIN) */
		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(
                        cx,
			new (cx) JSJavaScriptException(cx, stack[stackTop--]));
		/* NOT REACHED */
	    case JSTokenStream::JTHROW :
		cx->exceptionHandler->throwEx(cx, 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);
		stack[++stackTop] 
			= JS_OBJECT_TO_VAL(
				new (cx) JSInterpretedFunction(
						theData->itsNestedFunctions[i],
						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(cx, 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(cx, ex);
		}
		stack[0] = JS_OBJECT_TO_VAL(ee->getErrorObject());
	    } else {
		stack[0] = JS_OBJECT_TO_VAL(ee->getErrorObject());
	    }
	} else {
	    cx->popFrame();
	    cx->exceptionHandler->throwEx(cx, 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(cx, ex);
		}
		stackTop = -1;
		frame->ex = ex;
	    } else {
		stack[0] = JSScriptRuntime::unwrapJavaScriptException(jsx);
	    }
	} else {
	    cx->popFrame();
	    cx->exceptionHandler->throwEx(cx, 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(cx, ex);
	    }
	} else {
	    cx->popFrame();
	    cx->exceptionHandler->throwEx(cx, ex);
	}
	goto again;
    } else {	// uncaught
	cx->popFrame();
	cx->exceptionHandler->throwEx(cx, 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;
}
