зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1412202 - Part 4: Copy any unaliased locals between stack and GeneratorObject on suspend/resume. r=jandem
No effect yet, as there are no unaliased locals to copy. Differential Revision: https://phabricator.services.mozilla.com/D93384
This commit is contained in:
Родитель
61a1c23f13
Коммит
250ff7fccb
|
@ -5780,12 +5780,10 @@ bool BaselineCodeGen<Handler>::emitSuspend(JSOp op) {
|
|||
masm.unboxObject(R0, genObj);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
size_t liveFixed;
|
||||
MOZ_ASSERT_IF(handler.tryCountLiveFixed(&liveFixed), liveFixed == 0);
|
||||
#endif
|
||||
|
||||
if (op == JSOp::InitialYield || frame.hasKnownStackDepth(1)) {
|
||||
if (frame.hasKnownStackDepth(1) && !handler.canHaveFixedSlots()) {
|
||||
// If the expression stack is empty, we can inline the Yield. Note that this
|
||||
// branch is never taken for the interpreter because it doesn't know static
|
||||
// stack depths.
|
||||
MOZ_ASSERT_IF(op == JSOp::InitialYield && handler.maybePC(),
|
||||
GET_RESUMEINDEX(handler.maybePC()) == 0);
|
||||
Address resumeIndexSlot(genObj,
|
||||
|
@ -5794,9 +5792,6 @@ bool BaselineCodeGen<Handler>::emitSuspend(JSOp op) {
|
|||
if (op == JSOp::InitialYield) {
|
||||
masm.storeValue(Int32Value(0), resumeIndexSlot);
|
||||
} else {
|
||||
// If the expression stack is empty, we can inline the Yield. Note that
|
||||
// this branch is never taken for the interpreter because it doesn't know
|
||||
// static stack depths.
|
||||
jsbytecode* pc = handler.maybePC();
|
||||
MOZ_ASSERT(pc, "compiler-only code never has a null pc");
|
||||
masm.move32(Imm32(GET_RESUMEINDEX(pc)), temp);
|
||||
|
@ -5814,14 +5809,8 @@ bool BaselineCodeGen<Handler>::emitSuspend(JSOp op) {
|
|||
masm.branchPtrInNurseryChunk(Assembler::Equal, genObj, temp, &skipBarrier);
|
||||
masm.branchPtrInNurseryChunk(Assembler::NotEqual, envObj, temp,
|
||||
&skipBarrier);
|
||||
if (op == JSOp::InitialYield) {
|
||||
masm.push(genObj);
|
||||
}
|
||||
MOZ_ASSERT(genObj == R2.scratchReg());
|
||||
masm.call(&postBarrierSlot_);
|
||||
if (op == JSOp::InitialYield) {
|
||||
masm.pop(genObj);
|
||||
}
|
||||
masm.bind(&skipBarrier);
|
||||
} else {
|
||||
masm.loadBaselineFramePtr(BaselineFrameReg, R1.scratchReg());
|
||||
|
@ -5839,8 +5828,8 @@ bool BaselineCodeGen<Handler>::emitSuspend(JSOp op) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
masm.loadValue(frame.addressOfStackValue(-1), JSReturnOperand);
|
||||
|
||||
masm.loadValue(frame.addressOfStackValue(-1), JSReturnOperand);
|
||||
if (!emitReturn()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -6145,7 +6134,7 @@ bool BaselineCodeGen<Handler>::emit_Resume() {
|
|||
}
|
||||
masm.bind(&noArgsObj);
|
||||
|
||||
// Push expression slots if needed.
|
||||
// Push locals and expression slots if needed.
|
||||
Label noStackStorage;
|
||||
Address stackStorageSlot(genObj,
|
||||
AbstractGeneratorObject::offsetOfStackStorageSlot());
|
||||
|
|
|
@ -362,10 +362,7 @@ class BaselineCompilerHandler {
|
|||
return script()->nslots() > NumSlotsLimit;
|
||||
}
|
||||
|
||||
bool tryCountLiveFixed(size_t* liveFixed) const {
|
||||
*liveFixed = script()->calculateLiveFixed(pc());
|
||||
return true;
|
||||
}
|
||||
bool canHaveFixedSlots() const { return script()->nfixed() != 0; }
|
||||
};
|
||||
|
||||
using BaselineCompilerCodeGen = BaselineCodeGen<BaselineCompilerHandler>;
|
||||
|
@ -488,7 +485,7 @@ class BaselineInterpreterHandler {
|
|||
// include them.
|
||||
bool mustIncludeSlotsInStackCheck() const { return true; }
|
||||
|
||||
bool tryCountLiveFixed(size_t* liveFixed) const { return false; }
|
||||
bool canHaveFixedSlots() const { return true; }
|
||||
};
|
||||
|
||||
using BaselineInterpreterCodeGen = BaselineCodeGen<BaselineInterpreterHandler>;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "vm/EnvironmentObject-inl.h"
|
||||
#include "vm/JSScript-inl.h"
|
||||
#include "vm/NativeObject-inl.h" // js::NativeObject::initDenseElementsFromRange
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
@ -39,6 +40,17 @@ inline void BaselineFrame::replaceInnermostEnvironment(EnvironmentObject& env) {
|
|||
envChain_ = &env;
|
||||
}
|
||||
|
||||
inline bool BaselineFrame::saveGeneratorSlots(JSContext* cx, unsigned nslots,
|
||||
ArrayObject* dest) const {
|
||||
// By convention, generator slots are stored in interpreter order,
|
||||
// which is the reverse of BaselineFrame order.
|
||||
|
||||
MOZ_ASSERT(nslots == numValueSlots(debugFrameSize()) - 1);
|
||||
const Value* end = reinterpret_cast<const Value*>(this);
|
||||
mozilla::Span<const Value> span{end - nslots, end};
|
||||
return dest->initDenseElementsFromRange(cx, span.rbegin(), span.rend());
|
||||
}
|
||||
|
||||
inline bool BaselineFrame::pushLexicalEnvironment(JSContext* cx,
|
||||
Handle<LexicalScope*> scope) {
|
||||
LexicalEnvironmentObject* env =
|
||||
|
|
|
@ -195,6 +195,9 @@ class BaselineFrame {
|
|||
BaselineFrame::Size() + offsetOfArg(0));
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool saveGeneratorSlots(JSContext* cx, unsigned nslots,
|
||||
ArrayObject* dest) const;
|
||||
|
||||
private:
|
||||
Value* evalNewTargetAddress() const {
|
||||
MOZ_ASSERT(isEvalFrame());
|
||||
|
|
|
@ -1437,33 +1437,13 @@ JSObject* CreateGenerator(JSContext* cx, BaselineFrame* frame) {
|
|||
|
||||
bool NormalSuspend(JSContext* cx, HandleObject obj, BaselineFrame* frame,
|
||||
uint32_t frameSize, jsbytecode* pc) {
|
||||
MOZ_ASSERT(JSOp(*pc) == JSOp::Yield || JSOp(*pc) == JSOp::Await);
|
||||
MOZ_ASSERT(JSOp(*pc) == JSOp::InitialYield || JSOp(*pc) == JSOp::Yield ||
|
||||
JSOp(*pc) == JSOp::Await);
|
||||
|
||||
uint32_t numValueSlots = frame->numValueSlots(frameSize);
|
||||
|
||||
MOZ_ASSERT(numValueSlots > frame->script()->nfixed());
|
||||
uint32_t stackDepth = numValueSlots - frame->script()->nfixed();
|
||||
|
||||
// Return value is still on the stack.
|
||||
MOZ_ASSERT(stackDepth >= 1);
|
||||
|
||||
// The expression stack slots are stored on the stack in reverse order, so
|
||||
// we copy them to a Vector and pass a pointer to that instead. We use
|
||||
// stackDepth - 1 because we don't want to include the return value.
|
||||
RootedValueVector stackStorage(cx);
|
||||
if (!stackStorage.reserve(stackDepth - 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t firstSlot = numValueSlots - stackDepth;
|
||||
for (size_t i = 0; i < stackDepth - 1; i++) {
|
||||
stackStorage.infallibleAppend(*frame->valueSlot(firstSlot + i));
|
||||
}
|
||||
|
||||
MOZ_ASSERT(stackStorage.length() == stackDepth - 1);
|
||||
|
||||
return AbstractGeneratorObject::normalSuspend(
|
||||
cx, obj, frame, pc, stackStorage.begin(), stackDepth - 1);
|
||||
// Minus one because we don't want to include the return value.
|
||||
uint32_t numSlots = frame->numValueSlots(frameSize) - 1;
|
||||
MOZ_ASSERT(numSlots >= frame->script()->nfixed());
|
||||
return AbstractGeneratorObject::suspend(cx, obj, frame, pc, numSlots);
|
||||
}
|
||||
|
||||
bool FinalSuspend(JSContext* cx, HandleObject obj, jsbytecode* pc) {
|
||||
|
|
|
@ -28,7 +28,6 @@ using namespace js;
|
|||
JSObject* AbstractGeneratorObject::create(JSContext* cx,
|
||||
AbstractFramePtr frame) {
|
||||
MOZ_ASSERT(frame.isGeneratorFrame());
|
||||
MOZ_ASSERT(frame.script()->nfixed() == 0);
|
||||
MOZ_ASSERT(!frame.isConstructing());
|
||||
|
||||
RootedFunction fun(cx, frame.callee());
|
||||
|
@ -65,7 +64,7 @@ void AbstractGeneratorObject::trace(JSTracer* trc) {
|
|||
|
||||
bool AbstractGeneratorObject::suspend(JSContext* cx, HandleObject obj,
|
||||
AbstractFramePtr frame, jsbytecode* pc,
|
||||
Value* vp, unsigned nvalues) {
|
||||
unsigned nvalues) {
|
||||
MOZ_ASSERT(JSOp(*pc) == JSOp::InitialYield || JSOp(*pc) == JSOp::Yield ||
|
||||
JSOp(*pc) == JSOp::Await);
|
||||
|
||||
|
@ -74,36 +73,24 @@ bool AbstractGeneratorObject::suspend(JSContext* cx, HandleObject obj,
|
|||
MOZ_ASSERT_IF(JSOp(*pc) == JSOp::Await, genObj->callee().isAsync());
|
||||
MOZ_ASSERT_IF(JSOp(*pc) == JSOp::Yield, genObj->callee().isGenerator());
|
||||
|
||||
ArrayObject* stack = nullptr;
|
||||
if (nvalues > 0) {
|
||||
do {
|
||||
if (genObj->hasStackStorage()) {
|
||||
MOZ_ASSERT(genObj->stackStorage().getDenseInitializedLength() == 0);
|
||||
auto result = genObj->stackStorage().setOrExtendDenseElements(
|
||||
cx, 0, vp, nvalues, ShouldUpdateTypes::DontUpdate);
|
||||
if (result == DenseElementResult::Success) {
|
||||
MOZ_ASSERT(genObj->stackStorage().getDenseInitializedLength() ==
|
||||
nvalues);
|
||||
break;
|
||||
}
|
||||
if (result == DenseElementResult::Failure) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
stack = NewDenseCopiedArray(cx, nvalues, vp);
|
||||
ArrayObject* stack = nullptr;
|
||||
if (genObj->hasStackStorage()) {
|
||||
stack = &genObj->stackStorage();
|
||||
} else {
|
||||
stack = NewDenseEmptyArray(cx);
|
||||
if (!stack) {
|
||||
return false;
|
||||
}
|
||||
} while (false);
|
||||
genObj->setStackStorage(*stack);
|
||||
}
|
||||
if (!frame.saveGeneratorSlots(cx, nvalues, stack)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
genObj->setResumeIndex(pc);
|
||||
genObj->setEnvironmentChain(*frame.environmentChain());
|
||||
if (stack) {
|
||||
genObj->setStackStorage(*stack);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -127,23 +114,13 @@ AbstractGeneratorObject* js::GetGeneratorObjectForFrame(
|
|||
Shape* shape = callObj.lookup(cx, cx->names().dotGenerator);
|
||||
Value genValue = callObj.getSlot(shape->slot());
|
||||
|
||||
// If the `generator; setaliasedvar ".generator"; initialyield` bytecode
|
||||
// If the `Generator; SetAliasedVar ".generator"; InitialYield` bytecode
|
||||
// sequence has not run yet, genValue is undefined.
|
||||
return genValue.isObject()
|
||||
? &genValue.toObject().as<AbstractGeneratorObject>()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void js::SetGeneratorClosed(JSContext* cx, AbstractFramePtr frame) {
|
||||
CallObject& callObj = frame.callObj();
|
||||
|
||||
// Get the generator object stored on the scope chain and close it.
|
||||
Shape* shape = callObj.lookup(cx, cx->names().dotGenerator);
|
||||
auto& genObj =
|
||||
callObj.getSlot(shape->slot()).toObject().as<AbstractGeneratorObject>();
|
||||
genObj.setClosed();
|
||||
}
|
||||
|
||||
bool js::GeneratorThrowOrReturn(JSContext* cx, AbstractFramePtr frame,
|
||||
Handle<AbstractGeneratorObject*> genObj,
|
||||
HandleValue arg,
|
||||
|
@ -181,12 +158,12 @@ bool AbstractGeneratorObject::resume(JSContext* cx,
|
|||
}
|
||||
|
||||
if (genObj->hasStackStorage() && !genObj->isStackStorageEmpty()) {
|
||||
uint32_t len = genObj->stackStorage().getDenseInitializedLength();
|
||||
MOZ_ASSERT(activation.regs().spForStackDepth(len));
|
||||
const Value* src = genObj->stackStorage().getDenseElements();
|
||||
mozilla::PodCopy(activation.regs().sp, src, len);
|
||||
activation.regs().sp += len;
|
||||
genObj->stackStorage().setDenseInitializedLength(0);
|
||||
JSScript* script = activation.regs().fp()->script();
|
||||
ArrayObject* storage = &genObj->stackStorage();
|
||||
uint32_t len = storage->getDenseInitializedLength();
|
||||
activation.regs().fp()->restoreGeneratorSlots(storage);
|
||||
activation.regs().sp += len - script->nfixed();
|
||||
storage->setDenseInitializedLength(0);
|
||||
}
|
||||
|
||||
JSScript* script = callee->nonLazyScript();
|
||||
|
|
|
@ -38,10 +38,6 @@ class AbstractGeneratorObject : public NativeObject {
|
|||
RESERVED_SLOTS
|
||||
};
|
||||
|
||||
private:
|
||||
static bool suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame,
|
||||
jsbytecode* pc, Value* vp, unsigned nvalues);
|
||||
|
||||
public:
|
||||
static JSObject* create(JSContext* cx, AbstractFramePtr frame);
|
||||
|
||||
|
@ -49,16 +45,8 @@ class AbstractGeneratorObject : public NativeObject {
|
|||
Handle<AbstractGeneratorObject*> genObj, HandleValue arg,
|
||||
HandleValue resumeKind);
|
||||
|
||||
static bool initialSuspend(JSContext* cx, HandleObject obj,
|
||||
AbstractFramePtr frame, jsbytecode* pc) {
|
||||
return suspend(cx, obj, frame, pc, nullptr, 0);
|
||||
}
|
||||
|
||||
static bool normalSuspend(JSContext* cx, HandleObject obj,
|
||||
AbstractFramePtr frame, jsbytecode* pc, Value* vp,
|
||||
unsigned nvalues) {
|
||||
return suspend(cx, obj, frame, pc, vp, nvalues);
|
||||
}
|
||||
static bool suspend(JSContext* cx, HandleObject obj, AbstractFramePtr frame,
|
||||
jsbytecode* pc, unsigned nvalues);
|
||||
|
||||
static void finalSuspend(HandleObject obj);
|
||||
|
||||
|
@ -210,8 +198,6 @@ bool GeneratorThrowOrReturn(JSContext* cx, AbstractFramePtr frame,
|
|||
AbstractGeneratorObject* GetGeneratorObjectForFrame(JSContext* cx,
|
||||
AbstractFramePtr frame);
|
||||
|
||||
void SetGeneratorClosed(JSContext* cx, AbstractFramePtr frame);
|
||||
|
||||
inline GeneratorResumeKind IntToResumeKind(int32_t value) {
|
||||
MOZ_ASSERT(uint32_t(value) <= uint32_t(GeneratorResumeKind::Return));
|
||||
return static_cast<GeneratorResumeKind>(value);
|
||||
|
|
|
@ -1274,7 +1274,8 @@ bool js::HandleClosingGeneratorReturn(JSContext* cx, AbstractFramePtr frame,
|
|||
if (cx->isClosingGenerator()) {
|
||||
cx->clearPendingException();
|
||||
ok = true;
|
||||
SetGeneratorClosed(cx, frame);
|
||||
auto* genObj = GetGeneratorObjectForFrame(cx, frame);
|
||||
genObj->setClosed();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
@ -4265,8 +4266,8 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-1].toObject());
|
||||
POP_RETURN_VALUE();
|
||||
MOZ_ASSERT(REGS.stackDepth() == 0);
|
||||
if (!AbstractGeneratorObject::initialSuspend(cx, obj, REGS.fp(),
|
||||
REGS.pc)) {
|
||||
if (!AbstractGeneratorObject::suspend(cx, obj, REGS.fp(), REGS.pc,
|
||||
script->nfixed())) {
|
||||
goto error;
|
||||
}
|
||||
goto successful_return_continuation;
|
||||
|
@ -4277,9 +4278,9 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
MOZ_ASSERT(REGS.fp()->isFunctionFrame());
|
||||
ReservedRooted<JSObject*> obj(&rootObject0, ®S.sp[-1].toObject());
|
||||
if (!AbstractGeneratorObject::normalSuspend(cx, obj, REGS.fp(), REGS.pc,
|
||||
REGS.spForStackDepth(0),
|
||||
REGS.stackDepth() - 2)) {
|
||||
if (!AbstractGeneratorObject::suspend(
|
||||
cx, obj, REGS.fp(), REGS.pc,
|
||||
script->nfixed() + REGS.stackDepth() - 2)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
|
@ -229,6 +229,48 @@ inline void NativeObject::initDenseElements(const Value* src, uint32_t count) {
|
|||
elementsRangePostWriteBarrier(0, count);
|
||||
}
|
||||
|
||||
template <typename Iter>
|
||||
inline bool NativeObject::initDenseElementsFromRange(JSContext* cx, Iter begin,
|
||||
Iter end) {
|
||||
// This method populates the elements of a particular Array that's an
|
||||
// internal implementation detail of GeneratorObject. Failing any of the
|
||||
// following means the Array has escaped and/or been mistreated.
|
||||
MOZ_ASSERT(isExtensible());
|
||||
MOZ_ASSERT(!isIndexed());
|
||||
MOZ_ASSERT(is<ArrayObject>());
|
||||
MOZ_ASSERT(as<ArrayObject>().lengthIsWritable());
|
||||
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
|
||||
MOZ_ASSERT(!denseElementsAreFrozen());
|
||||
MOZ_ASSERT(getElementsHeader()->numShiftedElements() == 0);
|
||||
|
||||
MOZ_ASSERT(getDenseInitializedLength() == 0);
|
||||
|
||||
auto size = end - begin;
|
||||
uint32_t count = uint32_t(size);
|
||||
MOZ_ASSERT(count == size);
|
||||
MOZ_ASSERT(count <= uint32_t(INT32_MAX));
|
||||
if (count > getDenseCapacity()) {
|
||||
if (!growElements(cx, count)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
HeapSlot* sp = elements_;
|
||||
size_t slot = 0;
|
||||
for (; begin != end; sp++, begin++) {
|
||||
Value v = *begin;
|
||||
#ifdef DEBUG
|
||||
checkStoredValue(v);
|
||||
#endif
|
||||
sp->init(this, HeapSlot::Element, slot++, v);
|
||||
}
|
||||
MOZ_ASSERT(slot == count);
|
||||
|
||||
getElementsHeader()->initializedLength = count;
|
||||
as<ArrayObject>().setLengthInt32(count);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool NativeObject::tryShiftDenseElements(uint32_t count) {
|
||||
MOZ_ASSERT(isExtensible());
|
||||
|
||||
|
|
|
@ -1408,9 +1408,24 @@ class NativeObject : public JSObject {
|
|||
|
||||
inline void copyDenseElements(uint32_t dstStart, const Value* src,
|
||||
uint32_t count);
|
||||
|
||||
inline void initDenseElements(const Value* src, uint32_t count);
|
||||
inline void initDenseElements(JSContext* cx, NativeObject* src,
|
||||
uint32_t srcStart, uint32_t count);
|
||||
|
||||
// Store the Values in the range [begin, end) as elements of this array.
|
||||
//
|
||||
// Preconditions: This must be a boring ArrayObject with dense initialized
|
||||
// length 0: no shifted elements, no frozen elements, no fixed "length", not
|
||||
// indexed, not inextensible, not copy-on-write. Existing capacity is
|
||||
// optional.
|
||||
//
|
||||
// This runs write barriers but does not update types. `end - begin` must
|
||||
// return the size of the range, which must be >= 0 and fit in an int32_t.
|
||||
template <typename Iter>
|
||||
inline MOZ_MUST_USE bool initDenseElementsFromRange(JSContext* cx, Iter begin,
|
||||
Iter end);
|
||||
|
||||
inline void moveDenseElements(uint32_t dstStart, uint32_t srcStart,
|
||||
uint32_t count);
|
||||
inline void reverseDenseElementsNoPreBarrier(uint32_t length);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
|
||||
#include "builtin/Array.h" // js::NewDenseEmptyArray
|
||||
#include "jit/BaselineFrame.h"
|
||||
#include "jit/RematerializedFrame.h"
|
||||
#include "js/Debug.h"
|
||||
|
@ -186,6 +187,19 @@ inline void InterpreterFrame::unsetIsDebuggee() {
|
|||
flags_ &= ~DEBUGGEE;
|
||||
}
|
||||
|
||||
inline bool InterpreterFrame::saveGeneratorSlots(JSContext* cx, unsigned nslots,
|
||||
ArrayObject* dest) const {
|
||||
return dest->initDenseElementsFromRange(cx, slots(), slots() + nslots);
|
||||
}
|
||||
|
||||
inline void InterpreterFrame::restoreGeneratorSlots(ArrayObject* src) {
|
||||
MOZ_ASSERT(script()->nfixed() <= src->length());
|
||||
MOZ_ASSERT(src->length() <= script()->nslots());
|
||||
MOZ_ASSERT(src->getDenseInitializedLength() == src->length());
|
||||
const Value* srcElements = src->getDenseElements();
|
||||
mozilla::PodCopy(slots(), srcElements, src->length());
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
inline void InterpreterStack::purge(JSRuntime* rt) {
|
||||
|
@ -661,6 +675,16 @@ inline bool AbstractFramePtr::isGeneratorFrame() const {
|
|||
return s->isGenerator() || s->isAsync();
|
||||
}
|
||||
|
||||
inline bool AbstractFramePtr::saveGeneratorSlots(JSContext* cx, unsigned nslots,
|
||||
ArrayObject* dest) const {
|
||||
MOZ_ASSERT(isGeneratorFrame());
|
||||
if (isInterpreterFrame()) {
|
||||
return asInterpreterFrame()->saveGeneratorSlots(cx, nslots, dest);
|
||||
}
|
||||
MOZ_ASSERT(isBaselineFrame(), "unexpected generator frame in Ion");
|
||||
return asBaselineFrame()->saveGeneratorSlots(cx, nslots, dest);
|
||||
}
|
||||
|
||||
inline Value* AbstractFramePtr::argv() const {
|
||||
if (isInterpreterFrame()) {
|
||||
return asInterpreterFrame()->argv();
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Span.h" // for Span
|
||||
#include "mozilla/Variant.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -213,6 +214,9 @@ class AbstractFramePtr {
|
|||
inline bool isFunctionFrame() const;
|
||||
inline bool isGeneratorFrame() const;
|
||||
|
||||
inline bool saveGeneratorSlots(JSContext* cx, unsigned nslots,
|
||||
ArrayObject* dest) const;
|
||||
|
||||
inline unsigned numActualArgs() const;
|
||||
inline unsigned numFormalArgs() const;
|
||||
|
||||
|
@ -641,6 +645,14 @@ class InterpreterFrame {
|
|||
markReturnValue();
|
||||
}
|
||||
|
||||
// Copy values from this frame into a private Array, owned by the
|
||||
// GeneratorObject, for suspending.
|
||||
MOZ_MUST_USE inline bool saveGeneratorSlots(JSContext* cx, unsigned nslots,
|
||||
ArrayObject* dest) const;
|
||||
|
||||
// Copy values from the Array into this stack frame, for resuming.
|
||||
inline void restoreGeneratorSlots(ArrayObject* src);
|
||||
|
||||
void resumeGeneratorFrame(JSObject* envChain) {
|
||||
MOZ_ASSERT(script()->isGenerator() || script()->isAsync());
|
||||
MOZ_ASSERT(isFunctionFrame());
|
||||
|
|
Загрузка…
Ссылка в новой задаче