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:
parent
43a10a0c4a
commit
d3f3f6c818
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
27
src/utils.h
27
src/utils.h
@ -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
|
||||
|
||||
|
@ -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_}.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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', {
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user