Implement asynchronous iterators (ES2018).
This commit is contained in:
parent
041acd156d
commit
84d4cb2e76
|
@ -779,7 +779,7 @@ struct JSClass {
|
|||
// application.
|
||||
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT \
|
||||
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 40)
|
||||
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 45)
|
||||
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
|
||||
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
|
||||
#define JSCLASS_GLOBAL_FLAGS \
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
/* 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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -44,6 +44,8 @@ class PromiseObject : public NativeObject
|
|||
static PromiseObject* create(JSContext* cx, HandleObject executor,
|
||||
HandleObject proto = nullptr, bool needsWrapping = false);
|
||||
|
||||
static PromiseObject* createSkippingExecutor(JSContext* cx);
|
||||
|
||||
static JSObject* unforgeableResolve(JSContext* cx, HandleValue value);
|
||||
static JSObject* unforgeableReject(JSContext* cx, HandleValue value);
|
||||
|
||||
|
@ -149,6 +151,26 @@ 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);
|
||||
|
||||
bool
|
||||
AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind);
|
||||
|
||||
/**
|
||||
* A PromiseTask represents a task that can be dispatched to a helper thread
|
||||
* (via StartPromiseTask), executed (by implementing PromiseTask::execute()),
|
||||
|
|
|
@ -2800,11 +2800,11 @@ ASTSerializer::generatorExpression(ParseNode* pn, MutableHandleValue dst)
|
|||
|
||||
LOCAL_ASSERT(next->isKind(PNK_SEMI) &&
|
||||
next->pn_kid->isKind(PNK_YIELD) &&
|
||||
next->pn_kid->pn_left);
|
||||
next->pn_kid->pn_kid);
|
||||
|
||||
RootedValue body(cx);
|
||||
|
||||
return expression(next->pn_kid->pn_left, &body) &&
|
||||
return expression(next->pn_kid->pn_kid, &body) &&
|
||||
builder.generatorExpression(body, blocks, filter, isLegacy, &pn->pn_pos, dst);
|
||||
}
|
||||
|
||||
|
@ -3146,7 +3146,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
|||
|
||||
case PNK_YIELD_STAR:
|
||||
{
|
||||
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
|
||||
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
|
||||
|
||||
RootedValue arg(cx);
|
||||
return expression(pn->pn_left, &arg) &&
|
||||
|
@ -3155,10 +3155,10 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
|||
|
||||
case PNK_YIELD:
|
||||
{
|
||||
MOZ_ASSERT_IF(pn->pn_left, pn->pn_pos.encloses(pn->pn_left->pn_pos));
|
||||
MOZ_ASSERT_IF(pn->pn_kid, pn->pn_pos.encloses(pn->pn_kid->pn_pos));
|
||||
|
||||
RootedValue arg(cx);
|
||||
return optExpression(pn->pn_left, &arg) &&
|
||||
return optExpression(pn->pn_kid, &arg) &&
|
||||
builder.yieldExpression(arg, NotDelegating, &pn->pn_pos, dst);
|
||||
}
|
||||
|
||||
|
@ -3422,10 +3422,10 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
|
|||
RootedFunction func(cx, pn->pn_funbox->function());
|
||||
|
||||
GeneratorStyle generatorStyle =
|
||||
pn->pn_funbox->isGenerator()
|
||||
? (pn->pn_funbox->isLegacyGenerator()
|
||||
? GeneratorStyle::Legacy
|
||||
: GeneratorStyle::ES6)
|
||||
pn->pn_funbox->isStarGenerator()
|
||||
? GeneratorStyle::ES6
|
||||
: pn->pn_funbox->isLegacyGenerator()
|
||||
? GeneratorStyle::Legacy
|
||||
: GeneratorStyle::None;
|
||||
|
||||
bool isAsync = pn->pn_funbox->isAsync();
|
||||
|
@ -3480,7 +3480,7 @@ ASTSerializer::functionArgsAndBody(ParseNode* pn, NodeVector& args, NodeVector&
|
|||
ParseNode* pnstart = pnbody->pn_head;
|
||||
|
||||
// Skip over initial yield in generator.
|
||||
if (pnstart && pnstart->isKind(PNK_YIELD)) {
|
||||
if (pnstart && pnstart->isKind(PNK_INITIALYIELD)) {
|
||||
MOZ_ASSERT(pnstart->getOp() == JSOP_INITIALYIELD);
|
||||
pnstart = pnstart->pn_next;
|
||||
}
|
||||
|
|
|
@ -110,8 +110,8 @@ resumption value has one of the following forms:
|
|||
the `new` expression returns the frame's `this` value. Similarly, if
|
||||
the function is the constructor for a subclass, then a non-object
|
||||
value may result in a TypeError.
|
||||
If the frame is a generator or async function, then <i>value</i> must
|
||||
conform to the iterator protocol: it must be a non-proxy object of the form
|
||||
If the frame is a generator function, then <i>value</i> must conform to the
|
||||
iterator protocol: it must be a non-proxy object of the form
|
||||
<code>{ done: <i>boolean</i>, value: <i>v</i> }</code>, where
|
||||
both `done` and `value` are ordinary properties.
|
||||
|
||||
|
|
|
@ -725,6 +725,19 @@ frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fu
|
|||
{
|
||||
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
|
||||
|
||||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
|
||||
TraceLogger_ParserCompileFunction);
|
||||
return compiler.compileStandaloneFunction(fun, NotGenerator, AsyncFunction, parameterListEnd);
|
||||
}
|
||||
|
||||
bool
|
||||
frontend::CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
Maybe<uint32_t> parameterListEnd)
|
||||
{
|
||||
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
|
||||
|
||||
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
|
||||
TraceLogger_ParserCompileFunction);
|
||||
return compiler.compileStandaloneFunction(fun, StarGenerator, AsyncFunction, parameterListEnd);
|
||||
|
|
|
@ -84,6 +84,12 @@ CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
|
|||
JS::SourceBufferHolder& srcBuf,
|
||||
mozilla::Maybe<uint32_t> parameterListEnd);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileStandaloneAsyncGenerator(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
JS::SourceBufferHolder& srcBuf,
|
||||
mozilla::Maybe<uint32_t> parameterListEnd);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
|
||||
const ReadOnlyCompileOptions& options,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,6 +10,7 @@
|
|||
#define frontend_BytecodeEmitter_h
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jsiter.h"
|
||||
#include "jsopcode.h"
|
||||
#include "jsscript.h"
|
||||
|
||||
|
@ -98,15 +99,15 @@ struct CGScopeNoteList {
|
|||
void finish(ScopeNoteArray* array, uint32_t prologueLength);
|
||||
};
|
||||
|
||||
struct CGYieldOffsetList {
|
||||
struct CGYieldAndAwaitOffsetList {
|
||||
Vector<uint32_t> list;
|
||||
uint32_t numYields;
|
||||
uint32_t numAwaits;
|
||||
explicit CGYieldOffsetList(ExclusiveContext* cx) : list(cx), numYields(0), numAwaits(0) {}
|
||||
explicit CGYieldAndAwaitOffsetList(ExclusiveContext* cx) : list(cx), numYields(0), numAwaits(0) {}
|
||||
|
||||
MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); }
|
||||
size_t length() const { return list.length(); }
|
||||
void finish(YieldOffsetArray& array, uint32_t prologueLength);
|
||||
void finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength);
|
||||
};
|
||||
|
||||
static size_t MaxBytecodeLength = INT32_MAX;
|
||||
|
@ -227,9 +228,23 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
|
||||
EmitterScope* varEmitterScope;
|
||||
NestableControl* innermostNestableControl;
|
||||
EmitterScope* innermostEmitterScope;
|
||||
EmitterScope* innermostEmitterScope_;
|
||||
TDZCheckCache* innermostTDZCheckCache;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool unstableEmitterScope;
|
||||
|
||||
friend class AutoCheckUnstableEmitterScope;
|
||||
#endif
|
||||
|
||||
EmitterScope* innermostEmitterScope() const {
|
||||
MOZ_ASSERT(!unstableEmitterScope);
|
||||
return innermostEmitterScopeNoCheck();
|
||||
}
|
||||
EmitterScope* innermostEmitterScopeNoCheck() const {
|
||||
return innermostEmitterScope_;
|
||||
}
|
||||
|
||||
CGConstList constList; /* constants to be included with the script */
|
||||
CGObjectList objectList; /* list of emitted objects */
|
||||
CGScopeList scopeList; /* list of emitted scopes */
|
||||
|
@ -237,10 +252,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
CGScopeNoteList scopeNoteList; /* list of emitted block scope notes */
|
||||
|
||||
/*
|
||||
* For each yield op, map the yield index (stored as bytecode operand) to
|
||||
* the offset of the next op.
|
||||
* For each yield or await op, map the yield and await index (stored as
|
||||
* bytecode operand) to the offset of the next op.
|
||||
*/
|
||||
CGYieldOffsetList yieldOffsetList;
|
||||
CGYieldAndAwaitOffsetList yieldAndAwaitOffsetList;
|
||||
|
||||
uint16_t typesetCount; /* Number of JOF_TYPESET opcodes generated */
|
||||
|
||||
|
@ -318,7 +333,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
EmitterScope* source);
|
||||
|
||||
mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(JSAtom* name) {
|
||||
return locationOfNameBoundInFunctionScope(name, innermostEmitterScope);
|
||||
return locationOfNameBoundInFunctionScope(name, innermostEmitterScope());
|
||||
}
|
||||
|
||||
void setVarEmitterScope(EmitterScope* emitterScope) {
|
||||
|
@ -606,17 +621,29 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool emitPrepareIteratorResult();
|
||||
MOZ_MUST_USE bool emitFinishIteratorResult(bool done);
|
||||
MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
|
||||
MOZ_MUST_USE bool emitToIteratorResult(bool done);
|
||||
|
||||
MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() {
|
||||
return emitGetDotGeneratorInScope(*innermostEmitterScope());
|
||||
}
|
||||
MOZ_MUST_USE bool emitGetDotGeneratorInScope(EmitterScope& currentScope);
|
||||
|
||||
MOZ_MUST_USE bool emitInitialYield(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitYield(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitYieldOp(JSOp op);
|
||||
MOZ_MUST_USE bool emitYieldStar(ParseNode* iter, ParseNode* gen);
|
||||
|
||||
MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
|
||||
MOZ_MUST_USE bool emitAwaitInInnermostScope() {
|
||||
return emitAwaitInScope(*innermostEmitterScope());
|
||||
}
|
||||
MOZ_MUST_USE bool emitAwaitInInnermostScope(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope);
|
||||
MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
|
||||
MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op);
|
||||
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);
|
||||
MOZ_MUST_USE bool emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isArrow,
|
||||
bool isStarGenerator);
|
||||
|
||||
MOZ_MUST_USE bool emitComputedPropertyName(ParseNode* computedPropName);
|
||||
|
||||
|
@ -703,11 +730,22 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
// It will replace that stack value with the corresponding iterator
|
||||
MOZ_MUST_USE bool emitIterator();
|
||||
|
||||
MOZ_MUST_USE bool emitAsyncIterator();
|
||||
|
||||
// Pops iterator from the top of the stack. Pushes the result of |.next()|
|
||||
// onto the stack.
|
||||
MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, bool allowSelfHosted = false);
|
||||
MOZ_MUST_USE bool emitIteratorClose(CompletionKind completionKind = CompletionKind::Normal,
|
||||
bool allowSelfHosted = false);
|
||||
MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, IteratorKind kind = IteratorKind::Sync,
|
||||
bool allowSelfHosted = false);
|
||||
MOZ_MUST_USE bool emitIteratorCloseInScope(EmitterScope& currentScope,
|
||||
IteratorKind iterKind = IteratorKind::Sync,
|
||||
CompletionKind completionKind = CompletionKind::Normal,
|
||||
bool allowSelfHosted = false);
|
||||
MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(IteratorKind iterKind = IteratorKind::Sync,
|
||||
CompletionKind completionKind = CompletionKind::Normal,
|
||||
bool allowSelfHosted = false) {
|
||||
return emitIteratorCloseInScope(*innermostEmitterScope(), iterKind, completionKind,
|
||||
allowSelfHosted);
|
||||
}
|
||||
|
||||
template <typename InnerEmitter>
|
||||
MOZ_MUST_USE bool wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth,
|
||||
|
@ -805,6 +843,31 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
|||
MOZ_MUST_USE bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
|
||||
};
|
||||
|
||||
class MOZ_RAII AutoCheckUnstableEmitterScope {
|
||||
#ifdef DEBUG
|
||||
bool prev_;
|
||||
BytecodeEmitter* bce_;
|
||||
#endif
|
||||
|
||||
public:
|
||||
AutoCheckUnstableEmitterScope() = delete;
|
||||
explicit AutoCheckUnstableEmitterScope(BytecodeEmitter* bce)
|
||||
#ifdef DEBUG
|
||||
: bce_(bce)
|
||||
#endif
|
||||
{
|
||||
#ifdef DEBUG
|
||||
prev_ = bce_->unstableEmitterScope;
|
||||
bce_->unstableEmitterScope = true;
|
||||
#endif
|
||||
}
|
||||
~AutoCheckUnstableEmitterScope() {
|
||||
#ifdef DEBUG
|
||||
bce_->unstableEmitterScope = prev_;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace frontend */
|
||||
} /* namespace js */
|
||||
|
||||
|
|
|
@ -117,9 +117,10 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
|
|||
|
||||
// These two aren't statements in the spec, but we sometimes insert them
|
||||
// in statement lists anyway.
|
||||
case PNK_INITIALYIELD:
|
||||
case PNK_YIELD_STAR:
|
||||
case PNK_YIELD:
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
*result = false;
|
||||
return true;
|
||||
|
||||
|
@ -1775,21 +1776,23 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
|
|||
case PNK_GENEXP:
|
||||
return FoldList(cx, pn, parser, inGenexpLambda);
|
||||
|
||||
case PNK_INITIALYIELD:
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
|
||||
pn->pn_kid->pn_left->isKind(PNK_NAME) &&
|
||||
pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
|
||||
return true;
|
||||
|
||||
case PNK_YIELD_STAR:
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME));
|
||||
return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
|
||||
|
||||
case PNK_YIELD:
|
||||
case PNK_AWAIT:
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) ||
|
||||
(pn->pn_right->isKind(PNK_ASSIGN) &&
|
||||
pn->pn_right->pn_left->isKind(PNK_NAME) &&
|
||||
pn->pn_right->pn_right->isKind(PNK_GENERATOR)));
|
||||
if (!pn->pn_left)
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
if (!pn->pn_kid)
|
||||
return true;
|
||||
return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
|
||||
return Fold(cx, &pn->pn_kid, parser, inGenexpLambda);
|
||||
|
||||
case PNK_RETURN:
|
||||
return FoldReturn(cx, pn, parser, inGenexpLambda);
|
||||
|
|
|
@ -440,20 +440,24 @@ class FullParseHandler
|
|||
return true;
|
||||
}
|
||||
|
||||
ParseNode* newYieldExpression(uint32_t begin, ParseNode* value, ParseNode* gen,
|
||||
JSOp op = JSOP_YIELD) {
|
||||
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
|
||||
return new_<BinaryNode>(PNK_YIELD, op, pos, value, gen);
|
||||
ParseNode* newInitialYieldExpression(uint32_t begin, ParseNode* gen) {
|
||||
TokenPos pos(begin, begin + 1);
|
||||
return new_<UnaryNode>(PNK_INITIALYIELD, JSOP_INITIALYIELD, pos, gen);
|
||||
}
|
||||
|
||||
ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
|
||||
ParseNode* newYieldExpression(uint32_t begin, ParseNode* value) {
|
||||
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
|
||||
return new_<UnaryNode>(PNK_YIELD, JSOP_YIELD, pos, value);
|
||||
}
|
||||
|
||||
ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value) {
|
||||
TokenPos pos(begin, value->pn_pos.end);
|
||||
return new_<BinaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen);
|
||||
return new_<UnaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value);
|
||||
}
|
||||
|
||||
ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
|
||||
ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value) {
|
||||
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
|
||||
return new_<BinaryNode>(PNK_AWAIT, JSOP_YIELD, pos, value, gen);
|
||||
return new_<UnaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value);
|
||||
}
|
||||
|
||||
// Statements
|
||||
|
@ -506,8 +510,7 @@ class FullParseHandler
|
|||
if (!genInit)
|
||||
return false;
|
||||
|
||||
ParseNode* initialYield = newYieldExpression(yieldPos.begin, nullptr, genInit,
|
||||
JSOP_INITIALYIELD);
|
||||
ParseNode* initialYield = newInitialYieldExpression(yieldPos.begin, genInit);
|
||||
if (!initialYield)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -501,24 +501,25 @@ class NameResolver
|
|||
return false;
|
||||
break;
|
||||
|
||||
case PNK_INITIALYIELD:
|
||||
MOZ_ASSERT(cur->pn_kid->isKind(PNK_ASSIGN) &&
|
||||
cur->pn_kid->pn_left->isKind(PNK_NAME) &&
|
||||
cur->pn_kid->pn_right->isKind(PNK_GENERATOR));
|
||||
break;
|
||||
|
||||
case PNK_YIELD_STAR:
|
||||
MOZ_ASSERT(cur->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(cur->pn_right->isKind(PNK_NAME));
|
||||
if (!resolve(cur->pn_left, prefix))
|
||||
MOZ_ASSERT(cur->isArity(PN_UNARY));
|
||||
if (!resolve(cur->pn_kid, prefix))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case PNK_YIELD:
|
||||
case PNK_AWAIT:
|
||||
MOZ_ASSERT(cur->isArity(PN_BINARY));
|
||||
if (cur->pn_left) {
|
||||
if (!resolve(cur->pn_left, prefix))
|
||||
MOZ_ASSERT(cur->isArity(PN_UNARY));
|
||||
if (cur->pn_kid) {
|
||||
if (!resolve(cur->pn_kid, prefix))
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(cur->pn_right->isKind(PNK_NAME) ||
|
||||
(cur->pn_right->isKind(PNK_ASSIGN) &&
|
||||
cur->pn_right->pn_left->isKind(PNK_NAME) &&
|
||||
cur->pn_right->pn_right->isKind(PNK_GENERATOR)));
|
||||
break;
|
||||
|
||||
case PNK_RETURN:
|
||||
|
|
|
@ -286,22 +286,24 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
|
|||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
// The left half is the expression being yielded. The right half is
|
||||
// internal goop: a name reference to the invisible '.generator' local
|
||||
// variable, or an assignment of a PNK_GENERATOR node to the '.generator'
|
||||
// local, for a synthesized, prepended initial yield. Yum!
|
||||
// The child is an assignment of a PNK_GENERATOR node to the
|
||||
// '.generator' local, for a synthesized, prepended initial yield.
|
||||
case PNK_INITIALYIELD: {
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
MOZ_ASSERT(pn->pn_kid->isKind(PNK_ASSIGN) &&
|
||||
pn->pn_kid->pn_left->isKind(PNK_NAME) &&
|
||||
pn->pn_kid->pn_right->isKind(PNK_GENERATOR));
|
||||
stack->push(pn->pn_kid);
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
// The child is the expression being yielded.
|
||||
case PNK_YIELD_STAR:
|
||||
case PNK_YIELD:
|
||||
case PNK_AWAIT: {
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
MOZ_ASSERT(pn->pn_right);
|
||||
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) ||
|
||||
(pn->pn_right->isKind(PNK_ASSIGN) &&
|
||||
pn->pn_right->pn_left->isKind(PNK_NAME) &&
|
||||
pn->pn_right->pn_right->isKind(PNK_GENERATOR)));
|
||||
if (pn->pn_left)
|
||||
stack->push(pn->pn_left);
|
||||
stack->push(pn->pn_right);
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
if (pn->pn_kid)
|
||||
stack->push(pn->pn_kid);
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ class ObjectBox;
|
|||
F(THROW) \
|
||||
F(DEBUGGER) \
|
||||
F(GENERATOR) \
|
||||
F(INITIALYIELD) \
|
||||
F(YIELD) \
|
||||
F(YIELD_STAR) \
|
||||
F(GENEXP) \
|
||||
|
@ -418,8 +419,9 @@ IsTypeofKind(ParseNodeKind kind)
|
|||
* PNK_LEXICALSCOPE scope pn_u.scope.bindings: scope bindings
|
||||
* pn_u.scope.body: scope body
|
||||
* PNK_GENERATOR nullary
|
||||
* PNK_YIELD, binary pn_left: expr or null; pn_right: generator object
|
||||
* PNK_YIELD_STAR
|
||||
* PNK_INITIALYIELD unary pn_kid: generator object
|
||||
* PNK_YIELD, unary pn_kid: expr or null
|
||||
* PNK_YIELD_STAR,
|
||||
* PNK_ARRAYCOMP list pn_count: 1
|
||||
* pn_head: list of 1 element, which is block
|
||||
* enclosing for loop(s) and optionally
|
||||
|
|
|
@ -2474,10 +2474,8 @@ Parser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /* = false
|
|||
}
|
||||
|
||||
static YieldHandling
|
||||
GetYieldHandling(GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
|
||||
GetYieldHandling(GeneratorKind generatorKind)
|
||||
{
|
||||
if (asyncKind == AsyncFunction)
|
||||
return YieldIsName;
|
||||
if (generatorKind == NotGenerator)
|
||||
return YieldIsName;
|
||||
return YieldIsKeyword;
|
||||
|
@ -2541,7 +2539,7 @@ Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
|
|||
return null();
|
||||
funpc.setIsStandaloneFunctionBody();
|
||||
|
||||
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
|
||||
YieldHandling yieldHandling = GetYieldHandling(generatorKind);
|
||||
AutoAwaitIsKeyword<FullParseHandler> awaitIsKeyword(this, asyncKind == AsyncFunction);
|
||||
if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement,
|
||||
parameterListEnd, /* isStandaloneFunction = */ true))
|
||||
|
@ -2699,7 +2697,7 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
|
|||
|
||||
switch (pc->generatorKind()) {
|
||||
case NotGenerator:
|
||||
MOZ_ASSERT(pc->lastYieldOffset == startYieldOffset);
|
||||
MOZ_ASSERT_IF(!pc->isAsync(), pc->lastYieldOffset == startYieldOffset);
|
||||
break;
|
||||
|
||||
case LegacyGenerator:
|
||||
|
@ -2715,12 +2713,12 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
|
|||
break;
|
||||
|
||||
case StarGenerator:
|
||||
MOZ_ASSERT_IF(!pc->isAsync(), kind != Arrow);
|
||||
MOZ_ASSERT_IF(!pc->isAsync(), type == StatementListBody);
|
||||
MOZ_ASSERT(kind != Arrow);
|
||||
MOZ_ASSERT(type == StatementListBody);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pc->isGenerator()) {
|
||||
if (pc->needsDotGeneratorName()) {
|
||||
MOZ_ASSERT_IF(!pc->isAsync(), type == StatementListBody);
|
||||
if (!declareDotGeneratorName())
|
||||
return null();
|
||||
|
@ -2761,9 +2759,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
|
|||
#endif
|
||||
switch (kind) {
|
||||
case Expression:
|
||||
flags = (generatorKind == NotGenerator
|
||||
flags = (generatorKind == NotGenerator && asyncKind == SyncFunction
|
||||
? JSFunction::INTERPRETED_LAMBDA
|
||||
: JSFunction::INTERPRETED_LAMBDA_GENERATOR);
|
||||
: JSFunction::INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC);
|
||||
break;
|
||||
case Arrow:
|
||||
flags = JSFunction::INTERPRETED_LAMBDA_ARROW;
|
||||
|
@ -2771,9 +2769,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
|
|||
break;
|
||||
case Method:
|
||||
MOZ_ASSERT(generatorKind == NotGenerator || generatorKind == StarGenerator);
|
||||
flags = (generatorKind == NotGenerator
|
||||
flags = (generatorKind == NotGenerator && asyncKind == SyncFunction
|
||||
? JSFunction::INTERPRETED_METHOD
|
||||
: JSFunction::INTERPRETED_METHOD_GENERATOR);
|
||||
: JSFunction::INTERPRETED_METHOD_GENERATOR_OR_ASYNC);
|
||||
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
|
||||
break;
|
||||
case ClassConstructor:
|
||||
|
@ -2799,9 +2797,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
|
|||
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
|
||||
}
|
||||
#endif
|
||||
flags = (generatorKind == NotGenerator
|
||||
flags = (generatorKind == NotGenerator && asyncKind == SyncFunction
|
||||
? JSFunction::INTERPRETED_NORMAL
|
||||
: JSFunction::INTERPRETED_GENERATOR);
|
||||
: JSFunction::INTERPRETED_GENERATOR_OR_ASYNC);
|
||||
}
|
||||
|
||||
// We store the async wrapper in a slot for later access.
|
||||
|
@ -3324,7 +3322,6 @@ Parser<ParseHandler>::functionDefinition(uint32_t toStringStart, Node pn, InHand
|
|||
bool tryAnnexB /* = false */)
|
||||
{
|
||||
MOZ_ASSERT_IF(kind == Statement, funName);
|
||||
MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator);
|
||||
|
||||
// When fully parsing a LazyScript, we do not fully reparse its inner
|
||||
// functions, which are also lazy. Instead, their free variables and
|
||||
|
@ -3336,7 +3333,7 @@ Parser<ParseHandler>::functionDefinition(uint32_t toStringStart, Node pn, InHand
|
|||
}
|
||||
|
||||
RootedObject proto(context);
|
||||
if (generatorKind == StarGenerator) {
|
||||
if (generatorKind == StarGenerator || asyncKind == AsyncFunction) {
|
||||
// If we are off the main thread, the generator meta-objects have
|
||||
// already been created by js::StartOffThreadParseScript, so cx will not
|
||||
// be necessary.
|
||||
|
@ -3408,7 +3405,7 @@ Parser<FullParseHandler>::trySyntaxParseInnerFunction(ParseNode* pn, HandleFunct
|
|||
// parse to avoid the overhead of a lazy syntax-only parse. Although
|
||||
// the prediction may be incorrect, IIFEs are common enough that it
|
||||
// pays off for lots of code.
|
||||
if (pn->isLikelyIIFE() && generatorKind == NotGenerator)
|
||||
if (pn->isLikelyIIFE() && generatorKind == NotGenerator && asyncKind == SyncFunction)
|
||||
break;
|
||||
|
||||
Parser<SyntaxParseHandler>* parser = handler.syntaxParser;
|
||||
|
@ -3584,7 +3581,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
|
|||
if (!tokenStream.peekTokenPos(&pn->pn_pos, modifier))
|
||||
return null();
|
||||
|
||||
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
|
||||
YieldHandling yieldHandling = GetYieldHandling(generatorKind);
|
||||
FunctionSyntaxKind syntaxKind = Statement;
|
||||
if (fun->isClassConstructor())
|
||||
syntaxKind = ClassConstructor;
|
||||
|
@ -3665,7 +3662,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
|
|||
return false;
|
||||
uint32_t openedPos = 0;
|
||||
if (tt != TOK_LC) {
|
||||
if ((funbox->isStarGenerator() && !funbox->isAsync()) || kind == Method ||
|
||||
if (funbox->isStarGenerator() || kind == Method ||
|
||||
kind == GetterNoExpressionClosure || kind == SetterNoExpressionClosure ||
|
||||
IsConstructorKind(kind)) {
|
||||
error(JSMSG_CURLY_BEFORE_BODY);
|
||||
|
@ -3695,7 +3692,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
|
|||
// whether the arrow function is enclosed in a generator function or not.
|
||||
// Whereas the |yield| in the function body is always parsed as a name.
|
||||
// The same goes when parsing |await| in arrow functions.
|
||||
YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind(), pc->asyncKind());
|
||||
YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind());
|
||||
Node body;
|
||||
{
|
||||
AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, funbox->isAsync());
|
||||
|
@ -3786,12 +3783,8 @@ Parser<ParseHandler>::functionStmt(uint32_t toStringStart, YieldHandling yieldHa
|
|||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
|
||||
GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
|
||||
GeneratorKind generatorKind = NotGenerator;
|
||||
if (tt == TOK_MUL) {
|
||||
if (asyncKind != SyncFunction) {
|
||||
error(JSMSG_ASYNC_GENERATOR);
|
||||
return null();
|
||||
}
|
||||
generatorKind = StarGenerator;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
|
@ -3817,7 +3810,7 @@ Parser<ParseHandler>::functionStmt(uint32_t toStringStart, YieldHandling yieldHa
|
|||
MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
|
||||
MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
|
||||
|
||||
if (!pc->sc()->strict() && generatorKind == NotGenerator) {
|
||||
if (!pc->sc()->strict() && generatorKind == NotGenerator && asyncKind == SyncFunction) {
|
||||
// In sloppy mode, try Annex B.3.3 semantics. If making an
|
||||
// additional 'var' binding of the same name does not throw an
|
||||
// early error, do so. This 'var' binding would be assigned
|
||||
|
@ -3841,7 +3834,7 @@ Parser<ParseHandler>::functionStmt(uint32_t toStringStart, YieldHandling yieldHa
|
|||
if (!pn)
|
||||
return null();
|
||||
|
||||
YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
|
||||
YieldHandling newYieldHandling = GetYieldHandling(generatorKind);
|
||||
return functionDefinition(toStringStart, pn, InAllowed, newYieldHandling,
|
||||
name, Statement, generatorKind, asyncKind, tryAnnexB);
|
||||
}
|
||||
|
@ -3854,22 +3847,18 @@ Parser<ParseHandler>::functionExpr(uint32_t toStringStart, InvokedPrediction inv
|
|||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
|
||||
|
||||
AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, asyncKind == AsyncFunction);
|
||||
GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
|
||||
GeneratorKind generatorKind = NotGenerator;
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
|
||||
if (tt == TOK_MUL) {
|
||||
if (asyncKind != SyncFunction) {
|
||||
error(JSMSG_ASYNC_GENERATOR);
|
||||
return null();
|
||||
}
|
||||
generatorKind = StarGenerator;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
}
|
||||
|
||||
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
|
||||
YieldHandling yieldHandling = GetYieldHandling(generatorKind);
|
||||
|
||||
RootedPropertyName name(context);
|
||||
if (TokenKindIsPossibleIdentifier(tt)) {
|
||||
|
@ -5971,6 +5960,7 @@ Parser<ParseHandler>::matchInOrOf(bool* isForInp, bool* isForOfp)
|
|||
template <class ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
|
||||
IteratorKind iterKind,
|
||||
ParseNodeKind* forHeadKind,
|
||||
Node* forInitialPart,
|
||||
Maybe<ParseContext::Scope>& forLoopLexicalScope,
|
||||
|
@ -6061,6 +6051,11 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
|
|||
if (!matchInOrOf(&isForIn, &isForOf))
|
||||
return false;
|
||||
|
||||
if (iterKind == IteratorKind::Async && !isForOf) {
|
||||
error(JSMSG_FOR_AWAIT_NOT_OF);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we don't encounter 'in'/'of', we have a for(;;) loop. We've handled
|
||||
// the init expression; the caller handles the rest. Allow the Operand
|
||||
// modifier when regetting: Operand must be used to examine the ';' in
|
||||
|
@ -6134,6 +6129,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
|
|||
ParseContext::Statement stmt(pc, StatementKind::ForLoop);
|
||||
|
||||
bool isForEach = false;
|
||||
IteratorKind iterKind = IteratorKind::Sync;
|
||||
unsigned iflags = 0;
|
||||
|
||||
if (allowsForEachIn()) {
|
||||
|
@ -6148,6 +6144,17 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
|
|||
}
|
||||
}
|
||||
|
||||
if (pc->isAsync()) {
|
||||
bool matched;
|
||||
if (!tokenStream.matchToken(&matched, TOK_AWAIT))
|
||||
return null();
|
||||
|
||||
if (matched) {
|
||||
iflags |= JSITER_FORAWAITOF;
|
||||
iterKind = IteratorKind::Async;
|
||||
}
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
|
||||
|
||||
// PNK_FORHEAD, PNK_FORIN, or PNK_FOROF depending on the loop type.
|
||||
|
@ -6185,7 +6192,7 @@ Parser<ParseHandler>::forStatement(YieldHandling yieldHandling)
|
|||
//
|
||||
// In either case the subsequent token can be consistently accessed using
|
||||
// TokenStream::None semantics.
|
||||
if (!forHeadStart(yieldHandling, &headKind, &startNode, forLoopLexicalScope,
|
||||
if (!forHeadStart(yieldHandling, iterKind, &headKind, &startNode, forLoopLexicalScope,
|
||||
&iteratedExpr))
|
||||
{
|
||||
return null();
|
||||
|
@ -6549,29 +6556,6 @@ Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
|
|||
return pn;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::newYieldExpression(uint32_t begin, typename ParseHandler::Node expr,
|
||||
bool isYieldStar)
|
||||
{
|
||||
Node generator = newDotGeneratorName();
|
||||
if (!generator)
|
||||
return null();
|
||||
if (isYieldStar)
|
||||
return handler.newYieldStarExpression(begin, expr, generator);
|
||||
return handler.newYieldExpression(begin, expr, generator);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::newAwaitExpression(uint32_t begin, typename ParseHandler::Node expr)
|
||||
{
|
||||
Node generator = newDotGeneratorName();
|
||||
if (!generator)
|
||||
return null();
|
||||
return handler.newAwaitExpression(begin, expr, generator);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::yieldExpression(InHandling inHandling)
|
||||
|
@ -6620,7 +6604,9 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
|
|||
if (!exprNode)
|
||||
return null();
|
||||
}
|
||||
return newYieldExpression(begin, exprNode, kind == PNK_YIELD_STAR);
|
||||
if (kind == PNK_YIELD_STAR)
|
||||
return handler.newYieldStarExpression(begin, exprNode);
|
||||
return handler.newYieldExpression(begin, exprNode);
|
||||
}
|
||||
|
||||
case NotGenerator:
|
||||
|
@ -6697,7 +6683,7 @@ Parser<ParseHandler>::yieldExpression(InHandling inHandling)
|
|||
return null();
|
||||
}
|
||||
|
||||
return newYieldExpression(begin, exprNode);
|
||||
return handler.newYieldExpression(begin, exprNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8187,7 +8173,6 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
|||
uint32_t toStringStart = pos().begin;
|
||||
tokenStream.ungetToken();
|
||||
|
||||
GeneratorKind generatorKind = NotGenerator;
|
||||
FunctionAsyncKind asyncKind = SyncFunction;
|
||||
|
||||
if (next == TOK_ASYNC) {
|
||||
|
@ -8200,7 +8185,6 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
|||
if (nextSameLine == TOK_ARROW) {
|
||||
tokenStream.ungetToken();
|
||||
} else {
|
||||
generatorKind = StarGenerator;
|
||||
asyncKind = AsyncFunction;
|
||||
}
|
||||
}
|
||||
|
@ -8210,7 +8194,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
|||
return null();
|
||||
|
||||
Node arrowFunc = functionDefinition(toStringStart, pn, inHandling, yieldHandling, nullptr,
|
||||
Arrow, generatorKind, asyncKind);
|
||||
Arrow, NotGenerator, asyncKind);
|
||||
if (!arrowFunc)
|
||||
return null();
|
||||
|
||||
|
@ -8454,7 +8438,7 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, TripledotHandling t
|
|||
if (!kid)
|
||||
return null();
|
||||
pc->lastAwaitOffset = begin;
|
||||
return newAwaitExpression(begin, kid);
|
||||
return handler.newAwaitExpression(begin, kid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8712,7 +8696,7 @@ Parser<ParseHandler>::comprehensionTail(GeneratorKind comprehensionKind)
|
|||
return handler.newArrayPush(begin, bodyExpr);
|
||||
|
||||
MOZ_ASSERT(comprehensionKind == StarGenerator);
|
||||
Node yieldExpr = newYieldExpression(begin, bodyExpr);
|
||||
Node yieldExpr = handler.newYieldExpression(begin, bodyExpr);
|
||||
if (!yieldExpr)
|
||||
return null();
|
||||
yieldExpr = handler.parenthesize(yieldExpr);
|
||||
|
@ -9494,11 +9478,6 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling,
|
|||
|
||||
bool isGenerator = false;
|
||||
bool isAsync = false;
|
||||
if (ltok == TOK_MUL) {
|
||||
isGenerator = true;
|
||||
if (!tokenStream.getToken(<ok))
|
||||
return null();
|
||||
}
|
||||
|
||||
if (ltok == TOK_ASYNC) {
|
||||
// AsyncMethod[Yield, Await]:
|
||||
|
@ -9526,9 +9505,10 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling,
|
|||
}
|
||||
}
|
||||
|
||||
if (isAsync && isGenerator) {
|
||||
error(JSMSG_ASYNC_GENERATOR);
|
||||
return null();
|
||||
if (ltok == TOK_MUL) {
|
||||
isGenerator = true;
|
||||
if (!tokenStream.getToken(<ok))
|
||||
return null();
|
||||
}
|
||||
|
||||
propAtom.set(nullptr);
|
||||
|
@ -9950,8 +9930,7 @@ Parser<ParseHandler>::methodDefinition(uint32_t toStringStart, PropertyType prop
|
|||
MOZ_CRASH("Parser: methodDefinition: unexpected property type");
|
||||
}
|
||||
|
||||
GeneratorKind generatorKind = (propType == PropertyType::GeneratorMethod ||
|
||||
propType == PropertyType::AsyncMethod)
|
||||
GeneratorKind generatorKind = propType == PropertyType::GeneratorMethod
|
||||
? StarGenerator
|
||||
: NotGenerator;
|
||||
|
||||
|
@ -9959,7 +9938,7 @@ Parser<ParseHandler>::methodDefinition(uint32_t toStringStart, PropertyType prop
|
|||
? AsyncFunction
|
||||
: SyncFunction;
|
||||
|
||||
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
|
||||
YieldHandling yieldHandling = GetYieldHandling(generatorKind);
|
||||
|
||||
Node pn = handler.newFunctionExpression();
|
||||
if (!pn)
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mozilla/Array.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
#include "jsiter.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
|
@ -496,10 +497,6 @@ class ParseContext : public Nestable<ParseContext>
|
|||
return sc_->isFunctionBox() ? sc_->asFunctionBox()->generatorKind() : NotGenerator;
|
||||
}
|
||||
|
||||
bool isGenerator() const {
|
||||
return generatorKind() != NotGenerator;
|
||||
}
|
||||
|
||||
bool isLegacyGenerator() const {
|
||||
return generatorKind() == LegacyGenerator;
|
||||
}
|
||||
|
@ -512,6 +509,10 @@ class ParseContext : public Nestable<ParseContext>
|
|||
return sc_->isFunctionBox() && sc_->asFunctionBox()->isAsync();
|
||||
}
|
||||
|
||||
bool needsDotGeneratorName() const {
|
||||
return isStarGenerator() || isLegacyGenerator() || isAsync();
|
||||
}
|
||||
|
||||
FunctionAsyncKind asyncKind() const {
|
||||
return isAsync() ? AsyncFunction : SyncFunction;
|
||||
}
|
||||
|
@ -818,7 +819,9 @@ class ParserBase : public StrictModeGetter
|
|||
// whether it's prohibited due to strictness, JS version, or occurrence
|
||||
// inside a star generator.
|
||||
bool yieldExpressionsSupported() {
|
||||
return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync();
|
||||
return (versionNumber() >= JSVERSION_1_7 && !pc->isAsync()) ||
|
||||
pc->isStarGenerator() ||
|
||||
pc->isLegacyGenerator();
|
||||
}
|
||||
|
||||
virtual bool strictMode() { return pc->sc()->strict(); }
|
||||
|
@ -1108,8 +1111,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
|
||||
inline Node newName(PropertyName* name);
|
||||
inline Node newName(PropertyName* name, TokenPos pos);
|
||||
inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
|
||||
inline Node newAwaitExpression(uint32_t begin, Node expr);
|
||||
|
||||
inline bool abortIfSyntaxParser();
|
||||
|
||||
|
@ -1196,6 +1197,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
|
|||
|
||||
Node forStatement(YieldHandling yieldHandling);
|
||||
bool forHeadStart(YieldHandling yieldHandling,
|
||||
IteratorKind iterKind,
|
||||
ParseNodeKind* forHeadKind,
|
||||
Node* forInitialPart,
|
||||
mozilla::Maybe<ParseContext::Scope>& forLetImpliedScope,
|
||||
|
|
|
@ -520,7 +520,9 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||
return hasExtensibleScope() ||
|
||||
needsHomeObject() ||
|
||||
isDerivedClassConstructor() ||
|
||||
isGenerator();
|
||||
isStarGenerator() ||
|
||||
isLegacyGenerator() ||
|
||||
isAsync();
|
||||
}
|
||||
|
||||
bool hasExtraBodyVarScope() const {
|
||||
|
@ -531,7 +533,7 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||
|
||||
bool needsExtraBodyVarEnvironmentRegardlessOfBindings() const {
|
||||
MOZ_ASSERT(hasParameterExprs);
|
||||
return hasExtensibleScope() || isGenerator();
|
||||
return hasExtensibleScope() || needsDotGeneratorName();
|
||||
}
|
||||
|
||||
bool isLikelyConstructorWrapper() const {
|
||||
|
@ -539,10 +541,21 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||
}
|
||||
|
||||
GeneratorKind generatorKind() const { return GeneratorKindFromBits(generatorKindBits_); }
|
||||
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 needsFinalYield() const {
|
||||
return isStarGenerator() || isLegacyGenerator() || isAsync();
|
||||
}
|
||||
bool needsDotGeneratorName() const {
|
||||
return isStarGenerator() || isLegacyGenerator() || isAsync();
|
||||
}
|
||||
|
||||
bool needsIteratorResult() const {
|
||||
return isStarGenerator();
|
||||
}
|
||||
|
||||
bool isAsync() const { return asyncKind() == AsyncFunction; }
|
||||
bool isArrow() const { return function()->isArrow(); }
|
||||
|
||||
|
@ -560,7 +573,7 @@ class FunctionBox : public ObjectBox, public SharedContext
|
|||
// A generator kind can be set at initialization, or when "yield" is
|
||||
// first seen. In both cases the transition can only happen from
|
||||
// NotGenerator.
|
||||
MOZ_ASSERT(!isGenerator());
|
||||
MOZ_ASSERT(!isStarGenerator() && !isLegacyGenerator());
|
||||
generatorKindBits_ = GeneratorKindAsBits(kind);
|
||||
}
|
||||
|
||||
|
@ -655,7 +668,11 @@ SharedContext::asModuleContext()
|
|||
inline bool
|
||||
SharedContext::allBindingsClosedOver()
|
||||
{
|
||||
return bindingsAccessedDynamically() || (isFunctionBox() && asFunctionBox()->isGenerator());
|
||||
return bindingsAccessedDynamically() ||
|
||||
(isFunctionBox() &&
|
||||
(asFunctionBox()->isStarGenerator() ||
|
||||
asFunctionBox()->isLegacyGenerator() ||
|
||||
asFunctionBox()->isAsync()));
|
||||
}
|
||||
|
||||
} // namespace frontend
|
||||
|
|
|
@ -301,9 +301,9 @@ class SyntaxParseHandler
|
|||
MOZ_MUST_USE bool addSpreadProperty(Node literal, uint32_t begin, Node inner) { return true; }
|
||||
MOZ_MUST_USE bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
|
||||
MOZ_MUST_USE bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; }
|
||||
Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
|
||||
Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
|
||||
Node newAwaitExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
|
||||
Node newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
Node newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
Node newAwaitExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
|
||||
// Statements
|
||||
|
||||
|
|
|
@ -9,28 +9,6 @@ async function f() {
|
|||
}
|
||||
`);
|
||||
|
||||
// To continue testing after uncaught exception, remember the exception and
|
||||
// return normal completeion.
|
||||
var currentFrame;
|
||||
var uncaughtException;
|
||||
dbg.uncaughtExceptionHook = function(e) {
|
||||
uncaughtException = e;
|
||||
return {
|
||||
return: currentFrame.eval("({ done: true, value: 'uncaught' })").return
|
||||
};
|
||||
};
|
||||
function testUncaughtException() {
|
||||
uncaughtException = undefined;
|
||||
var val = g.eval(`
|
||||
var val;
|
||||
f().then(v => { val = v });
|
||||
drainJobQueue();
|
||||
val;
|
||||
`);
|
||||
assertEq(val, "uncaught");
|
||||
assertEq(uncaughtException instanceof TypeError, true);
|
||||
}
|
||||
|
||||
// Just continue
|
||||
dbg.onExceptionUnwind = function(frame) {
|
||||
return undefined;
|
||||
|
@ -42,83 +20,10 @@ drainJobQueue();
|
|||
assertEq(exc instanceof ReferenceError, true);
|
||||
`);
|
||||
|
||||
// Should return object.
|
||||
// Return with resumption value.
|
||||
dbg.onExceptionUnwind = function(frame) {
|
||||
currentFrame = frame;
|
||||
return {
|
||||
return: "foo"
|
||||
};
|
||||
};
|
||||
testUncaughtException();
|
||||
|
||||
// The object should have `done` property and `value` property.
|
||||
dbg.onExceptionUnwind = function(frame) {
|
||||
currentFrame = frame;
|
||||
return {
|
||||
return: frame.eval("({})").return
|
||||
};
|
||||
};
|
||||
testUncaughtException();
|
||||
|
||||
// The object should have `done` property.
|
||||
dbg.onExceptionUnwind = function(frame) {
|
||||
currentFrame = frame;
|
||||
return {
|
||||
return: frame.eval("({ value: 10 })").return
|
||||
};
|
||||
};
|
||||
testUncaughtException();
|
||||
|
||||
// The object should have `value` property.
|
||||
dbg.onExceptionUnwind = function(frame) {
|
||||
currentFrame = frame;
|
||||
return {
|
||||
return: frame.eval("({ done: true })").return
|
||||
};
|
||||
};
|
||||
testUncaughtException();
|
||||
|
||||
// `done` property should be a boolean value.
|
||||
dbg.onExceptionUnwind = function(frame) {
|
||||
currentFrame = frame;
|
||||
return {
|
||||
return: frame.eval("({ done: 10, value: 10 })").return
|
||||
};
|
||||
};
|
||||
testUncaughtException();
|
||||
|
||||
// `done` property shouldn't be an accessor.
|
||||
dbg.onExceptionUnwind = function(frame) {
|
||||
currentFrame = frame;
|
||||
return {
|
||||
return: frame.eval("({ get done() { return true; }, value: 10 })").return
|
||||
};
|
||||
};
|
||||
testUncaughtException();
|
||||
|
||||
// `value` property shouldn't be an accessor.
|
||||
dbg.onExceptionUnwind = function(frame) {
|
||||
currentFrame = frame;
|
||||
return {
|
||||
return: frame.eval("({ done: true, get value() { return 10; } })").return
|
||||
};
|
||||
};
|
||||
testUncaughtException();
|
||||
|
||||
// The object shouldn't be a Proxy.
|
||||
dbg.onExceptionUnwind = function(frame) {
|
||||
currentFrame = frame;
|
||||
return {
|
||||
return: frame.eval("new Proxy({ done: true, value: 10 }, {})").return
|
||||
};
|
||||
};
|
||||
testUncaughtException();
|
||||
|
||||
// Correct resumption value.
|
||||
dbg.onExceptionUnwind = function(frame) {
|
||||
currentFrame = frame;
|
||||
return {
|
||||
return: frame.eval("({ done: true, value: 10 })").return
|
||||
return: 10
|
||||
};
|
||||
};
|
||||
var val = g.eval(`
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "jit/VMFunctions.h"
|
||||
#include "js/UniquePtr.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/AsyncIteration.h"
|
||||
#include "vm/EnvironmentObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
@ -43,7 +44,7 @@ using mozilla::AssertedCast;
|
|||
|
||||
BaselineCompiler::BaselineCompiler(JSContext* cx, TempAllocator& alloc, JSScript* script)
|
||||
: BaselineCompilerSpecific(cx, alloc, script),
|
||||
yieldOffsets_(cx),
|
||||
yieldAndAwaitOffsets_(cx),
|
||||
modifiesArguments_(false)
|
||||
{
|
||||
}
|
||||
|
@ -210,7 +211,7 @@ BaselineCompiler::compile()
|
|||
pcMappingIndexEntries.length(),
|
||||
pcEntries.length(),
|
||||
bytecodeTypeMapEntries,
|
||||
yieldOffsets_.length(),
|
||||
yieldAndAwaitOffsets_.length(),
|
||||
traceLoggerToggleOffsets_.length()),
|
||||
JS::DeletePolicy<BaselineScript>(cx->runtime()));
|
||||
if (!baselineScript) {
|
||||
|
@ -275,7 +276,7 @@ BaselineCompiler::compile()
|
|||
// searches for the sought entry when queries are in linear order.
|
||||
bytecodeMap[script->nTypeSets()] = 0;
|
||||
|
||||
baselineScript->copyYieldEntries(script, yieldOffsets_);
|
||||
baselineScript->copyYieldAndAwaitEntries(script, yieldAndAwaitOffsets_);
|
||||
|
||||
if (compileDebugInstrumentation_)
|
||||
baselineScript->setHasDebugInstrumentation();
|
||||
|
@ -3908,6 +3909,50 @@ BaselineCompiler::emit_JSOP_TOASYNC()
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef JSObject* (*ToAsyncGenFn)(JSContext*, HandleFunction);
|
||||
static const VMFunction ToAsyncGenInfo =
|
||||
FunctionInfo<ToAsyncGenFn>(js::WrapAsyncGenerator, "ToAsyncGen");
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_TOASYNCGEN()
|
||||
{
|
||||
frame.syncStack(0);
|
||||
masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
|
||||
|
||||
prepareVMCall();
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
if (!callVM(ToAsyncGenInfo))
|
||||
return false;
|
||||
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
|
||||
frame.pop();
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject);
|
||||
static const VMFunction ToAsyncIterInfo =
|
||||
FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_TOASYNCITER()
|
||||
{
|
||||
frame.syncStack(0);
|
||||
masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
|
||||
|
||||
prepareVMCall();
|
||||
pushArg(R0.scratchReg());
|
||||
|
||||
if (!callVM(ToAsyncIterInfo))
|
||||
return false;
|
||||
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
|
||||
frame.pop();
|
||||
frame.push(R0);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef bool (*ThrowObjectCoercibleFn)(JSContext*, HandleValue);
|
||||
static const VMFunction ThrowObjectCoercibleInfo =
|
||||
FunctionInfo<ThrowObjectCoercibleFn>(ThrowObjectCoercible, "ThrowObjectCoercible");
|
||||
|
@ -4174,27 +4219,28 @@ BaselineCompiler::emit_JSOP_GENERATOR()
|
|||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::addYieldOffset()
|
||||
BaselineCompiler::addYieldAndAwaitOffset()
|
||||
{
|
||||
MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD);
|
||||
MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD || *pc == JSOP_AWAIT);
|
||||
|
||||
uint32_t yieldIndex = GET_UINT24(pc);
|
||||
uint32_t yieldAndAwaitIndex = GET_UINT24(pc);
|
||||
|
||||
while (yieldIndex >= yieldOffsets_.length()) {
|
||||
if (!yieldOffsets_.append(0))
|
||||
while (yieldAndAwaitIndex >= yieldAndAwaitOffsets_.length()) {
|
||||
if (!yieldAndAwaitOffsets_.append(0))
|
||||
return false;
|
||||
}
|
||||
|
||||
static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH,
|
||||
"code below assumes INITIALYIELD and YIELD have same length");
|
||||
yieldOffsets_[yieldIndex] = script->pcToOffset(pc + JSOP_YIELD_LENGTH);
|
||||
static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH &&
|
||||
JSOP_INITIALYIELD_LENGTH == JSOP_AWAIT_LENGTH,
|
||||
"code below assumes INITIALYIELD and YIELD and AWAIT have same length");
|
||||
yieldAndAwaitOffsets_[yieldAndAwaitIndex] = script->pcToOffset(pc + JSOP_YIELD_LENGTH);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_INITIALYIELD()
|
||||
{
|
||||
if (!addYieldOffset())
|
||||
if (!addYieldAndAwaitOffset())
|
||||
return false;
|
||||
|
||||
frame.syncStack(0);
|
||||
|
@ -4204,7 +4250,8 @@ BaselineCompiler::emit_JSOP_INITIALYIELD()
|
|||
masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), genObj);
|
||||
|
||||
MOZ_ASSERT(GET_UINT24(pc) == 0);
|
||||
masm.storeValue(Int32Value(0), Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()));
|
||||
masm.storeValue(Int32Value(0),
|
||||
Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
|
||||
|
||||
Register envObj = R0.scratchReg();
|
||||
Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot());
|
||||
|
@ -4233,7 +4280,7 @@ static const VMFunction NormalSuspendInfo =
|
|||
bool
|
||||
BaselineCompiler::emit_JSOP_YIELD()
|
||||
{
|
||||
if (!addYieldOffset())
|
||||
if (!addYieldAndAwaitOffset())
|
||||
return false;
|
||||
|
||||
// Store generator in R0.
|
||||
|
@ -4250,7 +4297,7 @@ BaselineCompiler::emit_JSOP_YIELD()
|
|||
// generator is in the closing state, see GeneratorObject::suspend.
|
||||
|
||||
masm.storeValue(Int32Value(GET_UINT24(pc)),
|
||||
Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()));
|
||||
Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
|
||||
|
||||
Register envObj = R0.scratchReg();
|
||||
Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot());
|
||||
|
@ -4282,6 +4329,12 @@ BaselineCompiler::emit_JSOP_YIELD()
|
|||
return emitReturn();
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCompiler::emit_JSOP_AWAIT()
|
||||
{
|
||||
return emit_JSOP_YIELD();
|
||||
}
|
||||
|
||||
typedef bool (*DebugAfterYieldFn)(JSContext*, BaselineFrame*);
|
||||
static const VMFunction DebugAfterYieldInfo =
|
||||
FunctionInfo<DebugAfterYieldFn>(jit::DebugAfterYield, "DebugAfterYield");
|
||||
|
@ -4501,16 +4554,17 @@ BaselineCompiler::emit_JSOP_RESUME()
|
|||
masm.pushValue(retVal);
|
||||
|
||||
if (resumeKind == GeneratorObject::NEXT) {
|
||||
// Determine the resume address based on the yieldIndex and the
|
||||
// yieldIndex -> native table in the BaselineScript.
|
||||
// Determine the resume address based on the yieldAndAwaitIndex and the
|
||||
// yieldAndAwaitIndex -> native table in the BaselineScript.
|
||||
masm.load32(Address(scratch1, BaselineScript::offsetOfYieldEntriesOffset()), scratch2);
|
||||
masm.addPtr(scratch2, scratch1);
|
||||
masm.unboxInt32(Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()), scratch2);
|
||||
masm.unboxInt32(Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()),
|
||||
scratch2);
|
||||
masm.loadPtr(BaseIndex(scratch1, scratch2, ScaleFromElemWidth(sizeof(uintptr_t))), scratch1);
|
||||
|
||||
// Mark as running and jump to the generator's JIT code.
|
||||
masm.storeValue(Int32Value(GeneratorObject::YIELD_INDEX_RUNNING),
|
||||
Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()));
|
||||
masm.storeValue(Int32Value(GeneratorObject::YIELD_AND_AWAIT_INDEX_RUNNING),
|
||||
Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
|
||||
masm.jump(scratch1);
|
||||
} else {
|
||||
MOZ_ASSERT(resumeKind == GeneratorObject::THROW || resumeKind == GeneratorObject::CLOSE);
|
||||
|
|
|
@ -196,6 +196,8 @@ namespace jit {
|
|||
_(JSOP_RUNONCE) \
|
||||
_(JSOP_REST) \
|
||||
_(JSOP_TOASYNC) \
|
||||
_(JSOP_TOASYNCGEN) \
|
||||
_(JSOP_TOASYNCITER) \
|
||||
_(JSOP_TOID) \
|
||||
_(JSOP_TOSTRING) \
|
||||
_(JSOP_TABLESWITCH) \
|
||||
|
@ -207,6 +209,7 @@ namespace jit {
|
|||
_(JSOP_GENERATOR) \
|
||||
_(JSOP_INITIALYIELD) \
|
||||
_(JSOP_YIELD) \
|
||||
_(JSOP_AWAIT) \
|
||||
_(JSOP_DEBUGAFTERYIELD) \
|
||||
_(JSOP_FINALYIELDRVAL) \
|
||||
_(JSOP_RESUME) \
|
||||
|
@ -255,9 +258,9 @@ class BaselineCompiler : public BaselineCompilerSpecific
|
|||
// equivalent positions when debug mode is off.
|
||||
CodeOffset postDebugPrologueOffset_;
|
||||
|
||||
// For each INITIALYIELD or YIELD op, this Vector maps the yield index
|
||||
// to the bytecode offset of the next op.
|
||||
Vector<uint32_t> yieldOffsets_;
|
||||
// For each INITIALYIELD or YIELD or AWAIT op, this Vector maps the yield
|
||||
// index to the bytecode offset of the next op.
|
||||
Vector<uint32_t> yieldAndAwaitOffsets_;
|
||||
|
||||
// Whether any on stack arguments are modified.
|
||||
bool modifiesArguments_;
|
||||
|
@ -349,7 +352,7 @@ class BaselineCompiler : public BaselineCompilerSpecific
|
|||
|
||||
MOZ_MUST_USE bool addPCMappingEntry(bool addIndexEntry);
|
||||
|
||||
MOZ_MUST_USE bool addYieldOffset();
|
||||
MOZ_MUST_USE bool addYieldAndAwaitOffset();
|
||||
|
||||
void getEnvironmentCoordinateObject(Register reg);
|
||||
Address getEnvironmentCoordinateAddressFromObject(Register objReg, Register reg);
|
||||
|
|
|
@ -6600,12 +6600,13 @@ ICCall_IsSuspendedStarGenerator::Compiler::generateStubCode(MacroAssembler& masm
|
|||
masm.branchTestObjClass(Assembler::NotEqual, genObj, scratch, &StarGeneratorObject::class_,
|
||||
&returnFalse);
|
||||
|
||||
// If the yield index slot holds an int32 value < YIELD_INDEX_CLOSING,
|
||||
// If the yield index slot holds an int32 value < YIELD_AND_AWAIT_INDEX_CLOSING,
|
||||
// the generator is suspended.
|
||||
masm.loadValue(Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()), argVal);
|
||||
masm.loadValue(Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()), argVal);
|
||||
masm.branchTestInt32(Assembler::NotEqual, argVal, &returnFalse);
|
||||
masm.unboxInt32(argVal, scratch);
|
||||
masm.branch32(Assembler::AboveOrEqual, scratch, Imm32(StarGeneratorObject::YIELD_INDEX_CLOSING),
|
||||
masm.branch32(Assembler::AboveOrEqual, scratch,
|
||||
Imm32(StarGeneratorObject::YIELD_AND_AWAIT_INDEX_CLOSING),
|
||||
&returnFalse);
|
||||
|
||||
masm.moveValue(BooleanValue(true), R0);
|
||||
|
|
|
@ -760,12 +760,12 @@ BaselineScript::icEntryFromReturnAddress(uint8_t* returnAddr)
|
|||
}
|
||||
|
||||
void
|
||||
BaselineScript::copyYieldEntries(JSScript* script, Vector<uint32_t>& yieldOffsets)
|
||||
BaselineScript::copyYieldAndAwaitEntries(JSScript* script, Vector<uint32_t>& yieldAndAwaitOffsets)
|
||||
{
|
||||
uint8_t** entries = yieldEntryList();
|
||||
|
||||
for (size_t i = 0; i < yieldOffsets.length(); i++) {
|
||||
uint32_t offset = yieldOffsets[i];
|
||||
for (size_t i = 0; i < yieldAndAwaitOffsets.length(); i++) {
|
||||
uint32_t offset = yieldAndAwaitOffsets[i];
|
||||
entries[i] = nativeCodeForPC(script, script->offsetToPC(offset));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -397,7 +397,7 @@ struct BaselineScript
|
|||
void copyICEntries(JSScript* script, const BaselineICEntry* entries, MacroAssembler& masm);
|
||||
void adoptFallbackStubs(FallbackICStubSpace* stubSpace);
|
||||
|
||||
void copyYieldEntries(JSScript* script, Vector<uint32_t>& yieldOffsets);
|
||||
void copyYieldAndAwaitEntries(JSScript* script, Vector<uint32_t>& yieldAndAwaitOffsets);
|
||||
|
||||
PCMappingIndexEntry& pcMappingIndexEntry(size_t index);
|
||||
CompactBufferReader pcMappingReader(size_t indexEntry);
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "jit/RangeAnalysis.h"
|
||||
#include "jit/SharedICHelpers.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/AsyncIteration.h"
|
||||
#include "vm/MatchPairs.h"
|
||||
#include "vm/RegExpObject.h"
|
||||
#include "vm/RegExpStatics.h"
|
||||
|
@ -10213,6 +10214,28 @@ CodeGenerator::visitToAsync(LToAsync* lir)
|
|||
callVM(ToAsyncInfo, lir);
|
||||
}
|
||||
|
||||
typedef JSObject* (*ToAsyncGenFn)(JSContext*, HandleFunction);
|
||||
static const VMFunction ToAsyncGenInfo =
|
||||
FunctionInfo<ToAsyncGenFn>(js::WrapAsyncGenerator, "ToAsyncGen");
|
||||
|
||||
void
|
||||
CodeGenerator::visitToAsyncGen(LToAsyncGen* lir)
|
||||
{
|
||||
pushArg(ToRegister(lir->unwrapped()));
|
||||
callVM(ToAsyncGenInfo, lir);
|
||||
}
|
||||
|
||||
typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject);
|
||||
static const VMFunction ToAsyncIterInfo =
|
||||
FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
|
||||
|
||||
void
|
||||
CodeGenerator::visitToAsyncIter(LToAsyncIter* lir)
|
||||
{
|
||||
pushArg(ToRegister(lir->unwrapped()));
|
||||
callVM(ToAsyncIterInfo, lir);
|
||||
}
|
||||
|
||||
typedef bool (*ToIdFn)(JSContext*, HandleScript, jsbytecode*, HandleValue,
|
||||
MutableHandleValue);
|
||||
static const VMFunction ToIdInfo = FunctionInfo<ToIdFn>(ToIdOperation, "ToIdOperation");
|
||||
|
|
|
@ -286,6 +286,8 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
|||
void visitTypeOfV(LTypeOfV* lir);
|
||||
void visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool);
|
||||
void visitToAsync(LToAsync* lir);
|
||||
void visitToAsyncGen(LToAsyncGen* lir);
|
||||
void visitToAsyncIter(LToAsyncIter* lir);
|
||||
void visitToIdV(LToIdV* lir);
|
||||
template<typename T> void emitLoadElementT(LLoadElementT* lir, const T& source);
|
||||
void visitLoadElementT(LLoadElementT* lir);
|
||||
|
|
|
@ -2320,7 +2320,9 @@ IonCompile(JSContext* cx, JSScript* script,
|
|||
static bool
|
||||
CheckFrame(JSContext* cx, BaselineFrame* frame)
|
||||
{
|
||||
MOZ_ASSERT(!frame->script()->isGenerator());
|
||||
MOZ_ASSERT(!frame->script()->isStarGenerator());
|
||||
MOZ_ASSERT(!frame->script()->isLegacyGenerator());
|
||||
MOZ_ASSERT(!frame->script()->isAsync());
|
||||
MOZ_ASSERT(!frame->isDebuggerEvalFrame());
|
||||
MOZ_ASSERT(!frame->isEvalFrame());
|
||||
|
||||
|
@ -2351,11 +2353,16 @@ CheckScript(JSContext* cx, JSScript* script, bool osr)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (script->isGenerator()) {
|
||||
if (script->isStarGenerator() || script->isLegacyGenerator()) {
|
||||
TrackAndSpewIonAbort(cx, script, "generator script");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (script->isAsync()) {
|
||||
TrackAndSpewIonAbort(cx, script, "async script");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (script->hasNonSyntacticScope() && !script->functionNonDelazifying()) {
|
||||
// Support functions with a non-syntactic global scope but not other
|
||||
// scripts. For global scripts, IonBuilder currently uses the global
|
||||
|
|
|
@ -4402,8 +4402,14 @@ jit::AnalyzeArgumentsUsage(JSContext* cx, JSScript* scriptArg)
|
|||
// direct eval is present.
|
||||
//
|
||||
// FIXME: Don't build arguments for ES6 generator expressions.
|
||||
if (scriptArg->isDebuggee() || script->isGenerator() || script->bindingsAccessedDynamically())
|
||||
if (scriptArg->isDebuggee() ||
|
||||
script->isStarGenerator() ||
|
||||
script->isLegacyGenerator() ||
|
||||
script->isAsync() ||
|
||||
script->bindingsAccessedDynamically())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!jit::IsIonEnabled(cx))
|
||||
return true;
|
||||
|
|
|
@ -2130,6 +2130,12 @@ IonBuilder::inspectOpcode(JSOp op)
|
|||
case JSOP_TOASYNC:
|
||||
return jsop_toasync();
|
||||
|
||||
case JSOP_TOASYNCGEN:
|
||||
return jsop_toasyncgen();
|
||||
|
||||
case JSOP_TOASYNCITER:
|
||||
return jsop_toasynciter();
|
||||
|
||||
case JSOP_TOID:
|
||||
return jsop_toid();
|
||||
|
||||
|
@ -3351,7 +3357,7 @@ IonBuilder::whileOrForInLoop(jssrcnote* sn)
|
|||
|
||||
unsigned stackPhiCount;
|
||||
if (SN_TYPE(sn) == SRC_FOR_OF)
|
||||
stackPhiCount = 2;
|
||||
stackPhiCount = 3;
|
||||
else if (SN_TYPE(sn) == SRC_FOR_IN)
|
||||
stackPhiCount = 1;
|
||||
else
|
||||
|
@ -13195,6 +13201,34 @@ IonBuilder::jsop_toasync()
|
|||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_toasyncgen()
|
||||
{
|
||||
MDefinition* unwrapped = current->pop();
|
||||
MOZ_ASSERT(unwrapped->type() == MIRType::Object);
|
||||
|
||||
MToAsyncGen* ins = MToAsyncGen::New(alloc(), unwrapped);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_toasynciter()
|
||||
{
|
||||
MDefinition* unwrapped = current->pop();
|
||||
MOZ_ASSERT(unwrapped->type() == MIRType::Object);
|
||||
|
||||
MToAsyncIter* ins = MToAsyncIter::New(alloc(), unwrapped);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
return resumeAfter(ins);
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::jsop_toid()
|
||||
{
|
||||
|
|
|
@ -762,6 +762,8 @@ class IonBuilder
|
|||
MOZ_MUST_USE bool jsop_globalthis();
|
||||
MOZ_MUST_USE bool jsop_typeof();
|
||||
MOZ_MUST_USE bool jsop_toasync();
|
||||
MOZ_MUST_USE bool jsop_toasyncgen();
|
||||
MOZ_MUST_USE bool jsop_toasynciter();
|
||||
MOZ_MUST_USE bool jsop_toid();
|
||||
MOZ_MUST_USE bool jsop_iter(uint8_t flags);
|
||||
MOZ_MUST_USE bool jsop_itermore();
|
||||
|
|
|
@ -1175,6 +1175,22 @@ LIRGenerator::visitToAsync(MToAsync* ins)
|
|||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitToAsyncGen(MToAsyncGen* ins)
|
||||
{
|
||||
LToAsyncGen* lir = new(alloc()) LToAsyncGen(useRegisterAtStart(ins->input()));
|
||||
defineReturn(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitToAsyncIter(MToAsyncIter* ins)
|
||||
{
|
||||
LToAsyncIter* lir = new(alloc()) LToAsyncIter(useRegisterAtStart(ins->input()));
|
||||
defineReturn(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitToId(MToId* ins)
|
||||
{
|
||||
|
|
|
@ -121,6 +121,8 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitCompare(MCompare* comp);
|
||||
void visitTypeOf(MTypeOf* ins);
|
||||
void visitToAsync(MToAsync* ins);
|
||||
void visitToAsyncGen(MToAsyncGen* ins);
|
||||
void visitToAsyncIter(MToAsyncIter* ins);
|
||||
void visitToId(MToId* ins);
|
||||
void visitBitNot(MBitNot* ins);
|
||||
void visitBitAnd(MBitAnd* ins);
|
||||
|
|
|
@ -5784,6 +5784,36 @@ class MToAsync
|
|||
TRIVIAL_NEW_WRAPPERS
|
||||
};
|
||||
|
||||
class MToAsyncGen
|
||||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data
|
||||
{
|
||||
explicit MToAsyncGen(MDefinition* unwrapped)
|
||||
: MUnaryInstruction(unwrapped)
|
||||
{
|
||||
setResultType(MIRType::Object);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(ToAsyncGen)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
};
|
||||
|
||||
class MToAsyncIter
|
||||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data
|
||||
{
|
||||
explicit MToAsyncIter(MDefinition* unwrapped)
|
||||
: MUnaryInstruction(unwrapped)
|
||||
{
|
||||
setResultType(MIRType::Object);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(ToAsyncIter)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
};
|
||||
|
||||
class MToId
|
||||
: public MUnaryInstruction,
|
||||
public BoxInputsPolicy::Data
|
||||
|
|
|
@ -79,6 +79,8 @@ namespace jit {
|
|||
_(BitNot) \
|
||||
_(TypeOf) \
|
||||
_(ToAsync) \
|
||||
_(ToAsyncGen) \
|
||||
_(ToAsyncIter) \
|
||||
_(ToId) \
|
||||
_(BitAnd) \
|
||||
_(BitOr) \
|
||||
|
|
|
@ -735,7 +735,7 @@ bool
|
|||
NormalSuspend(JSContext* cx, HandleObject obj, BaselineFrame* frame, jsbytecode* pc,
|
||||
uint32_t stackDepth)
|
||||
{
|
||||
MOZ_ASSERT(*pc == JSOP_YIELD);
|
||||
MOZ_ASSERT(*pc == JSOP_YIELD || *pc == JSOP_AWAIT);
|
||||
|
||||
// Return value is still on the stack.
|
||||
MOZ_ASSERT(stackDepth >= 1);
|
||||
|
@ -816,7 +816,7 @@ GeneratorThrowOrClose(JSContext* cx, BaselineFrame* frame, Handle<GeneratorObjec
|
|||
// work. This function always returns false, so we're guaranteed to enter
|
||||
// the exception handler where we will clear the pc.
|
||||
JSScript* script = frame->script();
|
||||
uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()];
|
||||
uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
|
||||
frame->setOverridePc(script->offsetToPC(offset));
|
||||
|
||||
MOZ_ALWAYS_TRUE(DebugAfterYield(cx, frame));
|
||||
|
|
|
@ -1606,6 +1606,32 @@ class LToAsync : public LCallInstructionHelper<1, 1, 0>
|
|||
}
|
||||
};
|
||||
|
||||
class LToAsyncGen : public LCallInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ToAsyncGen)
|
||||
explicit LToAsyncGen(const LAllocation& input) {
|
||||
setOperand(0, input);
|
||||
}
|
||||
|
||||
const LAllocation* unwrapped() {
|
||||
return getOperand(0);
|
||||
}
|
||||
};
|
||||
|
||||
class LToAsyncIter : public LCallInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ToAsyncIter)
|
||||
explicit LToAsyncIter(const LAllocation& input) {
|
||||
setOperand(0, input);
|
||||
}
|
||||
|
||||
const LAllocation* unwrapped() {
|
||||
return getOperand(0);
|
||||
}
|
||||
};
|
||||
|
||||
class LToIdV : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 1>
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -353,6 +353,8 @@
|
|||
_(Rest) \
|
||||
_(TypeOfV) \
|
||||
_(ToAsync) \
|
||||
_(ToAsyncGen) \
|
||||
_(ToAsyncIter) \
|
||||
_(ToIdV) \
|
||||
_(Floor) \
|
||||
_(FloorF) \
|
||||
|
|
|
@ -185,7 +185,6 @@ MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid array compre
|
|||
MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initializer too large")
|
||||
MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' after import *")
|
||||
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
|
||||
MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async")
|
||||
MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await can't be used in default expression")
|
||||
MSG_DEF(JSMSG_AWAIT_OUTSIDE_ASYNC, 0, JSEXN_SYNTAXERR, "await is only valid in async functions")
|
||||
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
|
||||
|
@ -438,7 +437,6 @@ MSG_DEF(JSMSG_SC_SAB_DISABLED, 0, JSEXN_TYPEERR, "SharedArrayBuffer not
|
|||
|
||||
// Debugger
|
||||
MSG_DEF(JSMSG_ASSIGN_FUNCTION_OR_NULL, 1, JSEXN_TYPEERR, "value assigned to {0} must be a function or null")
|
||||
MSG_DEF(JSMSG_DEBUG_BAD_AWAIT, 0, JSEXN_TYPEERR, "await expression received invalid value")
|
||||
MSG_DEF(JSMSG_DEBUG_BAD_LINE, 0, JSEXN_TYPEERR, "invalid line number")
|
||||
MSG_DEF(JSMSG_DEBUG_BAD_OFFSET, 0, JSEXN_TYPEERR, "invalid script offset")
|
||||
MSG_DEF(JSMSG_DEBUG_BAD_REFERENT, 2, JSEXN_TYPEERR, "{0} does not refer to {1}")
|
||||
|
@ -594,3 +592,9 @@ 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_FOR_AWAIT_NOT_OF, 0, JSEXN_TYPEERR, "'for await' loop should be used with 'of'")
|
||||
MSG_DEF(JSMSG_NOT_AN_ASYNC_GENERATOR, 0, JSEXN_TYPEERR, "Not an async generator")
|
||||
MSG_DEF(JSMSG_NOT_AN_ASYNC_ITERATOR, 0, JSEXN_TYPEERR, "Not an async from sync iterator")
|
||||
MSG_DEF(JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "[Symbol.asyncIterator]() returned a non-object value")
|
||||
|
|
|
@ -70,6 +70,7 @@
|
|||
#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"
|
||||
|
@ -3591,6 +3592,11 @@ 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
|
||||
|
|
|
@ -5088,6 +5088,7 @@ GetSymbolDescription(HandleSymbol symbol);
|
|||
macro(toPrimitive) \
|
||||
macro(toStringTag) \
|
||||
macro(unscopables) \
|
||||
macro(asyncIterator) \
|
||||
macro(matchAll)
|
||||
|
||||
enum class SymbolCode : uint32_t {
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "vm/ErrorObject.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/SavedStacks.h"
|
||||
#include "vm/SelfHosting.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
@ -1091,3 +1092,19 @@ js::ValueToSourceForError(JSContext* cx, HandleValue val, JSAutoByteString& byte
|
|||
return "<<error converting value to string>>";
|
||||
return bytes.encodeLatin1(cx, str);
|
||||
}
|
||||
|
||||
bool
|
||||
js::GetInternalError(JSContext* cx, unsigned errorNumber, MutableHandleValue error)
|
||||
{
|
||||
FixedInvokeArgs<1> args(cx);
|
||||
args[0].set(Int32Value(errorNumber));
|
||||
return CallSelfHostedFunction(cx, "GetInternalError", NullHandleValue, args, error);
|
||||
}
|
||||
|
||||
bool
|
||||
js::GetTypeError(JSContext* cx, unsigned errorNumber, MutableHandleValue error)
|
||||
{
|
||||
FixedInvokeArgs<1> args(cx);
|
||||
args[0].set(Int32Value(errorNumber));
|
||||
return CallSelfHostedFunction(cx, "GetTypeError", NullHandleValue, args, error);
|
||||
}
|
||||
|
|
|
@ -131,6 +131,11 @@ class AutoAssertNoPendingException
|
|||
extern const char*
|
||||
ValueToSourceForError(JSContext* cx, HandleValue val, JSAutoByteString& bytes);
|
||||
|
||||
bool
|
||||
GetInternalError(JSContext* cx, unsigned errorNumber, MutableHandleValue error);
|
||||
bool
|
||||
GetTypeError(JSContext* cx, unsigned errorNumber, MutableHandleValue error);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* jsexn_h */
|
||||
|
|
|
@ -948,6 +948,7 @@ IsObjectInContextCompartment(JSObject* obj, const JSContext* cx);
|
|||
#define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */
|
||||
#define JSITER_SYMBOLS 0x20 /* also include symbol property keys */
|
||||
#define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */
|
||||
#define JSITER_FORAWAITOF 0x80 /* for-await-of */
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
RunningWithTrustedPrincipals(JSContext* cx);
|
||||
|
|
120
js/src/jsfun.cpp
120
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
|
||||
|
@ -1794,6 +1826,40 @@ 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()
|
||||
{
|
||||
|
@ -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;
|
||||
|
|
|
@ -89,15 +89,15 @@ class JSFunction : public js::NativeObject
|
|||
ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
|
||||
ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
|
||||
INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
|
||||
INTERPRETED_METHOD_GENERATOR = INTERPRETED | METHOD_KIND,
|
||||
INTERPRETED_METHOD_GENERATOR_OR_ASYNC = INTERPRETED | METHOD_KIND,
|
||||
INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | CLASSCONSTRUCTOR_KIND | CONSTRUCTOR,
|
||||
INTERPRETED_GETTER = INTERPRETED | GETTER_KIND,
|
||||
INTERPRETED_SETTER = INTERPRETED | SETTER_KIND,
|
||||
INTERPRETED_LAMBDA = INTERPRETED | LAMBDA | CONSTRUCTOR,
|
||||
INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
|
||||
INTERPRETED_LAMBDA_GENERATOR = INTERPRETED | LAMBDA,
|
||||
INTERPRETED_LAMBDA_GENERATOR_OR_ASYNC = INTERPRETED | LAMBDA,
|
||||
INTERPRETED_NORMAL = INTERPRETED | CONSTRUCTOR,
|
||||
INTERPRETED_GENERATOR = INTERPRETED,
|
||||
INTERPRETED_GENERATOR_OR_ASYNC = INTERPRETED,
|
||||
NO_XDR_FLAGS = RESOLVED_LENGTH | RESOLVED_NAME,
|
||||
|
||||
STABLE_ACROSS_CLONES = CONSTRUCTOR | HAS_GUESSED_ATOM | LAMBDA |
|
||||
|
@ -146,7 +146,9 @@ class JSFunction : public js::NativeObject
|
|||
MOZ_ASSERT_IF(nonLazyScript()->funHasExtensibleScope() ||
|
||||
nonLazyScript()->needsHomeObject() ||
|
||||
nonLazyScript()->isDerivedClassConstructor() ||
|
||||
isGenerator(),
|
||||
isStarGenerator() ||
|
||||
isLegacyGenerator() ||
|
||||
isAsync(),
|
||||
nonLazyScript()->bodyScope()->hasEnvironment());
|
||||
|
||||
return nonLazyScript()->bodyScope()->hasEnvironment();
|
||||
|
@ -501,8 +503,6 @@ class JSFunction : public js::NativeObject
|
|||
return js::NotGenerator;
|
||||
}
|
||||
|
||||
bool isGenerator() const { return generatorKind() != js::NotGenerator; }
|
||||
|
||||
bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
|
||||
|
||||
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
|
||||
|
@ -513,9 +513,9 @@ class JSFunction : public js::NativeObject
|
|||
|
||||
bool isAsync() const {
|
||||
if (isInterpretedLazy())
|
||||
return lazyScript()->asyncKind() == js::AsyncFunction;
|
||||
return lazyScript()->isAsync();
|
||||
if (hasScript())
|
||||
return nonLazyScript()->asyncKind() == js::AsyncFunction;
|
||||
return nonLazyScript()->isAsync();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -660,6 +660,9 @@ 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*
|
||||
|
|
|
@ -916,28 +916,30 @@ js::GetIteratorObject(JSContext* cx, HandleObject obj, uint32_t flags)
|
|||
return iterator;
|
||||
}
|
||||
|
||||
// ES 2017 draft 7.4.7.
|
||||
JSObject*
|
||||
js::CreateItrResultObject(JSContext* cx, HandleValue value, bool done)
|
||||
js::CreateIterResultObject(JSContext* cx, HandleValue value, bool done)
|
||||
{
|
||||
// FIXME: We can cache the iterator result object shape somewhere.
|
||||
AssertHeapIsIdle(cx);
|
||||
// Step 1 (implicit).
|
||||
|
||||
RootedObject proto(cx, GlobalObject::getOrCreateObjectPrototype(cx, cx->global()));
|
||||
if (!proto)
|
||||
// Step 2.
|
||||
RootedObject resultObj(cx, NewBuiltinClassInstance<PlainObject>(cx));
|
||||
if (!resultObj)
|
||||
return nullptr;
|
||||
|
||||
RootedPlainObject obj(cx, NewObjectWithGivenProto<PlainObject>(cx, proto));
|
||||
if (!obj)
|
||||
// Step 3.
|
||||
if (!DefineProperty(cx, resultObj, cx->names().value, value))
|
||||
return nullptr;
|
||||
|
||||
if (!DefineProperty(cx, obj, cx->names().value, value))
|
||||
// Step 4.
|
||||
if (!DefineProperty(cx, resultObj, cx->names().done,
|
||||
done ? TrueHandleValue : FalseHandleValue))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RootedValue doneBool(cx, BooleanValue(done));
|
||||
if (!DefineProperty(cx, obj, cx->names().done, doneBool))
|
||||
return nullptr;
|
||||
|
||||
return obj;
|
||||
// Step 5.
|
||||
return resultObj;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -216,10 +216,10 @@ ThrowStopIteration(JSContext* cx);
|
|||
|
||||
/*
|
||||
* Create an object of the form { value: VALUE, done: DONE }.
|
||||
* ES6 draft from 2013-09-05, section 25.4.3.4.
|
||||
* ES 2017 draft 7.4.7.
|
||||
*/
|
||||
extern JSObject*
|
||||
CreateItrResultObject(JSContext* cx, HandleValue value, bool done);
|
||||
CreateIterResultObject(JSContext* cx, HandleValue value, bool done);
|
||||
|
||||
extern JSObject*
|
||||
InitLegacyIteratorClass(JSContext* cx, HandleObject obj);
|
||||
|
@ -227,6 +227,8 @@ InitLegacyIteratorClass(JSContext* cx, HandleObject obj);
|
|||
extern JSObject*
|
||||
InitStopIterationClass(JSContext* cx, HandleObject obj);
|
||||
|
||||
enum class IteratorKind { Sync, Async };
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsiter_h */
|
||||
|
|
|
@ -655,7 +655,8 @@ IsValidBytecodeOffset(JSContext* cx, JSScript* script, size_t offset);
|
|||
inline bool
|
||||
FlowsIntoNext(JSOp op)
|
||||
{
|
||||
/* JSOP_YIELD is considered to flow into the next instruction, like JSOP_CALL. */
|
||||
// JSOP_YIELD/JSOP_AWAIT is considered to flow into the next instruction,
|
||||
// like JSOP_CALL.
|
||||
switch (op) {
|
||||
case JSOP_RETRVAL:
|
||||
case JSOP_RETURN:
|
||||
|
|
|
@ -402,8 +402,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
|||
ntrynotes = script->trynotes()->length;
|
||||
if (script->hasScopeNotes())
|
||||
nscopenotes = script->scopeNotes()->length;
|
||||
if (script->hasYieldOffsets())
|
||||
nyieldoffsets = script->yieldOffsets().length();
|
||||
if (script->hasYieldAndAwaitOffsets())
|
||||
nyieldoffsets = script->yieldAndAwaitOffsets().length();
|
||||
|
||||
nTypeSets = script->nTypeSets();
|
||||
funLength = script->funLength();
|
||||
|
@ -902,7 +902,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
|||
}
|
||||
|
||||
for (i = 0; i < nyieldoffsets; ++i) {
|
||||
uint32_t* offset = &script->yieldOffsets()[i];
|
||||
uint32_t* offset = &script->yieldAndAwaitOffsets()[i];
|
||||
if (!xdr->codeUint32(offset))
|
||||
return false;
|
||||
}
|
||||
|
@ -2456,7 +2456,7 @@ ScriptDataSize(uint32_t nscopes, uint32_t nconsts, uint32_t nobjects,
|
|||
if (nscopenotes != 0)
|
||||
size += sizeof(ScopeNoteArray) + nscopenotes * sizeof(ScopeNote);
|
||||
if (nyieldoffsets != 0)
|
||||
size += sizeof(YieldOffsetArray) + nyieldoffsets * sizeof(uint32_t);
|
||||
size += sizeof(YieldAndAwaitOffsetArray) + nyieldoffsets * sizeof(uint32_t);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
@ -2558,10 +2558,10 @@ JSScript::partiallyInit(ExclusiveContext* cx, HandleScript script, uint32_t nsco
|
|||
cursor += sizeof(ScopeNoteArray);
|
||||
}
|
||||
|
||||
YieldOffsetArray* yieldOffsets = nullptr;
|
||||
YieldAndAwaitOffsetArray* yieldAndAwaitOffsets = nullptr;
|
||||
if (nyieldoffsets != 0) {
|
||||
yieldOffsets = reinterpret_cast<YieldOffsetArray*>(cursor);
|
||||
cursor += sizeof(YieldOffsetArray);
|
||||
yieldAndAwaitOffsets = reinterpret_cast<YieldAndAwaitOffsetArray*>(cursor);
|
||||
cursor += sizeof(YieldAndAwaitOffsetArray);
|
||||
}
|
||||
|
||||
if (nconsts != 0) {
|
||||
|
@ -2602,8 +2602,8 @@ JSScript::partiallyInit(ExclusiveContext* cx, HandleScript script, uint32_t nsco
|
|||
}
|
||||
|
||||
if (nyieldoffsets != 0) {
|
||||
yieldOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
|
||||
size_t vectorSize = nyieldoffsets * sizeof(script->yieldOffsets()[0]);
|
||||
yieldAndAwaitOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
|
||||
size_t vectorSize = nyieldoffsets * sizeof(script->yieldAndAwaitOffsets()[0]);
|
||||
#ifdef DEBUG
|
||||
memset(cursor, 0, vectorSize);
|
||||
#endif
|
||||
|
@ -2623,10 +2623,10 @@ JSScript::initFunctionPrototype(ExclusiveContext* cx, Handle<JSScript*> script,
|
|||
uint32_t numObjects = 0;
|
||||
uint32_t numTryNotes = 0;
|
||||
uint32_t numScopeNotes = 0;
|
||||
uint32_t numYieldOffsets = 0;
|
||||
uint32_t numYieldAndAwaitOffsets = 0;
|
||||
uint32_t numTypeSets = 0;
|
||||
if (!partiallyInit(cx, script, numScopes, numConsts, numObjects, numTryNotes,
|
||||
numScopeNotes, numYieldOffsets, numTypeSets))
|
||||
numScopeNotes, numYieldAndAwaitOffsets, numTypeSets))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -2739,7 +2739,7 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
|
|||
if (!partiallyInit(cx, script,
|
||||
bce->scopeList.length(), bce->constList.length(), bce->objectList.length,
|
||||
bce->tryNoteList.length(), bce->scopeNoteList.length(),
|
||||
bce->yieldOffsetList.length(), bce->typesetCount))
|
||||
bce->yieldAndAwaitOffsetList.length(), bce->typesetCount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -2794,8 +2794,8 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
|
|||
|
||||
// Copy yield offsets last, as the generator kind is set in
|
||||
// initFromFunctionBox.
|
||||
if (bce->yieldOffsetList.length() != 0)
|
||||
bce->yieldOffsetList.finish(script->yieldOffsets(), prologueLength);
|
||||
if (bce->yieldAndAwaitOffsetList.length() != 0)
|
||||
bce->yieldAndAwaitOffsetList.finish(script->yieldAndAwaitOffsets(), prologueLength);
|
||||
|
||||
#ifdef DEBUG
|
||||
script->assertValidJumpTargets();
|
||||
|
@ -3188,7 +3188,7 @@ CloneInnerInterpretedFunction(JSContext* cx, HandleScope enclosingScope, HandleF
|
|||
{
|
||||
/* NB: Keep this in sync with XDRInterpretedFunction. */
|
||||
RootedObject cloneProto(cx);
|
||||
if (srcFun->isStarGenerator()) {
|
||||
if (srcFun->isStarGenerator() || srcFun->isAsync()) {
|
||||
cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global());
|
||||
if (!cloneProto)
|
||||
return nullptr;
|
||||
|
@ -3242,7 +3242,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
|
|||
uint32_t nscopes = src->scopes()->length;
|
||||
uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
|
||||
uint32_t nscopenotes = src->hasScopeNotes() ? src->scopeNotes()->length : 0;
|
||||
uint32_t nyieldoffsets = src->hasYieldOffsets() ? src->yieldOffsets().length() : 0;
|
||||
uint32_t nyieldoffsets = src->hasYieldAndAwaitOffsets() ? src->yieldAndAwaitOffsets().length() : 0;
|
||||
|
||||
/* Script data */
|
||||
|
||||
|
@ -3380,8 +3380,10 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
|
|||
dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
|
||||
if (nscopenotes != 0)
|
||||
dst->scopeNotes()->vector = Rebase<ScopeNote>(dst, src, src->scopeNotes()->vector);
|
||||
if (nyieldoffsets != 0)
|
||||
dst->yieldOffsets().vector_ = Rebase<uint32_t>(dst, src, src->yieldOffsets().vector_);
|
||||
if (nyieldoffsets != 0) {
|
||||
dst->yieldAndAwaitOffsets().vector_ =
|
||||
Rebase<uint32_t>(dst, src, src->yieldAndAwaitOffsets().vector_);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function delazification assumes that their script does not have a
|
||||
|
@ -3917,7 +3919,9 @@ JSScript::argumentsOptimizationFailed(JSContext* cx, HandleScript script)
|
|||
if (script->needsArgsObj())
|
||||
return true;
|
||||
|
||||
MOZ_ASSERT(!script->isGenerator());
|
||||
MOZ_ASSERT(!script->isStarGenerator());
|
||||
MOZ_ASSERT(!script->isLegacyGenerator());
|
||||
MOZ_ASSERT(!script->isAsync());
|
||||
|
||||
script->needsArgsObj_ = true;
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ struct ScopeNoteArray {
|
|||
uint32_t length; // Count of indexed try notes.
|
||||
};
|
||||
|
||||
class YieldOffsetArray {
|
||||
class YieldAndAwaitOffsetArray {
|
||||
friend bool
|
||||
detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
|
||||
MutableHandle<GCVector<Scope*>> scopes);
|
||||
|
@ -1327,13 +1327,12 @@ class JSScript : public js::gc::TenuredCell
|
|||
js::GeneratorKind generatorKind() const {
|
||||
return js::GeneratorKindFromBits(generatorKindBits_);
|
||||
}
|
||||
bool isGenerator() const { return generatorKind() != js::NotGenerator; }
|
||||
bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
|
||||
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
|
||||
void setGeneratorKind(js::GeneratorKind kind) {
|
||||
// A script only gets its generator kind set as part of initialization,
|
||||
// so it can only transition from not being a generator.
|
||||
MOZ_ASSERT(!isGenerator());
|
||||
MOZ_ASSERT(!isStarGenerator() && !isLegacyGenerator());
|
||||
generatorKindBits_ = GeneratorKindAsBits(kind);
|
||||
}
|
||||
|
||||
|
@ -1341,6 +1340,10 @@ class JSScript : public js::gc::TenuredCell
|
|||
return isAsync_ ? js::AsyncFunction : js::SyncFunction;
|
||||
}
|
||||
|
||||
bool isAsync() const {
|
||||
return isAsync_;
|
||||
}
|
||||
|
||||
void setAsyncKind(js::FunctionAsyncKind kind) {
|
||||
isAsync_ = kind == js::AsyncFunction;
|
||||
}
|
||||
|
@ -1493,7 +1496,8 @@ class JSScript : public js::gc::TenuredCell
|
|||
|
||||
bool isRelazifiable() const {
|
||||
return (selfHosted() || lazyScript) && !hasInnerFunctions_ && !types_ &&
|
||||
!isGenerator() && !hasBaselineScript() && !hasAnyIonScript() &&
|
||||
!isStarGenerator() && !isLegacyGenerator() && !isAsync() &&
|
||||
!hasBaselineScript() && !hasAnyIonScript() &&
|
||||
!isDefaultClassConstructor() &&
|
||||
!doNotRelazify_;
|
||||
}
|
||||
|
@ -1695,7 +1699,9 @@ class JSScript : public js::gc::TenuredCell
|
|||
bool hasObjects() const { return hasArray(OBJECTS); }
|
||||
bool hasTrynotes() const { return hasArray(TRYNOTES); }
|
||||
bool hasScopeNotes() const { return hasArray(SCOPENOTES); }
|
||||
bool hasYieldOffsets() const { return isGenerator(); }
|
||||
bool hasYieldAndAwaitOffsets() const {
|
||||
return isStarGenerator() || isLegacyGenerator() || isAsync();
|
||||
}
|
||||
|
||||
#define OFF(fooOff, hasFoo, t) (fooOff() + (hasFoo() ? sizeof(t) : 0))
|
||||
|
||||
|
@ -1704,7 +1710,9 @@ class JSScript : public js::gc::TenuredCell
|
|||
size_t objectsOffset() const { return OFF(constsOffset, hasConsts, js::ConstArray); }
|
||||
size_t trynotesOffset() const { return OFF(objectsOffset, hasObjects, js::ObjectArray); }
|
||||
size_t scopeNotesOffset() const { return OFF(trynotesOffset, hasTrynotes, js::TryNoteArray); }
|
||||
size_t yieldOffsetsOffset() const { return OFF(scopeNotesOffset, hasScopeNotes, js::ScopeNoteArray); }
|
||||
size_t yieldAndAwaitOffsetsOffset() const {
|
||||
return OFF(scopeNotesOffset, hasScopeNotes, js::ScopeNoteArray);
|
||||
}
|
||||
|
||||
#undef OFF
|
||||
|
||||
|
@ -1734,9 +1742,10 @@ class JSScript : public js::gc::TenuredCell
|
|||
return reinterpret_cast<js::ScopeNoteArray*>(data + scopeNotesOffset());
|
||||
}
|
||||
|
||||
js::YieldOffsetArray& yieldOffsets() {
|
||||
MOZ_ASSERT(hasYieldOffsets());
|
||||
return *reinterpret_cast<js::YieldOffsetArray*>(data + yieldOffsetsOffset());
|
||||
js::YieldAndAwaitOffsetArray& yieldAndAwaitOffsets() {
|
||||
MOZ_ASSERT(hasYieldAndAwaitOffsets());
|
||||
return *reinterpret_cast<js::YieldAndAwaitOffsetArray*>(data +
|
||||
yieldAndAwaitOffsetsOffset());
|
||||
}
|
||||
|
||||
bool hasLoops();
|
||||
|
@ -2112,8 +2121,6 @@ class LazyScript : public gc::TenuredCell
|
|||
|
||||
GeneratorKind generatorKind() const { return GeneratorKindFromBits(p_.generatorKindBits); }
|
||||
|
||||
bool isGenerator() const { return generatorKind() != NotGenerator; }
|
||||
|
||||
bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
|
||||
|
||||
bool isStarGenerator() const { return generatorKind() == StarGenerator; }
|
||||
|
@ -2121,7 +2128,7 @@ class LazyScript : public gc::TenuredCell
|
|||
void setGeneratorKind(GeneratorKind kind) {
|
||||
// A script only gets its generator kind set as part of initialization,
|
||||
// so it can only transition from NotGenerator.
|
||||
MOZ_ASSERT(!isGenerator());
|
||||
MOZ_ASSERT(!isStarGenerator() && !isLegacyGenerator());
|
||||
// Legacy generators cannot currently be lazy.
|
||||
MOZ_ASSERT(kind != LegacyGenerator);
|
||||
p_.generatorKindBits = GeneratorKindAsBits(kind);
|
||||
|
@ -2131,6 +2138,10 @@ class LazyScript : public gc::TenuredCell
|
|||
return p_.isAsync ? AsyncFunction : SyncFunction;
|
||||
}
|
||||
|
||||
bool isAsync() const {
|
||||
return p_.isAsync;
|
||||
}
|
||||
|
||||
void setAsyncKind(FunctionAsyncKind kind) {
|
||||
p_.isAsync = kind == AsyncFunction;
|
||||
}
|
||||
|
|
|
@ -305,6 +305,7 @@ UNIFIED_SOURCES += [
|
|||
'vm/ArgumentsObject.cpp',
|
||||
'vm/ArrayBufferObject.cpp',
|
||||
'vm/AsyncFunction.cpp',
|
||||
'vm/AsyncIteration.cpp',
|
||||
'vm/Caches.cpp',
|
||||
'vm/CallNonGenericMethod.cpp',
|
||||
'vm/CharacterEncoding.cpp',
|
||||
|
@ -747,6 +748,7 @@ selfhosted.inputs = [
|
|||
'builtin/SelfHostingDefines.h',
|
||||
'builtin/Utilities.js',
|
||||
'builtin/Array.js',
|
||||
'builtin/AsyncIteration.js',
|
||||
'builtin/Classes.js',
|
||||
'builtin/Date.js',
|
||||
'builtin/Error.js',
|
||||
|
@ -790,3 +792,6 @@ if CONFIG['GNU_CXX']:
|
|||
# Suppress warnings in third-party code.
|
||||
if CONFIG['CLANG_CXX'] or CONFIG['GNU_CXX']:
|
||||
SOURCES['jsdtoa.cpp'].flags += ['-Wno-implicit-fallthrough']
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DEFINES['NOMINMAX'] = True
|
||||
|
|
|
@ -85,6 +85,7 @@
|
|||
#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"
|
||||
|
@ -2304,6 +2305,8 @@ 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);
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/* 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 assertOwnDescriptor(object, propertyKey, expected) {
|
||||
var desc = Object.getOwnPropertyDescriptor(object, propertyKey);
|
||||
if (desc === undefined) {
|
||||
assertEq(expected, undefined, "Property shouldn't be present");
|
||||
return;
|
||||
}
|
||||
|
||||
assertEq(desc.enumerable, expected.enumerable, `${String(propertyKey)}.[[Enumerable]]`);
|
||||
assertEq(desc.configurable, expected.configurable, `${String(propertyKey)}.[[Configurable]]`);
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(desc, "value")) {
|
||||
assertEq(desc.value, expected.value, `${String(propertyKey)}.[[Value]]`);
|
||||
assertEq(desc.writable, expected.writable, `${String(propertyKey)}.[[Writable]]`);
|
||||
} else {
|
||||
assertEq(desc.get, expected.get, `${String(propertyKey)}.[[Get]]`);
|
||||
assertEq(desc.set, expected.set, `${String(propertyKey)}.[[Set]]`);
|
||||
}
|
||||
}
|
||||
|
||||
async function asyncFunc(){}
|
||||
var AsyncFunctionPrototype = Object.getPrototypeOf(asyncFunc);
|
||||
var AsyncFunction = AsyncFunctionPrototype.constructor;
|
||||
|
||||
|
||||
// ES2017, 25.5.2 Properties of the AsyncFunction Constructor
|
||||
|
||||
assertEqArray(Object.getOwnPropertyNames(AsyncFunction).sort(), ["length", "name", "prototype"]);
|
||||
assertEqArray(Object.getOwnPropertySymbols(AsyncFunction), []);
|
||||
|
||||
assertOwnDescriptor(AsyncFunction, "length", {
|
||||
value: 1, writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(AsyncFunction, "name", {
|
||||
value: "AsyncFunction", writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(AsyncFunction, "prototype", {
|
||||
value: AsyncFunctionPrototype, writable: false, enumerable: false, configurable: false
|
||||
});
|
||||
|
||||
|
||||
// ES2017, 25.5.3 Properties of the AsyncFunction Prototype Object
|
||||
|
||||
assertEqArray(Object.getOwnPropertyNames(AsyncFunctionPrototype).sort(), ["constructor"]);
|
||||
assertEqArray(Object.getOwnPropertySymbols(AsyncFunctionPrototype), [Symbol.toStringTag]);
|
||||
|
||||
assertOwnDescriptor(AsyncFunctionPrototype, "constructor", {
|
||||
value: AsyncFunction, writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(AsyncFunctionPrototype, Symbol.toStringTag, {
|
||||
value: "AsyncFunction", writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
|
||||
// ES2017, 25.5.4 AsyncFunction Instances
|
||||
|
||||
assertEqArray(Object.getOwnPropertyNames(asyncFunc).sort(), ["length", "name"]);
|
||||
assertEqArray(Object.getOwnPropertySymbols(asyncFunc), []);
|
||||
|
||||
assertOwnDescriptor(asyncFunc, "length", {
|
||||
value: 0, writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(asyncFunc, "name", {
|
||||
value: "asyncFunc", writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
|
||||
if (typeof reportCompare == "function")
|
||||
reportCompare(true, true);
|
|
@ -0,0 +1,111 @@
|
|||
/* 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 assertOwnDescriptor(object, propertyKey, expected) {
|
||||
var desc = Object.getOwnPropertyDescriptor(object, propertyKey);
|
||||
if (desc === undefined) {
|
||||
assertEq(expected, undefined, "Property shouldn't be present");
|
||||
return;
|
||||
}
|
||||
|
||||
assertEq(desc.enumerable, expected.enumerable, `${String(propertyKey)}.[[Enumerable]]`);
|
||||
assertEq(desc.configurable, expected.configurable, `${String(propertyKey)}.[[Configurable]]`);
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(desc, "value")) {
|
||||
assertEq(desc.value, expected.value, `${String(propertyKey)}.[[Value]]`);
|
||||
assertEq(desc.writable, expected.writable, `${String(propertyKey)}.[[Writable]]`);
|
||||
} else {
|
||||
assertEq(desc.get, expected.get, `${String(propertyKey)}.[[Get]]`);
|
||||
assertEq(desc.set, expected.set, `${String(propertyKey)}.[[Set]]`);
|
||||
}
|
||||
}
|
||||
|
||||
function* generator(){}
|
||||
var GeneratorFunctionPrototype = Object.getPrototypeOf(generator);
|
||||
var GeneratorFunction = GeneratorFunctionPrototype.constructor;
|
||||
var GeneratorPrototype = GeneratorFunctionPrototype.prototype;
|
||||
|
||||
|
||||
// ES2017, 25.2.2 Properties of the GeneratorFunction Constructor
|
||||
|
||||
assertEqArray(Object.getOwnPropertyNames(GeneratorFunction).sort(), ["length", "name", "prototype"]);
|
||||
assertEqArray(Object.getOwnPropertySymbols(GeneratorFunction), []);
|
||||
|
||||
assertOwnDescriptor(GeneratorFunction, "length", {
|
||||
value: 1, writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(GeneratorFunction, "name", {
|
||||
value: "GeneratorFunction", writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(GeneratorFunction, "prototype", {
|
||||
value: GeneratorFunctionPrototype, writable: false, enumerable: false, configurable: false
|
||||
});
|
||||
|
||||
|
||||
// ES2017, 25.2.3 Properties of the GeneratorFunction Prototype Object
|
||||
|
||||
assertEqArray(Object.getOwnPropertyNames(GeneratorFunctionPrototype).sort(), ["constructor", "prototype"]);
|
||||
assertEqArray(Object.getOwnPropertySymbols(GeneratorFunctionPrototype), [Symbol.toStringTag]);
|
||||
|
||||
assertOwnDescriptor(GeneratorFunctionPrototype, "constructor", {
|
||||
value: GeneratorFunction, writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(GeneratorFunctionPrototype, "prototype", {
|
||||
value: GeneratorPrototype, writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(GeneratorFunctionPrototype, Symbol.toStringTag, {
|
||||
value: "GeneratorFunction", writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
|
||||
// ES2017, 25.2.4 GeneratorFunction Instances
|
||||
|
||||
assertEqArray(Object.getOwnPropertyNames(generator).sort(), ["length", "name", "prototype"]);
|
||||
assertEqArray(Object.getOwnPropertySymbols(generator), []);
|
||||
|
||||
assertOwnDescriptor(generator, "length", {
|
||||
value: 0, writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(generator, "name", {
|
||||
value: "generator", writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(generator, "prototype", {
|
||||
value: generator.prototype, writable: true, enumerable: false, configurable: false
|
||||
});
|
||||
|
||||
|
||||
// ES2017, 25.3.1 Properties of Generator Prototype
|
||||
|
||||
assertEqArray(Object.getOwnPropertyNames(GeneratorPrototype).sort(), ["constructor", "next", "return", "throw"]);
|
||||
assertEqArray(Object.getOwnPropertySymbols(GeneratorPrototype), [Symbol.toStringTag]);
|
||||
|
||||
assertOwnDescriptor(GeneratorPrototype, "constructor", {
|
||||
value: GeneratorFunctionPrototype, writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(GeneratorPrototype, "next", {
|
||||
value: GeneratorPrototype.next, writable: true, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(GeneratorPrototype, "return", {
|
||||
value: GeneratorPrototype.return, writable: true, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(GeneratorPrototype, "throw", {
|
||||
value: GeneratorPrototype.throw, writable: true, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
assertOwnDescriptor(GeneratorPrototype, Symbol.toStringTag, {
|
||||
value: "Generator", writable: false, enumerable: false, configurable: true
|
||||
});
|
||||
|
||||
|
||||
if (typeof reportCompare == "function")
|
||||
reportCompare(true, true);
|
|
@ -5,6 +5,7 @@ if (!this.Promise) {
|
|||
quit(0);
|
||||
}
|
||||
|
||||
// Resolve Promise with itself by directly calling the "Promise Resolve Function".
|
||||
let resolve;
|
||||
let promise = new Promise(function(x) { resolve = x; });
|
||||
resolve(promise)
|
||||
|
@ -20,4 +21,23 @@ drainJobQueue()
|
|||
assertEq(results.length, 1);
|
||||
assertEq(results[0], "rejected");
|
||||
|
||||
// Resolve Promise with itself when the "Promise Resolve Function" is called
|
||||
// from (the fast path in) PromiseReactionJob.
|
||||
results = [];
|
||||
|
||||
promise = new Promise(x => { resolve = x; });
|
||||
let promise2 = promise.then(() => promise2);
|
||||
|
||||
promise2.then(() => assertEq(true, false, "not reached"), res => {
|
||||
assertEq(res instanceof TypeError, true);
|
||||
results.push("rejected");
|
||||
});
|
||||
|
||||
resolve();
|
||||
|
||||
drainJobQueue();
|
||||
|
||||
assertEq(results.length, 1);
|
||||
assertEq(results[0], "rejected");
|
||||
|
||||
this.reportCompare && reportCompare(0, 0, "ok");
|
||||
|
|
|
@ -11,7 +11,8 @@ var names = [
|
|||
"hasInstance",
|
||||
"split",
|
||||
"toPrimitive",
|
||||
"unscopables"
|
||||
"unscopables",
|
||||
"asyncIterator"
|
||||
];
|
||||
|
||||
for (var name of names) {
|
||||
|
|
|
@ -9,9 +9,6 @@ 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");
|
||||
|
||||
|
|
|
@ -53,9 +53,8 @@ function asyncFunDecl(id, params, body) {
|
|||
params: params,
|
||||
defaults: [],
|
||||
body: body,
|
||||
generator: true,
|
||||
async: true,
|
||||
style: "es6" });
|
||||
generator: false,
|
||||
async: true });
|
||||
}
|
||||
function varDecl(decls) {
|
||||
return Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" });
|
||||
|
@ -181,9 +180,8 @@ function asyncFunExpr(id, args, body) {
|
|||
id: id,
|
||||
params: args,
|
||||
body: body,
|
||||
generator: true,
|
||||
async: true,
|
||||
style: "es6" });
|
||||
generator: false,
|
||||
async: true });
|
||||
}
|
||||
function arrowExpr(args, body) {
|
||||
return Pattern({ type: "ArrowFunctionExpression",
|
||||
|
@ -194,10 +192,9 @@ function asyncArrowExpr(isExpression, args, body) {
|
|||
return Pattern({ type: "ArrowFunctionExpression",
|
||||
params: args,
|
||||
body: body,
|
||||
generator: true,
|
||||
generator: false,
|
||||
async: true,
|
||||
expression: isExpression,
|
||||
style: "es6" });
|
||||
expression: isExpression });
|
||||
}
|
||||
|
||||
function metaProperty(meta, property) {
|
||||
|
|
|
@ -40,8 +40,11 @@ GlobalObject::initAsyncFunction(JSContext* cx, Handle<GlobalObject*> global)
|
|||
proto));
|
||||
if (!asyncFunction)
|
||||
return false;
|
||||
if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto))
|
||||
if (!LinkConstructorAndPrototype(cx, asyncFunction, asyncFunctionProto,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
global->setReservedSlot(ASYNC_FUNCTION, ObjectValue(*asyncFunction));
|
||||
global->setReservedSlot(ASYNC_FUNCTION_PROTO, ObjectValue(*asyncFunctionProto));
|
||||
|
@ -109,7 +112,7 @@ WrappedAsyncFunction(JSContext* cx, unsigned argc, Value* vp)
|
|||
JSObject*
|
||||
js::WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto)
|
||||
{
|
||||
MOZ_ASSERT(unwrapped->isStarGenerator());
|
||||
MOZ_ASSERT(unwrapped->isAsync());
|
||||
MOZ_ASSERT(proto, "We need an explicit prototype to avoid the default"
|
||||
"%FunctionPrototype% fallback in NewFunctionWithProto().");
|
||||
|
||||
|
@ -171,22 +174,14 @@ AsyncFunctionResume(JSContext* cx, Handle<PromiseObject*> resultPromise, HandleV
|
|||
: cx->names().StarGeneratorThrow;
|
||||
FixedInvokeArgs<1> args(cx);
|
||||
args[0].set(valueOrReason);
|
||||
RootedValue result(cx);
|
||||
if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &result))
|
||||
RootedValue value(cx);
|
||||
if (!CallSelfHostedFunction(cx, funName, generatorVal, args, &value))
|
||||
return AsyncFunctionThrown(cx, resultPromise);
|
||||
|
||||
RootedObject resultObj(cx, &result.toObject());
|
||||
RootedValue doneVal(cx);
|
||||
RootedValue value(cx);
|
||||
if (!GetProperty(cx, resultObj, resultObj, cx->names().done, &doneVal))
|
||||
return false;
|
||||
if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
|
||||
return false;
|
||||
if (generatorVal.toObject().as<GeneratorObject>().isAfterAwait())
|
||||
return AsyncFunctionAwait(cx, resultPromise, value);
|
||||
|
||||
if (doneVal.toBoolean())
|
||||
return AsyncFunctionReturned(cx, resultPromise, value);
|
||||
|
||||
return AsyncFunctionAwait(cx, resultPromise, value);
|
||||
return AsyncFunctionReturned(cx, resultPromise, value);
|
||||
}
|
||||
|
||||
// Async Functions proposal 2.2 steps 3-8.
|
||||
|
@ -242,9 +237,3 @@ js::IsWrappedAsyncFunction(JSFunction* fun)
|
|||
{
|
||||
return fun->maybeNative() == WrappedAsyncFunction;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
js::CheckAsyncResumptionValue(JSContext* cx, HandleValue v)
|
||||
{
|
||||
return CheckStarGeneratorResumptionValue(cx, v);
|
||||
}
|
||||
|
|
|
@ -35,9 +35,6 @@ MOZ_MUST_USE bool
|
|||
AsyncFunctionAwaitedRejected(JSContext* cx, Handle<PromiseObject*> resultPromise,
|
||||
HandleValue generatorVal, HandleValue reason);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
CheckAsyncResumptionValue(JSContext* cx, HandleValue v);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* vm_AsyncFunction_h */
|
||||
|
|
|
@ -0,0 +1,644 @@
|
|||
/* -*- 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 8.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;
|
||||
}
|
||||
|
||||
// Async Iteration proposal 4.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 4.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 11.4.3.7 step 8.d-e.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncGeneratorYieldReturnAwaitedFulfilled(JSContext* cx,
|
||||
Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue value)
|
||||
{
|
||||
return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Return, value);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 11.4.3.7 step 8.d-e.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncGeneratorYieldReturnAwaitedRejected(JSContext* cx,
|
||||
Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue reason)
|
||||
{
|
||||
return AsyncGeneratorResume(cx, asyncGenObj, CompletionKind::Throw, reason);
|
||||
}
|
||||
|
||||
const Class AsyncFromSyncIteratorObject::class_ = {
|
||||
"AsyncFromSyncIteratorObject",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(AsyncFromSyncIteratorObject::Slots)
|
||||
};
|
||||
|
||||
// Async Iteration proposal 11.1.3.1.
|
||||
JSObject*
|
||||
js::CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter)
|
||||
{
|
||||
// Step 1 (implicit).
|
||||
// Done in bytecode emitted by emitAsyncIterator.
|
||||
|
||||
// Steps 2-4.
|
||||
return AsyncFromSyncIteratorObject::create(cx, iter);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 11.1.3.1 steps 2-4.
|
||||
/* static */ JSObject*
|
||||
AsyncFromSyncIteratorObject::create(JSContext* cx, HandleObject iter)
|
||||
{
|
||||
// Step 2.
|
||||
RootedObject proto(cx, GlobalObject::getOrCreateAsyncFromSyncIteratorPrototype(cx,
|
||||
cx->global()));
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
|
||||
RootedObject obj(cx, NewNativeObjectWithGivenProto(cx, &class_, proto));
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
Handle<AsyncFromSyncIteratorObject*> asyncIter = obj.as<AsyncFromSyncIteratorObject>();
|
||||
|
||||
// Step 3.
|
||||
asyncIter->setIterator(iter);
|
||||
|
||||
// Step 4.
|
||||
return asyncIter;
|
||||
}
|
||||
|
||||
// Async Iteration proposal 11.1.3.2.1 %AsyncFromSyncIteratorPrototype%.next.
|
||||
static bool
|
||||
AsyncFromSyncIteratorNext(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Normal);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 11.1.3.2.2 %AsyncFromSyncIteratorPrototype%.return.
|
||||
static bool
|
||||
AsyncFromSyncIteratorReturn(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Return);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 11.1.3.2.3 %AsyncFromSyncIteratorPrototype%.throw.
|
||||
static bool
|
||||
AsyncFromSyncIteratorThrow(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return AsyncFromSyncIteratorMethod(cx, args, CompletionKind::Throw);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 11.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 11.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 11.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
|
||||
InternalEnqueue(JSContext* cx, HandleArrayObject queue, HandleValue val)
|
||||
{
|
||||
uint32_t length;
|
||||
if (!GetLengthProperty(cx, queue, &length))
|
||||
return false;
|
||||
|
||||
if (length >= MAX_ARRAY_INDEX) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!DefineElement(cx, queue, length, val))
|
||||
return false;
|
||||
return SetLengthProperty(cx, queue, length + 1);
|
||||
}
|
||||
|
||||
static MOZ_MUST_USE bool
|
||||
InternalDequeue(JSContext* cx, HandleArrayObject queue, MutableHandleValue val)
|
||||
{
|
||||
uint32_t length;
|
||||
if (!GetLengthProperty(cx, queue, &length))
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(length != 0, "Queue should not be empty here");
|
||||
|
||||
if (!GetElement(cx, queue, queue, 0, val))
|
||||
return false;
|
||||
|
||||
uint32_t newlength = length - 1;
|
||||
RootedValue tmp(cx);
|
||||
for (uint32_t i = 0; i < newlength; i++) {
|
||||
if (!GetElement(cx, queue, queue, i + 1, &tmp))
|
||||
return false;
|
||||
if (!DefineElement(cx, queue, i, tmp))
|
||||
return false;
|
||||
}
|
||||
ObjectOpResult result;
|
||||
if (!DeleteElement(cx, queue, newlength, result))
|
||||
return false;
|
||||
if (!result) {
|
||||
RootedId id(cx, INT_TO_JSID(newlength));
|
||||
return result.reportError(cx, queue, id);
|
||||
}
|
||||
return SetLengthProperty(cx, queue, newlength);
|
||||
}
|
||||
|
||||
/* 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());
|
||||
RootedValue requestVal(cx, ObjectValue(*request));
|
||||
return InternalEnqueue(cx, queue, requestVal);
|
||||
}
|
||||
|
||||
/* 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());
|
||||
RootedValue requestVal(cx);
|
||||
if (!InternalDequeue(cx, queue, &requestVal))
|
||||
return nullptr;
|
||||
|
||||
return &requestVal.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 11.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 11.4.3.2 AsyncGeneratorStart 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 11.4.3.2 AsyncGeneratorStart 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 11.4.3.7 (partially).
|
||||
// Most steps are done in generator.
|
||||
static MOZ_MUST_USE bool
|
||||
AsyncGeneratorYield(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj, HandleValue value)
|
||||
{
|
||||
// Step 5 is done in bytecode.
|
||||
|
||||
// Step 6.
|
||||
asyncGenObj->setSuspendedYield();
|
||||
|
||||
// Step 9.
|
||||
return AsyncGeneratorResolve(cx, asyncGenObj, value, false);
|
||||
}
|
||||
|
||||
// Async Iteration proposal 4.1 Await steps 2-9.
|
||||
// Async Iteration proposal 8.2.1 yield* steps 6.a.vii, 6.b.ii.7, 6.c.ix.
|
||||
// Async Iteration proposal 11.4.3.2 AsyncGeneratorStart step 5.f-g.
|
||||
// Async Iteration proposal 11.4.3.5 AsyncGeneratorResumeNext
|
||||
// steps 12-14, 16-20.
|
||||
// Execution context switching is handled in generator.
|
||||
MOZ_MUST_USE bool
|
||||
js::AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
CompletionKind completionKind, HandleValue argument)
|
||||
{
|
||||
RootedValue generatorVal(cx, asyncGenObj->generatorVal());
|
||||
|
||||
// 11.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)) {
|
||||
// 11.4.3.2 step 5.d, f.
|
||||
return AsyncGeneratorThrown(cx, asyncGenObj);
|
||||
}
|
||||
|
||||
// 4.1 steps 2-9.
|
||||
if (asyncGenObj->generatorObj()->isAfterAwait())
|
||||
return AsyncGeneratorAwait(cx, asyncGenObj, result);
|
||||
|
||||
// The following code corresponds to the following 3 cases:
|
||||
// * yield
|
||||
// * yield*
|
||||
// * return
|
||||
// For yield and return, property access is done on an internal result
|
||||
// object and it's not observable.
|
||||
// For yield*, it's done on a possibly user-provided result object, and
|
||||
// it's observable.
|
||||
//
|
||||
// Note that IteratorComplete steps in 8.2.1 are done in bytecode.
|
||||
|
||||
// 8.2.1 yield* steps 6.a.vii, 6.b.ii.7, 6.c.ix.
|
||||
RootedObject resultObj(cx, &result.toObject());
|
||||
RootedValue value(cx);
|
||||
|
||||
if (!GetProperty(cx, resultObj, resultObj, cx->names().value, &value))
|
||||
return false;
|
||||
|
||||
if (asyncGenObj->generatorObj()->isAfterYield())
|
||||
return AsyncGeneratorYield(cx, asyncGenObj, value);
|
||||
|
||||
// 11.4.3.2 step 5.d-g.
|
||||
return AsyncGeneratorReturned(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_from_sync_iter_methods[] = {
|
||||
JS_FN("next", AsyncFromSyncIteratorNext, 1, 0),
|
||||
JS_FN("throw", AsyncFromSyncIteratorThrow, 1, 0),
|
||||
JS_FN("return", AsyncFromSyncIteratorReturn, 1, 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 11.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 11.1.3.2 %AsyncFromSyncIteratorPrototype%.
|
||||
RootedObject asyncFromSyncIterProto(
|
||||
cx, GlobalObject::createBlankPrototypeInheriting(cx, global, &PlainObject::class_,
|
||||
asyncIterProto));
|
||||
if (!asyncFromSyncIterProto)
|
||||
return false;
|
||||
if (!DefinePropertiesAndFunctions(cx, asyncFromSyncIterProto, nullptr,
|
||||
async_from_sync_iter_methods) ||
|
||||
!DefineToStringTag(cx, asyncFromSyncIterProto, cx->names().AsyncFromSyncIterator))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Async Iteration proposal 11.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 11.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 11.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_FROM_SYNC_ITERATOR_PROTO, ObjectValue(*asyncFromSyncIterProto));
|
||||
global->setReservedSlot(ASYNC_GENERATOR, ObjectValue(*asyncGenerator));
|
||||
global->setReservedSlot(ASYNC_GENERATOR_FUNCTION, ObjectValue(*asyncGenFunction));
|
||||
global->setReservedSlot(ASYNC_GENERATOR_PROTO, ObjectValue(*asyncGenProto));
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
/* -*- 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);
|
||||
MOZ_MUST_USE bool
|
||||
AsyncGeneratorYieldReturnAwaitedFulfilled(JSContext* cx,
|
||||
Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
HandleValue value);
|
||||
MOZ_MUST_USE bool
|
||||
AsyncGeneratorYieldReturnAwaitedRejected(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_AwaitingYieldReturn corresponds to the case that
|
||||
// AsyncGenerator#return is called while State_Executing,
|
||||
// just like the case that AsyncGenerator#return is called
|
||||
// while State_Completed.
|
||||
State_AwaitingYieldReturn,
|
||||
State_AwaitingReturn,
|
||||
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 isAwaitingYieldReturn() const {
|
||||
return state() == State_AwaitingYieldReturn;
|
||||
}
|
||||
bool isAwaitingReturn() const {
|
||||
return state() == State_AwaitingReturn;
|
||||
}
|
||||
bool isCompleted() const {
|
||||
return state() == State_Completed;
|
||||
}
|
||||
|
||||
void setSuspendedStart() {
|
||||
setState(State_SuspendedStart);
|
||||
}
|
||||
void setSuspendedYield() {
|
||||
setState(State_SuspendedYield);
|
||||
}
|
||||
void setExecuting() {
|
||||
setState(State_Executing);
|
||||
}
|
||||
void setAwaitingYieldReturn() {
|
||||
setState(State_AwaitingYieldReturn);
|
||||
}
|
||||
void setAwaitingReturn() {
|
||||
setState(State_AwaitingReturn);
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
JSObject*
|
||||
CreateAsyncFromSyncIterator(JSContext* cx, HandleObject iter);
|
||||
|
||||
class AsyncFromSyncIteratorObject : public NativeObject
|
||||
{
|
||||
private:
|
||||
enum AsyncFromSyncIteratorObjectSlots {
|
||||
Slot_Iterator = 0,
|
||||
Slots
|
||||
};
|
||||
|
||||
void setIterator(HandleObject iterator_) {
|
||||
setFixedSlot(Slot_Iterator, ObjectValue(*iterator_));
|
||||
}
|
||||
|
||||
public:
|
||||
static const Class class_;
|
||||
|
||||
static JSObject*
|
||||
create(JSContext* cx, HandleObject iter);
|
||||
|
||||
JSObject* iterator() const {
|
||||
return &getFixedSlot(Slot_Iterator).toObject();
|
||||
}
|
||||
};
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
AsyncGeneratorResume(JSContext* cx, Handle<AsyncGeneratorObject*> asyncGenObj,
|
||||
CompletionKind completionKind, HandleValue argument);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* vm_AsyncIteration_h */
|
|
@ -29,7 +29,10 @@
|
|||
macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
|
||||
macro(as, as, "as") \
|
||||
macro(Async, Async, "Async") \
|
||||
macro(AsyncFromSyncIterator, AsyncFromSyncIterator, "Async-from-Sync Iterator") \
|
||||
macro(AsyncFunction, AsyncFunction, "AsyncFunction") \
|
||||
macro(AsyncGenerator, AsyncGenerator, "AsyncGenerator") \
|
||||
macro(AsyncGeneratorFunction, AsyncGeneratorFunction, "AsyncGeneratorFunction") \
|
||||
macro(AsyncWrapped, AsyncWrapped, "AsyncWrapped") \
|
||||
macro(async, async, "async") \
|
||||
macro(await, await, "await") \
|
||||
|
@ -311,6 +314,7 @@
|
|||
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") \
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include "js/Vector.h"
|
||||
#include "proxy/ScriptedProxyHandler.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/AsyncFunction.h"
|
||||
#include "vm/DebuggerMemory.h"
|
||||
#include "vm/GeneratorObject.h"
|
||||
#include "vm/SPSProfiler.h"
|
||||
|
@ -1560,16 +1559,11 @@ CheckResumptionValue(JSContext* cx, AbstractFramePtr frame, const Maybe<HandleVa
|
|||
JSTrapStatus status, MutableHandleValue vp)
|
||||
{
|
||||
if (status == JSTRAP_RETURN && frame && frame.isFunctionFrame()) {
|
||||
// Don't let a { return: ... } resumption value make a generator or
|
||||
// async function violate the iterator protocol. The return value from
|
||||
// Don't let a { return: ... } resumption value make a generator
|
||||
// function violate the iterator protocol. The return value from
|
||||
// such a frame must have the form { done: <bool>, value: <anything> }.
|
||||
RootedFunction callee(cx, frame.callee());
|
||||
if (callee->isAsync()) {
|
||||
if (!CheckAsyncResumptionValue(cx, vp)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_AWAIT);
|
||||
return false;
|
||||
}
|
||||
} else if (callee->isStarGenerator()) {
|
||||
if (callee->isStarGenerator()) {
|
||||
if (!CheckStarGeneratorResumptionValue(cx, vp)) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_YIELD);
|
||||
return false;
|
||||
|
@ -7356,7 +7350,8 @@ DebuggerFrame::getEnvironment(JSContext* cx, HandleDebuggerFrame frame,
|
|||
/* static */ bool
|
||||
DebuggerFrame::getIsGenerator(HandleDebuggerFrame frame)
|
||||
{
|
||||
return DebuggerFrame::getReferent(frame).script()->isGenerator();
|
||||
return DebuggerFrame::getReferent(frame).script()->isStarGenerator() ||
|
||||
DebuggerFrame::getReferent(frame).script()->isLegacyGenerator();
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
|
|
@ -2448,7 +2448,9 @@ DebugEnvironments::addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
|
|||
MOZ_ASSERT(cx->compartment() == debugEnv->compartment());
|
||||
// Generators should always have environments.
|
||||
MOZ_ASSERT_IF(ei.scope().is<FunctionScope>(),
|
||||
!ei.scope().as<FunctionScope>().canonicalFunction()->isGenerator());
|
||||
!ei.scope().as<FunctionScope>().canonicalFunction()->isStarGenerator() &&
|
||||
!ei.scope().as<FunctionScope>().canonicalFunction()->isLegacyGenerator() &&
|
||||
!ei.scope().as<FunctionScope>().canonicalFunction()->isAsync());
|
||||
|
||||
if (!CanUseDebugEnvironmentMaps(cx))
|
||||
return true;
|
||||
|
@ -2594,8 +2596,11 @@ DebugEnvironments::onPopCall(JSContext* cx, AbstractFramePtr frame)
|
|||
if (!frame.environmentChain()->is<CallObject>())
|
||||
return;
|
||||
|
||||
if (frame.callee()->isGenerator())
|
||||
if (frame.callee()->isStarGenerator() || frame.callee()->isLegacyGenerator() ||
|
||||
frame.callee()->isAsync())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CallObject& callobj = frame.environmentChain()->as<CallObject>();
|
||||
envs->liveEnvs.remove(&callobj);
|
||||
|
@ -2726,8 +2731,13 @@ DebugEnvironments::updateLiveEnvironments(JSContext* cx)
|
|||
if (frame.environmentChain()->compartment() != cx->compartment())
|
||||
continue;
|
||||
|
||||
if (frame.isFunctionFrame() && frame.callee()->isGenerator())
|
||||
continue;
|
||||
if (frame.isFunctionFrame()) {
|
||||
if (frame.callee()->isStarGenerator() || frame.callee()->isLegacyGenerator() ||
|
||||
frame.callee()->isAsync())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!frame.isDebuggee())
|
||||
continue;
|
||||
|
@ -2882,7 +2892,8 @@ GetDebugEnvironmentForMissing(JSContext* cx, const EnvironmentIter& ei)
|
|||
if (ei.scope().is<FunctionScope>()) {
|
||||
RootedFunction callee(cx, ei.scope().as<FunctionScope>().canonicalFunction());
|
||||
// Generators should always reify their scopes.
|
||||
MOZ_ASSERT(!callee->isGenerator());
|
||||
MOZ_ASSERT(!callee->isStarGenerator() && !callee->isLegacyGenerator() &&
|
||||
!callee->isAsync());
|
||||
|
||||
JS::ExposeObjectToActiveJS(callee);
|
||||
Rooted<CallObject*> callobj(cx, CallObject::createHollowForDebug(cx, callee));
|
||||
|
|
|
@ -19,12 +19,13 @@ using namespace js;
|
|||
JSObject*
|
||||
GeneratorObject::create(JSContext* cx, AbstractFramePtr frame)
|
||||
{
|
||||
MOZ_ASSERT(frame.script()->isGenerator());
|
||||
MOZ_ASSERT(frame.script()->isStarGenerator() || frame.script()->isLegacyGenerator() ||
|
||||
frame.script()->isAsync());
|
||||
MOZ_ASSERT(frame.script()->nfixed() == 0);
|
||||
|
||||
Rooted<GlobalObject*> global(cx, cx->global());
|
||||
RootedNativeObject obj(cx);
|
||||
if (frame.script()->isStarGenerator()) {
|
||||
if (frame.script()->isStarGenerator() || frame.script()->isAsync()) {
|
||||
RootedValue pval(cx);
|
||||
RootedObject fun(cx, frame.callee());
|
||||
// FIXME: This would be faster if we could avoid doing a lookup to get
|
||||
|
@ -63,10 +64,14 @@ bool
|
|||
GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
|
||||
Value* vp, unsigned nvalues)
|
||||
{
|
||||
MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD);
|
||||
MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD || *pc == JSOP_AWAIT);
|
||||
|
||||
Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
|
||||
MOZ_ASSERT(!genObj->hasExpressionStack());
|
||||
MOZ_ASSERT_IF(*pc == JSOP_AWAIT, genObj->callee().isAsync());
|
||||
MOZ_ASSERT_IF(*pc == JSOP_YIELD,
|
||||
genObj->callee().isStarGenerator() ||
|
||||
genObj->callee().isLegacyGenerator());
|
||||
|
||||
if (*pc == JSOP_YIELD && genObj->isClosing() && genObj->is<LegacyGeneratorObject>()) {
|
||||
RootedValue val(cx, ObjectValue(*frame.callee()));
|
||||
|
@ -74,8 +79,8 @@ GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32_t yieldIndex = GET_UINT24(pc);
|
||||
genObj->setYieldIndex(yieldIndex);
|
||||
uint32_t yieldAndAwaitIndex = GET_UINT24(pc);
|
||||
genObj->setYieldAndAwaitIndex(yieldAndAwaitIndex);
|
||||
genObj->setEnvironmentChain(*frame.environmentChain());
|
||||
|
||||
if (nvalues) {
|
||||
|
@ -172,7 +177,7 @@ GeneratorObject::resume(JSContext* cx, InterpreterActivation& activation,
|
|||
}
|
||||
|
||||
JSScript* script = callee->nonLazyScript();
|
||||
uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()];
|
||||
uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
|
||||
activation.regs().pc = script->offsetToPC(offset);
|
||||
|
||||
// Always push on a value, even if we are raising an exception. In the
|
||||
|
@ -311,7 +316,8 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global)
|
|||
RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
|
||||
if (!genFunctionProto || !JSObject::setDelegate(cx, genFunctionProto))
|
||||
return false;
|
||||
if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto) ||
|
||||
if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto, JSPROP_READONLY,
|
||||
JSPROP_READONLY) ||
|
||||
!DefineToStringTag(cx, genFunctionProto, cx->names().GeneratorFunction))
|
||||
{
|
||||
return false;
|
||||
|
@ -328,8 +334,11 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global)
|
|||
SingletonObject));
|
||||
if (!genFunction)
|
||||
return false;
|
||||
if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
|
||||
if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto,
|
||||
JSPROP_PERMANENT | JSPROP_READONLY, JSPROP_READONLY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
global->setReservedSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
|
||||
global->setReservedSlot(STAR_GENERATOR_FUNCTION, ObjectValue(*genFunction));
|
||||
|
@ -365,3 +374,34 @@ js::CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GeneratorObject::isAfterYield()
|
||||
{
|
||||
return isAfterYieldOrAwait(JSOP_YIELD);
|
||||
}
|
||||
|
||||
bool
|
||||
GeneratorObject::isAfterAwait()
|
||||
{
|
||||
return isAfterYieldOrAwait(JSOP_AWAIT);
|
||||
}
|
||||
|
||||
bool
|
||||
GeneratorObject::isAfterYieldOrAwait(JSOp op)
|
||||
{
|
||||
if (isClosed() || isClosing() || isRunning())
|
||||
return false;
|
||||
|
||||
JSScript* script = callee().nonLazyScript();
|
||||
jsbytecode* code = script->code();
|
||||
uint32_t nextOffset = script->yieldAndAwaitOffsets()[yieldAndAwaitIndex()];
|
||||
if (code[nextOffset] != JSOP_DEBUGAFTERYIELD)
|
||||
return false;
|
||||
|
||||
uint32_t offset = nextOffset - JSOP_YIELD_LENGTH;
|
||||
MOZ_ASSERT(code[offset] == JSOP_INITIALYIELD || code[offset] == JSOP_YIELD ||
|
||||
code[offset] == JSOP_AWAIT);
|
||||
|
||||
return code[offset] == op;
|
||||
}
|
||||
|
|
|
@ -21,15 +21,15 @@ class GeneratorObject : public NativeObject
|
|||
public:
|
||||
// Magic values stored in the yield index slot when the generator is
|
||||
// running or closing. See the yield index comment below.
|
||||
static const int32_t YIELD_INDEX_RUNNING = INT32_MAX;
|
||||
static const int32_t YIELD_INDEX_CLOSING = INT32_MAX - 1;
|
||||
static const int32_t YIELD_AND_AWAIT_INDEX_RUNNING = INT32_MAX;
|
||||
static const int32_t YIELD_AND_AWAIT_INDEX_CLOSING = INT32_MAX - 1;
|
||||
|
||||
enum {
|
||||
CALLEE_SLOT = 0,
|
||||
ENV_CHAIN_SLOT,
|
||||
ARGS_OBJ_SLOT,
|
||||
EXPRESSION_STACK_SLOT,
|
||||
YIELD_INDEX_SLOT,
|
||||
YIELD_AND_AWAIT_INDEX_SLOT,
|
||||
NEWTARGET_SLOT,
|
||||
RESERVED_SLOTS
|
||||
};
|
||||
|
@ -124,47 +124,48 @@ class GeneratorObject : public NativeObject
|
|||
// The yield index slot is abused for a few purposes. It's undefined if
|
||||
// it hasn't been set yet (before the initial yield), and null if the
|
||||
// generator is closed. If the generator is running, the yield index is
|
||||
// YIELD_INDEX_RUNNING. If the generator is in that bizarre "closing"
|
||||
// state, the yield index is YIELD_INDEX_CLOSING.
|
||||
// YIELD_AND_AWAIT_INDEX_RUNNING. If the generator is in that bizarre
|
||||
// "closing" state, the yield index is YIELD_AND_AWAIT_INDEX_CLOSING.
|
||||
//
|
||||
// If the generator is suspended, it's the yield index (stored as
|
||||
// JSOP_INITIALYIELD/JSOP_YIELD operand) of the yield instruction that
|
||||
// suspended the generator. The yield index can be mapped to the bytecode
|
||||
// offset (interpreter) or to the native code offset (JIT).
|
||||
// JSOP_INITIALYIELD/JSOP_YIELD/JSOP_AWAIT operand) of the yield
|
||||
// instruction that suspended the generator. The yield index can be mapped
|
||||
// to the bytecode offset (interpreter) or to the native code offset (JIT).
|
||||
|
||||
bool isRunning() const {
|
||||
MOZ_ASSERT(!isClosed());
|
||||
return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_RUNNING;
|
||||
return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() == YIELD_AND_AWAIT_INDEX_RUNNING;
|
||||
}
|
||||
bool isClosing() const {
|
||||
return getFixedSlot(YIELD_INDEX_SLOT).toInt32() == YIELD_INDEX_CLOSING;
|
||||
return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() == YIELD_AND_AWAIT_INDEX_CLOSING;
|
||||
}
|
||||
bool isSuspended() const {
|
||||
// Note: also update Baseline's IsSuspendedStarGenerator code if this
|
||||
// changes.
|
||||
MOZ_ASSERT(!isClosed());
|
||||
static_assert(YIELD_INDEX_CLOSING < YIELD_INDEX_RUNNING,
|
||||
"test below should return false for YIELD_INDEX_RUNNING");
|
||||
return getFixedSlot(YIELD_INDEX_SLOT).toInt32() < YIELD_INDEX_CLOSING;
|
||||
static_assert(YIELD_AND_AWAIT_INDEX_CLOSING < YIELD_AND_AWAIT_INDEX_RUNNING,
|
||||
"test below should return false for YIELD_AND_AWAIT_INDEX_RUNNING");
|
||||
return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() < YIELD_AND_AWAIT_INDEX_CLOSING;
|
||||
}
|
||||
void setRunning() {
|
||||
MOZ_ASSERT(isSuspended());
|
||||
setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_RUNNING));
|
||||
setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_RUNNING));
|
||||
}
|
||||
void setClosing() {
|
||||
MOZ_ASSERT(isSuspended());
|
||||
setFixedSlot(YIELD_INDEX_SLOT, Int32Value(YIELD_INDEX_CLOSING));
|
||||
setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_CLOSING));
|
||||
}
|
||||
void setYieldIndex(uint32_t yieldIndex) {
|
||||
MOZ_ASSERT_IF(yieldIndex == 0, getFixedSlot(YIELD_INDEX_SLOT).isUndefined());
|
||||
MOZ_ASSERT_IF(yieldIndex != 0, isRunning() || isClosing());
|
||||
MOZ_ASSERT(yieldIndex < uint32_t(YIELD_INDEX_CLOSING));
|
||||
setFixedSlot(YIELD_INDEX_SLOT, Int32Value(yieldIndex));
|
||||
void setYieldAndAwaitIndex(uint32_t yieldAndAwaitIndex) {
|
||||
MOZ_ASSERT_IF(yieldAndAwaitIndex == 0,
|
||||
getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).isUndefined());
|
||||
MOZ_ASSERT_IF(yieldAndAwaitIndex != 0, isRunning() || isClosing());
|
||||
MOZ_ASSERT(yieldAndAwaitIndex < uint32_t(YIELD_AND_AWAIT_INDEX_CLOSING));
|
||||
setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(yieldAndAwaitIndex));
|
||||
MOZ_ASSERT(isSuspended());
|
||||
}
|
||||
uint32_t yieldIndex() const {
|
||||
uint32_t yieldAndAwaitIndex() const {
|
||||
MOZ_ASSERT(isSuspended());
|
||||
return getFixedSlot(YIELD_INDEX_SLOT).toInt32();
|
||||
return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32();
|
||||
}
|
||||
bool isClosed() const {
|
||||
return getFixedSlot(CALLEE_SLOT).isNull();
|
||||
|
@ -174,10 +175,17 @@ class GeneratorObject : public NativeObject
|
|||
setFixedSlot(ENV_CHAIN_SLOT, NullValue());
|
||||
setFixedSlot(ARGS_OBJ_SLOT, NullValue());
|
||||
setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
|
||||
setFixedSlot(YIELD_INDEX_SLOT, NullValue());
|
||||
setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, NullValue());
|
||||
setFixedSlot(NEWTARGET_SLOT, NullValue());
|
||||
}
|
||||
|
||||
bool isAfterYield();
|
||||
bool isAfterAwait();
|
||||
|
||||
private:
|
||||
bool isAfterYieldOrAwait(JSOp op);
|
||||
|
||||
public:
|
||||
static size_t offsetOfCalleeSlot() {
|
||||
return getFixedSlotOffset(CALLEE_SLOT);
|
||||
}
|
||||
|
@ -187,8 +195,8 @@ class GeneratorObject : public NativeObject
|
|||
static size_t offsetOfArgsObjSlot() {
|
||||
return getFixedSlotOffset(ARGS_OBJ_SLOT);
|
||||
}
|
||||
static size_t offsetOfYieldIndexSlot() {
|
||||
return getFixedSlotOffset(YIELD_INDEX_SLOT);
|
||||
static size_t offsetOfYieldAndAwaitIndexSlot() {
|
||||
return getFixedSlotOffset(YIELD_AND_AWAIT_INDEX_SLOT);
|
||||
}
|
||||
static size_t offsetOfExpressionStackSlot() {
|
||||
return getFixedSlotOffset(EXPRESSION_STACK_SLOT);
|
||||
|
|
|
@ -586,17 +586,18 @@ GlobalObject::createBlankPrototypeInheriting(JSContext* cx, Handle<GlobalObject*
|
|||
}
|
||||
|
||||
bool
|
||||
js::LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor_, JSObject* proto_)
|
||||
js::LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor_, JSObject* proto_,
|
||||
unsigned prototypeAttrs, unsigned constructorAttrs)
|
||||
{
|
||||
RootedObject ctor(cx, ctor_), proto(cx, proto_);
|
||||
|
||||
RootedValue protoVal(cx, ObjectValue(*proto));
|
||||
RootedValue ctorVal(cx, ObjectValue(*ctor));
|
||||
|
||||
return DefineProperty(cx, ctor, cx->names().prototype, protoVal,
|
||||
nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY) &&
|
||||
DefineProperty(cx, proto, cx->names().constructor, ctorVal,
|
||||
nullptr, nullptr, 0);
|
||||
return DefineProperty(cx, ctor, cx->names().prototype, protoVal, nullptr, nullptr,
|
||||
prototypeAttrs) &&
|
||||
DefineProperty(cx, proto, cx->names().constructor, ctorVal, nullptr, nullptr,
|
||||
constructorAttrs);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -100,6 +100,11 @@ class GlobalObject : public NativeObject
|
|||
STAR_GENERATOR_FUNCTION,
|
||||
ASYNC_FUNCTION_PROTO,
|
||||
ASYNC_FUNCTION,
|
||||
ASYNC_ITERATOR_PROTO,
|
||||
ASYNC_FROM_SYNC_ITERATOR_PROTO,
|
||||
ASYNC_GENERATOR,
|
||||
ASYNC_GENERATOR_FUNCTION,
|
||||
ASYNC_GENERATOR_PROTO,
|
||||
MAP_ITERATOR_PROTO,
|
||||
SET_ITERATOR_PROTO,
|
||||
COLLATOR_PROTO,
|
||||
|
@ -624,6 +629,36 @@ 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*
|
||||
getOrCreateAsyncFromSyncIteratorPrototype(JSContext* cx, Handle<GlobalObject*> global) {
|
||||
return MaybeNativeObject(getOrCreateObject(cx, global, ASYNC_FROM_SYNC_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);
|
||||
|
@ -782,6 +817,8 @@ 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);
|
||||
|
@ -985,12 +1022,14 @@ GlobalObject::createArrayFromBuffer<uint8_clamped>() const
|
|||
}
|
||||
|
||||
/*
|
||||
* Define ctor.prototype = proto as non-enumerable, non-configurable, and
|
||||
* non-writable; define proto.constructor = ctor as non-enumerable but
|
||||
* configurable and writable.
|
||||
* Unless otherwise specified, define ctor.prototype = proto as non-enumerable,
|
||||
* non-configurable, and non-writable; and define proto.constructor = ctor as
|
||||
* non-enumerable but configurable and writable.
|
||||
*/
|
||||
extern bool
|
||||
LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor, JSObject* proto);
|
||||
LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor, JSObject* proto,
|
||||
unsigned prototypeAttrs = JSPROP_PERMANENT | JSPROP_READONLY,
|
||||
unsigned constructorAttrs = 0);
|
||||
|
||||
/*
|
||||
* Define properties and/or functions on any object. Either ps or fs, or both,
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#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"
|
||||
|
@ -1939,9 +1940,6 @@ CASE(EnableInterruptsPseudoOpcode)
|
|||
CASE(JSOP_NOP)
|
||||
CASE(JSOP_NOP_DESTRUCTURING)
|
||||
CASE(JSOP_UNUSED126)
|
||||
CASE(JSOP_UNUSED192)
|
||||
CASE(JSOP_UNUSED209)
|
||||
CASE(JSOP_UNUSED210)
|
||||
CASE(JSOP_UNUSED211)
|
||||
CASE(JSOP_TRY_DESTRUCTURING_ITERCLOSE)
|
||||
CASE(JSOP_UNUSED221)
|
||||
|
@ -3585,6 +3583,29 @@ CASE(JSOP_TOASYNC)
|
|||
}
|
||||
END_CASE(JSOP_TOASYNC)
|
||||
|
||||
CASE(JSOP_TOASYNCGEN)
|
||||
{
|
||||
ReservedRooted<JSFunction*> unwrapped(&rootFunction0,
|
||||
®S.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_TOASYNCITER)
|
||||
{
|
||||
ReservedRooted<JSObject*> iter(&rootObject1, ®S.sp[-1].toObject());
|
||||
JSObject* asyncIter = CreateAsyncFromSyncIterator(cx, iter);
|
||||
if (!asyncIter)
|
||||
goto error;
|
||||
|
||||
REGS.sp[-1].setObject(*asyncIter);
|
||||
}
|
||||
END_CASE(JSOP_TOASYNCITER)
|
||||
|
||||
CASE(JSOP_SETFUNNAME)
|
||||
{
|
||||
MOZ_ASSERT(REGS.stackDepth() >= 2);
|
||||
|
@ -3994,6 +4015,7 @@ CASE(JSOP_INITIALYIELD)
|
|||
}
|
||||
|
||||
CASE(JSOP_YIELD)
|
||||
CASE(JSOP_AWAIT)
|
||||
{
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
MOZ_ASSERT(REGS.fp()->isFunctionFrame());
|
||||
|
@ -5126,6 +5148,10 @@ js::ThrowCheckIsObject(JSContext* cx, CheckIsObjectKind kind)
|
|||
case CheckIsObjectKind::GetIterator:
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_GET_ITER_RETURNED_PRIMITIVE);
|
||||
break;
|
||||
case CheckIsObjectKind::GetAsyncIterator:
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_GET_ASYNC_ITER_RETURNED_PRIMITIVE);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unknown kind");
|
||||
}
|
||||
|
|
|
@ -561,7 +561,8 @@ enum class CheckIsObjectKind : uint8_t {
|
|||
IteratorNext,
|
||||
IteratorReturn,
|
||||
IteratorThrow,
|
||||
GetIterator
|
||||
GetIterator,
|
||||
GetAsyncIterator
|
||||
};
|
||||
|
||||
bool
|
||||
|
|
|
@ -184,7 +184,7 @@ ObjectGroup::useSingletonForNewObject(JSContext* cx, JSScript* script, jsbytecod
|
|||
* Sub2 lets us continue to distinguish the two subclasses and any extra
|
||||
* properties added to those prototype objects.
|
||||
*/
|
||||
if (script->isGenerator())
|
||||
if (script->isStarGenerator() || script->isLegacyGenerator() || script->isAsync())
|
||||
return false;
|
||||
if (JSOp(*pc) != JSOP_NEW)
|
||||
return false;
|
||||
|
|
|
@ -1952,7 +1952,15 @@
|
|||
* Stack: this => this
|
||||
*/ \
|
||||
macro(JSOP_CHECKTHISREINIT,191,"checkthisreinit",NULL,1, 1, 1, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED192, 192,"unused192", NULL, 1, 0, 0, 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) \
|
||||
\
|
||||
/*
|
||||
* Pops the top two values on the stack as 'propval' and 'obj', pushes
|
||||
|
@ -2055,7 +2063,7 @@
|
|||
* interpretation.
|
||||
* Category: Statements
|
||||
* Type: Generator
|
||||
* Operands: uint24_t yieldIndex
|
||||
* Operands: uint24_t yieldAndAwaitIndex
|
||||
* Stack: generator =>
|
||||
*/ \
|
||||
macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 4, 1, 1, JOF_UINT24) \
|
||||
|
@ -2064,7 +2072,7 @@
|
|||
* returns 'rval1'. Pushes sent value from 'send()' onto the stack.
|
||||
* Category: Statements
|
||||
* Type: Generator
|
||||
* Operands: uint24_t yieldIndex
|
||||
* Operands: uint24_t yieldAndAwaitIndex
|
||||
* Stack: rval1, gen => rval2
|
||||
*/ \
|
||||
macro(JSOP_YIELD, 203,"yield", NULL, 4, 2, 1, JOF_UINT24) \
|
||||
|
@ -2119,8 +2127,24 @@
|
|||
* Stack: =>
|
||||
*/ \
|
||||
macro(JSOP_DEBUGAFTERYIELD, 208, "debugafteryield", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED209, 209, "unused209", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED210, 210, "unused210", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
/*
|
||||
* Pops the generator and the return value 'promise', stops interpretation
|
||||
* and returns 'promise'. Pushes resolved value onto the stack.
|
||||
* Category: Statements
|
||||
* Type: Generator
|
||||
* Operands: uint24_t yieldAndAwaitIndex
|
||||
* Stack: promise, gen => resolved
|
||||
*/ \
|
||||
macro(JSOP_AWAIT, 209, "await", NULL, 4, 2, 1, JOF_UINT24) \
|
||||
/*
|
||||
* Pops the iterator from the top of the stack, and create async iterator
|
||||
* from it and push the async iterator back onto the stack.
|
||||
* Category: Statements
|
||||
* Type: Generator
|
||||
* Operands:
|
||||
* Stack: iter => asynciter
|
||||
*/ \
|
||||
macro(JSOP_TOASYNCITER, 210, "toasynciter", NULL, 1, 1, 1, JOF_BYTE) \
|
||||
macro(JSOP_UNUSED211, 211, "unused211", NULL, 1, 0, 0, JOF_BYTE) \
|
||||
/*
|
||||
* Initializes generator frame, creates a generator and pushes it on the
|
||||
|
|
|
@ -41,7 +41,10 @@ probes::EnterScript(JSContext* cx, JSScript* script, JSFunction* maybeFun,
|
|||
if (rt->spsProfiler.enabled()) {
|
||||
if (!rt->spsProfiler.enter(cx, script, maybeFun))
|
||||
return false;
|
||||
MOZ_ASSERT_IF(!fp->script()->isGenerator(), !fp->hasPushedSPSFrame());
|
||||
MOZ_ASSERT_IF(!fp->script()->isStarGenerator() &&
|
||||
!fp->script()->isLegacyGenerator() &&
|
||||
!fp->script()->isAsync(),
|
||||
!fp->hasPushedSPSFrame());
|
||||
fp->setPushedSPSFrame();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "builtin/MapObject.h"
|
||||
#include "builtin/ModuleObject.h"
|
||||
#include "builtin/Object.h"
|
||||
#include "builtin/Promise.h"
|
||||
#include "builtin/Reflect.h"
|
||||
#include "builtin/SelfHostingDefines.h"
|
||||
#include "builtin/SIMD.h"
|
||||
|
@ -2135,6 +2136,105 @@ intrinsic_PromiseResolve(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_CreatePendingPromise(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 0);
|
||||
RootedObject promise(cx, PromiseObject::createSkippingExecutor(cx));
|
||||
if (!promise)
|
||||
return false;
|
||||
args.rval().setObject(*promise);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_CreatePromiseResolvedWith(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
RootedObject promise(cx, PromiseObject::unforgeableResolve(cx, args[0]));
|
||||
if (!promise)
|
||||
return false;
|
||||
args.rval().setObject(*promise);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_CreatePromiseRejectedWith(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
RootedObject promise(cx, PromiseObject::unforgeableReject(cx, args[0]));
|
||||
if (!promise)
|
||||
return false;
|
||||
args.rval().setObject(*promise);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_ResolvePromise(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 2);
|
||||
Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
|
||||
if (!PromiseObject::resolve(cx, promise, args[1]))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_RejectPromise(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 2);
|
||||
Rooted<PromiseObject*> promise(cx, &args[0].toObject().as<PromiseObject>());
|
||||
if (!PromiseObject::reject(cx, promise, args[1]))
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_CallOriginalPromiseThen(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() >= 2);
|
||||
|
||||
RootedObject promise(cx, &args[0].toObject());
|
||||
Value val = args[1];
|
||||
RootedObject onResolvedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
|
||||
val = args.get(2);
|
||||
RootedObject onRejectedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
|
||||
|
||||
RootedObject resultPromise(cx, JS::CallOriginalPromiseThen(cx, promise, onResolvedObj,
|
||||
onRejectedObj));
|
||||
if (!resultPromise)
|
||||
return false;
|
||||
args.rval().setObject(*resultPromise);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_AddPromiseReactions(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() >= 2);
|
||||
|
||||
RootedObject promise(cx, &args[0].toObject());
|
||||
Value val = args[1];
|
||||
RootedObject onResolvedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
|
||||
val = args.get(2);
|
||||
RootedObject onRejectedObj(cx, val.isUndefined() ? nullptr : val.toObjectOrNull());
|
||||
|
||||
bool result = JS::AddPromiseReactions(cx, promise, onResolvedObj, onRejectedObj);
|
||||
if (!result)
|
||||
return false;
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
// The self-hosting global isn't initialized with the normal set of builtins.
|
||||
// Instead, individual C++-implemented functions that're required by
|
||||
// self-hosted code are defined as global functions. Accessing these
|
||||
|
@ -2536,6 +2636,14 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0),
|
||||
JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0),
|
||||
|
||||
JS_FN("CreatePendingPromise", intrinsic_CreatePendingPromise, 0, 0),
|
||||
JS_FN("CreatePromiseResolvedWith", intrinsic_CreatePromiseResolvedWith, 1, 0),
|
||||
JS_FN("CreatePromiseRejectedWith", intrinsic_CreatePromiseRejectedWith, 1, 0),
|
||||
JS_FN("ResolvePromise", intrinsic_ResolvePromise, 2, 0),
|
||||
JS_FN("RejectPromise", intrinsic_RejectPromise, 2, 0),
|
||||
JS_FN("AddPromiseReactions", intrinsic_AddPromiseReactions, 3, 0),
|
||||
JS_FN("CallOriginalPromiseThen", intrinsic_CallOriginalPromiseThen, 3, 0),
|
||||
|
||||
JS_FN("IsPromiseObject", intrinsic_IsInstanceOfBuiltin<PromiseObject>, 1, 0),
|
||||
JS_FN("CallPromiseMethodIfWrapped", CallNonGenericSelfhostedMethod<Is<PromiseObject>>, 2, 0),
|
||||
JS_FN("PromiseResolve", intrinsic_PromiseResolve, 2, 0),
|
||||
|
@ -3005,7 +3113,8 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name,
|
|||
return false;
|
||||
// JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
|
||||
// aren't any.
|
||||
MOZ_ASSERT(!sourceFun->isGenerator());
|
||||
MOZ_ASSERT(!sourceFun->isStarGenerator() && !sourceFun->isLegacyGenerator() &&
|
||||
!sourceFun->isAsync());
|
||||
MOZ_ASSERT(targetFun->isExtended());
|
||||
MOZ_ASSERT(targetFun->isInterpretedLazy());
|
||||
MOZ_ASSERT(targetFun->isSelfHostedBuiltin());
|
||||
|
|
|
@ -335,7 +335,7 @@ InterpreterStack::resumeGeneratorCallFrame(JSContext* cx, InterpreterRegs& regs,
|
|||
HandleFunction callee, HandleValue newTarget,
|
||||
HandleObject envChain)
|
||||
{
|
||||
MOZ_ASSERT(callee->isGenerator());
|
||||
MOZ_ASSERT(callee->isStarGenerator() || callee->isLegacyGenerator() || callee->isAsync());
|
||||
RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee));
|
||||
InterpreterFrame* prev = regs.fp();
|
||||
jsbytecode* prevpc = regs.pc;
|
||||
|
|
|
@ -270,7 +270,9 @@ InterpreterFrame::epilogue(JSContext* cx, jsbytecode* pc)
|
|||
UnwindAllEnvironmentsInFrame(cx, ei);
|
||||
|
||||
if (isFunctionFrame()) {
|
||||
if (!callee().isGenerator() &&
|
||||
if (!callee().isStarGenerator() &&
|
||||
!callee().isLegacyGenerator() &&
|
||||
!callee().isAsync() &&
|
||||
isConstructing() &&
|
||||
thisArgument().isObject() &&
|
||||
returnValue().isPrimitive())
|
||||
|
|
|
@ -693,7 +693,8 @@ class InterpreterFrame
|
|||
}
|
||||
|
||||
void resumeGeneratorFrame(JSObject* envChain) {
|
||||
MOZ_ASSERT(script()->isGenerator());
|
||||
MOZ_ASSERT(script()->isStarGenerator() || script()->isLegacyGenerator() ||
|
||||
script()->isAsync());
|
||||
MOZ_ASSERT(isFunctionFrame());
|
||||
flags_ |= HAS_INITIAL_ENV;
|
||||
envChain_ = envChain;
|
||||
|
|
|
@ -8608,9 +8608,12 @@ EstablishPreconditions(ExclusiveContext* cx, AsmJSParser& parser)
|
|||
break;
|
||||
}
|
||||
|
||||
if (parser.pc->isGenerator())
|
||||
if (parser.pc->isStarGenerator() || parser.pc->isLegacyGenerator())
|
||||
return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by generator context");
|
||||
|
||||
if (parser.pc->isAsync())
|
||||
return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by async context");
|
||||
|
||||
if (parser.pc->isArrowFunction())
|
||||
return Warn(parser, JSMSG_USE_ASM_TYPE_FAIL, "Disabled by arrow function context");
|
||||
|
||||
|
|
Loading…
Reference in New Issue