mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-06 07:48:38 +09:00
Bug 1343481 - Part 3: Add JSOP_AWAIT and rename {yieldIndex,yieldOffset} to {yieldAndAwaitIndex,yieldAndAwaitOffset}.
Tag #1287
This commit is contained in:
parent
45337018ef
commit
a6872d9ea3
16 changed files with 142 additions and 110 deletions
|
|
@ -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());
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -6600,12 +6600,13 @@ ICCall_IsSuspendedStarGenerator::Compiler::generateStubCode(MacroAssembler& masm
|
|||
masm.branchTestObjClass(Assembler::NotEqual, genObj, scratch, &StarGeneratorObject::class_,
|
||||
&returnFalse);
|
||||
|
||||
// If the yield index slot holds an int32 value < YIELD_INDEX_CLOSING,
|
||||
// If the yield index slot holds an int32 value < YIELD_AND_AWAIT_INDEX_CLOSING,
|
||||
// the generator is suspended.
|
||||
masm.loadValue(Address(genObj, GeneratorObject::offsetOfYieldIndexSlot()), argVal);
|
||||
masm.loadValue(Address(genObj, GeneratorObject::offsetOfYieldAndAwaitIndexSlot()), argVal);
|
||||
masm.branchTestInt32(Assembler::NotEqual, argVal, &returnFalse);
|
||||
masm.unboxInt32(argVal, scratch);
|
||||
masm.branch32(Assembler::AboveOrEqual, scratch, Imm32(StarGeneratorObject::YIELD_INDEX_CLOSING),
|
||||
masm.branch32(Assembler::AboveOrEqual, scratch,
|
||||
Imm32(StarGeneratorObject::YIELD_AND_AWAIT_INDEX_CLOSING),
|
||||
&returnFalse);
|
||||
|
||||
masm.moveValue(BooleanValue(true), R0);
|
||||
|
|
|
|||
|
|
@ -760,12 +760,12 @@ BaselineScript::icEntryFromReturnAddress(uint8_t* returnAddr)
|
|||
}
|
||||
|
||||
void
|
||||
BaselineScript::copyYieldEntries(JSScript* script, Vector<uint32_t>& yieldOffsets)
|
||||
BaselineScript::copyYieldAndAwaitEntries(JSScript* script, Vector<uint32_t>& yieldAndAwaitOffsets)
|
||||
{
|
||||
uint8_t** entries = yieldEntryList();
|
||||
|
||||
for (size_t i = 0; i < yieldOffsets.length(); i++) {
|
||||
uint32_t offset = yieldOffsets[i];
|
||||
for (size_t i = 0; i < yieldAndAwaitOffsets.length(); i++) {
|
||||
uint32_t offset = yieldAndAwaitOffsets[i];
|
||||
entries[i] = nativeCodeForPC(script, script->offsetToPC(offset));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ struct BaselineScript
|
|||
void copyICEntries(JSScript* script, const BaselineICEntry* entries, MacroAssembler& masm);
|
||||
void adoptFallbackStubs(FallbackICStubSpace* stubSpace);
|
||||
|
||||
void copyYieldEntries(JSScript* script, Vector<uint32_t>& yieldOffsets);
|
||||
void copyYieldAndAwaitEntries(JSScript* script, Vector<uint32_t>& yieldAndAwaitOffsets);
|
||||
|
||||
PCMappingIndexEntry& pcMappingIndexEntry(size_t index);
|
||||
CompactBufferReader pcMappingReader(size_t indexEntry);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -655,7 +655,8 @@ IsValidBytecodeOffset(JSContext* cx, JSScript* script, size_t offset);
|
|||
inline bool
|
||||
FlowsIntoNext(JSOp op)
|
||||
{
|
||||
/* JSOP_YIELD is considered to flow into the next instruction, like JSOP_CALL. */
|
||||
// JSOP_YIELD/JSOP_AWAIT is considered to flow into the next instruction,
|
||||
// like JSOP_CALL.
|
||||
switch (op) {
|
||||
case JSOP_RETRVAL:
|
||||
case JSOP_RETURN:
|
||||
|
|
|
|||
|
|
@ -402,8 +402,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
|||
ntrynotes = script->trynotes()->length;
|
||||
if (script->hasScopeNotes())
|
||||
nscopenotes = script->scopeNotes()->length;
|
||||
if (script->hasYieldOffsets())
|
||||
nyieldoffsets = script->yieldOffsets().length();
|
||||
if (script->hasYieldAndAwaitOffsets())
|
||||
nyieldoffsets = script->yieldAndAwaitOffsets().length();
|
||||
|
||||
nTypeSets = script->nTypeSets();
|
||||
funLength = script->funLength();
|
||||
|
|
@ -902,7 +902,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
|||
}
|
||||
|
||||
for (i = 0; i < nyieldoffsets; ++i) {
|
||||
uint32_t* offset = &script->yieldOffsets()[i];
|
||||
uint32_t* offset = &script->yieldAndAwaitOffsets()[i];
|
||||
if (!xdr->codeUint32(offset))
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2456,7 +2456,7 @@ ScriptDataSize(uint32_t nscopes, uint32_t nconsts, uint32_t nobjects,
|
|||
if (nscopenotes != 0)
|
||||
size += sizeof(ScopeNoteArray) + nscopenotes * sizeof(ScopeNote);
|
||||
if (nyieldoffsets != 0)
|
||||
size += sizeof(YieldOffsetArray) + nyieldoffsets * sizeof(uint32_t);
|
||||
size += sizeof(YieldAndAwaitOffsetArray) + nyieldoffsets * sizeof(uint32_t);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
|
@ -2558,10 +2558,10 @@ JSScript::partiallyInit(ExclusiveContext* cx, HandleScript script, uint32_t nsco
|
|||
cursor += sizeof(ScopeNoteArray);
|
||||
}
|
||||
|
||||
YieldOffsetArray* yieldOffsets = nullptr;
|
||||
YieldAndAwaitOffsetArray* yieldAndAwaitOffsets = nullptr;
|
||||
if (nyieldoffsets != 0) {
|
||||
yieldOffsets = reinterpret_cast<YieldOffsetArray*>(cursor);
|
||||
cursor += sizeof(YieldOffsetArray);
|
||||
yieldAndAwaitOffsets = reinterpret_cast<YieldAndAwaitOffsetArray*>(cursor);
|
||||
cursor += sizeof(YieldAndAwaitOffsetArray);
|
||||
}
|
||||
|
||||
if (nconsts != 0) {
|
||||
|
|
@ -2602,8 +2602,8 @@ JSScript::partiallyInit(ExclusiveContext* cx, HandleScript script, uint32_t nsco
|
|||
}
|
||||
|
||||
if (nyieldoffsets != 0) {
|
||||
yieldOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
|
||||
size_t vectorSize = nyieldoffsets * sizeof(script->yieldOffsets()[0]);
|
||||
yieldAndAwaitOffsets->init(reinterpret_cast<uint32_t*>(cursor), nyieldoffsets);
|
||||
size_t vectorSize = nyieldoffsets * sizeof(script->yieldAndAwaitOffsets()[0]);
|
||||
#ifdef DEBUG
|
||||
memset(cursor, 0, vectorSize);
|
||||
#endif
|
||||
|
|
@ -2623,10 +2623,10 @@ JSScript::initFunctionPrototype(ExclusiveContext* cx, Handle<JSScript*> script,
|
|||
uint32_t numObjects = 0;
|
||||
uint32_t numTryNotes = 0;
|
||||
uint32_t numScopeNotes = 0;
|
||||
uint32_t numYieldOffsets = 0;
|
||||
uint32_t numYieldAndAwaitOffsets = 0;
|
||||
uint32_t numTypeSets = 0;
|
||||
if (!partiallyInit(cx, script, numScopes, numConsts, numObjects, numTryNotes,
|
||||
numScopeNotes, numYieldOffsets, numTypeSets))
|
||||
numScopeNotes, numYieldAndAwaitOffsets, numTypeSets))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2739,7 +2739,7 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
|
|||
if (!partiallyInit(cx, script,
|
||||
bce->scopeList.length(), bce->constList.length(), bce->objectList.length,
|
||||
bce->tryNoteList.length(), bce->scopeNoteList.length(),
|
||||
bce->yieldOffsetList.length(), bce->typesetCount))
|
||||
bce->yieldAndAwaitOffsetList.length(), bce->typesetCount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2794,8 +2794,8 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
|
|||
|
||||
// Copy yield offsets last, as the generator kind is set in
|
||||
// initFromFunctionBox.
|
||||
if (bce->yieldOffsetList.length() != 0)
|
||||
bce->yieldOffsetList.finish(script->yieldOffsets(), prologueLength);
|
||||
if (bce->yieldAndAwaitOffsetList.length() != 0)
|
||||
bce->yieldAndAwaitOffsetList.finish(script->yieldAndAwaitOffsets(), prologueLength);
|
||||
|
||||
#ifdef DEBUG
|
||||
script->assertValidJumpTargets();
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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) \
|
||||
/*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue