diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 0fd42c3a7..18a21fb41 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -6427,7 +6427,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line, unsigned* c AsmJSParseContext* outerpc = m.parser().pc; Directives directives(outerpc); - FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator); + FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator, SyncFunction); if (!funbox) return false; diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js index 4a0329c2d..8e232e8a0 100644 --- a/js/src/builtin/Utilities.js +++ b/js/src/builtin/Utilities.js @@ -152,6 +152,19 @@ function GetIterator(obj, method) { return iterator; } +var _builtinCtorsCache = {__proto__: null}; + +function GetBuiltinConstructor(builtinName) { + var ctor = _builtinCtorsCache[builtinName] || + (_builtinCtorsCache[builtinName] = GetBuiltinConstructorImpl(builtinName)); + assert(ctor, `No builtin with name "${builtinName}" found`); + return ctor; +} + +function GetBuiltinPrototype(builtinName) { + return (_builtinCtorsCache[builtinName] || GetBuiltinConstructor(builtinName)).prototype; +} + // ES6 draft 20150317 7.3.20. function SpeciesConstructor(obj, defaultConstructor) { // Step 1. diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 22519caa8..1309e4d1f 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -312,6 +312,7 @@ BytecodeCompiler::saveCallerFun(HandleScript evalCaller) Directives directives(/* strict = */ options.strictOption); ObjectBox* funbox = parser->newFunctionBox(/* fn = */ nullptr, fun, directives, fun->generatorKind(), + fun->asyncKind(), enclosingStaticScope); if (!funbox) return false; @@ -635,7 +636,7 @@ BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun, ParseNode* fn; do { Directives newDirectives = directives; - fn = parser->standaloneFunctionBody(fun, formals, generatorKind, directives, + fn = parser->standaloneFunctionBody(fun, formals, generatorKind, SyncFunction, directives, &newDirectives, enclosingStaticScope); if (!fn && !handleParseFailure(newDirectives)) return false; @@ -796,7 +797,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle lazy, const cha Rooted fun(cx, lazy->functionNonDelazifying()); MOZ_ASSERT(!lazy->isLegacyGenerator()); - ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind()); + ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind(), lazy->asyncKind()); if (!pn) return false; diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index a3e19e19d..df0d8a7b0 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -6401,6 +6401,13 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) MOZ_ASSERT(pn->getOp() == JSOP_LAMBDA); pn->setOp(JSOP_FUNWITHPROTO); } + + if (pn->getOp() == JSOP_DEFFUN) { + if (!emitIndex32(JSOP_LAMBDA, index)) + return false; + return emit1(JSOP_DEFFUN); + } + return emitIndex32(pn->getOp(), index); } @@ -6441,7 +6448,9 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto) MOZ_ASSERT(pn->pn_scopecoord.isFree()); MOZ_ASSERT(pn->getOp() == JSOP_NOP); switchToPrologue(); - if (!emitIndex32(JSOP_DEFFUN, index)) + if (!emitIndex32(JSOP_LAMBDA, index)) + return false; + if (!emit1(JSOP_DEFFUN)) return false; if (!updateSourceCoordNotes(pn->pn_pos.begin)) return false; diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index bd8b262aa..f4fcb1ee3 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -689,7 +689,8 @@ Parser::cloneParseTree(ParseNode* opn) RootedFunction fun(context, opn->pn_funbox->function()); NULLCHECK(pn->pn_funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ opn->pn_funbox->strict()), - opn->pn_funbox->generatorKind())); + opn->pn_funbox->generatorKind(), + opn->pn_funbox->asyncKind())); NULLCHECK(pn->pn_body = cloneParseTree(opn->pn_body)); pn->pn_scopecoord = opn->pn_scopecoord; pn->pn_dflags = opn->pn_dflags; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 22ff1ae4d..6e5fd4a77 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -760,7 +760,8 @@ Parser::newObjectBox(JSObject* obj) template FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun, JSObject* enclosingStaticScope, ParseContext* outerpc, - Directives directives, bool extraWarnings, GeneratorKind generatorKind) + Directives directives, bool extraWarnings, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind) : ObjectBox(fun, traceListHead), SharedContext(cx, directives, extraWarnings), bindings(), @@ -771,6 +772,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct startColumn(0), length(0), generatorKindBits_(GeneratorKindAsBits(generatorKind)), + asyncKindBits_(AsyncKindAsBits(asyncKind)), inGenexpLambda(false), hasDestructuringArgs(false), useAsm(false), @@ -794,6 +796,7 @@ Parser::newFunctionBox(Node fn, JSFunction* fun, ParseContext* outerpc, Directives inheritedDirectives, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, JSObject* enclosingStaticScope) { MOZ_ASSERT_IF(outerpc, enclosingStaticScope == outerpc->innermostStaticScope()); @@ -809,7 +812,7 @@ Parser::newFunctionBox(Node fn, JSFunction* fun, FunctionBox* funbox = alloc.new_(context, traceListHead, fun, enclosingStaticScope, outerpc, inheritedDirectives, options().extraWarningsOption, - generatorKind); + generatorKind, asyncKind); if (!funbox) { ReportOutOfMemory(context); return nullptr; @@ -1140,6 +1143,7 @@ ParseNode* Parser::standaloneFunctionBody(HandleFunction fun, Handle formals, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives, HandleObject enclosingStaticScope) @@ -1155,7 +1159,7 @@ Parser::standaloneFunctionBody(HandleFunction fun, return null(); fn->pn_body = argsbody; - FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind, + FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind, asyncKind, enclosingStaticScope); if (!funbox) return null(); @@ -1606,7 +1610,8 @@ struct BindData template JSFunction* Parser::newFunction(HandleAtom atom, FunctionSyntaxKind kind, - GeneratorKind generatorKind, HandleObject proto) + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + HandleObject proto) { MOZ_ASSERT_IF(kind == Statement, atom != nullptr); @@ -2507,7 +2512,7 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, RootedFunction fun(context, handler.nextLazyInnerFunction()); MOZ_ASSERT(!fun->isLegacyGenerator()); FunctionBox* funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false), - fun->generatorKind()); + fun->generatorKind(), fun->asyncKind()); if (!funbox) return false; @@ -2715,11 +2720,12 @@ Parser::templateLiteral(YieldHandling yieldHandling) return nodeList; } +/* ::functionDefinition */ template typename ParseHandler::Node Parser::functionDef(InHandling inHandling, YieldHandling yieldHandling, HandlePropertyName funName, FunctionSyntaxKind kind, - GeneratorKind generatorKind, InvokedPrediction invoked, + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, InvokedPrediction invoked, Node* assignmentForAnnexBOut) { MOZ_ASSERT_IF(kind == Statement, funName); @@ -2750,7 +2756,7 @@ Parser::functionDef(InHandling inHandling, YieldHandling yieldHand if (!proto) return null(); } - RootedFunction fun(context, newFunction(funName, kind, generatorKind, proto)); + RootedFunction fun(context, newFunction(funName, kind, generatorKind, asyncKind, proto)); if (!fun) return null(); @@ -2765,7 +2771,7 @@ Parser::functionDef(InHandling inHandling, YieldHandling yieldHand tokenStream.tell(&start); while (true) { - if (functionArgsAndBody(inHandling, pn, fun, kind, generatorKind, directives, + if (functionArgsAndBody(inHandling, pn, fun, kind, generatorKind, asyncKind, directives, &newDirectives)) { break; @@ -2836,6 +2842,7 @@ Parser::finishFunctionDefinition(Node pn, FunctionBox* funbo if (pc->sc->strict()) lazy->setStrict(); lazy->setGeneratorKind(funbox->generatorKind()); + lazy->setAsyncKind(funbox->asyncKind()); if (funbox->isLikelyConstructorWrapper()) lazy->setLikelyConstructorWrapper(); if (funbox->isDerivedClassConstructor()) @@ -2848,18 +2855,19 @@ Parser::finishFunctionDefinition(Node pn, FunctionBox* funbo return true; } +/* ::trySyntaxParseInnerFunction */ template <> bool Parser::functionArgsAndBody(InHandling inHandling, ParseNode* pn, HandleFunction fun, FunctionSyntaxKind kind, - GeneratorKind generatorKind, + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives) { ParseContext* outerpc = pc; // Create box for fun->object early to protect against last-ditch GC. - FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind); + FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind, asyncKind); if (!funbox) return false; @@ -2953,13 +2961,14 @@ bool Parser::functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun, FunctionSyntaxKind kind, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives) { ParseContext* outerpc = pc; // Create box for fun->object early to protect against last-ditch GC. - FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind); + FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind, asyncKind); if (!funbox) return false; @@ -3003,7 +3012,8 @@ Parser::appendToCallSiteObj(Node callSiteObj) template <> ParseNode* Parser::standaloneLazyFunction(HandleFunction fun, bool strict, - GeneratorKind generatorKind) + GeneratorKind generatorKind, + FunctionAsyncKind asyncKind) { MOZ_ASSERT(checkOptionsCalled); @@ -3018,7 +3028,7 @@ Parser::standaloneLazyFunction(HandleFunction fun, bool strict RootedObject enclosing(context, fun->lazyScript()->enclosingScope()); Directives directives(/* strict = */ strict); - FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, enclosing); + FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind, enclosing); if (!funbox) return null(); funbox->length = fun->nargs() - fun->hasRest(); @@ -3226,7 +3236,7 @@ Parser::functionStmt(YieldHandling yieldHandling, DefaultHandling Node assignmentForAnnexB; Node fun = functionDef(InAllowed, yieldHandling, name, Statement, generatorKind, - PredictUninvoked, &assignmentForAnnexB); + SyncFunction, PredictUninvoked, &assignmentForAnnexB); if (!fun) return null(); @@ -3284,7 +3294,7 @@ Parser::functionExpr(InvokedPrediction invoked) } YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName; - return functionDef(InAllowed, yieldHandling, name, Expression, generatorKind, invoked); + return functionDef(InAllowed, yieldHandling, name, Expression, generatorKind, SyncFunction, invoked); } /* @@ -7748,7 +7758,7 @@ Parser::assignExpr(InHandling inHandling, YieldHandling yieldHandl if (!tokenStream.peekToken(&ignored, TokenStream::Operand)) return null(); - Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator); + Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator, SyncFunction); if (!arrowFunc) return null(); @@ -8626,13 +8636,13 @@ Parser::generatorComprehensionLambda(GeneratorKind comprehensionKi } RootedFunction fun(context, newFunction(/* atom = */ nullptr, Expression, - comprehensionKind, proto)); + comprehensionKind, SyncFunction, proto)); if (!fun) return null(); // Create box for fun->object early to root it. Directives directives(/* strict = */ outerpc->sc->strict()); - FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind); + FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind, SyncFunction); if (!genFunbox) return null(); @@ -9872,7 +9882,7 @@ Parser::methodDefinition(YieldHandling yieldHandling, PropertyType { FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType); GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType); - return functionDef(InAllowed, yieldHandling, funName, kind, generatorKind); + return functionDef(InAllowed, yieldHandling, funName, kind, generatorKind, SyncFunction); } template diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index d62b6365a..6e2e83f5c 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -126,6 +126,10 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; } bool isStarGenerator() const { return generatorKind() == StarGenerator; } + bool isAsync() const { + return sc->isFunctionBox() && sc->asFunctionBox()->isAsync(); + } + bool isArrowFunction() const { return sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow(); } @@ -579,22 +583,26 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter ObjectBox* newObjectBox(JSObject* obj); FunctionBox* newFunctionBox(Node fn, JSFunction* fun, ParseContext* outerpc, Directives directives, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, JSObject* enclosingStaticScope); // Use when the funbox is the outermost. FunctionBox* newFunctionBox(Node fn, HandleFunction fun, Directives directives, - GeneratorKind generatorKind, HandleObject enclosingStaticScope) + GeneratorKind generatorKind, FunctionAsyncKind asyncKind, + HandleObject enclosingStaticScope) { return newFunctionBox(fn, fun, nullptr, directives, generatorKind, + asyncKind, enclosingStaticScope); } // Use when the funbox should be linked to the outerpc's innermost scope. FunctionBox* newFunctionBox(Node fn, HandleFunction fun, ParseContext* outerpc, - Directives directives, GeneratorKind generatorKind) + Directives directives, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind) { RootedObject enclosing(context, outerpc->innermostStaticScope()); - return newFunctionBox(fn, fun, outerpc, directives, generatorKind, enclosing); + return newFunctionBox(fn, fun, outerpc, directives, generatorKind, asyncKind, enclosing); } ModuleBox* newModuleBox(Node pn, HandleModuleObject module); @@ -604,7 +612,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter * a function expression). */ JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind, GeneratorKind generatorKind, - HandleObject proto); + FunctionAsyncKind asyncKind, HandleObject proto); bool generateBlockId(JSObject* staticScope, uint32_t* blockIdOut) { if (blockScopes.length() == StmtInfoPC::BlockIdLimit) { @@ -671,12 +679,15 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter // Generator constructors. Node standaloneFunctionBody(HandleFunction fun, Handle formals, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives, HandleObject enclosingStaticScope); // Parse a function, given only its arguments and body. Used for lazily // parsed functions. - Node standaloneLazyFunction(HandleFunction fun, bool strict, GeneratorKind generatorKind); + Node standaloneLazyFunction(HandleFunction fun, bool strict, + GeneratorKind generatorKind, + FunctionAsyncKind asyncKind); /* * Parse a function body. Pass StatementListBody if the body is a list of @@ -874,10 +885,12 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter Node functionDef(InHandling inHandling, YieldHandling uieldHandling, HandlePropertyName name, FunctionSyntaxKind kind, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, InvokedPrediction invoked = PredictUninvoked, Node* assignmentForAnnexBOut = nullptr); bool functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun, FunctionSyntaxKind kind, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind, Directives inheritedDirectives, Directives* newDirectives); Node unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin); diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index c07595112..263567f5b 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -333,6 +333,7 @@ class FunctionBox : public ObjectBox, public SharedContext uint16_t length; uint8_t generatorKindBits_; /* The GeneratorKind of this function. */ + uint8_t asyncKindBits_; /* The FunctionAsyncKing of this function. */ bool inGenexpLambda:1; /* lambda from generator expression */ bool hasDestructuringArgs:1; /* arguments list contains destructuring expression */ bool useAsm:1; /* see useAsmOrInsideUseAsm */ @@ -350,7 +351,8 @@ class FunctionBox : public ObjectBox, public SharedContext template FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun, JSObject* enclosingStaticScope, ParseContext* pc, - Directives directives, bool extraWarnings, GeneratorKind generatorKind); + Directives directives, bool extraWarnings, GeneratorKind generatorKind, + FunctionAsyncKind asyncKind); ObjectBox* toObjectBox() override { return this; } JSFunction* function() const { return &object->as(); } @@ -365,6 +367,8 @@ class FunctionBox : public ObjectBox, public SharedContext bool isGenerator() const { return generatorKind() != NotGenerator; } bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; } bool isStarGenerator() const { return generatorKind() == StarGenerator; } + FunctionAsyncKind asyncKind() const { return AsyncKindFromBits(asyncKindBits_); } + bool isAsync() const { return asyncKind() == AsyncFunction; } bool isArrow() const { return function()->isArrow(); } void setGeneratorKind(GeneratorKind kind) { diff --git a/js/src/frontend/TokenKind.h b/js/src/frontend/TokenKind.h index 83ee77172..a52b3f846 100644 --- a/js/src/frontend/TokenKind.h +++ b/js/src/frontend/TokenKind.h @@ -107,6 +107,7 @@ macro(THROW, "keyword 'throw'") \ macro(DEBUGGER, "keyword 'debugger'") \ macro(YIELD, "keyword 'yield'") \ + macro(AWAIT, "keyword 'await'") \ macro(LET, "keyword 'let'") \ macro(EXPORT, "keyword 'export'") \ macro(IMPORT, "keyword 'import'") \ diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 770d77d5b..cb9b5b675 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -981,6 +981,12 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart) bool TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp) { + if (!awaitIsKeyword && kw->tokentype == TOK_AWAIT) { + if (ttp) + *ttp = TOK_NAME; + return true; + } + if (kw->tokentype == TOK_RESERVED) return reportError(JSMSG_RESERVED_ID, kw->chars); diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index f3712cfec..ae1ca6f7d 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -32,6 +32,8 @@ struct KeywordInfo; namespace js { namespace frontend { +class AutoAwaitIsKeyword; + struct TokenPos { uint32_t begin; // Offset of the token's first char. uint32_t end; // Offset of 1 past the token's last char. @@ -452,6 +454,9 @@ class MOZ_STACK_CLASS TokenStream {} }; + bool awaitIsKeyword = false; + friend class AutoAwaitIsKeyword; + public: typedef Token::Modifier Modifier; static MOZ_CONSTEXPR_VAR Modifier None = Token::None; @@ -1034,6 +1039,25 @@ class MOZ_STACK_CLASS TokenStream StrictModeGetter* strictModeGetter; // used to test for strict mode }; +class MOZ_STACK_CLASS AutoAwaitIsKeyword +{ +private: + TokenStream* ts_; + bool oldAwaitIsKeyword_; + +public: + AutoAwaitIsKeyword(TokenStream* ts, bool awaitIsKeyword) { + ts_ = ts; + oldAwaitIsKeyword_ = ts_->awaitIsKeyword; + ts_->awaitIsKeyword = awaitIsKeyword; + } + + ~AutoAwaitIsKeyword() { + ts_->awaitIsKeyword = oldAwaitIsKeyword_; + ts_ = nullptr; + } +}; + // Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error // message have const char16_t* type, not const char*. #define JSREPORT_UC 0x100 diff --git a/js/src/jit-test/tests/self-hosting/getbuiltinconstructor.js b/js/src/jit-test/tests/self-hosting/getbuiltinconstructor.js new file mode 100644 index 000000000..57134875a --- /dev/null +++ b/js/src/jit-test/tests/self-hosting/getbuiltinconstructor.js @@ -0,0 +1,13 @@ +let getCtor = getSelfHostedValue('GetBuiltinConstructor'); + +assertEq(getCtor('Array'), Array); + +let origArray = Array; +Array = function(){}; +assertEq(getCtor('Array') == Array, false); +assertEq(getCtor('Array'), origArray); + +let origMap = Map; +Map = function(){}; +assertEq(getCtor('Map') == Map, false); +assertEq(getCtor('Map'), origMap); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index a13394a8b..dbe206c68 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -2677,15 +2677,14 @@ static const VMFunction DefFunOperationInfo = FunctionInfo(De bool BaselineCompiler::emit_JSOP_DEFFUN() { - RootedFunction fun(cx, script->getFunction(GET_UINT32_INDEX(pc))); - - frame.syncStack(0); - masm.loadPtr(frame.addressOfScopeChain(), R0.scratchReg()); + frame.popRegsAndSync(1); + masm.unboxObject(R0, R0.scratchReg()); + masm.loadPtr(frame.addressOfScopeChain(), R1.scratchReg()); prepareVMCall(); - pushArg(ImmGCPtr(fun)); pushArg(R0.scratchReg()); + pushArg(R1.scratchReg()); pushArg(ImmGCPtr(script)); return callVM(DefFunOperationInfo); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index e3dc5003f..ac7b03b4f 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -3854,7 +3854,8 @@ CodeGenerator::visitDefFun(LDefFun* lir) { Register scopeChain = ToRegister(lir->scopeChain()); - pushArg(ImmGCPtr(lir->mir()->fun())); + Register fun = ToRegister(lir->fun()); + pushArg(fun); pushArg(scopeChain); pushArg(ImmGCPtr(current->mir()->info().script())); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 1bd06824b..f0010b97c 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -12932,13 +12932,9 @@ IonBuilder::jsop_deflexical(uint32_t index) bool IonBuilder::jsop_deffun(uint32_t index) { - JSFunction* fun = script()->getFunction(index); - if (fun->isNative() && IsAsmJSModuleNative(fun->native())) - return abort("asm.js module function"); - MOZ_ASSERT(analysis().usesScopeChain()); - MDefFun* deffun = MDefFun::New(alloc(), fun, current->scopeChain()); + MDefFun* deffun = MDefFun::New(alloc(), current->pop(), current->scopeChain()); current->add(deffun); return resumeAfter(deffun); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 717e5557c..c57579dbc 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -164,7 +164,11 @@ LIRGenerator::visitDefLexical(MDefLexical* ins) void LIRGenerator::visitDefFun(MDefFun* ins) { - LDefFun* lir = new(alloc()) LDefFun(useRegisterAtStart(ins->scopeChain())); + MDefinition* fun = ins->fun(); + MOZ_ASSERT(fun->type() == MIRType_Object); + + LDefFun* lir = new(alloc()) LDefFun(useRegisterAtStart(fun), + useRegisterAtStart(ins->scopeChain())); add(lir, ins); assignSafepoint(lir, ins); } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index b93b79413..d94ec4c9d 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -7423,30 +7423,28 @@ class MDefLexical }; class MDefFun - : public MUnaryInstruction, - public NoTypePolicy::Data + : public MBinaryInstruction, + public SingleObjectPolicy::Data { - CompilerFunction fun_; - private: - MDefFun(JSFunction* fun, MDefinition* scopeChain) - : MUnaryInstruction(scopeChain), - fun_(fun) + MDefFun(MDefinition* fun, MDefinition* scopeChain) + : MBinaryInstruction(fun, scopeChain) {} public: INSTRUCTION_HEADER(DefFun) - static MDefFun* New(TempAllocator& alloc, JSFunction* fun, MDefinition* scopeChain) { + static MDefFun* New(TempAllocator& alloc, MDefinition* fun, MDefinition* scopeChain) { return new(alloc) MDefFun(fun, scopeChain); } - JSFunction* fun() const { - return fun_; - } - MDefinition* scopeChain() const { + MDefinition* fun() const { return getOperand(0); } + MDefinition* scopeChain() const { + return getOperand(1); + } + bool possiblyCalls() const override { return true; } diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index d60892924..3b2a3f143 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -1238,19 +1238,23 @@ class LDefLexical : public LCallInstructionHelper<0, 0, 0> } }; -class LDefFun : public LCallInstructionHelper<0, 1, 0> +class LDefFun : public LCallInstructionHelper<0, 2, 0> { public: LIR_HEADER(DefFun) - explicit LDefFun(const LAllocation& scopeChain) + LDefFun(const LAllocation& fun, const LAllocation& scopeChain) { - setOperand(0, scopeChain); + setOperand(0, fun); + setOperand(1, scopeChain); } - const LAllocation* scopeChain() { + const LAllocation* fun() { return getOperand(0); } + const LAllocation* scopeChain() { + return getOperand(1); + } MDefFun* mir() const { return mir_->toDefFun(); } diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 8b732150c..0b87ec411 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -291,6 +291,13 @@ class JSFunction : public js::NativeObject flags_ |= RESOLVED_NAME; } + void setAsyncKind(js::FunctionAsyncKind asyncKind) { + if (isInterpretedLazy()) + lazyScript()->setAsyncKind(asyncKind); + else + nonLazyScript()->setAsyncKind(asyncKind); + } + JSAtom* atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); } js::PropertyName* name() const { @@ -471,6 +478,18 @@ class JSFunction : public js::NativeObject bool isStarGenerator() const { return generatorKind() == js::StarGenerator; } + js::FunctionAsyncKind asyncKind() const { + return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind(); + } + + bool isAsync() const { + if (isInterpretedLazy()) + return lazyScript()->asyncKind() == js::AsyncFunction; + if (hasScript()) + return nonLazyScript()->asyncKind() == js::AsyncFunction; + return false; + } + void setScript(JSScript* script_) { mutableScript() = script_; } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 778117a4c..15ac14b03 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -867,6 +867,7 @@ js::XDRScript(XDRState* xdr, HandleObject enclosingScopeArg, HandleScript return false; if (mode == XDR_DECODE) { + /* XXX: AsyncFunction and isAsync not implemented. */ if (!JSScript::partiallyInit(cx, script, nconsts, nobjects, nregexps, ntrynotes, nblockscopes, nyieldoffsets, nTypeSets)) { @@ -2746,6 +2747,7 @@ JSScript::Create(ExclusiveContext* cx, HandleObject enclosingScope, bool savedCa script->setSourceObject(sourceObject); script->sourceStart_ = bufStart; script->sourceEnd_ = bufEnd; + script->isAsync_ = false; return script; } @@ -2910,6 +2912,7 @@ JSScript::linkToFunctionFromEmitter(js::ExclusiveContext* cx, JS::HandleisGeneratorExp_ = funbox->inGenexpLambda; script->setGeneratorKind(funbox->generatorKind()); + script->setAsyncKind(funbox->asyncKind()); // Link the function and the script to each other, so that StaticScopeIter // may walk the scope chain of currently compiling scripts. @@ -2935,6 +2938,7 @@ JSScript::linkToModuleFromEmitter(js::ExclusiveContext* cx, JS::HandlefunLength_ = 0; script->isGeneratorExp_ = false; + script->isAsync_ = false; script->setGeneratorKind(NotGenerator); // Link the module and the script to each other, so that StaticScopeIter @@ -3570,6 +3574,7 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri dst->hasInnerFunctions_ = src->hasInnerFunctions(); dst->isGeneratorExp_ = src->isGeneratorExp(); dst->setGeneratorKind(src->generatorKind()); + dst->isAsync_ = src->asyncKind() == AsyncFunction; if (nconsts != 0) { HeapValue* vector = Rebase(dst, src, src->consts()->vector); @@ -4270,6 +4275,7 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, // Reset runtime flags to obtain a fresh LazyScript. p.hasBeenCloned = false; p.treatAsRunOnce = false; + p.isAsync = false; size_t bytes = (p.numFreeVariables * sizeof(FreeVariable)) + (p.numInnerFunctions * sizeof(HeapPtrFunction)); @@ -4301,6 +4307,7 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun, p.version = version; p.numFreeVariables = numFreeVariables; + p.isAsync = false; p.numInnerFunctions = numInnerFunctions; p.generatorKindBits = GeneratorKindAsBits(NotGenerator); p.strict = false; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 59b94dd34..90eb07ed9 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -894,6 +894,7 @@ class ScriptSourceObject : public NativeObject }; enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator }; +enum FunctionAsyncKind { SyncFunction, AsyncFunction }; static inline unsigned GeneratorKindAsBits(GeneratorKind generatorKind) { @@ -906,6 +907,17 @@ GeneratorKindFromBits(unsigned val) { return static_cast(val); } +static inline unsigned +AsyncKindAsBits(FunctionAsyncKind asyncKind) { + return static_cast(asyncKind); +} + +static inline FunctionAsyncKind +AsyncKindFromBits(unsigned val) { + MOZ_ASSERT(val <= AsyncFunction); + return static_cast(val); +} + /* * NB: after a successful XDR_DECODE, XDRScript callers must do any required * subsequent set-up of owning function or script object and then call @@ -1190,6 +1202,8 @@ class JSScript : public js::gc::TenuredCell bool isDerivedClassConstructor_:1; + bool isAsync_:1; + // Add padding so JSScript is gc::Cell aligned. Make padding protected // instead of private to suppress -Wunused-private-field compiler warnings. protected: @@ -1456,6 +1470,14 @@ class JSScript : public js::gc::TenuredCell generatorKindBits_ = GeneratorKindAsBits(kind); } + js::FunctionAsyncKind asyncKind() const { + return isAsync_ ? js::AsyncFunction : js::SyncFunction; + } + + void setAsyncKind(js::FunctionAsyncKind kind) { + isAsync_ = kind == js::AsyncFunction; + } + void setNeedsHomeObject() { needsHomeObject_ = true; } @@ -2136,7 +2158,8 @@ class LazyScript : public gc::TenuredCell // Assorted bits that should really be in ScriptSourceObject. uint32_t version : 8; - uint32_t numFreeVariables : 24; + uint32_t numFreeVariables : 23; + uint32_t isAsync: 1; uint32_t numInnerFunctions : 20; uint32_t generatorKindBits : 2; @@ -2274,6 +2297,14 @@ class LazyScript : public gc::TenuredCell p_.generatorKindBits = GeneratorKindAsBits(kind); } + FunctionAsyncKind asyncKind() const { + return p_.isAsync ? AsyncFunction : SyncFunction; + } + + void setAsyncKind(FunctionAsyncKind kind) { + p_.isAsync = kind == AsyncFunction; + } + bool strict() const { return p_.strict; } diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 9828268a8..1a8aa25ec 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -23,6 +23,7 @@ macro(ArrayValues, ArrayValues, "ArrayValues") \ macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \ macro(Async, Async, "Async") \ + macro(await, await, "await") \ macro(breakdown, breakdown, "breakdown") \ macro(buffer, buffer, "buffer") \ macro(builder, builder, "builder") \ diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 66e392668..6326a325e 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -3277,9 +3277,10 @@ CASE(JSOP_DEFFUN) * a compound statement (not at the top statement level of global code, or * at the top level of a function body). */ - ReservedRooted fun(&rootFunction0, script->getFunction(GET_UINT32_INDEX(REGS.pc))); + ReservedRooted fun(&rootFunction0, ®S.sp[-1].toObject().as()); if (!DefFunOperation(cx, script, REGS.fp()->scopeChain(), fun)) goto error; + REGS.sp--; } END_CASE(JSOP_DEFFUN) @@ -4095,27 +4096,8 @@ js::LambdaArrow(JSContext* cx, HandleFunction fun, HandleObject parent, HandleVa bool js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject scopeChain, - HandleFunction funArg) + HandleFunction fun) { - /* - * If static link is not current scope, clone fun's object to link to the - * current scope via parent. We do this to enable sharing of compiled - * functions among multiple equivalent scopes, amortizing the cost of - * compilation over a number of executions. Examples include XUL scripts - * and event handlers shared among Firefox or other Mozilla app chrome - * windows, and user-defined JS functions precompiled and then shared among - * requests in server-side JS. - */ - RootedFunction fun(cx, funArg); - if (fun->isNative() || fun->environment() != scopeChain) { - fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain, nullptr, TenuredObject); - if (!fun) - return false; - } else { - MOZ_ASSERT(script->treatAsRunOnce()); - MOZ_ASSERT(!script->functionNonDelazifying()); - } - /* * We define the function as a property of the variable object and not the * current scope chain even for the case of function expression statements diff --git a/js/src/vm/Keywords.h b/js/src/vm/Keywords.h index 73e73d26f..de91031fc 100644 --- a/js/src/vm/Keywords.h +++ b/js/src/vm/Keywords.h @@ -56,6 +56,7 @@ macro(protected, protected_, TOK_STRICT_RESERVED) \ macro(public, public_, TOK_STRICT_RESERVED) \ macro(static, static_, TOK_STRICT_RESERVED) \ + macro(await, await, TOK_AWAIT) \ /* \ * Yield is a token inside function*. Outside of a function*, it is a \ * future reserved keyword in strict mode, but a keyword in JS1.7 even \ diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index eae3e5333..7bcb3b6ed 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -1286,10 +1286,10 @@ * scripts where use of dynamic scoping inhibits optimization. * Category: Variables and Scopes * Type: Variables - * Operands: uint32_t funcIndex - * Stack: => + * Operands: + * Stack: fun => */ \ - macro(JSOP_DEFFUN, 127,"deffun", NULL, 5, 0, 0, JOF_OBJECT) \ + macro(JSOP_DEFFUN, 127,"deffun", NULL, 1, 1, 0, JOF_BYTE) \ /* Defines the new constant binding on global lexical scope. * * Throws if a binding with the same name already exists on the scope, or diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index bac95301c..683ed29d9 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -148,6 +148,41 @@ intrinsic_IsInstanceOfBuiltin(JSContext* cx, unsigned argc, Value* vp) return true; } +/** + * Self-hosting intrinsic returning the original constructor for a builtin + * the name of which is the first and only argument. + * + * The return value is guaranteed to be the original constructor even if + * content code changed the named binding on the global object. + * + * This intrinsic shouldn't be called directly. Instead, the + * `GetBuiltinConstructor` and `GetBuiltinPrototype` helper functions in + * Utilities.js should be used, as they cache results, improving performance. + */ +static bool +intrinsic_GetBuiltinConstructor(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + RootedString str(cx, args[0].toString()); + JSAtom* atom; + if (str->isAtom()) { + atom = &str->asAtom(); + } else { + atom = AtomizeString(cx, str); + if (!atom) + return false; + } + RootedId id(cx, AtomToId(atom)); + JSProtoKey key = JS_IdToProtoKey(cx, id); + MOZ_ASSERT(key != JSProto_Null); + RootedObject ctor(cx); + if (!GetBuiltinConstructor(cx, key, &ctor)) + return false; + args.rval().setObject(*ctor); + return true; +} + static bool intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp) { @@ -1467,6 +1502,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("ToPropertyKey", intrinsic_ToPropertyKey, 1,0), JS_INLINABLE_FN("IsCallable", intrinsic_IsCallable, 1,0, IntrinsicIsCallable), JS_FN("IsConstructor", intrinsic_IsConstructor, 1,0), + JS_FN("GetBuiltinConstructorImpl", intrinsic_GetBuiltinConstructor, 1,0), JS_FN("OwnPropertyKeys", intrinsic_OwnPropertyKeys, 1,0), JS_FN("ThrowRangeError", intrinsic_ThrowRangeError, 4,0), JS_FN("ThrowTypeError", intrinsic_ThrowTypeError, 4,0), diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index d300a65c0..8ab54ce5f 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -433,6 +433,7 @@ nsHttpHandler::AddStandardRequestHeaders(nsHttpHeaderArray *request, !hostLine.EqualsLiteral("i.imgur.com") && !hostLine.EqualsLiteral("imgur.com") && !hostLine.EqualsLiteral("github.com") && + !hostLine.EqualsLiteral("gist.github.com") && 1)) { rv = request->SetHeader(nsHttp::User_Agent, UserAgent(), false, nsHttpHeaderArray::eVarietyDefault);