diff --git a/js/rhino/src/org/mozilla/javascript/IRFactory.java b/js/rhino/src/org/mozilla/javascript/IRFactory.java index e2cb6b72422..463e2d7b7bd 100644 --- a/js/rhino/src/org/mozilla/javascript/IRFactory.java +++ b/js/rhino/src/org/mozilla/javascript/IRFactory.java @@ -838,17 +838,20 @@ class IRFactory n.putIntProp(Node.INCRDECR_PROP, incrDecrMask); return n; } - case Token.CALL: { - // Turn call into reference_call and recurse - child.setType(Token.REF_CALL); - Node ref = new Node(Token.GET_REF, child); - return createIncDec(nodeType, post, ref); - } } - // TODO: This should be a ReferenceError--but that's a runtime - // exception. Should we compile an exception into the code? - parser.reportError("msg.bad.lhs.assign"); - return child; + return createIncDec(nodeType, post, makeReferenceGet(child)); + } + + private Node makeReferenceGet(Node node) + { + Node ref; + if (node.getType() == Token.CALL) { + node.setType(Token.REF_CALL); + ref = node; + } else { + ref = new Node(Token.GENERIC_REF, node); + } + return new Node(Token.GET_REF, ref); } /** @@ -1054,17 +1057,8 @@ class IRFactory Node ref = left.getFirstChild(); return new Node(Token.SET_REF, ref, right); } - case Token.CALL: { - left.setType(Token.REF_CALL); - return new Node(Token.SET_REF, left, right); - } - - default: - // TODO: This should be a ReferenceError--but that's a runtime - // exception. Should we compile an exception into the code? - parser.reportError("msg.bad.lhs.assign"); - return left; } + return createAssignment(makeReferenceGet(left), right); } Object createAssignmentOp(int assignOp, Object leftObj, Object rightObj) @@ -1082,7 +1076,6 @@ class IRFactory Node lvalueLeft = Node.newString(Token.BINDNAME, s); return new Node(Token.SETNAME, lvalueLeft, op); } - case Token.GETPROP: case Token.GETELEM: { Node obj = left.getFirstChild(); @@ -1096,26 +1089,14 @@ class IRFactory Node op = new Node(assignOp, opLeft, right); return new Node(type, obj, id, op); } - case Token.GET_REF: { Node ref = left.getFirstChild(); Node opLeft = new Node(Token.USE_STACK); Node op = new Node(assignOp, opLeft, right); return new Node(Token.SET_REF_OP, ref, op); } - case Token.CALL: { - // Turn call into reference_call and recurse - left.setType(Token.REF_CALL); - Node ref = new Node(Token.GET_REF, left); - return createAssignmentOp(assignOp, ref, right); - } - - default: - // TODO: This should be a ReferenceError--but that's a runtime - // exception. Should we compile an exception into the code? - parser.reportError("msg.bad.lhs.assign"); - return left; } + return createAssignmentOp(assignOp, makeReferenceGet(left), right); } Node createUseLocal(Node localBlock) diff --git a/js/rhino/src/org/mozilla/javascript/Interpreter.java b/js/rhino/src/org/mozilla/javascript/Interpreter.java index 19b2c533366..76fe02d31ff 100644 --- a/js/rhino/src/org/mozilla/javascript/Interpreter.java +++ b/js/rhino/src/org/mozilla/javascript/Interpreter.java @@ -129,11 +129,8 @@ public class Interpreter Icode_GETVAR1 = -43, Icode_SETVAR1 = -44, - // Construct special reference - Icode_SPECIAL_REF = -45, - // Last icode - MIN_ICODE = -45; + MIN_ICODE = -44; static { // Checks for byte code consistencies, good compiler can eliminate them @@ -1051,11 +1048,17 @@ public class Interpreter stackDelta = 1; iCodeTop = generateICode(child, iCodeTop); int special = node.getExistingIntProp(Node.SPECIAL_PROP_PROP); - iCodeTop = addIcode(Icode_SPECIAL_REF, iCodeTop); + iCodeTop = addToken(Token.SPECIAL_REF, iCodeTop); iCodeTop = addByte(special, iCodeTop); break; } + case Token.GENERIC_REF: + stackDelta = 1; + iCodeTop = generateICode(child, iCodeTop); + iCodeTop = addToken(Token.GENERIC_REF, iCodeTop); + break; + default : throw badTree(node); } @@ -1638,7 +1641,6 @@ 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 @@ -1695,7 +1697,7 @@ public class Interpreter break; } - case Icode_SPECIAL_REF : { + case Token.SPECIAL_REF : { int specialType = iCode[pc]; out.println(tname + " " + specialType); ++pc; @@ -1861,7 +1863,7 @@ public class Interpreter // type of ++/-- return 1 + 1; - case Icode_SPECIAL_REF: + case Token.SPECIAL_REF: // type of special property return 1 + 1; @@ -2828,13 +2830,20 @@ switch (op) { stack[++stackTop] = ScriptRuntime.getParent(lhs); continue Loop; } - case Icode_SPECIAL_REF : { + case Token.SPECIAL_REF : { Object lhs = stack[stackTop]; if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]); - stack[stackTop] = ScriptRuntime.specialReference(lhs, scope, iCode[pc]); + stack[stackTop] = ScriptRuntime.specialReference(lhs, iCode[pc], + cx, scope); ++pc; continue Loop; } + case Token.GENERIC_REF : { + Object lhs = stack[stackTop]; + if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]); + stack[stackTop] = ScriptRuntime.genericReference(lhs, cx, scope); + continue Loop; + } case Icode_SCOPE : stack[++stackTop] = scope; continue Loop; diff --git a/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java b/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java index 758e48a4fae..475b44ce398 100644 --- a/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java +++ b/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java @@ -1277,8 +1277,9 @@ public class ScriptRuntime { } public static Object specialReference(final Object obj, - final Scriptable scope, - final int specialType) + final int specialType, + Context cx, + final Scriptable scope) { if (!(specialType == Node.SPECIAL_PROP_PROTO || specialType == Node.SPECIAL_PROP_PARENT)) @@ -1306,6 +1307,13 @@ public class ScriptRuntime { }; } + public static Object genericReference(Object obj, + Context cx, Scriptable scope) + { + String msg = getMessage1("msg.not.ref", toString(obj)); + throw constructError("ReferenceError", msg); + } + /** * The delete operator * diff --git a/js/rhino/src/org/mozilla/javascript/Token.java b/js/rhino/src/org/mozilla/javascript/Token.java index 5bf30229efe..b4054bdc6fe 100644 --- a/js/rhino/src/org/mozilla/javascript/Token.java +++ b/js/rhino/src/org/mozilla/javascript/Token.java @@ -143,71 +143,72 @@ public class Token GET_REF = 69, // *reference SET_REF = 70, // *reference = something REF_CALL = 71, // f(args) = something or f(args)++ + SPECIAL_REF = 72, // reference for special properties like __proto + GENERIC_REF = 73, // generic reference to generate runtime ref errors - LAST_BYTECODE_TOKEN = 71, + LAST_BYTECODE_TOKEN = 73, // End of interpreter bytecodes - TRY = 72, - SEMI = 73, // semicolon - LB = 74, // left and right brackets - RB = 75, - LC = 76, // left and right curlies (braces) - RC = 77, - LP = 78, // left and right parentheses - RP = 79, - COMMA = 80, // comma operator - ASSIGN = 81, // simple assignment (=) - ASSIGNOP = 82, // assignment with operation (+= -= etc.) - HOOK = 83, // conditional (?:) - COLON = 84, - OR = 85, // logical or (||) - AND = 86, // logical and (&&) - INC = 87, // increment/decrement (++ --) - DEC = 88, - DOT = 89, // member operator (.) - FUNCTION = 90, // function keyword - EXPORT = 91, // export keyword - IMPORT = 92, // import keyword - IF = 93, // if keyword - ELSE = 94, // else keyword - SWITCH = 95, // switch keyword - CASE = 96, // case keyword - DEFAULT = 97, // default keyword - WHILE = 98, // while keyword - DO = 99, // do keyword - FOR = 100, // for keyword - BREAK = 101, // break keyword - CONTINUE = 102, // continue keyword - VAR = 103, // var keyword - WITH = 104, // with keyword - CATCH = 105, // catch keyword - FINALLY = 106, // finally keyword - VOID = 107, // void keyword - RESERVED = 108, // reserved keywords + TRY = 74, + SEMI = 75, // semicolon + LB = 76, // left and right brackets + RB = 77, + LC = 78, // left and right curlies (braces) + RC = 79, + LP = 80, // left and right parentheses + RP = 81, + COMMA = 82, // comma operator + ASSIGN = 83, // simple assignment (=) + ASSIGNOP = 84, // assignment with operation (+= -= etc.) + HOOK = 85, // conditional (?:) + COLON = 86, + OR = 87, // logical or (||) + AND = 88, // logical and (&&) + INC = 89, // increment/decrement (++ --) + DEC = 90, + DOT = 91, // member operator (.) + FUNCTION = 92, // function keyword + EXPORT = 93, // export keyword + IMPORT = 94, // import keyword + IF = 95, // if keyword + ELSE = 96, // else keyword + SWITCH = 97, // switch keyword + CASE = 98, // case keyword + DEFAULT = 99, // default keyword + WHILE = 100, // while keyword + DO = 101, // do keyword + FOR = 102, // for keyword + BREAK = 103, // break keyword + CONTINUE = 104, // continue keyword + VAR = 105, // var keyword + WITH = 106, // with keyword + CATCH = 107, // catch keyword + FINALLY = 108, // finally keyword + VOID = 109, // void keyword + RESERVED = 110, // reserved keywords - EMPTY = 109, + EMPTY = 111, /* types used for the parse tree - these never get returned * by the scanner. */ - BLOCK = 110, // statement block - LABEL = 111, // label - TARGET = 112, - LOOP = 113, - EXPRSTMT = 114, - JSR = 115, - SCRIPT = 116, // top-level node for entire script - TYPEOFNAME = 117, // for typeof(simple-name) - USE_STACK = 118, - SETPROP_OP = 119, // x.y op= something - SETELEM_OP = 120, // x[y] op= something - INIT_LIST = 121, - LOCAL_BLOCK = 122, - SET_REF_OP = 123, // *reference op= something - SPECIAL_REF = 124, // reference for special properties like __proto + BLOCK = 112, // statement block + LABEL = 113, // label + TARGET = 114, + LOOP = 115, + EXPRSTMT = 116, + JSR = 117, + SCRIPT = 118, // top-level node for entire script + TYPEOFNAME = 119, // for typeof(simple-name) + USE_STACK = 120, + SETPROP_OP = 121, // x.y op= something + SETELEM_OP = 122, // x[y] op= something + INIT_LIST = 123, + LOCAL_BLOCK = 124, + SET_REF_OP = 125, // *reference op= something - LAST_TOKEN = 124; + LAST_TOKEN = 125; public static String name(int token) { @@ -293,6 +294,8 @@ public class Token case GET_REF: return "GET_REF"; case SET_REF: return "SET_REF"; case REF_CALL: return "REF_CALL"; + case SPECIAL_REF: return "SPECIAL_REF"; + case GENERIC_REF: return "GENERIC_REF"; case TRY: return "TRY"; case SEMI: return "SEMI"; case LB: return "LB"; @@ -344,7 +347,6 @@ public class Token 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 diff --git a/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java b/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java index 74f1cee8956..fe7c9183ac0 100644 --- a/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java +++ b/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java @@ -1850,6 +1850,10 @@ class BodyCodegen visitSpecialRef(node, child); break; + case Token.GENERIC_REF: + visitGenericRef(node, child); + break; + default: throw new RuntimeException("Unexpected node type "+type); } @@ -3508,12 +3512,26 @@ class BodyCodegen { int special = node.getExistingIntProp(Node.SPECIAL_PROP_PROP); generateCodeFromNode(child, node); - cfw.addALoad(variableObjectLocal); // get variable object - cfw.addPush(special); // push name + cfw.addPush(special); + cfw.addALoad(contextLocal); + cfw.addALoad(variableObjectLocal); addScriptRuntimeInvoke("specialReference", - "(Ljava/lang/Object;" + "(Ljava/lang/Object;I" + +"Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" - +"I)Ljava/lang/Object;"); + +")Ljava/lang/Object;"); + } + + private void visitGenericRef(Node node, Node child) + { + generateCodeFromNode(child, node); + cfw.addALoad(contextLocal); + cfw.addALoad(variableObjectLocal); + addScriptRuntimeInvoke("genericReference", + "(Ljava/lang/Object;" + +"Lorg/mozilla/javascript/Context;" + +"Lorg/mozilla/javascript/Scriptable;" + +")Ljava/lang/Object;"); } private int getLocalBlockRegister(Node node) diff --git a/js/rhino/src/org/mozilla/javascript/resources/Messages.properties b/js/rhino/src/org/mozilla/javascript/resources/Messages.properties index c4031245f54..828648a7f44 100644 --- a/js/rhino/src/org/mozilla/javascript/resources/Messages.properties +++ b/js/rhino/src/org/mozilla/javascript/resources/Messages.properties @@ -102,9 +102,6 @@ msg.method.not.found =\ msg.bad.for.in.lhs =\ Invalid left-hand side of for..in loop. -msg.bad.lhs.assign =\ - Invalid assignment left-hand side. - msg.mult.index =\ Only one variable allowed in for..in loop. @@ -417,6 +414,10 @@ msg.no.ref.from.function =\ Function {0} can not be used as the left-hand side of assignment \ or as an operand of ++ or -- operator. +msg.not.ref =\ + {0} can not be used as the left-hand side of assignment \ + or as an operand of ++ or -- operator. + msg.bad.default.value =\ Object''s getDefaultValue() method returned an object.