// Copyright 2019 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 "test/wasm-api-tests/wasm-api-test.h" namespace v8 { namespace internal { namespace wasm { using ::wasm::Limits; using ::wasm::MemoryType; TEST_F(WasmCapiTest, Memory) { builder()->SetMinMemorySize(2); builder()->SetMaxMemorySize(3); builder()->AddExport(base::CStrVector("memory"), kExternalMemory, 0); ValueType i32_type[] = {kWasmI32, kWasmI32}; FunctionSig return_i32(1, 0, i32_type); FunctionSig param_i32_return_i32(1, 1, i32_type); FunctionSig param_i32_i32(0, 2, i32_type); uint8_t size_code[] = {WASM_MEMORY_SIZE}; AddExportedFunction(base::CStrVector("size"), size_code, sizeof(size_code), &return_i32); uint8_t load_code[] = {WASM_LOAD_MEM(MachineType::Int8(), WASM_LOCAL_GET(0))}; AddExportedFunction(base::CStrVector("load"), load_code, sizeof(load_code), ¶m_i32_return_i32); uint8_t store_code[] = {WASM_STORE_MEM(MachineType::Int8(), WASM_LOCAL_GET(0), WASM_LOCAL_GET(1))}; AddExportedFunction(base::CStrVector("store"), store_code, sizeof(store_code), ¶m_i32_i32); uint8_t data[] = {0x1, 0x2, 0x3, 0x4}; builder()->AddDataSegment(data, sizeof(data), 0x1000); Instantiate(nullptr); Memory* memory = GetExportedMemory(0); Func* size_func = GetExportedFunction(1); Func* load_func = GetExportedFunction(2); Func* store_func = GetExportedFunction(3); // Try cloning. EXPECT_TRUE(memory->copy()->same(memory)); // Check initial state. EXPECT_EQ(2u, memory->size()); EXPECT_EQ(0x20000u, memory->data_size()); EXPECT_EQ(0, memory->data()[0]); EXPECT_EQ(1, memory->data()[0x1000]); EXPECT_EQ(4, memory->data()[0x1003]); Val args[2]; Val result[1]; // size == 2 size_func->call(nullptr, result); EXPECT_EQ(2, result[0].i32()); // load(0) == 0 args[0] = Val::i32(0x0); load_func->call(args, result); EXPECT_EQ(0, result[0].i32()); // load(0x1000) == 1 args[0] = Val::i32(0x1000); load_func->call(args, result); EXPECT_EQ(1, result[0].i32()); // load(0x1003) == 4 args[0] = Val::i32(0x1003); load_func->call(args, result); EXPECT_EQ(4, result[0].i32()); // load(0x1FFFF) == 0 args[0] = Val::i32(0x1FFFF); load_func->call(args, result); EXPECT_EQ(0, result[0].i32()); // load(0x20000) -> trap args[0] = Val::i32(0x20000); own trap = load_func->call(args, result); EXPECT_NE(nullptr, trap.get()); // Mutate memory. memory->data()[0x1003] = 5; args[0] = Val::i32(0x1002); args[1] = Val::i32(6); trap = store_func->call(args, nullptr); EXPECT_EQ(nullptr, trap.get()); args[0] = Val::i32(0x20000); trap = store_func->call(args, nullptr); EXPECT_NE(nullptr, trap.get()); EXPECT_EQ(6, memory->data()[0x1002]); EXPECT_EQ(5, memory->data()[0x1003]); args[0] = Val::i32(0x1002); load_func->call(args, result); EXPECT_EQ(6, result[0].i32()); args[0] = Val::i32(0x1003); load_func->call(args, result); EXPECT_EQ(5, result[0].i32()); // Grow memory. EXPECT_EQ(true, memory->grow(1)); EXPECT_EQ(3u, memory->size()); EXPECT_EQ(0x30000u, memory->data_size()); args[0] = Val::i32(0x20000); trap = load_func->call(args, result); EXPECT_EQ(nullptr, trap.get()); EXPECT_EQ(0, result[0].i32()); trap = store_func->call(args, nullptr); EXPECT_EQ(nullptr, trap.get()); args[0] = Val::i32(0x30000); trap = load_func->call(args, result); EXPECT_NE(nullptr, trap.get()); trap = store_func->call(args, nullptr); EXPECT_NE(nullptr, trap.get()); EXPECT_EQ(false, memory->grow(1)); EXPECT_EQ(true, memory->grow(0)); // Create standalone memory. // TODO(wasm): Once Wasm allows multiple memories, turn this into an import. own mem_type = MemoryType::make(Limits(5, 5)); own memory2 = Memory::make(store(), mem_type.get()); EXPECT_EQ(5u, memory2->size()); EXPECT_EQ(false, memory2->grow(1)); EXPECT_EQ(true, memory2->grow(0)); } } // namespace wasm } // namespace internal } // namespace v8