Commit 77546feb authored by ivica.bogosavljevic's avatar ivica.bogosavljevic Committed by Commit bot

Reland of "Implement WASM big-endian support".

Reland of https://codereview.chromium.org/2034093002 (reverted by
https://codereview.chromium.org/2080153002).

Original commit message:
Implement WASM support on big-endian platforms. WASM has
an implicit requirement that it is running on little-endian
machine. We achieve WASM support on BE by keeping data
in memory in little-endian order, and changing data
endianness before storing to memory and after loading from
memory.

BUG=

Review-Url: https://codereview.chromium.org/2083523002
Cr-Commit-Position: refs/heads/master@{#37373}
parent 45190a4f
...@@ -998,6 +998,134 @@ Node* WasmGraphBuilder::MaskShiftCount64(Node* node) { ...@@ -998,6 +998,134 @@ Node* WasmGraphBuilder::MaskShiftCount64(Node* node) {
return node; return node;
} }
Node* WasmGraphBuilder::BuildChangeEndianness(Node* node, MachineType memtype,
wasm::LocalType wasmtype) {
Node* result;
Node* value = node;
const Operator* shiftLeftOpcode;
const Operator* shiftRightOpcode;
const Operator* andOpcode;
const Operator* orOpcode;
MachineOperatorBuilder* m = jsgraph()->machine();
int valueSizeInBytes = 1 << ElementSizeLog2Of(memtype.representation());
int valueSizeInBits = 8 * valueSizeInBytes;
bool isFloat = false;
switch (memtype.representation()) {
case MachineRepresentation::kFloat64:
value = graph()->NewNode(m->BitcastFloat64ToInt64(), node);
isFloat = true;
case MachineRepresentation::kWord64:
shiftLeftOpcode = m->Word64Shl();
shiftRightOpcode = m->Word64Shr();
andOpcode = m->Word64And();
orOpcode = m->Word64Or();
result = jsgraph()->Int64Constant(0);
break;
case MachineRepresentation::kFloat32:
value = graph()->NewNode(m->BitcastFloat32ToInt32(), node);
isFloat = true;
case MachineRepresentation::kWord32:
case MachineRepresentation::kWord16:
shiftLeftOpcode = m->Word32Shl();
shiftRightOpcode = m->Word32Shr();
andOpcode = m->Word32And();
orOpcode = m->Word32Or();
result = jsgraph()->Int32Constant(0);
break;
case MachineRepresentation::kWord8:
// No need to change endianness for byte size, return original node
return node;
break;
default:
UNREACHABLE();
break;
}
int i;
uint32_t shiftCount;
for (i = 0, shiftCount = valueSizeInBits - 8; i < valueSizeInBits / 2;
i += 8, shiftCount -= 16) {
Node* shiftLower;
Node* shiftHigher;
Node* lowerByte;
Node* higherByte;
DCHECK(shiftCount > 0);
DCHECK((shiftCount + 8) % 16 == 0);
if (valueSizeInBits > 32) {
shiftLower = graph()->NewNode(shiftLeftOpcode, value,
jsgraph()->Int64Constant(shiftCount));
shiftHigher = graph()->NewNode(shiftRightOpcode, value,
jsgraph()->Int64Constant(shiftCount));
lowerByte = graph()->NewNode(
andOpcode, shiftLower,
jsgraph()->Int64Constant(static_cast<uint64_t>(0xFF)
<< (valueSizeInBits - 8 - i)));
higherByte = graph()->NewNode(
andOpcode, shiftHigher,
jsgraph()->Int64Constant(static_cast<uint64_t>(0xFF) << i));
} else {
shiftLower = graph()->NewNode(shiftLeftOpcode, value,
jsgraph()->Int32Constant(shiftCount));
shiftHigher = graph()->NewNode(shiftRightOpcode, value,
jsgraph()->Int32Constant(shiftCount));
lowerByte = graph()->NewNode(
andOpcode, shiftLower,
jsgraph()->Int32Constant(static_cast<uint32_t>(0xFF)
<< (valueSizeInBits - 8 - i)));
higherByte = graph()->NewNode(
andOpcode, shiftHigher,
jsgraph()->Int32Constant(static_cast<uint32_t>(0xFF) << i));
}
result = graph()->NewNode(orOpcode, result, lowerByte);
result = graph()->NewNode(orOpcode, result, higherByte);
}
if (isFloat) {
switch (memtype.representation()) {
case MachineRepresentation::kFloat64:
result = graph()->NewNode(m->BitcastInt64ToFloat64(), result);
break;
case MachineRepresentation::kFloat32:
result = graph()->NewNode(m->BitcastInt32ToFloat32(), result);
break;
default:
UNREACHABLE();
break;
}
}
// We need to sign extend the value
if (memtype.IsSigned()) {
DCHECK(!isFloat);
if (valueSizeInBits < 32) {
Node* shiftBitCount;
// Perform sign extension using following trick
// result = (x << machine_width - type_width) >> (machine_width -
// type_width)
if (wasmtype == wasm::kAstI64) {
shiftBitCount = jsgraph()->Int32Constant(64 - valueSizeInBits);
result = graph()->NewNode(
m->Word64Sar(),
graph()->NewNode(m->Word64Shl(), result, shiftBitCount),
shiftBitCount);
} else if (wasmtype == wasm::kAstI32) {
shiftBitCount = jsgraph()->Int32Constant(32 - valueSizeInBits);
result = graph()->NewNode(
m->Word32Sar(),
graph()->NewNode(m->Word32Shl(), result, shiftBitCount),
shiftBitCount);
}
}
}
return result;
}
Node* WasmGraphBuilder::BuildF32Neg(Node* input) { Node* WasmGraphBuilder::BuildF32Neg(Node* input) {
Node* result = Node* result =
Unop(wasm::kExprF32ReinterpretI32, Unop(wasm::kExprF32ReinterpretI32,
...@@ -2770,6 +2898,11 @@ Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, ...@@ -2770,6 +2898,11 @@ Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype,
} else { } else {
load = BuildUnalignedLoad(type, memtype, index, offset, alignment); load = BuildUnalignedLoad(type, memtype, index, offset, alignment);
} }
#if defined(V8_TARGET_BIG_ENDIAN)
// TODO(john.yan) Implement byte swap turbofan operator
// and use it if available for better performance
load = BuildChangeEndianness(load, memtype, type);
#endif
if (type == wasm::kAstI64 && if (type == wasm::kAstI64 &&
ElementSizeLog2Of(memtype.representation()) < 3) { ElementSizeLog2Of(memtype.representation()) < 3) {
...@@ -2890,6 +3023,12 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, ...@@ -2890,6 +3023,12 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
bool aligned = static_cast<int>(alignment) >= bool aligned = static_cast<int>(alignment) >=
ElementSizeLog2Of(memtype.representation()); ElementSizeLog2Of(memtype.representation());
#if defined(V8_TARGET_BIG_ENDIAN)
// TODO(john.yan) Implement byte swap turbofan operator
// and use it if available for better performance
val = BuildChangeEndianness(val, memtype);
#endif
if (aligned || if (aligned ||
jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) { jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) {
StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
......
...@@ -236,6 +236,9 @@ class WasmGraphBuilder { ...@@ -236,6 +236,9 @@ class WasmGraphBuilder {
Node* BuildUnalignedStore(MachineType memtype, Node* index, uint32_t offset, Node* BuildUnalignedStore(MachineType memtype, Node* index, uint32_t offset,
uint32_t alignment, Node* val); uint32_t alignment, Node* val);
Node* BuildChangeEndianness(Node* node, MachineType type,
wasm::LocalType wasmtype = wasm::kAstStmt);
Node* MaskShiftCount32(Node* node); Node* MaskShiftCount32(Node* node);
Node* MaskShiftCount64(Node* node); Node* MaskShiftCount64(Node* node);
......
...@@ -1506,22 +1506,22 @@ inline uintptr_t GetCurrentStackPosition() { ...@@ -1506,22 +1506,22 @@ inline uintptr_t GetCurrentStackPosition() {
template <typename V> template <typename V>
static inline V ReadUnalignedValue(const void* p) { static inline V ReadUnalignedValue(const void* p) {
#if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64) #if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM)
return *reinterpret_cast<const V*>(p); return *reinterpret_cast<const V*>(p);
#else #else // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM
V r; V r;
memmove(&r, p, sizeof(V)); memmove(&r, p, sizeof(V));
return r; return r;
#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM
} }
template <typename V> template <typename V>
static inline void WriteUnalignedValue(void* p, V value) { static inline void WriteUnalignedValue(void* p, V value) {
#if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64) #if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM)
*(reinterpret_cast<V*>(p)) = value; *(reinterpret_cast<V*>(p)) = value;
#else // V8_TARGET_ARCH_MIPS #else // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM
memmove(p, &value, sizeof(V)); memmove(p, &value, sizeof(V));
#endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 #endif // V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM
} }
static inline double ReadFloatValue(const void* p) { static inline double ReadFloatValue(const void* p) {
...@@ -1552,6 +1552,33 @@ static inline void WriteUnalignedUInt32(void* p, uint32_t value) { ...@@ -1552,6 +1552,33 @@ static inline void WriteUnalignedUInt32(void* p, uint32_t value) {
WriteUnalignedValue(p, value); WriteUnalignedValue(p, value);
} }
template <typename V>
static inline V ReadLittleEndianValue(const void* p) {
#if defined(V8_TARGET_LITTLE_ENDIAN)
return ReadUnalignedValue<V>(p);
#elif defined(V8_TARGET_BIG_ENDIAN)
V ret = 0;
const byte* src = reinterpret_cast<const byte*>(p);
byte* dst = reinterpret_cast<byte*>(&ret);
for (size_t i = 0; i < sizeof(V); i++) {
dst[i] = src[sizeof(V) - i - 1];
}
return ret;
#endif // V8_TARGET_LITTLE_ENDIAN
}
template <typename V>
static inline void WriteLittleEndianValue(void* p, V value) {
#if defined(V8_TARGET_LITTLE_ENDIAN)
WriteUnalignedValue<V>(p, value);
#elif defined(V8_TARGET_BIG_ENDIAN)
byte* src = reinterpret_cast<byte*>(&value);
byte* dst = reinterpret_cast<byte*>(p);
for (size_t i = 0; i < sizeof(V); i++) {
dst[i] = src[sizeof(V) - i - 1];
}
#endif // V8_TARGET_LITTLE_ENDIAN
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -26,12 +26,6 @@ namespace wasm { ...@@ -26,12 +26,6 @@ namespace wasm {
#define TRACE(...) #define TRACE(...)
#endif #endif
#if !(V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_ARM)
#define UNALIGNED_ACCESS_OK 1
#else
#define UNALIGNED_ACCESS_OK 0
#endif
// A helper utility to decode bytes, integers, fields, varints, etc, from // A helper utility to decode bytes, integers, fields, varints, etc, from
// a buffer of bytes. // a buffer of bytes.
class Decoder { class Decoder {
...@@ -125,47 +119,19 @@ class Decoder { ...@@ -125,47 +119,19 @@ class Decoder {
// Reads a single 16-bit unsigned integer (little endian). // Reads a single 16-bit unsigned integer (little endian).
inline uint16_t read_u16(const byte* ptr) { inline uint16_t read_u16(const byte* ptr) {
DCHECK(ptr >= start_ && (ptr + 2) <= end_); DCHECK(ptr >= start_ && (ptr + 2) <= end_);
#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK return ReadLittleEndianValue<uint16_t>(ptr);
return *reinterpret_cast<const uint16_t*>(ptr);
#else
uint16_t b0 = ptr[0];
uint16_t b1 = ptr[1];
return (b1 << 8) | b0;
#endif
} }
// Reads a single 32-bit unsigned integer (little endian). // Reads a single 32-bit unsigned integer (little endian).
inline uint32_t read_u32(const byte* ptr) { inline uint32_t read_u32(const byte* ptr) {
DCHECK(ptr >= start_ && (ptr + 4) <= end_); DCHECK(ptr >= start_ && (ptr + 4) <= end_);
#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK return ReadLittleEndianValue<uint32_t>(ptr);
return *reinterpret_cast<const uint32_t*>(ptr);
#else
uint32_t b0 = ptr[0];
uint32_t b1 = ptr[1];
uint32_t b2 = ptr[2];
uint32_t b3 = ptr[3];
return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
#endif
} }
// Reads a single 64-bit unsigned integer (little endian). // Reads a single 64-bit unsigned integer (little endian).
inline uint64_t read_u64(const byte* ptr) { inline uint64_t read_u64(const byte* ptr) {
DCHECK(ptr >= start_ && (ptr + 8) <= end_); DCHECK(ptr >= start_ && (ptr + 8) <= end_);
#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK return ReadLittleEndianValue<uint64_t>(ptr);
return *reinterpret_cast<const uint64_t*>(ptr);
#else
uint32_t b0 = ptr[0];
uint32_t b1 = ptr[1];
uint32_t b2 = ptr[2];
uint32_t b3 = ptr[3];
uint32_t low = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
uint32_t b4 = ptr[4];
uint32_t b5 = ptr[5];
uint32_t b6 = ptr[6];
uint32_t b7 = ptr[7];
uint64_t high = (b7 << 24) | (b6 << 16) | (b5 << 8) | b4;
return (high << 32) | low;
#endif
} }
// Reads a 8-bit unsigned integer (byte) and advances {pc_}. // Reads a 8-bit unsigned integer (byte) and advances {pc_}.
......
...@@ -36,25 +36,13 @@ class ZoneBuffer : public ZoneObject { ...@@ -36,25 +36,13 @@ class ZoneBuffer : public ZoneObject {
void write_u16(uint16_t x) { void write_u16(uint16_t x) {
EnsureSpace(2); EnsureSpace(2);
#if V8_TARGET_LITTLE_ENDIAN WriteLittleEndianValue<uint16_t>(pos_, x);
WriteUnalignedUInt16(pos_, x);
#else
pos_[0] = x & 0xff;
pos_[1] = (x >> 8) & 0xff;
#endif
pos_ += 2; pos_ += 2;
} }
void write_u32(uint32_t x) { void write_u32(uint32_t x) {
EnsureSpace(4); EnsureSpace(4);
#if V8_TARGET_LITTLE_ENDIAN WriteLittleEndianValue<uint32_t>(pos_, x);
WriteUnalignedUInt32(pos_, x);
#else
pos_[0] = x & 0xff;
pos_[1] = (x >> 8) & 0xff;
pos_[2] = (x >> 16) & 0xff;
pos_[3] = (x >> 24) & 0xff;
#endif
pos_ += 4; pos_ += 4;
} }
......
...@@ -1459,20 +1459,20 @@ class ThreadImpl : public WasmInterpreter::Thread { ...@@ -1459,20 +1459,20 @@ class ThreadImpl : public WasmInterpreter::Thread {
break; break;
} }
#define LOAD_CASE(name, ctype, mtype) \ #define LOAD_CASE(name, ctype, mtype) \
case kExpr##name: { \ case kExpr##name: { \
MemoryAccessOperand operand(&decoder, code->at(pc)); \ MemoryAccessOperand operand(&decoder, code->at(pc)); \
uint32_t index = Pop().to<uint32_t>(); \ uint32_t index = Pop().to<uint32_t>(); \
size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \ size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \
if (operand.offset > effective_mem_size || \ if (operand.offset > effective_mem_size || \
index > (effective_mem_size - operand.offset)) { \ index > (effective_mem_size - operand.offset)) { \
return DoTrap(kTrapMemOutOfBounds, pc); \ return DoTrap(kTrapMemOutOfBounds, pc); \
} \ } \
byte* addr = instance()->mem_start + operand.offset + index; \ byte* addr = instance()->mem_start + operand.offset + index; \
WasmVal result(static_cast<ctype>(ReadUnalignedValue<mtype>(addr))); \ WasmVal result(static_cast<ctype>(ReadLittleEndianValue<mtype>(addr))); \
Push(pc, result); \ Push(pc, result); \
len = 1 + operand.length; \ len = 1 + operand.length; \
break; \ break; \
} }
LOAD_CASE(I32LoadMem8S, int32_t, int8_t); LOAD_CASE(I32LoadMem8S, int32_t, int8_t);
...@@ -1491,21 +1491,21 @@ class ThreadImpl : public WasmInterpreter::Thread { ...@@ -1491,21 +1491,21 @@ class ThreadImpl : public WasmInterpreter::Thread {
LOAD_CASE(F64LoadMem, double, double); LOAD_CASE(F64LoadMem, double, double);
#undef LOAD_CASE #undef LOAD_CASE
#define STORE_CASE(name, ctype, mtype) \ #define STORE_CASE(name, ctype, mtype) \
case kExpr##name: { \ case kExpr##name: { \
MemoryAccessOperand operand(&decoder, code->at(pc)); \ MemoryAccessOperand operand(&decoder, code->at(pc)); \
WasmVal val = Pop(); \ WasmVal val = Pop(); \
uint32_t index = Pop().to<uint32_t>(); \ uint32_t index = Pop().to<uint32_t>(); \
size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \ size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \
if (operand.offset > effective_mem_size || \ if (operand.offset > effective_mem_size || \
index > (effective_mem_size - operand.offset)) { \ index > (effective_mem_size - operand.offset)) { \
return DoTrap(kTrapMemOutOfBounds, pc); \ return DoTrap(kTrapMemOutOfBounds, pc); \
} \ } \
byte* addr = instance()->mem_start + operand.offset + index; \ byte* addr = instance()->mem_start + operand.offset + index; \
WriteUnalignedValue<mtype>(addr, static_cast<mtype>(val.to<ctype>())); \ WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>())); \
Push(pc, val); \ Push(pc, val); \
len = 1 + operand.length; \ len = 1 + operand.length; \
break; \ break; \
} }
STORE_CASE(I32StoreMem8, int32_t, int8_t); STORE_CASE(I32StoreMem8, int32_t, int8_t);
......
...@@ -297,25 +297,6 @@ ...@@ -297,25 +297,6 @@
'test-cpu-profiler/JsNative1JsNative2JsSample': [SKIP], 'test-cpu-profiler/JsNative1JsNative2JsSample': [SKIP],
}], # 'system == windows' }], # 'system == windows'
##############################################################################
['byteorder == big', {
# TODO(mips-team): Fix Wasm for big-endian.
'test-run-wasm-module/Run_WasmModule_CallAdd': [SKIP],
'test-run-wasm-module/Run_WasmModule_CallMain_recursive': [SKIP],
'test-run-wasm-module/Run_WasmModule_ReadLoadedDataSegment': [SKIP],
'test-run-wasm-module/Run_WasmModule_Return114': [SKIP],
'test-run-wasm-module/Run_WasmModule_CheckMemoryIsZero': [SKIP],
'test-run-wasm-module/Run_WasmModule_Global': [SKIP],
'test-run-wasm/RunWasmCompiled_Int32LoadInt16_signext': [SKIP],
'test-run-wasm/RunWasmCompiled_Int32LoadInt16_zeroext': [SKIP],
'test-run-wasm/RunWasmCompiled_MixedGlobals': [SKIP],
'test-run-wasm-64/RunWasmCompiled_I64*': [SKIP],
'test-run-wasm-64/RunWasmCompiled_LoadStoreI64_sx': [SKIP],
'test-run-wasm-64/Run_TestI64WasmRunner': [SKIP],
'test-run-wasm-64/RunWasmCompiled_Call_Int64Sub': [SKIP],
'test-run-wasm-64/RunWasmCompiled_MemI64_Sum': [SKIP],
}], # 'byteorder == big'
############################################################################## ##############################################################################
['arch == arm', { ['arch == arm', {
......
...@@ -1245,7 +1245,7 @@ WASM_EXEC_TEST(I64ReinterpretF64) { ...@@ -1245,7 +1245,7 @@ WASM_EXEC_TEST(I64ReinterpretF64) {
FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(i) {
int64_t expected = static_cast<int64_t>(*i) * 0x300010001; int64_t expected = static_cast<int64_t>(*i) * 0x300010001;
memory[0] = expected; module.WriteMemory(&memory[0], expected);
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
} }
...@@ -1264,7 +1264,7 @@ WASM_EXEC_TEST(F64ReinterpretI64) { ...@@ -1264,7 +1264,7 @@ WASM_EXEC_TEST(F64ReinterpretI64) {
FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(i) {
int64_t expected = static_cast<int64_t>(*i) * 0x300010001; int64_t expected = static_cast<int64_t>(*i) * 0x300010001;
CHECK_EQ(expected, r.Call(expected)); CHECK_EQ(expected, r.Call(expected));
CHECK_EQ(expected, memory[0]); CHECK_EQ(expected, module.ReadMemory<int64_t>(&memory[0]));
} }
} }
...@@ -1277,13 +1277,13 @@ WASM_EXEC_TEST(LoadMemI64) { ...@@ -1277,13 +1277,13 @@ WASM_EXEC_TEST(LoadMemI64) {
BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_I8(0))); BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_I8(0)));
memory[0] = 0xaabbccdd00112233LL; module.WriteMemory<int64_t>(&memory[0], 0xaabbccdd00112233LL);
CHECK_EQ(0xaabbccdd00112233LL, r.Call()); CHECK_EQ(0xaabbccdd00112233LL, r.Call());
memory[0] = 0x33aabbccdd001122LL; module.WriteMemory<int64_t>(&memory[0], 0x33aabbccdd001122LL);
CHECK_EQ(0x33aabbccdd001122LL, r.Call()); CHECK_EQ(0x33aabbccdd001122LL, r.Call());
memory[0] = 77777777; module.WriteMemory<int64_t>(&memory[0], 77777777);
CHECK_EQ(77777777, r.Call()); CHECK_EQ(77777777, r.Call());
} }
...@@ -1298,13 +1298,13 @@ WASM_EXEC_TEST(LoadMemI64_alignment) { ...@@ -1298,13 +1298,13 @@ WASM_EXEC_TEST(LoadMemI64_alignment) {
BUILD(r, BUILD(r,
WASM_LOAD_MEM_ALIGNMENT(MachineType::Int64(), WASM_I8(0), alignment)); WASM_LOAD_MEM_ALIGNMENT(MachineType::Int64(), WASM_I8(0), alignment));
memory[0] = 0xaabbccdd00112233LL; module.WriteMemory<int64_t>(&memory[0], 0xaabbccdd00112233LL);
CHECK_EQ(0xaabbccdd00112233LL, r.Call()); CHECK_EQ(0xaabbccdd00112233LL, r.Call());
memory[0] = 0x33aabbccdd001122LL; module.WriteMemory<int64_t>(&memory[0], 0x33aabbccdd001122LL);
CHECK_EQ(0x33aabbccdd001122LL, r.Call()); CHECK_EQ(0x33aabbccdd001122LL, r.Call());
memory[0] = 77777777; module.WriteMemory<int64_t>(&memory[0], 77777777);
CHECK_EQ(77777777, r.Call()); CHECK_EQ(77777777, r.Call());
} }
} }
...@@ -1338,7 +1338,7 @@ WASM_EXEC_TEST(MemI64_Sum) { ...@@ -1338,7 +1338,7 @@ WASM_EXEC_TEST(MemI64_Sum) {
module.RandomizeMemory(i * 33); module.RandomizeMemory(i * 33);
uint64_t expected = 0; uint64_t expected = 0;
for (size_t j = kNumElems - 1; j > 0; j--) { for (size_t j = kNumElems - 1; j > 0; j--) {
expected += memory[j]; expected += module.ReadMemory(&memory[j]);
} }
uint64_t result = r.Call(8 * (kNumElems - 1)); uint64_t result = r.Call(8 * (kNumElems - 1));
CHECK_EQ(expected, result); CHECK_EQ(expected, result);
...@@ -1355,10 +1355,10 @@ WASM_EXEC_TEST(StoreMemI64_alignment) { ...@@ -1355,10 +1355,10 @@ WASM_EXEC_TEST(StoreMemI64_alignment) {
BUILD(r, WASM_STORE_MEM_ALIGNMENT(MachineType::Int64(), WASM_ZERO, i, BUILD(r, WASM_STORE_MEM_ALIGNMENT(MachineType::Int64(), WASM_ZERO, i,
WASM_GET_LOCAL(0))); WASM_GET_LOCAL(0)));
module.RandomizeMemory(1111); module.RandomizeMemory(1111);
memory[0] = 0; module.WriteMemory<int64_t>(&memory[0], 0);
CHECK_EQ(kWritten, r.Call(kWritten)); CHECK_EQ(kWritten, r.Call(kWritten));
CHECK_EQ(kWritten, memory[0]); CHECK_EQ(kWritten, module.ReadMemory(&memory[0]));
} }
} }
...@@ -1376,7 +1376,7 @@ WASM_EXEC_TEST(I64Global) { ...@@ -1376,7 +1376,7 @@ WASM_EXEC_TEST(I64Global) {
WASM_I64_SCONVERT_I32(WASM_GET_LOCAL(0)))), WASM_I64_SCONVERT_I32(WASM_GET_LOCAL(0)))),
WASM_ZERO)); WASM_ZERO));
*global = 0xFFFFFFFFFFFFFFFFLL; module.WriteMemory<int64_t>(global, 0xFFFFFFFFFFFFFFFFLL);
for (int i = 9; i < 444444; i += 111111) { for (int i = 9; i < 444444; i += 111111) {
int64_t expected = *global & i; int64_t expected = *global & i;
r.Call(i); r.Call(i);
......
...@@ -1012,7 +1012,7 @@ WASM_EXEC_TEST(F32ReinterpretI32) { ...@@ -1012,7 +1012,7 @@ WASM_EXEC_TEST(F32ReinterpretI32) {
FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(i) {
int32_t expected = *i; int32_t expected = *i;
memory[0] = expected; module.WriteMemory(&memory[0], expected);
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
} }
...@@ -1030,7 +1030,7 @@ WASM_EXEC_TEST(I32ReinterpretF32) { ...@@ -1030,7 +1030,7 @@ WASM_EXEC_TEST(I32ReinterpretF32) {
FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(i) {
int32_t expected = *i; int32_t expected = *i;
CHECK_EQ(107, r.Call(expected)); CHECK_EQ(107, r.Call(expected));
CHECK_EQ(expected, memory[0]); CHECK_EQ(expected, module.ReadMemory(&memory[0]));
} }
} }
...@@ -1044,7 +1044,7 @@ WASM_EXEC_TEST(ReturnStore) { ...@@ -1044,7 +1044,7 @@ WASM_EXEC_TEST(ReturnStore) {
FOR_INT32_INPUTS(i) { FOR_INT32_INPUTS(i) {
int32_t expected = *i; int32_t expected = *i;
memory[0] = expected; module.WriteMemory(&memory[0], expected);
CHECK_EQ(expected, r.Call()); CHECK_EQ(expected, r.Call());
} }
} }
...@@ -1334,13 +1334,13 @@ WASM_EXEC_TEST(LoadMemI32) { ...@@ -1334,13 +1334,13 @@ WASM_EXEC_TEST(LoadMemI32) {
BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_I8(0))); BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_I8(0)));
memory[0] = 99999999; module.WriteMemory(&memory[0], 99999999);
CHECK_EQ(99999999, r.Call(0)); CHECK_EQ(99999999, r.Call(0));
memory[0] = 88888888; module.WriteMemory(&memory[0], 88888888);
CHECK_EQ(88888888, r.Call(0)); CHECK_EQ(88888888, r.Call(0));
memory[0] = 77777777; module.WriteMemory(&memory[0], 77777777);
CHECK_EQ(77777777, r.Call(0)); CHECK_EQ(77777777, r.Call(0));
} }
...@@ -1354,14 +1354,14 @@ WASM_EXEC_TEST(LoadMemI32_alignment) { ...@@ -1354,14 +1354,14 @@ WASM_EXEC_TEST(LoadMemI32_alignment) {
BUILD(r, BUILD(r,
WASM_LOAD_MEM_ALIGNMENT(MachineType::Int32(), WASM_I8(0), alignment)); WASM_LOAD_MEM_ALIGNMENT(MachineType::Int32(), WASM_I8(0), alignment));
memory[0] = 0x1a2b3c4d; module.WriteMemory(&memory[0], 0x1a2b3c4d);
CHECK_EQ(0x1a2b3c4d, r.Call(0)); CHECK_EQ(0x1a2b3c4d, r.Call(0));
memory[0] = 0x5e6f7a8b; module.WriteMemory(&memory[0], 0x5e6f7a8b);
CHECK_EQ(0x5e6f7a8b, r.Call(0)); CHECK_EQ(0x5e6f7a8b, r.Call(0));
memory[0] = 0x9ca0b1c2; module.WriteMemory(&memory[0], 0x7ca0b1c2);
CHECK_EQ(0x9ca0b1c2, r.Call(0)); CHECK_EQ(0x7ca0b1c2, r.Call(0));
} }
} }
...@@ -1373,7 +1373,7 @@ WASM_EXEC_TEST(LoadMemI32_oob) { ...@@ -1373,7 +1373,7 @@ WASM_EXEC_TEST(LoadMemI32_oob) {
BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0))); BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0)));
memory[0] = 88888888; module.WriteMemory(&memory[0], 88888888);
CHECK_EQ(88888888, r.Call(0u)); CHECK_EQ(88888888, r.Call(0u));
for (uint32_t offset = 29; offset < 40; ++offset) { for (uint32_t offset = 29; offset < 40; ++offset) {
CHECK_TRAP(r.Call(offset)); CHECK_TRAP(r.Call(offset));
...@@ -1418,18 +1418,18 @@ WASM_EXEC_TEST(LoadMemI32_offset) { ...@@ -1418,18 +1418,18 @@ WASM_EXEC_TEST(LoadMemI32_offset) {
BUILD(r, WASM_LOAD_MEM_OFFSET(MachineType::Int32(), 4, WASM_GET_LOCAL(0))); BUILD(r, WASM_LOAD_MEM_OFFSET(MachineType::Int32(), 4, WASM_GET_LOCAL(0)));
memory[0] = 66666666; module.WriteMemory(&memory[0], 66666666);
memory[1] = 77777777; module.WriteMemory(&memory[1], 77777777);
memory[2] = 88888888; module.WriteMemory(&memory[2], 88888888);
memory[3] = 99999999; module.WriteMemory(&memory[3], 99999999);
CHECK_EQ(77777777, r.Call(0)); CHECK_EQ(77777777, r.Call(0));
CHECK_EQ(88888888, r.Call(4)); CHECK_EQ(88888888, r.Call(4));
CHECK_EQ(99999999, r.Call(8)); CHECK_EQ(99999999, r.Call(8));
memory[0] = 11111111; module.WriteMemory(&memory[0], 11111111);
memory[1] = 22222222; module.WriteMemory(&memory[1], 22222222);
memory[2] = 33333333; module.WriteMemory(&memory[2], 33333333);
memory[3] = 44444444; module.WriteMemory(&memory[3], 44444444);
CHECK_EQ(22222222, r.Call(0)); CHECK_EQ(22222222, r.Call(0));
CHECK_EQ(33333333, r.Call(4)); CHECK_EQ(33333333, r.Call(4));
CHECK_EQ(44444444, r.Call(8)); CHECK_EQ(44444444, r.Call(8));
...@@ -1493,7 +1493,7 @@ WASM_EXEC_TEST(StoreMemI32_alignment) { ...@@ -1493,7 +1493,7 @@ WASM_EXEC_TEST(StoreMemI32_alignment) {
memory[0] = 0; memory[0] = 0;
CHECK_EQ(kWritten, r.Call(kWritten)); CHECK_EQ(kWritten, r.Call(kWritten));
CHECK_EQ(kWritten, memory[0]); CHECK_EQ(kWritten, module.ReadMemory(&memory[0]));
} }
} }
...@@ -1508,15 +1508,15 @@ WASM_EXEC_TEST(StoreMemI32_offset) { ...@@ -1508,15 +1508,15 @@ WASM_EXEC_TEST(StoreMemI32_offset) {
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
module.RandomizeMemory(1111); module.RandomizeMemory(1111);
memory[0] = 66666666; module.WriteMemory(&memory[0], 66666666);
memory[1] = 77777777; module.WriteMemory(&memory[1], 77777777);
memory[2] = 88888888; module.WriteMemory(&memory[2], 88888888);
memory[3] = 99999999; module.WriteMemory(&memory[3], 99999999);
CHECK_EQ(kWritten, r.Call(i * 4)); CHECK_EQ(kWritten, r.Call(i * 4));
CHECK_EQ(66666666, memory[0]); CHECK_EQ(66666666, module.ReadMemory(&memory[0]));
CHECK_EQ(i == 0 ? kWritten : 77777777, memory[1]); CHECK_EQ(i == 0 ? kWritten : 77777777, module.ReadMemory(&memory[1]));
CHECK_EQ(i == 1 ? kWritten : 88888888, memory[2]); CHECK_EQ(i == 1 ? kWritten : 88888888, module.ReadMemory(&memory[2]));
CHECK_EQ(i == 2 ? kWritten : 99999999, memory[3]); CHECK_EQ(i == 2 ? kWritten : 99999999, module.ReadMemory(&memory[3]));
} }
} }
...@@ -1559,7 +1559,7 @@ WASM_EXEC_TEST(LoadMemI32_P) { ...@@ -1559,7 +1559,7 @@ WASM_EXEC_TEST(LoadMemI32_P) {
BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0))); BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0)));
for (int i = 0; i < kNumElems; ++i) { for (int i = 0; i < kNumElems; ++i) {
CHECK_EQ(memory[i], r.Call(i * 4)); CHECK_EQ(module.ReadMemory(&memory[i]), r.Call(i * 4));
} }
} }
...@@ -1588,7 +1588,7 @@ WASM_EXEC_TEST(MemI32_Sum) { ...@@ -1588,7 +1588,7 @@ WASM_EXEC_TEST(MemI32_Sum) {
module.RandomizeMemory(i * 33); module.RandomizeMemory(i * 33);
uint32_t expected = 0; uint32_t expected = 0;
for (size_t j = kNumElems - 1; j > 0; --j) { for (size_t j = kNumElems - 1; j > 0; --j) {
expected += memory[j]; expected += module.ReadMemory(&memory[j]);
} }
uint32_t result = r.Call(4 * (kNumElems - 1)); uint32_t result = r.Call(4 * (kNumElems - 1));
CHECK_EQ(expected, result); CHECK_EQ(expected, result);
...@@ -1615,11 +1615,11 @@ WASM_EXEC_TEST(MemF32_Sum) { ...@@ -1615,11 +1615,11 @@ WASM_EXEC_TEST(MemF32_Sum) {
TestingModule module(execution_mode); TestingModule module(execution_mode);
module.AddMemoryElems<float>(kSize); module.AddMemoryElems<float>(kSize);
float* buffer = module.raw_mem_start<float>(); float* buffer = module.raw_mem_start<float>();
buffer[0] = -99.25; module.WriteMemory(&buffer[0], -99.25f);
buffer[1] = -888.25; module.WriteMemory(&buffer[1], -888.25f);
buffer[2] = -77.25; module.WriteMemory(&buffer[2], -77.25f);
buffer[3] = 66666.25; module.WriteMemory(&buffer[3], 66666.25f);
buffer[4] = 5555.25; module.WriteMemory(&buffer[4], 5555.25f);
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
const byte kSum = r.AllocateLocal(kAstF32); const byte kSum = r.AllocateLocal(kAstF32);
...@@ -1639,8 +1639,8 @@ WASM_EXEC_TEST(MemF32_Sum) { ...@@ -1639,8 +1639,8 @@ WASM_EXEC_TEST(MemF32_Sum) {
WASM_GET_LOCAL(0))); WASM_GET_LOCAL(0)));
CHECK_EQ(0, r.Call(4 * (kSize - 1))); CHECK_EQ(0, r.Call(4 * (kSize - 1)));
CHECK_NE(-99.25, buffer[0]); CHECK_NE(-99.25f, module.ReadMemory(&buffer[0]));
CHECK_EQ(71256.0f, buffer[0]); CHECK_EQ(71256.0f, module.ReadMemory(&buffer[0]));
} }
template <typename T> template <typename T>
...@@ -1648,9 +1648,9 @@ T GenerateAndRunFold(WasmExecutionMode execution_mode, WasmOpcode binop, ...@@ -1648,9 +1648,9 @@ T GenerateAndRunFold(WasmExecutionMode execution_mode, WasmOpcode binop,
T* buffer, uint32_t size, LocalType astType, T* buffer, uint32_t size, LocalType astType,
MachineType memType) { MachineType memType) {
TestingModule module(execution_mode); TestingModule module(execution_mode);
module.AddMemoryElems<T>(size); T* memory = module.AddMemoryElems<T>(size);
for (uint32_t i = 0; i < size; ++i) { for (uint32_t i = 0; i < size; ++i) {
module.raw_mem_start<T>()[i] = buffer[i]; module.WriteMemory(&memory[i], buffer[i]);
} }
WasmRunner<int32_t> r(&module, MachineType::Int32()); WasmRunner<int32_t> r(&module, MachineType::Int32());
const byte kAccum = r.AllocateLocal(astType); const byte kAccum = r.AllocateLocal(astType);
...@@ -1671,7 +1671,7 @@ T GenerateAndRunFold(WasmExecutionMode execution_mode, WasmOpcode binop, ...@@ -1671,7 +1671,7 @@ T GenerateAndRunFold(WasmExecutionMode execution_mode, WasmOpcode binop,
WASM_STORE_MEM(memType, WASM_ZERO, WASM_GET_LOCAL(kAccum)), WASM_STORE_MEM(memType, WASM_ZERO, WASM_GET_LOCAL(kAccum)),
WASM_GET_LOCAL(0))); WASM_GET_LOCAL(0)));
r.Call(static_cast<int>(sizeof(T) * (size - 1))); r.Call(static_cast<int>(sizeof(T) * (size - 1)));
return module.raw_mem_at<double>(0); return module.ReadMemory(&memory[0]);
} }
WASM_EXEC_TEST(MemF64_Mul) { WASM_EXEC_TEST(MemF64_Mul) {
...@@ -2064,11 +2064,11 @@ WASM_EXEC_TEST(CallF64StackParameter) { ...@@ -2064,11 +2064,11 @@ WASM_EXEC_TEST(CallF64StackParameter) {
WASM_EXEC_TEST(CallVoid) { WASM_EXEC_TEST(CallVoid) {
const byte kMemOffset = 8; const byte kMemOffset = 8;
const int32_t kElemNum = kMemOffset / sizeof(int32_t); const int32_t kElemNum = kMemOffset / sizeof(int32_t);
const int32_t kExpected = -414444; const int32_t kExpected = 414444;
// Build the target function. // Build the target function.
TestSignatures sigs; TestSignatures sigs;
TestingModule module(execution_mode); TestingModule module(execution_mode);
module.AddMemory(16); int32_t* memory = module.AddMemoryElems<int32_t>(16 / sizeof(int32_t));
module.RandomizeMemory(); module.RandomizeMemory();
WasmFunctionCompiler t(sigs.v_v(), &module); WasmFunctionCompiler t(sigs.v_v(), &module);
BUILD(t, WASM_STORE_MEM(MachineType::Int32(), WASM_I8(kMemOffset), BUILD(t, WASM_STORE_MEM(MachineType::Int32(), WASM_I8(kMemOffset),
...@@ -2082,7 +2082,8 @@ WASM_EXEC_TEST(CallVoid) { ...@@ -2082,7 +2082,8 @@ WASM_EXEC_TEST(CallVoid) {
int32_t result = r.Call(); int32_t result = r.Call();
CHECK_EQ(kExpected, result); CHECK_EQ(kExpected, result);
CHECK_EQ(kExpected, module.raw_mem_start<int32_t>()[kElemNum]); CHECK_EQ(static_cast<int64_t>(kExpected),
static_cast<int64_t>(module.ReadMemory(&memory[kElemNum])));
} }
WASM_EXEC_TEST(Call_Int32Add) { WASM_EXEC_TEST(Call_Int32Add) {
...@@ -2139,14 +2140,15 @@ WASM_EXEC_TEST(Call_Float64Sub) { ...@@ -2139,14 +2140,15 @@ WASM_EXEC_TEST(Call_Float64Sub) {
FOR_FLOAT64_INPUTS(i) { FOR_FLOAT64_INPUTS(i) {
FOR_FLOAT64_INPUTS(j) { FOR_FLOAT64_INPUTS(j) {
memory[0] = *i; module.WriteMemory(&memory[0], *i);
memory[1] = *j; module.WriteMemory(&memory[1], *j);
double expected = *i - *j; double expected = *i - *j;
CHECK_EQ(107, r.Call()); CHECK_EQ(107, r.Call());
if (expected != expected) { if (expected != expected) {
CHECK(memory[0] != memory[0]); CHECK(module.ReadMemory(&memory[0]) != module.ReadMemory(&memory[0]));
} else { } else {
CHECK_EQ(expected, memory[0]); CHECK_EQ(expected, module.ReadMemory(&memory[0]));
} }
} }
} }
......
...@@ -139,14 +139,22 @@ class TestingModule : public ModuleEnv { ...@@ -139,14 +139,22 @@ class TestingModule : public ModuleEnv {
template <typename T> template <typename T>
T raw_mem_at(int i) { T raw_mem_at(int i) {
DCHECK(instance->mem_start); DCHECK(instance->mem_start);
return reinterpret_cast<T*>(instance->mem_start)[i]; return ReadMemory(&(reinterpret_cast<T*>(instance->mem_start)[i]));
} }
template <typename T> template <typename T>
T raw_val_at(int i) { T raw_val_at(int i) {
T val; return ReadMemory(reinterpret_cast<T*>(instance->mem_start + i));
memcpy(&val, reinterpret_cast<void*>(instance->mem_start + i), sizeof(T)); }
return val;
template <typename T>
void WriteMemory(T* p, T val) {
WriteLittleEndianValue<T>(p, val);
}
template <typename T>
T ReadMemory(T* p) {
return ReadLittleEndianValue<T>(p);
} }
// Zero-initialize the memory. // Zero-initialize the memory.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment