From 641450c9ba5cdaa5a496065870073407ed866cf1 Mon Sep 17 00:00:00 2001 From: Eric Faust Date: Wed, 26 Nov 2014 14:42:52 -0800 Subject: [PATCH] Bug 1101905 - Part 4: Add strict variant of JSOP_SETGNAME. (r=Waldo) --- js/src/frontend/BytecodeEmitter.cpp | 24 ++++++++++++++++++------ js/src/jit/BaselineCompiler.cpp | 6 ++++++ js/src/jit/BaselineCompiler.h | 1 + js/src/jit/BaselineIC.cpp | 4 +++- js/src/jit/IonBuilder.cpp | 1 + js/src/jit/VMFunctions.cpp | 2 +- js/src/jsopcode.h | 5 +++-- js/src/vm/Interpreter-inl.h | 7 ++++--- js/src/vm/Interpreter.cpp | 4 +++- js/src/vm/Opcodes.h | 15 +++++++++++++-- js/src/vm/Xdr.h | 2 +- 11 files changed, 54 insertions(+), 17 deletions(-) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 145be36657c7..2bf6beffd449 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -1522,6 +1522,10 @@ StrictifySetNameOp(JSOp op, BytecodeEmitter *bce) if (bce->sc->strict) op = JSOP_STRICTSETNAME; break; + case JSOP_SETGNAME: + if (bce->sc->strict) + op = JSOP_STRICTSETGNAME; + break; default:; } return op; @@ -1658,7 +1662,7 @@ TryConvertFreeName(BytecodeEmitter *bce, ParseNode *pn) JSOp op; switch (pn->getOp()) { case JSOP_NAME: op = JSOP_GETGNAME; break; - case JSOP_SETNAME: op = JSOP_SETGNAME; break; + case JSOP_SETNAME: op = StrictifySetNameOp(JSOP_SETGNAME, bce); break; case JSOP_SETCONST: // Not supported. return false; @@ -3351,6 +3355,7 @@ EmitDestructuringLHS(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, case JSOP_SETNAME: case JSOP_STRICTSETNAME: case JSOP_SETGNAME: + case JSOP_STRICTSETGNAME: case JSOP_SETCONST: { // This is like ordinary assignment, but with one difference. // @@ -3367,7 +3372,8 @@ EmitDestructuringLHS(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, return false; if (!pn->isOp(JSOP_SETCONST)) { - JSOp bindOp = pn->isOp(JSOP_SETGNAME) ? JSOP_BINDGNAME : JSOP_BINDNAME; + bool global = pn->isOp(JSOP_SETGNAME) || pn->isOp(JSOP_STRICTSETGNAME); + JSOp bindOp = global ? JSOP_BINDGNAME : JSOP_BINDNAME; if (!EmitIndex32(cx, bindOp, atomIndex, bce)) return false; if (Emit1(cx, bce, JSOP_SWAP) < 0) @@ -3893,12 +3899,17 @@ EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit if (pn3) { MOZ_ASSERT(emitOption != DefineVars); - if (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME || op == JSOP_SETGNAME || op == JSOP_SETINTRINSIC) { + if (op == JSOP_SETNAME || + op == JSOP_STRICTSETNAME || + op == JSOP_SETGNAME || + op == JSOP_STRICTSETGNAME || + op == JSOP_SETINTRINSIC) + { MOZ_ASSERT(emitOption != PushInitialValues); JSOp bindOp; if (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME) bindOp = JSOP_BINDNAME; - else if (op == JSOP_SETGNAME) + else if (op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME) bindOp = JSOP_BINDGNAME; else bindOp = JSOP_BINDINTRINSIC; @@ -3974,7 +3985,7 @@ EmitAssignment(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp JSOp bindOp; if (lhs->isOp(JSOP_SETNAME) || lhs->isOp(JSOP_STRICTSETNAME)) bindOp = JSOP_BINDNAME; - else if (lhs->isOp(JSOP_SETGNAME)) + else if (lhs->isOp(JSOP_SETGNAME) || lhs->isOp(JSOP_STRICTSETGNAME)) bindOp = JSOP_BINDGNAME; else bindOp = JSOP_BINDINTRINSIC; @@ -4034,7 +4045,7 @@ EmitAssignment(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp return false; if (!EmitIndex32(cx, JSOP_GETXPROP, atomIndex, bce)) return false; - } else if (lhs->isOp(JSOP_SETGNAME)) { + } else if (lhs->isOp(JSOP_SETGNAME) || lhs->isOp(JSOP_STRICTSETGNAME)) { MOZ_ASSERT(lhs->pn_cookie.isFree()); if (!EmitAtomOp(cx, lhs, JSOP_GETGNAME, bce)) return false; @@ -6311,6 +6322,7 @@ EmitIncOrDec(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) case JSOP_SETNAME: case JSOP_STRICTSETNAME: case JSOP_SETGNAME: + case JSOP_STRICTSETGNAME: maySet = true; break; default: diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index d8a6f9c9e770..3a2e946cf650 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2082,6 +2082,12 @@ BaselineCompiler::emit_JSOP_SETGNAME() return emit_JSOP_SETPROP(); } +bool +BaselineCompiler::emit_JSOP_STRICTSETGNAME() +{ + return emit_JSOP_SETPROP(); +} + bool BaselineCompiler::emit_JSOP_GETPROP() { diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h index 09b1dc90ca9c..e4aa1d218092 100644 --- a/js/src/jit/BaselineCompiler.h +++ b/js/src/jit/BaselineCompiler.h @@ -115,6 +115,7 @@ namespace jit { _(JSOP_GETGNAME) \ _(JSOP_BINDGNAME) \ _(JSOP_SETGNAME) \ + _(JSOP_STRICTSETGNAME) \ _(JSOP_SETNAME) \ _(JSOP_STRICTSETNAME) \ _(JSOP_GETPROP) \ diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 13eb448e7f7b..735c57b3ab06 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -7900,6 +7900,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_ op == JSOP_SETNAME || op == JSOP_STRICTSETNAME || op == JSOP_SETGNAME || + op == JSOP_STRICTSETGNAME || op == JSOP_INITPROP || op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLEXICAL); @@ -7943,7 +7944,8 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_ } } else if (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME || - op == JSOP_SETGNAME) + op == JSOP_SETGNAME || + op == JSOP_STRICTSETGNAME) { if (!SetNameOperation(cx, script, pc, obj, rhs)) return false; diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 232d1a9c032e..697448bd502b 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -1680,6 +1680,7 @@ IonBuilder::inspectOpcode(JSOp op) return pushConstant(ObjectValue(script()->global())); case JSOP_SETGNAME: + case JSOP_STRICTSETGNAME: { PropertyName *name = info().getAtom(pc)->asPropertyName(); JSObject *obj = &script()->global(); diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index d3f87915d014..8c3dafb63762 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -508,7 +508,7 @@ SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValu return baseops::SetPropertyHelper( cx, obj.as(), obj.as(), id, (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME || - op == JSOP_SETGNAME) + op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME) ? baseops::Unqualified : baseops::Qualified, &v, diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index dafcebbb44c8..426dfa19968d 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -659,7 +659,8 @@ IsStrictSetPC(jsbytecode *pc) { JSOp op = JSOp(*pc); return op == JSOP_STRICTSETPROP || - op == JSOP_STRICTSETNAME; + op == JSOP_STRICTSETNAME || + op == JSOP_STRICTSETGNAME; } inline bool @@ -668,7 +669,7 @@ IsSetPropPC(jsbytecode *pc) JSOp op = JSOp(*pc); return op == JSOP_SETPROP || op == JSOP_STRICTSETPROP || op == JSOP_SETNAME || op == JSOP_STRICTSETNAME || - op == JSOP_SETGNAME; + op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME; } inline bool diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 5c887f90d297..79d00b62a318 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -307,11 +307,12 @@ SetNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleObject s { MOZ_ASSERT(*pc == JSOP_SETNAME || *pc == JSOP_STRICTSETNAME || - *pc == JSOP_SETGNAME); + *pc == JSOP_SETGNAME || + *pc == JSOP_STRICTSETGNAME); MOZ_ASSERT_IF(*pc == JSOP_SETGNAME, scope == cx->global()); + MOZ_ASSERT_IF(*pc == JSOP_STRICTSETGNAME, scope == cx->global()); - // XXX: Removed later in stack. SETGNAME still relies on script. - bool strict = *pc == JSOP_STRICTSETNAME || script->strict(); + bool strict = *pc == JSOP_STRICTSETNAME || *pc == JSOP_STRICTSETGNAME; RootedPropertyName name(cx, script->getName(pc)); RootedValue valCopy(cx, val); diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 4fafd8e06cad..c4e0f02fa944 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1608,7 +1608,6 @@ CASE(JSOP_UNUSED147) CASE(JSOP_UNUSED148) CASE(JSOP_BACKPATCH) CASE(JSOP_UNUSED150) -CASE(JSOP_UNUSED156) CASE(JSOP_UNUSED157) CASE(JSOP_UNUSED158) CASE(JSOP_UNUSED159) @@ -2381,11 +2380,14 @@ CASE(JSOP_SETINTRINSIC) END_CASE(JSOP_SETINTRINSIC) CASE(JSOP_SETGNAME) +CASE(JSOP_STRICTSETGNAME) CASE(JSOP_SETNAME) CASE(JSOP_STRICTSETNAME) { static_assert(JSOP_SETNAME_LENGTH == JSOP_STRICTSETNAME_LENGTH, "setname and strictsetname must be the same size"); + static_assert(JSOP_SETGNAME_LENGTH == JSOP_STRICTSETGNAME_LENGTH, + "setganem adn strictsetgname must be the same size"); RootedObject &scope = rootObject0; scope = ®S.sp[-2].toObject(); HandleValue value = REGS.stackHandleAt(-1); diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index 39a4043eee77..a11796dba292 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -1444,9 +1444,20 @@ * Operands: uint32_t nameIndex * Stack: scope, val => val */ \ - macro(JSOP_SETGNAME, 155,"setgname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME) \ + macro(JSOP_SETGNAME, 155,"setgname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME|JOF_CHECKSLOPPY) \ \ - macro(JSOP_UNUSED156, 156, "unused156", NULL, 1, 0, 0, JOF_BYTE) \ + /* + * Pops the top two values on the stack as 'val' and 'scope', sets property + * of 'scope' as 'val' and pushes 'val' back on the stack. Throws a + * TypeError if the set fails, per strict mode semantics. + * + * 'scope' should be the global scope. + * Category: Variables and Scopes + * Type: Free Variables + * Operands: uint32_t nameIndex + * Stack: scope, val => val + */ \ + macro(JSOP_STRICTSETGNAME, 156, "strict-setgname", NULL, 5, 2, 1, JOF_ATOM|JOF_NAME|JOF_SET|JOF_DETECTING|JOF_GNAME|JOF_CHECKSTRICT) \ macro(JSOP_UNUSED157, 157, "unused157", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED158, 158, "unused158", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED159, 159, "unused159", NULL, 1, 0, 0, JOF_BYTE) \ diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index c3eeba0b91e3..453e872f2ba4 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -34,7 +34,7 @@ namespace js { * Nightly) and without (all others). FIXME: Bug 1066322 - Enable ES6 symbols * in all builds. */ -static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 212; +static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 214; static_assert(XDR_BYTECODE_VERSION_SUBTRAHEND % 2 == 0, "see the comment above"); static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - (XDR_BYTECODE_VERSION_SUBTRAHEND