зеркало из 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,9 +535,11 @@ public class Interpreter
|
||||||
Node child = node.getFirstChild();
|
Node child = node.getFirstChild();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
||||||
case Token.FUNCTION: {
|
case Token.FUNCTION:
|
||||||
|
{
|
||||||
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
|
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
|
||||||
int fnType = scriptOrFn.getFunctionNode(fnIndex).getFunctionType();
|
int fnType = scriptOrFn.getFunctionNode(fnIndex).
|
||||||
|
getFunctionType();
|
||||||
// Only function expressions or function expression
|
// Only function expressions or function expression
|
||||||
// statements needs closure code creating new function
|
// statements needs closure code creating new function
|
||||||
// object on stack as function statements are initialized
|
// object on stack as function statements are initialized
|
||||||
|
@ -551,8 +553,8 @@ public class Interpreter
|
||||||
throw Kit.codeBug();
|
throw Kit.codeBug();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.SCRIPT:
|
case Token.SCRIPT:
|
||||||
case Token.LABEL:
|
case Token.LABEL:
|
||||||
|
@ -600,7 +602,32 @@ public class Interpreter
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.SWITCH:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.TARGET:
|
case Token.TARGET:
|
||||||
|
@ -608,25 +635,28 @@ public class Interpreter
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.IFEQ :
|
case Token.IFEQ :
|
||||||
case Token.IFNE : {
|
case Token.IFNE :
|
||||||
|
{
|
||||||
Node.Target target = ((Node.Jump)node).target;
|
Node.Target target = ((Node.Jump)node).target;
|
||||||
visitExpression(child, 0);
|
visitExpression(child, 0);
|
||||||
addGoto(target, type);
|
addGoto(target, type);
|
||||||
stackChange(-1);
|
stackChange(-1);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.GOTO: {
|
case Token.GOTO:
|
||||||
|
{
|
||||||
Node.Target target = ((Node.Jump)node).target;
|
Node.Target target = ((Node.Jump)node).target;
|
||||||
addGoto(target, type);
|
addGoto(target, type);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.JSR: {
|
case Token.JSR:
|
||||||
|
{
|
||||||
Node.Target target = ((Node.Jump)node).target;
|
Node.Target target = ((Node.Jump)node).target;
|
||||||
addGoto(target, Icode_GOSUB);
|
addGoto(target, Icode_GOSUB);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.FINALLY:
|
case Token.FINALLY:
|
||||||
{
|
{
|
||||||
|
@ -652,7 +682,33 @@ public class Interpreter
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.TRY:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.CATCH_SCOPE:
|
case Token.CATCH_SCOPE:
|
||||||
|
@ -722,7 +778,8 @@ public class Interpreter
|
||||||
int savedStackDepth = itsStackDepth;
|
int savedStackDepth = itsStackDepth;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
||||||
case Token.FUNCTION: {
|
case Token.FUNCTION:
|
||||||
|
{
|
||||||
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
|
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
|
||||||
FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
|
FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
|
||||||
// See comments in visitStatement for Token.FUNCTION case
|
// See comments in visitStatement for Token.FUNCTION case
|
||||||
|
@ -731,17 +788,19 @@ public class Interpreter
|
||||||
}
|
}
|
||||||
addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
|
addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
|
||||||
stackChange(1);
|
stackChange(1);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.LOCAL_LOAD: {
|
case Token.LOCAL_LOAD:
|
||||||
|
{
|
||||||
int localIndex = getLocalBlockRef(node);
|
int localIndex = getLocalBlockRef(node);
|
||||||
addIndexOp(Token.LOCAL_LOAD, localIndex);
|
addIndexOp(Token.LOCAL_LOAD, localIndex);
|
||||||
stackChange(1);
|
stackChange(1);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.COMMA: {
|
case Token.COMMA:
|
||||||
|
{
|
||||||
Node lastChild = node.getLastChild();
|
Node lastChild = node.getLastChild();
|
||||||
while (child != lastChild) {
|
while (child != lastChild) {
|
||||||
visitExpression(child, 0);
|
visitExpression(child, 0);
|
||||||
|
@ -751,8 +810,8 @@ public class Interpreter
|
||||||
}
|
}
|
||||||
// Preserve tail context flag if any
|
// Preserve tail context flag if any
|
||||||
visitExpression(child, contextFlags & ECF_TAIL);
|
visitExpression(child, contextFlags & ECF_TAIL);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.USE_STACK:
|
case Token.USE_STACK:
|
||||||
// Indicates that stack was modified externally,
|
// Indicates that stack was modified externally,
|
||||||
|
@ -763,11 +822,50 @@ public class Interpreter
|
||||||
case Token.CALL:
|
case Token.CALL:
|
||||||
case Token.NEW:
|
case Token.NEW:
|
||||||
case Token.REF_CALL:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.AND:
|
case Token.AND:
|
||||||
case Token.OR: {
|
case Token.OR:
|
||||||
|
{
|
||||||
visitExpression(child, 0);
|
visitExpression(child, 0);
|
||||||
addIcode(Icode_DUP);
|
addIcode(Icode_DUP);
|
||||||
stackChange(1);
|
stackChange(1);
|
||||||
|
@ -781,10 +879,11 @@ public class Interpreter
|
||||||
// Preserve tail context flag if any
|
// Preserve tail context flag if any
|
||||||
visitExpression(child, contextFlags & ECF_TAIL);
|
visitExpression(child, contextFlags & ECF_TAIL);
|
||||||
resolveForwardGoto(afterSecondJumpStart);
|
resolveForwardGoto(afterSecondJumpStart);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.HOOK: {
|
case Token.HOOK:
|
||||||
|
{
|
||||||
Node ifThen = child.getNext();
|
Node ifThen = child.getNext();
|
||||||
Node ifElse = ifThen.getNext();
|
Node ifElse = ifThen.getNext();
|
||||||
visitExpression(child, 0);
|
visitExpression(child, 0);
|
||||||
|
@ -800,19 +899,26 @@ public class Interpreter
|
||||||
// Preserve tail context flag if any
|
// Preserve tail context flag if any
|
||||||
visitExpression(ifElse, contextFlags & ECF_TAIL);
|
visitExpression(ifElse, contextFlags & ECF_TAIL);
|
||||||
resolveForwardGoto(afterElseJumpStart);
|
resolveForwardGoto(afterElseJumpStart);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.GETPROP:
|
case Token.GETPROP:
|
||||||
visitGetProp(node, child);
|
visitExpression(child, 0);
|
||||||
|
child = child.getNext();
|
||||||
|
addStringOp(Token.GETPROP, child.getString());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.GETELEM:
|
case Token.GETELEM:
|
||||||
visitGetElem(node, child);
|
visitExpression(child, 0);
|
||||||
|
child = child.getNext();
|
||||||
|
visitExpression(child, 0);
|
||||||
|
addToken(Token.GETELEM);
|
||||||
|
stackChange(-1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.GET_REF:
|
case Token.GET_REF:
|
||||||
visitGetRef(node, child);
|
visitExpression(child, 0);
|
||||||
|
addToken(Token.GET_REF);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.DELPROP:
|
case Token.DELPROP:
|
||||||
|
@ -861,7 +967,8 @@ public class Interpreter
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.SETPROP:
|
case Token.SETPROP:
|
||||||
case Token.SETPROP_OP: {
|
case Token.SETPROP_OP:
|
||||||
|
{
|
||||||
visitExpression(child, 0);
|
visitExpression(child, 0);
|
||||||
child = child.getNext();
|
child = child.getNext();
|
||||||
String property = child.getString();
|
String property = child.getString();
|
||||||
|
@ -876,8 +983,8 @@ public class Interpreter
|
||||||
visitExpression(child, 0);
|
visitExpression(child, 0);
|
||||||
addStringOp(Token.SETPROP, property);
|
addStringOp(Token.SETPROP, property);
|
||||||
stackChange(-1);
|
stackChange(-1);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.SETELEM:
|
case Token.SETELEM:
|
||||||
case Token.SETELEM_OP:
|
case Token.SETELEM_OP:
|
||||||
|
@ -914,17 +1021,19 @@ public class Interpreter
|
||||||
stackChange(-1);
|
stackChange(-1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.SETNAME: {
|
case Token.SETNAME:
|
||||||
|
{
|
||||||
String name = child.getString();
|
String name = child.getString();
|
||||||
visitExpression(child, 0);
|
visitExpression(child, 0);
|
||||||
child = child.getNext();
|
child = child.getNext();
|
||||||
visitExpression(child, 0);
|
visitExpression(child, 0);
|
||||||
addStringOp(Token.SETNAME, name);
|
addStringOp(Token.SETNAME, name);
|
||||||
stackChange(-1);
|
stackChange(-1);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.TYPEOFNAME: {
|
case Token.TYPEOFNAME:
|
||||||
|
{
|
||||||
String name = node.getString();
|
String name = node.getString();
|
||||||
int index = -1;
|
int index = -1;
|
||||||
// use typeofname if an activation frame exists
|
// use typeofname if an activation frame exists
|
||||||
|
@ -939,8 +1048,8 @@ public class Interpreter
|
||||||
stackChange(1);
|
stackChange(1);
|
||||||
addToken(Token.TYPEOF);
|
addToken(Token.TYPEOF);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.BINDNAME:
|
case Token.BINDNAME:
|
||||||
case Token.NAME:
|
case Token.NAME:
|
||||||
|
@ -955,10 +1064,36 @@ public class Interpreter
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.NUMBER:
|
case Token.NUMBER:
|
||||||
visitNumber(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);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.GETVAR: {
|
case Token.GETVAR:
|
||||||
|
{
|
||||||
String name = node.getString();
|
String name = node.getString();
|
||||||
if (itsData.itsNeedsActivation) {
|
if (itsData.itsNeedsActivation) {
|
||||||
// SETVAR handled this by turning into a SETPROP, but
|
// SETVAR handled this by turning into a SETPROP, but
|
||||||
|
@ -973,10 +1108,11 @@ public class Interpreter
|
||||||
addVarOp(Token.GETVAR, index);
|
addVarOp(Token.GETVAR, index);
|
||||||
stackChange(1);
|
stackChange(1);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.SETVAR: {
|
case Token.SETVAR:
|
||||||
|
{
|
||||||
if (itsData.itsNeedsActivation) {
|
if (itsData.itsNeedsActivation) {
|
||||||
child.setType(Token.BINDNAME);
|
child.setType(Token.BINDNAME);
|
||||||
node.setType(Token.SETNAME);
|
node.setType(Token.SETNAME);
|
||||||
|
@ -988,8 +1124,8 @@ public class Interpreter
|
||||||
int index = scriptOrFn.getParamOrVarIndex(name);
|
int index = scriptOrFn.getParamOrVarIndex(name);
|
||||||
addVarOp(Token.SETVAR, index);
|
addVarOp(Token.SETVAR, index);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.NULL:
|
case Token.NULL:
|
||||||
case Token.THIS:
|
case Token.THIS:
|
||||||
|
@ -1006,24 +1142,26 @@ public class Interpreter
|
||||||
stackChange(1);
|
stackChange(1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.REGEXP: {
|
case Token.REGEXP:
|
||||||
|
{
|
||||||
int index = node.getExistingIntProp(Node.REGEXP_PROP);
|
int index = node.getExistingIntProp(Node.REGEXP_PROP);
|
||||||
addIndexOp(Token.REGEXP, index);
|
addIndexOp(Token.REGEXP, index);
|
||||||
stackChange(1);
|
stackChange(1);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.ARRAYLIT:
|
case Token.ARRAYLIT:
|
||||||
case Token.OBJECTLIT:
|
case Token.OBJECTLIT:
|
||||||
visitLiteral(node, child);
|
visitLiteral(node, child);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.SPECIAL_REF: {
|
case Token.SPECIAL_REF:
|
||||||
visitExpression(child, 0);
|
{
|
||||||
String special = (String)node.getProp(Node.SPECIAL_PROP_PROP);
|
String special = (String)node.getProp(Node.SPECIAL_PROP_PROP);
|
||||||
|
visitExpression(child, 0);
|
||||||
addStringOp(Token.SPECIAL_REF, special);
|
addStringOp(Token.SPECIAL_REF, special);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.XML_REF:
|
case Token.XML_REF:
|
||||||
visitExpression(child, 0);
|
visitExpression(child, 0);
|
||||||
|
@ -1031,7 +1169,16 @@ public class Interpreter
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.DOTQUERY:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.DEFAULTNAMESPACE :
|
case Token.DEFAULTNAMESPACE :
|
||||||
|
@ -1043,16 +1190,16 @@ public class Interpreter
|
||||||
addToken(type);
|
addToken(type);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.COLONCOLON : {
|
case Token.COLONCOLON :
|
||||||
|
{
|
||||||
if (child.getType() != Token.STRING)
|
if (child.getType() != Token.STRING)
|
||||||
throw badTree(child);
|
throw badTree(child);
|
||||||
String namespace = child.getString();
|
String namespace = child.getString();
|
||||||
child = child.getNext();
|
child = child.getNext();
|
||||||
visitExpression(child, 0);
|
visitExpression(child, 0);
|
||||||
addStringOp(Token.COLONCOLON, namespace);
|
addStringOp(Token.COLONCOLON, namespace);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw badTree(node);
|
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)
|
private void generateCallFunAndThis(Node left)
|
||||||
{
|
{
|
||||||
// Generate code to place on stack function and thisObj
|
// 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)
|
private void visitIncDec(Node node, Node child)
|
||||||
{
|
{
|
||||||
int incrDecrMask = node.getExistingIntProp(Node.INCRDECR_PROP);
|
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)
|
private void visitLiteral(Node node, Node child)
|
||||||
{
|
{
|
||||||
int type = node.getType();
|
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)
|
private int getLocalBlockRef(Node node)
|
||||||
{
|
{
|
||||||
Node localBlock = (Node)node.getProp(Node.LOCAL_BLOCK_PROP);
|
Node localBlock = (Node)node.getProp(Node.LOCAL_BLOCK_PROP);
|
||||||
|
|
|
@ -1022,90 +1022,6 @@ public class ScriptRuntime {
|
||||||
return (char)i;
|
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
|
// XXX: this is until setDefaultNamespace will learn how to store NS
|
||||||
// properly and separates namespace form Scriptable.get etc.
|
// properly and separates namespace form Scriptable.get etc.
|
||||||
private static final String DEFAULT_NS_TAG = "__default_namespace__";
|
private static final String DEFAULT_NS_TAG = "__default_namespace__";
|
||||||
|
@ -2982,26 +2898,95 @@ public class ScriptRuntime {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Scriptable newCatchScope(Throwable exception,
|
public static Scriptable newCatchScope(Throwable t,
|
||||||
Scriptable lastCatchScope,
|
Scriptable lastCatchScope,
|
||||||
String exceptionName,
|
String exceptionName,
|
||||||
Context cx, Scriptable scope)
|
Context cx, Scriptable scope)
|
||||||
{
|
{
|
||||||
Object obj;
|
Object obj;
|
||||||
if (lastCatchScope == null) {
|
boolean cacheObj;
|
||||||
obj = getCatchObject(cx, scope, exception);
|
|
||||||
|
getObj:
|
||||||
|
if (t instanceof JavaScriptException) {
|
||||||
|
cacheObj = false;
|
||||||
|
obj = ((JavaScriptException)t).getValue();
|
||||||
} else {
|
} else {
|
||||||
|
cacheObj = true;
|
||||||
|
|
||||||
|
// Create wrapper object unless it was associated with
|
||||||
|
// the previous scope object
|
||||||
|
|
||||||
|
if (lastCatchScope != null) {
|
||||||
NativeObject last = (NativeObject)lastCatchScope;
|
NativeObject last = (NativeObject)lastCatchScope;
|
||||||
obj = last.getAssociatedValue(exception);
|
obj = last.getAssociatedValue(t);
|
||||||
if (obj == null) Kit.codeBug();
|
if (obj == null) Kit.codeBug();
|
||||||
|
break getObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
NativeObject catchScope = new NativeObject();
|
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 catchScopeObject = new NativeObject();
|
||||||
// See ECMA 12.4
|
// See ECMA 12.4
|
||||||
catchScope.defineProperty(
|
catchScopeObject.defineProperty(
|
||||||
exceptionName, obj, ScriptableObject.PERMANENT);
|
exceptionName, obj, ScriptableObject.PERMANENT);
|
||||||
catchScope.associateValue(exception, obj);
|
if (cacheObj) {
|
||||||
return catchScope;
|
catchScopeObject.associateValue(t, obj);
|
||||||
|
}
|
||||||
|
return catchScopeObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Scriptable enterWith(Object value, Scriptable scope)
|
public static Scriptable enterWith(Object value, Scriptable scope)
|
||||||
|
|
|
@ -1192,7 +1192,7 @@ class BodyCodegen
|
||||||
localsMax = firstFreeLocal;
|
localsMax = firstFreeLocal;
|
||||||
|
|
||||||
if (fnCurrent == null) {
|
if (fnCurrent == null) {
|
||||||
// See comments in visitRegexp
|
// See comments in case Token.REGEXP
|
||||||
if (scriptOrFn.getRegexpCount() != 0) {
|
if (scriptOrFn.getRegexpCount() != 0) {
|
||||||
scriptRegexpLocal = getNewWordLocal();
|
scriptRegexpLocal = getNewWordLocal();
|
||||||
codegen.pushRegExpArray(cfw, scriptOrFn, contextLocal,
|
codegen.pushRegExpArray(cfw, scriptOrFn, contextLocal,
|
||||||
|
@ -1470,11 +1470,50 @@ class BodyCodegen
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.CATCH_SCOPE:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.THROW:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.RETHROW:
|
case Token.RETHROW:
|
||||||
|
@ -1504,11 +1543,23 @@ class BodyCodegen
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.ENTERWITH:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.LEAVEWITH:
|
case Token.LEAVEWITH:
|
||||||
visitLeaveWith(node, child);
|
cfw.addALoad(variableObjectLocal);
|
||||||
|
addScriptRuntimeInvoke(
|
||||||
|
"leaveWith",
|
||||||
|
"(Lorg/mozilla/javascript/Scriptable;"
|
||||||
|
+")Lorg/mozilla/javascript/Scriptable;");
|
||||||
|
cfw.addAStore(variableObjectLocal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.ENUM_INIT_KEYS:
|
case Token.ENUM_INIT_KEYS:
|
||||||
|
@ -1547,7 +1598,10 @@ class BodyCodegen
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.TARGET:
|
case Token.TARGET:
|
||||||
visitTarget((Node.Target)node);
|
{
|
||||||
|
int label = getTargetLabel((Node.Target)node);
|
||||||
|
cfw.markLabel(label);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.JSR:
|
case Token.JSR:
|
||||||
|
@ -1558,7 +1612,17 @@ class BodyCodegen
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.FINALLY:
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1589,27 +1653,68 @@ class BodyCodegen
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.NAME:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.CALL:
|
case Token.CALL:
|
||||||
case Token.NEW: {
|
case Token.NEW:
|
||||||
|
{
|
||||||
int specialType = node.getIntProp(Node.SPECIALCALL_PROP,
|
int specialType = node.getIntProp(Node.SPECIALCALL_PROP,
|
||||||
Node.NON_SPECIALCALL);
|
Node.NON_SPECIALCALL);
|
||||||
if (specialType == Node.NON_SPECIALCALL) {
|
if (specialType == Node.NON_SPECIALCALL) {
|
||||||
visitCall(node, type, child);
|
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 {
|
} else {
|
||||||
visitSpecialCall(node, type, specialType, child);
|
visitSpecialCall(node, type, specialType, child);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case Token.REF_CALL:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.NUMBER:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.STRING:
|
case Token.STRING:
|
||||||
|
@ -1639,7 +1744,24 @@ class BodyCodegen
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.REGEXP:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.COMMA: {
|
case Token.COMMA: {
|
||||||
|
@ -1875,11 +1997,35 @@ class BodyCodegen
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.GETELEM:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.GET_REF:
|
case Token.GET_REF:
|
||||||
visitGetRef(node, child);
|
generateExpression(child, node); // reference
|
||||||
|
addScriptRuntimeInvoke(
|
||||||
|
"getReference",
|
||||||
|
"(Ljava/lang/Object;"
|
||||||
|
+")Ljava/lang/Object;");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.GETVAR:
|
case Token.GETVAR:
|
||||||
|
@ -1906,7 +2052,23 @@ class BodyCodegen
|
||||||
|
|
||||||
case Token.SET_REF:
|
case Token.SET_REF:
|
||||||
case Token.SET_REF_OP:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.DEL_REF:
|
case Token.DEL_REF:
|
||||||
|
@ -1931,7 +2093,22 @@ class BodyCodegen
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.BINDNAME:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.LOCAL_LOAD:
|
case Token.LOCAL_LOAD:
|
||||||
|
@ -1939,11 +2116,33 @@ class BodyCodegen
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.SPECIAL_REF:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.XML_REF:
|
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;
|
break;
|
||||||
|
|
||||||
case Token.DOTQUERY:
|
case Token.DOTQUERY:
|
||||||
|
@ -2142,12 +2341,6 @@ class BodyCodegen
|
||||||
return target.labelId;
|
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)
|
private void visitGOTO(Node.Jump node, int type, Node child)
|
||||||
{
|
{
|
||||||
Node.Target target = node.target;
|
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)
|
private void visitArrayLiteral(Node node, Node child)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -2274,20 +2434,6 @@ class BodyCodegen
|
||||||
+")Lorg/mozilla/javascript/Scriptable;");
|
+")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,
|
private void visitSpecialCall(Node node, int type, int specialType,
|
||||||
Node child)
|
Node child)
|
||||||
{
|
{
|
||||||
|
@ -2341,23 +2487,6 @@ class BodyCodegen
|
||||||
addOptRuntimeInvoke(methodName, callSignature);
|
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)
|
private void visitStandardCall(Node node, Node child)
|
||||||
{
|
{
|
||||||
if (node.getType() != Token.CALL) throw Codegen.badTree();
|
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);
|
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)
|
private void visitSwitch(Node.Jump switchNode, Node child)
|
||||||
{
|
{
|
||||||
// See comments in IRFactory.createSwitch() for description
|
// 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();
|
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)
|
private void visitSetName(Node node, Node child)
|
||||||
{
|
{
|
||||||
String name = node.getFirstChild().getString();
|
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)
|
private void visitSetProp(int type, Node node, Node child)
|
||||||
{
|
{
|
||||||
Node objectChild = 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)
|
private void visitDotQuery(Node node, Node child)
|
||||||
{
|
{
|
||||||
updateLineNumber(node);
|
updateLineNumber(node);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче