summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp24
-rw-r--r--js/src/frontend/BytecodeEmitter.h12
-rw-r--r--js/src/frontend/FullParseHandler.h2
-rw-r--r--js/src/jit/BaselineCompiler.cpp49
-rw-r--r--js/src/jit/BaselineCompiler.h9
-rw-r--r--js/src/jit/BaselineIC.cpp7
-rw-r--r--js/src/jit/BaselineJIT.cpp6
-rw-r--r--js/src/jit/BaselineJIT.h2
-rw-r--r--js/src/jit/VMFunctions.cpp4
-rw-r--r--js/src/jsopcode.h3
-rw-r--r--js/src/jsscript.cpp36
-rw-r--r--js/src/jsscript.h17
-rw-r--r--js/src/vm/GeneratorObject.cpp12
-rw-r--r--js/src/vm/GeneratorObject.h53
-rw-r--r--js/src/vm/Interpreter.cpp2
-rw-r--r--js/src/vm/Opcodes.h14
16 files changed, 142 insertions, 110 deletions
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index b8a9bdf7e..6a6deed12 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2046,7 +2046,7 @@ class ForOfLoopControl : public LoopControl
return false;
MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
- numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldOffsetList.numYields;
+ numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldAndAwaitOffsetList.numYields;
return true;
}
@@ -2088,7 +2088,7 @@ class ForOfLoopControl : public LoopControl
// If any yields were emitted, then this for-of loop is inside a star
// generator and must handle the case of Generator.return. Like in
// yield*, it is handled with a finally block.
- uint32_t numYieldsEmitted = bce->yieldOffsetList.numYields;
+ uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
if (!tryCatch_->emitFinally())
return false;
@@ -2190,7 +2190,7 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
scopeList(cx),
tryNoteList(cx),
scopeNoteList(cx),
- yieldOffsetList(cx),
+ yieldAndAwaitOffsetList(cx),
typesetCount(0),
hasSingletons(false),
hasTryFinally(false),
@@ -4798,26 +4798,26 @@ BytecodeEmitter::emitYieldOp(JSOp op)
if (op == JSOP_FINALYIELDRVAL)
return emit1(JSOP_FINALYIELDRVAL);
- MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD);
+ MOZ_ASSERT(op == JSOP_INITIALYIELD || op == JSOP_YIELD || op == JSOP_AWAIT);
ptrdiff_t off;
if (!emitN(op, 3, &off))
return false;
- uint32_t yieldIndex = yieldOffsetList.length();
- if (yieldIndex >= JS_BIT(24)) {
+ uint32_t yieldAndAwaitIndex = yieldAndAwaitOffsetList.length();
+ if (yieldAndAwaitIndex >= JS_BIT(24)) {
reportError(nullptr, JSMSG_TOO_MANY_YIELDS);
return false;
}
if (op == JSOP_YIELD)
- yieldOffsetList.numYields++;
+ yieldAndAwaitOffsetList.numYields++;
else
- yieldOffsetList.numAwaits++;
+ yieldAndAwaitOffsetList.numAwaits++;
- SET_UINT24(code(off), yieldIndex);
+ SET_UINT24(code(off), yieldAndAwaitIndex);
- if (!yieldOffsetList.append(offset()))
+ if (!yieldAndAwaitOffsetList.append(offset()))
return false;
return emit1(JSOP_DEBUGAFTERYIELD);
@@ -8530,7 +8530,7 @@ BytecodeEmitter::emitYield(ParseNode* pn)
{
MOZ_ASSERT(sc->isFunctionBox());
- if (pn->getOp() == JSOP_YIELD) {
+ if (pn->getOp() == JSOP_YIELD || pn->getOp() == JSOP_AWAIT) {
bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
if (needsIteratorResult) {
if (!emitPrepareIteratorResult())
@@ -11293,7 +11293,7 @@ CGScopeNoteList::finish(ScopeNoteArray* array, uint32_t prologueLength)
}
void
-CGYieldOffsetList::finish(YieldOffsetArray& array, uint32_t prologueLength)
+CGYieldAndAwaitOffsetList::finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength)
{
MOZ_ASSERT(length() == array.length());
diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h
index 595ee6405..7f2dddfed 100644
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -98,15 +98,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;
@@ -237,10 +237,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 */
diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
index 2d7f57e1e..6ab93f3f9 100644
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -453,7 +453,7 @@ class FullParseHandler
ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
- return new_<BinaryNode>(PNK_AWAIT, JSOP_YIELD, pos, value, gen);
+ return new_<BinaryNode>(PNK_AWAIT, JSOP_AWAIT, pos, value, gen);
}
// Statements
diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp
index b2f9d3b23..52c3eccef 100644
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -43,7 +43,7 @@ using mozilla::AssertedCast;
BaselineCompiler::BaselineCompiler(JSContext* cx, TempAllocator& alloc, JSScript* script)
: BaselineCompilerSpecific(cx, alloc, script),
- yieldOffsets_(cx),
+ yieldAndAwaitOffsets_(cx),
modifiesArguments_(false)
{
}
@@ -210,7 +210,7 @@ BaselineCompiler::compile()
pcMappingIndexEntries.length(),
pcEntries.length(),
bytecodeTypeMapEntries,
- yieldOffsets_.length(),
+ yieldAndAwaitOffsets_.length(),
traceLoggerToggleOffsets_.length()),
JS::DeletePolicy<BaselineScript>(cx->runtime()));
if (!baselineScript) {
@@ -275,7 +275,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();
@@ -4174,27 +4174,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 +4205,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 +4235,7 @@ static const VMFunction NormalSuspendInfo =
bool
BaselineCompiler::emit_JSOP_YIELD()
{
- if (!addYieldOffset())
+ if (!addYieldAndAwaitOffset())
return false;
// Store generator in R0.
@@ -4250,7 +4252,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 +4284,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 +4509,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);
diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h
index 95e0c77ad..1f236ed82 100644
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -207,6 +207,7 @@ namespace jit {
_(JSOP_GENERATOR) \
_(JSOP_INITIALYIELD) \
_(JSOP_YIELD) \
+ _(JSOP_AWAIT) \
_(JSOP_DEBUGAFTERYIELD) \
_(JSOP_FINALYIELDRVAL) \
_(JSOP_RESUME) \
@@ -255,9 +256,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 +350,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);
diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp
index 9530f65fa..e65f10aac 100644
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -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);
diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp
index 5c21926b5..94e018252 100644
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -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));
}
}
diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h
index 5e7775a61..b6ccd2ff9 100644
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -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);
diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp
index 1ff7adfd1..652c23bf1 100644
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -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));
diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h
index e56eebb2d..e417e3a64 100644
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.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:
diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
index eb74a1ec6..bdd411d04 100644
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -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();
@@ -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
diff --git a/js/src/jsscript.h b/js/src/jsscript.h
index 13eaeff34..c19fbfc71 100644
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -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);
@@ -1699,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 isStarGenerator() || isLegacyGenerator() || isAsync(); }
+ bool hasYieldAndAwaitOffsets() const {
+ return isStarGenerator() || isLegacyGenerator() || isAsync();
+ }
#define OFF(fooOff, hasFoo, t) (fooOff() + (hasFoo() ? sizeof(t) : 0))
@@ -1708,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
@@ -1738,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();
diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp
index c0dff8faa..a61d37132 100644
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -64,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()));
@@ -75,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) {
@@ -173,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
diff --git a/js/src/vm/GeneratorObject.h b/js/src/vm/GeneratorObject.h
index ca1452b34..beb15f790 100644
--- a/js/src/vm/GeneratorObject.h
+++ b/js/src/vm/GeneratorObject.h
@@ -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));
- }
- 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));
+ setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(YIELD_AND_AWAIT_INDEX_CLOSING));
+ }
+ 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,7 +175,7 @@ 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());
}
@@ -187,8 +188,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);
diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp
index 030f0f3b6..92bb18b36 100644
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1940,7 +1940,6 @@ 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)
@@ -3994,6 +3993,7 @@ CASE(JSOP_INITIALYIELD)
}
CASE(JSOP_YIELD)
+CASE(JSOP_AWAIT)
{
MOZ_ASSERT(!cx->isExceptionPending());
MOZ_ASSERT(REGS.fp()->isFunctionFrame());
diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h
index 3c4d61a67..b44628080 100644
--- a/js/src/vm/Opcodes.h
+++ b/js/src/vm/Opcodes.h
@@ -2055,7 +2055,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 +2064,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,7 +2119,15 @@
* Stack: =>
*/ \
macro(JSOP_DEBUGAFTERYIELD, 208, "debugafteryield", NULL, 1, 0, 0, JOF_BYTE) \
- macro(JSOP_UNUSED209, 209, "unused209", NULL, 1, 0, 0, JOF_BYTE) \
+ /*
+ * Pops the generator and the return value 'result', stops interpretation
+ * and returns 'result'. Pushes resolved value onto the stack.
+ * Category: Statements
+ * Type: Generator
+ * Operands: uint24_t yieldAndAwaitIndex
+ * Stack: result, gen => resolved
+ */ \
+ macro(JSOP_AWAIT, 209, "await", NULL, 4, 2, 1, JOF_UINT24) \
macro(JSOP_UNUSED210, 210, "unused210", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED211, 211, "unused211", NULL, 1, 0, 0, JOF_BYTE) \
/*