mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 13:25:37 +00:00
Introduction of generic Reference class to support latter constructions like f(args) = y and f(args)++. For now it is used to implement __proto__ and __parent__ special properties so x.__proto__++ now works
This commit is contained in:
parent
086c591c10
commit
2f00186bd2
@ -375,6 +375,7 @@ class IRFactory
|
||||
case Token.NAME:
|
||||
case Token.GETPROP:
|
||||
case Token.GETELEM:
|
||||
case Token.GET_REF:
|
||||
break;
|
||||
|
||||
case Token.VAR:
|
||||
@ -841,7 +842,7 @@ class IRFactory
|
||||
Node lvalueLeft = Node.newString(Token.BINDNAME, s);
|
||||
return new Node(Token.SETNAME, lvalueLeft, op);
|
||||
|
||||
} else if (childType == Token.GETELEM) {
|
||||
} else if (childType == Token.GETELEM || childType == Token.GET_REF) {
|
||||
Node n = new Node(nodeType, childNode);
|
||||
int type;
|
||||
if (nodeType == Token.INC) {
|
||||
@ -901,12 +902,11 @@ class IRFactory
|
||||
}
|
||||
}
|
||||
if (special != 0) {
|
||||
Node result = new Node(nodeType, left);
|
||||
result.putIntProp(Node.SPECIAL_PROP_PROP, special);
|
||||
return result;
|
||||
} else {
|
||||
checkActivationName(id, Token.GETPROP);
|
||||
Node ref = new Node(Token.SPECIAL_REF, left);
|
||||
ref.putIntProp(Node.SPECIAL_PROP_PROP, special);
|
||||
return new Node(Token.GET_REF, ref);
|
||||
}
|
||||
checkActivationName(id, Token.GETPROP);
|
||||
break;
|
||||
|
||||
case Token.LB:
|
||||
@ -1070,17 +1070,15 @@ class IRFactory
|
||||
int type;
|
||||
if (nodeType == Token.GETPROP) {
|
||||
type = Token.SETPROP;
|
||||
int special = left.getIntProp(Node.SPECIAL_PROP_PROP, 0);
|
||||
if (special != 0) {
|
||||
Node result = new Node(Token.SETPROP, obj, right);
|
||||
result.putIntProp(Node.SPECIAL_PROP_PROP, special);
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
type = Token.SETELEM;
|
||||
}
|
||||
return new Node(type, obj, id, right);
|
||||
}
|
||||
case Token.GET_REF: {
|
||||
Node ref = left.getFirstChild();
|
||||
return new Node(Token.SET_REF, ref, right);
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO: This should be a ReferenceError--but that's a runtime
|
||||
@ -1129,6 +1127,17 @@ class IRFactory
|
||||
return new Node(type, obj, id, op);
|
||||
}
|
||||
|
||||
case Token.GET_REF: {
|
||||
Node ref = left.getFirstChild();
|
||||
|
||||
Node opLeft = new Node(Token.USE_STACK);
|
||||
if (tonumber) {
|
||||
opLeft = new Node(Token.POS, opLeft);
|
||||
}
|
||||
Node op = new Node(assignOp, opLeft, right);
|
||||
return new Node(Token.SET_REF_OP, ref, op);
|
||||
}
|
||||
|
||||
default:
|
||||
// TODO: This should be a ReferenceError--but that's a runtime
|
||||
// exception. Should we compile an exception into the code?
|
||||
|
@ -69,80 +69,75 @@ public class Interpreter
|
||||
Icode_PROPDEC = -9,
|
||||
Icode_VARDEC = -10,
|
||||
|
||||
Icode_ELEM_PRE_INC = -11,
|
||||
Icode_ELEM_PRE_DEC = -12,
|
||||
Icode_ELEM_POST_INC = -13,
|
||||
Icode_ELEM_POST_DEC = -14,
|
||||
Icode_ELEM_INC_DEC = -11,
|
||||
Icode_REF_INC_DEC = -12,
|
||||
|
||||
// helper codes to deal with activation
|
||||
Icode_SCOPE = -15,
|
||||
Icode_TYPEOFNAME = -16,
|
||||
Icode_SCOPE = -13,
|
||||
Icode_TYPEOFNAME = -14,
|
||||
|
||||
// helper for function calls
|
||||
Icode_NAME_FAST_THIS = -17,
|
||||
Icode_NAME_SLOW_THIS = -18,
|
||||
Icode_PUSH_PARENT = -19,
|
||||
|
||||
// Access to parent scope and prototype
|
||||
Icode_GETPROTO = -20,
|
||||
Icode_GETSCOPEPARENT = -21,
|
||||
Icode_SETPROTO = -22,
|
||||
Icode_SETPARENT = -23,
|
||||
Icode_NAME_FAST_THIS = -15,
|
||||
Icode_NAME_SLOW_THIS = -16,
|
||||
Icode_PUSH_PARENT = -17,
|
||||
|
||||
// Create closure object for nested functions
|
||||
Icode_CLOSURE = -24,
|
||||
Icode_CLOSURE = -18,
|
||||
|
||||
// Special calls
|
||||
Icode_CALLSPECIAL = -25,
|
||||
Icode_CALLSPECIAL = -19,
|
||||
|
||||
// To return undefined value
|
||||
Icode_RETUNDEF = -26,
|
||||
Icode_RETUNDEF = -20,
|
||||
|
||||
// Exception handling implementation
|
||||
Icode_CATCH = -27,
|
||||
Icode_GOSUB = -28,
|
||||
Icode_RETSUB = -29,
|
||||
Icode_CATCH = -21,
|
||||
Icode_GOSUB = -22,
|
||||
Icode_RETSUB = -23,
|
||||
|
||||
// To indicating a line number change in icodes.
|
||||
Icode_LINE = -30,
|
||||
Icode_LINE = -24,
|
||||
|
||||
// To store shorts and ints inline
|
||||
Icode_SHORTNUMBER = -31,
|
||||
Icode_INTNUMBER = -32,
|
||||
Icode_SHORTNUMBER = -25,
|
||||
Icode_INTNUMBER = -26,
|
||||
|
||||
// To create and populate array to hold values for [] and {} literals
|
||||
Icode_LITERAL_NEW = -33,
|
||||
Icode_LITERAL_SET = -34,
|
||||
Icode_LITERAL_NEW = -27,
|
||||
Icode_LITERAL_SET = -28,
|
||||
|
||||
// Array literal with skipped index like [1,,2]
|
||||
Icode_SPARE_ARRAYLIT = -35,
|
||||
Icode_SPARE_ARRAYLIT = -29,
|
||||
|
||||
// Load index register to prepare for the following index operation
|
||||
Icode_REG_IND_C0 = -36,
|
||||
Icode_REG_IND_C1 = -37,
|
||||
Icode_REG_IND_C2 = -38,
|
||||
Icode_REG_IND_C3 = -39,
|
||||
Icode_REG_IND_C4 = -40,
|
||||
Icode_REG_IND_C5 = -41,
|
||||
Icode_REG_IND1 = -42,
|
||||
Icode_REG_IND2 = -43,
|
||||
Icode_REG_IND4 = -44,
|
||||
Icode_REG_IND_C0 = -30,
|
||||
Icode_REG_IND_C1 = -31,
|
||||
Icode_REG_IND_C2 = -32,
|
||||
Icode_REG_IND_C3 = -33,
|
||||
Icode_REG_IND_C4 = -34,
|
||||
Icode_REG_IND_C5 = -35,
|
||||
Icode_REG_IND1 = -36,
|
||||
Icode_REG_IND2 = -37,
|
||||
Icode_REG_IND4 = -38,
|
||||
|
||||
// Load string register to prepare for the following string operation
|
||||
Icode_REG_STR_C0 = -45,
|
||||
Icode_REG_STR_C1 = -46,
|
||||
Icode_REG_STR_C2 = -47,
|
||||
Icode_REG_STR_C3 = -48,
|
||||
Icode_REG_STR1 = -49,
|
||||
Icode_REG_STR2 = -50,
|
||||
Icode_REG_STR4 = -51,
|
||||
Icode_REG_STR_C0 = -39,
|
||||
Icode_REG_STR_C1 = -40,
|
||||
Icode_REG_STR_C2 = -41,
|
||||
Icode_REG_STR_C3 = -42,
|
||||
Icode_REG_STR1 = -43,
|
||||
Icode_REG_STR2 = -44,
|
||||
Icode_REG_STR4 = -45,
|
||||
|
||||
// Version of getvar/setvar that read var index directly from bytecode
|
||||
Icode_GETVAR1 = -52,
|
||||
Icode_SETVAR1 = -53,
|
||||
Icode_GETVAR1 = -46,
|
||||
Icode_SETVAR1 = -47,
|
||||
|
||||
// Construct special reference
|
||||
Icode_SPECIAL_REF = -48,
|
||||
|
||||
// Last icode
|
||||
MIN_ICODE = -53;
|
||||
MIN_ICODE = -48;
|
||||
|
||||
static {
|
||||
// Checks for byte code consistencies, good compiler can eliminate them
|
||||
@ -157,16 +152,6 @@ public class Interpreter
|
||||
System.err.println(str);
|
||||
throw new IllegalStateException(str);
|
||||
}
|
||||
|
||||
if (!(Icode_ELEM_PRE_INC - Node.PRE_INC == Icode_ELEM_PRE_INC
|
||||
&& Icode_ELEM_PRE_INC - Node.PRE_DEC == Icode_ELEM_PRE_DEC
|
||||
&& Icode_ELEM_PRE_INC - Node.POST_INC == Icode_ELEM_POST_INC
|
||||
&& Icode_ELEM_PRE_INC - Node.POST_DEC == Icode_ELEM_POST_DEC))
|
||||
{
|
||||
String str = "Violation of pre/post mapping into elem bytecodes";
|
||||
System.err.println(str);
|
||||
throw new IllegalStateException(str);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean validIcode(int icode)
|
||||
@ -695,12 +680,17 @@ public class Interpreter
|
||||
|
||||
case Token.GETPROP :
|
||||
stackDelta = 1;
|
||||
iCodeTop = visitGetProp(iCodeTop, node, child, false);
|
||||
iCodeTop = visitGetProp(node, child, false, iCodeTop);
|
||||
break;
|
||||
|
||||
case Token.GETELEM :
|
||||
stackDelta = 1;
|
||||
iCodeTop = visitGetElem(iCodeTop, node, child, false);
|
||||
iCodeTop = visitGetElem(node, child, false, iCodeTop);
|
||||
break;
|
||||
|
||||
case Token.GET_REF :
|
||||
stackDelta = 1;
|
||||
iCodeTop = visitGetRef(node, child, iCodeTop);
|
||||
break;
|
||||
|
||||
case Token.DELPROP :
|
||||
@ -754,45 +744,18 @@ public class Interpreter
|
||||
stackDelta = 1;
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
child = child.getNext();
|
||||
int special = node.getIntProp(Node.SPECIAL_PROP_PROP, 0);
|
||||
if (special != 0) {
|
||||
if (type == Token.SETPROP_OP) {
|
||||
iCodeTop = addIcode(Icode_DUP, iCodeTop);
|
||||
if (itsStackDepth > itsData.itsMaxStack)
|
||||
itsData.itsMaxStack = itsStackDepth;
|
||||
if (special == Node.SPECIAL_PROP_PROTO) {
|
||||
iCodeTop = addIcode(Icode_GETPROTO, iCodeTop);
|
||||
} else if (special == Node.SPECIAL_PROP_PARENT) {
|
||||
iCodeTop = addIcode(Icode_GETSCOPEPARENT, iCodeTop);
|
||||
} else {
|
||||
throw badTree(node);
|
||||
}
|
||||
// Compensate for the following USE_STACK
|
||||
itsStackDepth--;
|
||||
}
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
if (special == Node.SPECIAL_PROP_PROTO) {
|
||||
iCodeTop = addIcode(Icode_SETPROTO, iCodeTop);
|
||||
} else if (special == Node.SPECIAL_PROP_PARENT) {
|
||||
iCodeTop = addIcode(Icode_SETPARENT, iCodeTop);
|
||||
} else {
|
||||
throw badTree(node);
|
||||
}
|
||||
itsStackDepth--;
|
||||
} else {
|
||||
String property = child.getString();
|
||||
child = child.getNext();
|
||||
if (type == Token.SETPROP_OP) {
|
||||
iCodeTop = addIcode(Icode_DUP, iCodeTop);
|
||||
stackChange(1);
|
||||
iCodeTop = addStringOp(Token.GETPROP, property, iCodeTop);
|
||||
// Compensate for the following USE_STACK
|
||||
stackChange(-1);
|
||||
}
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
iCodeTop = addStringOp(Token.SETPROP, property, iCodeTop);
|
||||
String property = child.getString();
|
||||
child = child.getNext();
|
||||
if (type == Token.SETPROP_OP) {
|
||||
iCodeTop = addIcode(Icode_DUP, iCodeTop);
|
||||
stackChange(1);
|
||||
iCodeTop = addStringOp(Token.GETPROP, property, iCodeTop);
|
||||
// Compensate for the following USE_STACK
|
||||
stackChange(-1);
|
||||
}
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
iCodeTop = addStringOp(Token.SETPROP, property, iCodeTop);
|
||||
stackChange(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -816,6 +779,23 @@ public class Interpreter
|
||||
stackChange(-2);
|
||||
break;
|
||||
|
||||
case Token.SET_REF :
|
||||
case Token.SET_REF_OP :
|
||||
stackDelta = 1;
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
child = child.getNext();
|
||||
if (type == Token.SET_REF_OP) {
|
||||
iCodeTop = addIcode(Icode_DUP, iCodeTop);
|
||||
stackChange(1);
|
||||
iCodeTop = addToken(Token.GET_REF, iCodeTop);
|
||||
// Compensate for the following USE_STACK
|
||||
stackChange(-1);
|
||||
}
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
iCodeTop = addToken(Token.SET_REF, iCodeTop);
|
||||
stackChange(-1);
|
||||
break;
|
||||
|
||||
case Token.SETNAME :
|
||||
stackDelta = 1;
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
@ -1067,9 +1047,18 @@ public class Interpreter
|
||||
case Token.ARRAYLIT:
|
||||
case Token.OBJECTLIT:
|
||||
stackDelta = 1;
|
||||
iCodeTop = visitLiteral(iCodeTop, node, child);
|
||||
iCodeTop = visitLiteral(node, child, iCodeTop);
|
||||
break;
|
||||
|
||||
case Token.SPECIAL_REF: {
|
||||
stackDelta = 1;
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
int special = node.getExistingIntProp(Node.SPECIAL_PROP_PROP);
|
||||
iCodeTop = addIcode(Icode_SPECIAL_REF, iCodeTop);
|
||||
iCodeTop = addByte(special, iCodeTop);
|
||||
break;
|
||||
}
|
||||
|
||||
default :
|
||||
throw badTree(node);
|
||||
}
|
||||
@ -1110,13 +1099,13 @@ public class Interpreter
|
||||
case Token.GETPROP:
|
||||
// x.y(...)
|
||||
// -> tmp = x, (tmp.y, tmp)(...)
|
||||
iCodeTop = visitGetProp(iCodeTop, left, left.getFirstChild(), true);
|
||||
iCodeTop = visitGetProp(left, left.getFirstChild(), true, iCodeTop);
|
||||
iCodeTop = addIcode(Icode_SWAP, iCodeTop);
|
||||
break;
|
||||
case Token.GETELEM:
|
||||
// x[y](...)
|
||||
// -> tmp = x, (tmp[y], tmp)(...)
|
||||
iCodeTop = visitGetElem(iCodeTop, left, left.getFirstChild(), true);
|
||||
iCodeTop = visitGetElem(left, left.getFirstChild(), true, iCodeTop);
|
||||
iCodeTop = addIcode(Icode_SWAP, iCodeTop);
|
||||
break;
|
||||
default:
|
||||
@ -1129,31 +1118,22 @@ public class Interpreter
|
||||
return iCodeTop;
|
||||
}
|
||||
|
||||
private int visitGetProp(int iCodeTop, Node node, Node child, boolean dupObject)
|
||||
private int visitGetProp(Node node, Node child, boolean dupObject,
|
||||
int iCodeTop)
|
||||
{
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
if (dupObject) {
|
||||
iCodeTop = addIcode(Icode_DUP, iCodeTop);
|
||||
stackChange(1);
|
||||
}
|
||||
int special = node.getIntProp(Node.SPECIAL_PROP_PROP, 0);
|
||||
if (special != 0) {
|
||||
if (special == Node.SPECIAL_PROP_PROTO) {
|
||||
iCodeTop = addIcode(Icode_GETPROTO, iCodeTop);
|
||||
} else if (special == Node.SPECIAL_PROP_PARENT) {
|
||||
iCodeTop = addIcode(Icode_GETSCOPEPARENT, iCodeTop);
|
||||
} else {
|
||||
throw badTree(node);
|
||||
}
|
||||
} else {
|
||||
child = child.getNext();
|
||||
String property = child.getString();
|
||||
iCodeTop = addStringOp(Token.GETPROP, property, iCodeTop);
|
||||
}
|
||||
child = child.getNext();
|
||||
String property = child.getString();
|
||||
iCodeTop = addStringOp(Token.GETPROP, property, iCodeTop);
|
||||
return iCodeTop;
|
||||
}
|
||||
|
||||
private int visitGetElem(int iCodeTop, Node node, Node child, boolean dupObject)
|
||||
private int visitGetElem(Node node, Node child, boolean dupObject,
|
||||
int iCodeTop)
|
||||
{
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
if (dupObject) {
|
||||
@ -1167,6 +1147,13 @@ public class Interpreter
|
||||
return iCodeTop;
|
||||
}
|
||||
|
||||
private int visitGetRef(Node node, Node child, int iCodeTop)
|
||||
{
|
||||
iCodeTop = generateICode(child, iCodeTop);
|
||||
iCodeTop = addToken(Token.GET_REF, iCodeTop);
|
||||
return iCodeTop;
|
||||
}
|
||||
|
||||
private int visitIncDec(int iCodeTop, Node node, Node child)
|
||||
{
|
||||
int type = node.getType();
|
||||
@ -1199,16 +1186,24 @@ public class Interpreter
|
||||
break;
|
||||
}
|
||||
case Token.GETELEM : {
|
||||
int incrDecrType = node.getExistingIntProp(Node.INCRDECR_PROP);
|
||||
Node object = child.getFirstChild();
|
||||
iCodeTop = generateICode(object, iCodeTop);
|
||||
Node index = object.getNext();
|
||||
iCodeTop = generateICode(index, iCodeTop);
|
||||
int op = Icode_ELEM_PRE_INC
|
||||
- node.getExistingIntProp(Node.INCRDECR_PROP);
|
||||
iCodeTop = addIcode(op, iCodeTop);
|
||||
iCodeTop = addIcode(Icode_ELEM_INC_DEC, iCodeTop);
|
||||
iCodeTop = addByte(incrDecrType, iCodeTop);
|
||||
stackChange(-1);
|
||||
break;
|
||||
}
|
||||
case Token.GET_REF : {
|
||||
int incrDecrType = node.getExistingIntProp(Node.INCRDECR_PROP);
|
||||
Node ref = child.getFirstChild();
|
||||
iCodeTop = generateICode(ref, iCodeTop);
|
||||
iCodeTop = addIcode(Icode_REF_INC_DEC, iCodeTop);
|
||||
iCodeTop = addByte(incrDecrType, iCodeTop);
|
||||
break;
|
||||
}
|
||||
default : {
|
||||
iCodeTop = addStringOp(type == Token.INC
|
||||
? Icode_NAMEINC
|
||||
@ -1223,7 +1218,7 @@ public class Interpreter
|
||||
return iCodeTop;
|
||||
}
|
||||
|
||||
private int visitLiteral(int iCodeTop, Node node, Node child)
|
||||
private int visitLiteral(Node node, Node child, int iCodeTop)
|
||||
{
|
||||
int type = node.getType();
|
||||
int count;
|
||||
@ -1618,19 +1613,13 @@ public class Interpreter
|
||||
case Icode_NAMEDEC: return "NAMEDEC";
|
||||
case Icode_PROPDEC: return "PROPDEC";
|
||||
case Icode_VARDEC: return "VARDEC";
|
||||
case Icode_ELEM_PRE_INC: return "ELEM_PRE_INC";
|
||||
case Icode_ELEM_PRE_DEC: return "ELEM_PRE_DEC";
|
||||
case Icode_ELEM_POST_INC: return "ELEM_POST_INC";
|
||||
case Icode_ELEM_POST_DEC: return "ELEM_POST_DEC";
|
||||
case Icode_ELEM_INC_DEC: return "ELEM_INC_DEC";
|
||||
case Icode_REF_INC_DEC: return "REF_INC_DEC";
|
||||
case Icode_SCOPE: return "SCOPE";
|
||||
case Icode_TYPEOFNAME: return "TYPEOFNAME";
|
||||
case Icode_NAME_FAST_THIS: return "NAME_FAST_THIS";
|
||||
case Icode_NAME_SLOW_THIS: return "NAME_SLOW_THIS";
|
||||
case Icode_GETPROTO: return "GETPROTO";
|
||||
case Icode_PUSH_PARENT: return "PUSH_PARENT";
|
||||
case Icode_GETSCOPEPARENT: return "GETSCOPEPARENT";
|
||||
case Icode_SETPROTO: return "SETPROTO";
|
||||
case Icode_SETPARENT: return "SETPARENT";
|
||||
case Icode_CLOSURE: return "CLOSURE";
|
||||
case Icode_CALLSPECIAL: return "CALLSPECIAL";
|
||||
case Icode_RETUNDEF: return "RETUNDEF";
|
||||
@ -1661,6 +1650,7 @@ public class Interpreter
|
||||
case Icode_REG_STR4: return "LOAD_STR4";
|
||||
case Icode_GETVAR1: return "GETVAR1";
|
||||
case Icode_SETVAR1: return "SETVAR1";
|
||||
case Icode_SPECIAL_REF: return "SPECIAL_REF";
|
||||
}
|
||||
|
||||
// icode without name
|
||||
@ -1706,6 +1696,21 @@ public class Interpreter
|
||||
pc += 2;
|
||||
break;
|
||||
}
|
||||
case Icode_ELEM_INC_DEC :
|
||||
case Icode_REF_INC_DEC: {
|
||||
int incrDecrType = iCode[pc];
|
||||
out.println(tname + " " + incrDecrType);
|
||||
++pc;
|
||||
break;
|
||||
}
|
||||
|
||||
case Icode_SPECIAL_REF : {
|
||||
int specialType = iCode[pc];
|
||||
out.println(tname + " " + specialType);
|
||||
++pc;
|
||||
break;
|
||||
}
|
||||
|
||||
case Icode_CALLSPECIAL : {
|
||||
int callType = iCode[pc] & 0xFF;
|
||||
boolean isNew = (iCode[pc + 1] != 0);
|
||||
@ -1855,6 +1860,15 @@ public class Interpreter
|
||||
// index of potential function name for debugging
|
||||
return 1 + 2;
|
||||
|
||||
case Icode_ELEM_INC_DEC:
|
||||
case Icode_REF_INC_DEC:
|
||||
// type of ++/--
|
||||
return 1 + 1;
|
||||
|
||||
case Icode_SPECIAL_REF:
|
||||
// type of special property
|
||||
return 1 + 1;
|
||||
|
||||
case Icode_SHORTNUMBER :
|
||||
// short number
|
||||
return 1 + 2;
|
||||
@ -2482,25 +2496,46 @@ switch (op) {
|
||||
case Token.SETELEM :
|
||||
stackTop = do_setElem(stack, sDbl, stackTop, cx, scope);
|
||||
continue Loop;
|
||||
case Icode_PROPINC :
|
||||
case Icode_PROPDEC : {
|
||||
Object lhs = stack[stackTop];
|
||||
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
|
||||
stack[stackTop] = ScriptRuntime.postIncrDecr(lhs, stringReg, scope,
|
||||
op == Icode_PROPINC);
|
||||
continue Loop;
|
||||
}
|
||||
case Icode_ELEM_PRE_INC:
|
||||
case Icode_ELEM_PRE_DEC:
|
||||
case Icode_ELEM_POST_INC:
|
||||
case Icode_ELEM_POST_DEC: {
|
||||
case Icode_ELEM_INC_DEC: {
|
||||
Object rhs = stack[stackTop];
|
||||
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
|
||||
--stackTop;
|
||||
Object lhs = stack[stackTop];
|
||||
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
|
||||
stack[stackTop] = ScriptRuntime.elemIncrDecr(lhs, rhs, scope,
|
||||
Icode_ELEM_PRE_INC - op);
|
||||
iCode[pc]);
|
||||
++pc;
|
||||
continue Loop;
|
||||
}
|
||||
case Token.GET_REF : {
|
||||
Object lhs = stack[stackTop];
|
||||
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
|
||||
stack[stackTop] = ScriptRuntime.getReference(lhs);
|
||||
continue Loop;
|
||||
}
|
||||
case Token.SET_REF : {
|
||||
Object rhs = stack[stackTop];
|
||||
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);
|
||||
--stackTop;
|
||||
Object lhs = stack[stackTop];
|
||||
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
|
||||
ScriptRuntime.setReference(lhs, rhs);
|
||||
stack[stackTop] = rhs;
|
||||
continue Loop;
|
||||
}
|
||||
case Icode_REF_INC_DEC : {
|
||||
Object lhs = stack[stackTop];
|
||||
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
|
||||
stack[stackTop] = ScriptRuntime.referenceIncrDecr(lhs, iCode[pc]);
|
||||
++pc;
|
||||
continue Loop;
|
||||
}
|
||||
case Icode_PROPINC :
|
||||
case Icode_PROPDEC : {
|
||||
Object lhs = stack[stackTop];
|
||||
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
|
||||
stack[stackTop] = ScriptRuntime.postIncrDecr(lhs, stringReg, scope,
|
||||
op == Icode_PROPINC);
|
||||
continue Loop;
|
||||
}
|
||||
case Token.LOCAL_SAVE :
|
||||
@ -2773,12 +2808,13 @@ switch (op) {
|
||||
stack[++stackTop] = ScriptRuntime.getParent(lhs);
|
||||
continue Loop;
|
||||
}
|
||||
case Icode_GETPROTO :
|
||||
case Icode_GETSCOPEPARENT :
|
||||
case Icode_SETPROTO :
|
||||
case Icode_SETPARENT :
|
||||
stackTop = do_specialProp(stack, sDbl, stackTop, op, scope);
|
||||
case Icode_SPECIAL_REF : {
|
||||
Object lhs = stack[stackTop];
|
||||
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
|
||||
stack[stackTop] = ScriptRuntime.specialReference(lhs, scope, iCode[pc]);
|
||||
++pc;
|
||||
continue Loop;
|
||||
}
|
||||
case Icode_SCOPE :
|
||||
stack[++stackTop] = scope;
|
||||
continue Loop;
|
||||
@ -3284,36 +3320,6 @@ switch (op) {
|
||||
return stackTop;
|
||||
}
|
||||
|
||||
private static int do_specialProp(Object[] stack, double[] sDbl,
|
||||
int stackTop, int op, Scriptable scope)
|
||||
{
|
||||
Object val;
|
||||
Object top = stack[stackTop];
|
||||
if (top == DBL_MRK) top = doubleWrap(sDbl[stackTop]);
|
||||
switch (op) {
|
||||
default: throw Kit.codeBug();
|
||||
case Icode_GETPROTO:
|
||||
val = ScriptRuntime.getProto(top, scope);
|
||||
break;
|
||||
case Icode_GETSCOPEPARENT:
|
||||
val = ScriptRuntime.getParent(top, scope);
|
||||
break;
|
||||
case Icode_SETPROTO:
|
||||
case Icode_SETPARENT:
|
||||
--stackTop;
|
||||
Object snd = stack[stackTop];
|
||||
if (snd == DBL_MRK) snd = doubleWrap(sDbl[stackTop]);
|
||||
if (op == Icode_SETPROTO) {
|
||||
val = ScriptRuntime.setProto(snd, top, scope);
|
||||
} else {
|
||||
val = ScriptRuntime.setParent(snd, top, scope);
|
||||
}
|
||||
break;
|
||||
}
|
||||
stack[stackTop] = val;
|
||||
return stackTop;
|
||||
}
|
||||
|
||||
static RuntimeException notAFunction(Object notAFunction,
|
||||
InterpreterData idata, int namePC)
|
||||
{
|
||||
|
55
js/rhino/src/org/mozilla/javascript/Reference.java
Normal file
55
js/rhino/src/org/mozilla/javascript/Reference.java
Normal file
@ -0,0 +1,55 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Reference class for Rhino.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* RUnit Software AS.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Igor Bukanov, igor@fastmail.fm
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
/**
|
||||
* Generic notion of callable object that can execute some script-related code
|
||||
* upon request with specified values for script scope and this objects.
|
||||
*/
|
||||
public abstract class Reference
|
||||
{
|
||||
public abstract Object get();
|
||||
|
||||
public abstract void set(Object value);
|
||||
|
||||
public void delete()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -1255,6 +1255,57 @@ public class ScriptRuntime {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Object getReference(Object obj)
|
||||
{
|
||||
if (!(obj instanceof Reference)) {
|
||||
String msg = getMessage1("msg.no.ref.to.get", toString(obj));
|
||||
throw constructError("ReferenceError", msg);
|
||||
}
|
||||
Reference ref = (Reference)obj;
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
public static void setReference(Object obj, Object value)
|
||||
{
|
||||
if (!(obj instanceof Reference)) {
|
||||
String msg = getMessage2("msg.no.ref.to.set",
|
||||
toString(obj), toString(value));
|
||||
throw constructError("ReferenceError", msg);
|
||||
}
|
||||
Reference ref = (Reference)obj;
|
||||
ref.set(value);
|
||||
}
|
||||
|
||||
public static Object specialReference(final Object obj,
|
||||
final Scriptable scope,
|
||||
final int specialType)
|
||||
{
|
||||
if (!(specialType == Node.SPECIAL_PROP_PROTO
|
||||
|| specialType == Node.SPECIAL_PROP_PARENT))
|
||||
{
|
||||
throw Kit.codeBug();
|
||||
}
|
||||
return new Reference() {
|
||||
public Object get()
|
||||
{
|
||||
if (specialType == Node.SPECIAL_PROP_PROTO) {
|
||||
return getProto(obj, scope);
|
||||
} else {
|
||||
return getParent(obj, scope);
|
||||
}
|
||||
}
|
||||
|
||||
public void set(Object value)
|
||||
{
|
||||
if (specialType == Node.SPECIAL_PROP_PROTO) {
|
||||
setProto(obj, value, scope);
|
||||
} else {
|
||||
setParent(obj, value, scope);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The delete operator
|
||||
*
|
||||
@ -1729,6 +1780,36 @@ public class ScriptRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
public static Object referenceIncrDecr(Object obj, int type)
|
||||
{
|
||||
Object value = getReference(obj);
|
||||
if (value == Undefined.instance)
|
||||
return value;
|
||||
boolean post = (type == Node.POST_INC || type == Node.POST_DEC);
|
||||
double number;
|
||||
if (value instanceof Number) {
|
||||
number = ((Number)value).doubleValue();
|
||||
} else {
|
||||
number = toNumber(value);
|
||||
if (post) {
|
||||
// convert result to number
|
||||
value = new Double(number);
|
||||
}
|
||||
}
|
||||
if (type == Node.PRE_INC || type == Node.POST_INC) {
|
||||
++number;
|
||||
} else {
|
||||
--number;
|
||||
}
|
||||
Number result = new Double(number);
|
||||
setReference(obj, result);
|
||||
if (post) {
|
||||
return value;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static Object toPrimitive(Object val) {
|
||||
if (val == null || !(val instanceof Scriptable)) {
|
||||
return val;
|
||||
|
@ -140,69 +140,73 @@ public class Token
|
||||
RETURN_POPV = 66, // to return result stored as popv in functions
|
||||
ARRAYLIT = 67, // array literal
|
||||
OBJECTLIT = 68, // object literal
|
||||
GET_REF = 69, // *reference
|
||||
SET_REF = 70, // *reference = something
|
||||
|
||||
LAST_BYTECODE_TOKEN = 68,
|
||||
LAST_BYTECODE_TOKEN = 70,
|
||||
// End of interpreter bytecodes
|
||||
|
||||
TRY = 69,
|
||||
SEMI = 70, // semicolon
|
||||
LB = 71, // left and right brackets
|
||||
RB = 72,
|
||||
LC = 73, // left and right curlies (braces)
|
||||
RC = 74,
|
||||
LP = 75, // left and right parentheses
|
||||
RP = 76,
|
||||
COMMA = 77, // comma operator
|
||||
ASSIGN = 78, // simple assignment (=)
|
||||
ASSIGNOP = 79, // assignment with operation (+= -= etc.)
|
||||
HOOK = 80, // conditional (?:)
|
||||
COLON = 81,
|
||||
OR = 82, // logical or (||)
|
||||
AND = 83, // logical and (&&)
|
||||
INC = 84, // increment/decrement (++ --)
|
||||
DEC = 85,
|
||||
DOT = 86, // member operator (.)
|
||||
FUNCTION = 87, // function keyword
|
||||
EXPORT = 88, // export keyword
|
||||
IMPORT = 89, // import keyword
|
||||
IF = 90, // if keyword
|
||||
ELSE = 91, // else keyword
|
||||
SWITCH = 92, // switch keyword
|
||||
CASE = 93, // case keyword
|
||||
DEFAULT = 94, // default keyword
|
||||
WHILE = 95, // while keyword
|
||||
DO = 96, // do keyword
|
||||
FOR = 97, // for keyword
|
||||
BREAK = 98, // break keyword
|
||||
CONTINUE = 99, // continue keyword
|
||||
VAR = 100, // var keyword
|
||||
WITH = 101, // with keyword
|
||||
CATCH = 102, // catch keyword
|
||||
FINALLY = 103, // finally keyword
|
||||
VOID = 104, // void keyword
|
||||
RESERVED = 105, // reserved keywords
|
||||
TRY = 71,
|
||||
SEMI = 72, // semicolon
|
||||
LB = 73, // left and right brackets
|
||||
RB = 74,
|
||||
LC = 75, // left and right curlies (braces)
|
||||
RC = 76,
|
||||
LP = 77, // left and right parentheses
|
||||
RP = 78,
|
||||
COMMA = 79, // comma operator
|
||||
ASSIGN = 80, // simple assignment (=)
|
||||
ASSIGNOP = 81, // assignment with operation (+= -= etc.)
|
||||
HOOK = 82, // conditional (?:)
|
||||
COLON = 83,
|
||||
OR = 84, // logical or (||)
|
||||
AND = 85, // logical and (&&)
|
||||
INC = 86, // increment/decrement (++ --)
|
||||
DEC = 87,
|
||||
DOT = 88, // member operator (.)
|
||||
FUNCTION = 89, // function keyword
|
||||
EXPORT = 90, // export keyword
|
||||
IMPORT = 91, // import keyword
|
||||
IF = 92, // if keyword
|
||||
ELSE = 93, // else keyword
|
||||
SWITCH = 94, // switch keyword
|
||||
CASE = 95, // case keyword
|
||||
DEFAULT = 96, // default keyword
|
||||
WHILE = 97, // while keyword
|
||||
DO = 98, // do keyword
|
||||
FOR = 99, // for keyword
|
||||
BREAK = 100, // break keyword
|
||||
CONTINUE = 101, // continue keyword
|
||||
VAR = 102, // var keyword
|
||||
WITH = 103, // with keyword
|
||||
CATCH = 104, // catch keyword
|
||||
FINALLY = 105, // finally keyword
|
||||
VOID = 106, // void keyword
|
||||
RESERVED = 107, // reserved keywords
|
||||
|
||||
EMPTY = 106,
|
||||
EMPTY = 108,
|
||||
|
||||
/* types used for the parse tree - these never get returned
|
||||
* by the scanner.
|
||||
*/
|
||||
|
||||
BLOCK = 107, // statement block
|
||||
LABEL = 108, // label
|
||||
TARGET = 109,
|
||||
LOOP = 110,
|
||||
EXPRSTMT = 111,
|
||||
JSR = 112,
|
||||
SCRIPT = 113, // top-level node for entire script
|
||||
TYPEOFNAME = 114, // for typeof(simple-name)
|
||||
USE_STACK = 115,
|
||||
SETPROP_OP = 116, // x.y op= something
|
||||
SETELEM_OP = 117, // x[y] op= something
|
||||
INIT_LIST = 118,
|
||||
LOCAL_BLOCK = 119,
|
||||
BLOCK = 109, // statement block
|
||||
LABEL = 110, // label
|
||||
TARGET = 111,
|
||||
LOOP = 112,
|
||||
EXPRSTMT = 113,
|
||||
JSR = 114,
|
||||
SCRIPT = 115, // top-level node for entire script
|
||||
TYPEOFNAME = 116, // for typeof(simple-name)
|
||||
USE_STACK = 117,
|
||||
SETPROP_OP = 118, // x.y op= something
|
||||
SETELEM_OP = 119, // x[y] op= something
|
||||
INIT_LIST = 120,
|
||||
LOCAL_BLOCK = 121,
|
||||
SET_REF_OP = 122, // *reference op= something
|
||||
SPECIAL_REF = 123, // reference for special properties like __proto
|
||||
|
||||
LAST_TOKEN = 119;
|
||||
LAST_TOKEN = 123;
|
||||
|
||||
public static String name(int token)
|
||||
{
|
||||
@ -285,6 +289,8 @@ public class Token
|
||||
case RETURN_POPV: return "RETURN_POPV";
|
||||
case ARRAYLIT: return "ARRAYLIT";
|
||||
case OBJECTLIT: return "OBJECTLIT";
|
||||
case GET_REF: return "GET_REF";
|
||||
case SET_REF: return "SET_REF";
|
||||
case TRY: return "TRY";
|
||||
case SEMI: return "SEMI";
|
||||
case LB: return "LB";
|
||||
@ -335,6 +341,8 @@ public class Token
|
||||
case SETELEM_OP: return "SETELEM_OP";
|
||||
case INIT_LIST: return "INIT_LIST";
|
||||
case LOCAL_BLOCK: return "LOCAL_BLOCK";
|
||||
case SET_REF_OP: return "SET_REF_OP";
|
||||
case SPECIAL_REF: return "SPECIAL_REF";
|
||||
}
|
||||
|
||||
// Token without name
|
||||
|
@ -1791,6 +1791,10 @@ class BodyCodegen
|
||||
visitGetElem(node, child, false);
|
||||
break;
|
||||
|
||||
case Token.GET_REF:
|
||||
visitGetRef(node, child);
|
||||
break;
|
||||
|
||||
case Token.GETVAR:
|
||||
visitGetVar(node);
|
||||
break;
|
||||
@ -1809,62 +1813,14 @@ class BodyCodegen
|
||||
break;
|
||||
|
||||
case Token.SETELEM:
|
||||
case Token.SETELEM_OP: {
|
||||
generateCodeFromNode(child, node);
|
||||
child = child.getNext();
|
||||
if (type == Token.SETELEM_OP) {
|
||||
cfw.add(ByteCode.DUP);
|
||||
}
|
||||
generateCodeFromNode(child, node);
|
||||
child = child.getNext();
|
||||
boolean indexIsNumber
|
||||
= (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1);
|
||||
if (type == Token.SETELEM_OP) {
|
||||
if (indexIsNumber) {
|
||||
// stack: ... object object number
|
||||
// -> ... object number object number
|
||||
cfw.add(ByteCode.DUP2_X1);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addOptRuntimeInvoke(
|
||||
"getElem",
|
||||
"(Ljava/lang/Object;D"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
} else {
|
||||
// stack: ... object object indexObject
|
||||
// -> ... object indexObject object indexObject
|
||||
cfw.add(ByteCode.DUP_X1);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke(
|
||||
"getElem",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
}
|
||||
generateCodeFromNode(child, node);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
if (indexIsNumber) {
|
||||
addOptRuntimeInvoke(
|
||||
"setElem",
|
||||
"(Ljava/lang/Object;"
|
||||
+"D"
|
||||
+"Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
else {
|
||||
addScriptRuntimeInvoke(
|
||||
"setElem",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Ljava/lang/Object;"
|
||||
+"Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
case Token.SETELEM_OP:
|
||||
visitSetElem(type, node, child);
|
||||
break;
|
||||
|
||||
case Token.SET_REF:
|
||||
case Token.SET_REF_OP:
|
||||
visitSetRef(type, node, child);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token.DELPROP:
|
||||
cfw.addALoad(contextLocal);
|
||||
@ -1889,6 +1845,10 @@ class BodyCodegen
|
||||
cfw.addALoad(getLocalBlockRegister(node));
|
||||
break;
|
||||
|
||||
case Token.SPECIAL_REF:
|
||||
visitSpecialRef(node, child);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Unexpected node type "+type);
|
||||
}
|
||||
@ -2794,11 +2754,12 @@ class BodyCodegen
|
||||
break;
|
||||
}
|
||||
case Token.GETELEM: {
|
||||
int incrDecrType = node.getExistingIntProp(Node.INCRDECR_PROP);
|
||||
Node getElemChild = child.getFirstChild();
|
||||
generateCodeFromNode(getElemChild, node);
|
||||
generateCodeFromNode(getElemChild.getNext(), node);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
cfw.addPush(node.getExistingIntProp(Node.INCRDECR_PROP));
|
||||
cfw.addPush(incrDecrType);
|
||||
addScriptRuntimeInvoke("elemIncrDecr",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Ljava/lang/Object;"
|
||||
@ -2806,6 +2767,15 @@ class BodyCodegen
|
||||
+"I)Ljava/lang/Object;");
|
||||
break;
|
||||
}
|
||||
case Token.GET_REF: {
|
||||
int incrDecrType = node.getExistingIntProp(Node.INCRDECR_PROP);
|
||||
Node refChild = child.getFirstChild();
|
||||
generateCodeFromNode(refChild, node);
|
||||
cfw.addPush(incrDecrType);
|
||||
addScriptRuntimeInvoke(
|
||||
"referenceIncrDecr", "(Ljava/lang/Object;I)Ljava/lang/Object;");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Codegen.badTree();
|
||||
}
|
||||
@ -3307,24 +3277,6 @@ class BodyCodegen
|
||||
if (dupObject) {
|
||||
cfw.add(ByteCode.DUP);
|
||||
}
|
||||
int special = node.getIntProp(Node.SPECIAL_PROP_PROP, 0);
|
||||
if (special != 0) {
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
String runtimeMethod;
|
||||
if (special == Node.SPECIAL_PROP_PROTO) {
|
||||
runtimeMethod = "getProto";
|
||||
} else if (special == Node.SPECIAL_PROP_PARENT) {
|
||||
runtimeMethod = "getParent";
|
||||
} else {
|
||||
throw Codegen.badTree();
|
||||
}
|
||||
addScriptRuntimeInvoke(
|
||||
runtimeMethod,
|
||||
"(Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
return;
|
||||
}
|
||||
Node nameChild = child.getNext();
|
||||
generateCodeFromNode(nameChild, node); // the name
|
||||
/*
|
||||
@ -3375,49 +3327,18 @@ class BodyCodegen
|
||||
}
|
||||
}
|
||||
|
||||
private void visitGetRef(Node node, Node child)
|
||||
{
|
||||
generateCodeFromNode(child, node); // reference
|
||||
addScriptRuntimeInvoke(
|
||||
"getReference", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
private void visitSetProp(int type, Node node, Node child)
|
||||
{
|
||||
Node objectChild = child;
|
||||
generateCodeFromNode(child, node);
|
||||
child = child.getNext();
|
||||
int special = node.getIntProp(Node.SPECIAL_PROP_PROP, 0);
|
||||
if (special != 0) {
|
||||
if (type == Token.SETPROP_OP) {
|
||||
cfw.add(ByteCode.DUP);
|
||||
String runtimeMethod;
|
||||
if (special == Node.SPECIAL_PROP_PROTO) {
|
||||
runtimeMethod = "getProto";
|
||||
} else if (special == Node.SPECIAL_PROP_PARENT) {
|
||||
runtimeMethod = "getParent";
|
||||
} else {
|
||||
throw Codegen.badTree();
|
||||
}
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke(
|
||||
runtimeMethod,
|
||||
"(Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
}
|
||||
generateCodeFromNode(child, node);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
String runtimeMethod;
|
||||
if (special == Node.SPECIAL_PROP_PROTO) {
|
||||
runtimeMethod = "setProto";
|
||||
} else if (special == Node.SPECIAL_PROP_PARENT) {
|
||||
runtimeMethod = "setParent";
|
||||
} else {
|
||||
throw Codegen.badTree();
|
||||
}
|
||||
addScriptRuntimeInvoke(
|
||||
runtimeMethod,
|
||||
"(Ljava/lang/Object;"
|
||||
+"Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == Token.SETPROP_OP) {
|
||||
cfw.add(ByteCode.DUP);
|
||||
}
|
||||
@ -3459,6 +3380,78 @@ class BodyCodegen
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
private void visitSetElem(int type, Node node, Node child)
|
||||
{
|
||||
generateCodeFromNode(child, node);
|
||||
child = child.getNext();
|
||||
if (type == Token.SETELEM_OP) {
|
||||
cfw.add(ByteCode.DUP);
|
||||
}
|
||||
generateCodeFromNode(child, node);
|
||||
child = child.getNext();
|
||||
boolean indexIsNumber = (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1);
|
||||
if (type == Token.SETELEM_OP) {
|
||||
if (indexIsNumber) {
|
||||
// stack: ... object object number
|
||||
// -> ... object number object number
|
||||
cfw.add(ByteCode.DUP2_X1);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addOptRuntimeInvoke(
|
||||
"getElem",
|
||||
"(Ljava/lang/Object;D"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
} else {
|
||||
// stack: ... object object indexObject
|
||||
// -> ... object indexObject object indexObject
|
||||
cfw.add(ByteCode.DUP_X1);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
addScriptRuntimeInvoke(
|
||||
"getElem",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
}
|
||||
generateCodeFromNode(child, node);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
if (indexIsNumber) {
|
||||
addOptRuntimeInvoke(
|
||||
"setElem",
|
||||
"(Ljava/lang/Object;"
|
||||
+"D"
|
||||
+"Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
} else {
|
||||
addScriptRuntimeInvoke(
|
||||
"setElem",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Ljava/lang/Object;"
|
||||
+"Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Ljava/lang/Object;");
|
||||
}
|
||||
}
|
||||
|
||||
private void visitSetRef(int type, Node node, Node child)
|
||||
{
|
||||
generateCodeFromNode(child, node);
|
||||
child = child.getNext();
|
||||
if (type == Token.SET_REF_OP) {
|
||||
cfw.add(ByteCode.DUP);
|
||||
addScriptRuntimeInvoke(
|
||||
"getReference", "(Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
}
|
||||
generateCodeFromNode(child, node);
|
||||
cfw.add(ByteCode.DUP_X1);
|
||||
// stack: value ref value
|
||||
addScriptRuntimeInvoke(
|
||||
"setReference", "(Ljava/lang/Object;Ljava/lang/Object;)V");
|
||||
// stack: value
|
||||
}
|
||||
|
||||
private void visitBind(Node node, Node child)
|
||||
{
|
||||
while (child != null) {
|
||||
@ -3474,6 +3467,18 @@ class BodyCodegen
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
}
|
||||
|
||||
private void visitSpecialRef(Node node, Node child)
|
||||
{
|
||||
int special = node.getExistingIntProp(Node.SPECIAL_PROP_PROP);
|
||||
generateCodeFromNode(child, node);
|
||||
cfw.addALoad(variableObjectLocal); // get variable object
|
||||
cfw.addPush(special); // push name
|
||||
addScriptRuntimeInvoke("specialReference",
|
||||
"(Ljava/lang/Object;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"I)Ljava/lang/Object;");
|
||||
}
|
||||
|
||||
private int getLocalBlockRegister(Node node)
|
||||
{
|
||||
Node localBlock = (Node)node.getProp(Node.LOCAL_BLOCK_PROP);
|
||||
|
Loading…
Reference in New Issue
Block a user