Implement WASM big-endian support.

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/2034093002
Cr-Commit-Position: refs/heads/master@{#37065}
This commit is contained in:
ivica.bogosavljevic 2016-06-17 04:51:17 -07:00 committed by Commit bot
parent 43a10a0c4a
commit d3f3f6c818
10 changed files with 267 additions and 162 deletions

View File

@ -992,6 +992,125 @@ Node* WasmGraphBuilder::MaskShiftCount64(Node* 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) {
DCHECK(shiftCount > 0);
DCHECK((shiftCount + 8) % 16 == 0);
Node* shiftLower = graph()->NewNode(shiftLeftOpcode, value,
jsgraph()->Int32Constant(shiftCount));
Node* shiftHigher = graph()->NewNode(shiftRightOpcode, value,
jsgraph()->Int32Constant(shiftCount));
Node* lowerByte;
Node* higherByte;
if (valueSizeInBits > 32) {
lowerByte = graph()->NewNode(
andOpcode, shiftLower,
jsgraph()->Int64Constant(0xFFl << (valueSizeInBits - 8 - i)));
higherByte = graph()->NewNode(andOpcode, shiftHigher,
jsgraph()->Int64Constant(0xFFl << i));
} else {
lowerByte = graph()->NewNode(
andOpcode, shiftLower,
jsgraph()->Int32Constant(0xFF << (valueSizeInBits - 8 - i)));
higherByte = graph()->NewNode(andOpcode, shiftHigher,
jsgraph()->Int32Constant(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* result =
Unop(wasm::kExprF32ReinterpretI32,
@ -2749,6 +2868,11 @@ Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype,
} else {
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 &&
ElementSizeLog2Of(memtype.representation()) < 3) {
@ -2869,6 +2993,12 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
bool aligned = static_cast<int>(alignment) >=
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 ||
jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) {
StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);

View File

@ -234,6 +234,9 @@ class WasmGraphBuilder {
Node* BuildUnalignedStore(MachineType memtype, Node* index, uint32_t offset,
uint32_t alignment, Node* val);
Node* BuildChangeEndianness(Node* node, MachineType type,
wasm::LocalType wasmtype = wasm::kAstStmt);
Node* MaskShiftCount32(Node* node);
Node* MaskShiftCount64(Node* node);

View File

@ -1552,6 +1552,33 @@ static inline void WriteUnalignedUInt32(void* p, uint32_t 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 v8

View File

@ -26,12 +26,6 @@ namespace wasm {
#define TRACE(...)
#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 buffer of bytes.
class Decoder {
@ -122,47 +116,19 @@ class Decoder {
// Reads a single 16-bit unsigned integer (little endian).
inline uint16_t read_u16(const byte* ptr) {
DCHECK(ptr >= start_ && (ptr + 2) <= end_);
#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
return *reinterpret_cast<const uint16_t*>(ptr);
#else
uint16_t b0 = ptr[0];
uint16_t b1 = ptr[1];
return (b1 << 8) | b0;
#endif
return ReadLittleEndianValue<uint16_t>(ptr);
}
// Reads a single 32-bit unsigned integer (little endian).
inline uint32_t read_u32(const byte* ptr) {
DCHECK(ptr >= start_ && (ptr + 4) <= end_);
#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
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
return ReadLittleEndianValue<uint32_t>(ptr);
}
// Reads a single 64-bit unsigned integer (little endian).
inline uint64_t read_u64(const byte* ptr) {
DCHECK(ptr >= start_ && (ptr + 8) <= end_);
#if V8_TARGET_LITTLE_ENDIAN && UNALIGNED_ACCESS_OK
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
return ReadLittleEndianValue<uint64_t>(ptr);
}
// Reads a 8-bit unsigned integer (byte) and advances {pc_}.

View File

@ -36,25 +36,13 @@ class ZoneBuffer : public ZoneObject {
void write_u16(uint16_t x) {
EnsureSpace(2);
#if V8_TARGET_LITTLE_ENDIAN
WriteUnalignedUInt16(pos_, x);
#else
pos_[0] = x & 0xff;
pos_[1] = (x >> 8) & 0xff;
#endif
WriteLittleEndianValue<uint16_t>(pos_, x);
pos_ += 2;
}
void write_u32(uint32_t x) {
EnsureSpace(4);
#if V8_TARGET_LITTLE_ENDIAN
WriteUnalignedUInt32(pos_, x);
#else
pos_[0] = x & 0xff;
pos_[1] = (x >> 8) & 0xff;
pos_[2] = (x >> 16) & 0xff;
pos_[3] = (x >> 24) & 0xff;
#endif
WriteLittleEndianValue<uint32_t>(pos_, x);
pos_ += 4;
}

View File

@ -1437,20 +1437,20 @@ class ThreadImpl : public WasmInterpreter::Thread {
break;
}
#define LOAD_CASE(name, ctype, mtype) \
case kExpr##name: { \
MemoryAccessOperand operand(&decoder, code->at(pc)); \
uint32_t index = Pop().to<uint32_t>(); \
size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \
if (operand.offset > effective_mem_size || \
index > (effective_mem_size - operand.offset)) { \
return DoTrap(kTrapMemOutOfBounds, pc); \
} \
byte* addr = instance()->mem_start + operand.offset + index; \
WasmVal result(static_cast<ctype>(ReadUnalignedValue<mtype>(addr))); \
Push(pc, result); \
len = 1 + operand.length; \
break; \
#define LOAD_CASE(name, ctype, mtype) \
case kExpr##name: { \
MemoryAccessOperand operand(&decoder, code->at(pc)); \
uint32_t index = Pop().to<uint32_t>(); \
size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \
if (operand.offset > effective_mem_size || \
index > (effective_mem_size - operand.offset)) { \
return DoTrap(kTrapMemOutOfBounds, pc); \
} \
byte* addr = instance()->mem_start + operand.offset + index; \
WasmVal result(static_cast<ctype>(ReadLittleEndianValue<mtype>(addr))); \
Push(pc, result); \
len = 1 + operand.length; \
break; \
}
LOAD_CASE(I32LoadMem8S, int32_t, int8_t);
@ -1469,21 +1469,21 @@ class ThreadImpl : public WasmInterpreter::Thread {
LOAD_CASE(F64LoadMem, double, double);
#undef LOAD_CASE
#define STORE_CASE(name, ctype, mtype) \
case kExpr##name: { \
MemoryAccessOperand operand(&decoder, code->at(pc)); \
WasmVal val = Pop(); \
uint32_t index = Pop().to<uint32_t>(); \
size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \
if (operand.offset > effective_mem_size || \
index > (effective_mem_size - operand.offset)) { \
return DoTrap(kTrapMemOutOfBounds, pc); \
} \
byte* addr = instance()->mem_start + operand.offset + index; \
WriteUnalignedValue<mtype>(addr, static_cast<mtype>(val.to<ctype>())); \
Push(pc, val); \
len = 1 + operand.length; \
break; \
#define STORE_CASE(name, ctype, mtype) \
case kExpr##name: { \
MemoryAccessOperand operand(&decoder, code->at(pc)); \
WasmVal val = Pop(); \
uint32_t index = Pop().to<uint32_t>(); \
size_t effective_mem_size = instance()->mem_size - sizeof(mtype); \
if (operand.offset > effective_mem_size || \
index > (effective_mem_size - operand.offset)) { \
return DoTrap(kTrapMemOutOfBounds, pc); \
} \
byte* addr = instance()->mem_start + operand.offset + index; \
WriteLittleEndianValue<mtype>(addr, static_cast<mtype>(val.to<ctype>())); \
Push(pc, val); \
len = 1 + operand.length; \
break; \
}
STORE_CASE(I32StoreMem8, int32_t, int8_t);

View File

@ -294,25 +294,6 @@
'test-cpu-profiler/JsNative1JsNative2JsSample': [SKIP],
}], # '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', {

View File

@ -1245,7 +1245,7 @@ WASM_EXEC_TEST(I64ReinterpretF64) {
FOR_INT32_INPUTS(i) {
int64_t expected = static_cast<int64_t>(*i) * 0x300010001;
memory[0] = expected;
module.WriteMemory(&memory[0], expected);
CHECK_EQ(expected, r.Call());
}
}
@ -1264,7 +1264,7 @@ WASM_EXEC_TEST(F64ReinterpretI64) {
FOR_INT32_INPUTS(i) {
int64_t expected = static_cast<int64_t>(*i) * 0x300010001;
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) {
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());
memory[0] = 0x33aabbccdd001122LL;
module.WriteMemory<int64_t>(&memory[0], 0x33aabbccdd001122LL);
CHECK_EQ(0x33aabbccdd001122LL, r.Call());
memory[0] = 77777777;
module.WriteMemory<int64_t>(&memory[0], 77777777);
CHECK_EQ(77777777, r.Call());
}
@ -1298,13 +1298,13 @@ WASM_EXEC_TEST(LoadMemI64_alignment) {
BUILD(r,
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());
memory[0] = 0x33aabbccdd001122LL;
module.WriteMemory<int64_t>(&memory[0], 0x33aabbccdd001122LL);
CHECK_EQ(0x33aabbccdd001122LL, r.Call());
memory[0] = 77777777;
module.WriteMemory<int64_t>(&memory[0], 77777777);
CHECK_EQ(77777777, r.Call());
}
}
@ -1338,7 +1338,7 @@ WASM_EXEC_TEST(MemI64_Sum) {
module.RandomizeMemory(i * 33);
uint64_t expected = 0;
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));
CHECK_EQ(expected, result);
@ -1355,10 +1355,10 @@ WASM_EXEC_TEST(StoreMemI64_alignment) {
BUILD(r, WASM_STORE_MEM_ALIGNMENT(MachineType::Int64(), WASM_ZERO, i,
WASM_GET_LOCAL(0)));
module.RandomizeMemory(1111);
memory[0] = 0;
module.WriteMemory<int64_t>(&memory[0], 0);
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) {
WASM_I64_SCONVERT_I32(WASM_GET_LOCAL(0)))),
WASM_ZERO));
*global = 0xFFFFFFFFFFFFFFFFLL;
module.WriteMemory<int64_t>(global, 0xFFFFFFFFFFFFFFFFLL);
for (int i = 9; i < 444444; i += 111111) {
int64_t expected = *global & i;
r.Call(i);

View File

@ -987,7 +987,7 @@ WASM_EXEC_TEST(F32ReinterpretI32) {
FOR_INT32_INPUTS(i) {
int32_t expected = *i;
memory[0] = expected;
module.WriteMemory(&memory[0], expected);
CHECK_EQ(expected, r.Call());
}
}
@ -1005,7 +1005,7 @@ WASM_EXEC_TEST(I32ReinterpretF32) {
FOR_INT32_INPUTS(i) {
int32_t expected = *i;
CHECK_EQ(107, r.Call(expected));
CHECK_EQ(expected, memory[0]);
CHECK_EQ(expected, module.ReadMemory(&memory[0]));
}
}
@ -1019,7 +1019,7 @@ WASM_EXEC_TEST(ReturnStore) {
FOR_INT32_INPUTS(i) {
int32_t expected = *i;
memory[0] = expected;
module.WriteMemory(&memory[0], expected);
CHECK_EQ(expected, r.Call());
}
}
@ -1309,13 +1309,13 @@ WASM_EXEC_TEST(LoadMemI32) {
BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_I8(0)));
memory[0] = 99999999;
module.WriteMemory(&memory[0], 99999999);
CHECK_EQ(99999999, r.Call(0));
memory[0] = 88888888;
module.WriteMemory(&memory[0], 88888888);
CHECK_EQ(88888888, r.Call(0));
memory[0] = 77777777;
module.WriteMemory(&memory[0], 77777777);
CHECK_EQ(77777777, r.Call(0));
}
@ -1329,14 +1329,14 @@ WASM_EXEC_TEST(LoadMemI32_alignment) {
BUILD(r,
WASM_LOAD_MEM_ALIGNMENT(MachineType::Int32(), WASM_I8(0), alignment));
memory[0] = 0x1a2b3c4d;
module.WriteMemory(&memory[0], 0x1a2b3c4d);
CHECK_EQ(0x1a2b3c4d, r.Call(0));
memory[0] = 0x5e6f7a8b;
module.WriteMemory(&memory[0], 0x5e6f7a8b);
CHECK_EQ(0x5e6f7a8b, r.Call(0));
memory[0] = 0x9ca0b1c2;
CHECK_EQ(0x9ca0b1c2, r.Call(0));
module.WriteMemory(&memory[0], 0x7ca0b1c2);
CHECK_EQ(0x7ca0b1c2, r.Call(0));
}
}
@ -1348,7 +1348,7 @@ WASM_EXEC_TEST(LoadMemI32_oob) {
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));
for (uint32_t offset = 29; offset < 40; ++offset) {
CHECK_TRAP(r.Call(offset));
@ -1393,18 +1393,18 @@ WASM_EXEC_TEST(LoadMemI32_offset) {
BUILD(r, WASM_LOAD_MEM_OFFSET(MachineType::Int32(), 4, WASM_GET_LOCAL(0)));
memory[0] = 66666666;
memory[1] = 77777777;
memory[2] = 88888888;
memory[3] = 99999999;
module.WriteMemory(&memory[0], 66666666);
module.WriteMemory(&memory[1], 77777777);
module.WriteMemory(&memory[2], 88888888);
module.WriteMemory(&memory[3], 99999999);
CHECK_EQ(77777777, r.Call(0));
CHECK_EQ(88888888, r.Call(4));
CHECK_EQ(99999999, r.Call(8));
memory[0] = 11111111;
memory[1] = 22222222;
memory[2] = 33333333;
memory[3] = 44444444;
module.WriteMemory(&memory[0], 11111111);
module.WriteMemory(&memory[1], 22222222);
module.WriteMemory(&memory[2], 33333333);
module.WriteMemory(&memory[3], 44444444);
CHECK_EQ(22222222, r.Call(0));
CHECK_EQ(33333333, r.Call(4));
CHECK_EQ(44444444, r.Call(8));
@ -1468,7 +1468,7 @@ WASM_EXEC_TEST(StoreMemI32_alignment) {
memory[0] = 0;
CHECK_EQ(kWritten, r.Call(kWritten));
CHECK_EQ(kWritten, memory[0]);
CHECK_EQ(kWritten, module.ReadMemory(&memory[0]));
}
}
@ -1483,15 +1483,15 @@ WASM_EXEC_TEST(StoreMemI32_offset) {
for (int i = 0; i < 2; ++i) {
module.RandomizeMemory(1111);
memory[0] = 66666666;
memory[1] = 77777777;
memory[2] = 88888888;
memory[3] = 99999999;
module.WriteMemory(&memory[0], 66666666);
module.WriteMemory(&memory[1], 77777777);
module.WriteMemory(&memory[2], 88888888);
module.WriteMemory(&memory[3], 99999999);
CHECK_EQ(kWritten, r.Call(i * 4));
CHECK_EQ(66666666, memory[0]);
CHECK_EQ(i == 0 ? kWritten : 77777777, memory[1]);
CHECK_EQ(i == 1 ? kWritten : 88888888, memory[2]);
CHECK_EQ(i == 2 ? kWritten : 99999999, memory[3]);
CHECK_EQ(66666666, module.ReadMemory(&memory[0]));
CHECK_EQ(i == 0 ? kWritten : 77777777, module.ReadMemory(&memory[1]));
CHECK_EQ(i == 1 ? kWritten : 88888888, module.ReadMemory(&memory[2]));
CHECK_EQ(i == 2 ? kWritten : 99999999, module.ReadMemory(&memory[3]));
}
}
@ -1534,7 +1534,7 @@ WASM_EXEC_TEST(LoadMemI32_P) {
BUILD(r, WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0)));
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));
}
}
@ -1563,7 +1563,7 @@ WASM_EXEC_TEST(MemI32_Sum) {
module.RandomizeMemory(i * 33);
uint32_t expected = 0;
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));
CHECK_EQ(expected, result);
@ -1590,11 +1590,11 @@ WASM_EXEC_TEST(MemF32_Sum) {
TestingModule module(execution_mode);
module.AddMemoryElems<float>(kSize);
float* buffer = module.raw_mem_start<float>();
buffer[0] = -99.25;
buffer[1] = -888.25;
buffer[2] = -77.25;
buffer[3] = 66666.25;
buffer[4] = 5555.25;
module.WriteMemory(&buffer[0], -99.25f);
module.WriteMemory(&buffer[1], -888.25f);
module.WriteMemory(&buffer[2], -77.25f);
module.WriteMemory(&buffer[3], 66666.25f);
module.WriteMemory(&buffer[4], 5555.25f);
WasmRunner<int32_t> r(&module, MachineType::Int32());
const byte kSum = r.AllocateLocal(kAstF32);
@ -1614,8 +1614,8 @@ WASM_EXEC_TEST(MemF32_Sum) {
WASM_GET_LOCAL(0)));
CHECK_EQ(0, r.Call(4 * (kSize - 1)));
CHECK_NE(-99.25, buffer[0]);
CHECK_EQ(71256.0f, buffer[0]);
CHECK_NE(-99.25f, module.ReadMemory(&buffer[0]));
CHECK_EQ(71256.0f, module.ReadMemory(&buffer[0]));
}
template <typename T>
@ -1623,9 +1623,9 @@ T GenerateAndRunFold(WasmExecutionMode execution_mode, WasmOpcode binop,
T* buffer, uint32_t size, LocalType astType,
MachineType memType) {
TestingModule module(execution_mode);
module.AddMemoryElems<T>(size);
T* memory = module.AddMemoryElems<T>(size);
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());
const byte kAccum = r.AllocateLocal(astType);
@ -1646,7 +1646,7 @@ T GenerateAndRunFold(WasmExecutionMode execution_mode, WasmOpcode binop,
WASM_STORE_MEM(memType, WASM_ZERO, WASM_GET_LOCAL(kAccum)),
WASM_GET_LOCAL(0)));
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) {
@ -2039,11 +2039,11 @@ WASM_EXEC_TEST(CallF64StackParameter) {
WASM_EXEC_TEST(CallVoid) {
const byte kMemOffset = 8;
const int32_t kElemNum = kMemOffset / sizeof(int32_t);
const int32_t kExpected = -414444;
const int32_t kExpected = 414444;
// Build the target function.
TestSignatures sigs;
TestingModule module(execution_mode);
module.AddMemory(16);
int32_t* memory = module.AddMemoryElems<int32_t>(16 / sizeof(int32_t));
module.RandomizeMemory();
WasmFunctionCompiler t(sigs.v_v(), &module);
BUILD(t, WASM_STORE_MEM(MachineType::Int32(), WASM_I8(kMemOffset),
@ -2057,7 +2057,8 @@ WASM_EXEC_TEST(CallVoid) {
int32_t result = r.Call();
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) {
@ -2114,14 +2115,15 @@ WASM_EXEC_TEST(Call_Float64Sub) {
FOR_FLOAT64_INPUTS(i) {
FOR_FLOAT64_INPUTS(j) {
memory[0] = *i;
memory[1] = *j;
module.WriteMemory(&memory[0], *i);
module.WriteMemory(&memory[1], *j);
double expected = *i - *j;
CHECK_EQ(107, r.Call());
if (expected != expected) {
CHECK(memory[0] != memory[0]);
CHECK(module.ReadMemory(&memory[0]) != module.ReadMemory(&memory[0]));
} else {
CHECK_EQ(expected, memory[0]);
CHECK_EQ(expected, module.ReadMemory(&memory[0]));
}
}
}

View File

@ -140,14 +140,22 @@ class TestingModule : public ModuleEnv {
template <typename T>
T raw_mem_at(int i) {
DCHECK(instance->mem_start);
return reinterpret_cast<T*>(instance->mem_start)[i];
return ReadMemory(&(reinterpret_cast<T*>(instance->mem_start)[i]));
}
template <typename T>
T raw_val_at(int i) {
T val;
memcpy(&val, reinterpret_cast<void*>(instance->mem_start + i), sizeof(T));
return val;
return ReadMemory(reinterpret_cast<T*>(instance->mem_start + i));
}
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.