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;
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())
@ -11294,7 +11294,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());

View file

@ -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 */

View file

@ -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

View file

@ -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();
@ -4180,27 +4180,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);
@ -4210,7 +4211,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());
@ -4239,7 +4241,7 @@ static const VMFunction NormalSuspendInfo =
bool
BaselineCompiler::emit_JSOP_YIELD()
{
if (!addYieldOffset())
if (!addYieldAndAwaitOffset())
return false;
// Store generator in R0.
@ -4256,7 +4258,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());
@ -4288,6 +4290,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");
@ -4507,16 +4515,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);

View file

@ -208,6 +208,7 @@ namespace jit {
_(JSOP_GENERATOR) \
_(JSOP_INITIALYIELD) \
_(JSOP_YIELD) \
_(JSOP_AWAIT) \
_(JSOP_DEBUGAFTERYIELD) \
_(JSOP_FINALYIELDRVAL) \
_(JSOP_RESUME) \
@ -256,9 +257,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_;
@ -350,7 +351,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);

View file

@ -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);

View file

@ -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));
}
}

View file

@ -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);

View file

@ -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));

View file

@ -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:

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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,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);

View file

@ -1939,7 +1939,6 @@ CASE(EnableInterruptsPseudoOpcode)
CASE(JSOP_NOP)
CASE(JSOP_NOP_DESTRUCTURING)
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());

View file

@ -2065,7 +2065,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) \
@ -2074,7 +2074,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) \
@ -2129,7 +2129,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) \
/*