mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-24 19:37:15 +00:00
Bug 1728549 - Un-inline some stack map generator functions. r=jseward
Not moving createStackMap during the initial refactor was an oversight. We take the opportunity to do some minor related cleanup. Differential Revision: https://phabricator.services.mozilla.com/D124182
This commit is contained in:
parent
cdf590aadd
commit
5a9e854ada
@ -31,6 +31,10 @@
|
||||
namespace js {
|
||||
namespace wasm {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// BaseLocalIter methods.
|
||||
|
||||
BaseLocalIter::BaseLocalIter(const ValTypeVector& locals,
|
||||
const ArgTypeVector& args, bool debugEnabled)
|
||||
: locals_(locals),
|
||||
@ -131,6 +135,10 @@ void BaseLocalIter::operator++(int) {
|
||||
settle();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Stack map methods.
|
||||
|
||||
bool BaseCompiler::createStackMap(const char* who) {
|
||||
const ExitStubMapVector noExtras;
|
||||
return stackMapGenerator_.createStackMap(who, noExtras, masm.currentOffset(),
|
||||
@ -158,6 +166,269 @@ bool BaseCompiler::createStackMap(
|
||||
debugFrameWithLiveRefs, stk_);
|
||||
}
|
||||
|
||||
bool MachineStackTracker::cloneTo(MachineStackTracker* dst) {
|
||||
MOZ_ASSERT(dst->vec_.empty());
|
||||
if (!dst->vec_.appendAll(vec_)) {
|
||||
return false;
|
||||
}
|
||||
dst->numPtrs_ = numPtrs_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StackMapGenerator::generateStackmapEntriesForTrapExit(
|
||||
const ArgTypeVector& args, ExitStubMapVector* extras) {
|
||||
return GenerateStackmapEntriesForTrapExit(args, trapExitLayout_,
|
||||
trapExitLayoutNumWords_, extras);
|
||||
}
|
||||
|
||||
bool StackMapGenerator::createStackMap(
|
||||
const char* who, const ExitStubMapVector& extras, uint32_t assemblerOffset,
|
||||
HasDebugFrameWithLiveRefs debugFrameWithLiveRefs, const StkVector& stk) {
|
||||
size_t countedPointers = machineStackTracker.numPtrs() + memRefsOnStk;
|
||||
#ifndef DEBUG
|
||||
// An important optimization. If there are obviously no pointers, as
|
||||
// we expect in the majority of cases, exit quickly.
|
||||
if (countedPointers == 0 &&
|
||||
debugFrameWithLiveRefs == HasDebugFrameWithLiveRefs::No) {
|
||||
// We can skip creating the map if there are no |true| elements in
|
||||
// |extras|.
|
||||
bool extrasHasRef = false;
|
||||
for (bool b : extras) {
|
||||
if (b) {
|
||||
extrasHasRef = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!extrasHasRef) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// In the debug case, create the stackmap regardless, and cross-check
|
||||
// the pointer-counting below. We expect the final map to have
|
||||
// |countedPointers| in total. This doesn't include those in the
|
||||
// DebugFrame, but they do not appear in the map's bitmap. Note that
|
||||
// |countedPointers| is debug-only from this point onwards.
|
||||
for (bool b : extras) {
|
||||
countedPointers += (b ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Start with the frame-setup map, and add operand-stack information to
|
||||
// that. augmentedMst holds live data only within individual calls to
|
||||
// createStackMap.
|
||||
augmentedMst.clear();
|
||||
if (!machineStackTracker.cloneTo(&augmentedMst)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// At this point, augmentedMst only contains entries covering the
|
||||
// incoming argument area (if any) and for the area allocated by this
|
||||
// function's prologue. We now need to calculate how far the machine's
|
||||
// stack pointer is below where it was at the start of the body. But we
|
||||
// must take care not to include any words pushed as arguments to an
|
||||
// upcoming function call, since those words "belong" to the stackmap of
|
||||
// the callee, not to the stackmap of this function. Note however that
|
||||
// any alignment padding pushed prior to pushing the args *does* belong to
|
||||
// this function.
|
||||
//
|
||||
// That padding is taken into account at the point where
|
||||
// framePushedExcludingOutboundCallArgs is set, viz, in startCallArgs(),
|
||||
// and comprises two components:
|
||||
//
|
||||
// * call->frameAlignAdjustment
|
||||
// * the padding applied to the stack arg area itself. That is:
|
||||
// StackArgAreaSize(argTys) - StackArgAreaSizeUnpadded(argTys)
|
||||
Maybe<uint32_t> framePushedExcludingArgs;
|
||||
if (framePushedAtEntryToBody.isNothing()) {
|
||||
// Still in the prologue. framePushedExcludingArgs remains Nothing.
|
||||
MOZ_ASSERT(framePushedExcludingOutboundCallArgs.isNothing());
|
||||
} else {
|
||||
// In the body.
|
||||
MOZ_ASSERT(masm_.framePushed() >= framePushedAtEntryToBody.value());
|
||||
if (framePushedExcludingOutboundCallArgs.isSome()) {
|
||||
// In the body, and we've potentially pushed some args onto the stack.
|
||||
// We must ignore them when sizing the stackmap.
|
||||
MOZ_ASSERT(masm_.framePushed() >=
|
||||
framePushedExcludingOutboundCallArgs.value());
|
||||
MOZ_ASSERT(framePushedExcludingOutboundCallArgs.value() >=
|
||||
framePushedAtEntryToBody.value());
|
||||
framePushedExcludingArgs =
|
||||
Some(framePushedExcludingOutboundCallArgs.value());
|
||||
} else {
|
||||
// In the body, but not with call args on the stack. The stackmap
|
||||
// must be sized so as to extend all the way "down" to
|
||||
// masm_.framePushed().
|
||||
framePushedExcludingArgs = Some(masm_.framePushed());
|
||||
}
|
||||
}
|
||||
|
||||
if (framePushedExcludingArgs.isSome()) {
|
||||
uint32_t bodyPushedBytes =
|
||||
framePushedExcludingArgs.value() - framePushedAtEntryToBody.value();
|
||||
MOZ_ASSERT(0 == bodyPushedBytes % sizeof(void*));
|
||||
if (!augmentedMst.pushNonGCPointers(bodyPushedBytes / sizeof(void*))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan the operand stack, marking pointers in the just-added new
|
||||
// section.
|
||||
MOZ_ASSERT_IF(framePushedAtEntryToBody.isNothing(), stk.empty());
|
||||
MOZ_ASSERT_IF(framePushedExcludingArgs.isNothing(), stk.empty());
|
||||
|
||||
for (const Stk& v : stk) {
|
||||
#ifndef DEBUG
|
||||
// We don't track roots in registers, per rationale below, so if this
|
||||
// doesn't hold, something is seriously wrong, and we're likely to get a
|
||||
// GC-related crash.
|
||||
MOZ_RELEASE_ASSERT(v.kind() != Stk::RegisterRef);
|
||||
if (v.kind() != Stk::MemRef) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
// Take the opportunity to check everything we reasonably can about
|
||||
// operand stack elements.
|
||||
switch (v.kind()) {
|
||||
case Stk::MemI32:
|
||||
case Stk::MemI64:
|
||||
case Stk::MemF32:
|
||||
case Stk::MemF64:
|
||||
case Stk::ConstI32:
|
||||
case Stk::ConstI64:
|
||||
case Stk::ConstF32:
|
||||
case Stk::ConstF64:
|
||||
# ifdef ENABLE_WASM_SIMD
|
||||
case Stk::MemV128:
|
||||
case Stk::ConstV128:
|
||||
# endif
|
||||
// All of these have uninteresting type.
|
||||
continue;
|
||||
case Stk::LocalI32:
|
||||
case Stk::LocalI64:
|
||||
case Stk::LocalF32:
|
||||
case Stk::LocalF64:
|
||||
# ifdef ENABLE_WASM_SIMD
|
||||
case Stk::LocalV128:
|
||||
# endif
|
||||
// These also have uninteresting type. Check that they live in the
|
||||
// section of stack set up by beginFunction(). The unguarded use of
|
||||
// |value()| here is safe due to the assertion above this loop.
|
||||
MOZ_ASSERT(v.offs() <= framePushedAtEntryToBody.value());
|
||||
continue;
|
||||
case Stk::RegisterI32:
|
||||
case Stk::RegisterI64:
|
||||
case Stk::RegisterF32:
|
||||
case Stk::RegisterF64:
|
||||
# ifdef ENABLE_WASM_SIMD
|
||||
case Stk::RegisterV128:
|
||||
# endif
|
||||
// These also have uninteresting type, but more to the point: all
|
||||
// registers holding live values should have been flushed to the
|
||||
// machine stack immediately prior to the instruction to which this
|
||||
// stackmap pertains. So these can't happen.
|
||||
MOZ_CRASH("createStackMap: operand stack has Register-non-Ref");
|
||||
case Stk::MemRef:
|
||||
// This is the only case we care about. We'll handle it after the
|
||||
// switch.
|
||||
break;
|
||||
case Stk::LocalRef:
|
||||
// We need the stackmap to mention this pointer, but it should
|
||||
// already be in the machineStackTracker section created by
|
||||
// beginFunction().
|
||||
MOZ_ASSERT(v.offs() <= framePushedAtEntryToBody.value());
|
||||
continue;
|
||||
case Stk::ConstRef:
|
||||
// This can currently only be a null pointer.
|
||||
MOZ_ASSERT(v.refval() == 0);
|
||||
continue;
|
||||
case Stk::RegisterRef:
|
||||
// This can't happen, per rationale above.
|
||||
MOZ_CRASH("createStackMap: operand stack contains RegisterRef");
|
||||
default:
|
||||
MOZ_CRASH("createStackMap: unknown operand stack element");
|
||||
}
|
||||
#endif
|
||||
// v.offs() holds masm.framePushed() at the point immediately after it
|
||||
// was pushed on the stack. Since it's still on the stack,
|
||||
// masm.framePushed() can't be less.
|
||||
MOZ_ASSERT(v.offs() <= framePushedExcludingArgs.value());
|
||||
uint32_t offsFromMapLowest = framePushedExcludingArgs.value() - v.offs();
|
||||
MOZ_ASSERT(0 == offsFromMapLowest % sizeof(void*));
|
||||
augmentedMst.setGCPointer(offsFromMapLowest / sizeof(void*));
|
||||
}
|
||||
|
||||
// Create the final StackMap. The initial map is zeroed out, so there's
|
||||
// no need to write zero bits in it.
|
||||
const uint32_t extraWords = extras.length();
|
||||
const uint32_t augmentedMstWords = augmentedMst.length();
|
||||
const uint32_t numMappedWords = extraWords + augmentedMstWords;
|
||||
StackMap* stackMap = StackMap::create(numMappedWords);
|
||||
if (!stackMap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// First the exit stub extra words, if any.
|
||||
uint32_t i = 0;
|
||||
for (bool b : extras) {
|
||||
if (b) {
|
||||
stackMap->setBit(i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// Followed by the "main" part of the map.
|
||||
for (uint32_t i = 0; i < augmentedMstWords; i++) {
|
||||
if (augmentedMst.isGCPointer(i)) {
|
||||
stackMap->setBit(extraWords + i);
|
||||
}
|
||||
}
|
||||
|
||||
stackMap->setExitStubWords(extraWords);
|
||||
|
||||
// Record in the map, how far down from the highest address the Frame* is.
|
||||
// Take the opportunity to check that we haven't marked any part of the
|
||||
// Frame itself as a pointer.
|
||||
stackMap->setFrameOffsetFromTop(numStackArgWords +
|
||||
sizeof(Frame) / sizeof(void*));
|
||||
#ifdef DEBUG
|
||||
for (uint32_t i = 0; i < sizeof(Frame) / sizeof(void*); i++) {
|
||||
MOZ_ASSERT(stackMap->getBit(stackMap->numMappedWords -
|
||||
stackMap->frameOffsetFromTop + i) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Note the presence of a DebugFrame with live pointers, if any.
|
||||
if (debugFrameWithLiveRefs != HasDebugFrameWithLiveRefs::No) {
|
||||
stackMap->setHasDebugFrameWithLiveRefs();
|
||||
}
|
||||
|
||||
// Add the completed map to the running collection thereof.
|
||||
if (!stackMaps_->add((uint8_t*)(uintptr_t)assemblerOffset, stackMap)) {
|
||||
stackMap->destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Crosscheck the map pointer counting.
|
||||
uint32_t nw = stackMap->numMappedWords;
|
||||
uint32_t np = 0;
|
||||
for (uint32_t i = 0; i < nw; i++) {
|
||||
np += stackMap->getBit(i);
|
||||
}
|
||||
MOZ_ASSERT(size_t(np) == countedPointers);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Stack frame methods.
|
||||
|
||||
void BaseStackFrame::zeroLocals(BaseRegAlloc* ra) {
|
||||
MOZ_ASSERT(varLow_ != UINT32_MAX);
|
||||
|
||||
|
@ -1134,14 +1134,7 @@ class MachineStackTracker {
|
||||
}
|
||||
|
||||
// Clone this MachineStackTracker, writing the result at |dst|.
|
||||
[[nodiscard]] bool cloneTo(MachineStackTracker* dst) {
|
||||
MOZ_ASSERT(dst->vec_.empty());
|
||||
if (!dst->vec_.appendAll(vec_)) {
|
||||
return false;
|
||||
}
|
||||
dst->numPtrs_ = numPtrs_;
|
||||
return true;
|
||||
}
|
||||
[[nodiscard]] bool cloneTo(MachineStackTracker* dst);
|
||||
|
||||
// Notionally push |n| non-pointers on the stack.
|
||||
[[nodiscard]] bool pushNonGCPointers(size_t n) {
|
||||
@ -1273,10 +1266,7 @@ struct StackMapGenerator {
|
||||
// trapExitLayoutNumWords_, which together comprise a description of the
|
||||
// layout and are created by GenerateTrapExitMachineState().
|
||||
[[nodiscard]] bool generateStackmapEntriesForTrapExit(
|
||||
const ArgTypeVector& args, ExitStubMapVector* extras) {
|
||||
return GenerateStackmapEntriesForTrapExit(args, trapExitLayout_,
|
||||
trapExitLayoutNumWords_, extras);
|
||||
}
|
||||
const ArgTypeVector& args, ExitStubMapVector* extras);
|
||||
|
||||
// Creates a stackmap associated with the instruction denoted by
|
||||
// |assemblerOffset|, incorporating pointers from the current operand
|
||||
@ -1286,247 +1276,7 @@ struct StackMapGenerator {
|
||||
[[nodiscard]] bool createStackMap(
|
||||
const char* who, const ExitStubMapVector& extras,
|
||||
uint32_t assemblerOffset,
|
||||
HasDebugFrameWithLiveRefs debugFrameWithLiveRefs, const StkVector& stk) {
|
||||
size_t countedPointers = machineStackTracker.numPtrs() + memRefsOnStk;
|
||||
#ifndef DEBUG
|
||||
// An important optimization. If there are obviously no pointers, as
|
||||
// we expect in the majority of cases, exit quickly.
|
||||
if (countedPointers == 0 &&
|
||||
debugFrameWithLiveRefs == HasDebugFrameWithLiveRefs::No) {
|
||||
// We can skip creating the map if there are no |true| elements in
|
||||
// |extras|.
|
||||
bool extrasHasRef = false;
|
||||
for (bool b : extras) {
|
||||
if (b) {
|
||||
extrasHasRef = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!extrasHasRef) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// In the debug case, create the stackmap regardless, and cross-check
|
||||
// the pointer-counting below. We expect the final map to have
|
||||
// |countedPointers| in total. This doesn't include those in the
|
||||
// DebugFrame, but they do not appear in the map's bitmap. Note that
|
||||
// |countedPointers| is debug-only from this point onwards.
|
||||
for (bool b : extras) {
|
||||
countedPointers += (b ? 1 : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Start with the frame-setup map, and add operand-stack information to
|
||||
// that. augmentedMst holds live data only within individual calls to
|
||||
// createStackMap.
|
||||
augmentedMst.clear();
|
||||
if (!machineStackTracker.cloneTo(&augmentedMst)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// At this point, augmentedMst only contains entries covering the
|
||||
// incoming argument area (if any) and for the area allocated by this
|
||||
// function's prologue. We now need to calculate how far the machine's
|
||||
// stack pointer is below where it was at the start of the body. But we
|
||||
// must take care not to include any words pushed as arguments to an
|
||||
// upcoming function call, since those words "belong" to the stackmap of
|
||||
// the callee, not to the stackmap of this function. Note however that
|
||||
// any alignment padding pushed prior to pushing the args *does* belong to
|
||||
// this function.
|
||||
//
|
||||
// That padding is taken into account at the point where
|
||||
// framePushedExcludingOutboundCallArgs is set, viz, in startCallArgs(),
|
||||
// and comprises two components:
|
||||
//
|
||||
// * call->frameAlignAdjustment
|
||||
// * the padding applied to the stack arg area itself. That is:
|
||||
// StackArgAreaSize(argTys) - StackArgAreaSizeUnpadded(argTys)
|
||||
Maybe<uint32_t> framePushedExcludingArgs;
|
||||
if (framePushedAtEntryToBody.isNothing()) {
|
||||
// Still in the prologue. framePushedExcludingArgs remains Nothing.
|
||||
MOZ_ASSERT(framePushedExcludingOutboundCallArgs.isNothing());
|
||||
} else {
|
||||
// In the body.
|
||||
MOZ_ASSERT(masm_.framePushed() >= framePushedAtEntryToBody.value());
|
||||
if (framePushedExcludingOutboundCallArgs.isSome()) {
|
||||
// In the body, and we've potentially pushed some args onto the stack.
|
||||
// We must ignore them when sizing the stackmap.
|
||||
MOZ_ASSERT(masm_.framePushed() >=
|
||||
framePushedExcludingOutboundCallArgs.value());
|
||||
MOZ_ASSERT(framePushedExcludingOutboundCallArgs.value() >=
|
||||
framePushedAtEntryToBody.value());
|
||||
framePushedExcludingArgs =
|
||||
Some(framePushedExcludingOutboundCallArgs.value());
|
||||
} else {
|
||||
// In the body, but not with call args on the stack. The stackmap
|
||||
// must be sized so as to extend all the way "down" to
|
||||
// masm_.framePushed().
|
||||
framePushedExcludingArgs = Some(masm_.framePushed());
|
||||
}
|
||||
}
|
||||
|
||||
if (framePushedExcludingArgs.isSome()) {
|
||||
uint32_t bodyPushedBytes =
|
||||
framePushedExcludingArgs.value() - framePushedAtEntryToBody.value();
|
||||
MOZ_ASSERT(0 == bodyPushedBytes % sizeof(void*));
|
||||
if (!augmentedMst.pushNonGCPointers(bodyPushedBytes / sizeof(void*))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Scan the operand stack, marking pointers in the just-added new
|
||||
// section.
|
||||
MOZ_ASSERT_IF(framePushedAtEntryToBody.isNothing(), stk.empty());
|
||||
MOZ_ASSERT_IF(framePushedExcludingArgs.isNothing(), stk.empty());
|
||||
|
||||
for (const Stk& v : stk) {
|
||||
#ifndef DEBUG
|
||||
// We don't track roots in registers, per rationale below, so if this
|
||||
// doesn't hold, something is seriously wrong, and we're likely to get a
|
||||
// GC-related crash.
|
||||
MOZ_RELEASE_ASSERT(v.kind() != Stk::RegisterRef);
|
||||
if (v.kind() != Stk::MemRef) {
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
// Take the opportunity to check everything we reasonably can about
|
||||
// operand stack elements.
|
||||
switch (v.kind()) {
|
||||
case Stk::MemI32:
|
||||
case Stk::MemI64:
|
||||
case Stk::MemF32:
|
||||
case Stk::MemF64:
|
||||
case Stk::ConstI32:
|
||||
case Stk::ConstI64:
|
||||
case Stk::ConstF32:
|
||||
case Stk::ConstF64:
|
||||
# ifdef ENABLE_WASM_SIMD
|
||||
case Stk::MemV128:
|
||||
case Stk::ConstV128:
|
||||
# endif
|
||||
// All of these have uninteresting type.
|
||||
continue;
|
||||
case Stk::LocalI32:
|
||||
case Stk::LocalI64:
|
||||
case Stk::LocalF32:
|
||||
case Stk::LocalF64:
|
||||
# ifdef ENABLE_WASM_SIMD
|
||||
case Stk::LocalV128:
|
||||
# endif
|
||||
// These also have uninteresting type. Check that they live in the
|
||||
// section of stack set up by beginFunction(). The unguarded use of
|
||||
// |value()| here is safe due to the assertion above this loop.
|
||||
MOZ_ASSERT(v.offs() <= framePushedAtEntryToBody.value());
|
||||
continue;
|
||||
case Stk::RegisterI32:
|
||||
case Stk::RegisterI64:
|
||||
case Stk::RegisterF32:
|
||||
case Stk::RegisterF64:
|
||||
# ifdef ENABLE_WASM_SIMD
|
||||
case Stk::RegisterV128:
|
||||
# endif
|
||||
// These also have uninteresting type, but more to the point: all
|
||||
// registers holding live values should have been flushed to the
|
||||
// machine stack immediately prior to the instruction to which this
|
||||
// stackmap pertains. So these can't happen.
|
||||
MOZ_CRASH("createStackMap: operand stack has Register-non-Ref");
|
||||
case Stk::MemRef:
|
||||
// This is the only case we care about. We'll handle it after the
|
||||
// switch.
|
||||
break;
|
||||
case Stk::LocalRef:
|
||||
// We need the stackmap to mention this pointer, but it should
|
||||
// already be in the machineStackTracker section created by
|
||||
// beginFunction().
|
||||
MOZ_ASSERT(v.offs() <= framePushedAtEntryToBody.value());
|
||||
continue;
|
||||
case Stk::ConstRef:
|
||||
// This can currently only be a null pointer.
|
||||
MOZ_ASSERT(v.refval() == 0);
|
||||
continue;
|
||||
case Stk::RegisterRef:
|
||||
// This can't happen, per rationale above.
|
||||
MOZ_CRASH("createStackMap: operand stack contains RegisterRef");
|
||||
default:
|
||||
MOZ_CRASH("createStackMap: unknown operand stack element");
|
||||
}
|
||||
#endif
|
||||
// v.offs() holds masm.framePushed() at the point immediately after it
|
||||
// was pushed on the stack. Since it's still on the stack,
|
||||
// masm.framePushed() can't be less.
|
||||
MOZ_ASSERT(v.offs() <= framePushedExcludingArgs.value());
|
||||
uint32_t offsFromMapLowest = framePushedExcludingArgs.value() - v.offs();
|
||||
MOZ_ASSERT(0 == offsFromMapLowest % sizeof(void*));
|
||||
augmentedMst.setGCPointer(offsFromMapLowest / sizeof(void*));
|
||||
}
|
||||
|
||||
// Create the final StackMap. The initial map is zeroed out, so there's
|
||||
// no need to write zero bits in it.
|
||||
const uint32_t extraWords = extras.length();
|
||||
const uint32_t augmentedMstWords = augmentedMst.length();
|
||||
const uint32_t numMappedWords = extraWords + augmentedMstWords;
|
||||
StackMap* stackMap = StackMap::create(numMappedWords);
|
||||
if (!stackMap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// First the exit stub extra words, if any.
|
||||
uint32_t i = 0;
|
||||
for (bool b : extras) {
|
||||
if (b) {
|
||||
stackMap->setBit(i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// Followed by the "main" part of the map.
|
||||
for (uint32_t i = 0; i < augmentedMstWords; i++) {
|
||||
if (augmentedMst.isGCPointer(i)) {
|
||||
stackMap->setBit(extraWords + i);
|
||||
}
|
||||
}
|
||||
|
||||
stackMap->setExitStubWords(extraWords);
|
||||
|
||||
// Record in the map, how far down from the highest address the Frame* is.
|
||||
// Take the opportunity to check that we haven't marked any part of the
|
||||
// Frame itself as a pointer.
|
||||
stackMap->setFrameOffsetFromTop(numStackArgWords +
|
||||
sizeof(Frame) / sizeof(void*));
|
||||
#ifdef DEBUG
|
||||
for (uint32_t i = 0; i < sizeof(Frame) / sizeof(void*); i++) {
|
||||
MOZ_ASSERT(stackMap->getBit(stackMap->numMappedWords -
|
||||
stackMap->frameOffsetFromTop + i) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Note the presence of a DebugFrame with live pointers, if any.
|
||||
if (debugFrameWithLiveRefs != HasDebugFrameWithLiveRefs::No) {
|
||||
stackMap->setHasDebugFrameWithLiveRefs();
|
||||
}
|
||||
|
||||
// Add the completed map to the running collection thereof.
|
||||
if (!stackMaps_->add((uint8_t*)(uintptr_t)assemblerOffset, stackMap)) {
|
||||
stackMap->destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Crosscheck the map pointer counting.
|
||||
uint32_t nw = stackMap->numMappedWords;
|
||||
uint32_t np = 0;
|
||||
for (uint32_t i = 0; i < nw; i++) {
|
||||
np += stackMap->getBit(i);
|
||||
}
|
||||
MOZ_ASSERT(size_t(np) == countedPointers);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
HasDebugFrameWithLiveRefs debugFrameWithLiveRefs, const StkVector& stk);
|
||||
};
|
||||
|
||||
} // namespace wasm
|
||||
|
Loading…
x
Reference in New Issue
Block a user