Backed out changeset 0705d5b86ad7 (bug 1331092)

This commit is contained in:
Sebastian Hengst 2017-03-27 17:25:37 +02:00
Родитель 3ed58db45c
Коммит ee7e020090
24 изменённых файлов: 55 добавлений и 1260 удалений

Просмотреть файл

@ -852,7 +852,7 @@ struct JSClass {
// application.
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
#define JSCLASS_GLOBAL_SLOT_COUNT \
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 45)
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 41)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \

Просмотреть файл

@ -1,7 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
function AsyncIteratorIdentity() {
return this;
}

Просмотреть файл

@ -12,12 +12,10 @@
#include "jscntxt.h"
#include "jsexn.h"
#include "jsiter.h"
#include "gc/Heap.h"
#include "js/Debug.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
#include "jsobjinlines.h"
@ -38,16 +36,6 @@ enum PromiseHandler {
PromiseHandlerThrower,
PromiseHandlerAsyncFunctionAwaitFulfilled,
PromiseHandlerAsyncFunctionAwaitRejected,
PromiseHandlerAsyncGeneratorAwaitFulfilled,
PromiseHandlerAsyncGeneratorAwaitRejected,
// Async Iteration proposal 6.1.1.2.1.
// Async iterator handlers take the resolved value and create new iterator
// objects. To do so it needs to forward whether the iterator is done. In
// spec, this is achieved via the [[Done]] internal slot. We enumerate both
// true and false cases here.
PromiseHandlerAsyncIteratorValueUnwrapDone,
PromiseHandlerAsyncIteratorValueUnwrapNotDone,
};
enum ResolutionMode {
@ -190,7 +178,6 @@ enum ReactionRecordSlots {
ReactionRecordSlot_IncumbentGlobalObject,
ReactionRecordSlot_Flags,
ReactionRecordSlot_HandlerArg,
ReactionRecordSlot_Generator,
ReactionRecordSlots,
};
@ -198,7 +185,6 @@ enum ReactionRecordSlots {
#define REACTION_FLAG_FULFILLED 0x2
#define REACTION_FLAG_IGNORE_DEFAULT_RESOLUTION 0x4
#define REACTION_FLAG_ASYNC_FUNCTION_AWAIT 0x8
#define REACTION_FLAG_ASYNC_GENERATOR_AWAIT 0x10
// ES2016, 25.4.1.2.
class PromiseReactionRecord : public NativeObject
@ -234,22 +220,6 @@ class PromiseReactionRecord : public NativeObject
int32_t flags = this->flags();
return flags & REACTION_FLAG_ASYNC_FUNCTION_AWAIT;
}
void setIsAsyncGeneratorAwait(Handle<AsyncGeneratorObject*> asyncGenObj) {
int32_t flags = this->flags();
flags |= REACTION_FLAG_ASYNC_GENERATOR_AWAIT;
setFixedSlot(ReactionRecordSlot_Flags, Int32Value(flags));
setFixedSlot(ReactionRecordSlot_Generator, ObjectValue(*asyncGenObj));
}
bool isAsyncGeneratorAwait() {
int32_t flags = this->flags();
return flags & REACTION_FLAG_ASYNC_GENERATOR_AWAIT;
}
AsyncGeneratorObject* asyncGenerator() {
MOZ_ASSERT(isAsyncGeneratorAwait());
return &getFixedSlot(ReactionRecordSlot_Generator).toObject()
.as<AsyncGeneratorObject>();
}
Value handler() {
MOZ_ASSERT(targetState() != JS::PromiseState::Pending);
uint32_t slot = targetState() == JS::PromiseState::Fulfilled
@ -874,34 +844,6 @@ AsyncFunctionAwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord
return true;
}
static MOZ_MUST_USE bool
AsyncGeneratorAwaitPromiseReactionJob(JSContext* cx, Handle<PromiseReactionRecord*> reaction,
MutableHandleValue rval)
{
MOZ_ASSERT(reaction->isAsyncGeneratorAwait());
RootedValue handlerVal(cx, reaction->handler());
RootedValue argument(cx, reaction->handlerArg());
Rooted<AsyncGeneratorObject*> asyncGenObj(cx, reaction->asyncGenerator());
int32_t handlerNum = int32_t(handlerVal.toNumber());
MOZ_ASSERT(handlerNum == PromiseHandlerAsyncGeneratorAwaitFulfilled ||
handlerNum == PromiseHandlerAsyncGeneratorAwaitRejected);
// Await's handlers don't return a value, nor throw exception.
// They fail only on OOM.
if (handlerNum == PromiseHandlerAsyncGeneratorAwaitFulfilled) {
if (!AsyncGeneratorAwaitedFulfilled(cx, asyncGenObj, argument))
return false;
} else {
if (!AsyncGeneratorAwaitedRejected(cx, asyncGenObj, argument))
return false;
}
rval.setUndefined();
return true;
}
// ES2016, 25.4.2.1.
/**
* Callback triggering the fulfill/reject reaction for a resolved Promise,
@ -940,8 +882,6 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
Rooted<PromiseReactionRecord*> reaction(cx, &reactionObj->as<PromiseReactionRecord>());
if (reaction->isAsyncFunctionAwait())
return AsyncFunctionAwaitPromiseReactionJob(cx, reaction, args.rval());
if (reaction->isAsyncGeneratorAwait())
return AsyncGeneratorAwaitPromiseReactionJob(cx, reaction, args.rval());
// Step 3.
RootedValue handlerVal(cx, reaction->handler());
@ -958,21 +898,11 @@ PromiseReactionJob(JSContext* cx, unsigned argc, Value* vp)
// Step 4.
if (handlerNum == PromiseHandlerIdentity) {
handlerResult = argument;
} else if (handlerNum == PromiseHandlerThrower) {
} else {
// Step 5.
MOZ_ASSERT(handlerNum == PromiseHandlerThrower);
resolutionMode = RejectMode;
handlerResult = argument;
} else {
MOZ_ASSERT(handlerNum == PromiseHandlerAsyncIteratorValueUnwrapDone ||
handlerNum == PromiseHandlerAsyncIteratorValueUnwrapNotDone);
bool done = handlerNum == PromiseHandlerAsyncIteratorValueUnwrapDone;
// Async Iteration proposal 6.1.1.2.1 step 1.
RootedObject resultObj(cx, CreateIterResultObject(cx, argument, done));
if (!resultObj)
return false;
handlerResult = ObjectValue(*resultObj);
}
} else {
// Step 6.
@ -2261,185 +2191,6 @@ js::AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, Hand
return PerformPromiseThenWithReaction(cx, promise, reaction);
}
// Async Iteration proposal 5.1 steps 2-9.
MOZ_MUST_USE bool
js::AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue value)
{
// Step 2.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
if (!promise)
return false;
// Steps 3.
if (!ResolvePromiseInternal(cx, promise, value))
return false;
// Steps 4-5.
RootedValue onFulfilled(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitFulfilled));
RootedValue onRejected(cx, Int32Value(PromiseHandlerAsyncGeneratorAwaitRejected));
RootedObject incumbentGlobal(cx);
if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
return false;
// Step 6 (skipped).
// Steps 7-8.
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, nullptr,
onFulfilled, onRejected,
nullptr, nullptr,
incumbentGlobal));
if (!reaction)
return false;
reaction->setIsAsyncGeneratorAwait(asyncGenObj);
// Step 9.
return PerformPromiseThenWithReaction(cx, promise, reaction);
}
// Async Iteration proposal 6.4.3.3.
MOZ_MUST_USE bool
js::AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue value, bool done)
{
// Step 1 (implicit).
// Steps 2-3.
MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
// Step 4.
Rooted<AsyncGeneratorRequest*> request(
cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
if (!request)
return false;
// Step 5.
RootedObject resultPromise(cx, request->promise());
// Step 6.
Rooted<PromiseObject*> promise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
if (!promise)
return false;
// Step 7.
if (!ResolvePromiseInternal(cx, promise, value))
return false;
// Steps 8-9.
RootedValue onFulfilled(cx, Int32Value(done
? PromiseHandlerAsyncIteratorValueUnwrapDone
: PromiseHandlerAsyncIteratorValueUnwrapNotDone));
RootedObject incumbentGlobal(cx);
if (!GetObjectFromIncumbentGlobal(cx, &incumbentGlobal))
return false;
// Step 10.
Rooted<PromiseReactionRecord*> reaction(cx, NewReactionRecord(cx, resultPromise, onFulfilled,
UndefinedHandleValue,
nullptr, nullptr,
incumbentGlobal));
if (!reaction)
return false;
if (!PerformPromiseThenWithReaction(cx, promise, reaction))
return false;
// Step 11.
if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
return false;
// Step 12.
return true;
}
// Async Iteration proposal 6.4.3.4.
MOZ_MUST_USE bool
js::AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue exception)
{
// Step 1 (implicit).
// Steps 2-3.
MOZ_ASSERT(!asyncGenObj->isQueueEmpty());
// Step 4.
Rooted<AsyncGeneratorRequest*> request(
cx, AsyncGeneratorObject::dequeueRequest(cx, asyncGenObj));
if (!request)
return false;
// Step 5.
RootedObject resultPromise(cx, request->promise());
// Step 6.
if (!RejectMaybeWrappedPromise(cx, resultPromise, exception))
return false;
// Step 7.
if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
return false;
// Step 8.
return true;
}
// Async Iteration proposal 6.4.3.6.
MOZ_MUST_USE bool
js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
CompletionKind completionKind, HandleValue completionValue,
MutableHandleValue result)
{
// Step 1 (implicit).
// Step 2.
RootedObject resultPromise(cx, CreatePromiseObjectWithoutResolutionFunctions(cx));
if (!resultPromise)
return false;
// Step 3.
if (!asyncGenVal.isObject() || !asyncGenVal.toObject().is<AsyncGeneratorObject>()) {
// Step 3.a.
RootedValue badGeneratorError(cx);
if (!GetTypeError(cx, JSMSG_NOT_AN_ASYNC_GENERATOR, &badGeneratorError))
return false;
// Step 3.b.
if (!RejectMaybeWrappedPromise(cx, resultPromise, badGeneratorError))
return false;
// Step 3.c.
result.setObject(*resultPromise);
return true;
}
Rooted<AsyncGeneratorObject*> asyncGenObj(
cx, &asyncGenVal.toObject().as<AsyncGeneratorObject>());
// Step 5 (reordered).
Rooted<AsyncGeneratorRequest*> request(
cx, AsyncGeneratorRequest::create(cx, completionKind, completionValue, resultPromise));
if (!request)
return false;
// Steps 4, 6.
if (!AsyncGeneratorObject::enqueueRequest(cx, asyncGenObj, request))
return false;
// Step 7.
if (!asyncGenObj->isExecuting()) {
// Step 8.
if (!AsyncGeneratorResumeNext(cx, asyncGenObj))
return false;
}
// Step 9.
result.setObject(*resultPromise);
return true;
}
// ES2016, 25.4.5.3.
bool
js::Promise_then(JSContext* cx, unsigned argc, Value* vp)

Просмотреть файл

@ -135,23 +135,6 @@ AsyncFunctionThrown(JSContext* cx, Handle<PromiseObject*> resultPromise);
MOZ_MUST_USE bool
AsyncFunctionAwait(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleValue value);
class AsyncGeneratorObject;
MOZ_MUST_USE bool
AsyncGeneratorAwait(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value);
MOZ_MUST_USE bool
AsyncGeneratorResolve(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue value, bool done);
MOZ_MUST_USE bool
AsyncGeneratorReject(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue exception);
MOZ_MUST_USE bool
AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal, CompletionKind completionKind,
HandleValue completionValue, MutableHandleValue result);
/**
* A PromiseTask represents a task that can be dispatched to a helper thread
* (via StartPromiseTask), executed (by implementing PromiseTask::execute()),

Просмотреть файл

@ -778,15 +778,3 @@ frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fu
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope);
return compiler.compileStandaloneFunction(fun, NotGenerator, AsyncFunction, parameterListEnd);
}
bool
frontend::CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
JS::SourceBufferHolder& srcBuf,
const Maybe<uint32_t>& parameterListEnd)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope);
return compiler.compileStandaloneFunction(fun, StarGenerator, AsyncFunction, parameterListEnd);
}

Просмотреть файл

@ -89,12 +89,6 @@ CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
JS::SourceBufferHolder& srcBuf,
const mozilla::Maybe<uint32_t>& parameterListEnd);
MOZ_MUST_USE bool
CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
JS::SourceBufferHolder& srcBuf,
const mozilla::Maybe<uint32_t>& parameterListEnd);
MOZ_MUST_USE bool
CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,

Просмотреть файл

@ -7841,8 +7841,7 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
MOZ_ASSERT(fun->isArrow() == (pn->getOp() == JSOP_LAMBDA_ARROW));
if (funbox->isAsync()) {
MOZ_ASSERT(!needsProto);
return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow(),
fun->isStarGenerator());
return emitAsyncWrapper(index, funbox->needsHomeObject(), fun->isArrow());
}
if (fun->isArrow()) {
@ -7897,11 +7896,8 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
MOZ_ASSERT(pn->getOp() == JSOP_NOP);
switchToPrologue();
if (funbox->isAsync()) {
if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow(),
fun->isStarGenerator()))
{
if (!emitAsyncWrapper(index, fun->isMethod(), fun->isArrow()))
return false;
}
} else {
if (!emitIndex32(JSOP_LAMBDA, index))
return false;
@ -7917,12 +7913,10 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
// initialize the binding name of the function in the current scope.
bool isAsync = funbox->isAsync();
bool isStarGenerator = funbox->isStarGenerator();
auto emitLambda = [index, isAsync, isStarGenerator](BytecodeEmitter* bce,
const NameLocation&, bool) {
auto emitLambda = [index, isAsync](BytecodeEmitter* bce, const NameLocation&, bool) {
if (isAsync) {
return bce->emitAsyncWrapper(index, /* needsHomeObject = */ false,
/* isArrow = */ false, isStarGenerator);
/* isArrow = */ false);
}
return bce->emitIndexOp(JSOP_LAMBDA, index);
};
@ -7957,8 +7951,7 @@ BytecodeEmitter::emitAsyncWrapperLambda(unsigned index, bool isArrow) {
}
bool
BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow,
bool isStarGenerator)
BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow)
{
// needsHomeObject can be true for propertyList for extended class.
// In that case push both unwrapped and wrapped function, in order to
@ -7990,13 +7983,8 @@ BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isA
if (!emit1(JSOP_DUP))
return false;
}
if (isStarGenerator) {
if (!emit1(JSOP_TOASYNCGEN))
return false;
} else {
if (!emit1(JSOP_TOASYNC))
return false;
}
if (!emit1(JSOP_TOASYNC))
return false;
return true;
}

Просмотреть файл

@ -619,8 +619,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitPropIncDec(ParseNode* pn);
MOZ_MUST_USE bool emitAsyncWrapperLambda(unsigned index, bool isArrow);
MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow,
bool isStarGenerator);
MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow);
MOZ_MUST_USE bool emitComputedPropertyName(ParseNode* computedPropName);

Просмотреть файл

@ -3753,12 +3753,10 @@ Parser<ParseHandler>::functionStmt(uint32_t preludeStart, YieldHandling yieldHan
GeneratorKind generatorKind = NotGenerator;
if (tt == TOK_MUL) {
#ifdef RELEASE_OR_BETA
if (asyncKind != SyncFunction) {
error(JSMSG_ASYNC_GENERATOR);
return null();
}
#endif
generatorKind = StarGenerator;
if (!tokenStream.getToken(&tt))
return null();
@ -3827,12 +3825,10 @@ Parser<ParseHandler>::functionExpr(uint32_t preludeStart, InvokedPrediction invo
return null();
if (tt == TOK_MUL) {
#ifdef RELEASE_OR_BETA
if (asyncKind != SyncFunction) {
error(JSMSG_ASYNC_GENERATOR);
return null();
}
#endif
generatorKind = StarGenerator;
if (!tokenStream.getToken(&tt))
return null();
@ -9292,6 +9288,11 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
bool isGenerator = false;
bool isAsync = false;
if (ltok == TOK_MUL) {
isGenerator = true;
if (!tokenStream.getToken(&ltok))
return null();
}
if (ltok == TOK_ASYNC) {
// AsyncMethod[Yield, Await]:
@ -9320,15 +9321,9 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
}
}
if (ltok == TOK_MUL) {
#ifdef RELEASE_OR_BETA
if (isAsync && isGenerator) {
error(JSMSG_ASYNC_GENERATOR);
return null();
#else
isGenerator = true;
if (!tokenStream.getToken(&ltok))
return null();
#endif
}
propAtom.set(nullptr);

Просмотреть файл

@ -591,6 +591,3 @@ MSG_DEF(JSMSG_PROMISE_ERROR_IN_WRAPPED_REJECTION_REASON,0, JSEXN_INTERNALERR, "P
// Iterator
MSG_DEF(JSMSG_RETURN_NOT_CALLABLE, 0, JSEXN_TYPEERR, "property 'return' of iterator is not callable")
MSG_DEF(JSMSG_ITERATOR_NO_THROW, 0, JSEXN_TYPEERR, "iterator does not have a 'throw' method")
// Async Iteration
MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator")

Просмотреть файл

@ -71,7 +71,6 @@
#include "js/StructuredClone.h"
#include "js/Utility.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
#include "vm/DateObject.h"
#include "vm/Debugger.h"
#include "vm/EnvironmentObject.h"
@ -3616,11 +3615,6 @@ CloneFunctionObject(JSContext* cx, HandleObject funobj, HandleObject env, Handle
return nullptr;
}
if (IsWrappedAsyncGenerator(fun)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CANT_CLONE_OBJECT);
return nullptr;
}
if (CanReuseScriptForClone(cx->compartment(), fun, env)) {
// If the script is to be reused, either the script can already handle
// non-syntactic scopes, or there is only the standard global lexical

Просмотреть файл

@ -41,7 +41,6 @@
#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"
@ -307,8 +306,6 @@ 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()) {
@ -405,15 +402,13 @@ static const JSPropertySpec function_properties[] = {
static bool
ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId id)
{
bool isAsyncGenerator = IsWrappedAsyncGenerator(fun);
MOZ_ASSERT_IF(!isAsyncGenerator, fun->isInterpreted() || fun->isAsmJSNative());
MOZ_ASSERT(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_IF(!isAsyncGenerator, !IsInternalFunctionObject(*fun));
MOZ_ASSERT(!IsInternalFunctionObject(*fun));
MOZ_ASSERT(!fun->isBoundFunction());
// Make the prototype object an instance of Object with the same parent as
@ -423,9 +418,7 @@ ResolveInterpretedFunctionPrototype(JSContext* cx, HandleFunction fun, HandleId
bool isStarGenerator = fun->isStarGenerator();
Rooted<GlobalObject*> global(cx, &fun->global());
RootedObject objProto(cx);
if (isAsyncGenerator)
objProto = GlobalObject::getOrCreateAsyncGeneratorPrototype(cx, global);
else if (isStarGenerator)
if (isStarGenerator)
objProto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global);
else
objProto = GlobalObject::getOrCreateObjectPrototype(cx, global);
@ -441,7 +434,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 && !isAsyncGenerator) {
if (!isStarGenerator) {
RootedValue objVal(cx, ObjectValue(*fun));
if (!DefineProperty(cx, proto, cx->names().constructor, objVal, nullptr, nullptr, 0))
return false;
@ -491,13 +484,11 @@ fun_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
* - Arrow functions
* - Function.prototype
*/
if (!IsWrappedAsyncGenerator(fun)) {
if (fun->isBuiltin())
if (fun->isBuiltin())
return true;
if (!fun->isConstructor()) {
if (!fun->isStarGenerator() && !fun->isLegacyGenerator() && !fun->isAsync())
return true;
if (!fun->isConstructor()) {
if (!fun->isStarGenerator() && !fun->isLegacyGenerator() && !fun->isAsync())
return true;
}
}
if (!ResolveInterpretedFunctionPrototype(cx, fun, id))
@ -994,10 +985,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
return FunctionToString(cx, unwrapped, prettyPrint);
}
if (IsWrappedAsyncGenerator(fun)) {
RootedFunction unwrapped(cx, GetUnwrappedAsyncGenerator(fun));
return FunctionToString(cx, unwrapped, prettyPrint);
}
StringBuffer out(cx);
RootedScript script(cx);
@ -1650,14 +1637,10 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
&mutedErrors);
const char* introductionType = "Function";
if (isAsync) {
if (isStarGenerator)
introductionType = "AsyncGenerator";
else
introductionType = "AsyncFunction";
} else if (generatorKind != NotGenerator) {
if (isAsync)
introductionType = "AsyncFunction";
else if (generatorKind != NotGenerator)
introductionType = "GeneratorFunction";
}
const char* introducerFilename = filename;
if (maybeScript && maybeScript->scriptSource()->introducerFilename())
@ -1784,20 +1767,12 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
: SourceBufferHolder::NoOwnership;
bool ok;
SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership);
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);
}
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);
// Step 33.
args.rval().setObject(*fun);
@ -1823,7 +1798,7 @@ js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Save the callee before it's reset in FunctionConstructor().
// Save the callee before its reset in FunctionConstructor().
RootedObject newTarget(cx);
if (args.isConstructing())
newTarget = &args.newTarget().toObject();
@ -1855,40 +1830,6 @@ js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
return true;
}
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()
{

Просмотреть файл

@ -647,9 +647,6 @@ Generator(JSContext* cx, unsigned argc, Value* vp);
extern bool
AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp);
extern bool
AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp);
// Allocate a new function backed by a JSNative. Note that by default this
// creates a singleton object.
extern JSFunction*

Просмотреть файл

@ -938,30 +938,28 @@ js::GetIteratorObject(JSContext* cx, HandleObject obj, uint32_t flags)
return iterator;
}
// ES 2017 draft 7.4.7.
JSObject*
js::CreateIterResultObject(JSContext* cx, HandleValue value, bool done)
js::CreateItrResultObject(JSContext* cx, HandleValue value, bool done)
{
// Step 1 (implicit).
// FIXME: We can cache the iterator result object shape somewhere.
AssertHeapIsIdle();
// Step 2.
RootedObject resultObj(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!resultObj)
RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, cx->global()));
if (!proto)
return nullptr;
// Step 3.
if (!DefineProperty(cx, resultObj, cx->names().value, value))
RootedPlainObject obj(cx, NewObjectWithGivenProto<PlainObject>(cx, proto));
if (!obj)
return nullptr;
// Step 4.
if (!DefineProperty(cx, resultObj, cx->names().done,
done ? TrueHandleValue : FalseHandleValue))
{
if (!DefineProperty(cx, obj, cx->names().value, value))
return nullptr;
}
// Step 5.
return resultObj;
RootedValue doneBool(cx, BooleanValue(done));
if (!DefineProperty(cx, obj, cx->names().done, doneBool))
return nullptr;
return obj;
}
bool

