summaryrefslogtreecommitdiffstats
path: root/js/src/jsfun.cpp
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2019-12-17 21:47:18 +0000
committerGitHub <noreply@github.com>2019-12-17 21:47:18 +0000
commit07d0bcbf112a4e274905837c6ea0b0212b51e4e3 (patch)
tree3b43cb63b33d82d4965d402aca39028836983bb4 /js/src/jsfun.cpp
parente2de507e0261c9b138cd3cf5356c21eca3e7a28d (diff)
parent6c3e42ac6427fabaf83b5acc7877aa3d15117125 (diff)
downloadUXP-07d0bcbf112a4e274905837c6ea0b0212b51e4e3.tar
UXP-07d0bcbf112a4e274905837c6ea0b0212b51e4e3.tar.gz
UXP-07d0bcbf112a4e274905837c6ea0b0212b51e4e3.tar.lz
UXP-07d0bcbf112a4e274905837c6ea0b0212b51e4e3.tar.xz
UXP-07d0bcbf112a4e274905837c6ea0b0212b51e4e3.zip
Merge pull request #1327 from g4jc/async_iteration
Implement Async Iteration in SpiderMonkey This resolves #1287
Diffstat (limited to 'js/src/jsfun.cpp')
-rw-r--r--js/src/jsfun.cpp120
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;