Implement Wasm GrowMemory opcode as a wasm runtime call
- GrowMemory runtime function, tests added to checks if memory can be grown and relocation information is updated correctly R=titzer@chromium.org, bradnelson@chromium.org Review-Url: https://codereview.chromium.org/2051043002 Cr-Commit-Position: refs/heads/master@{#37338}
This commit is contained in:
parent
3325de6d68
commit
ef2f33d6c6
1
BUILD.gn
1
BUILD.gn
@ -1408,6 +1408,7 @@ v8_source_set("v8_base") {
|
||||
"src/runtime/runtime-test.cc",
|
||||
"src/runtime/runtime-typedarray.cc",
|
||||
"src/runtime/runtime-utils.h",
|
||||
"src/runtime/runtime-wasm.cc",
|
||||
"src/runtime/runtime.cc",
|
||||
"src/runtime/runtime.h",
|
||||
"src/safepoint-table.cc",
|
||||
|
@ -881,6 +881,8 @@ Node* WasmGraphBuilder::Unop(wasm::WasmOpcode opcode, Node* input,
|
||||
return BuildI64UConvertF32(input, position);
|
||||
case wasm::kExprI64UConvertF64:
|
||||
return BuildI64UConvertF64(input, position);
|
||||
case wasm::kExprGrowMemory:
|
||||
return BuildGrowMemory(input);
|
||||
case wasm::kExprI32AsmjsLoadMem8S:
|
||||
return BuildAsmjsLoadMem(MachineType::Int8(), input);
|
||||
case wasm::kExprI32AsmjsLoadMem8U:
|
||||
@ -1571,6 +1573,32 @@ Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction(
|
||||
return load;
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::BuildGrowMemory(Node* input) {
|
||||
Runtime::FunctionId function_id = Runtime::kWasmGrowMemory;
|
||||
const Runtime::Function* function = Runtime::FunctionForId(function_id);
|
||||
CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
|
||||
jsgraph()->zone(), function_id, function->nargs, Operator::kNoProperties,
|
||||
CallDescriptor::kNoFlags);
|
||||
Node** control_ptr = control_;
|
||||
Node** effect_ptr = effect_;
|
||||
wasm::ModuleEnv* module = module_;
|
||||
input = BuildChangeUint32ToSmi(input);
|
||||
Node* inputs[] = {
|
||||
jsgraph()->CEntryStubConstant(function->result_size), input, // C entry
|
||||
jsgraph()->ExternalConstant(
|
||||
ExternalReference(function_id, jsgraph()->isolate())), // ref
|
||||
jsgraph()->Int32Constant(function->nargs), // arity
|
||||
jsgraph()->HeapConstant(module->instance->context), // context
|
||||
*effect_ptr,
|
||||
*control_ptr};
|
||||
Node* node = graph()->NewNode(jsgraph()->common()->Call(desc),
|
||||
static_cast<int>(arraysize(inputs)), inputs);
|
||||
*control_ptr = node;
|
||||
*effect_ptr = node;
|
||||
node = BuildChangeSmiToInt32(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right,
|
||||
wasm::WasmCodePosition position) {
|
||||
MachineOperatorBuilder* m = jsgraph()->machine();
|
||||
@ -2283,6 +2311,15 @@ Node* WasmGraphBuilder::BuildChangeSmiToInt32(Node* value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::BuildChangeUint32ToSmi(Node* value) {
|
||||
if (jsgraph()->machine()->Is64()) {
|
||||
value =
|
||||
graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), value);
|
||||
}
|
||||
return graph()->NewNode(jsgraph()->machine()->WordShl(), value,
|
||||
BuildSmiShiftBitsConstant());
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::BuildChangeSmiToFloat64(Node* value) {
|
||||
return graph()->NewNode(jsgraph()->machine()->ChangeInt32ToFloat64(),
|
||||
BuildChangeSmiToInt32(value));
|
||||
@ -2588,7 +2625,6 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
|
||||
jsgraph()->RelocatableInt32Constant(
|
||||
static_cast<uint32_t>(effective_size),
|
||||
RelocInfo::WASM_MEMORY_SIZE_REFERENCE));
|
||||
|
||||
trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
|
||||
}
|
||||
|
||||
|
@ -317,6 +317,7 @@ class WasmGraphBuilder {
|
||||
|
||||
Node* BuildChangeInt32ToSmi(Node* value);
|
||||
Node* BuildChangeSmiToInt32(Node* value);
|
||||
Node* BuildChangeUint32ToSmi(Node* value);
|
||||
Node* BuildChangeSmiToFloat64(Node* value);
|
||||
Node* BuildTestNotSmi(Node* value);
|
||||
Node* BuildSmiShiftBitsConstant();
|
||||
@ -324,6 +325,7 @@ class WasmGraphBuilder {
|
||||
Node* BuildAllocateHeapNumberWithValue(Node* value, Node* control);
|
||||
Node* BuildLoadHeapNumberValue(Node* value, Node* control);
|
||||
Node* BuildHeapNumberValueIndexConstant();
|
||||
Node* BuildGrowMemory(Node* input);
|
||||
|
||||
// Asm.js specific functionality.
|
||||
Node* BuildI32AsmjsSConvertF32(Node* input);
|
||||
|
@ -489,7 +489,8 @@ class CallSite {
|
||||
T(WasmTrapRemByZero, "remainder by zero") \
|
||||
T(WasmTrapFloatUnrepresentable, "integer result unrepresentable") \
|
||||
T(WasmTrapFuncInvalid, "invalid function") \
|
||||
T(WasmTrapFuncSigMismatch, "function signature mismatch")
|
||||
T(WasmTrapFuncSigMismatch, "function signature mismatch") \
|
||||
T(WasmTrapMemAllocationFail, "failed to allocate memory")
|
||||
|
||||
class MessageTemplate {
|
||||
public:
|
||||
|
104
src/runtime/runtime-wasm.cc
Normal file
104
src/runtime/runtime-wasm.cc
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/runtime/runtime-utils.h"
|
||||
|
||||
#include "src/arguments.h"
|
||||
#include "src/assembler.h"
|
||||
#include "src/conversions.h"
|
||||
#include "src/debug/debug.h"
|
||||
#include "src/factory.h"
|
||||
#include "src/frames-inl.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/v8memory.h"
|
||||
#include "src/wasm/wasm-module.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
uint32_t delta_pages = 0;
|
||||
RUNTIME_ASSERT(args[0]->ToUint32(&delta_pages));
|
||||
|
||||
// Get the module JSObject
|
||||
const Address entry = Isolate::c_entry_fp(isolate->thread_local_top());
|
||||
Address pc =
|
||||
Memory::Address_at(entry + StandardFrameConstants::kCallerPCOffset);
|
||||
Code* code = isolate->inner_pointer_to_code_cache()->GetCacheEntry(pc)->code;
|
||||
FixedArray* deopt_data = code->deoptimization_data();
|
||||
DCHECK(deopt_data->length() == 2);
|
||||
JSObject* module_object = JSObject::cast(deopt_data->get(0));
|
||||
RUNTIME_ASSERT(!module_object->IsNull(isolate));
|
||||
|
||||
Address old_mem_start, new_mem_start;
|
||||
uint32_t old_size, new_size;
|
||||
const int kWasmMemArrayBuffer = 2;
|
||||
|
||||
// Get mem buffer associated with module object
|
||||
Object* obj = module_object->GetInternalField(kWasmMemArrayBuffer);
|
||||
Handle<JSArrayBuffer> old_buffer =
|
||||
Handle<JSArrayBuffer>(JSArrayBuffer::cast(obj));
|
||||
|
||||
if (old_buffer->byte_length()->Number() == 0) {
|
||||
// If module object does not have linear memory associated with it,
|
||||
// Allocate new array buffer of given size.
|
||||
old_mem_start = static_cast<Address>(old_buffer->backing_store());
|
||||
old_size = 0;
|
||||
// TODO(gdeepti): Fix bounds check to take into account size of memtype.
|
||||
new_size = delta_pages * wasm::WasmModule::kPageSize;
|
||||
if (delta_pages > wasm::WasmModule::kMaxMemPages) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewRangeError(MessageTemplate::kWasmTrapMemOutOfBounds));
|
||||
}
|
||||
new_mem_start =
|
||||
static_cast<Address>(isolate->array_buffer_allocator()->Allocate(
|
||||
static_cast<uint32_t>(new_size)));
|
||||
if (new_mem_start == NULL) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewRangeError(MessageTemplate::kWasmTrapMemAllocationFail));
|
||||
}
|
||||
#if DEBUG
|
||||
// Double check the API allocator actually zero-initialized the memory.
|
||||
for (size_t i = old_size; i < new_size; i++) {
|
||||
DCHECK_EQ(0, new_mem_start[i]);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
old_mem_start = static_cast<Address>(old_buffer->backing_store());
|
||||
old_size = old_buffer->byte_length()->Number();
|
||||
new_size = old_size + delta_pages * wasm::WasmModule::kPageSize;
|
||||
if (new_size >
|
||||
wasm::WasmModule::kMaxMemPages * wasm::WasmModule::kPageSize) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewRangeError(MessageTemplate::kWasmTrapMemOutOfBounds));
|
||||
}
|
||||
new_mem_start = static_cast<Address>(realloc(old_mem_start, new_size));
|
||||
if (new_mem_start == NULL) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewRangeError(MessageTemplate::kWasmTrapMemAllocationFail));
|
||||
}
|
||||
old_buffer->set_is_external(true);
|
||||
isolate->heap()->UnregisterArrayBuffer(*old_buffer);
|
||||
// Zero initializing uninitialized memory from realloc
|
||||
memset(new_mem_start + old_size, 0, new_size - old_size);
|
||||
}
|
||||
|
||||
Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
|
||||
JSArrayBuffer::Setup(buffer, isolate, false, new_mem_start, new_size);
|
||||
buffer->set_is_neuterable(false);
|
||||
|
||||
// Set new buffer to be wasm memory
|
||||
module_object->SetInternalField(kWasmMemArrayBuffer, *buffer);
|
||||
|
||||
RUNTIME_ASSERT(wasm::UpdateWasmModuleMemory(
|
||||
module_object, old_mem_start, new_mem_start, old_size, new_size));
|
||||
|
||||
return *isolate->factory()->NewNumberFromUint(old_size /
|
||||
wasm::WasmModule::kPageSize);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -926,6 +926,7 @@ namespace internal {
|
||||
F(DataViewSetFloat32, 4, 1) \
|
||||
F(DataViewSetFloat64, 4, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_WASM(F) F(WasmGrowMemory, 1, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_RETURN_PAIR(F) \
|
||||
F(LoadLookupSlotForCall, 1, 2)
|
||||
@ -989,7 +990,8 @@ namespace internal {
|
||||
FOR_EACH_INTRINSIC_STRINGS(F) \
|
||||
FOR_EACH_INTRINSIC_SYMBOL(F) \
|
||||
FOR_EACH_INTRINSIC_TEST(F) \
|
||||
FOR_EACH_INTRINSIC_TYPEDARRAY(F)
|
||||
FOR_EACH_INTRINSIC_TYPEDARRAY(F) \
|
||||
FOR_EACH_INTRINSIC_WASM(F)
|
||||
|
||||
// FOR_EACH_INTRINSIC defines the list of all intrinsics, coming in 2 flavors,
|
||||
// either returning an object or a pair.
|
||||
|
@ -1079,6 +1079,7 @@
|
||||
'runtime/runtime-test.cc',
|
||||
'runtime/runtime-typedarray.cc',
|
||||
'runtime/runtime-utils.h',
|
||||
'runtime/runtime-wasm.cc',
|
||||
'runtime/runtime.cc',
|
||||
'runtime/runtime.h',
|
||||
'safepoint-table.cc',
|
||||
|
@ -331,6 +331,7 @@ class WasmDecoder : public Decoder {
|
||||
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE)
|
||||
FOREACH_MISC_MEM_OPCODE(DECLARE_OPCODE_CASE)
|
||||
FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE)
|
||||
FOREACH_SIMPLE_MEM_OPCODE(DECLARE_OPCODE_CASE)
|
||||
FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE)
|
||||
FOREACH_SIMD_OPCODE(DECLARE_OPCODE_CASE)
|
||||
#undef DECLARE_OPCODE_CASE
|
||||
@ -995,12 +996,6 @@ class SR_WasmDecoder : public WasmDecoder {
|
||||
case kExprMemorySize:
|
||||
Push(kAstI32, BUILD(MemSize, 0));
|
||||
break;
|
||||
case kExprGrowMemory: {
|
||||
Value val = Pop(0, kAstI32);
|
||||
USE(val); // TODO(titzer): build node for grow memory
|
||||
Push(kAstI32, BUILD(Int32Constant, 0));
|
||||
break;
|
||||
}
|
||||
case kExprCallFunction: {
|
||||
CallFunctionOperand operand(this, pc_);
|
||||
if (Validate(pc_, operand)) {
|
||||
|
@ -1026,6 +1026,37 @@ WasmDebugInfo* GetDebugInfo(JSObject* wasm) {
|
||||
return *new_info;
|
||||
}
|
||||
|
||||
bool UpdateWasmModuleMemory(JSObject* object, Address old_start,
|
||||
Address new_start, uint32_t old_size,
|
||||
uint32_t new_size) {
|
||||
if (!IsWasmObject(object)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get code table associated with the module js_object
|
||||
Object* obj = object->GetInternalField(kWasmModuleCodeTable);
|
||||
Handle<FixedArray> code_table(FixedArray::cast(obj));
|
||||
|
||||
// Iterate through the code objects in the code table and update relocation
|
||||
// information
|
||||
for (int i = 0; i < code_table->length(); i++) {
|
||||
obj = code_table->get(i);
|
||||
Handle<Code> code(Code::cast(obj));
|
||||
|
||||
int mode_mask = RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_REFERENCE) |
|
||||
RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
|
||||
for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
|
||||
RelocInfo::Mode mode = it.rinfo()->rmode();
|
||||
if (RelocInfo::IsWasmMemoryReference(mode) ||
|
||||
RelocInfo::IsWasmMemorySizeReference(mode)) {
|
||||
it.rinfo()->update_wasm_memory_reference(old_start, new_start, old_size,
|
||||
new_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace testing {
|
||||
|
||||
int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
|
||||
|
@ -361,6 +361,11 @@ WasmDebugInfo* GetDebugInfo(JSObject* wasm);
|
||||
// else.
|
||||
bool IsWasmObject(Object* object);
|
||||
|
||||
// Update memory references of code objects associated with the module
|
||||
bool UpdateWasmModuleMemory(JSObject* object, Address old_start,
|
||||
Address new_start, uint32_t old_size,
|
||||
uint32_t new_size);
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Decode, verify, and run the function labeled "main" in the
|
||||
@ -369,7 +374,6 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
|
||||
const byte* module_end, bool asm_js = false);
|
||||
|
||||
} // namespace testing
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -75,6 +75,7 @@ static void InitSigTable() {
|
||||
#define SET_SIG_TABLE(name, opcode, sig) \
|
||||
kSimpleExprSigTable[opcode] = static_cast<int>(kSigEnum_##sig) + 1;
|
||||
FOREACH_SIMPLE_OPCODE(SET_SIG_TABLE);
|
||||
FOREACH_SIMPLE_MEM_OPCODE(SET_SIG_TABLE);
|
||||
FOREACH_ASMJS_COMPAT_OPCODE(SET_SIG_TABLE);
|
||||
#undef SET_SIG_TABLE
|
||||
}
|
||||
|
@ -116,9 +116,10 @@ const WasmCodePosition kNoCodePosition = -1;
|
||||
V(F32StoreMem, 0x35, f_if) \
|
||||
V(F64StoreMem, 0x36, d_id)
|
||||
|
||||
#define FOREACH_SIMPLE_MEM_OPCODE(V) V(GrowMemory, 0x39, i_i)
|
||||
|
||||
// Load memory expressions.
|
||||
#define FOREACH_MISC_MEM_OPCODE(V) \
|
||||
V(GrowMemory, 0x39, i_i) \
|
||||
V(MemorySize, 0x3b, i_v)
|
||||
|
||||
// Expressions with signatures.
|
||||
@ -410,6 +411,7 @@ const WasmCodePosition kNoCodePosition = -1;
|
||||
FOREACH_CONTROL_OPCODE(V) \
|
||||
FOREACH_MISC_OPCODE(V) \
|
||||
FOREACH_SIMPLE_OPCODE(V) \
|
||||
FOREACH_SIMPLE_MEM_OPCODE(V) \
|
||||
FOREACH_STORE_MEM_OPCODE(V) \
|
||||
FOREACH_LOAD_MEM_OPCODE(V) \
|
||||
FOREACH_MISC_MEM_OPCODE(V) \
|
||||
@ -468,14 +470,15 @@ enum WasmOpcode {
|
||||
|
||||
// The reason for a trap.
|
||||
#define FOREACH_WASM_TRAPREASON(V) \
|
||||
V(TrapUnreachable) \
|
||||
V(TrapMemOutOfBounds) \
|
||||
V(TrapDivByZero) \
|
||||
V(TrapDivUnrepresentable) \
|
||||
V(TrapRemByZero) \
|
||||
V(TrapFloatUnrepresentable) \
|
||||
V(TrapFuncInvalid) \
|
||||
V(TrapFuncSigMismatch)
|
||||
V(TrapUnreachable) \
|
||||
V(TrapMemOutOfBounds) \
|
||||
V(TrapDivByZero) \
|
||||
V(TrapDivUnrepresentable) \
|
||||
V(TrapRemByZero) \
|
||||
V(TrapFloatUnrepresentable) \
|
||||
V(TrapFuncInvalid) \
|
||||
V(TrapFuncSigMismatch) \
|
||||
V(TrapMemAllocationFail)
|
||||
|
||||
enum TrapReason {
|
||||
#define DECLARE_ENUM(name) k##name,
|
||||
|
@ -886,6 +886,11 @@
|
||||
'es6/tail-call-megatest*': [SKIP],
|
||||
}], # (ignition or ignition_turbofan) and msan
|
||||
|
||||
['system == windows and arch == ia32', {
|
||||
# TODO(gdeepti): Flaky on multiple runs, windows nosnap crashes
|
||||
'wasm/grow-memory': [SKIP],
|
||||
}], # 'system == windows'
|
||||
|
||||
##############################################################################
|
||||
['gcov_coverage', {
|
||||
# Tests taking too long.
|
||||
|
137
test/mjsunit/wasm/grow-memory.js
Normal file
137
test/mjsunit/wasm/grow-memory.js
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --expose-wasm --expose-gc --stress-compaction
|
||||
|
||||
load("test/mjsunit/wasm/wasm-constants.js");
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
var kPageSize = 0x10000;
|
||||
|
||||
function genGrowMemoryBuilder() {
|
||||
var builder = new WasmModuleBuilder();
|
||||
builder.addFunction("grow_memory", kSig_i_i)
|
||||
.addBody([kExprGetLocal, 0, kExprGrowMemory])
|
||||
.exportFunc();
|
||||
builder.addFunction("load", kSig_i_i)
|
||||
.addBody([kExprGetLocal, 0, kExprI32LoadMem, 0, 0])
|
||||
.exportFunc();
|
||||
builder.addFunction("store", kSig_i_ii)
|
||||
.addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprI32StoreMem, 0, 0])
|
||||
.exportFunc();
|
||||
return builder;
|
||||
}
|
||||
|
||||
function testGrowMemoryReadWrite() {
|
||||
var builder = genGrowMemoryBuilder();
|
||||
builder.addMemory(1, 1, false);
|
||||
var module = builder.instantiate();
|
||||
var offset;
|
||||
function peek() { return module.exports.load(offset); }
|
||||
function poke(value) { return module.exports.store(offset, value); }
|
||||
function growMem(pages) { return module.exports.grow_memory(pages); }
|
||||
|
||||
for(offset = 0; offset <= (kPageSize - 4); offset++) {
|
||||
poke(20);
|
||||
assertEquals(peek(), 20);
|
||||
}
|
||||
for (offset = kPageSize - 3; offset < kPageSize + 4; offset++) {
|
||||
assertTraps(kTrapMemOutOfBounds, poke);
|
||||
assertTraps(kTrapMemOutOfBounds, peek);
|
||||
}
|
||||
|
||||
try {
|
||||
assertEquals(growMem(3), 1);
|
||||
} catch (e) {
|
||||
assertEquals("object", typeof e);
|
||||
assertEquals(e.message, kTrapMsgs[kTrapMemAllocationFail]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (offset = kPageSize; offset <= 4*kPageSize -4; offset++) {
|
||||
poke(20);
|
||||
assertEquals(peek(), 20);
|
||||
}
|
||||
for (offset = 4*kPageSize - 3; offset < 4*kPageSize + 4; offset++) {
|
||||
assertTraps(kTrapMemOutOfBounds, poke);
|
||||
assertTraps(kTrapMemOutOfBounds, peek);
|
||||
}
|
||||
|
||||
try {
|
||||
assertEquals(growMem(15), 4);
|
||||
} catch (e) {
|
||||
assertEquals("object", typeof e);
|
||||
assertEquals(e.message, kTrapMsgs[kTrapMemAllocationFail]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (offset = 4*kPageSize - 3; offset <= 4*kPageSize + 4; offset++) {
|
||||
poke(20);
|
||||
assertEquals(peek(), 20);
|
||||
}
|
||||
for (offset = 19*kPageSize - 10; offset <= 19*kPageSize - 4; offset++) {
|
||||
poke(20);
|
||||
assertEquals(peek(), 20);
|
||||
}
|
||||
for (offset = 19*kPageSize - 3; offset < 19*kPageSize + 5; offset++) {
|
||||
assertTraps(kTrapMemOutOfBounds, poke);
|
||||
assertTraps(kTrapMemOutOfBounds, peek);
|
||||
}
|
||||
}
|
||||
|
||||
testGrowMemoryReadWrite();
|
||||
|
||||
function testGrowMemoryZeroInitialSize() {
|
||||
var builder = genGrowMemoryBuilder();
|
||||
var module = builder.instantiate();
|
||||
var offset;
|
||||
function peek() { return module.exports.load(offset); }
|
||||
function poke(value) { return module.exports.store(offset, value); }
|
||||
function growMem(pages) { return module.exports.grow_memory(pages); }
|
||||
|
||||
assertTraps(kTrapMemOutOfBounds, peek);
|
||||
assertTraps(kTrapMemOutOfBounds, poke);
|
||||
|
||||
try {
|
||||
assertEquals(growMem(1), 0);
|
||||
} catch (e) {
|
||||
assertEquals("object", typeof e);
|
||||
assertEquals(e.message, kTrapMsgs[kTrapMemAllocationFail]);
|
||||
return;
|
||||
}
|
||||
|
||||
for(offset = 0; offset <= kPageSize - 4; offset++) {
|
||||
poke(20);
|
||||
assertEquals(peek(), 20);
|
||||
}
|
||||
|
||||
//TODO(gdeepti): Fix tests with correct write boundaries
|
||||
//when runtime function is fixed.
|
||||
for(offset = kPageSize; offset <= kPageSize + 5; offset++) {
|
||||
assertTraps(kTrapMemOutOfBounds, peek);
|
||||
}
|
||||
}
|
||||
|
||||
testGrowMemoryZeroInitialSize();
|
||||
|
||||
function testGrowMemoryTrapMaxPagesZeroInitialMemory() {
|
||||
var builder = genGrowMemoryBuilder();
|
||||
var module = builder.instantiate();
|
||||
var maxPages = 16385;
|
||||
function growMem() { return module.exports.grow_memory(maxPages); }
|
||||
assertTraps(kTrapMemOutOfBounds, growMem);
|
||||
}
|
||||
|
||||
testGrowMemoryTrapMaxPagesZeroInitialMemory();
|
||||
|
||||
function testGrowMemoryTrapMaxPages() {
|
||||
var builder = genGrowMemoryBuilder();
|
||||
builder.addMemory(1, 1, false);
|
||||
var module = builder.instantiate();
|
||||
var maxPages = 16384;
|
||||
function growMem() { return module.exports.grow_memory(maxPages); }
|
||||
assertTraps(kTrapMemOutOfBounds, growMem);
|
||||
}
|
||||
|
||||
testGrowMemoryTrapMaxPages();
|
@ -312,6 +312,7 @@ var kTrapRemByZero = 4;
|
||||
var kTrapFloatUnrepresentable = 5;
|
||||
var kTrapFuncInvalid = 6;
|
||||
var kTrapFuncSigMismatch = 7;
|
||||
var kTrapMemAllocationFail = 8;
|
||||
|
||||
var kTrapMsgs = [
|
||||
"unreachable",
|
||||
@ -321,7 +322,8 @@ var kTrapMsgs = [
|
||||
"remainder by zero",
|
||||
"integer result unrepresentable",
|
||||
"invalid function",
|
||||
"function signature mismatch"
|
||||
"function signature mismatch",
|
||||
"failed to allocate memory"
|
||||
];
|
||||
|
||||
function assertTraps(trap, code) {
|
||||
|
Loading…
Reference in New Issue
Block a user