зеркало из https://github.com/mozilla/gecko-dev.git
Inline small functions used for code generation to produce intepreter or JVM bytecode for particular parser tree node: they just add to jar file size without readability benefits.
This commit is contained in:
Родитель
96aed722f8
Коммит
d29f6cb477
|
@ -535,24 +535,26 @@ public class Interpreter
|
|||
Node child = node.getFirstChild();
|
||||
switch (type) {
|
||||
|
||||
case Token.FUNCTION: {
|
||||
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
|
||||
int fnType = scriptOrFn.getFunctionNode(fnIndex).getFunctionType();
|
||||
// Only function expressions or function expression
|
||||
// statements needs closure code creating new function
|
||||
// object on stack as function statements are initialized
|
||||
// at script/function start
|
||||
// In addition function expression can not present here
|
||||
// at statement level, they must only present as expressions.
|
||||
if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
|
||||
addIndexOp(Icode_CLOSURE_STMT, fnIndex);
|
||||
} else {
|
||||
if (fnType != FunctionNode.FUNCTION_STATEMENT) {
|
||||
throw Kit.codeBug();
|
||||
case Token.FUNCTION:
|
||||
{
|
||||
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
|
||||
int fnType = scriptOrFn.getFunctionNode(fnIndex).
|
||||
getFunctionType();
|
||||
// Only function expressions or function expression
|
||||
// statements needs closure code creating new function
|
||||
// object on stack as function statements are initialized
|
||||
// at script/function start
|
||||
// In addition function expression can not present here
|
||||
// at statement level, they must only present as expressions.
|
||||
if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
|
||||
addIndexOp(Icode_CLOSURE_STMT, fnIndex);
|
||||
} else {
|
||||
if (fnType != FunctionNode.FUNCTION_STATEMENT) {
|
||||
throw Kit.codeBug();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.SCRIPT:
|
||||
case Token.LABEL:
|
||||
|
@ -600,7 +602,32 @@ public class Interpreter
|
|||
break;
|
||||
|
||||
case Token.SWITCH:
|
||||
visitSwitch((Node.Jump)node);
|
||||
updateLineNumber(node);
|
||||
// See comments in IRFactory.createSwitch() for description
|
||||
// of SWITCH node
|
||||
{
|
||||
Node switchNode = (Node.Jump)node;
|
||||
visitExpression(child, 0);
|
||||
for (Node.Jump caseNode = (Node.Jump)child.getNext();
|
||||
caseNode != null;
|
||||
caseNode = (Node.Jump)caseNode.getNext())
|
||||
{
|
||||
if (caseNode.getType() != Token.CASE)
|
||||
throw badTree(caseNode);
|
||||
Node test = caseNode.getFirstChild();
|
||||
addIcode(Icode_DUP);
|
||||
stackChange(1);
|
||||
visitExpression(test, 0);
|
||||
addToken(Token.SHEQ);
|
||||
stackChange(-1);
|
||||
// If true, Icode_IFEQ_POP will jump and remove case
|
||||
// value from stack
|
||||
addGoto(caseNode.target, Icode_IFEQ_POP);
|
||||
stackChange(-1);
|
||||
}
|
||||
addIcode(Icode_POP);
|
||||
stackChange(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.TARGET:
|
||||
|
@ -608,25 +635,28 @@ public class Interpreter
|
|||
break;
|
||||
|
||||
case Token.IFEQ :
|
||||
case Token.IFNE : {
|
||||
Node.Target target = ((Node.Jump)node).target;
|
||||
visitExpression(child, 0);
|
||||
addGoto(target, type);
|
||||
stackChange(-1);
|
||||
case Token.IFNE :
|
||||
{
|
||||
Node.Target target = ((Node.Jump)node).target;
|
||||
visitExpression(child, 0);
|
||||
addGoto(target, type);
|
||||
stackChange(-1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.GOTO: {
|
||||
Node.Target target = ((Node.Jump)node).target;
|
||||
addGoto(target, type);
|
||||
case Token.GOTO:
|
||||
{
|
||||
Node.Target target = ((Node.Jump)node).target;
|
||||
addGoto(target, type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.JSR: {
|
||||
Node.Target target = ((Node.Jump)node).target;
|
||||
addGoto(target, Icode_GOSUB);
|
||||
case Token.JSR:
|
||||
{
|
||||
Node.Target target = ((Node.Jump)node).target;
|
||||
addGoto(target, Icode_GOSUB);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.FINALLY:
|
||||
{
|
||||
|
@ -652,7 +682,33 @@ public class Interpreter
|
|||
break;
|
||||
|
||||
case Token.TRY:
|
||||
visitTry((Node.Jump)node, child);
|
||||
{
|
||||
Node.Jump tryNode = (Node.Jump)node;
|
||||
int exceptionObjectLocal = getLocalBlockRef(tryNode);
|
||||
int tryStart = itsICodeTop;
|
||||
|
||||
while (child != null) {
|
||||
visitStatement(child);
|
||||
child = child.getNext();
|
||||
}
|
||||
|
||||
Node.Target catchTarget = tryNode.target;
|
||||
if (catchTarget != null) {
|
||||
int catchStartPC
|
||||
= itsLabelTable[getTargetLabel(catchTarget)];
|
||||
addExceptionHandler(
|
||||
tryStart, catchStartPC, catchStartPC,
|
||||
false, itsWithDepth, exceptionObjectLocal);
|
||||
}
|
||||
Node.Target finallyTarget = tryNode.getFinally();
|
||||
if (finallyTarget != null) {
|
||||
int finallyStartPC
|
||||
= itsLabelTable[getTargetLabel(finallyTarget)];
|
||||
addExceptionHandler(
|
||||
tryStart, finallyStartPC, finallyStartPC,
|
||||
true, itsWithDepth, exceptionObjectLocal);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.CATCH_SCOPE:
|
||||
|
@ -722,37 +778,40 @@ public class Interpreter
|
|||
int savedStackDepth = itsStackDepth;
|
||||
switch (type) {
|
||||
|
||||
case Token.FUNCTION: {
|
||||
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
|
||||
FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
|
||||
// See comments in visitStatement for Token.FUNCTION case
|
||||
if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION) {
|
||||
throw Kit.codeBug();
|
||||
case Token.FUNCTION:
|
||||
{
|
||||
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
|
||||
FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
|
||||
// See comments in visitStatement for Token.FUNCTION case
|
||||
if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION) {
|
||||
throw Kit.codeBug();
|
||||
}
|
||||
addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
|
||||
stackChange(1);
|
||||
}
|
||||
addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
|
||||
stackChange(1);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.LOCAL_LOAD: {
|
||||
int localIndex = getLocalBlockRef(node);
|
||||
addIndexOp(Token.LOCAL_LOAD, localIndex);
|
||||
stackChange(1);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.COMMA: {
|
||||
Node lastChild = node.getLastChild();
|
||||
while (child != lastChild) {
|
||||
visitExpression(child, 0);
|
||||
addIcode(Icode_POP);
|
||||
stackChange(-1);
|
||||
child = child.getNext();
|
||||
case Token.LOCAL_LOAD:
|
||||
{
|
||||
int localIndex = getLocalBlockRef(node);
|
||||
addIndexOp(Token.LOCAL_LOAD, localIndex);
|
||||
stackChange(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.COMMA:
|
||||
{
|
||||
Node lastChild = node.getLastChild();
|
||||
while (child != lastChild) {
|
||||
visitExpression(child, 0);
|
||||
addIcode(Icode_POP);
|
||||
stackChange(-1);
|
||||
child = child.getNext();
|
||||
}
|
||||
// Preserve tail context flag if any
|
||||
visitExpression(child, contextFlags & ECF_TAIL);
|
||||
}
|
||||
// Preserve tail context flag if any
|
||||
visitExpression(child, contextFlags & ECF_TAIL);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.USE_STACK:
|
||||
// Indicates that stack was modified externally,
|
||||
|
@ -763,56 +822,103 @@ public class Interpreter
|
|||
case Token.CALL:
|
||||
case Token.NEW:
|
||||
case Token.REF_CALL:
|
||||
visitCall(node, contextFlags);
|
||||
{
|
||||
if (type == Token.NEW) {
|
||||
visitExpression(child, 0);
|
||||
} else {
|
||||
generateCallFunAndThis(child);
|
||||
}
|
||||
int argCount = 0;
|
||||
while ((child = child.getNext()) != null) {
|
||||
visitExpression(child, 0);
|
||||
++argCount;
|
||||
}
|
||||
int callType = node.getIntProp(Node.SPECIALCALL_PROP,
|
||||
Node.NON_SPECIALCALL);
|
||||
if (callType != Node.NON_SPECIALCALL) {
|
||||
// embed line number and source filename
|
||||
addIndexOp(Icode_CALLSPECIAL, argCount);
|
||||
addUint8(callType);
|
||||
addUint8(type == Token.NEW ? 1 : 0);
|
||||
addUint16(itsLineNumber & 0xFFFF);
|
||||
} else {
|
||||
if (type == Token.CALL) {
|
||||
if ((contextFlags & ECF_TAIL) != 0) {
|
||||
type = Icode_TAIL_CALL;
|
||||
}
|
||||
}
|
||||
addIndexOp(type, argCount);
|
||||
}
|
||||
// adjust stack
|
||||
if (type == Token.NEW) {
|
||||
// f, args -> results
|
||||
stackChange(-argCount);
|
||||
} else {
|
||||
// f, thisObj, args -> results
|
||||
stackChange(-1 - argCount);
|
||||
}
|
||||
if (argCount > itsData.itsMaxCalleeArgs) {
|
||||
itsData.itsMaxCalleeArgs = argCount;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.AND:
|
||||
case Token.OR: {
|
||||
visitExpression(child, 0);
|
||||
addIcode(Icode_DUP);
|
||||
stackChange(1);
|
||||
int afterSecondJumpStart = itsICodeTop;
|
||||
int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ;
|
||||
addForwardGoto(jump);
|
||||
stackChange(-1);
|
||||
addIcode(Icode_POP);
|
||||
stackChange(-1);
|
||||
child = child.getNext();
|
||||
// Preserve tail context flag if any
|
||||
visitExpression(child, contextFlags & ECF_TAIL);
|
||||
resolveForwardGoto(afterSecondJumpStart);
|
||||
case Token.OR:
|
||||
{
|
||||
visitExpression(child, 0);
|
||||
addIcode(Icode_DUP);
|
||||
stackChange(1);
|
||||
int afterSecondJumpStart = itsICodeTop;
|
||||
int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ;
|
||||
addForwardGoto(jump);
|
||||
stackChange(-1);
|
||||
addIcode(Icode_POP);
|
||||
stackChange(-1);
|
||||
child = child.getNext();
|
||||
// Preserve tail context flag if any
|
||||
visitExpression(child, contextFlags & ECF_TAIL);
|
||||
resolveForwardGoto(afterSecondJumpStart);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.HOOK: {
|
||||
Node ifThen = child.getNext();
|
||||
Node ifElse = ifThen.getNext();
|
||||
visitExpression(child, 0);
|
||||
int elseJumpStart = itsICodeTop;
|
||||
addForwardGoto(Token.IFNE);
|
||||
stackChange(-1);
|
||||
// Preserve tail context flag if any
|
||||
visitExpression(ifThen, contextFlags & ECF_TAIL);
|
||||
int afterElseJumpStart = itsICodeTop;
|
||||
addForwardGoto(Token.GOTO);
|
||||
resolveForwardGoto(elseJumpStart);
|
||||
itsStackDepth = savedStackDepth;
|
||||
// Preserve tail context flag if any
|
||||
visitExpression(ifElse, contextFlags & ECF_TAIL);
|
||||
resolveForwardGoto(afterElseJumpStart);
|
||||
case Token.HOOK:
|
||||
{
|
||||
Node ifThen = child.getNext();
|
||||
Node ifElse = ifThen.getNext();
|
||||
visitExpression(child, 0);
|
||||
int elseJumpStart = itsICodeTop;
|
||||
addForwardGoto(Token.IFNE);
|
||||
stackChange(-1);
|
||||
// Preserve tail context flag if any
|
||||
visitExpression(ifThen, contextFlags & ECF_TAIL);
|
||||
int afterElseJumpStart = itsICodeTop;
|
||||
addForwardGoto(Token.GOTO);
|
||||
resolveForwardGoto(elseJumpStart);
|
||||
itsStackDepth = savedStackDepth;
|
||||
// Preserve tail context flag if any
|
||||
visitExpression(ifElse, contextFlags & ECF_TAIL);
|
||||
resolveForwardGoto(afterElseJumpStart);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.GETPROP:
|
||||
visitGetProp(node, child);
|
||||
visitExpression(child, 0);
|
||||
child = child.getNext();
|
||||
addStringOp(Token.GETPROP, child.getString());
|
||||
break;
|
||||
|
||||
case Token.GETELEM:
|
||||
visitGetElem(node, child);
|
||||
visitExpression(child, 0);
|
||||
child = child.getNext();
|
||||
visitExpression(child, 0);
|
||||
addToken(Token.GETELEM);
|
||||
stackChange(-1);
|
||||
break;
|
||||
|
||||
case Token.GET_REF:
|
||||
visitGetRef(node, child);
|
||||
visitExpression(child, 0);
|
||||
addToken(Token.GET_REF);
|
||||
break;
|
||||
|
||||
case Token.DELPROP:
|
||||
|
@ -860,24 +966,25 @@ public class Interpreter
|
|||
}
|
||||
break;
|
||||
|
||||
case Token.SETPROP:
|
||||
case Token.SETPROP_OP: {
|
||||
visitExpression(child, 0);
|
||||
child = child.getNext();
|
||||
String property = child.getString();
|
||||
child = child.getNext();
|
||||
if (type == Token.SETPROP_OP) {
|
||||
addIcode(Icode_DUP);
|
||||
stackChange(1);
|
||||
addStringOp(Token.GETPROP, property);
|
||||
// Compensate for the following USE_STACK
|
||||
case Token.SETPROP:
|
||||
case Token.SETPROP_OP:
|
||||
{
|
||||
visitExpression(child, 0);
|
||||
child = child.getNext();
|
||||
String property = child.getString();
|
||||
child = child.getNext();
|
||||
if (type == Token.SETPROP_OP) {
|
||||
addIcode(Icode_DUP);
|
||||
stackChange(1);
|
||||
addStringOp(Token.GETPROP, property);
|
||||
// Compensate for the following USE_STACK
|
||||
stackChange(-1);
|
||||
}
|
||||
visitExpression(child, 0);
|
||||
addStringOp(Token.SETPROP, property);
|
||||
stackChange(-1);
|
||||
}
|
||||
visitExpression(child, 0);
|
||||
addStringOp(Token.SETPROP, property);
|
||||
stackChange(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.SETELEM:
|
||||
case Token.SETELEM_OP:
|
||||
|
@ -914,33 +1021,35 @@ public class Interpreter
|
|||
stackChange(-1);
|
||||
break;
|
||||
|
||||
case Token.SETNAME: {
|
||||
String name = child.getString();
|
||||
visitExpression(child, 0);
|
||||
child = child.getNext();
|
||||
visitExpression(child, 0);
|
||||
addStringOp(Token.SETNAME, name);
|
||||
stackChange(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.TYPEOFNAME: {
|
||||
String 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 = scriptOrFn.getParamOrVarIndex(name);
|
||||
if (index == -1) {
|
||||
addStringOp(Icode_TYPEOFNAME, name);
|
||||
stackChange(1);
|
||||
} else {
|
||||
addVarOp(Token.GETVAR, index);
|
||||
stackChange(1);
|
||||
addToken(Token.TYPEOF);
|
||||
case Token.SETNAME:
|
||||
{
|
||||
String name = child.getString();
|
||||
visitExpression(child, 0);
|
||||
child = child.getNext();
|
||||
visitExpression(child, 0);
|
||||
addStringOp(Token.SETNAME, name);
|
||||
stackChange(-1);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.TYPEOFNAME:
|
||||
{
|
||||
String 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 = scriptOrFn.getParamOrVarIndex(name);
|
||||
if (index == -1) {
|
||||
addStringOp(Icode_TYPEOFNAME, name);
|
||||
stackChange(1);
|
||||
} else {
|
||||
addVarOp(Token.GETVAR, index);
|
||||
stackChange(1);
|
||||
addToken(Token.TYPEOF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.BINDNAME:
|
||||
case Token.NAME:
|
||||
|
@ -955,41 +1064,68 @@ public class Interpreter
|
|||
break;
|
||||
|
||||
case Token.NUMBER:
|
||||
visitNumber(node);
|
||||
break;
|
||||
|
||||
case Token.GETVAR: {
|
||||
String 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.
|
||||
addIcode(Icode_SCOPE);
|
||||
stackChange(1);
|
||||
addStringOp(Token.GETPROP, name);
|
||||
} else {
|
||||
int index = scriptOrFn.getParamOrVarIndex(name);
|
||||
addVarOp(Token.GETVAR, index);
|
||||
{
|
||||
double num = node.getDouble();
|
||||
int inum = (int)num;
|
||||
if (inum == num) {
|
||||
if (inum == 0) {
|
||||
addIcode(Icode_ZERO);
|
||||
// Check for negative zero
|
||||
if (1.0 / num < 0.0) {
|
||||
addToken(Token.NEG);
|
||||
}
|
||||
} else if (inum == 1) {
|
||||
addIcode(Icode_ONE);
|
||||
} else if ((short)inum == inum) {
|
||||
addIcode(Icode_SHORTNUMBER);
|
||||
// write short as uin16 bit pattern
|
||||
addUint16(inum & 0xFFFF);
|
||||
} else {
|
||||
addIcode(Icode_INTNUMBER);
|
||||
addInt(inum);
|
||||
}
|
||||
} else {
|
||||
int index = getDoubleIndex(num);
|
||||
addIndexOp(Token.NUMBER, index);
|
||||
}
|
||||
stackChange(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.SETVAR: {
|
||||
if (itsData.itsNeedsActivation) {
|
||||
child.setType(Token.BINDNAME);
|
||||
node.setType(Token.SETNAME);
|
||||
visitExpression(node, 0);
|
||||
} else {
|
||||
String name = child.getString();
|
||||
child = child.getNext();
|
||||
visitExpression(child, 0);
|
||||
int index = scriptOrFn.getParamOrVarIndex(name);
|
||||
addVarOp(Token.SETVAR, index);
|
||||
case Token.GETVAR:
|
||||
{
|
||||
String 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.
|
||||
addIcode(Icode_SCOPE);
|
||||
stackChange(1);
|
||||
addStringOp(Token.GETPROP, name);
|
||||
} else {
|
||||
int index = scriptOrFn.getParamOrVarIndex(name);
|
||||
addVarOp(Token.GETVAR, index);
|
||||
stackChange(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.SETVAR:
|
||||
{
|
||||
if (itsData.itsNeedsActivation) {
|
||||
child.setType(Token.BINDNAME);
|
||||
node.setType(Token.SETNAME);
|
||||
visitExpression(node, 0);
|
||||
} else {
|
||||
String name = child.getString();
|
||||
child = child.getNext();
|
||||
visitExpression(child, 0);
|
||||
int index = scriptOrFn.getParamOrVarIndex(name);
|
||||
addVarOp(Token.SETVAR, index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.NULL:
|
||||
case Token.THIS:
|
||||
|
@ -1006,24 +1142,26 @@ public class Interpreter
|
|||
stackChange(1);
|
||||
break;
|
||||
|
||||
case Token.REGEXP: {
|
||||
int index = node.getExistingIntProp(Node.REGEXP_PROP);
|
||||
addIndexOp(Token.REGEXP, index);
|
||||
stackChange(1);
|
||||
case Token.REGEXP:
|
||||
{
|
||||
int index = node.getExistingIntProp(Node.REGEXP_PROP);
|
||||
addIndexOp(Token.REGEXP, index);
|
||||
stackChange(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.ARRAYLIT:
|
||||
case Token.OBJECTLIT:
|
||||
visitLiteral(node, child);
|
||||
break;
|
||||
|
||||
case Token.SPECIAL_REF: {
|
||||
visitExpression(child, 0);
|
||||
String special = (String)node.getProp(Node.SPECIAL_PROP_PROP);
|
||||
addStringOp(Token.SPECIAL_REF, special);
|
||||
case Token.SPECIAL_REF:
|
||||
{
|
||||
String special = (String)node.getProp(Node.SPECIAL_PROP_PROP);
|
||||
visitExpression(child, 0);
|
||||
addStringOp(Token.SPECIAL_REF, special);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.XML_REF:
|
||||
visitExpression(child, 0);
|
||||
|
@ -1031,7 +1169,16 @@ public class Interpreter
|
|||
break;
|
||||
|
||||
case Token.DOTQUERY:
|
||||
visitDotQery(node, child);
|
||||
{
|
||||
int queryPC;
|
||||
updateLineNumber(node);
|
||||
visitExpression(child, 0);
|
||||
addIcode(Icode_ENTERDQ);
|
||||
stackChange(-1);
|
||||
queryPC = itsICodeTop;
|
||||
visitExpression(child.getNext(), 0);
|
||||
addBackwardGoto(Icode_LEAVEDQ, queryPC);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.DEFAULTNAMESPACE :
|
||||
|
@ -1043,16 +1190,16 @@ public class Interpreter
|
|||
addToken(type);
|
||||
break;
|
||||
|
||||
case Token.COLONCOLON : {
|
||||
if (child.getType() != Token.STRING)
|
||||
throw badTree(child);
|
||||
String namespace = child.getString();
|
||||
child = child.getNext();
|
||||
visitExpression(child, 0);
|
||||
addStringOp(Token.COLONCOLON, namespace);
|
||||
case Token.COLONCOLON :
|
||||
{
|
||||
if (child.getType() != Token.STRING)
|
||||
throw badTree(child);
|
||||
String namespace = child.getString();
|
||||
child = child.getNext();
|
||||
visitExpression(child, 0);
|
||||
addStringOp(Token.COLONCOLON, namespace);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
throw badTree(node);
|
||||
|
@ -1062,103 +1209,6 @@ public class Interpreter
|
|||
}
|
||||
}
|
||||
|
||||
private void visitSwitch(Node.Jump switchNode)
|
||||
{
|
||||
// See comments in IRFactory.createSwitch() for description
|
||||
// of SWITCH node
|
||||
|
||||
updateLineNumber(switchNode);
|
||||
|
||||
Node child = switchNode.getFirstChild();
|
||||
visitExpression(child, 0);
|
||||
for (Node.Jump caseNode = (Node.Jump)child.getNext();
|
||||
caseNode != null;
|
||||
caseNode = (Node.Jump)caseNode.getNext())
|
||||
{
|
||||
if (caseNode.getType() != Token.CASE)
|
||||
throw badTree(caseNode);
|
||||
Node test = caseNode.getFirstChild();
|
||||
addIcode(Icode_DUP);
|
||||
stackChange(1);
|
||||
visitExpression(test, 0);
|
||||
addToken(Token.SHEQ);
|
||||
stackChange(-1);
|
||||
// If true, Icode_IFEQ_POP will jump and remove case value
|
||||
// from stack
|
||||
addGoto(caseNode.target, Icode_IFEQ_POP);
|
||||
stackChange(-1);
|
||||
}
|
||||
addIcode(Icode_POP);
|
||||
stackChange(-1);
|
||||
}
|
||||
|
||||
private void visitTry(Node.Jump tryNode, Node child)
|
||||
{
|
||||
int tryStart = itsICodeTop;
|
||||
while (child != null) {
|
||||
visitStatement(child);
|
||||
child = child.getNext();
|
||||
}
|
||||
|
||||
int exceptionObjectLocal = getLocalBlockRef(tryNode);
|
||||
|
||||
Node.Target catchTarget = tryNode.target;
|
||||
if (catchTarget != null) {
|
||||
int catchStartPC = itsLabelTable[getTargetLabel(catchTarget)];
|
||||
addExceptionHandler(tryStart, catchStartPC, catchStartPC,
|
||||
false, itsWithDepth, exceptionObjectLocal);
|
||||
}
|
||||
Node.Target finallyTarget = tryNode.getFinally();
|
||||
if (finallyTarget != null) {
|
||||
int finallyStartPC = itsLabelTable[getTargetLabel(finallyTarget)];
|
||||
addExceptionHandler(tryStart, finallyStartPC, finallyStartPC,
|
||||
true, itsWithDepth, exceptionObjectLocal);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitCall(Node node, int contextFlags)
|
||||
{
|
||||
int type = node.getType();
|
||||
Node child = node.getFirstChild();
|
||||
if (type == Token.NEW) {
|
||||
visitExpression(child, 0);
|
||||
} else {
|
||||
generateCallFunAndThis(child);
|
||||
}
|
||||
int argCount = 0;
|
||||
while ((child = child.getNext()) != null) {
|
||||
visitExpression(child, 0);
|
||||
++argCount;
|
||||
}
|
||||
int callType = node.getIntProp(Node.SPECIALCALL_PROP,
|
||||
Node.NON_SPECIALCALL);
|
||||
if (callType != Node.NON_SPECIALCALL) {
|
||||
// embed line number and source filename
|
||||
addIndexOp(Icode_CALLSPECIAL, argCount);
|
||||
addUint8(callType);
|
||||
addUint8(type == Token.NEW ? 1 : 0);
|
||||
addUint16(itsLineNumber & 0xFFFF);
|
||||
} else {
|
||||
if (type == Token.CALL) {
|
||||
if ((contextFlags & ECF_TAIL) != 0) {
|
||||
type = Icode_TAIL_CALL;
|
||||
}
|
||||
}
|
||||
addIndexOp(type, argCount);
|
||||
}
|
||||
// adjust stack
|
||||
if (type == Token.NEW) {
|
||||
// f, args -> results
|
||||
stackChange(-argCount);
|
||||
} else {
|
||||
// f, thisObj, args -> results
|
||||
stackChange(-1 - argCount);
|
||||
}
|
||||
if (argCount > itsData.itsMaxCalleeArgs)
|
||||
itsData.itsMaxCalleeArgs = argCount;
|
||||
|
||||
}
|
||||
|
||||
private void generateCallFunAndThis(Node left)
|
||||
{
|
||||
// Generate code to place on stack function and thisObj
|
||||
|
@ -1198,29 +1248,6 @@ public class Interpreter
|
|||
}
|
||||
}
|
||||
|
||||
private void visitGetProp(Node node, Node child)
|
||||
{
|
||||
visitExpression(child, 0);
|
||||
child = child.getNext();
|
||||
String property = child.getString();
|
||||
addStringOp(Token.GETPROP, property);
|
||||
}
|
||||
|
||||
private void visitGetElem(Node node, Node child)
|
||||
{
|
||||
visitExpression(child, 0);
|
||||
child = child.getNext();
|
||||
visitExpression(child, 0);
|
||||
addToken(Token.GETELEM);
|
||||
stackChange(-1);
|
||||
}
|
||||
|
||||
private void visitGetRef(Node node, Node child)
|
||||
{
|
||||
visitExpression(child, 0);
|
||||
addToken(Token.GET_REF);
|
||||
}
|
||||
|
||||
private void visitIncDec(Node node, Node child)
|
||||
{
|
||||
int incrDecrMask = node.getExistingIntProp(Node.INCRDECR_PROP);
|
||||
|
@ -1279,34 +1306,6 @@ public class Interpreter
|
|||
}
|
||||
}
|
||||
|
||||
private void visitNumber(Node node)
|
||||
{
|
||||
double num = node.getDouble();
|
||||
int inum = (int)num;
|
||||
if (inum == num) {
|
||||
if (inum == 0) {
|
||||
addIcode(Icode_ZERO);
|
||||
// Check for negative zero
|
||||
if (1.0 / num < 0.0) {
|
||||
addToken(Token.NEG);
|
||||
}
|
||||
} else if (inum == 1) {
|
||||
addIcode(Icode_ONE);
|
||||
} else if ((short)inum == inum) {
|
||||
addIcode(Icode_SHORTNUMBER);
|
||||
// write short as uin16 bit pattern
|
||||
addUint16(inum & 0xFFFF);
|
||||
} else {
|
||||
addIcode(Icode_INTNUMBER);
|
||||
addInt(inum);
|
||||
}
|
||||
} else {
|
||||
int index = getDoubleIndex(num);
|
||||
addIndexOp(Token.NUMBER, index);
|
||||
}
|
||||
stackChange(1);
|
||||
}
|
||||
|
||||
private void visitLiteral(Node node, Node child)
|
||||
{
|
||||
int type = node.getType();
|
||||
|
@ -1347,17 +1346,6 @@ public class Interpreter
|
|||
}
|
||||
}
|
||||
|
||||
private void visitDotQery(Node node, Node child)
|
||||
{
|
||||
updateLineNumber(node);
|
||||
visitExpression(child, 0);
|
||||
addIcode(Icode_ENTERDQ);
|
||||
stackChange(-1);
|
||||
int queryPC = itsICodeTop;
|
||||
visitExpression(child.getNext(), 0);
|
||||
addBackwardGoto(Icode_LEAVEDQ, queryPC);
|
||||
}
|
||||
|
||||
private int getLocalBlockRef(Node node)
|
||||
{
|
||||
Node localBlock = (Node)node.getProp(Node.LOCAL_BLOCK_PROP);
|
||||
|
|
|
@ -1022,90 +1022,6 @@ public class ScriptRuntime {
|
|||
return (char)i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Java exceptions that JS can catch into an object the script
|
||||
* will see as the catch argument.
|
||||
*/
|
||||
private static Object getCatchObject(Context cx, Scriptable scope,
|
||||
Throwable t)
|
||||
throws JavaScriptException
|
||||
{
|
||||
EvaluatorException evaluator = null;
|
||||
if (t instanceof EvaluatorException) {
|
||||
evaluator = (EvaluatorException)t;
|
||||
while (t instanceof WrappedException) {
|
||||
t = ((WrappedException)t).getWrappedException();
|
||||
}
|
||||
}
|
||||
|
||||
if (t instanceof JavaScriptException) {
|
||||
return ((JavaScriptException)t).getValue();
|
||||
|
||||
} else if (t instanceof EcmaError) {
|
||||
EcmaError ee = (EcmaError)t;
|
||||
String errorName = ee.getName();
|
||||
return makeErrorObject(cx, scope, errorName, ee.getErrorMessage(),
|
||||
ee.sourceName(), ee.lineNumber());
|
||||
} else if (evaluator == null) {
|
||||
// Script can catch only instances of JavaScriptException,
|
||||
// EcmaError and EvaluatorException
|
||||
Kit.codeBug();
|
||||
}
|
||||
|
||||
if (t != evaluator && t instanceof EvaluatorException) {
|
||||
// ALERT: it should not happen as throwAsUncheckedException
|
||||
// takes care about it when exception is propagated through Java
|
||||
// reflection calls, but for now check for it
|
||||
evaluator = (EvaluatorException)t;
|
||||
}
|
||||
|
||||
String errorName;
|
||||
String message;
|
||||
if (t == evaluator) {
|
||||
// Pure evaluator exception
|
||||
if (evaluator instanceof WrappedException) Kit.codeBug();
|
||||
message = evaluator.getMessage();
|
||||
errorName = "InternalError";
|
||||
} else {
|
||||
errorName = "JavaException";
|
||||
message = t.getClass().getName()+": "+t.getMessage();
|
||||
}
|
||||
|
||||
Scriptable errorObject = makeErrorObject(cx, scope, errorName,
|
||||
message,
|
||||
evaluator.sourceName(),
|
||||
evaluator.lineNumber());
|
||||
if (t != evaluator) {
|
||||
Object twrap = cx.getWrapFactory().wrap(cx, scope, t, null);
|
||||
ScriptableObject.putProperty(errorObject, "javaException", twrap);
|
||||
}
|
||||
return errorObject;
|
||||
|
||||
}
|
||||
|
||||
private static Scriptable makeErrorObject(Context cx, Scriptable scope,
|
||||
String errorName, String message,
|
||||
String fileName, int lineNumber)
|
||||
throws JavaScriptException
|
||||
{
|
||||
int argLength;
|
||||
if (lineNumber > 0) {
|
||||
argLength = 3;
|
||||
} else {
|
||||
argLength = 2;
|
||||
}
|
||||
Object args[] = new Object[argLength];
|
||||
args[0] = message;
|
||||
args[1] = (fileName != null) ? fileName : "";
|
||||
if (lineNumber > 0) {
|
||||
args[2] = new Integer(lineNumber);
|
||||
}
|
||||
|
||||
Scriptable errorObject = cx.newObject(scope, errorName, args);
|
||||
ScriptableObject.putProperty(errorObject, "name", errorName);
|
||||
return errorObject;
|
||||
}
|
||||
|
||||
// XXX: this is until setDefaultNamespace will learn how to store NS
|
||||
// properly and separates namespace form Scriptable.get etc.
|
||||
private static final String DEFAULT_NS_TAG = "__default_namespace__";
|
||||
|
@ -2982,26 +2898,95 @@ public class ScriptRuntime {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static Scriptable newCatchScope(Throwable exception,
|
||||
public static Scriptable newCatchScope(Throwable t,
|
||||
Scriptable lastCatchScope,
|
||||
String exceptionName,
|
||||
Context cx, Scriptable scope)
|
||||
{
|
||||
Object obj;
|
||||
if (lastCatchScope == null) {
|
||||
obj = getCatchObject(cx, scope, exception);
|
||||
boolean cacheObj;
|
||||
|
||||
getObj:
|
||||
if (t instanceof JavaScriptException) {
|
||||
cacheObj = false;
|
||||
obj = ((JavaScriptException)t).getValue();
|
||||
} else {
|
||||
NativeObject last = (NativeObject)lastCatchScope;
|
||||
obj = last.getAssociatedValue(exception);
|
||||
if (obj == null) Kit.codeBug();
|
||||
cacheObj = true;
|
||||
|
||||
// Create wrapper object unless it was associated with
|
||||
// the previous scope object
|
||||
|
||||
if (lastCatchScope != null) {
|
||||
NativeObject last = (NativeObject)lastCatchScope;
|
||||
obj = last.getAssociatedValue(t);
|
||||
if (obj == null) Kit.codeBug();
|
||||
break getObj;
|
||||
}
|
||||
|
||||
RhinoException re;
|
||||
String errorName;
|
||||
String errorMsg;
|
||||
Throwable javaException = null;
|
||||
|
||||
if (t instanceof EcmaError) {
|
||||
EcmaError ee = (EcmaError)t;
|
||||
re = ee;
|
||||
errorName = ee.getName();
|
||||
errorMsg = ee.getErrorMessage();
|
||||
} else if (t instanceof WrappedException) {
|
||||
WrappedException we = (WrappedException)t;
|
||||
re = we;
|
||||
javaException = we.getWrappedException();
|
||||
errorName = "JavaException";
|
||||
errorMsg = javaException.getClass().getName()
|
||||
+": "+javaException.getMessage();
|
||||
} else if (t instanceof EvaluatorException) {
|
||||
// Pure evaluator exception, nor WrappedException instance
|
||||
EvaluatorException ee = (EvaluatorException)t;
|
||||
re = ee;
|
||||
errorName = "InternalError";
|
||||
errorMsg = ee.getMessage();
|
||||
} else {
|
||||
// Script can catch only instances of JavaScriptException,
|
||||
// EcmaError and EvaluatorException
|
||||
throw Kit.codeBug();
|
||||
}
|
||||
|
||||
String sourceUri = re.sourceName();
|
||||
if (sourceUri == null) {
|
||||
sourceUri = "";
|
||||
}
|
||||
int line = re.lineNumber();
|
||||
Object args[];
|
||||
if (line > 0) {
|
||||
args = new Object[] { errorMsg, sourceUri, new Integer(line) };
|
||||
} else {
|
||||
args = new Object[] { errorMsg, sourceUri };
|
||||
}
|
||||
|
||||
Scriptable errorObject = cx.newObject(scope, errorName, args);
|
||||
ScriptableObject.putProperty(errorObject, "name", errorName);
|
||||
|
||||
if (javaException != null) {
|
||||
Object wrap = cx.getWrapFactory().wrap(cx, scope, javaException,
|
||||
null);
|
||||
ScriptableObject.defineProperty(
|
||||
errorObject, "javaException", wrap,
|
||||
ScriptableObject.PERMANENT | ScriptableObject.READONLY);
|
||||
}
|
||||
|
||||
obj = errorObject;
|
||||
}
|
||||
|
||||
NativeObject catchScope = new NativeObject();
|
||||
|
||||
NativeObject catchScopeObject = new NativeObject();
|
||||
// See ECMA 12.4
|
||||
catchScope.defineProperty(
|
||||
catchScopeObject.defineProperty(
|
||||
exceptionName, obj, ScriptableObject.PERMANENT);
|
||||
catchScope.associateValue(exception, obj);
|
||||
return catchScope;
|
||||
if (cacheObj) {
|
||||
catchScopeObject.associateValue(t, obj);
|
||||
}
|
||||
return catchScopeObject;
|
||||
}
|
||||
|
||||
public static Scriptable enterWith(Object value, Scriptable scope)
|
||||
|
|
|
@ -1192,7 +1192,7 @@ class BodyCodegen
|
|||
localsMax = firstFreeLocal;
|
||||
|
||||
if (fnCurrent == null) {
|
||||
// See comments in visitRegexp
|
||||
// See comments in case Token.REGEXP
|
||||
if (scriptOrFn.getRegexpCount() != 0) {
|
||||
scriptRegexpLocal = getNewWordLocal();
|
||||
codegen.pushRegExpArray(cfw, scriptOrFn, contextLocal,
|
||||
|
@ -1470,11 +1470,50 @@ class BodyCodegen
|
|||
break;
|
||||
|
||||
case Token.CATCH_SCOPE:
|
||||
visitCatchScope(node, child);
|
||||
{
|
||||
int local = getLocalBlockRegister(node);
|
||||
int scopeIndex
|
||||
= node.getExistingIntProp(Node.CATCH_SCOPE_PROP);
|
||||
|
||||
String name = child.getString(); // name of exception
|
||||
child = child.getNext();
|
||||
generateExpression(child, node); // load expression object
|
||||
if (scopeIndex == 0) {
|
||||
cfw.add(ByteCode.ACONST_NULL);
|
||||
} else {
|
||||
// Load previous catch scope object
|
||||
cfw.addALoad(local);
|
||||
}
|
||||
cfw.addPush(name);
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
|
||||
addScriptRuntimeInvoke(
|
||||
"newCatchScope",
|
||||
"(Ljava/lang/Throwable;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"Ljava/lang/String;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
cfw.addAStore(local);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.THROW:
|
||||
visitThrow(node, child);
|
||||
generateExpression(child, node);
|
||||
cfw.add(ByteCode.NEW,
|
||||
"org/mozilla/javascript/JavaScriptException");
|
||||
cfw.add(ByteCode.DUP_X1);
|
||||
cfw.add(ByteCode.SWAP);
|
||||
cfw.addPush(scriptOrFn.getSourceName());
|
||||
cfw.addPush(itsLineNumber);
|
||||
cfw.addInvoke(
|
||||
ByteCode.INVOKESPECIAL,
|
||||
"org/mozilla/javascript/JavaScriptException",
|
||||
"<init>",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;I)V");
|
||||
cfw.add(ByteCode.ATHROW);
|
||||
break;
|
||||
|
||||
case Token.RETHROW:
|
||||
|
@ -1504,11 +1543,23 @@ class BodyCodegen
|
|||
break;
|
||||
|
||||
case Token.ENTERWITH:
|
||||
visitEnterWith(node, child);
|
||||
generateExpression(child, node);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke(
|
||||
"enterWith",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
cfw.addAStore(variableObjectLocal);
|
||||
break;
|
||||
|
||||
case Token.LEAVEWITH:
|
||||
visitLeaveWith(node, child);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke(
|
||||
"leaveWith",
|
||||
"(Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
cfw.addAStore(variableObjectLocal);
|
||||
break;
|
||||
|
||||
case Token.ENUM_INIT_KEYS:
|
||||
|
@ -1547,7 +1598,10 @@ class BodyCodegen
|
|||
break;
|
||||
|
||||
case Token.TARGET:
|
||||
visitTarget((Node.Target)node);
|
||||
{
|
||||
int label = getTargetLabel((Node.Target)node);
|
||||
cfw.markLabel(label);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.JSR:
|
||||
|
@ -1558,7 +1612,17 @@ class BodyCodegen
|
|||
break;
|
||||
|
||||
case Token.FINALLY:
|
||||
visitFinally(node, child);
|
||||
{
|
||||
//Save return address in a new local where
|
||||
int finallyRegister = getNewWordLocal();
|
||||
cfw.addAStore(finallyRegister);
|
||||
while (child != null) {
|
||||
generateStatement(child, node);
|
||||
child = child.getNext();
|
||||
}
|
||||
cfw.add(ByteCode.RET, finallyRegister);
|
||||
releaseWordLocal((short)finallyRegister);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1589,27 +1653,68 @@ class BodyCodegen
|
|||
break;
|
||||
|
||||
case Token.NAME:
|
||||
visitName(node);
|
||||
{
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
cfw.addPush(node.getString());
|
||||
addScriptRuntimeInvoke(
|
||||
"name",
|
||||
"(Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"Ljava/lang/String;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.CALL:
|
||||
case Token.NEW: {
|
||||
int specialType = node.getIntProp(Node.SPECIALCALL_PROP,
|
||||
Node.NON_SPECIALCALL);
|
||||
if (specialType == Node.NON_SPECIALCALL) {
|
||||
visitCall(node, type, child);
|
||||
} else {
|
||||
visitSpecialCall(node, type, specialType, child);
|
||||
case Token.NEW:
|
||||
{
|
||||
int specialType = node.getIntProp(Node.SPECIALCALL_PROP,
|
||||
Node.NON_SPECIALCALL);
|
||||
if (specialType == Node.NON_SPECIALCALL) {
|
||||
OptFunctionNode target;
|
||||
target = (OptFunctionNode)node.getProp(
|
||||
Node.DIRECTCALL_PROP);
|
||||
|
||||
if (target != null) {
|
||||
visitOptimizedCall(node, target, type, child);
|
||||
} else if (type == Token.CALL) {
|
||||
visitStandardCall(node, child);
|
||||
} else {
|
||||
visitStandardNew(node, child);
|
||||
}
|
||||
} else {
|
||||
visitSpecialCall(node, type, specialType, child);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.REF_CALL:
|
||||
visitRefCall(node, type, child);
|
||||
generateFunctionAndThisObj(child, node);
|
||||
// stack: ... functionObj thisObj
|
||||
child = child.getNext();
|
||||
generateCallArgArray(node, child, false);
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke(
|
||||
"referenceCall",
|
||||
"(Lorg/mozilla/javascript/Function;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"[Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
break;
|
||||
|
||||
case Token.NUMBER:
|
||||
visitNumber(node);
|
||||
{
|
||||
double num = node.getDouble();
|
||||
if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
|
||||
cfw.addPush(num);
|
||||
} else {
|
||||
codegen.pushNumberAsObject(cfw, num);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.STRING:
|
||||
|
@ -1639,7 +1744,24 @@ class BodyCodegen
|
|||
break;
|
||||
|
||||
case Token.REGEXP:
|
||||
visitRegexp(node);
|
||||
{
|
||||
int i = node.getExistingIntProp(Node.REGEXP_PROP);
|
||||
// Scripts can not use REGEXP_ARRAY_FIELD_NAME since
|
||||
// it it will make script.exec non-reentrant so they
|
||||
// store regexp array in a local variable while
|
||||
// functions always access precomputed
|
||||
// REGEXP_ARRAY_FIELD_NAME not to consume locals
|
||||
if (fnCurrent == null) {
|
||||
cfw.addALoad(scriptRegexpLocal);
|
||||
} else {
|
||||
cfw.addALoad(funObjLocal);
|
||||
cfw.add(ByteCode.GETFIELD, codegen.mainClassName,
|
||||
Codegen.REGEXP_ARRAY_FIELD_NAME,
|
||||
Codegen.REGEXP_ARRAY_FIELD_TYPE);
|
||||
}
|
||||
cfw.addPush(i);
|
||||
cfw.add(ByteCode.AALOAD);
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.COMMA: {
|
||||
|
@ -1875,11 +1997,35 @@ class BodyCodegen
|
|||
break;
|
||||
|
||||
case Token.GETELEM:
|
||||
visitGetElem(node, child);
|
||||
generateExpression(child, node); // object
|
||||
generateExpression(child.getNext(), node); // id
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
|
||||
addOptRuntimeInvoke(
|
||||
"getObjectIndex",
|
||||
"(Ljava/lang/Object;D"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
else {
|
||||
addScriptRuntimeInvoke(
|
||||
"getObjectElem",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.GET_REF:
|
||||
visitGetRef(node, child);
|
||||
generateExpression(child, node); // reference
|
||||
addScriptRuntimeInvoke(
|
||||
"getReference",
|
||||
"(Ljava/lang/Object;"
|
||||
+")Ljava/lang/Object;");
|
||||
break;
|
||||
|
||||
case Token.GETVAR:
|
||||
|
@ -1906,7 +2052,23 @@ class BodyCodegen
|
|||
|
||||
case Token.SET_REF:
|
||||
case Token.SET_REF_OP:
|
||||
visitSetRef(type, node, child);
|
||||
{
|
||||
generateExpression(child, node);
|
||||
child = child.getNext();
|
||||
if (type == Token.SET_REF_OP) {
|
||||
cfw.add(ByteCode.DUP);
|
||||
addScriptRuntimeInvoke(
|
||||
"getReference",
|
||||
"(Ljava/lang/Object;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
generateExpression(child, node);
|
||||
addScriptRuntimeInvoke(
|
||||
"setReference",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Ljava/lang/Object;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.DEL_REF:
|
||||
|
@ -1931,7 +2093,22 @@ class BodyCodegen
|
|||
break;
|
||||
|
||||
case Token.BINDNAME:
|
||||
visitBind(node, child);
|
||||
{
|
||||
while (child != null) {
|
||||
generateExpression(child, node);
|
||||
child = child.getNext();
|
||||
}
|
||||
// Generate code for "ScriptRuntime.bind(varObj, "s")"
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
cfw.addPush(node.getString());
|
||||
addScriptRuntimeInvoke(
|
||||
"bind",
|
||||
"(Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"Ljava/lang/String;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.LOCAL_LOAD:
|
||||
|
@ -1939,11 +2116,33 @@ class BodyCodegen
|
|||
break;
|
||||
|
||||
case Token.SPECIAL_REF:
|
||||
visitSpecialRef(node, child);
|
||||
{
|
||||
String special
|
||||
= (String)node.getProp(Node.SPECIAL_PROP_PROP);
|
||||
generateExpression(child, node);
|
||||
cfw.addPush(special);
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke("specialReference",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Ljava/lang/String;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.XML_REF:
|
||||
visitXMLRef(node, child);
|
||||
{
|
||||
generateExpression(child, node);
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke("xmlReference",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
break;
|
||||
|
||||
case Token.DOTQUERY:
|
||||
|
@ -2142,12 +2341,6 @@ class BodyCodegen
|
|||
return target.labelId;
|
||||
}
|
||||
|
||||
private void visitTarget(Node.Target target)
|
||||
{
|
||||
int label = getTargetLabel(target);
|
||||
cfw.markLabel(label);
|
||||
}
|
||||
|
||||
private void visitGOTO(Node.Jump node, int type, Node child)
|
||||
{
|
||||
Node.Target target = node.target;
|
||||
|
@ -2168,39 +2361,6 @@ class BodyCodegen
|
|||
}
|
||||
}
|
||||
|
||||
private void visitFinally(Node node, Node child)
|
||||
{
|
||||
//Save return address in a new local where
|
||||
int finallyRegister = getNewWordLocal();
|
||||
cfw.addAStore(finallyRegister);
|
||||
while (child != null) {
|
||||
generateStatement(child, node);
|
||||
child = child.getNext();
|
||||
}
|
||||
cfw.add(ByteCode.RET, finallyRegister);
|
||||
releaseWordLocal((short)finallyRegister);
|
||||
}
|
||||
|
||||
private void visitEnterWith(Node node, Node child)
|
||||
{
|
||||
generateExpression(child, node);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke("enterWith",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
cfw.addAStore(variableObjectLocal);
|
||||
}
|
||||
|
||||
private void visitLeaveWith(Node node, Node child)
|
||||
{
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke("leaveWith",
|
||||
"(Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
cfw.addAStore(variableObjectLocal);
|
||||
}
|
||||
|
||||
private void visitArrayLiteral(Node node, Node child)
|
||||
{
|
||||
int count = 0;
|
||||
|
@ -2274,20 +2434,6 @@ class BodyCodegen
|
|||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
}
|
||||
|
||||
private void visitCall(Node node, int type, Node child)
|
||||
{
|
||||
OptFunctionNode
|
||||
target = (OptFunctionNode)node.getProp(Node.DIRECTCALL_PROP);
|
||||
|
||||
if (target != null) {
|
||||
visitOptimizedCall(node, target, type, child);
|
||||
} else if (type == Token.CALL) {
|
||||
visitStandardCall(node, child);
|
||||
} else {
|
||||
visitStandardNew(node, child);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitSpecialCall(Node node, int type, int specialType,
|
||||
Node child)
|
||||
{
|
||||
|
@ -2341,23 +2487,6 @@ class BodyCodegen
|
|||
addOptRuntimeInvoke(methodName, callSignature);
|
||||
}
|
||||
|
||||
private void visitRefCall(Node node, int type, Node child)
|
||||
{
|
||||
generateFunctionAndThisObj(child, node);
|
||||
// stack: ... functionObj thisObj
|
||||
child = child.getNext();
|
||||
generateCallArgArray(node, child, false);
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke("referenceCall",
|
||||
"(Lorg/mozilla/javascript/Function;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"[Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
private void visitStandardCall(Node node, Node child)
|
||||
{
|
||||
if (node.getType() != Token.CALL) throw Codegen.badTree();
|
||||
|
@ -2867,23 +2996,6 @@ Else pass the JS object in the aReg and 0.0 in the dReg.
|
|||
cfw.add(ByteCode.GOTO, catchLabel);
|
||||
}
|
||||
|
||||
private void visitThrow(Node node, Node child)
|
||||
{
|
||||
generateExpression(child, node);
|
||||
cfw.add(ByteCode.NEW,
|
||||
"org/mozilla/javascript/JavaScriptException");
|
||||
cfw.add(ByteCode.DUP_X1);
|
||||
cfw.add(ByteCode.SWAP);
|
||||
cfw.addPush(scriptOrFn.getSourceName());
|
||||
cfw.addPush(itsLineNumber);
|
||||
cfw.addInvoke(ByteCode.INVOKESPECIAL,
|
||||
"org/mozilla/javascript/JavaScriptException",
|
||||
"<init>",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;I)V");
|
||||
|
||||
cfw.add(ByteCode.ATHROW);
|
||||
}
|
||||
|
||||
private void visitSwitch(Node.Jump switchNode, Node child)
|
||||
{
|
||||
// See comments in IRFactory.createSwitch() for description
|
||||
|
@ -3397,77 +3509,6 @@ Else pass the JS object in the aReg and 0.0 in the dReg.
|
|||
if (stackInitial != cfw.getStackTop()) throw Codegen.badTree();
|
||||
}
|
||||
|
||||
private void visitNumber(Node node)
|
||||
{
|
||||
double num = node.getDouble();
|
||||
if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
|
||||
cfw.addPush(num);
|
||||
} else {
|
||||
codegen.pushNumberAsObject(cfw, num);
|
||||
}
|
||||
}
|
||||
|
||||
private void visitRegexp(Node node)
|
||||
{
|
||||
int i = node.getExistingIntProp(Node.REGEXP_PROP);
|
||||
// Scripts can not use REGEXP_ARRAY_FIELD_NAME since
|
||||
// it it will make script.exec non-reentrant so they
|
||||
// store regexp array in a local variable while
|
||||
// functions always access precomputed REGEXP_ARRAY_FIELD_NAME
|
||||
// not to consume locals
|
||||
if (fnCurrent == null) {
|
||||
cfw.addALoad(scriptRegexpLocal);
|
||||
} else {
|
||||
cfw.addALoad(funObjLocal);
|
||||
cfw.add(ByteCode.GETFIELD, codegen.mainClassName,
|
||||
Codegen.REGEXP_ARRAY_FIELD_NAME,
|
||||
Codegen.REGEXP_ARRAY_FIELD_TYPE);
|
||||
}
|
||||
cfw.addPush(i);
|
||||
cfw.add(ByteCode.AALOAD);
|
||||
}
|
||||
|
||||
private void visitCatchScope(Node node, Node child)
|
||||
{
|
||||
int local = getLocalBlockRegister(node);
|
||||
int scopeIndex = node.getExistingIntProp(Node.CATCH_SCOPE_PROP);
|
||||
|
||||
String name = child.getString(); // name of exception variable
|
||||
child = child.getNext();
|
||||
generateExpression(child, node); // load expression object
|
||||
if (scopeIndex == 0) {
|
||||
cfw.add(ByteCode.ACONST_NULL);
|
||||
} else {
|
||||
// Load previous catch scope object
|
||||
cfw.addALoad(local);
|
||||
}
|
||||
cfw.addPush(name);
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
|
||||
addScriptRuntimeInvoke("newCatchScope",
|
||||
"(Ljava/lang/Throwable;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"Ljava/lang/String;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
cfw.addAStore(local);
|
||||
}
|
||||
|
||||
private void visitName(Node node)
|
||||
{
|
||||
cfw.addALoad(contextLocal); // push cx
|
||||
cfw.addALoad(variableObjectLocal); // get variable object
|
||||
cfw.addPush(node.getString()); // push name
|
||||
addScriptRuntimeInvoke(
|
||||
"name",
|
||||
"(Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"Ljava/lang/String;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
private void visitSetName(Node node, Node child)
|
||||
{
|
||||
String name = node.getFirstChild().getString();
|
||||
|
@ -3609,38 +3650,6 @@ Else pass the JS object in the aReg and 0.0 in the dReg.
|
|||
}
|
||||
}
|
||||
|
||||
private void visitGetElem(Node node, Node child)
|
||||
{
|
||||
generateExpression(child, node); // object
|
||||
generateExpression(child.getNext(), node); // id
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
|
||||
addOptRuntimeInvoke(
|
||||
"getObjectIndex",
|
||||
"(Ljava/lang/Object;D"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
else {
|
||||
addScriptRuntimeInvoke(
|
||||
"getObjectElem",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
}
|
||||
|
||||
private void visitGetRef(Node node, Node child)
|
||||
{
|
||||
generateExpression(child, node); // reference
|
||||
addScriptRuntimeInvoke(
|
||||
"getReference", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
private void visitSetProp(int type, Node node, Node child)
|
||||
{
|
||||
Node objectChild = child;
|
||||
|
@ -3754,65 +3763,6 @@ Else pass the JS object in the aReg and 0.0 in the dReg.
|
|||
}
|
||||
}
|
||||
|
||||
private void visitSetRef(int type, Node node, Node child)
|
||||
{
|
||||
generateExpression(child, node);
|
||||
child = child.getNext();
|
||||
if (type == Token.SET_REF_OP) {
|
||||
cfw.add(ByteCode.DUP);
|
||||
addScriptRuntimeInvoke(
|
||||
"getReference", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
}
|
||||
generateExpression(child, node);
|
||||
addScriptRuntimeInvoke(
|
||||
"setReference",
|
||||
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
private void visitBind(Node node, Node child)
|
||||
{
|
||||
while (child != null) {
|
||||
generateExpression(child, node);
|
||||
child = child.getNext();
|
||||
}
|
||||
// Generate code for "ScriptRuntime.bind(varObj, "s")"
|
||||
cfw.addALoad(contextLocal); // push cx
|
||||
cfw.addALoad(variableObjectLocal); // push variable object
|
||||
cfw.addPush(node.getString()); // push name
|
||||
addScriptRuntimeInvoke("bind",
|
||||
"(Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"Ljava/lang/String;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
}
|
||||
|
||||
private void visitSpecialRef(Node node, Node child)
|
||||
{
|
||||
String special = (String)node.getProp(Node.SPECIAL_PROP_PROP);
|
||||
generateExpression(child, node);
|
||||
cfw.addPush(special);
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke("specialReference",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Ljava/lang/String;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
private void visitXMLRef(Node node, Node child)
|
||||
{
|
||||
generateExpression(child, node);
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke("xmlReference",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
private void visitDotQuery(Node node, Node child)
|
||||
{
|
||||
updateLineNumber(node);
|
||||
|
|
Загрузка…
Ссылка в новой задаче