зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset aca2e6cff6b9 (bug 1578418) for bustages complaining about WasmBaselineCompile.cpp CLOSED TREE
This commit is contained in:
Родитель
f16e836b61
Коммит
8fb59cb8ed
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1764,13 +1764,11 @@ static bool EmitF64Const(FunctionCompiler& f) {
|
|||
}
|
||||
|
||||
static bool EmitBlock(FunctionCompiler& f) {
|
||||
ResultType params;
|
||||
return f.iter().readBlock(¶ms) && f.startBlock();
|
||||
return f.iter().readBlock() && f.startBlock();
|
||||
}
|
||||
|
||||
static bool EmitLoop(FunctionCompiler& f) {
|
||||
ResultType params;
|
||||
if (!f.iter().readLoop(¶ms)) {
|
||||
if (!f.iter().readLoop()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1786,9 +1784,8 @@ static bool EmitLoop(FunctionCompiler& f) {
|
|||
}
|
||||
|
||||
static bool EmitIf(FunctionCompiler& f) {
|
||||
ResultType params;
|
||||
MDefinition* condition = nullptr;
|
||||
if (!f.iter().readIf(¶ms, &condition)) {
|
||||
if (!f.iter().readIf(&condition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1802,10 +1799,9 @@ static bool EmitIf(FunctionCompiler& f) {
|
|||
}
|
||||
|
||||
static bool EmitElse(FunctionCompiler& f) {
|
||||
ResultType paramType;
|
||||
ResultType resultType;
|
||||
ResultType thenType;
|
||||
DefVector thenValues;
|
||||
if (!f.iter().readElse(¶mType, &resultType, &thenValues)) {
|
||||
if (!f.iter().readElse(&thenType, &thenValues)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -720,11 +720,10 @@ class MOZ_STACK_CLASS OpIter : private Policy {
|
|||
MOZ_MUST_USE bool readFunctionStart(uint32_t funcIndex);
|
||||
MOZ_MUST_USE bool readFunctionEnd(const uint8_t* bodyEnd);
|
||||
MOZ_MUST_USE bool readReturn(ValueVector* values);
|
||||
MOZ_MUST_USE bool readBlock(ResultType* paramType);
|
||||
MOZ_MUST_USE bool readLoop(ResultType* paramType);
|
||||
MOZ_MUST_USE bool readIf(ResultType* paramType, Value* condition);
|
||||
MOZ_MUST_USE bool readElse(ResultType* paramType, ResultType* resultType,
|
||||
ValueVector* thenValues);
|
||||
MOZ_MUST_USE bool readBlock();
|
||||
MOZ_MUST_USE bool readLoop();
|
||||
MOZ_MUST_USE bool readIf(Value* condition);
|
||||
MOZ_MUST_USE bool readElse(ResultType* thenType, ValueVector* thenValues);
|
||||
MOZ_MUST_USE bool readEnd(LabelKind* kind, ResultType* type,
|
||||
ValueVector* values);
|
||||
void popEnd();
|
||||
|
@ -1263,7 +1262,7 @@ inline bool OpIter<Policy>::readReturn(ValueVector* values) {
|
|||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readBlock(ResultType* paramType) {
|
||||
inline bool OpIter<Policy>::readBlock() {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::Block);
|
||||
|
||||
BlockType type;
|
||||
|
@ -1271,12 +1270,11 @@ inline bool OpIter<Policy>::readBlock(ResultType* paramType) {
|
|||
return false;
|
||||
}
|
||||
|
||||
*paramType = type.params();
|
||||
return pushControl(LabelKind::Block, type);
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readLoop(ResultType* paramType) {
|
||||
inline bool OpIter<Policy>::readLoop() {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::Loop);
|
||||
|
||||
BlockType type;
|
||||
|
@ -1284,12 +1282,11 @@ inline bool OpIter<Policy>::readLoop(ResultType* paramType) {
|
|||
return false;
|
||||
}
|
||||
|
||||
*paramType = type.params();
|
||||
return pushControl(LabelKind::Loop, type);
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readIf(ResultType* paramType, Value* condition) {
|
||||
inline bool OpIter<Policy>::readIf(Value* condition) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::If);
|
||||
|
||||
BlockType type;
|
||||
|
@ -1305,14 +1302,12 @@ inline bool OpIter<Policy>::readIf(ResultType* paramType, Value* condition) {
|
|||
return false;
|
||||
}
|
||||
|
||||
*paramType = type.params();
|
||||
size_t paramsLength = type.params().length();
|
||||
return thenParamStack_.append(valueStack_.end() - paramsLength, paramsLength);
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readElse(ResultType* paramType,
|
||||
ResultType* resultType,
|
||||
inline bool OpIter<Policy>::readElse(ResultType* thenType,
|
||||
ValueVector* values) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::Else);
|
||||
|
||||
|
@ -1321,8 +1316,7 @@ inline bool OpIter<Policy>::readElse(ResultType* paramType,
|
|||
return fail("else can only be used within an if");
|
||||
}
|
||||
|
||||
*paramType = block.type().params();
|
||||
if (!checkStackAtEndOfBlock(resultType, values)) {
|
||||
if (!checkStackAtEndOfBlock(thenType, values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1353,8 +1347,7 @@ inline bool OpIter<Policy>::readEnd(LabelKind* kind, ResultType* type,
|
|||
|
||||
// If an `if` block ends with `end` instead of `else`, then we must
|
||||
// additionally validate that the then-block doesn't push anything.
|
||||
if (block.kind() == LabelKind::Then &&
|
||||
block.type().params() != block.type().results()) {
|
||||
if (block.kind() == LabelKind::Then && !block.resultType().empty()) {
|
||||
return fail("if without else with a result value");
|
||||
}
|
||||
|
||||
|
|
|
@ -39,93 +39,6 @@ typedef Vector<jit::MIRType, 8, SystemAllocPolicy> MIRTypeVector;
|
|||
typedef jit::ABIArgIter<MIRTypeVector> ABIArgMIRTypeIter;
|
||||
typedef jit::ABIArgIter<ValTypeVector> ABIArgValTypeIter;
|
||||
|
||||
/*****************************************************************************/
|
||||
// ABIResultIter implementation
|
||||
|
||||
static uint32_t ResultStackSize(ValType type) {
|
||||
switch (type.code()) {
|
||||
case ValType::I32:
|
||||
return ABIResult::StackSizeOfInt32;
|
||||
case ValType::I64:
|
||||
return ABIResult::StackSizeOfInt64;
|
||||
case ValType::F32:
|
||||
return ABIResult::StackSizeOfFloat;
|
||||
case ValType::F64:
|
||||
return ABIResult::StackSizeOfDouble;
|
||||
case ValType::Ref:
|
||||
case ValType::FuncRef:
|
||||
case ValType::AnyRef:
|
||||
return ABIResult::StackSizeOfPtr;
|
||||
case ValType::NullRef:
|
||||
default:
|
||||
MOZ_CRASH("Unexpected result type");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ABIResult::size() const { return ResultStackSize(type()); }
|
||||
|
||||
void ABIResultIter::settleRegister(ValType type) {
|
||||
MOZ_ASSERT(!done());
|
||||
MOZ_ASSERT(index() < RegisterResultCount);
|
||||
static_assert(RegisterResultCount == 1, "expected a single register result");
|
||||
|
||||
switch (type.code()) {
|
||||
case ValType::I32:
|
||||
cur_ = ABIResult(type, ReturnReg);
|
||||
break;
|
||||
case ValType::I64:
|
||||
cur_ = ABIResult(type, ReturnReg64);
|
||||
break;
|
||||
case ValType::F32:
|
||||
cur_ = ABIResult(type, ReturnFloat32Reg);
|
||||
break;
|
||||
case ValType::F64:
|
||||
cur_ = ABIResult(type, ReturnDoubleReg);
|
||||
break;
|
||||
case ValType::Ref:
|
||||
case ValType::FuncRef:
|
||||
case ValType::AnyRef:
|
||||
cur_ = ABIResult(type, ReturnReg);
|
||||
break;
|
||||
case ValType::NullRef:
|
||||
default:
|
||||
MOZ_CRASH("Unexpected result type");
|
||||
}
|
||||
}
|
||||
|
||||
void ABIResultIter::settleNext() {
|
||||
MOZ_ASSERT(direction_ == Next);
|
||||
MOZ_ASSERT(!done());
|
||||
|
||||
uint32_t typeIndex = count_ - index_ - 1;
|
||||
ValType type = type_[typeIndex];
|
||||
|
||||
if (index_ < RegisterResultCount) {
|
||||
settleRegister(type);
|
||||
return;
|
||||
}
|
||||
|
||||
cur_ = ABIResult(type, nextStackOffset_);
|
||||
nextStackOffset_ += ResultStackSize(type);
|
||||
}
|
||||
|
||||
void ABIResultIter::settlePrev() {
|
||||
MOZ_ASSERT(direction_ == Prev);
|
||||
MOZ_ASSERT(!done());
|
||||
uint32_t typeIndex = index_;
|
||||
ValType type = type_[typeIndex];
|
||||
|
||||
if (count_ - index_ - 1 < RegisterResultCount) {
|
||||
settleRegister(type);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t size = ResultStackSize(type);
|
||||
MOZ_ASSERT(nextStackOffset_ >= size);
|
||||
nextStackOffset_ -= size;
|
||||
cur_ = ABIResult(type, nextStackOffset_);
|
||||
}
|
||||
|
||||
#ifdef WASM_CODEGEN_DEBUG
|
||||
template <class Closure>
|
||||
static void GenPrint(DebugChannel channel, MacroAssembler& masm,
|
||||
|
|
|
@ -20,227 +20,10 @@
|
|||
#define wasm_stubs_h
|
||||
|
||||
#include "wasm/WasmGenerator.h"
|
||||
#include "wasm/WasmOpIter.h"
|
||||
|
||||
namespace js {
|
||||
namespace wasm {
|
||||
|
||||
// ValType and location for a single result: either in a register or on the
|
||||
// stack.
|
||||
|
||||
class ABIResult {
|
||||
ValType type_;
|
||||
enum class Location { Gpr, Gpr64, Fpr, Stack } loc_;
|
||||
union {
|
||||
Register gpr_;
|
||||
Register64 gpr64_;
|
||||
FloatRegister fpr_;
|
||||
uint32_t stackOffset_;
|
||||
};
|
||||
|
||||
void validate() {
|
||||
#ifdef DEBUG
|
||||
if (onStack()) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(inRegister());
|
||||
switch (type_.code()) {
|
||||
case ValType::I32:
|
||||
MOZ_ASSERT(loc_ == Location::Gpr);
|
||||
break;
|
||||
case ValType::I64:
|
||||
MOZ_ASSERT(loc_ == Location::Gpr64);
|
||||
break;
|
||||
case ValType::F32:
|
||||
case ValType::F64:
|
||||
MOZ_ASSERT(loc_ == Location::Fpr);
|
||||
break;
|
||||
case ValType::AnyRef:
|
||||
case ValType::FuncRef:
|
||||
case ValType::Ref:
|
||||
MOZ_ASSERT(loc_ == Location::Gpr);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("bad value type");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
friend class ABIResultIter;
|
||||
ABIResult(){};
|
||||
|
||||
public:
|
||||
// Sizes of items in the stack area.
|
||||
//
|
||||
// The size values come from the implementations of Push() in
|
||||
// MacroAssembler-x86-shared.cpp and MacroAssembler-arm-shared.cpp, and from
|
||||
// VFPRegister::size() in Architecture-arm.h.
|
||||
//
|
||||
// On ARM unlike on x86 we push a single for float.
|
||||
|
||||
static constexpr size_t StackSizeOfPtr = sizeof(intptr_t);
|
||||
static constexpr size_t StackSizeOfInt32 = StackSizeOfPtr;
|
||||
static constexpr size_t StackSizeOfInt64 = sizeof(int64_t);
|
||||
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32)
|
||||
static constexpr size_t StackSizeOfFloat = sizeof(float);
|
||||
#else
|
||||
static constexpr size_t StackSizeOfFloat = sizeof(double);
|
||||
#endif
|
||||
static constexpr size_t StackSizeOfDouble = sizeof(double);
|
||||
|
||||
ABIResult(ValType type, Register gpr)
|
||||
: type_(type), loc_(Location::Gpr), gpr_(gpr) {
|
||||
validate();
|
||||
}
|
||||
ABIResult(ValType type, Register64 gpr64)
|
||||
: type_(type), loc_(Location::Gpr64), gpr64_(gpr64) {
|
||||
validate();
|
||||
}
|
||||
ABIResult(ValType type, FloatRegister fpr)
|
||||
: type_(type), loc_(Location::Fpr), fpr_(fpr) {
|
||||
validate();
|
||||
}
|
||||
ABIResult(ValType type, uint32_t stackOffset)
|
||||
: type_(type), loc_(Location::Stack), stackOffset_(stackOffset) {
|
||||
validate();
|
||||
}
|
||||
|
||||
ValType type() const { return type_; }
|
||||
bool onStack() const { return loc_ == Location::Stack; }
|
||||
bool inRegister() const { return !onStack(); }
|
||||
Register gpr() const {
|
||||
MOZ_ASSERT(loc_ == Location::Gpr);
|
||||
return gpr_;
|
||||
}
|
||||
Register64 gpr64() const {
|
||||
MOZ_ASSERT(loc_ == Location::Gpr64);
|
||||
return gpr64_;
|
||||
}
|
||||
FloatRegister fpr() const {
|
||||
MOZ_ASSERT(loc_ == Location::Fpr);
|
||||
return fpr_;
|
||||
}
|
||||
// Offset from SP.
|
||||
uint32_t stackOffset() const {
|
||||
MOZ_ASSERT(loc_ == Location::Stack);
|
||||
return stackOffset_;
|
||||
}
|
||||
uint32_t size() const;
|
||||
};
|
||||
|
||||
// Just as WebAssembly functions can take multiple arguments, they can also
|
||||
// return multiple results. As with a call, a limited number of results will be
|
||||
// located in registers, and the rest will be stored in a stack area. The
|
||||
// |ABIResultIter| computes result locations, given a |ResultType|.
|
||||
//
|
||||
// Recall that a |ResultType| represents a sequence of value types t1..tN,
|
||||
// indexed from 1 to N. In principle it doesn't matter how we decide which
|
||||
// results get to be in registers and which go to the stack. To better
|
||||
// harmonize with WebAssembly's abstract stack machine, whose properties are
|
||||
// taken advantage of by the baseline compiler, our strategy is to start
|
||||
// allocating result locations in "reverse" order: from result N down to 1.
|
||||
//
|
||||
// If a result with index I is in a register, then all results with index J > I
|
||||
// are also in registers. If a result I is on the stack, then all results with
|
||||
// index K < I are also on the stack, farther away from the stack pointer than
|
||||
// result I.
|
||||
//
|
||||
// Currently only a single result is ever stored in a register, though this may
|
||||
// change in the future on register-rich platforms.
|
||||
//
|
||||
// NB: The baseline compiler also uses thie ABI for locations of block
|
||||
// parameters and return values, within individual WebAssembly functions.
|
||||
|
||||
class ABIResultIter {
|
||||
ResultType type_;
|
||||
uint32_t count_;
|
||||
uint32_t index_;
|
||||
uint32_t nextStackOffset_;
|
||||
enum { Next, Prev } direction_;
|
||||
ABIResult cur_;
|
||||
|
||||
void settleRegister(ValType type);
|
||||
void settleNext();
|
||||
void settlePrev();
|
||||
|
||||
static constexpr size_t RegisterResultCount = 1;
|
||||
|
||||
public:
|
||||
explicit ABIResultIter(const ResultType& type)
|
||||
: type_(type), count_(type.length()) {
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
index_ = nextStackOffset_ = 0;
|
||||
direction_ = Next;
|
||||
if (!done()) {
|
||||
settleNext();
|
||||
}
|
||||
}
|
||||
bool done() const { return index_ == count_; }
|
||||
uint32_t index() const { return index_; }
|
||||
uint32_t count() const { return count_; }
|
||||
uint32_t remaining() const { return count_ - index_; }
|
||||
void switchToNext() {
|
||||
MOZ_ASSERT(direction_ == Prev);
|
||||
if (!done() && cur().onStack()) {
|
||||
nextStackOffset_ += cur().size();
|
||||
}
|
||||
index_ = count_ - index_;
|
||||
direction_ = Next;
|
||||
if (!done()) {
|
||||
settleNext();
|
||||
}
|
||||
}
|
||||
void switchToPrev() {
|
||||
MOZ_ASSERT(direction_ == Next);
|
||||
if (!done() && cur().onStack()) {
|
||||
nextStackOffset_ -= cur().size();
|
||||
}
|
||||
index_ = count_ - index_;
|
||||
direction_ = Prev;
|
||||
if (!done()) settlePrev();
|
||||
}
|
||||
void next() {
|
||||
MOZ_ASSERT(direction_ == Next);
|
||||
MOZ_ASSERT(!done());
|
||||
index_++;
|
||||
if (!done()) {
|
||||
settleNext();
|
||||
}
|
||||
}
|
||||
void prev() {
|
||||
MOZ_ASSERT(direction_ == Prev);
|
||||
MOZ_ASSERT(!done());
|
||||
index_++;
|
||||
if (!done()) {
|
||||
settlePrev();
|
||||
}
|
||||
}
|
||||
const ABIResult& cur() const {
|
||||
MOZ_ASSERT(!done());
|
||||
return cur_;
|
||||
}
|
||||
|
||||
uint32_t stackBytesConsumedSoFar() const { return nextStackOffset_; }
|
||||
|
||||
static inline bool HasStackResults(const ResultType& type) {
|
||||
return type.length() > RegisterResultCount;
|
||||
}
|
||||
|
||||
static uint32_t MeasureStackBytes(const ResultType& type) {
|
||||
if (!HasStackResults(type)) {
|
||||
return 0;
|
||||
}
|
||||
ABIResultIter iter(type);
|
||||
while (!iter.done()) {
|
||||
iter.next();
|
||||
}
|
||||
return iter.stackBytesConsumedSoFar();
|
||||
}
|
||||
};
|
||||
|
||||
extern bool GenerateBuiltinThunk(jit::MacroAssembler& masm,
|
||||
jit::ABIFunctionType abiType,
|
||||
ExitReason exitReason, void* funcPtr,
|
||||
|
|
|
@ -578,13 +578,13 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
|
|||
¬hing));
|
||||
}
|
||||
case uint16_t(Op::Block):
|
||||
CHECK(iter.readBlock(&unusedType));
|
||||
CHECK(iter.readBlock());
|
||||
case uint16_t(Op::Loop):
|
||||
CHECK(iter.readLoop(&unusedType));
|
||||
CHECK(iter.readLoop());
|
||||
case uint16_t(Op::If):
|
||||
CHECK(iter.readIf(&unusedType, ¬hing));
|
||||
CHECK(iter.readIf(¬hing));
|
||||
case uint16_t(Op::Else):
|
||||
CHECK(iter.readElse(&unusedType, &unusedType, ¬hings));
|
||||
CHECK(iter.readElse(&unusedType, ¬hings));
|
||||
case uint16_t(Op::I32Clz):
|
||||
case uint16_t(Op::I32Ctz):
|
||||
case uint16_t(Op::I32Popcnt):
|
||||
|
|
Загрузка…
Ссылка в новой задаче