mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-23 18:26:15 +00:00
Bug 1141863 - Part 2: Implement ES6 SuperCall. (r=jandem, r=jorendorff)
This commit is contained in:
parent
3eab0ab893
commit
6cbeeeb97c
@ -3111,13 +3111,20 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
||||
case PNK_NEW:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
case PNK_CALL:
|
||||
case PNK_SUPERCALL:
|
||||
{
|
||||
ParseNode* next = pn->pn_head;
|
||||
MOZ_ASSERT(pn->pn_pos.encloses(next->pn_pos));
|
||||
|
||||
RootedValue callee(cx);
|
||||
if (!expression(next, &callee))
|
||||
return false;
|
||||
if (pn->isKind(PNK_SUPERCALL)) {
|
||||
MOZ_ASSERT(next->isKind(PNK_POSHOLDER));
|
||||
if (!builder.super(&next->pn_pos, &callee))
|
||||
return false;
|
||||
} else {
|
||||
if (!expression(next, &callee))
|
||||
return false;
|
||||
}
|
||||
|
||||
NodeVector args(cx);
|
||||
if (!args.reserve(pn->pn_count - 1))
|
||||
@ -3135,6 +3142,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
||||
if (pn->getKind() == PNK_TAGGED_TEMPLATE)
|
||||
return builder.taggedTemplate(callee, args, &pn->pn_pos, dst);
|
||||
|
||||
// SUPERCALL is Call(super, args)
|
||||
return pn->isKind(PNK_NEW)
|
||||
? builder.newExpression(callee, args, &pn->pn_pos, dst)
|
||||
|
||||
|
@ -2190,6 +2190,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||
case PNK_NEW:
|
||||
case PNK_CALL:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
case PNK_SUPERCALL:
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
*answer = true;
|
||||
return true;
|
||||
@ -6732,6 +6733,12 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||
}
|
||||
callop = false;
|
||||
break;
|
||||
case PNK_POSHOLDER:
|
||||
MOZ_ASSERT(pn->isKind(PNK_SUPERCALL));
|
||||
MOZ_ASSERT(parser->handler.isSuperBase(pn2, cx));
|
||||
if (!emit1(JSOP_SUPERFUN))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
if (!emitTree(pn2))
|
||||
return false;
|
||||
@ -6744,7 +6751,8 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW;
|
||||
bool isNewOp = pn->getOp() == JSOP_NEW || pn->getOp() == JSOP_SPREADNEW ||
|
||||
pn->getOp() == JSOP_SUPERCALL || pn->getOp() == JSOP_SPREADSUPERCALL;;
|
||||
|
||||
/*
|
||||
* Emit code for each argument in order, then emit the JSOP_*CALL or
|
||||
@ -6760,17 +6768,27 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||
}
|
||||
|
||||
if (isNewOp) {
|
||||
// Repush the callee as new.target
|
||||
if (!emitDupAt(argc + 1))
|
||||
return false;
|
||||
if (pn->isKind(PNK_SUPERCALL)) {
|
||||
if (!emit1(JSOP_NEWTARGET))
|
||||
return false;
|
||||
} else {
|
||||
// Repush the callee as new.target
|
||||
if (!emitDupAt(argc + 1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!emitArray(pn2->pn_next, argc, JSOP_SPREADCALLARRAY))
|
||||
return false;
|
||||
|
||||
if (isNewOp) {
|
||||
if (!emitDupAt(2))
|
||||
return false;
|
||||
if (pn->isKind(PNK_SUPERCALL)) {
|
||||
if (!emit1(JSOP_NEWTARGET))
|
||||
return false;
|
||||
} else {
|
||||
if (!emitDupAt(2))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
emittingForInit = oldEmittingForInit;
|
||||
@ -6796,6 +6814,9 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn)
|
||||
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_BAD_LEFTSIDE_OF_ASS))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pn->isKind(PNK_SUPERCALL) && !emit1(JSOP_SETTHIS))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -7852,6 +7873,7 @@ BytecodeEmitter::emitTree(ParseNode* pn)
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
case PNK_CALL:
|
||||
case PNK_GENEXP:
|
||||
case PNK_SUPERCALL:
|
||||
ok = emitCallOrNew(pn);
|
||||
break;
|
||||
|
||||
|
@ -414,6 +414,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
|
||||
case PNK_CLASSNAMES:
|
||||
case PNK_NEWTARGET:
|
||||
case PNK_POSHOLDER:
|
||||
case PNK_SUPERCALL:
|
||||
MOZ_CRASH("ContainsHoistedDeclaration should have indicated false on "
|
||||
"some parent node without recurring to test this node");
|
||||
|
||||
@ -1579,7 +1580,8 @@ static bool
|
||||
FoldCall(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandler>& parser,
|
||||
bool inGenexpLambda)
|
||||
{
|
||||
MOZ_ASSERT(node->isKind(PNK_CALL) || node->isKind(PNK_TAGGED_TEMPLATE));
|
||||
MOZ_ASSERT(node->isKind(PNK_CALL) || node->isKind(PNK_SUPERCALL) ||
|
||||
node->isKind(PNK_TAGGED_TEMPLATE));
|
||||
MOZ_ASSERT(node->isArity(PN_LIST));
|
||||
|
||||
// Don't fold a parenthesized callable component in an invocation, as this
|
||||
@ -1876,6 +1878,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
|
||||
return FoldAdd(cx, pnp, parser, inGenexpLambda);
|
||||
|
||||
case PNK_CALL:
|
||||
case PNK_SUPERCALL:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
return FoldCall(cx, pn, parser, inGenexpLambda);
|
||||
|
||||
|
@ -376,6 +376,7 @@ class NameResolver
|
||||
case PNK_EXPORT_BATCH_SPEC:
|
||||
case PNK_FRESHENBLOCK:
|
||||
case PNK_OBJECT_PROPERTY_NAME:
|
||||
case PNK_POSHOLDER:
|
||||
MOZ_ASSERT(cur->isArity(PN_NULLARY));
|
||||
break;
|
||||
|
||||
@ -673,6 +674,7 @@ class NameResolver
|
||||
case PNK_COMMA:
|
||||
case PNK_NEW:
|
||||
case PNK_CALL:
|
||||
case PNK_SUPERCALL:
|
||||
case PNK_GENEXP:
|
||||
case PNK_ARRAY:
|
||||
case PNK_STATEMENTLIST:
|
||||
@ -796,7 +798,6 @@ class NameResolver
|
||||
case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST
|
||||
case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
|
||||
case PNK_CLASSNAMES: // by PNK_CLASS
|
||||
case PNK_POSHOLDER: // by PNK_NEWTARGET, PNK_DOT
|
||||
MOZ_CRASH("should have been handled by a parent node");
|
||||
|
||||
case PNK_LIMIT: // invalid sentinel value
|
||||
|
@ -489,6 +489,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
|
||||
case PNK_COMMA:
|
||||
case PNK_NEW:
|
||||
case PNK_CALL:
|
||||
case PNK_SUPERCALL:
|
||||
case PNK_GENEXP:
|
||||
case PNK_ARRAY:
|
||||
case PNK_OBJECT:
|
||||
|
@ -175,6 +175,7 @@ class PackedScopeCoordinate
|
||||
F(CLASSNAMES) \
|
||||
F(NEWTARGET) \
|
||||
F(POSHOLDER) \
|
||||
F(SUPERCALL) \
|
||||
\
|
||||
/* Unary operators. */ \
|
||||
F(TYPEOFNAME) \
|
||||
|
@ -8648,9 +8648,31 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
|
||||
tt == TOK_NO_SUBS_TEMPLATE)
|
||||
{
|
||||
if (handler.isSuperBase(lhs, context)) {
|
||||
// For now...
|
||||
report(ParseError, false, null(), JSMSG_BAD_SUPER);
|
||||
return null();
|
||||
if (!pc->sc->isFunctionBox() || !pc->sc->asFunctionBox()->isDerivedClassConstructor()) {
|
||||
report(ParseError, false, null(), JSMSG_BAD_SUPERCALL);
|
||||
return null();
|
||||
}
|
||||
|
||||
if (tt != TOK_LP) {
|
||||
report(ParseError, false, null(), JSMSG_BAD_SUPER);
|
||||
return null();
|
||||
}
|
||||
|
||||
nextMember = handler.newList(PNK_SUPERCALL, lhs, JSOP_SUPERCALL);
|
||||
if (!nextMember)
|
||||
return null();
|
||||
|
||||
// Despite the fact that it's impossible to have |super()| is a
|
||||
// generator, we still inherity the yieldHandling of the
|
||||
// memberExpression, per spec. Curious.
|
||||
bool isSpread = false;
|
||||
if (!argumentList(yieldHandling, nextMember, &isSpread))
|
||||
return null();
|
||||
|
||||
if (isSpread)
|
||||
handler.setOp(nextMember, JSOP_SPREADSUPERCALL);
|
||||
|
||||
return nextMember;
|
||||
}
|
||||
|
||||
nextMember = tt == TOK_LP ? handler.newCall() : handler.newTaggedTemplate();
|
||||
|
@ -374,6 +374,7 @@ class FunctionBox : public ObjectBox, public SharedContext
|
||||
hasExtensibleScope() ||
|
||||
needsDeclEnvObject() ||
|
||||
needsHomeObject() ||
|
||||
isDerivedClassConstructor() ||
|
||||
isGenerator();
|
||||
}
|
||||
};
|
||||
|
@ -2903,7 +2903,7 @@ BaselineCompiler::emitCall()
|
||||
{
|
||||
MOZ_ASSERT(IsCallPC(pc));
|
||||
|
||||
bool construct = JSOp(*pc) == JSOP_NEW;
|
||||
bool construct = JSOp(*pc) == JSOP_NEW || JSOp(*pc) == JSOP_SUPERCALL;
|
||||
uint32_t argc = GET_ARGC(pc);
|
||||
|
||||
frame.syncStack(0);
|
||||
@ -2930,13 +2930,13 @@ BaselineCompiler::emitSpreadCall()
|
||||
masm.move32(Imm32(1), R0.scratchReg());
|
||||
|
||||
// Call IC
|
||||
ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ JSOp(*pc) == JSOP_SPREADNEW,
|
||||
bool construct = JSOp(*pc) == JSOP_SPREADNEW || JSOp(*pc) == JSOP_SPREADSUPERCALL;
|
||||
ICCall_Fallback::Compiler stubCompiler(cx, /* isConstructing = */ construct,
|
||||
/* isSpread = */ true);
|
||||
if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
|
||||
return false;
|
||||
|
||||
// Update FrameInfo.
|
||||
bool construct = JSOp(*pc) == JSOP_SPREADNEW;
|
||||
frame.popn(3 + construct);
|
||||
frame.push(R0);
|
||||
return true;
|
||||
@ -2954,6 +2954,12 @@ BaselineCompiler::emit_JSOP_NEW()
|
||||
return emitCall();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SUPERCALL()
|
||||
{
|
||||
return emitCall();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_FUNCALL()
|
||||
{
|
||||
@ -2990,6 +2996,12 @@ BaselineCompiler::emit_JSOP_SPREADNEW()
|
||||
return emitSpreadCall();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SPREADSUPERCALL()
|
||||
{
|
||||
return emitSpreadCall();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_SPREADEVAL()
|
||||
{
|
||||
|
@ -201,7 +201,9 @@ namespace jit {
|
||||
_(JSOP_SETRVAL) \
|
||||
_(JSOP_RETRVAL) \
|
||||
_(JSOP_RETURN) \
|
||||
_(JSOP_NEWTARGET)
|
||||
_(JSOP_NEWTARGET) \
|
||||
_(JSOP_SUPERCALL) \
|
||||
_(JSOP_SPREADSUPERCALL)
|
||||
|
||||
class BaselineCompiler : public BaselineCompilerSpecific
|
||||
{
|
||||
|
@ -8644,6 +8644,8 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
|
||||
JSOp op, uint32_t argc, Value* vp, bool constructing, bool isSpread,
|
||||
bool createSingleton, bool* handled)
|
||||
{
|
||||
bool isSuper = op == JSOP_SUPERCALL || op == JSOP_SPREADSUPERCALL;
|
||||
|
||||
if (createSingleton || op == JSOP_EVAL || op == JSOP_STRICTEVAL)
|
||||
return true;
|
||||
|
||||
@ -8751,9 +8753,11 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
|
||||
EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
|
||||
|
||||
// Remember the template object associated with any script being called
|
||||
// as a constructor, for later use during Ion compilation.
|
||||
// as a constructor, for later use during Ion compilation. This is unsound
|
||||
// for super(), as a single callsite can have multiple possible prototype object
|
||||
// created (via different newTargets)
|
||||
RootedObject templateObject(cx);
|
||||
if (constructing) {
|
||||
if (constructing && !isSuper) {
|
||||
// If we are calling a constructor for which the new script
|
||||
// properties analysis has not been performed yet, don't attach a
|
||||
// stub. After the analysis is performed, CreateThisForFunction may
|
||||
@ -8853,7 +8857,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
|
||||
}
|
||||
|
||||
RootedObject templateObject(cx);
|
||||
if (MOZ_LIKELY(!isSpread)) {
|
||||
if (MOZ_LIKELY(!isSpread && !isSuper)) {
|
||||
bool skipAttach = false;
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject, &skipAttach))
|
||||
|
@ -1867,7 +1867,8 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||
|
||||
case JSOP_CALL:
|
||||
case JSOP_NEW:
|
||||
return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW);
|
||||
case JSOP_SUPERCALL:
|
||||
return jsop_call(GET_ARGC(pc), (JSOp)*pc == JSOP_NEW || (JSOp)*pc == JSOP_SUPERCALL);
|
||||
|
||||
case JSOP_EVAL:
|
||||
case JSOP_STRICTEVAL:
|
||||
@ -6140,6 +6141,8 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee)
|
||||
return nullptr;
|
||||
|
||||
JSObject* templateObject = inspector->getTemplateObject(pc);
|
||||
if (!templateObject)
|
||||
return nullptr;
|
||||
if (!templateObject->is<PlainObject>() && !templateObject->is<UnboxedPlainObject>())
|
||||
return nullptr;
|
||||
|
||||
|
@ -214,6 +214,7 @@ MSG_DEF(JSMSG_BAD_STRICT_ASSIGN, 1, JSEXN_SYNTAXERR, "can't assign to {0}
|
||||
MSG_DEF(JSMSG_BAD_SWITCH, 0, JSEXN_SYNTAXERR, "invalid switch statement")
|
||||
MSG_DEF(JSMSG_BAD_SUPER, 0, JSEXN_SYNTAXERR, "invalid use of keyword 'super'")
|
||||
MSG_DEF(JSMSG_BAD_SUPERPROP, 1, JSEXN_SYNTAXERR, "use of super {0} accesses only valid within methods or eval code within methods")
|
||||
MSG_DEF(JSMSG_BAD_SUPERCALL, 0, JSEXN_SYNTAXERR, "super() is only valid in derived class constructors")
|
||||
MSG_DEF(JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION, 0, JSEXN_SYNTAXERR, "missing ] after array comprehension")
|
||||
MSG_DEF(JSMSG_BRACKET_AFTER_LIST, 0, JSEXN_SYNTAXERR, "missing ] after element list")
|
||||
MSG_DEF(JSMSG_BRACKET_IN_INDEX, 0, JSEXN_SYNTAXERR, "missing ] in index expression")
|
||||
@ -509,6 +510,7 @@ MSG_DEF(JSMSG_NO_INDEXED_SETTER, 2, JSEXN_TYPEERR, "{0} doesn't have an
|
||||
|
||||
// Super
|
||||
MSG_DEF(JSMSG_CANT_DELETE_SUPER, 0, JSEXN_REFERENCEERR, "invalid delete involving 'super'")
|
||||
MSG_DEF(JSMSG_REINIT_THIS, 0, JSEXN_REFERENCEERR, "super() called twice in derived class constructor")
|
||||
|
||||
// Modules
|
||||
MSG_DEF(JSMSG_BAD_DEFAULT_EXPORT, 0, JSEXN_SYNTAXERR, "default export cannot be provided by export *")
|
||||
|
@ -156,6 +156,7 @@ class JSFunction : public js::NativeObject
|
||||
nonLazyScript()->funHasExtensibleScope() ||
|
||||
nonLazyScript()->funNeedsDeclEnvObject() ||
|
||||
nonLazyScript()->needsHomeObject() ||
|
||||
nonLazyScript()->isDerivedClassConstructor() ||
|
||||
isGenerator();
|
||||
}
|
||||
|
||||
|
@ -125,6 +125,7 @@ js::StackUses(JSScript* script, jsbytecode* pc)
|
||||
case JSOP_POPN:
|
||||
return GET_UINT16(pc);
|
||||
case JSOP_NEW:
|
||||
case JSOP_SUPERCALL:
|
||||
return 2 + GET_ARGC(pc) + 1;
|
||||
default:
|
||||
/* stack: fun, this, [argc arguments] */
|
||||
|
@ -36,16 +36,14 @@ class base {
|
||||
override() { overrideCalled = "base" }
|
||||
}
|
||||
class derived extends base {
|
||||
constructor() { };
|
||||
constructor() { super(); };
|
||||
override() { overrideCalled = "derived"; }
|
||||
}
|
||||
var derivedExpr = class extends base {
|
||||
constructor() { };
|
||||
constructor() { super(); };
|
||||
override() { overrideCalled = "derived"; }
|
||||
};
|
||||
|
||||
assertThrowsInstanceOf(()=>new derived(), TypeError, "You implemented |super()|?!");
|
||||
/*
|
||||
// Make sure we get the right object layouts.
|
||||
for (let extension of [derived, derivedExpr]) {
|
||||
baseMethodCalled = false;
|
||||
@ -67,7 +65,6 @@ for (let extension of [derived, derivedExpr]) {
|
||||
extension.staticMethod();
|
||||
assertEq(staticMethodCalled, true);
|
||||
}
|
||||
*/
|
||||
|
||||
// Gotta extend an object, or null.
|
||||
function nope() {
|
||||
|
@ -28,9 +28,7 @@ var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
dbg.onDebuggerStatement = function(frame) { assertThrowsInstanceOf(()=>frame.eval(''), InternalError); };
|
||||
|
||||
// Remove the assertion and add super() when super() is implemented!
|
||||
assertThrownErrorContains(() => g.eval("new class foo extends null { constructor() { debugger; } }"), "|this|");
|
||||
// g.eval("new class foo extends null { constructor() { debugger; } }()");
|
||||
g.eval("new class foo extends null { constructor() { debugger; return {}; } }()");
|
||||
`;
|
||||
|
||||
if (classesEnabled())
|
||||
|
@ -13,7 +13,7 @@ class base {
|
||||
}
|
||||
|
||||
class derived extends base {
|
||||
constructor() {}
|
||||
constructor() { super(); }
|
||||
|
||||
get a() { return super.getValue(); }
|
||||
set a(v) { super.setValue(v); }
|
||||
@ -31,11 +31,8 @@ class derived extends base {
|
||||
}
|
||||
}
|
||||
|
||||
assertThrowsInstanceOf(()=>new derived(), TypeError, "You implemented |super()|?!");
|
||||
/*
|
||||
var derivedInstance = new derived();
|
||||
derivedInstance.test();
|
||||
*/
|
||||
|
||||
`;
|
||||
|
||||
|
@ -4,19 +4,17 @@ class Base {
|
||||
constructor() {}
|
||||
}
|
||||
class Mid extends Base {
|
||||
constructor() {}
|
||||
constructor() { super(); }
|
||||
f() { return new super.constructor(); }
|
||||
}
|
||||
class Derived extends Mid {
|
||||
constructor() {}
|
||||
constructor() { super(); }
|
||||
}
|
||||
|
||||
assertThrowsInstanceOf(()=>new Derived(), TypeError, "You implemented |super()|?!");
|
||||
/*
|
||||
let d = new Derived();
|
||||
var df = d.f();
|
||||
assertEq(df.constructor, Base);
|
||||
*/
|
||||
|
||||
`;
|
||||
|
||||
if (classesEnabled())
|
||||
|
@ -9,7 +9,7 @@ class base {
|
||||
}
|
||||
|
||||
class middle extends base {
|
||||
constructor() { }
|
||||
constructor() { super(); }
|
||||
testChain() {
|
||||
this.middleCalled = true;
|
||||
super.testChain();
|
||||
@ -17,7 +17,7 @@ class middle extends base {
|
||||
}
|
||||
|
||||
class derived extends middle {
|
||||
constructor() { }
|
||||
constructor() { super(); }
|
||||
testChain() {
|
||||
super.testChain();
|
||||
assertEq(this.middleCalled, true);
|
||||
@ -25,8 +25,6 @@ class derived extends middle {
|
||||
}
|
||||
}
|
||||
|
||||
assertThrowsInstanceOf(()=>new derived(), TypeError, "You implemented |super()|?!");
|
||||
/*
|
||||
new derived().testChain();
|
||||
|
||||
// Super even chains in a wellbehaved fashion with normal functions.
|
||||
@ -34,7 +32,7 @@ function bootlegMiddle() { }
|
||||
bootlegMiddle.prototype = middle.prototype;
|
||||
|
||||
new class extends bootlegMiddle {
|
||||
constructor() { }
|
||||
constructor() { super(); }
|
||||
testChain() {
|
||||
super.testChain();
|
||||
assertEq(this.middleCalled, true);
|
||||
@ -45,11 +43,11 @@ new class extends bootlegMiddle {
|
||||
// Now let's try out some "long" chains
|
||||
base.prototype.x = "yeehaw";
|
||||
|
||||
let chain = class extends base { constructor() { } }
|
||||
let chain = class extends base { constructor() { super(); } }
|
||||
|
||||
const CHAIN_LENGTH = 100;
|
||||
for (let i = 0; i < CHAIN_LENGTH; i++)
|
||||
chain = class extends chain { constructor() { } }
|
||||
chain = class extends chain { constructor() { super(); } }
|
||||
|
||||
// Now we poke the chain
|
||||
let inst = new chain();
|
||||
@ -57,7 +55,7 @@ inst.testChain();
|
||||
assertEq(inst.baseCalled, true);
|
||||
|
||||
assertEq(inst.x, "yeehaw");
|
||||
*/
|
||||
|
||||
`;
|
||||
|
||||
if (classesEnabled())
|
||||
|
@ -8,7 +8,7 @@ class base {
|
||||
}
|
||||
|
||||
class derived extends base {
|
||||
constructor() { }
|
||||
constructor() { super(); }
|
||||
testDeleteProp() { delete super.prop; }
|
||||
testDeleteElem() {
|
||||
let sideEffect = 0;
|
||||
@ -22,9 +22,6 @@ class derived extends base {
|
||||
}
|
||||
}
|
||||
|
||||
assertThrowsInstanceOf(()=> new derived(), TypeError, "You implemented |super()|?!");
|
||||
|
||||
/*
|
||||
var d = new derived();
|
||||
assertThrowsInstanceOf(() => d.testDeleteProp(), ReferenceError);
|
||||
d.testDeleteElem();
|
||||
@ -46,7 +43,7 @@ Object.setPrototypeOf(thing2, new Proxy({}, {
|
||||
deleteProperty(x) { throw "FAIL"; }
|
||||
}));
|
||||
assertThrowsInstanceOf(() => thing2.go(), ReferenceError);
|
||||
*/
|
||||
|
||||
`;
|
||||
|
||||
if (classesEnabled())
|
||||
|
@ -26,7 +26,7 @@ class base {
|
||||
}
|
||||
|
||||
class derived extends base {
|
||||
constructor() { }
|
||||
constructor() { super(); }
|
||||
|
||||
// |super| actually checks the chain, not |this|
|
||||
method() { throw "FAIL"; }
|
||||
@ -70,13 +70,11 @@ class derived extends base {
|
||||
|
||||
}
|
||||
|
||||
assertThrowsInstanceOf(()=>new derived(), TypeError, "You implemented |super()|?!");
|
||||
/*
|
||||
derivedInstance = new derived();
|
||||
derivedInstance.test();
|
||||
derivedInstance.testInEval();
|
||||
derivedInstance.testInArrow();
|
||||
*/
|
||||
|
||||
`;
|
||||
|
||||
if (classesEnabled())
|
||||
|
@ -22,7 +22,7 @@ Object.defineProperty(base.prototype, "intendent",
|
||||
|
||||
const testArr = [525600, "Fred"];
|
||||
class derived extends base {
|
||||
constructor() { }
|
||||
constructor() { super(); }
|
||||
prepForTest() { seenValues = []; }
|
||||
testAsserts() { assertDeepEq(seenValues, testArr); }
|
||||
testProps() {
|
||||
@ -37,12 +37,10 @@ class derived extends base {
|
||||
}
|
||||
}
|
||||
|
||||
assertThrowsInstanceOf(()=>new derived(), TypeError, "You implemented |super()|?!");
|
||||
/*
|
||||
let d = new derived();
|
||||
d.testProps();
|
||||
d.testElems();
|
||||
*/
|
||||
|
||||
`;
|
||||
|
||||
if (classesEnabled())
|
||||
|
@ -14,14 +14,12 @@ class base {
|
||||
}
|
||||
|
||||
class derived extends base {
|
||||
constructor() { }
|
||||
constructor() { super(); }
|
||||
test(expected) { super.test(expected); }
|
||||
testArrow() { return (() => super.test(this)); }
|
||||
["testCPN"](expected) { super.test(expected); }
|
||||
}
|
||||
|
||||
assertThrowsInstanceOf(()=>new derived(), TypeError, "You implemented |super()|?!");
|
||||
/*
|
||||
let derivedInstance = new derived();
|
||||
derivedInstance.test(derivedInstance);
|
||||
derivedInstance.testCPN(derivedInstance);
|
||||
@ -57,11 +55,11 @@ class base2 {
|
||||
let animals = [];
|
||||
for (let exprBase of [base1, base2])
|
||||
new class extends exprBase {
|
||||
constructor() { }
|
||||
constructor() { super(); }
|
||||
test() { animals.push(super["test"]()); }
|
||||
}().test();
|
||||
assertDeepEq(animals, ["llama", "alpaca"]);
|
||||
*/
|
||||
|
||||
`;
|
||||
|
||||
if (classesEnabled())
|
||||
|
@ -6,7 +6,7 @@ class base {
|
||||
}
|
||||
|
||||
class derived extends base {
|
||||
constructor() { this.methodCalled = 0; }
|
||||
constructor() { super(); this.methodCalled = 0; }
|
||||
|
||||
// Test orderings of various evaluations relative to the superbase
|
||||
|
||||
@ -70,8 +70,6 @@ function reset() {
|
||||
Object.setPrototypeOf(derived.prototype, base.prototype);
|
||||
}
|
||||
|
||||
assertThrowsInstanceOf(() => new derived(), TypeError, "You implemented |super()|?!");
|
||||
/*
|
||||
let instance = new derived();
|
||||
assertThrowsInstanceOf(() => instance.testElem(), TypeError);
|
||||
reset();
|
||||
@ -92,7 +90,7 @@ instance.testAssignElemPropValChange();
|
||||
instance.testAssignProp();
|
||||
|
||||
instance.testCompoundAssignProp();
|
||||
*/
|
||||
|
||||
`;
|
||||
|
||||
if (classesEnabled())
|
||||
|
@ -10,7 +10,7 @@ class base {
|
||||
let standin = { test() { return true; } };
|
||||
|
||||
class derived extends base {
|
||||
constructor() { }
|
||||
constructor() { super(); }
|
||||
test() {
|
||||
assertEq(super.test(), false);
|
||||
Object.setPrototypeOf(derived.prototype, standin);
|
||||
@ -18,8 +18,7 @@ class derived extends base {
|
||||
}
|
||||
}
|
||||
|
||||
// This shouldn't throw, but we don't have |super()| yet.
|
||||
assertThrowsInstanceOf(() => new derived().test(), TypeError);
|
||||
new derived().test();
|
||||
|
||||
`;
|
||||
|
||||
|
@ -11,7 +11,7 @@ let midStaticHandler = { };
|
||||
let getterCalled, setterCalled;
|
||||
|
||||
class mid extends new Proxy(base, midStaticHandler) {
|
||||
constructor() { }
|
||||
constructor() { super(); }
|
||||
testSuperInProxy() {
|
||||
super.prop = "looking";
|
||||
assertEq(setterCalled, true);
|
||||
@ -21,7 +21,7 @@ class mid extends new Proxy(base, midStaticHandler) {
|
||||
}
|
||||
|
||||
class child extends mid {
|
||||
constructor() { }
|
||||
constructor() { super(); }
|
||||
static testStaticLookups() {
|
||||
// This funtion is called more than once.
|
||||
this.called = false;
|
||||
@ -30,9 +30,6 @@ class child extends mid {
|
||||
}
|
||||
}
|
||||
|
||||
assertThrowsInstanceOf(()=> new mid(), TypeError, "You implemented |super()|?!");
|
||||
|
||||
/*
|
||||
let midInstance = new mid();
|
||||
|
||||
// Make sure proxies are searched properly on the prototype chain
|
||||
@ -83,7 +80,7 @@ var wrappedBase = g.eval("({ method() { return this.__secretProp__; } })");
|
||||
var unwrappedDerived = { __secretProp__: 42, method() { return super.method(); } }
|
||||
Object.setPrototypeOf(unwrappedDerived, wrappedBase);
|
||||
assertEq(unwrappedDerived.method(), 42);
|
||||
*/
|
||||
|
||||
`;
|
||||
|
||||
if (classesEnabled())
|
||||
|
@ -9,7 +9,7 @@ class base {
|
||||
}
|
||||
|
||||
class derived extends base {
|
||||
constructor() { this.prop = "flamingo"; }
|
||||
constructor() { super(); this.prop = "flamingo"; }
|
||||
|
||||
toString() { throw "No!"; }
|
||||
|
||||
@ -38,13 +38,11 @@ class derived extends base {
|
||||
|
||||
Object.defineProperty(derived.prototype, "nonWritableProp", { writable: false, value: "pony" });
|
||||
|
||||
assertThrowsInstanceOf(()=> new derived(), TypeError, "You implemented |super()|?!");
|
||||
/*
|
||||
let instance = new derived();
|
||||
instance.testSkipGet();
|
||||
instance.testSkipDerivedOverrides();
|
||||
instance.testSkipSet();
|
||||
*/
|
||||
|
||||
`;
|
||||
|
||||
if (classesEnabled())
|
||||
|
@ -207,6 +207,9 @@ function newExpr(callee, args) {
|
||||
function callExpr(callee, args) {
|
||||
return Pattern({ type: "CallExpression", callee: callee, arguments: args });
|
||||
}
|
||||
function superCallExpr(args) {
|
||||
return callExpr({ type: "Super" }, args);
|
||||
}
|
||||
function arrExpr(elts) {
|
||||
return Pattern({ type: "ArrayExpression", elements: elts });
|
||||
}
|
||||
|
@ -437,6 +437,30 @@ function testClasses() {
|
||||
assertError("{ foo() { super } }", SyntaxError);
|
||||
assertClassError("class NAME { constructor() { super; } }", SyntaxError);
|
||||
|
||||
/* SuperCall */
|
||||
|
||||
// SuperCall is invalid outside derived class constructors.
|
||||
assertError("super()", SyntaxError);
|
||||
assertError("(function() { super(); })", SyntaxError);
|
||||
|
||||
// Even in class constructors
|
||||
assertClassError("class NAME { constructor() { super(); } }", SyntaxError);
|
||||
|
||||
function superConstructor(args) {
|
||||
return classMethod(ident("constructor"),
|
||||
methodFun("constructor", "method", false,
|
||||
[], [exprStmt(superCallExpr(args))]),
|
||||
"method", false);
|
||||
}
|
||||
|
||||
// SuperCall works with various argument configurations.
|
||||
assertClass("class NAME extends null { constructor() { super() } }",
|
||||
[superConstructor([])], lit(null));
|
||||
assertClass("class NAME extends null { constructor() { super(1) } }",
|
||||
[superConstructor([lit(1)])], lit(null));
|
||||
assertClass("class NAME extends null { constructor() { super(...[]) } }",
|
||||
[superConstructor([spread(arrExpr([]))])], lit(null));
|
||||
|
||||
/* EOF */
|
||||
// Clipped classes should throw a syntax error
|
||||
assertClassError("class NAME {", SyntaxError);
|
||||
|
@ -875,9 +875,9 @@ StackCheckIsConstructorCalleeNewTarget(JSContext* cx, HandleValue callee, Handle
|
||||
return false;
|
||||
}
|
||||
|
||||
// The new.target for a stack construction attempt is just the callee: no
|
||||
// need to check that it's a constructor.
|
||||
MOZ_ASSERT(&callee.toObject() == &newTarget.toObject());
|
||||
// The new.target has already been vetted by previous calls, or is the callee.
|
||||
// We can just assert that it's a constructor.
|
||||
MOZ_ASSERT(IsConstructor(newTarget));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1750,6 +1750,34 @@ SetObjectElementOperation(JSContext* cx, HandleObject obj, HandleValue receiver,
|
||||
result.checkStrictErrorOrWarning(cx, obj, id, strict);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the innermost enclosing function that has a 'this' binding.
|
||||
*
|
||||
* Implements ES6 12.3.5.2 GetSuperConstructor() steps 1-3, including
|
||||
* the loop in ES6 8.3.2 GetThisEnvironment(). Our implementation of
|
||||
* ES6 12.3.5.3 MakeSuperPropertyReference() also uses this code.
|
||||
*/
|
||||
static JSFunction&
|
||||
GetSuperEnvFunction(JSContext *cx, InterpreterRegs& regs)
|
||||
{
|
||||
ScopeIter si(cx, regs.fp()->scopeChain(), regs.fp()->script()->innermostStaticScope(regs.pc));
|
||||
for (; !si.done(); ++si) {
|
||||
if (si.hasSyntacticScopeObject() && si.type() == ScopeIter::Call) {
|
||||
JSFunction& callee = si.scope().as<CallObject>().callee();
|
||||
|
||||
// Arrow functions don't have the information we're looking for,
|
||||
// their enclosing scopes do. Nevertheless, they might have call
|
||||
// objects. Skip them to find what we came for.
|
||||
if (callee.isArrow())
|
||||
continue;
|
||||
|
||||
return callee;
|
||||
}
|
||||
}
|
||||
MOZ_CRASH("unexpected scope chain for GetSuperEnvFunction");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* As an optimization, the interpreter creates a handful of reserved Rooted<T>
|
||||
* variables at the beginning, thus inserting them into the Rooted list once
|
||||
@ -2059,10 +2087,6 @@ CASE(JSOP_NOP)
|
||||
CASE(JSOP_UNUSED2)
|
||||
CASE(JSOP_UNUSED14)
|
||||
CASE(JSOP_BACKPATCH)
|
||||
CASE(JSOP_UNUSED163)
|
||||
CASE(JSOP_UNUSED164)
|
||||
CASE(JSOP_UNUSED165)
|
||||
CASE(JSOP_UNUSED166)
|
||||
CASE(JSOP_UNUSED167)
|
||||
CASE(JSOP_UNUSED168)
|
||||
CASE(JSOP_UNUSED169)
|
||||
@ -3006,6 +3030,7 @@ END_CASE(JSOP_EVAL)
|
||||
|
||||
CASE(JSOP_SPREADNEW)
|
||||
CASE(JSOP_SPREADCALL)
|
||||
CASE(JSOP_SPREADSUPERCALL)
|
||||
if (REGS.fp()->hasPushedSPSFrame())
|
||||
cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
|
||||
/* FALL THROUGH */
|
||||
@ -3015,7 +3040,7 @@ CASE(JSOP_STRICTSPREADEVAL)
|
||||
{
|
||||
static_assert(JSOP_SPREADEVAL_LENGTH == JSOP_STRICTSPREADEVAL_LENGTH,
|
||||
"spreadeval and strictspreadeval must be the same size");
|
||||
bool construct = JSOp(*REGS.pc) == JSOP_SPREADNEW;
|
||||
bool construct = JSOp(*REGS.pc) == JSOP_SPREADNEW || JSOp(*REGS.pc) == JSOP_SPREADSUPERCALL;;
|
||||
|
||||
MOZ_ASSERT(REGS.stackDepth() >= 3u + construct);
|
||||
|
||||
@ -3047,12 +3072,13 @@ CASE(JSOP_FUNAPPLY)
|
||||
|
||||
CASE(JSOP_NEW)
|
||||
CASE(JSOP_CALL)
|
||||
CASE(JSOP_SUPERCALL)
|
||||
CASE(JSOP_FUNCALL)
|
||||
{
|
||||
if (REGS.fp()->hasPushedSPSFrame())
|
||||
cx->runtime()->spsProfiler.updatePC(script, REGS.pc);
|
||||
|
||||
bool construct = (*REGS.pc == JSOP_NEW);
|
||||
bool construct = (*REGS.pc == JSOP_NEW || *REGS.pc == JSOP_SUPERCALL);
|
||||
unsigned argStackSlots = GET_ARGC(REGS.pc) + construct;
|
||||
|
||||
MOZ_ASSERT(REGS.stackDepth() >= 2u + GET_ARGC(REGS.pc));
|
||||
@ -4075,37 +4101,22 @@ END_CASE(JSOP_INITHOMEOBJECT)
|
||||
|
||||
CASE(JSOP_SUPERBASE)
|
||||
{
|
||||
ScopeIter si(cx, REGS.fp()->scopeChain(), REGS.fp()->script()->innermostStaticScope(REGS.pc));
|
||||
for (; !si.done(); ++si) {
|
||||
if (si.hasSyntacticScopeObject() && si.type() == ScopeIter::Call) {
|
||||
JSFunction& callee = si.scope().as<CallObject>().callee();
|
||||
JSFunction& superEnvFunc = GetSuperEnvFunction(cx, REGS);
|
||||
MOZ_ASSERT(superEnvFunc.allowSuperProperty());
|
||||
MOZ_ASSERT(superEnvFunc.nonLazyScript()->needsHomeObject());
|
||||
const Value& homeObjVal = superEnvFunc.getExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT);
|
||||
|
||||
// Arrow functions don't have the information we're looking for,
|
||||
// their enclosing scopes do. Nevertheless, they might have call
|
||||
// objects. Skip them to find what we came for.
|
||||
if (callee.isArrow())
|
||||
continue;
|
||||
ReservedRooted<JSObject*> homeObj(&rootObject0, &homeObjVal.toObject());
|
||||
ReservedRooted<JSObject*> superBase(&rootObject1);
|
||||
if (!GetPrototype(cx, homeObj, &superBase))
|
||||
goto error;
|
||||
|
||||
MOZ_ASSERT(callee.allowSuperProperty());
|
||||
MOZ_ASSERT(callee.nonLazyScript()->needsHomeObject());
|
||||
const Value& homeObjVal = callee.getExtendedSlot(FunctionExtended::METHOD_HOMEOBJECT_SLOT);
|
||||
|
||||
ReservedRooted<JSObject*> homeObj(&rootObject0, &homeObjVal.toObject());
|
||||
ReservedRooted<JSObject*> superBase(&rootObject1);
|
||||
if (!GetPrototype(cx, homeObj, &superBase))
|
||||
goto error;
|
||||
|
||||
if (!superBase) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
|
||||
"null", "object");
|
||||
goto error;
|
||||
}
|
||||
PUSH_OBJECT(*superBase);
|
||||
break;
|
||||
}
|
||||
if (!superBase) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_CONVERT_TO,
|
||||
"null", "object");
|
||||
goto error;
|
||||
}
|
||||
if (si.done())
|
||||
MOZ_CRASH("Unexpected scope chain in superbase");
|
||||
PUSH_OBJECT(*superBase);
|
||||
}
|
||||
END_CASE(JSOP_SUPERBASE)
|
||||
|
||||
@ -4114,6 +4125,48 @@ CASE(JSOP_NEWTARGET)
|
||||
MOZ_ASSERT(REGS.sp[-1].isObject() || REGS.sp[-1].isUndefined());
|
||||
END_CASE(JSOP_NEWTARGET)
|
||||
|
||||
CASE(JSOP_SUPERFUN)
|
||||
{
|
||||
ReservedRooted<JSObject*> superEnvFunc(&rootObject0, &GetSuperEnvFunction(cx, REGS));
|
||||
MOZ_ASSERT(superEnvFunc->as<JSFunction>().isClassConstructor());
|
||||
MOZ_ASSERT(superEnvFunc->as<JSFunction>().nonLazyScript()->isDerivedClassConstructor());
|
||||
|
||||
ReservedRooted<JSObject*> superFun(&rootObject1);
|
||||
|
||||
if (!GetPrototype(cx, superEnvFunc, &superFun))
|
||||
goto error;
|
||||
|
||||
ReservedRooted<Value> superFunVal(&rootValue0, UndefinedValue());
|
||||
if (!superFun)
|
||||
superFunVal = NullValue();
|
||||
else if (!superFun->isConstructor())
|
||||
superFunVal = ObjectValue(*superFun);
|
||||
|
||||
if (superFunVal.isObjectOrNull()) {
|
||||
ReportIsNotFunction(cx, superFunVal, JSDVG_IGNORE_STACK, CONSTRUCT);
|
||||
goto error;
|
||||
}
|
||||
|
||||
PUSH_OBJECT(*superFun);
|
||||
}
|
||||
END_CASE(JSOP_SUPERFUN)
|
||||
|
||||
CASE(JSOP_SETTHIS)
|
||||
{
|
||||
MOZ_ASSERT(REGS.fp()->isNonEvalFunctionFrame());
|
||||
MOZ_ASSERT(REGS.fp()->script()->isDerivedClassConstructor());
|
||||
MOZ_ASSERT(REGS.fp()->callee().isClassConstructor());
|
||||
|
||||
if (!REGS.fp()->thisValue().isMagic(JS_UNINITIALIZED_LEXICAL)) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_REINIT_THIS);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ReservedRooted<JSObject*> thisv(&rootObject0, ®S.sp[-1].toObject());
|
||||
REGS.fp()->setDerivedConstructorThis(thisv);
|
||||
}
|
||||
END_CASE(JSOP_SETTHIS)
|
||||
|
||||
DEFAULT()
|
||||
{
|
||||
char numBuf[12];
|
||||
@ -4714,7 +4767,7 @@ js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc, Hand
|
||||
RootedArrayObject aobj(cx, &arr.toObject().as<ArrayObject>());
|
||||
uint32_t length = aobj->length();
|
||||
JSOp op = JSOp(*pc);
|
||||
bool constructing = op == JSOP_SPREADNEW;
|
||||
bool constructing = op == JSOP_SPREADNEW || op == JSOP_SPREADSUPERCALL;
|
||||
|
||||
if (length > ARGS_LENGTH_MAX) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
|
||||
@ -4732,7 +4785,7 @@ js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc, Hand
|
||||
MOZ_ASSERT(!aobj->getDenseElement(i).isMagic());
|
||||
#endif
|
||||
|
||||
if (op == JSOP_SPREADNEW) {
|
||||
if (constructing) {
|
||||
if (!StackCheckIsConstructorCalleeNewTarget(cx, callee, newTarget))
|
||||
return false;
|
||||
|
||||
|
@ -1669,10 +1669,45 @@
|
||||
*/ \
|
||||
macro(JSOP_DEFLET, 162,"deflet", NULL, 5, 0, 0, JOF_ATOM) \
|
||||
\
|
||||
macro(JSOP_UNUSED163, 163,"unused163", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED164, 164,"unused164", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED165, 165,"unused165", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED166, 166,"unused166", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
/*
|
||||
* Bind the |this| value of a function to the supplied value.
|
||||
*
|
||||
* Category: Variables and Scopes
|
||||
* Type: This
|
||||
* Operands:
|
||||
* Stack: this => this
|
||||
*/ \
|
||||
macro(JSOP_SETTHIS , 163,"setthis", NULL, 1, 1, 1, JOF_BYTE) \
|
||||
/*
|
||||
* Find the function to invoke with |super()| on the scope chain.
|
||||
*
|
||||
* Category: Variables and Scopes
|
||||
* Type: Super
|
||||
* Operands:
|
||||
* Stack: => superFun
|
||||
*/ \
|
||||
macro(JSOP_SUPERFUN, 164,"superfun", NULL, 1, 0, 1, JOF_BYTE) \
|
||||
/*
|
||||
* Behaves exactly like JSOP_NEW, but allows JITs to distinguish the two cases.
|
||||
*
|
||||
* Category: Statements
|
||||
* Type: Function
|
||||
* Operands: uint16_t argc
|
||||
* Stack: callee, this, args[0], ..., args[argc-1], newTarget => rval
|
||||
* nuses: (argc+3)
|
||||
*/ \
|
||||
macro(JSOP_SUPERCALL, 165,"supercall", NULL, 3, -1, 1, JOF_UINT16|JOF_INVOKE|JOF_TYPESET) \
|
||||
/*
|
||||
* spreadcall variant of JSOP_SUPERCALL.
|
||||
*
|
||||
* Behaves exactly like JSOP_SPREADNEW.
|
||||
*
|
||||
* Category: Statements
|
||||
* Type: Function
|
||||
* Operands:
|
||||
* Stack: callee, this, args, newTarget => rval
|
||||
*/ \
|
||||
macro(JSOP_SPREADSUPERCALL, 166, "spreadsupercall", NULL, 1, 4, 1, JOF_BYTE|JOF_INVOKE|JOF_TYPESET) \
|
||||
macro(JSOP_UNUSED167, 167,"unused167", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED168, 168,"unused168", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED169, 169,"unused169", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
|
@ -741,6 +741,14 @@ class InterpreterFrame
|
||||
return argv()[-1];
|
||||
}
|
||||
|
||||
void setDerivedConstructorThis(HandleObject thisv) {
|
||||
MOZ_ASSERT(isNonEvalFunctionFrame());
|
||||
MOZ_ASSERT(script()->isDerivedClassConstructor());
|
||||
MOZ_ASSERT(callee().isClassConstructor());
|
||||
MOZ_ASSERT(thisValue().isMagic(JS_UNINITIALIZED_LEXICAL));
|
||||
argv()[-1] = ObjectValue(*thisv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callee
|
||||
*
|
||||
|
@ -29,11 +29,11 @@ namespace js {
|
||||
*
|
||||
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
|
||||
*/
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 311;
|
||||
static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 312;
|
||||
static const uint32_t XDR_BYTECODE_VERSION =
|
||||
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
|
||||
|
||||
static_assert(JSErr_Limit == 417,
|
||||
static_assert(JSErr_Limit == 419,
|
||||
"GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
|
||||
"removed MSG_DEFs from js.msg, you should increment "
|
||||
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
|
||||
|
Loading…
Reference in New Issue
Block a user