Bug 1639153 - Part 1: Reserve two slots after stack arguments for the future tls preservation. r=lth

We are going to remove Frame::tls and support trampolines for indirect calls, so we need to get rid of using Frame::tls.
In this and the followup patches I will iteratively remove all dependencies of Frame::tls and remove it eventually.

In this patch I changed wasm ABI to allocate two stack slots after stack args to preserve caller's and callee's tls'es in the near future.

Differential Revision: https://phabricator.services.mozilla.com/D82881
This commit is contained in:
Dmitry Bezhetskov 2020-08-06 04:57:48 +00:00
Родитель d78a8c8c6a
Коммит 827e244302
15 изменённых файлов: 104 добавлений и 48 удалений

Просмотреть файл

@ -14481,7 +14481,7 @@ void CodeGenerator::emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir) {
const wasm::FuncExport& funcExport = lir->mir()->funcExport();
const wasm::FuncType& sig = funcExport.funcType();
ABIArgGenerator abi;
WasmABIArgGenerator abi;
for (size_t i = 0; i < lir->numOperands(); i++) {
MIRType argMir;
switch (sig.args()[i].kind()) {

Просмотреть файл

@ -4144,9 +4144,9 @@ static inline MIRType ToMIRType(ABIArgType argType) {
MOZ_CRASH("unexpected argType");
}
template <class VecT>
class ABIArgIter {
ABIArgGenerator gen_;
template <class VecT, class ABIArgGeneratorT>
class ABIArgIterBase {
ABIArgGeneratorT gen_;
const VecT& types_;
unsigned i_;
@ -4155,7 +4155,9 @@ class ABIArgIter {
}
public:
explicit ABIArgIter(const VecT& types) : types_(types), i_(0) { settle(); }
explicit ABIArgIterBase(const VecT& types) : types_(types), i_(0) {
settle();
}
void operator++(int) {
MOZ_ASSERT(!done());
i_++;
@ -4185,6 +4187,29 @@ class ABIArgIter {
}
};
// This is not an alias because we want to allow class template argument
// deduction.
template <class VecT>
class ABIArgIter : public ABIArgIterBase<VecT, ABIArgGenerator> {
public:
explicit ABIArgIter(const VecT& types)
: ABIArgIterBase<VecT, ABIArgGenerator>(types) {}
};
class WasmABIArgGenerator : public ABIArgGenerator {
public:
WasmABIArgGenerator() {
increaseStackOffset(wasm::FrameWithTls::sizeWithoutFrame());
}
};
template <class VecT>
class WasmABIArgIter : public ABIArgIterBase<VecT, WasmABIArgGenerator> {
public:
explicit WasmABIArgIter(const VecT& types)
: ABIArgIterBase<VecT, WasmABIArgGenerator>(types) {}
};
} // namespace jit
} // namespace js

Просмотреть файл

@ -147,6 +147,7 @@ class ABIArgGenerator {
ABIArg next(MIRType argType);
ABIArg& current() { return current_; }
uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
void increaseStackOffset(uint32_t bytes) { stackOffset_ += bytes; }
};
bool IsUnaligned(const wasm::MemoryAccessDesc& access);

Просмотреть файл

@ -415,6 +415,7 @@ class ABIArgGenerator {
ABIArg next(MIRType argType);
ABIArg& current() { return current_; }
uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
void increaseStackOffset(uint32_t bytes) { stackOffset_ += bytes; }
protected:
unsigned intRegIndex_;

Просмотреть файл

@ -43,6 +43,8 @@ class ABIArgGenerator {
return usedArgSlots_ * sizeof(intptr_t);
}
void increaseStackOffset(uint32_t bytes) { MOZ_CRASH("NYI"); }
};
// These registers may be volatile or nonvolatile.

Просмотреть файл

@ -38,6 +38,7 @@ class ABIArgGenerator {
return (usedArgSlots_ - 8) * sizeof(int64_t);
}
void increaseStackOffset(uint32_t bytes) { MOZ_CRASH("NYI"); }
};
// These registers may be volatile or nonvolatile.

Просмотреть файл

@ -617,6 +617,7 @@ class ABIArgGenerator {
ABIArg next(MIRType) { MOZ_CRASH(); }
ABIArg& current() { MOZ_CRASH(); }
uint32_t stackBytesConsumedSoFar() const { MOZ_CRASH(); }
void increaseStackOffset(uint32_t) { MOZ_CRASH(); }
};
static inline bool GetTempRegForIntArg(uint32_t, uint32_t, Register*) {

Просмотреть файл

@ -192,6 +192,7 @@ class ABIArgGenerator {
ABIArg next(MIRType argType);
ABIArg& current() { return current_; }
uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
void increaseStackOffset(uint32_t bytes) { stackOffset_ += bytes; }
};
// These registers may be volatile or nonvolatile.

Просмотреть файл

@ -5151,7 +5151,7 @@ class BaseCompiler final : public BaseCompilerInterface {
}
// Identify GC-managed pointers passed on the stack.
for (ABIArgIter i(args); !i.done(); i++) {
for (WasmABIArgIter i(args); !i.done(); i++) {
ABIArg argLoc = *i;
if (argLoc.kind() == ABIArg::Stack &&
args[i.index()] == MIRType::RefOrNull) {
@ -5236,7 +5236,7 @@ class BaseCompiler final : public BaseCompilerInterface {
}
// Copy arguments from registers to stack.
for (ABIArgIter i(args); !i.done(); i++) {
for (WasmABIArgIter i(args); !i.done(); i++) {
if (args.isSyntheticStackResultPointerArg(i.index())) {
// If there are stack results and the pointer to stack results
// was passed in a register, store it to the stack.
@ -5501,7 +5501,7 @@ class BaseCompiler final : public BaseCompilerInterface {
}
uint32_t lineOrBytecode;
ABIArgGenerator abi;
WasmABIArgGenerator abi;
bool isInterModule;
bool usesSystemAbi;
#ifdef JS_CODEGEN_ARM

Просмотреть файл

@ -42,7 +42,7 @@ class BaseLocalIter {
const ValTypeVector& locals_;
const ArgTypeVector& args_;
jit::ABIArgIter<ArgTypeVector> argsIter_;
jit::WasmABIArgIter<ArgTypeVector> argsIter_;
size_t index_;
int32_t frameSize_;
int32_t nextFrameSize_;

Просмотреть файл

@ -128,7 +128,7 @@ bool CreateStackMapForFunctionEntryTrap(const wasm::ArgTypeVector& argTypes,
return false;
}
for (ABIArgIter i(argTypes); !i.done(); i++) {
for (WasmABIArgIter i(argTypes); !i.done(); i++) {
ABIArg argLoc = *i;
if (argLoc.kind() == ABIArg::Stack &&
argTypes[i.index()] == MIRType::RefOrNull) {
@ -183,7 +183,7 @@ bool GenerateStackmapEntriesForTrapExit(const ArgTypeVector& args,
return false;
}
for (ABIArgIter i(args); !i.done(); i++) {
for (WasmABIArgIter i(args); !i.done(); i++) {
if (!i->argInRegister() || i.mirType() != MIRType::RefOrNull) {
continue;
}

Просмотреть файл

@ -252,7 +252,7 @@ class StackMaps {
// the complete native-ABI-level call signature.
template <class T>
static inline size_t StackArgAreaSizeUnaligned(const T& argTypes) {
ABIArgIter<const T> i(argTypes);
WasmABIArgIter<const T> i(argTypes);
while (!i.done()) {
i++;
}
@ -261,7 +261,7 @@ static inline size_t StackArgAreaSizeUnaligned(const T& argTypes) {
static inline size_t StackArgAreaSizeUnaligned(
const SymbolicAddressSignature& saSig) {
// ABIArgIter::ABIArgIter wants the items to be iterated over to be
// WasmABIArgIter::ABIArgIter wants the items to be iterated over to be
// presented in some type that has methods length() and operator[]. So we
// have to wrap up |saSig|'s array of types in this API-matching class.
class MOZ_STACK_CLASS ItemsAndLength {

Просмотреть файл

@ -64,7 +64,7 @@ class FunctionCompiler;
class CallCompileState {
// A generator object that is passed each argument as it is compiled.
ABIArgGenerator abi_;
WasmABIArgGenerator abi_;
// Accumulates the register arguments while compiling arguments.
MWasmCall::Args regArgs_;
@ -161,7 +161,7 @@ class FunctionCompiler {
return false;
}
for (ABIArgIter i(args); !i.done(); i++) {
for (WasmABIArgIter i(args); !i.done(); i++) {
MWasmParameter* ins = MWasmParameter::New(alloc(), *i, i.mirType());
curBlock_->add(ins);
if (args.isSyntheticStackResultPointerArg(i.index())) {

Просмотреть файл

@ -292,18 +292,28 @@ static void AssertStackAlignment(MacroAssembler& masm, uint32_t alignment,
masm.assertStackAlignment(alignment, addBeforeAssert);
}
template <class VectorT>
static unsigned StackArgBytes(const VectorT& args) {
ABIArgIter<VectorT> iter(args);
template <class VectorT, template <class VecT> class ABIArgIterT>
static unsigned StackArgBytesHelper(const VectorT& args) {
ABIArgIterT<VectorT> iter(args);
while (!iter.done()) {
iter++;
}
return iter.stackBytesConsumedSoFar();
}
static unsigned StackArgBytes(const FuncType& funcType) {
template <class VectorT>
static unsigned StackArgBytesForNativeABI(const VectorT& args) {
return StackArgBytesHelper<VectorT, ABIArgIter>(args);
}
template <class VectorT>
static unsigned StackArgBytesForWasmABI(const VectorT& args) {
return StackArgBytesHelper<VectorT, WasmABIArgIter>(args);
}
static unsigned StackArgBytesForWasmABI(const FuncType& funcType) {
ArgTypeVector args(funcType);
return StackArgBytes(args);
return StackArgBytesForWasmABI(args);
}
static void Move64(MacroAssembler& masm, const Address& src,
@ -323,12 +333,12 @@ static void Move64(MacroAssembler& masm, const Address& src,
static void SetupABIArguments(MacroAssembler& masm, const FuncExport& fe,
Register argv, Register scratch) {
// Copy parameters out of argv and into the registers/stack-slots specified by
// the system ABI.
// the wasm ABI.
//
// SetupABIArguments are only used for C++ -> wasm calls through callExport(),
// and V128 and Ref types (other than anyref) are not currently allowed.
ArgTypeVector args(fe.funcType());
for (ABIArgIter iter(args); !iter.done(); iter++) {
for (WasmABIArgIter iter(args); !iter.done(); iter++) {
unsigned argOffset = iter.index() * sizeof(ExportArg);
Address src(argv, argOffset);
MIRType type = iter.mirType();
@ -760,9 +770,10 @@ static bool GenerateInterpEntry(MacroAssembler& masm, const FuncExport& fe,
masm.Push(scratch);
#endif
// Reserve stack space for the call.
unsigned argDecrement = StackDecrementForCall(
WasmStackAlignment, masm.framePushed(), StackArgBytes(fe.funcType()));
// Reserve stack space for the wasm call.
unsigned argDecrement =
StackDecrementForCall(WasmStackAlignment, masm.framePushed(),
StackArgBytesForWasmABI(fe.funcType()));
masm.reserveStack(argDecrement);
// Copy parameters out of argv and into the wasm ABI registers/stack-slots.
@ -955,13 +966,13 @@ static bool GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex,
// left):
// <-- retAddr | descriptor | callee | argc | this | arg1..N
unsigned normalBytesNeeded = StackArgBytes(fe.funcType());
unsigned normalBytesNeeded = StackArgBytesForWasmABI(fe.funcType());
MIRTypeVector coerceArgTypes;
MOZ_ALWAYS_TRUE(coerceArgTypes.append(MIRType::Int32));
MOZ_ALWAYS_TRUE(coerceArgTypes.append(MIRType::Pointer));
MOZ_ALWAYS_TRUE(coerceArgTypes.append(MIRType::Pointer));
unsigned oolBytesNeeded = StackArgBytes(coerceArgTypes);
unsigned oolBytesNeeded = StackArgBytesForNativeABI(coerceArgTypes);
unsigned bytesNeeded = std::max(normalBytesNeeded, oolBytesNeeded);
@ -1152,7 +1163,7 @@ static bool GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex,
// Convert all the expected values to unboxed values on the stack.
ArgTypeVector args(fe.funcType());
for (ABIArgIter iter(args); !iter.done(); iter++) {
for (WasmABIArgIter iter(args); !iter.done(); iter++) {
unsigned jitArgOffset =
frameSize + JitFrameLayout::offsetOfActualArg(iter.index());
Address argv(sp, jitArgOffset);
@ -1411,7 +1422,7 @@ void wasm::GenerateDirectCallFromJit(MacroAssembler& masm, const FuncExport& fe,
masm.orPtr(Imm32(ExitOrJitEntryFPTag), FramePointer);
// Move stack arguments to their final locations.
unsigned bytesNeeded = StackArgBytes(fe.funcType());
unsigned bytesNeeded = StackArgBytesForWasmABI(fe.funcType());
bytesNeeded = StackDecrementForCall(WasmStackAlignment, masm.framePushed(),
bytesNeeded);
if (bytesNeeded) {
@ -1422,7 +1433,7 @@ void wasm::GenerateDirectCallFromJit(MacroAssembler& masm, const FuncExport& fe,
fe.funcIndex());
ArgTypeVector args(fe.funcType());
for (ABIArgIter iter(args); !iter.done(); iter++) {
for (WasmABIArgIter iter(args); !iter.done(); iter++) {
MOZ_ASSERT_IF(iter->kind() == ABIArg::GPR, iter->gpr() != scratch);
MOZ_ASSERT_IF(iter->kind() == ABIArg::GPR, iter->gpr() != FramePointer);
if (iter->kind() != ABIArg::Stack) {
@ -1877,10 +1888,10 @@ static bool GenerateImportFunction(jit::MacroAssembler& masm,
MOZ_ASSERT(masm.framePushed() == 0);
const unsigned sizeOfTlsSlot = sizeof(void*);
unsigned framePushed =
StackDecrementForCall(WasmStackAlignment,
sizeof(Frame), // pushed by prologue
StackArgBytes(fi.funcType()) + sizeOfTlsSlot);
unsigned framePushed = StackDecrementForCall(
WasmStackAlignment,
sizeof(Frame), // pushed by prologue
StackArgBytesForWasmABI(fi.funcType()) + sizeOfTlsSlot);
masm.wasmReserveStackChecked(framePushed, BytecodeOffset(0));
MOZ_ASSERT(masm.framePushed() == framePushed);
@ -1894,7 +1905,7 @@ static bool GenerateImportFunction(jit::MacroAssembler& masm,
// Copy our frame's stack arguments to the callee frame's stack argument.
unsigned offsetFromFPToCallerStackArgs = sizeof(Frame);
ArgTypeVector args(fi.funcType());
for (ABIArgIter i(args); !i.done(); i++) {
for (WasmABIArgIter i(args); !i.done(); i++) {
if (i->kind() != ABIArg::Stack) {
continue;
}
@ -1979,7 +1990,7 @@ static bool GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi,
// The padding between stack args and argv ensures that argv is aligned. The
// padding between argv and retaddr ensures that sp is aligned.
unsigned argOffset =
AlignBytes(StackArgBytes(invokeArgTypes), sizeof(double));
AlignBytes(StackArgBytesForNativeABI(invokeArgTypes), sizeof(double));
// The abiArgCount includes a stack result pointer argument if needed.
unsigned abiArgCount = ArgTypeVector(fi.funcType()).lengthWithStackResults();
unsigned argBytes = std::max<size_t>(1, abiArgCount) * sizeof(Value);
@ -1992,7 +2003,7 @@ static bool GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi,
offsets);
// Fill the argument array.
unsigned offsetFromFPToCallerStackArgs = sizeof(Frame);
unsigned offsetFromFPToCallerStackArgs = sizeof(FrameWithTls);
Register scratch = ABINonArgReturnReg0;
Register scratch2 = ABINonArgReturnReg1;
// The scratch3 reg does not need to be non-volatile, but has to be
@ -2213,7 +2224,7 @@ static bool GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi,
argOffset += sizeof(Value);
// 5. Fill the arguments.
const uint32_t offsetFromFPToCallerStackArgs = sizeof(Frame);
const uint32_t offsetFromFPToCallerStackArgs = sizeof(FrameWithTls);
Register scratch = ABINonArgReturnReg1; // Repeatedly clobbered
Register scratch2 = ABINonArgReturnReg0; // Reused as callee below
// The scratch3 reg does not need to be non-volatile, but has to be
@ -2391,7 +2402,7 @@ static bool GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi,
MIRTypeVector coerceArgTypes;
MOZ_ALWAYS_TRUE(coerceArgTypes.append(MIRType::Pointer));
unsigned offsetToCoerceArgv =
AlignBytes(StackArgBytes(coerceArgTypes), sizeof(Value));
AlignBytes(StackArgBytesForWasmABI(coerceArgTypes), sizeof(Value));
MOZ_ASSERT(nativeFramePushed >= offsetToCoerceArgv + sizeof(Value));
AssertStackAlignment(masm, ABIStackAlignment);
@ -2522,14 +2533,14 @@ bool wasm::GenerateBuiltinThunk(MacroAssembler& masm, ABIFunctionType abiType,
uint32_t framePushed =
StackDecrementForCall(ABIStackAlignment,
sizeof(Frame), // pushed by prologue
StackArgBytes(args));
StackArgBytesForNativeABI(args));
GenerateExitPrologue(masm, framePushed, exitReason, offsets);
// Copy out and convert caller arguments, if needed.
unsigned offsetFromFPToCallerStackArgs = sizeof(Frame);
unsigned offsetFromFPToCallerStackArgs = sizeof(FrameWithTls);
Register scratch = ABINonArgReturnReg0;
for (ABIArgIter<ABIFunctionArgs> i(args); !i.done(); i++) {
for (ABIArgIter i(args); !i.done(); i++) {
if (i->argInRegister()) {
#ifdef JS_CODEGEN_ARM
// Non hard-fp passes the args values in GPRs.

Просмотреть файл

@ -50,8 +50,8 @@ namespace js {
namespace jit {
class JitScript;
enum class RoundingMode;
template <class VecT>
class ABIArgIter;
template <class VecT, class ABIArgGeneratorT>
class ABIArgIterBase;
} // namespace jit
// This is a widespread header, so lets keep out the core wasm impl types.
@ -1276,13 +1276,13 @@ class ArgTypeVector {
const ValTypeVector& args_;
bool hasStackResults_;
// To allow ABIArgIter<ArgTypeVector>, we define a private length()
// method. To prevent accidental errors, other users need to be
// To allow ABIArgIterBase<VecT, ABIArgGeneratorT>, we define a private
// length() method. To prevent accidental errors, other users need to be
// explicit and call lengthWithStackResults() or
// lengthWithoutStackResults().
size_t length() const { return args_.length() + size_t(hasStackResults_); }
friend jit::ABIArgIter<ArgTypeVector>;
friend jit::ABIArgIter<const ArgTypeVector>;
template <class VecT, class ABIArgGeneratorT>
friend class jit::ABIArgIterBase;
public:
ArgTypeVector(const ValTypeVector& args, StackResults stackResults)
@ -3285,6 +3285,19 @@ class Frame {
static_assert(!std::is_polymorphic_v<Frame>, "Frame doesn't need a vtable.");
class FrameWithTls : public Frame {
public:
TlsData* calleeTls_;
TlsData* callerTls_;
constexpr static uint32_t sizeWithoutFrame() {
return sizeof(wasm::FrameWithTls) - sizeof(wasm::Frame);
}
};
static_assert(FrameWithTls::sizeWithoutFrame() == 2 * sizeof(void*),
"There are only two additional slots");
#if defined(JS_CODEGEN_ARM64)
static_assert(sizeof(Frame) % 16 == 0, "frame is aligned");
#endif