diff options
Diffstat (limited to 'js/src/jsfun.cpp')
-rw-r--r-- | js/src/jsfun.cpp | 120 |
1 files changed, 93 insertions, 27 deletions
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 9edf238ef..ce1ca33fe 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -41,6 +41,7 @@ #include "js/CallNonGenericMethod.h" #include "js/Proxy.h" #include "vm/AsyncFunction.h" +#include "vm/AsyncIteration.h" #include "vm/Debugger.h" #include "vm/GlobalObject.h" #include "vm/Interpreter.h" @@ -131,7 +132,11 @@ IsFunctionInStrictMode(JSFunction* fun) static bool IsNewerTypeFunction(JSFunction* fun) { - return fun->isArrow() || fun->isGenerator() || fun->isAsync() || fun->isMethod(); + return fun->isArrow() || + fun->isStarGenerator() || + fun->isLegacyGenerator() || + fun->isAsync() || + fun->isMethod(); } // Beware: this function can be invoked on *any* function! That includes @@ -308,6 +313,8 @@ CallerGetterImpl(JSContext* cx, const CallArgs& args) JSFunction* callerFun = &callerObj->as<JSFunction>(); if (IsWrappedAsyncFunction(callerFun)) callerFun = GetUnwrappedAsyncFunction(callerFun); + else if (IsWrappedAsyncGenerator(callerFun)) + callerFun = GetUnwrappedAsyncGenerator(callerFun); MOZ_ASSERT(!callerFun->isBuiltin(), "non-builtin iterator returned a builtin?"); if (callerFun->strict()) { @@ -360,13 +367,15 @@ static const JSPropertySpec function_properties[] = { static bool ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId id) { - MOZ_ASSERT(fun->isInterpreted() || fun->isAsmJSNative()); + bool isAsyncGenerator = IsWrappedAsyncGenerator(fun); + + MOZ_ASSERT_IF(!isAsyncGenerator, fun->isInterpreted() || fun->isAsmJSNative()); MOZ_ASSERT(id == NameToId(cx->names().prototype)); // Assert that fun is not a compiler-created function object, which // must never leak to script or embedding code and then be mutated. // Also assert that fun is not bound, per the ES5 15.3.4.5 ref above. - MOZ_ASSERT(!IsInternalFunctionObject(*fun)); + MOZ_ASSERT_IF(!isAsyncGenerator, !IsInternalFunctionObject(*fun)); MOZ_ASSERT(!fun->isBoundFunction()); // Make the prototype object an instance of Object with the same parent as @@ -376,7 +385,9 @@ ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId bool isStarGenerator = fun->isStarGenerator(); Rooted<GlobalObject*> global(cx, &fun->global()); RootedObject objProto(cx); - if (isStarGenerator) + if (isAsyncGenerator) + objProto = GlobalObject::getOrCreateAsyncGeneratorPrototype(cx, global); + else if (isStarGenerator) objProto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global); else objProto = GlobalObject::getOrCreateObjectPrototype(cx, global); @@ -392,7 +403,7 @@ ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId // non-enumerable, and writable. However, per the 15 July 2013 ES6 draft, // section 15.19.3, the .prototype of a generator function does not link // back with a .constructor. - if (!isStarGenerator) { + if (!isStarGenerator && !isAsyncGenerator) { RootedValue objVal(cx, ObjectValue(*fun)); if (!DefineProperty(cx, proto, cx->names().constructor, objVal, nullptr, nullptr, 0)) return false; @@ -442,8 +453,14 @@ fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp) * - Arrow functions * - Function.prototype */ - if (fun->isBuiltin() || (!fun->isConstructor() && !fun->isGenerator())) - return true; + if (!IsWrappedAsyncGenerator(fun)) { + if (fun->isBuiltin()) + return true; + if (!fun->isConstructor()) { + if (!fun->isStarGenerator() && !fun->isLegacyGenerator() && !fun->isAsync()) + return true; + } + } if (!ResolveInterpretedFunctionPrototype(cx, fun, id)) return false; @@ -515,7 +532,7 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope, { enum FirstWordFlag { HasAtom = 0x1, - IsStarGenerator = 0x2, + HasStarGeneratorProto = 0x2, IsLazy = 0x4, HasSingletonType = 0x8 }; @@ -544,8 +561,8 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope, if (fun->explicitName() || fun->hasCompileTimeName() || fun->hasGuessedAtom()) firstword |= HasAtom; - if (fun->isStarGenerator()) - firstword |= IsStarGenerator; + if (fun->isStarGenerator() || fun->isAsync()) + firstword |= HasStarGeneratorProto; if (fun->isInterpretedLazy()) { // Encode a lazy script. @@ -581,7 +598,7 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope, if (mode == XDR_DECODE) { RootedObject proto(cx); - if (firstword & IsStarGenerator) { + if (firstword & HasStarGeneratorProto) { proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global()); if (!proto) return false; @@ -938,6 +955,11 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint) return FunctionToString(cx, unwrapped, prettyPrint); } + if (IsWrappedAsyncGenerator(fun)) { + RootedFunction unwrapped(cx, GetUnwrappedAsyncGenerator(fun)); + return FunctionToString(cx, unwrapped, prettyPrint); + } + StringBuffer out(cx); RootedScript script(cx); @@ -1556,7 +1578,7 @@ fun_isGenerator(JSContext* cx, unsigned argc, Value* vp) return true; } - args.rval().setBoolean(fun->isGenerator()); + args.rval().setBoolean(fun->isStarGenerator() || fun->isLegacyGenerator()); return true; } @@ -1588,8 +1610,6 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator bool isStarGenerator = generatorKind == StarGenerator; bool isAsync = asyncKind == AsyncFunction; MOZ_ASSERT(generatorKind != LegacyGenerator); - MOZ_ASSERT_IF(isAsync, isStarGenerator); - MOZ_ASSERT_IF(!isStarGenerator, !isAsync); RootedScript maybeScript(cx); const char* filename; @@ -1600,10 +1620,14 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator &mutedErrors); const char* introductionType = "Function"; - if (isAsync) - introductionType = "AsyncFunction"; - else if (generatorKind != NotGenerator) + if (isAsync) { + if (isStarGenerator) + introductionType = "AsyncGenerator"; + else + introductionType = "AsyncFunction"; + } else if (generatorKind != NotGenerator) { introductionType = "GeneratorFunction"; + } const char* introducerFilename = filename; if (maybeScript && maybeScript->scriptSource()->introducerFilename()) @@ -1701,7 +1725,7 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator // Step 4.d, use %Generator% as the fallback prototype. // Also use %Generator% for the unwrapped function of async functions. - if (!proto && isStarGenerator) { + if (!proto && (isStarGenerator || isAsync)) { proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global); if (!proto) return false; @@ -1731,12 +1755,20 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator : SourceBufferHolder::NoOwnership; bool ok; SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership); - if (isAsync) - ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, parameterListEnd); - else if (isStarGenerator) - ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd); - else - ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd); + if (isAsync) { + if (isStarGenerator) { + ok = frontend::CompileStandaloneAsyncGenerator(cx, &fun, options, srcBuf, + parameterListEnd); + } else { + ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, + parameterListEnd); + } + } else { + if (isStarGenerator) + ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd); + else + ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd); + } // Step 33. args.rval().setObject(*fun); @@ -1762,14 +1794,14 @@ js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - // Save the callee before its reset in FunctionConstructor(). + // Save the callee before it's reset in FunctionConstructor(). RootedObject newTarget(cx); if (args.isConstructing()) newTarget = &args.newTarget().toObject(); else newTarget = &args.callee(); - if (!FunctionConstructor(cx, args, StarGenerator, AsyncFunction)) + if (!FunctionConstructor(cx, args, NotGenerator, AsyncFunction)) return false; // ES2017, draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077 @@ -1795,6 +1827,40 @@ js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp) } bool +js::AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + // Save the callee before its reset in FunctionConstructor(). + RootedObject newTarget(cx); + if (args.isConstructing()) + newTarget = &args.newTarget().toObject(); + else + newTarget = &args.callee(); + + if (!FunctionConstructor(cx, args, StarGenerator, AsyncFunction)) + return false; + + RootedObject proto(cx); + if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) + return false; + + if (!proto) { + proto = GlobalObject::getOrCreateAsyncGenerator(cx, cx->global()); + if (!proto) + return false; + } + + RootedFunction unwrapped(cx, &args.rval().toObject().as<JSFunction>()); + RootedObject wrapped(cx, WrapAsyncGeneratorWithProto(cx, unwrapped, proto)); + if (!wrapped) + return false; + + args.rval().setObject(*wrapped); + return true; +} + +bool JSFunction::isBuiltinFunctionConstructor() { return maybeNative() == Function || maybeNative() == Generator; @@ -1965,7 +2031,7 @@ NewFunctionClone(JSContext* cx, HandleFunction fun, NewObjectKind newKind, gc::AllocKind allocKind, HandleObject proto) { RootedObject cloneProto(cx, proto); - if (!proto && fun->isStarGenerator()) { + if (!proto && (fun->isStarGenerator() || fun->isAsync())) { cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global()); if (!cloneProto) return nullptr; |