Просмотреть файл

@ -210,10 +210,10 @@ ThrowStopIteration(JSContext* cx);
/*
* Create an object of the form { value: VALUE, done: DONE }.
* ES 2017 draft 7.4.7.
* ES6 draft from 2013-09-05, section 25.4.3.4.
*/
extern JSObject*
CreateIterResultObject(JSContext* cx, HandleValue value, bool done);
CreateItrResultObject(JSContext* cx, HandleValue value, bool done);
extern JSObject*
InitLegacyIteratorClass(JSContext* cx, HandleObject obj);

Просмотреть файл

@ -311,7 +311,6 @@ UNIFIED_SOURCES += [
'vm/ArgumentsObject.cpp',
'vm/ArrayBufferObject.cpp',
'vm/AsyncFunction.cpp',
'vm/AsyncIteration.cpp',
'vm/Caches.cpp',
'vm/CallNonGenericMethod.cpp',
'vm/CharacterEncoding.cpp',
@ -754,7 +753,6 @@ selfhosted.inputs = [
'builtin/SelfHostingDefines.h',
'builtin/Utilities.js',
'builtin/Array.js',
'builtin/AsyncIteration.js',
'builtin/Classes.js',
'builtin/Date.js',
'builtin/Error.js',

Просмотреть файл

@ -86,7 +86,6 @@
#include "threading/Thread.h"
#include "vm/ArgumentsObject.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
#include "vm/Compression.h"
#include "vm/Debugger.h"
#include "vm/HelperThreads.h"
@ -2396,8 +2395,6 @@ ValueToScript(JSContext* cx, HandleValue v, JSFunction** funp = nullptr)
// Get unwrapped async function.
if (IsWrappedAsyncFunction(fun))
fun = GetUnwrappedAsyncFunction(fun);
if (IsWrappedAsyncGenerator(fun))
fun = GetUnwrappedAsyncGenerator(fun);
if (!fun->isInterpreted()) {
JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr, JSSMSG_SCRIPTS_ONLY);

Просмотреть файл

@ -9,6 +9,9 @@ if (typeof Reflect !== "undefined" && Reflect.parse) {
assertEq(Reflect.parse("async function a() {}").body[0].async, true);
assertEq(Reflect.parse("() => {}").body[0].async, undefined);
// Async generators are not allowed (with regards to spec)
assertThrows(() => Reflect.parse("async function* a() {}"), SyntaxError);
// No line terminator after async
assertEq(Reflect.parse("async\nfunction a(){}").body[0].expression.name, "async");

Просмотреть файл

@ -1,564 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "vm/AsyncIteration.h"
#include "jsarray.h"
#include "jscompartment.h"
#include "builtin/Promise.h"
#include "vm/GeneratorObject.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
#include "vm/SelfHosting.h"
#include "jscntxtinlines.h"
#include "jsobjinlines.h"
#include "vm/NativeObject-inl.h"
using namespace js;
using namespace js::gc;
#define UNWRAPPED_ASYNC_WRAPPED_SLOT 1
#define WRAPPED_ASYNC_UNWRAPPED_SLOT 0
// Async Iteration proposal 2.3.10 Runtime Semantics: EvaluateBody.
static bool
WrappedAsyncGenerator(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedFunction wrapped(cx, &args.callee().as<JSFunction>());
RootedValue unwrappedVal(cx, wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT));
RootedFunction unwrapped(cx, &unwrappedVal.toObject().as<JSFunction>());
RootedValue thisValue(cx, args.thisv());
// Step 1.
RootedValue generatorVal(cx);
InvokeArgs args2(cx);
if (!args2.init(cx, argc))
return false;
for (size_t i = 0, len = argc; i < len; i++)
args2[i].set(args[i]);
if (!Call(cx, unwrappedVal, thisValue, args2, &generatorVal))
return false;
// Step 2.
Rooted<AsyncGeneratorObject*> asyncGenObj(
cx, AsyncGeneratorObject::create(cx, wrapped, generatorVal));
if (!asyncGenObj)
return false;
// Step 3 (skipped).
// Done in AsyncGeneratorObject::create and generator.
// Step 4.
args.rval().setObject(*asyncGenObj);
return true;
}
JSObject*
js::WrapAsyncGeneratorWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto)
{
MOZ_ASSERT(unwrapped->isAsync());
MOZ_ASSERT(proto, "We need an explicit prototype to avoid the default"
"%FunctionPrototype% fallback in NewFunctionWithProto().");
// Create a new function with AsyncGeneratorPrototype, reusing the name and
// the length of `unwrapped`.
RootedAtom funName(cx, unwrapped->explicitName());
uint16_t length;
if (!JSFunction::getLength(cx, unwrapped, &length))
return nullptr;
RootedFunction wrapped(cx, NewFunctionWithProto(cx, WrappedAsyncGenerator, length,
JSFunction::NATIVE_FUN, nullptr,
funName, proto,
AllocKind::FUNCTION_EXTENDED,
TenuredObject));
if (!wrapped)
return nullptr;
if (unwrapped->hasCompileTimeName())
wrapped->setCompileTimeName(unwrapped->compileTimeName());
// Link them to each other to make GetWrappedAsyncGenerator and
// GetUnwrappedAsyncGenerator work.
unwrapped->setExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT, ObjectValue(*wrapped));
wrapped->setExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT, ObjectValue(*unwrapped));
return wrapped;
}
JSObject*
js::WrapAsyncGenerator(JSContext* cx, HandleFunction unwrapped)
{
RootedObject proto(cx, GlobalObject::getOrCreateAsyncGenerator(cx, cx->global()));
if (!proto)
return nullptr;
return WrapAsyncGeneratorWithProto(cx, unwrapped, proto);
}
bool
js::IsWrappedAsyncGenerator(JSFunction* fun)
{
return fun->maybeNative() == WrappedAsyncGenerator;
}
JSFunction*
js::GetWrappedAsyncGenerator(JSFunction* unwrapped)
{
MOZ_ASSERT(unwrapped->isAsync());
return &unwrapped->getExtendedSlot(UNWRAPPED_ASYNC_WRAPPED_SLOT).toObject().as<JSFunction>();
}
JSFunction*
js::GetUnwrappedAsyncGenerator(JSFunction* wrapped)
{
MOZ_ASSERT(IsWrappedAsyncGenerator(wrapped));
JSFunction* unwrapped = &wrapped->getExtendedSlot(WRAPPED_ASYNC_UNWRAPPED_SLOT)
.toObject().as<JSFunction>();
MOZ_ASSERT(unwrapped->isAsync());
return unwrapped;
}
static MOZ_MUST_USE bool
AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
CompletionKind completionKind, HandleValue argument);
// Async Iteration proposal 5.1.1 Await Fulfilled Functions.
MOZ_MUST_USE bool
js::AsyncGeneratorAwaitedFulfilled(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue value)
{
return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Normal, value);
}
// Async Iteration proposal 5.1.2 Await Rejected Functions.
MOZ_MUST_USE bool
js::AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue reason)
{
return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Throw, reason);
}
// Async Iteration proposal 6.4.1.2 AsyncGenerator.prototype.next.
static bool
AsyncGeneratorNext(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Steps 1-3.
return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Normal, args.get(0),
args.rval());
}
// Async Iteration proposal 6.4.1.3 AsyncGenerator.prototype.return.
static bool
AsyncGeneratorReturn(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Steps 1-3.
return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Return, args.get(0),
args.rval());
}
// Async Iteration proposal 6.4.1.4 AsyncGenerator.prototype.throw.
static bool
AsyncGeneratorThrow(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Steps 1-3.
return AsyncGeneratorEnqueue(cx, args.thisv(), CompletionKind::Throw, args.get(0),
args.rval());
}
const Class AsyncGeneratorObject::class_ = {
"AsyncGenerator",
JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorObject::Slots)
};
// ES 2017 draft 9.1.13.
template <typename ProtoGetter>
static JSObject*
OrdinaryCreateFromConstructor(JSContext* cx, HandleFunction fun,
ProtoGetter protoGetter, const Class* clasp)
{
// Step 1 (skipped).
// Step 2.
RootedValue protoVal(cx);
if (!GetProperty(cx, fun, fun, cx->names().prototype, &protoVal))
return nullptr;
RootedObject proto(cx, protoVal.isObject() ? &protoVal.toObject() : nullptr);
if (!proto) {
proto = protoGetter(cx, cx->global());
if (!proto)
return nullptr;
}
// Step 3.
return NewNativeObjectWithGivenProto(cx, clasp, proto);
}
/* static */ AsyncGeneratorObject*
AsyncGeneratorObject::create(JSContext* cx, HandleFunction asyncGen, HandleValue generatorVal)
{
MOZ_ASSERT(generatorVal.isObject());
MOZ_ASSERT(generatorVal.toObject().is<GeneratorObject>());
RootedObject obj(
cx, OrdinaryCreateFromConstructor(cx, asyncGen,
GlobalObject::getOrCreateAsyncGeneratorPrototype,
&class_));
if (!obj)
return nullptr;
Handle<AsyncGeneratorObject*> asyncGenObj = obj.as<AsyncGeneratorObject>();
// Async Iteration proposal 6.4.3.2 AsyncGeneratorStart.
// Step 6.
asyncGenObj->setGenerator(generatorVal);
// Step 7.
asyncGenObj->setSuspendedStart();
// Step 8.
asyncGenObj->clearSingleQueueRequest();
return asyncGenObj;
}
/* static */ MOZ_MUST_USE bool
AsyncGeneratorObject::enqueueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
Handle<AsyncGeneratorRequest*> request)
{
if (asyncGenObj->isSingleQueue()) {
if (asyncGenObj->isSingleQueueEmpty()) {
asyncGenObj->setSingleQueueRequest(request);
return true;
}
RootedArrayObject queue(cx, NewDenseEmptyArray(cx));
if (!queue)
return false;
if (!NewbornArrayPush(cx, queue, ObjectValue(*asyncGenObj->singleQueueRequest())))
return false;
if (!NewbornArrayPush(cx, queue, ObjectValue(*request)))
return false;
asyncGenObj->setQueue(queue);
return true;
}
RootedArrayObject queue(cx, asyncGenObj->queue());
FixedInvokeArgs<1> args(cx);
args[0].setObject(*request);
args.setThis(ObjectValue(*queue));
return CallJSNative(cx, array_push, args);
}
/* static */ AsyncGeneratorRequest*
AsyncGeneratorObject::dequeueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
{
if (asyncGenObj->isSingleQueue()) {
AsyncGeneratorRequest* request = asyncGenObj->singleQueueRequest();
asyncGenObj->clearSingleQueueRequest();
return request;
}
RootedArrayObject queue(cx, asyncGenObj->queue());
FixedInvokeArgs<0> args(cx);
args.setThis(ObjectValue(*queue));
if (!CallJSNative(cx, array_shift, args))
return nullptr;
return &args.rval().toObject().as<AsyncGeneratorRequest>();
}
/* static */ AsyncGeneratorRequest*
AsyncGeneratorObject::peekRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
{
if (asyncGenObj->isSingleQueue())
return asyncGenObj->singleQueueRequest();
RootedArrayObject queue(cx, asyncGenObj->queue());
RootedValue requestVal(cx);
if (!GetElement(cx, queue, queue, 0, &requestVal))
return nullptr;
return &requestVal.toObject().as<AsyncGeneratorRequest>();
}
const Class AsyncGeneratorRequest::class_ = {
"AsyncGeneratorRequest",
JSCLASS_HAS_RESERVED_SLOTS(AsyncGeneratorRequest::Slots)
};
// Async Iteration proposal 6.4.3.1.
/* static */ AsyncGeneratorRequest*
AsyncGeneratorRequest::create(JSContext* cx, CompletionKind completionKind_,
HandleValue completionValue_, HandleObject promise_)
{
RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, nullptr));
if (!obj)
return nullptr;
Handle<AsyncGeneratorRequest*> request = obj.as<AsyncGeneratorRequest>();
request->setCompletionKind(completionKind_);
request->setCompletionValue(completionValue_);
request->setPromise(promise_);
return request;
}
// Async Iteration proposal 6.4.3.2 steps 5.d-g.
static MOZ_MUST_USE bool
AsyncGeneratorReturned(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue value)
{
// Step 5.d.
asyncGenObj->setCompleted();
// Step 5.e (done in bytecode).
// Step 5.f.i (implicit).
// Step 5.g.
return AsyncGeneratorResolve(cx, asyncGenObj, value, true);
}
// Async Iteration proposal 6.4.3.2 steps 5.d, f.
static MOZ_MUST_USE bool
AsyncGeneratorThrown(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
{
// Step 5.d.
asyncGenObj->setCompleted();
// Not much we can do about uncatchable exceptions, so just bail.
if (!cx->isExceptionPending())
return false;
// Step 5.f.i.
RootedValue value(cx);
if (!GetAndClearException(cx, &value))
return false;
// Step 5.f.ii.
return AsyncGeneratorReject(cx, asyncGenObj, value);
}
// Async Iteration proposal 6.4.3.5.
MOZ_MUST_USE bool
js::AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj)
{
// Step 1 (implicit).
// Steps 2-3.
MOZ_ASSERT(!asyncGenObj->isExecuting());
// Steps 4-5.
if (asyncGenObj->isQueueEmpty())
return true;
// Steps 6-7.
Rooted<AsyncGeneratorRequest*> request(
cx, AsyncGeneratorObject::peekRequest(cx, asyncGenObj));
if (!request)
return false;
// Step 8.
CompletionKind completionKind = request->completionKind();
// Step 9.
if (completionKind != CompletionKind::Normal) {
// Step 9.a.
if (asyncGenObj->isSuspendedStart())
asyncGenObj->setCompleted();
// Step 9.b.
if (asyncGenObj->isCompleted()) {
// Step 9.b.i.
RootedValue value(cx, request->completionValue());
if (completionKind == CompletionKind::Return)
return AsyncGeneratorResolve(cx, asyncGenObj, value, true);
// Step 9.b.ii.
return AsyncGeneratorReject(cx, asyncGenObj, value);
}
} else if (asyncGenObj->isCompleted()) {
// Step 10.
return AsyncGeneratorResolve(cx, asyncGenObj, UndefinedHandleValue, true);
}
// Step 11.
MOZ_ASSERT(asyncGenObj->isSuspendedStart() || asyncGenObj->isSuspendedYield());
// Step 15 (reordered).
asyncGenObj->setExecuting();
RootedValue argument(cx, request->completionValue());
// Steps 12-14, 16-20.
return AsyncGeneratorResume(cx, asyncGenObj, completionKind, argument);
}
// Async Iteration proposal 6.2.1.2 (partially).
// Most steps are done in generator.
static MOZ_MUST_USE bool
AsyncGeneratorYield(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue value, bool done)
{
// Step 6.
asyncGenObj->setSuspendedYield();
// Step 10.c.
return AsyncGeneratorResolve(cx, asyncGenObj, value, done);
}
// Async Iteration proposal 6.4.3.5 steps 12-14, 16-20.
// Async Iteration proposal 6.2.1.2 step 10.
// Async Iteration proposal 6.4.3.2 step 5.f-g.
// Async Iteration proposal 5.1 steps 2-9.
// Execution context switching is handled in generator.
static MOZ_MUST_USE bool
AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
CompletionKind completionKind, HandleValue argument)
{
RootedValue generatorVal(cx, asyncGenObj->generatorVal());
// 6.4.3.5 steps 12-14, 16-20.
HandlePropertyName funName = completionKind == CompletionKind::Normal
? cx->names().StarGeneratorNext
: completionKind == CompletionKind::Throw
? cx->names().StarGeneratorThrow
: cx->names().StarGeneratorReturn;
FixedInvokeArgs<1> args(cx);
args[0].set(argument);
RootedValue result(cx);
if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &result)) {
// 6.4.3.2 step 5.d, f.
return AsyncGeneratorThrown(cx, asyncGenObj);
}
// The following code corresponds to the following 3 cases:
// * yield
// * await
// * return
// For await and return, property access is done on an internal result
// object and it's not observable.
// For yield, it's done on an user-provided result object, and it's
// observable, so perform in that order in all cases.
RootedObject resultObj(cx, &result.toObject());
RootedValue value(cx);
RootedValue doneVal(cx);
// 6.2.1.2 step 10.a.
if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
return false;
// 6.2.1.2 step 10.b.
if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
return false;
// 6.2.1.2 step 10.c.
if (asyncGenObj->generatorObj()->isAfterYield())
return AsyncGeneratorYield(cx, asyncGenObj, value, ToBoolean(doneVal));
// 6.4.3.2 step 5.d-g.
if (ToBoolean(doneVal)) {
MOZ_ASSERT(!asyncGenObj->generatorObj()->isAfterAwait());
return AsyncGeneratorReturned(cx, asyncGenObj, value);
}
MOZ_ASSERT(asyncGenObj->generatorObj()->isAfterAwait());
// 5.1 steps 2-9.
return AsyncGeneratorAwait(cx, asyncGenObj, value);
}
static const JSFunctionSpec async_iterator_proto_methods[] = {
JS_SELF_HOSTED_SYM_FN(asyncIterator, "AsyncIteratorIdentity", 0, 0),
JS_FS_END
};
static const JSFunctionSpec async_generator_methods[] = {
JS_FN("next", AsyncGeneratorNext, 1, 0),
JS_FN("throw", AsyncGeneratorThrow, 1, 0),
JS_FN("return", AsyncGeneratorReturn, 1, 0),
JS_FS_END
};
/* static */ MOZ_MUST_USE bool
GlobalObject::initAsyncGenerators(JSContext* cx, Handle<GlobalObject*> global)
{
if (global->getReservedSlot(ASYNC_ITERATOR_PROTO).isObject())
return true;
// Async Iteration proposal 6.1.2 %AsyncIteratorPrototype%.
RootedObject asyncIterProto(cx, GlobalObject::createBlankPrototype<PlainObject>(cx, global));
if (!asyncIterProto)
return false;
if (!DefinePropertiesAndFunctions(cx, asyncIterProto, nullptr, async_iterator_proto_methods))
return false;
// Async Iteration proposal 6.4.1 %AsyncGeneratorPrototype%.
RootedObject asyncGenProto(
cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
asyncIterProto));
if (!asyncGenProto)
return false;
if (!DefinePropertiesAndFunctions(cx, asyncGenProto, nullptr, async_generator_methods) ||
!DefineToStringTag(cx, asyncGenProto, cx->names().AsyncGenerator))
{
return false;
}
// Async Iteration proposal 6.3.3 %AsyncGenerator%.
RootedObject asyncGenerator(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
if (!asyncGenerator)
return false;
if (!JSObject::setDelegate(cx, asyncGenerator))
return false;
if (!LinkConstructorAndPrototype(cx, asyncGenerator, asyncGenProto, JSPROP_READONLY,
JSPROP_READONLY) ||
!DefineToStringTag(cx, asyncGenerator, cx->names().AsyncGeneratorFunction))
{
return false;
}
RootedValue function(cx, global->getConstructor(JSProto_Function));
if (!function.toObjectOrNull())
return false;
RootedObject proto(cx, &function.toObject());
RootedAtom name(cx, cx->names().AsyncGeneratorFunction);
// Async Iteration proposal 6.3.2 %AsyncGeneratorFunction%.
RootedObject asyncGenFunction(
cx, NewFunctionWithProto(cx, AsyncGeneratorConstructor, 1, JSFunction::NATIVE_CTOR,
nullptr, name, proto, gc::AllocKind::FUNCTION, SingletonObject));
if (!asyncGenFunction)
return false;
if (!LinkConstructorAndPrototype(cx, asyncGenFunction, asyncGenerator,
JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
{
return false;
}
global->setReservedSlot(ASYNC_ITERATOR_PROTO, ObjectValue(*asyncIterProto));
global->setReservedSlot(ASYNC_GENERATOR, ObjectValue(*asyncGenerator));
global->setReservedSlot(ASYNC_GENERATOR_FUNCTION, ObjectValue(*asyncGenFunction));
global->setReservedSlot(ASYNC_GENERATOR_PROTO, ObjectValue(*asyncGenProto));
return true;
}

Просмотреть файл

@ -1,204 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_AsyncIteration_h
#define vm_AsyncIteration_h
#include "jscntxt.h"
#include "jsobj.h"
#include "builtin/Promise.h"
#include "vm/GeneratorObject.h"
namespace js {
// Async generator consists of 2 functions, |wrapped| and |unwrapped|.
// |unwrapped| is a generator function compiled from async generator script,
// |await| behaves just like |yield| there. |unwrapped| isn't exposed to user
// script.
// |wrapped| is a native function that is the value of async generator.
JSObject*
WrapAsyncGeneratorWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto);
JSObject*
WrapAsyncGenerator(JSContext* cx, HandleFunction unwrapped);
bool
IsWrappedAsyncGenerator(JSFunction* fun);
JSFunction*
GetWrappedAsyncGenerator(JSFunction* unwrapped);
JSFunction*
GetUnwrappedAsyncGenerator(JSFunction* wrapped);
MOZ_MUST_USE bool
AsyncGeneratorAwaitedFulfilled(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue value);
MOZ_MUST_USE bool
AsyncGeneratorAwaitedRejected(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
HandleValue reason);
class AsyncGeneratorRequest : public NativeObject
{
private:
enum AsyncGeneratorRequestSlots {
Slot_CompletionKind = 0,
Slot_CompletionValue,
Slot_Promise,
Slots,
};
void setCompletionKind(CompletionKind completionKind_) {
setFixedSlot(Slot_CompletionKind,
Int32Value(static_cast<int32_t>(completionKind_)));
}
void setCompletionValue(HandleValue completionValue_) {
setFixedSlot(Slot_CompletionValue, completionValue_);
}
void setPromise(HandleObject promise_) {
setFixedSlot(Slot_Promise, ObjectValue(*promise_));
}
public:
static const Class class_;
static AsyncGeneratorRequest*
create(JSContext* cx, CompletionKind completionKind, HandleValue completionValue,
HandleObject promise);
CompletionKind completionKind() const {
return static_cast<CompletionKind>(getFixedSlot(Slot_CompletionKind).toInt32());
}
JS::Value completionValue() const {
return getFixedSlot(Slot_CompletionValue);
}
JSObject* promise() const {
return &getFixedSlot(Slot_Promise).toObject();
}
};
class AsyncGeneratorObject : public NativeObject
{
private:
enum AsyncGeneratorObjectSlots {
Slot_State = 0,
Slot_Generator,
Slot_QueueOrRequest,
Slots
};
enum State {
State_SuspendedStart,
State_SuspendedYield,
State_Executing,
State_Completed
};
State state() const {
return static_cast<State>(getFixedSlot(Slot_State).toInt32());
}
void setState(State state_) {
setFixedSlot(Slot_State, Int32Value(state_));
}
void setGenerator(const Value& value) {
setFixedSlot(Slot_Generator, value);
}
// Queue is implemented in 2 ways. If only one request is queued ever,
// request is stored directly to the slot. Once 2 requests are queued, an
// array is created and requests are pushed into it, and the array is
// stored to the slot.
bool isSingleQueue() const {
return getFixedSlot(Slot_QueueOrRequest).isNull() ||
getFixedSlot(Slot_QueueOrRequest).toObject().is<AsyncGeneratorRequest>();
}
bool isSingleQueueEmpty() const {
return getFixedSlot(Slot_QueueOrRequest).isNull();
}
void setSingleQueueRequest(AsyncGeneratorRequest* request) {
setFixedSlot(Slot_QueueOrRequest, ObjectValue(*request));
}
void clearSingleQueueRequest() {
setFixedSlot(Slot_QueueOrRequest, NullHandleValue);
}
AsyncGeneratorRequest* singleQueueRequest() const {
return &getFixedSlot(Slot_QueueOrRequest).toObject().as<AsyncGeneratorRequest>();
}
ArrayObject* queue() const {
return &getFixedSlot(Slot_QueueOrRequest).toObject().as<ArrayObject>();
}
void setQueue(JSObject* queue_) {
setFixedSlot(Slot_QueueOrRequest, ObjectValue(*queue_));
}
public:
static const Class class_;
static AsyncGeneratorObject*
create(JSContext* cx, HandleFunction asyncGen, HandleValue generatorVal);
bool isSuspendedStart() const {
return state() == State_SuspendedStart;
}
bool isSuspendedYield() const {
return state() == State_SuspendedYield;
}
bool isExecuting() const {
return state() == State_Executing;
}
bool isCompleted() const {
return state() == State_Completed;
}
void setSuspendedStart() {
setState(State_SuspendedStart);
}
void setSuspendedYield() {
setState(State_SuspendedYield);
}
void setExecuting() {
setState(State_Executing);
}
void setCompleted() {
setState(State_Completed);
}
JS::Value generatorVal() const {
return getFixedSlot(Slot_Generator);
}
GeneratorObject* generatorObj() const {
return &getFixedSlot(Slot_Generator).toObject().as<GeneratorObject>();
}
static MOZ_MUST_USE bool
enqueueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
Handle<AsyncGeneratorRequest*> request);
static AsyncGeneratorRequest*
dequeueRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
static AsyncGeneratorRequest*
peekRequest(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
bool isQueueEmpty() const {
if (isSingleQueue())
return isSingleQueueEmpty();
return queue()->length() == 0;
}
};
MOZ_MUST_USE bool
AsyncGeneratorResumeNext(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj);
} // namespace js
#endif /* vm_AsyncIteration_h */

Просмотреть файл

@ -31,8 +31,6 @@
macro(as, as, "as") \
macro(Async, Async, "Async") \
macro(AsyncFunction, AsyncFunction, "AsyncFunction") \
macro(AsyncGenerator, AsyncGenerator, "AsyncGenerator") \
macro(AsyncGeneratorFunction, AsyncGeneratorFunction, "AsyncGeneratorFunction") \
macro(AsyncWrapped, AsyncWrapped, "AsyncWrapped") \
macro(async, async, "async") \
macro(await, await, "await") \
@ -321,7 +319,6 @@
macro(star, star, "*") \
macro(starDefaultStar, starDefaultStar, "*default*") \
macro(StarGeneratorNext, StarGeneratorNext, "StarGeneratorNext") \
macro(StarGeneratorReturn, StarGeneratorReturn, "StarGeneratorReturn") \
macro(StarGeneratorThrow, StarGeneratorThrow, "StarGeneratorThrow") \
macro(startTimestamp, startTimestamp, "startTimestamp") \
macro(state, state, "state") \

Просмотреть файл

@ -98,10 +98,6 @@ class GlobalObject : public NativeObject
STAR_GENERATOR_FUNCTION,
ASYNC_FUNCTION_PROTO,
ASYNC_FUNCTION,
ASYNC_ITERATOR_PROTO,
ASYNC_GENERATOR,
ASYNC_GENERATOR_FUNCTION,
ASYNC_GENERATOR_PROTO,
MAP_ITERATOR_PROTO,
SET_ITERATOR_PROTO,
COLLATOR_PROTO,
@ -633,30 +629,6 @@ class GlobalObject : public NativeObject
return getOrCreateObject(cx, global, ASYNC_FUNCTION, initAsyncFunction);
}
static NativeObject*
getOrCreateAsyncIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global)
{
return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_ITERATOR_PROTO,
initAsyncGenerators));
}
static NativeObject*
getOrCreateAsyncGenerator(JSContext* cx, Handle<GlobalObject*> global) {
return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_GENERATOR,
initAsyncGenerators));
}
static JSObject*
getOrCreateAsyncGeneratorFunction(JSContext* cx, Handle<GlobalObject*> global) {
return getOrCreateObject(cx, global, ASYNC_GENERATOR_FUNCTION, initAsyncGenerators);
}
static NativeObject*
getOrCreateAsyncGeneratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_GENERATOR_PROTO,
initAsyncGenerators));
}
static JSObject*
getOrCreateMapIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
return getOrCreateObject(cx, global, MAP_ITERATOR_PROTO, initMapIteratorProto);
@ -803,8 +775,6 @@ class GlobalObject : public NativeObject
static bool initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global);
static bool initAsyncGenerators(JSContext* cx, Handle<GlobalObject*> global);
// Implemented in builtin/MapObject.cpp.
static bool initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
static bool initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global);

