Bug 1343481 - Part 3: Add JSOP_AWAIT and rename {yieldIndex,yieldOffset} to {yieldAndAwaitIndex,yieldAndAwaitOffset}.

Tag #1287
This commit is contained in:
Gaming4JC 2019-12-01 19:14:11 -05:00 • committed by Roy Tam
commit a6872d9ea3
16 changed files with 142 additions and 110 deletions

View file

@ -2046,7 +2046,7 @@ class ForOfLoopControl : public LoopControl
return false; return false;
MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX); MOZ_ASSERT(numYieldsAtBeginCodeNeedingIterClose_ == UINT32_MAX);
numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldOffsetList.numYields; numYieldsAtBeginCodeNeedingIterClose_ = bce->yieldAndAwaitOffsetList.numYields;
return true; return true;
} }
@ -2088,7 +2088,7 @@ class ForOfLoopControl : public LoopControl
// If any yields were emitted, then this for-of loop is inside a star // 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 // generator and must handle the case of Generator.return. Like in
// yield*, it is handled with a finally block. // yield*, it is handled with a finally block.
uint32_t numYieldsEmitted = bce->yieldOffsetList.numYields; uint32_t numYieldsEmitted = bce->yieldAndAwaitOffsetList.numYields;
if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) { if (numYieldsEmitted > numYieldsAtBeginCodeNeedingIterClose_) {
if (!tryCatch_->emitFinally()) if (!tryCatch_->emitFinally())
return false; return false;
@ -2190,7 +2190,7 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
scopeList(cx), scopeList(cx),
tryNoteList(cx), tryNoteList(cx),
scopeNoteList(cx), scopeNoteList(cx),
yieldOffsetList(cx), yieldAndAwaitOffsetList(cx),
typesetCount(0), typesetCount(0),
hasSingletons(false), hasSingletons(false),
hasTryFinally(false), hasTryFinally(false),
@ -4798,26 +4798,26 @@ BytecodeEmitter::emitYieldOp(JSOp op)
if (op == JSOP_FINALYIELDRVAL) if (op == JSOP_FINALYIELDRVAL)
return emit1(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; ptrdiff_t off;
if (!emitN(op, 3, &off)) if (!emitN(op, 3, &off))
return false; return false;
uint32_t yieldIndex = yieldOffsetList.length(); uint32_t yieldAndAwaitIndex = yieldAndAwaitOffsetList.length();
if (yieldIndex >= JS_BIT(24)) { if (yieldAndAwaitIndex >= JS_BIT(24)) {
reportError(nullptr, JSMSG_TOO_MANY_YIELDS); reportError(nullptr, JSMSG_TOO_MANY_YIELDS);
return false; return false;
} }
if (op == JSOP_YIELD) if (op == JSOP_YIELD)
yieldOffsetList.numYields++; yieldAndAwaitOffsetList.numYields++;
else 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 false;
return emit1(JSOP_DEBUGAFTERYIELD); return emit1(JSOP_DEBUGAFTERYIELD);
@ -8530,7 +8530,7 @@ BytecodeEmitter::emitYield(ParseNode* pn)
{ {
MOZ_ASSERT(sc->isFunctionBox()); MOZ_ASSERT(sc->isFunctionBox());
if (pn->getOp() == JSOP_YIELD) { if (pn->getOp() == JSOP_YIELD || pn->getOp() == JSOP_AWAIT) {
bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult(); bool needsIteratorResult = sc->asFunctionBox()->needsIteratorResult();
if (needsIteratorResult) { if (needsIteratorResult) {
if (!emitPrepareIteratorResult()) if (!emitPrepareIteratorResult())
@ -11294,7 +11294,7 @@ CGScopeNoteList::finish(ScopeNoteArray* array, uint32_t prologueLength)
} }
void void
CGYieldOffsetList::finish(YieldOffsetArray& array, uint32_t prologueLength) CGYieldAndAwaitOffsetList::finish(YieldAndAwaitOffsetArray& array, uint32_t prologueLength)
{ {
MOZ_ASSERT(length() == array.length()); MOZ_ASSERT(length() == array.length());

View file

@ -98,15 +98,15 @@ struct CGScopeNoteList {
void finish(ScopeNoteArray* array, uint32_t prologueLength); void finish(ScopeNoteArray* array, uint32_t prologueLength);
}; };
struct CGYieldOffsetList { struct CGYieldAndAwaitOffsetList {
Vector<uint32_t> list; Vector<uint32_t> list;
uint32_t numYields; uint32_t numYields;
uint32_t numAwaits; 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); } MOZ_MUST_USE bool append(uint32_t offset) { return list.append(offset); }
size_t length() const { return list.length(); } 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; static size_t MaxBytecodeLength = INT32_MAX;
@ -237,10 +237,10 @@ struct MOZ_STACK_CLASS BytecodeEmitter
CGScopeNoteList scopeNoteList; /* list of emitted block scope notes */ CGScopeNoteList scopeNoteList; /* list of emitted block scope notes */
/* /*
* For each yield op, map the yield index (stored as bytecode operand) to * For each yield or await op, map the yield and await index (stored as
* the offset of the next op. * bytecode operand) to the offset of the next op.
*/ */
CGYieldOffsetList yieldOffsetList; CGYieldAndAwaitOffsetList yieldAndAwaitOffsetList;
uint16_t typesetCount; /* Number of JOF_TYPESET opcodes generated */ uint16_t typesetCount; /* Number of JOF_TYPESET opcodes generated */

View file

@ -453,7 +453,7 @@ class FullParseHandler
ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) { ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1); 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 // Statements

View file

@ -43,7 +43,7 @@ using mozilla::AssertedCast;
BaselineCompiler::BaselineCompiler(JSContext* cx, TempAllocator& alloc, JSScript* script) BaselineCompiler::BaselineCompiler(JSContext* cx, TempAllocator& alloc, JSScript* script)
: BaselineCompilerSpecific(cx, alloc, script), : BaselineCompilerSpecific(cx, alloc, script),
yieldOffsets_(cx), yieldAndAwaitOffsets_(cx),
modifiesArguments_(false) modifiesArguments_(false)
{ {
} }
@ -210,7 +210,7 @@ BaselineCompiler::compile()
pcMappingIndexEntries.length(), pcMappingIndexEntries.length(),
pcEntries.length(), pcEntries.length(),
bytecodeTypeMapEntries, bytecodeTypeMapEntries,
yieldOffsets_.length(), yieldAndAwaitOffsets_.length(),
traceLoggerToggleOffsets_.length()), traceLoggerToggleOffsets_.length()),
JS::DeletePolicy<BaselineScript>(cx->runtime())); JS::DeletePolicy<BaselineScript>(cx->runtime()));
if (!baselineScript) { if (!baselineScript) {
@ -275,7 +275,7 @@ BaselineCompiler::compile()
// searches for the sought entry when queries are in linear order. // searches for the sought entry when queries are in linear order.
bytecodeMap[script->nTypeSets()] = 0; bytecodeMap[script->nTypeSets()] = 0;
baselineScript->copyYieldEntries(script, yieldOffsets_); baselineScript->copyYieldAndAwaitEntries(script, yieldAndAwaitOffsets_);
if (compileDebugInstrumentation_) if (compileDebugInstrumentation_)
baselineScript->setHasDebugInstrumentation(); baselineScript->setHasDebugInstrumentation();
@ -4180,27 +4180,28 @@ BaselineCompiler::emit_JSOP_GENERATOR()
} }
bool 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()) { while (yieldAndAwaitIndex >= yieldAndAwaitOffsets_.length()) {
if (!yieldOffsets_.append(0)) if (!yieldAndAwaitOffsets_.append(0))
return false; return false;
} }
static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH, static_assert(JSOP_INITIALYIELD_LENGTH == JSOP_YIELD_LENGTH &&
"code below assumes INITIALYIELD and YIELD have same length"); JSOP_INITIALYIELD_LENGTH == JSOP_AWAIT_LENGTH,
yieldOffsets_[yieldIndex] = script->pcToOffset(pc + JSOP_YIELD_LENGTH); "code below assumes INITIALYIELD and YIELD and AWAIT have same length");
yieldAndAwaitOffsets_[yieldAndAwaitIndex] = script->pcToOffset(pc + JSOP_YIELD_LENGTH);
return true; return true;
} }
bool bool
BaselineCompiler::emit_JSOP_INITIALYIELD() BaselineCompiler::emit_JSOP_INITIALYIELD()
{ {
if (!addYieldOffset()) if (!addYieldAndAwaitOffset())
return false; return false;
frame.syncStack(0); frame.syncStack(0);
@ -4210,7 +4211,8 @@ BaselineCompiler::emit_JSOP_INITIALYIELD()
masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), genObj); masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), genObj);
MOZ_ASSERT(GET_UINT24(pc) == 0); 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(); Register envObj = R0.scratchReg();
Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot()); Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot());
@ -4239,7 +4241,7 @@ static const VMFunction NormalSuspendInfo =
bool bool
BaselineCompiler::emit_JSOP_YIELD() BaselineCompiler::emit_JSOP_YIELD()
{ {
if (!addYieldOffset()) if (!addYieldAndAwaitOffset())
return false; return false;
// Store generator in R0. // Store generator in R0.
@ -4256,7 +4258,7 @@ BaselineCompiler::emit_JSOP_YIELD()
// generator is in the closing state, see GeneratorObject::suspend. // generator is in the closing state, see GeneratorObject::suspend.
masm.storeValue(Int32Value(GET_UINT24(pc)), masm.storeValue(Int32Value(GET_UINT24(pc)),
Address(genObj, GeneratorObject::offsetOfYieldIndexSlot())); Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
Register envObj = R0.scratchReg(); Register envObj = R0.scratchReg();
Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot()); Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot());
@ -4288,6 +4290,12 @@ BaselineCompiler::emit_JSOP_YIELD()
return emitReturn(); return emitReturn();
} }
bool
BaselineCompiler::emit_JSOP_AWAIT()
{
return emit_JSOP_YIELD();
}
typedef bool (*DebugAfterYieldFn)(JSContext*, BaselineFrame*); typedef bool (*DebugAfterYieldFn)(JSContext*, BaselineFrame*);
static const VMFunction DebugAfterYieldInfo = static const VMFunction DebugAfterYieldInfo =
FunctionInfo<DebugAfterYieldFn>(jit::DebugAfterYield, "DebugAfterYield"); FunctionInfo<DebugAfterYieldFn>(jit::DebugAfterYield, "DebugAfterYield");
@ -4507,16 +4515,17 @@ BaselineCompiler::emit_JSOP_RESUME()
masm.pushValue(retVal); masm.pushValue(retVal);
if (resumeKind == GeneratorObject::NEXT) { if (resumeKind == GeneratorObject::NEXT) {
// Determine the resume address based on the yieldIndex and the // Determine the resume address based on the yieldAndAwaitIndex and the
// yieldIndex -> native table in the BaselineScript. // yieldAndAwaitIndex -> native table in the BaselineScript.
masm.load32(Address(scratch1, BaselineScript::offsetOfYieldEntriesOffset()), scratch2); masm.load32(Address(scratch1, BaselineScript::offsetOfYieldEntriesOffset()), scratch2);
masm.addPtr(scratch2, scratch1); 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); masm.loadPtr(BaseIndex(scratch1, scratch2, ScaleFromElemWidth(sizeof(uintptr_t))), scratch1);
// Mark as running and jump to the generator's JIT code. // Mark as running and jump to the generator's JIT code.
masm.storeValue(Int32Value(GeneratorObject::YIELD_INDEX_RUNNING), masm.storeValue(Int32Value(GeneratorObject::YIELD_AND_AWAIT_INDEX_RUNNING),
Address(genObj, GeneratorObject::offsetOfYieldIndexSlot())); Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()));
masm.jump(scratch1); masm.jump(scratch1);
} else { } else {
MOZ_ASSERT(resumeKind == GeneratorObject::THROW || resumeKind == GeneratorObject::CLOSE); MOZ_ASSERT(resumeKind == GeneratorObject::THROW || resumeKind == GeneratorObject::CLOSE);

View file

@ -208,6 +208,7 @@ namespace jit {
_(JSOP_GENERATOR) \ _(JSOP_GENERATOR) \
_(JSOP_INITIALYIELD) \ _(JSOP_INITIALYIELD) \
_(JSOP_YIELD) \ _(JSOP_YIELD) \
_(JSOP_AWAIT) \
_(JSOP_DEBUGAFTERYIELD) \ _(JSOP_DEBUGAFTERYIELD) \
_(JSOP_FINALYIELDRVAL) \ _(JSOP_FINALYIELDRVAL) \
_(JSOP_RESUME) \ _(JSOP_RESUME) \
@ -256,9 +257,9 @@ class BaselineCompiler : public BaselineCompilerSpecific
// equivalent positions when debug mode is off. // equivalent positions when debug mode is off.
CodeOffset postDebugPrologueOffset_; CodeOffset postDebugPrologueOffset_;
// For each INITIALYIELD or YIELD op, this Vector maps the yield index // For each INITIALYIELD or YIELD or AWAIT op, this Vector maps the yield
// to the bytecode offset of the next op. // index to the bytecode offset of the next op.
Vector<uint32_t> yieldOffsets_; Vector<uint32_t> yieldAndAwaitOffsets_;
// Whether any on stack arguments are modified. // Whether any on stack arguments are modified.
bool modifiesArguments_; bool modifiesArguments_;
@ -350,7 +351,7 @@ class BaselineCompiler : public BaselineCompilerSpecific
MOZ_MUST_USE bool addPCMappingEntry(bool addIndexEntry); MOZ_MUST_USE bool addPCMappingEntry(bool addIndexEntry);
MOZ_MUST_USE bool addYieldOffset(); MOZ_MUST_USE bool addYieldAndAwaitOffset();
void getEnvironmentCoordinateObject(Register reg); void getEnvironmentCoordinateObject(Register reg);
Address getEnvironmentCoordinateAddressFromObject(Register objReg, Register reg); Address getEnvironmentCoordinateAddressFromObject(Register objReg, Register reg);

View file

@ -6600,12 +6600,13 @@ ICCall_IsSuspendedStarGenerator::Compiler::generateStubCode(MacroAssembler& masm
masm.branchTestObjClass(Assembler::NotEqual, genObj, scratch, &StarGeneratorObject::class_, masm.branchTestObjClass(Assembler::NotEqual, genObj, scratch, &StarGeneratorObject::class_,
&returnFalse); &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. // 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.branchTestInt32(Assembler::NotEqual, argVal, &returnFalse);
masm.unboxInt32(argVal, scratch); 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); &returnFalse);
masm.moveValue(BooleanValue(true), R0); masm.moveValue(BooleanValue(true), R0);

View file

@ -760,12 +760,12 @@ BaselineScript::icEntryFromReturnAddress(uint8_t* returnAddr)
} }
void void
BaselineScript::copyYieldEntries(JSScript* script, Vector<uint32_t>& yieldOffsets) BaselineScript::copyYieldAndAwaitEntries(JSScript* script, Vector<uint32_t>& yieldAndAwaitOffsets)
{ {
uint8_t** entries = yieldEntryList(); uint8_t** entries = yieldEntryList();
for (size_t i = 0; i < yieldOffsets.length(); i++) { for (size_t i = 0; i < yieldAndAwaitOffsets.length(); i++) {
uint32_t offset = yieldOffsets[i]; uint32_t offset = yieldAndAwaitOffsets[i];
entries[i] = nativeCodeForPC(script, script->offsetToPC(offset)); entries[i] = nativeCodeForPC(script, script->offsetToPC(offset));
} }
} }

View file

@ -397,7 +397,7 @@ struct BaselineScript
void copyICEntries(JSScript* script, const BaselineICEntry* entries, MacroAssembler& masm); void copyICEntries(JSScript* script, const BaselineICEntry* entries, MacroAssembler& masm);
void adoptFallbackStubs(FallbackICStubSpace* stubSpace); 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); PCMappingIndexEntry& pcMappingIndexEntry(size_t index);
CompactBufferReader pcMappingReader(size_t indexEntry); CompactBufferReader pcMappingReader(size_t indexEntry);

View file

@ -735,7 +735,7 @@ bool
NormalSuspend(JSContext* cx, HandleObject obj, BaselineFrame* frame, jsbytecode* pc, NormalSuspend(JSContext* cx, HandleObject obj, BaselineFrame* frame, jsbytecode* pc,
uint32_t stackDepth) uint32_t stackDepth)
{ {
MOZ_ASSERT(*pc == JSOP_YIELD); MOZ_ASSERT(*pc == JSOP_YIELD || *pc == JSOP_AWAIT);
// Return value is still on the stack. // Return value is still on the stack.
MOZ_ASSERT(stackDepth >= 1); 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 // work. This function always returns false, so we're guaranteed to enter
// the exception handler where we will clear the pc. // the exception handler where we will clear the pc.
JSScript* script = frame->script(); JSScript* script = frame->script();
uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()]; uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
frame->setOverridePc(script->offsetToPC(offset)); frame->setOverridePc(script->offsetToPC(offset));
MOZ_ALWAYS_TRUE(DebugAfterYield(cx, frame)); MOZ_ALWAYS_TRUE(DebugAfterYield(cx, frame));

View file

@ -655,7 +655,8 @@ IsValidBytecodeOffset(JSContext* cx, JSScript* script, size_t offset);
inline bool inline bool
FlowsIntoNext(JSOp op) 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) { switch (op) {
case JSOP_RETRVAL: case JSOP_RETRVAL:
case JSOP_RETURN: case JSOP_RETURN:

View file

@ -402,8 +402,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
ntrynotes = script->trynotes()->length; ntrynotes = script->trynotes()->length;
if (script->hasScopeNotes()) if (script->hasScopeNotes())
nscopenotes = script->scopeNotes()->length; nscopenotes = script->scopeNotes()->length;
if (script->hasYieldOffsets()) if (script->hasYieldAndAwaitOffsets())
nyieldoffsets = script->yieldOffsets().length(); nyieldoffsets = script->yieldAndAwaitOffsets().length();
nTypeSets = script->nTypeSets(); nTypeSets = script->nTypeSets();
funLength = script->funLength(); funLength = script->funLength();
@ -902,7 +902,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
} }
for (i = 0; i < nyieldoffsets; ++i) { for (i = 0; i < nyieldoffsets; ++i) {
uint32_t* offset = &script->yieldOffsets()[i]; uint32_t* offset = &script->yieldAndAwaitOffsets()[i];
if (!xdr->codeUint32(offset)) if (!xdr->codeUint32(offset))
return false; return false;
} }
@ -2456,7 +2456,7 @@ ScriptDataSize(uint32_t nscopes, uint32_t nconsts, uint32_t nobjects,
if (nscopenotes != 0) if (nscopenotes != 0)
size += sizeof(ScopeNoteArray) + nscopenotes * sizeof(ScopeNote); size += sizeof(ScopeNoteArray) + nscopenotes * sizeof(ScopeNote);
if (nyieldoffsets != 0) if (nyieldoffsets != 0)
size += sizeof(YieldOffsetArray) + nyieldoffsets * sizeof(uint32_t); size += sizeof(YieldAndAwaitOffsetArray) + nyieldoffsets * sizeof(uint32_t);
return size; return size;
} }
@ -2558,10 +2558,10 @@ JSScript::partiallyInit(ExclusiveContext* cx, HandleScript script, uint32_t nsco
cursor += sizeof(ScopeNoteArray); cursor += sizeof(ScopeNoteArray);
} }
YieldOffsetArray* yieldOffsets = nullptr; YieldAndAwaitOffsetArray* yieldAndAwaitOffsets = nullptr;
if (nyieldoffsets != 0) { if (nyieldoffsets != 0) {
yieldOffsets = reinterpret_cast<YieldOffsetArray*>(cursor); yieldAndAwaitOffsets = reinterpret_cast<YieldAndAwaitOffsetArray*>(cursor);
cursor += sizeof(YieldOffsetArray); cursor += sizeof(YieldAndAwaitOffsetArray);
} }
if (nconsts != 0) { if (nconsts != 0) {
@ -2602,8 +2602,8 @@ JSScript::partiallyInit(ExclusiveContext* cx, HandleScript script, uint32_t nsco
} }
if (nyieldoffsets != 0) { if (nyieldoffsets != 0) {
yieldOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets); yieldAndAwaitOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
size_t vectorSize = nyieldoffsets * sizeof(script->yieldOffsets()[0]); size_t vectorSize = nyieldoffsets * sizeof(script->yieldAndAwaitOffsets()[0]);
#ifdef DEBUG #ifdef DEBUG
memset(cursor, 0, vectorSize); memset(cursor, 0, vectorSize);
#endif #endif
@ -2623,10 +2623,10 @@ JSScript::initFunctionPrototype(ExclusiveContext* cx, Handle<JSScript*> script,
uint32_t numObjects = 0; uint32_t numObjects = 0;
uint32_t numTryNotes = 0; uint32_t numTryNotes = 0;
uint32_t numScopeNotes = 0; uint32_t numScopeNotes = 0;
uint32_t numYieldOffsets = 0; uint32_t numYieldAndAwaitOffsets = 0;
uint32_t numTypeSets = 0; uint32_t numTypeSets = 0;
if (!partiallyInit(cx, script, numScopes, numConsts, numObjects, numTryNotes, if (!partiallyInit(cx, script, numScopes, numConsts, numObjects, numTryNotes,
numScopeNotes, numYieldOffsets, numTypeSets)) numScopeNotes, numYieldAndAwaitOffsets, numTypeSets))
{ {
return false; return false;
} }
@ -2739,7 +2739,7 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
if (!partiallyInit(cx, script, if (!partiallyInit(cx, script,
bce->scopeList.length(), bce->constList.length(), bce->objectList.length, bce->scopeList.length(), bce->constList.length(), bce->objectList.length,
bce->tryNoteList.length(), bce->scopeNoteList.length(), bce->tryNoteList.length(), bce->scopeNoteList.length(),
bce->yieldOffsetList.length(), bce->typesetCount)) bce->yieldAndAwaitOffsetList.length(), bce->typesetCount))
{ {
return false; return false;
} }
@ -2794,8 +2794,8 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
// Copy yield offsets last, as the generator kind is set in // Copy yield offsets last, as the generator kind is set in
// initFromFunctionBox. // initFromFunctionBox.
if (bce->yieldOffsetList.length() != 0) if (bce->yieldAndAwaitOffsetList.length() != 0)
bce->yieldOffsetList.finish(script->yieldOffsets(), prologueLength); bce->yieldAndAwaitOffsetList.finish(script->yieldAndAwaitOffsets(), prologueLength);
#ifdef DEBUG #ifdef DEBUG
script->assertValidJumpTargets(); script->assertValidJumpTargets();
@ -3242,7 +3242,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
uint32_t nscopes = src->scopes()->length; uint32_t nscopes = src->scopes()->length;
uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0; uint32_t ntrynotes = src->hasTrynotes() ? src->trynotes()->length : 0;
uint32_t nscopenotes = src->hasScopeNotes() ? src->scopeNotes()->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 */ /* 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); dst->trynotes()->vector = Rebase<JSTryNote>(dst, src, src->trynotes()->vector);
if (nscopenotes != 0) if (nscopenotes != 0)
dst->scopeNotes()->vector = Rebase<ScopeNote>(dst, src, src->scopeNotes()->vector); dst->scopeNotes()->vector = Rebase<ScopeNote>(dst, src, src->scopeNotes()->vector);
if (nyieldoffsets != 0) if (nyieldoffsets != 0) {
dst->yieldOffsets().vector_ = Rebase<uint32_t>(dst, src, src->yieldOffsets().vector_); dst->yieldAndAwaitOffsets().vector_ =
Rebase<uint32_t>(dst, src, src->yieldAndAwaitOffsets().vector_);
}
/* /*
* Function delazification assumes that their script does not have a * Function delazification assumes that their script does not have a

View file

@ -156,7 +156,7 @@ struct ScopeNoteArray {
uint32_t length; // Count of indexed try notes. uint32_t length; // Count of indexed try notes.
}; };
class YieldOffsetArray { class YieldAndAwaitOffsetArray {
friend bool friend bool
detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst, detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst,
MutableHandle<GCVector<Scope*>> scopes); MutableHandle<GCVector<Scope*>> scopes);
@ -1699,7 +1699,9 @@ class JSScript : public js::gc::TenuredCell
bool hasObjects() const { return hasArray(OBJECTS); } bool hasObjects() const { return hasArray(OBJECTS); }
bool hasTrynotes() const { return hasArray(TRYNOTES); } bool hasTrynotes() const { return hasArray(TRYNOTES); }
bool hasScopeNotes() const { return hasArray(SCOPENOTES); } 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)) #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 objectsOffset() const { return OFF(constsOffset, hasConsts, js::ConstArray); }
size_t trynotesOffset() const { return OFF(objectsOffset, hasObjects, js::ObjectArray); } size_t trynotesOffset() const { return OFF(objectsOffset, hasObjects, js::ObjectArray); }
size_t scopeNotesOffset() const { return OFF(trynotesOffset, hasTrynotes, js::TryNoteArray); } 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 #undef OFF
@ -1738,9 +1742,10 @@ class JSScript : public js::gc::TenuredCell
return reinterpret_cast<js::ScopeNoteArray*>(data + scopeNotesOffset()); return reinterpret_cast<js::ScopeNoteArray*>(data + scopeNotesOffset());
} }
js::YieldOffsetArray& yieldOffsets() { js::YieldAndAwaitOffsetArray& yieldAndAwaitOffsets() {
MOZ_ASSERT(hasYieldOffsets()); MOZ_ASSERT(hasYieldAndAwaitOffsets());
return *reinterpret_cast<js::YieldOffsetArray*>(data + yieldOffsetsOffset()); return *reinterpret_cast<js::YieldAndAwaitOffsetArray*>(data +
yieldAndAwaitOffsetsOffset());
} }
bool hasLoops(); bool hasLoops();

View file

@ -64,10 +64,14 @@ bool
GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc, GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame, jsbytecode* pc,
Value* vp, unsigned nvalues) 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>()); Rooted<GeneratorObject*> genObj(cx, &obj->as<GeneratorObject>());
MOZ_ASSERT(!genObj->hasExpressionStack()); 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>()) { if (*pc == JSOP_YIELD && genObj->isClosing() && genObj->is<LegacyGeneratorObject>()) {
RootedValue val(cx, ObjectValue(*frame.callee())); RootedValue val(cx, ObjectValue(*frame.callee()));
@ -75,8 +79,8 @@ GeneratorObject::suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame
return false; return false;
} }
uint32_t yieldIndex = GET_UINT24(pc); uint32_t yieldAndAwaitIndex = GET_UINT24(pc);
genObj->setYieldIndex(yieldIndex); genObj->setYieldAndAwaitIndex(yieldAndAwaitIndex);
genObj->setEnvironmentChain(*frame.environmentChain()); genObj->setEnvironmentChain(*frame.environmentChain());
if (nvalues) { if (nvalues) {
@ -173,7 +177,7 @@ GeneratorObject::resume(JSContext* cx, InterpreterActivation& activation,
} }
JSScript* script = callee->nonLazyScript(); JSScript* script = callee->nonLazyScript();
uint32_t offset = script->yieldOffsets()[genObj->yieldIndex()]; uint32_t offset = script->yieldAndAwaitOffsets()[genObj->yieldAndAwaitIndex()];
activation.regs().pc = script->offsetToPC(offset); activation.regs().pc = script->offsetToPC(offset);
// Always push on a value, even if we are raising an exception. In the // Always push on a value, even if we are raising an exception. In the

View file

@ -21,15 +21,15 @@ class GeneratorObject : public NativeObject
public: public:
// Magic values stored in the yield index slot when the generator is // Magic values stored in the yield index slot when the generator is
// running or closing. See the yield index comment below. // running or closing. See the yield index comment below.
static const int32_t YIELD_INDEX_RUNNING = INT32_MAX; static const int32_t YIELD_AND_AWAIT_INDEX_RUNNING = INT32_MAX;
static const int32_t YIELD_INDEX_CLOSING = INT32_MAX - 1; static const int32_t YIELD_AND_AWAIT_INDEX_CLOSING = INT32_MAX - 1;
enum { enum {
CALLEE_SLOT = 0, CALLEE_SLOT = 0,
ENV_CHAIN_SLOT, ENV_CHAIN_SLOT,
ARGS_OBJ_SLOT, ARGS_OBJ_SLOT,
EXPRESSION_STACK_SLOT, EXPRESSION_STACK_SLOT,
YIELD_INDEX_SLOT, YIELD_AND_AWAIT_INDEX_SLOT,
NEWTARGET_SLOT, NEWTARGET_SLOT,
RESERVED_SLOTS RESERVED_SLOTS
}; };
@ -124,47 +124,48 @@ class GeneratorObject : public NativeObject
// The yield index slot is abused for a few purposes. It's undefined if // 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 // 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 // generator is closed. If the generator is running, the yield index is
// YIELD_INDEX_RUNNING. If the generator is in that bizarre "closing" // YIELD_AND_AWAIT_INDEX_RUNNING. If the generator is in that bizarre
// state, the yield index is YIELD_INDEX_CLOSING. // "closing" state, the yield index is YIELD_AND_AWAIT_INDEX_CLOSING.
// //
// If the generator is suspended, it's the yield index (stored as // If the generator is suspended, it's the yield index (stored as
// JSOP_INITIALYIELD/JSOP_YIELD operand) of the yield instruction that // JSOP_INITIALYIELD/JSOP_YIELD/JSOP_AWAIT operand) of the yield
// suspended the generator. The yield index can be mapped to the bytecode // instruction that suspended the generator. The yield index can be mapped
// offset (interpreter) or to the native code offset (JIT). // to the bytecode offset (interpreter) or to the native code offset (JIT).
bool isRunning() const { bool isRunning() const {
MOZ_ASSERT(!isClosed()); 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 { 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 { bool isSuspended() const {
// Note: also update Baseline's IsSuspendedStarGenerator code if this // Note: also update Baseline's IsSuspendedStarGenerator code if this
// changes. // changes.
MOZ_ASSERT(!isClosed()); MOZ_ASSERT(!isClosed());
static_assert(YIELD_INDEX_CLOSING < YIELD_INDEX_RUNNING, static_assert(YIELD_AND_AWAIT_INDEX_CLOSING < YIELD_AND_AWAIT_INDEX_RUNNING,
"test below should return false for YIELD_INDEX_RUNNING"); "test below should return false for YIELD_AND_AWAIT_INDEX_RUNNING");
return getFixedSlot(YIELD_INDEX_SLOT).toInt32() < YIELD_INDEX_CLOSING; return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32() < YIELD_AND_AWAIT_INDEX_CLOSING;
} }
void setRunning() { void setRunning() {
MOZ_ASSERT(isSuspended()); 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() { void setClosing() {
MOZ_ASSERT(isSuspended()); 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) { void setYieldAndAwaitIndex(uint32_t yieldAndAwaitIndex) {
MOZ_ASSERT_IF(yieldIndex == 0, getFixedSlot(YIELD_INDEX_SLOT).isUndefined()); MOZ_ASSERT_IF(yieldAndAwaitIndex == 0,
MOZ_ASSERT_IF(yieldIndex != 0, isRunning() || isClosing()); getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).isUndefined());
MOZ_ASSERT(yieldIndex < uint32_t(YIELD_INDEX_CLOSING)); MOZ_ASSERT_IF(yieldAndAwaitIndex != 0, isRunning() || isClosing());
setFixedSlot(YIELD_INDEX_SLOT, Int32Value(yieldIndex)); MOZ_ASSERT(yieldAndAwaitIndex < uint32_t(YIELD_AND_AWAIT_INDEX_CLOSING));
setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, Int32Value(yieldAndAwaitIndex));
MOZ_ASSERT(isSuspended()); MOZ_ASSERT(isSuspended());
} }
uint32_t yieldIndex() const { uint32_t yieldAndAwaitIndex() const {
MOZ_ASSERT(isSuspended()); MOZ_ASSERT(isSuspended());
return getFixedSlot(YIELD_INDEX_SLOT).toInt32(); return getFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT).toInt32();
} }
bool isClosed() const { bool isClosed() const {
return getFixedSlot(CALLEE_SLOT).isNull(); return getFixedSlot(CALLEE_SLOT).isNull();
@ -174,7 +175,7 @@ class GeneratorObject : public NativeObject
setFixedSlot(ENV_CHAIN_SLOT, NullValue()); setFixedSlot(ENV_CHAIN_SLOT, NullValue());
setFixedSlot(ARGS_OBJ_SLOT, NullValue()); setFixedSlot(ARGS_OBJ_SLOT, NullValue());
setFixedSlot(EXPRESSION_STACK_SLOT, NullValue()); setFixedSlot(EXPRESSION_STACK_SLOT, NullValue());
setFixedSlot(YIELD_INDEX_SLOT, NullValue()); setFixedSlot(YIELD_AND_AWAIT_INDEX_SLOT, NullValue());
setFixedSlot(NEWTARGET_SLOT, NullValue()); setFixedSlot(NEWTARGET_SLOT, NullValue());
} }
@ -187,8 +188,8 @@ class GeneratorObject : public NativeObject
static size_t offsetOfArgsObjSlot() { static size_t offsetOfArgsObjSlot() {
return getFixedSlotOffset(ARGS_OBJ_SLOT); return getFixedSlotOffset(ARGS_OBJ_SLOT);
} }
static size_t offsetOfYieldIndexSlot() { static size_t offsetOfYieldAndAwaitIndexSlot() {
return getFixedSlotOffset(YIELD_INDEX_SLOT); return getFixedSlotOffset(YIELD_AND_AWAIT_INDEX_SLOT);
} }
static size_t offsetOfExpressionStackSlot() { static size_t offsetOfExpressionStackSlot() {
return getFixedSlotOffset(EXPRESSION_STACK_SLOT); return getFixedSlotOffset(EXPRESSION_STACK_SLOT);

View file

@ -1939,7 +1939,6 @@ CASE(EnableInterruptsPseudoOpcode)
CASE(JSOP_NOP) CASE(JSOP_NOP)
CASE(JSOP_NOP_DESTRUCTURING) CASE(JSOP_NOP_DESTRUCTURING)
CASE(JSOP_UNUSED192) CASE(JSOP_UNUSED192)
CASE(JSOP_UNUSED209)
CASE(JSOP_UNUSED210) CASE(JSOP_UNUSED210)
CASE(JSOP_UNUSED211) CASE(JSOP_UNUSED211)
CASE(JSOP_TRY_DESTRUCTURING_ITERCLOSE) CASE(JSOP_TRY_DESTRUCTURING_ITERCLOSE)
@ -3994,6 +3993,7 @@ CASE(JSOP_INITIALYIELD)
} }
CASE(JSOP_YIELD) CASE(JSOP_YIELD)
CASE(JSOP_AWAIT)
{ {
MOZ_ASSERT(!cx->isExceptionPending()); MOZ_ASSERT(!cx->isExceptionPending());
MOZ_ASSERT(REGS.fp()->isFunctionFrame()); MOZ_ASSERT(REGS.fp()->isFunctionFrame());

View file

@ -2065,7 +2065,7 @@
* interpretation. * interpretation.
* Category: Statements * Category: Statements
* Type: Generator * Type: Generator
* Operands: uint24_t yieldIndex * Operands: uint24_t yieldAndAwaitIndex
* Stack: generator => * Stack: generator =>
*/ \ */ \
macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 4, 1, 1, JOF_UINT24) \ macro(JSOP_INITIALYIELD, 202,"initialyield", NULL, 4, 1, 1, JOF_UINT24) \
@ -2074,7 +2074,7 @@
* returns 'rval1'. Pushes sent value from 'send()' onto the stack. * returns 'rval1'. Pushes sent value from 'send()' onto the stack.
* Category: Statements * Category: Statements
* Type: Generator * Type: Generator
* Operands: uint24_t yieldIndex * Operands: uint24_t yieldAndAwaitIndex
* Stack: rval1, gen => rval2 * Stack: rval1, gen => rval2
*/ \ */ \
macro(JSOP_YIELD, 203,"yield", NULL, 4, 2, 1, JOF_UINT24) \ macro(JSOP_YIELD, 203,"yield", NULL, 4, 2, 1, JOF_UINT24) \
@ -2129,7 +2129,15 @@
* Stack: => * Stack: =>
*/ \ */ \
macro(JSOP_DEBUGAFTERYIELD, 208, "debugafteryield", NULL, 1, 0, 0, JOF_BYTE) \ 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_UNUSED210, 210, "unused210", NULL, 1, 0, 0, JOF_BYTE) \
macro(JSOP_UNUSED211, 211, "unused211", NULL, 1, 0, 0, JOF_BYTE) \ macro(JSOP_UNUSED211, 211, "unused211", NULL, 1, 0, 0, JOF_BYTE) \
/* /*