[wasm] Call a runtime function for a MemorySize instruction.
The implementation of MemorySize with RelocatableInt32Constants is problematic if MemorySize is placed close to a GrowMemory instruction in the code. The use of a runtime function guarantees that the order in which MemorySize and GrowMemory is executed is correct. R=titzer@chromium.org BUG=chromium:651961 TEST=mjsunit/regress/wasm/regression-651961 Committed: https://crrev.com/2c12a9a42d454a36fcd2931fa458d72832eeb689 Review-Url: https://codereview.chromium.org/2386183004 Cr-Original-Commit-Position: refs/heads/master@{#39972} Cr-Commit-Position: refs/heads/master@{#39980}
This commit is contained in:
parent
9c3d08f972
commit
aa93e6ca95
@ -2759,8 +2759,27 @@ Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::CurrentMemoryPages() {
|
||||
return graph()->NewNode(jsgraph()->machine()->Word32Shr(), MemSize(0),
|
||||
jsgraph()->Int32Constant(16));
|
||||
Runtime::FunctionId function_id = Runtime::kWasmMemorySize;
|
||||
const Runtime::Function* function = Runtime::FunctionForId(function_id);
|
||||
CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
|
||||
jsgraph()->zone(), function_id, function->nargs, Operator::kNoThrow,
|
||||
CallDescriptor::kNoFlags);
|
||||
wasm::ModuleEnv* module = module_;
|
||||
Node* inputs[] = {
|
||||
jsgraph()->CEntryStubConstant(function->result_size), // C entry
|
||||
jsgraph()->ExternalConstant(
|
||||
ExternalReference(function_id, jsgraph()->isolate())), // ref
|
||||
jsgraph()->Int32Constant(function->nargs), // arity
|
||||
jsgraph()->HeapConstant(module->instance->context), // context
|
||||
*effect_,
|
||||
*control_};
|
||||
Node* call = graph()->NewNode(jsgraph()->common()->Call(desc),
|
||||
static_cast<int>(arraysize(inputs)), inputs);
|
||||
|
||||
Node* result = BuildChangeSmiToInt32(call);
|
||||
|
||||
*effect_ = call;
|
||||
return result;
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::MemSize(uint32_t offset) {
|
||||
|
@ -18,6 +18,27 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_WasmMemorySize) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(0, args.length());
|
||||
|
||||
Handle<JSObject> module_instance;
|
||||
{
|
||||
// Get the module JSObject
|
||||
DisallowHeapAllocation no_allocation;
|
||||
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;
|
||||
Object* owning_instance = wasm::GetOwningWasmInstance(code);
|
||||
CHECK_NOT_NULL(owning_instance);
|
||||
module_instance = handle(JSObject::cast(owning_instance), isolate);
|
||||
}
|
||||
return *isolate->factory()->NewNumberFromInt(
|
||||
wasm::GetInstanceMemorySize(isolate, module_instance));
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
|
@ -917,6 +917,7 @@ namespace internal {
|
||||
|
||||
#define FOR_EACH_INTRINSIC_WASM(F) \
|
||||
F(WasmGrowMemory, 1, 1) \
|
||||
F(WasmMemorySize, 0, 1) \
|
||||
F(WasmThrowTypeError, 0, 1) \
|
||||
F(WasmThrow, 2, 1) \
|
||||
F(WasmGetCaughtExceptionValue, 1, 1)
|
||||
|
@ -1809,6 +1809,17 @@ void SetInstanceMemory(Handle<JSObject> instance, JSArrayBuffer* buffer) {
|
||||
module->set_ptr_to_heap(buffer);
|
||||
}
|
||||
|
||||
int32_t GetInstanceMemorySize(Isolate* isolate, Handle<JSObject> instance) {
|
||||
MaybeHandle<JSArrayBuffer> maybe_mem_buffer =
|
||||
GetInstanceMemory(isolate, instance);
|
||||
Handle<JSArrayBuffer> buffer;
|
||||
if (!maybe_mem_buffer.ToHandle(&buffer)) {
|
||||
return 0;
|
||||
} else {
|
||||
return buffer->byte_length()->Number() / WasmModule::kPageSize;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t GrowInstanceMemory(Isolate* isolate, Handle<JSObject> instance,
|
||||
uint32_t pages) {
|
||||
Address old_mem_start = nullptr;
|
||||
|
@ -534,6 +534,8 @@ uint32_t GetNumImportedFunctions(Handle<JSObject> wasm_object);
|
||||
// Returns nullptr on failing to get owning instance.
|
||||
Object* GetOwningWasmInstance(Code* code);
|
||||
|
||||
int32_t GetInstanceMemorySize(Isolate* isolate, Handle<JSObject> instance);
|
||||
|
||||
int32_t GrowInstanceMemory(Isolate* isolate, Handle<JSObject> instance,
|
||||
uint32_t pages);
|
||||
|
||||
|
@ -253,6 +253,21 @@ TEST(Run_WasmModule_Serialization) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MemorySize) {
|
||||
// Initial memory size is 16, see wasm-module-builder.cc
|
||||
static const int kExpectedValue = 16;
|
||||
TestSignatures sigs;
|
||||
v8::internal::AccountingAllocator allocator;
|
||||
Zone zone(&allocator);
|
||||
|
||||
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
||||
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
||||
ExportAsMain(f);
|
||||
byte code[] = {WASM_MEMORY_SIZE};
|
||||
f->EmitCode(code, sizeof(code));
|
||||
TestModule(&zone, builder, kExpectedValue);
|
||||
}
|
||||
|
||||
TEST(Run_WasmModule_MemSize_GrowMem) {
|
||||
// Initial memory size = 16 + GrowMemory(10)
|
||||
static const int kExpectedValue = 26;
|
||||
|
@ -79,22 +79,6 @@ WASM_EXEC_TEST(Int32Const_many) {
|
||||
}
|
||||
}
|
||||
|
||||
WASM_EXEC_TEST(MemorySize1) {
|
||||
TestingModule module(execution_mode);
|
||||
WasmRunner<int32_t> r(&module);
|
||||
module.AddMemory(WasmModule::kPageSize * 1);
|
||||
BUILD(r, kExprMemorySize);
|
||||
CHECK_EQ(1, r.Call());
|
||||
}
|
||||
|
||||
WASM_EXEC_TEST(MemorySize2) {
|
||||
TestingModule module(execution_mode);
|
||||
WasmRunner<int32_t> r(&module);
|
||||
module.AddMemory(WasmModule::kPageSize * 3);
|
||||
BUILD(r, kExprMemorySize);
|
||||
CHECK_EQ(3, r.Call());
|
||||
}
|
||||
|
||||
WASM_EXEC_TEST(Int32Param0) {
|
||||
WasmRunner<int32_t> r(execution_mode, MachineType::Int32());
|
||||
// return(local[0])
|
||||
|
24
test/mjsunit/regress/wasm/regression-651961.js
Normal file
24
test/mjsunit/regress/wasm/regression-651961.js
Normal file
@ -0,0 +1,24 @@
|
||||
// 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
|
||||
|
||||
load("test/mjsunit/wasm/wasm-constants.js");
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
(function() {
|
||||
var builder = new WasmModuleBuilder();
|
||||
builder.addMemory(1, 1, false);
|
||||
builder.addFunction("foo", kSig_i_v)
|
||||
.addBody([
|
||||
kExprMemorySize,
|
||||
kExprI32Const, 0x10,
|
||||
kExprGrowMemory,
|
||||
kExprI32Mul,
|
||||
])
|
||||
.exportFunc();
|
||||
var module = builder.instantiate();
|
||||
var result = module.exports.foo();
|
||||
assertEquals(1, result);
|
||||
})();
|
30
test/mjsunit/wasm/memory-size.js
Normal file
30
test/mjsunit/wasm/memory-size.js
Normal file
@ -0,0 +1,30 @@
|
||||
// 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
|
||||
|
||||
load("test/mjsunit/wasm/wasm-constants.js");
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
(function testMemorySizeZero() {
|
||||
print("testMemorySizeZero()");
|
||||
var builder = new WasmModuleBuilder();
|
||||
builder.addFunction("memory_size", kSig_i_v)
|
||||
.addBody([kExprMemorySize])
|
||||
.exportFunc();
|
||||
var module = builder.instantiate();
|
||||
assertEquals(0, module.exports.memory_size());
|
||||
})();
|
||||
|
||||
(function testMemorySizeNonZero() {
|
||||
print("testMemorySizeNonZero()");
|
||||
var builder = new WasmModuleBuilder();
|
||||
var size = 11;
|
||||
builder.addMemory(size, size, false);
|
||||
builder.addFunction("memory_size", kSig_i_v)
|
||||
.addBody([kExprMemorySize])
|
||||
.exportFunc();
|
||||
var module = builder.instantiate();
|
||||
assertEquals(size, module.exports.memory_size());
|
||||
})();
|
Loading…
Reference in New Issue
Block a user