Просмотреть файл

@ -39,7 +39,6 @@
#include "jit/Ion.h"
#include "jit/IonAnalysis.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
#include "vm/Debugger.h"
#include "vm/GeneratorObject.h"
#include "vm/Opcodes.h"
@ -1923,6 +1922,7 @@ CASE(EnableInterruptsPseudoOpcode)
/* Various 1-byte no-ops. */
CASE(JSOP_NOP)
CASE(JSOP_NOP_DESTRUCTURING)
CASE(JSOP_UNUSED192)
CASE(JSOP_UNUSED210)
CASE(JSOP_UNUSED211)
CASE(JSOP_UNUSED220)
@ -3566,18 +3566,6 @@ CASE(JSOP_TOASYNC)
}
END_CASE(JSOP_TOASYNC)
CASE(JSOP_TOASYNCGEN)
{
ReservedRooted<JSFunction*> unwrapped(&rootFunction0,
&REGS.sp[-1].toObject().as<JSFunction>());
JSObject* wrapped = WrapAsyncGenerator(cx, unwrapped);
if (!wrapped)
goto error;
REGS.sp[-1].setObject(*wrapped);
}
END_CASE(JSOP_TOASYNCGEN)
CASE(JSOP_SETFUNNAME)
{
MOZ_ASSERT(REGS.stackDepth() >= 2);

Просмотреть файл

@ -1967,15 +1967,7 @@
* Stack: this => this
*/ \
macro(JSOP_CHECKTHISREINIT,191,"checkthisreinit",NULL,1, 1, 1, JOF_BYTE) \
/*
* Pops the top of stack value as 'unwrapped', converts it to async
* generator 'wrapped', and pushes 'wrapped' back on the stack.
* Category: Statements
* Type: Generator
* Operands:
* Stack: unwrapped => wrapped
*/ \
macro(JSOP_TOASYNCGEN, 192, "toasyncgen", NULL, 1, 1, 1, JOF_BYTE) \
macro(JSOP_UNUSED192, 192,"unused192", NULL, 1, 0, 0, JOF_BYTE) \
\
/*
* Pops the top two values on the stack as 'propval' and 'obj', pushes