2015-12-11 12:26:16 +00:00
|
|
|
// Copyright 2015 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 <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2016-10-14 14:24:59 +00:00
|
|
|
#include "src/snapshot/code-serializer.h"
|
|
|
|
#include "src/version.h"
|
2016-08-16 08:07:11 +00:00
|
|
|
#include "src/wasm/module-decoder.h"
|
2015-12-11 12:26:16 +00:00
|
|
|
#include "src/wasm/wasm-macro-gen.h"
|
2016-09-29 11:29:05 +00:00
|
|
|
#include "src/wasm/wasm-module-builder.h"
|
2015-12-11 12:26:16 +00:00
|
|
|
#include "src/wasm/wasm-module.h"
|
2016-11-11 11:12:31 +00:00
|
|
|
#include "src/wasm/wasm-objects.h"
|
2015-12-11 12:26:16 +00:00
|
|
|
#include "src/wasm/wasm-opcodes.h"
|
|
|
|
|
|
|
|
#include "test/cctest/cctest.h"
|
2016-10-05 11:59:47 +00:00
|
|
|
#include "test/common/wasm/test-signatures.h"
|
2016-09-14 10:31:23 +00:00
|
|
|
#include "test/common/wasm/wasm-module-runner.h"
|
2015-12-11 12:26:16 +00:00
|
|
|
|
|
|
|
using namespace v8::base;
|
|
|
|
using namespace v8::internal;
|
|
|
|
using namespace v8::internal::compiler;
|
|
|
|
using namespace v8::internal::wasm;
|
|
|
|
|
|
|
|
namespace {
|
2016-11-08 10:33:42 +00:00
|
|
|
void Cleanup(Isolate* isolate = nullptr) {
|
|
|
|
// By sending a low memory notifications, we will try hard to collect all
|
|
|
|
// garbage and will therefore also invoke all weak callbacks of actually
|
|
|
|
// unreachable persistent handles.
|
|
|
|
if (!isolate) {
|
|
|
|
isolate = CcTest::InitIsolateOnce();
|
|
|
|
}
|
|
|
|
reinterpret_cast<v8::Isolate*>(isolate)->LowMemoryNotification();
|
|
|
|
}
|
|
|
|
|
2016-05-25 16:12:09 +00:00
|
|
|
void TestModule(Zone* zone, WasmModuleBuilder* builder,
|
|
|
|
int32_t expected_result) {
|
|
|
|
ZoneBuffer buffer(zone);
|
2016-05-27 12:15:23 +00:00
|
|
|
builder->WriteTo(buffer);
|
2016-05-25 16:12:09 +00:00
|
|
|
|
2015-12-11 12:26:16 +00:00
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
2016-01-18 15:39:05 +00:00
|
|
|
HandleScope scope(isolate);
|
2016-09-17 01:30:09 +00:00
|
|
|
testing::SetupIsolateForWasmModule(isolate);
|
2016-09-12 22:11:12 +00:00
|
|
|
int32_t result = testing::CompileAndRunWasmModule(
|
|
|
|
isolate, buffer.begin(), buffer.end(), ModuleOrigin::kWasmOrigin);
|
2015-12-11 12:26:16 +00:00
|
|
|
CHECK_EQ(expected_result, result);
|
|
|
|
}
|
2016-06-22 21:38:42 +00:00
|
|
|
|
2016-09-28 20:55:42 +00:00
|
|
|
void TestModuleException(Zone* zone, WasmModuleBuilder* builder) {
|
|
|
|
ZoneBuffer buffer(zone);
|
|
|
|
builder->WriteTo(buffer);
|
|
|
|
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
testing::SetupIsolateForWasmModule(isolate);
|
|
|
|
v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
|
|
|
|
testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end(),
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
CHECK(try_catch.HasCaught());
|
|
|
|
isolate->clear_pending_exception();
|
|
|
|
}
|
|
|
|
|
2016-10-11 10:35:49 +00:00
|
|
|
void ExportAsMain(WasmFunctionBuilder* f) { f->ExportAs(CStrVector("main")); }
|
2016-08-16 08:07:11 +00:00
|
|
|
|
2015-12-11 12:26:16 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
TEST(Run_WasmModule_Return114) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
static const int32_t kReturnValue = 114;
|
|
|
|
TestSignatures sigs;
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
|
|
|
ExportAsMain(f);
|
2017-01-09 13:57:26 +00:00
|
|
|
byte code[] = {WASM_I32V_2(kReturnValue)};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-11-08 10:33:42 +00:00
|
|
|
TestModule(&zone, builder, kReturnValue);
|
|
|
|
}
|
|
|
|
Cleanup();
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Run_WasmModule_CallAdd) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
TestSignatures sigs;
|
2016-05-17 17:53:46 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
2016-05-17 17:53:46 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_ii());
|
|
|
|
uint16_t param1 = 0;
|
|
|
|
uint16_t param2 = 1;
|
|
|
|
byte code1[] = {
|
|
|
|
WASM_I32_ADD(WASM_GET_LOCAL(param1), WASM_GET_LOCAL(param2))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f1->EmitCode(code1, sizeof(code1));
|
2016-05-17 17:53:46 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
WasmFunctionBuilder* f2 = builder->AddFunction(sigs.i_v());
|
2016-05-17 17:53:46 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
ExportAsMain(f2);
|
|
|
|
byte code2[] = {
|
2017-01-09 13:57:26 +00:00
|
|
|
WASM_CALL_FUNCTION(f1->func_index(), WASM_I32V_2(77), WASM_I32V_1(22))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f2->EmitCode(code2, sizeof(code2));
|
2016-11-08 10:33:42 +00:00
|
|
|
TestModule(&zone, builder, 99);
|
|
|
|
}
|
|
|
|
Cleanup();
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Run_WasmModule_ReadLoadedDataSegment) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
static const byte kDataSegmentDest0 = 12;
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
TestSignatures sigs;
|
|
|
|
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
|
|
|
|
|
|
|
ExportAsMain(f);
|
|
|
|
byte code[] = {
|
2017-01-09 13:57:26 +00:00
|
|
|
WASM_LOAD_MEM(MachineType::Int32(), WASM_I32V_1(kDataSegmentDest0))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-11-08 10:33:42 +00:00
|
|
|
byte data[] = {0xaa, 0xbb, 0xcc, 0xdd};
|
|
|
|
builder->AddDataSegment(data, sizeof(data), kDataSegmentDest0);
|
|
|
|
TestModule(&zone, builder, 0xddccbbaa);
|
|
|
|
}
|
|
|
|
Cleanup();
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Run_WasmModule_CheckMemoryIsZero) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
static const int kCheckSize = 16 * 1024;
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
TestSignatures sigs;
|
|
|
|
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
|
|
|
|
2016-12-21 13:43:00 +00:00
|
|
|
uint16_t localIndex = f->AddLocal(kWasmI32);
|
2016-11-08 10:33:42 +00:00
|
|
|
ExportAsMain(f);
|
|
|
|
byte code[] = {WASM_BLOCK_I(
|
|
|
|
WASM_WHILE(
|
|
|
|
WASM_I32_LTS(WASM_GET_LOCAL(localIndex), WASM_I32V_3(kCheckSize)),
|
|
|
|
WASM_IF_ELSE(
|
|
|
|
WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(localIndex)),
|
2017-01-09 13:57:26 +00:00
|
|
|
WASM_BRV(3, WASM_I32V_1(-1)),
|
|
|
|
WASM_INC_LOCAL_BY(localIndex, 4))),
|
|
|
|
WASM_I32V_1(11))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-11-08 10:33:42 +00:00
|
|
|
TestModule(&zone, builder, 11);
|
|
|
|
}
|
|
|
|
Cleanup();
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Run_WasmModule_CallMain_recursive) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
TestSignatures sigs;
|
|
|
|
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
|
|
|
|
2016-12-21 13:43:00 +00:00
|
|
|
uint16_t localIndex = f->AddLocal(kWasmI32);
|
2016-11-08 10:33:42 +00:00
|
|
|
ExportAsMain(f);
|
|
|
|
byte code[] = {
|
|
|
|
WASM_SET_LOCAL(localIndex,
|
|
|
|
WASM_LOAD_MEM(MachineType::Int32(), WASM_ZERO)),
|
2017-01-09 13:57:26 +00:00
|
|
|
WASM_IF_ELSE_I(WASM_I32_LTS(WASM_GET_LOCAL(localIndex), WASM_I32V_1(5)),
|
2016-11-08 10:33:42 +00:00
|
|
|
WASM_SEQ(WASM_STORE_MEM(MachineType::Int32(), WASM_ZERO,
|
|
|
|
WASM_INC_LOCAL(localIndex)),
|
|
|
|
WASM_CALL_FUNCTION0(0)),
|
2017-01-09 13:57:26 +00:00
|
|
|
WASM_I32V_1(55))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-11-08 10:33:42 +00:00
|
|
|
TestModule(&zone, builder, 55);
|
|
|
|
}
|
|
|
|
Cleanup();
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Run_WasmModule_Global) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
TestSignatures sigs;
|
|
|
|
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
2016-12-21 13:43:00 +00:00
|
|
|
uint32_t global1 = builder->AddGlobal(kWasmI32, 0);
|
|
|
|
uint32_t global2 = builder->AddGlobal(kWasmI32, 0);
|
2016-11-08 10:33:42 +00:00
|
|
|
WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_v());
|
|
|
|
byte code1[] = {
|
|
|
|
WASM_I32_ADD(WASM_GET_GLOBAL(global1), WASM_GET_GLOBAL(global2))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f1->EmitCode(code1, sizeof(code1));
|
2016-11-08 10:33:42 +00:00
|
|
|
WasmFunctionBuilder* f2 = builder->AddFunction(sigs.i_v());
|
|
|
|
ExportAsMain(f2);
|
|
|
|
byte code2[] = {WASM_SET_GLOBAL(global1, WASM_I32V_1(56)),
|
|
|
|
WASM_SET_GLOBAL(global2, WASM_I32V_1(41)),
|
|
|
|
WASM_RETURN1(WASM_CALL_FUNCTION0(f1->func_index()))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f2->EmitCode(code2, sizeof(code2));
|
2016-11-08 10:33:42 +00:00
|
|
|
TestModule(&zone, builder, 97);
|
|
|
|
}
|
|
|
|
Cleanup();
|
2015-12-11 12:26:16 +00:00
|
|
|
}
|
2016-08-16 08:07:11 +00:00
|
|
|
|
2016-10-18 04:35:14 +00:00
|
|
|
// Approximate gtest TEST_F style, in case we adopt gtest.
|
|
|
|
class WasmSerializationTest {
|
|
|
|
public:
|
|
|
|
WasmSerializationTest() : zone_(&allocator_, ZONE_NAME) {
|
|
|
|
// Don't call here if we move to gtest.
|
|
|
|
SetUp();
|
|
|
|
}
|
2016-08-16 08:07:11 +00:00
|
|
|
|
2016-10-18 04:35:14 +00:00
|
|
|
void ClearSerializedData() {
|
|
|
|
serialized_bytes_.first = nullptr;
|
|
|
|
serialized_bytes_.second = 0;
|
|
|
|
}
|
2016-08-16 08:07:11 +00:00
|
|
|
|
2016-10-18 04:35:14 +00:00
|
|
|
void InvalidateVersion() {
|
|
|
|
uint32_t* buffer = reinterpret_cast<uint32_t*>(
|
|
|
|
const_cast<uint8_t*>(serialized_bytes_.first));
|
|
|
|
buffer[SerializedCodeData::kVersionHashOffset] = Version::Hash() + 1;
|
|
|
|
}
|
2016-08-16 08:07:11 +00:00
|
|
|
|
2016-10-18 04:35:14 +00:00
|
|
|
void InvalidateWireBytes() {
|
|
|
|
memset(const_cast<uint8_t*>(wire_bytes_.first), '\0',
|
|
|
|
wire_bytes_.second / 2);
|
|
|
|
}
|
2016-08-16 08:07:11 +00:00
|
|
|
|
2016-10-18 04:35:14 +00:00
|
|
|
v8::MaybeLocal<v8::WasmCompiledModule> Deserialize() {
|
|
|
|
ErrorThrower thrower(current_isolate(), "");
|
|
|
|
v8::MaybeLocal<v8::WasmCompiledModule> deserialized =
|
|
|
|
v8::WasmCompiledModule::DeserializeOrCompile(
|
|
|
|
current_isolate_v8(), serialized_bytes(), wire_bytes());
|
|
|
|
return deserialized;
|
2016-08-16 08:07:11 +00:00
|
|
|
}
|
|
|
|
|
2016-10-18 04:35:14 +00:00
|
|
|
void DeserializeAndRun() {
|
|
|
|
ErrorThrower thrower(current_isolate(), "");
|
|
|
|
v8::Local<v8::WasmCompiledModule> deserialized_module;
|
|
|
|
CHECK(Deserialize().ToLocal(&deserialized_module));
|
2017-01-13 20:47:44 +00:00
|
|
|
Handle<WasmModuleObject> module_object = Handle<WasmModuleObject>::cast(
|
|
|
|
v8::Utils::OpenHandle(*deserialized_module));
|
2016-10-18 04:35:14 +00:00
|
|
|
{
|
|
|
|
DisallowHeapAllocation assume_no_gc;
|
|
|
|
Handle<WasmCompiledModule> compiled_part(
|
|
|
|
WasmCompiledModule::cast(module_object->GetInternalField(0)),
|
|
|
|
current_isolate());
|
|
|
|
CHECK_EQ(memcmp(compiled_part->module_bytes()->GetCharsAddress(),
|
|
|
|
wire_bytes().first, wire_bytes().second),
|
|
|
|
0);
|
2016-10-14 14:24:59 +00:00
|
|
|
}
|
2016-10-18 04:35:14 +00:00
|
|
|
Handle<JSObject> instance =
|
|
|
|
WasmModule::Instantiate(current_isolate(), &thrower, module_object,
|
|
|
|
Handle<JSReceiver>::null(),
|
|
|
|
Handle<JSArrayBuffer>::null())
|
|
|
|
.ToHandleChecked();
|
|
|
|
Handle<Object> params[1] = {
|
|
|
|
Handle<Object>(Smi::FromInt(41), current_isolate())};
|
|
|
|
int32_t result = testing::CallWasmFunctionForTesting(
|
|
|
|
current_isolate(), instance, &thrower, kFunctionName, 1, params,
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
CHECK(result == 42);
|
|
|
|
}
|
2016-10-14 14:24:59 +00:00
|
|
|
|
2016-10-18 04:35:14 +00:00
|
|
|
Isolate* current_isolate() {
|
|
|
|
return reinterpret_cast<Isolate*>(current_isolate_v8_);
|
|
|
|
}
|
|
|
|
|
|
|
|
~WasmSerializationTest() {
|
|
|
|
// Don't call from here if we move to gtest
|
|
|
|
TearDown();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static const char* kFunctionName;
|
|
|
|
|
|
|
|
Zone* zone() { return &zone_; }
|
|
|
|
const v8::WasmCompiledModule::CallerOwnedBuffer& wire_bytes() const {
|
|
|
|
return wire_bytes_;
|
|
|
|
}
|
|
|
|
|
|
|
|
const v8::WasmCompiledModule::CallerOwnedBuffer& serialized_bytes() const {
|
|
|
|
return serialized_bytes_;
|
|
|
|
}
|
|
|
|
|
|
|
|
v8::Isolate* current_isolate_v8() { return current_isolate_v8_; }
|
|
|
|
|
|
|
|
void SetUp() {
|
|
|
|
WasmModuleBuilder* builder = new (zone()) WasmModuleBuilder(zone());
|
|
|
|
TestSignatures sigs;
|
|
|
|
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
|
|
|
|
byte code[] = {WASM_GET_LOCAL(0), kExprI32Const, 1, kExprI32Add};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-10-18 04:35:14 +00:00
|
|
|
f->ExportAs(CStrVector(kFunctionName));
|
|
|
|
|
|
|
|
ZoneBuffer buffer(&zone_);
|
|
|
|
builder->WriteTo(buffer);
|
|
|
|
|
|
|
|
Isolate* serialization_isolate = CcTest::InitIsolateOnce();
|
|
|
|
ErrorThrower thrower(serialization_isolate, "");
|
|
|
|
uint8_t* bytes = nullptr;
|
|
|
|
size_t bytes_size = 0;
|
2016-10-06 19:33:36 +00:00
|
|
|
{
|
2016-10-18 04:35:14 +00:00
|
|
|
HandleScope scope(serialization_isolate);
|
|
|
|
testing::SetupIsolateForWasmModule(serialization_isolate);
|
|
|
|
|
|
|
|
ModuleResult decoding_result =
|
[wasm] Use a Managed<WasmModule> to hold metadata about modules.
This CL refactors the handling of metadata associated with WebAssembly
modules to reduce the duplicate marshalling of data from the C++ world
to the JavaScript world. It does this by wrapping the C++ WasmModule*
object in a Foreign that is rooted from the on-heap WasmCompiledModule
(which is itself just a FixedArray). Upon serialization, the C++ object
is ignored and the original WASM wire bytes are serialized. Upon
deserialization, the C++ object is reconstituted by reparsing the bytes.
This is motivated by increasing complications in implementing the JS
API, in particular WebAssembly.Table, which must perform signature
canonicalization across instances.
Additionally, this CL implements the proper base + offset initialization
behavior for tables.
R=rossberg@chromium.org,bradnelson@chromium.org,mtrofin@chromium.org,yangguo@chromium.org
BUG=v8:5507, chromium:575167, chromium:657316
Review-Url: https://chromiumcodereview.appspot.com/2424623002
Cr-Commit-Position: refs/heads/master@{#40434}
2016-10-19 13:06:44 +00:00
|
|
|
DecodeWasmModule(serialization_isolate, buffer.begin(), buffer.end(),
|
|
|
|
false, kWasmOrigin);
|
2016-10-18 04:35:14 +00:00
|
|
|
CHECK(!decoding_result.failed());
|
|
|
|
|
[wasm] Use a Managed<WasmModule> to hold metadata about modules.
This CL refactors the handling of metadata associated with WebAssembly
modules to reduce the duplicate marshalling of data from the C++ world
to the JavaScript world. It does this by wrapping the C++ WasmModule*
object in a Foreign that is rooted from the on-heap WasmCompiledModule
(which is itself just a FixedArray). Upon serialization, the C++ object
is ignored and the original WASM wire bytes are serialized. Upon
deserialization, the C++ object is reconstituted by reparsing the bytes.
This is motivated by increasing complications in implementing the JS
API, in particular WebAssembly.Table, which must perform signature
canonicalization across instances.
Additionally, this CL implements the proper base + offset initialization
behavior for tables.
R=rossberg@chromium.org,bradnelson@chromium.org,mtrofin@chromium.org,yangguo@chromium.org
BUG=v8:5507, chromium:575167, chromium:657316
Review-Url: https://chromiumcodereview.appspot.com/2424623002
Cr-Commit-Position: refs/heads/master@{#40434}
2016-10-19 13:06:44 +00:00
|
|
|
Handle<WasmModuleWrapper> module_wrapper = WasmModuleWrapper::New(
|
|
|
|
serialization_isolate, const_cast<WasmModule*>(decoding_result.val));
|
|
|
|
|
2016-10-18 04:35:14 +00:00
|
|
|
MaybeHandle<WasmCompiledModule> compiled_module =
|
2016-11-30 15:02:40 +00:00
|
|
|
decoding_result.val->CompileFunctions(
|
|
|
|
serialization_isolate, module_wrapper, &thrower,
|
2016-12-20 14:34:07 +00:00
|
|
|
ModuleWireBytes(buffer.begin(), buffer.end()),
|
|
|
|
Handle<Script>::null(), Vector<const byte>::empty());
|
2016-10-18 04:35:14 +00:00
|
|
|
CHECK(!compiled_module.is_null());
|
2016-11-11 11:12:31 +00:00
|
|
|
Handle<JSObject> module_obj = WasmModuleObject::New(
|
|
|
|
serialization_isolate, compiled_module.ToHandleChecked());
|
2016-10-18 04:35:14 +00:00
|
|
|
v8::Local<v8::Object> v8_module_obj = v8::Utils::ToLocal(module_obj);
|
|
|
|
CHECK(v8_module_obj->IsWebAssemblyCompiledModule());
|
|
|
|
|
|
|
|
v8::Local<v8::WasmCompiledModule> v8_compiled_module =
|
|
|
|
v8_module_obj.As<v8::WasmCompiledModule>();
|
|
|
|
v8::Local<v8::String> uncompiled_bytes =
|
|
|
|
v8_compiled_module->GetWasmWireBytes();
|
|
|
|
bytes_size = static_cast<size_t>(uncompiled_bytes->Length());
|
2016-11-10 05:17:26 +00:00
|
|
|
bytes = zone()->NewArray<uint8_t>(bytes_size);
|
|
|
|
uncompiled_bytes->WriteOneByte(bytes, 0, uncompiled_bytes->Length(),
|
|
|
|
v8::String::NO_NULL_TERMINATION);
|
2016-10-18 04:35:14 +00:00
|
|
|
// keep alive data_ until the end
|
|
|
|
data_ = v8_compiled_module->Serialize();
|
2016-10-06 19:33:36 +00:00
|
|
|
}
|
2016-10-18 04:35:14 +00:00
|
|
|
|
|
|
|
wire_bytes_ = {const_cast<const uint8_t*>(bytes), bytes_size};
|
|
|
|
|
|
|
|
serialized_bytes_ = {data_.first.get(), data_.second};
|
|
|
|
|
|
|
|
v8::Isolate::CreateParams create_params;
|
|
|
|
create_params.array_buffer_allocator =
|
|
|
|
serialization_isolate->array_buffer_allocator();
|
|
|
|
|
|
|
|
current_isolate_v8_ = v8::Isolate::New(create_params);
|
|
|
|
v8::HandleScope new_scope(current_isolate_v8());
|
|
|
|
v8::Local<v8::Context> deserialization_context =
|
|
|
|
v8::Context::New(current_isolate_v8());
|
|
|
|
deserialization_context->Enter();
|
|
|
|
testing::SetupIsolateForWasmModule(current_isolate());
|
2016-08-16 08:07:11 +00:00
|
|
|
}
|
2016-10-18 04:35:14 +00:00
|
|
|
|
|
|
|
void TearDown() {
|
|
|
|
current_isolate_v8()->Dispose();
|
|
|
|
current_isolate_v8_ = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
v8::internal::AccountingAllocator allocator_;
|
|
|
|
Zone zone_;
|
|
|
|
v8::WasmCompiledModule::SerializedModule data_;
|
|
|
|
v8::WasmCompiledModule::CallerOwnedBuffer wire_bytes_;
|
|
|
|
v8::WasmCompiledModule::CallerOwnedBuffer serialized_bytes_;
|
|
|
|
v8::Isolate* current_isolate_v8_;
|
|
|
|
};
|
|
|
|
|
|
|
|
const char* WasmSerializationTest::kFunctionName = "increment";
|
|
|
|
|
|
|
|
TEST(DeserializeValidModule) {
|
|
|
|
WasmSerializationTest test;
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
HandleScope scope(test.current_isolate());
|
|
|
|
test.DeserializeAndRun();
|
|
|
|
}
|
|
|
|
Cleanup(test.current_isolate());
|
|
|
|
Cleanup();
|
2016-10-18 04:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(DeserializeMismatchingVersion) {
|
|
|
|
WasmSerializationTest test;
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
HandleScope scope(test.current_isolate());
|
|
|
|
test.InvalidateVersion();
|
|
|
|
test.DeserializeAndRun();
|
|
|
|
}
|
|
|
|
Cleanup(test.current_isolate());
|
|
|
|
Cleanup();
|
2016-10-18 04:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(DeserializeNoSerializedData) {
|
|
|
|
WasmSerializationTest test;
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
HandleScope scope(test.current_isolate());
|
|
|
|
test.ClearSerializedData();
|
|
|
|
test.DeserializeAndRun();
|
|
|
|
}
|
|
|
|
Cleanup(test.current_isolate());
|
|
|
|
Cleanup();
|
2016-10-18 04:35:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(DeserializeWireBytesAndSerializedDataInvalid) {
|
|
|
|
WasmSerializationTest test;
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
HandleScope scope(test.current_isolate());
|
|
|
|
test.InvalidateVersion();
|
|
|
|
test.InvalidateWireBytes();
|
|
|
|
test.Deserialize();
|
|
|
|
}
|
|
|
|
Cleanup(test.current_isolate());
|
|
|
|
Cleanup();
|
2016-08-16 08:07:11 +00:00
|
|
|
}
|
2016-08-31 12:32:13 +00:00
|
|
|
|
2016-10-05 09:11:54 +00:00
|
|
|
TEST(MemorySize) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
// Initial memory size is 16, see wasm-module-builder.cc
|
|
|
|
static const int kExpectedValue = 16;
|
|
|
|
TestSignatures sigs;
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
|
|
|
ExportAsMain(f);
|
|
|
|
byte code[] = {WASM_MEMORY_SIZE};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-11-08 10:33:42 +00:00
|
|
|
TestModule(&zone, builder, kExpectedValue);
|
|
|
|
}
|
|
|
|
Cleanup();
|
2016-10-05 09:11:54 +00:00
|
|
|
}
|
|
|
|
|
2016-09-02 01:38:10 +00:00
|
|
|
TEST(Run_WasmModule_MemSize_GrowMem) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
// Initial memory size = 16 + GrowMemory(10)
|
|
|
|
static const int kExpectedValue = 26;
|
|
|
|
TestSignatures sigs;
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
|
|
|
ExportAsMain(f);
|
2017-01-09 13:57:26 +00:00
|
|
|
byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(10)), WASM_DROP,
|
|
|
|
WASM_MEMORY_SIZE};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-11-08 10:33:42 +00:00
|
|
|
TestModule(&zone, builder, kExpectedValue);
|
|
|
|
}
|
|
|
|
Cleanup();
|
2016-09-02 01:38:10 +00:00
|
|
|
}
|
|
|
|
|
2016-10-06 11:44:25 +00:00
|
|
|
TEST(GrowMemoryZero) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
// Initial memory size is 16, see wasm-module-builder.cc
|
|
|
|
static const int kExpectedValue = 16;
|
|
|
|
TestSignatures sigs;
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
|
|
|
ExportAsMain(f);
|
|
|
|
byte code[] = {WASM_GROW_MEMORY(WASM_I32V(0))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-11-08 10:33:42 +00:00
|
|
|
TestModule(&zone, builder, kExpectedValue);
|
|
|
|
}
|
|
|
|
Cleanup();
|
2016-10-06 11:44:25 +00:00
|
|
|
}
|
|
|
|
|
2016-10-13 10:56:48 +00:00
|
|
|
class InterruptThread : public v8::base::Thread {
|
|
|
|
public:
|
|
|
|
explicit InterruptThread(Isolate* isolate, int32_t* memory)
|
|
|
|
: Thread(Options("TestInterruptLoop")),
|
|
|
|
isolate_(isolate),
|
|
|
|
memory_(memory) {}
|
|
|
|
|
|
|
|
static void OnInterrupt(v8::Isolate* isolate, void* data) {
|
|
|
|
int32_t* m = reinterpret_cast<int32_t*>(data);
|
|
|
|
// Set the interrupt location to 0 to break the loop in {TestInterruptLoop}.
|
2016-11-07 23:25:24 +00:00
|
|
|
int32_t* ptr = &m[interrupt_location_];
|
|
|
|
WriteLittleEndianValue<int32_t>(ptr, interrupt_value_);
|
2016-10-13 10:56:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void Run() {
|
|
|
|
// Wait for the main thread to write the signal value.
|
2016-11-07 23:25:24 +00:00
|
|
|
int32_t val = 0;
|
|
|
|
do {
|
|
|
|
val = memory_[0];
|
|
|
|
val = ReadLittleEndianValue<int32_t>(&val);
|
|
|
|
} while (val != signal_value_);
|
2016-10-13 10:56:48 +00:00
|
|
|
isolate_->RequestInterrupt(&OnInterrupt, const_cast<int32_t*>(memory_));
|
|
|
|
}
|
|
|
|
|
|
|
|
Isolate* isolate_;
|
|
|
|
volatile int32_t* memory_;
|
|
|
|
static const int32_t interrupt_location_ = 10;
|
|
|
|
static const int32_t interrupt_value_ = 154;
|
|
|
|
static const int32_t signal_value_ = 1221;
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST(TestInterruptLoop) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
// Do not dump the module of this test because it contains an infinite loop.
|
|
|
|
if (FLAG_dump_wasm_module) return;
|
|
|
|
|
|
|
|
// This test tests that WebAssembly loops can be interrupted, i.e. that if
|
|
|
|
// an
|
|
|
|
// InterruptCallback is registered by {Isolate::RequestInterrupt}, then the
|
|
|
|
// InterruptCallback is eventually called even if a loop in WebAssembly code
|
|
|
|
// is executed.
|
|
|
|
// Test setup:
|
|
|
|
// The main thread executes a WebAssembly function with a loop. In the loop
|
|
|
|
// {signal_value_} is written to memory to signal a helper thread that the
|
|
|
|
// main thread reached the loop in the WebAssembly program. When the helper
|
|
|
|
// thread reads {signal_value_} from memory, it registers the
|
|
|
|
// InterruptCallback. Upon exeution, the InterruptCallback write into the
|
|
|
|
// WebAssemblyMemory to end the loop in the WebAssembly program.
|
|
|
|
TestSignatures sigs;
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
|
|
|
ExportAsMain(f);
|
|
|
|
byte code[] = {
|
|
|
|
WASM_LOOP(
|
|
|
|
WASM_IFB(WASM_NOT(WASM_LOAD_MEM(
|
2016-10-13 10:56:48 +00:00
|
|
|
MachineType::Int32(),
|
|
|
|
WASM_I32V(InterruptThread::interrupt_location_ * 4))),
|
|
|
|
WASM_STORE_MEM(MachineType::Int32(), WASM_ZERO,
|
|
|
|
WASM_I32V(InterruptThread::signal_value_)),
|
|
|
|
WASM_BR(1))),
|
2016-11-08 10:33:42 +00:00
|
|
|
WASM_I32V(121)};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-11-08 10:33:42 +00:00
|
|
|
ZoneBuffer buffer(&zone);
|
|
|
|
builder->WriteTo(buffer);
|
2016-10-13 10:56:48 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
HandleScope scope(isolate);
|
|
|
|
testing::SetupIsolateForWasmModule(isolate);
|
|
|
|
ErrorThrower thrower(isolate, "Test");
|
2016-11-16 16:17:22 +00:00
|
|
|
const Handle<WasmInstanceObject> instance =
|
2016-11-08 10:33:42 +00:00
|
|
|
testing::CompileInstantiateWasmModuleForTesting(
|
|
|
|
isolate, &thrower, buffer.begin(), buffer.end(),
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
CHECK(!instance.is_null());
|
|
|
|
|
|
|
|
MaybeHandle<JSArrayBuffer> maybe_memory =
|
|
|
|
GetInstanceMemory(isolate, instance);
|
|
|
|
Handle<JSArrayBuffer> memory = maybe_memory.ToHandleChecked();
|
|
|
|
int32_t* memory_array = reinterpret_cast<int32_t*>(memory->backing_store());
|
|
|
|
|
|
|
|
InterruptThread thread(isolate, memory_array);
|
|
|
|
thread.Start();
|
|
|
|
testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr,
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
int32_t val = memory_array[InterruptThread::interrupt_location_];
|
|
|
|
CHECK_EQ(InterruptThread::interrupt_value_,
|
|
|
|
ReadLittleEndianValue<int32_t>(&val));
|
|
|
|
}
|
|
|
|
Cleanup();
|
2016-10-13 10:56:48 +00:00
|
|
|
}
|
|
|
|
|
2016-08-31 12:32:13 +00:00
|
|
|
TEST(Run_WasmModule_GrowMemoryInIf) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
TestSignatures sigs;
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
|
|
|
ExportAsMain(f);
|
|
|
|
byte code[] = {WASM_IF_ELSE_I(WASM_I32V(0), WASM_GROW_MEMORY(WASM_I32V(1)),
|
|
|
|
WASM_I32V(12))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-11-08 10:33:42 +00:00
|
|
|
TestModule(&zone, builder, 12);
|
|
|
|
}
|
|
|
|
Cleanup();
|
2016-08-31 12:32:13 +00:00
|
|
|
}
|
2016-09-28 20:55:42 +00:00
|
|
|
|
|
|
|
TEST(Run_WasmModule_GrowMemOobOffset) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
static const int kPageSize = 0x10000;
|
|
|
|
// Initial memory size = 16 + GrowMemory(10)
|
|
|
|
static const int index = kPageSize * 17 + 4;
|
|
|
|
int value = 0xaced;
|
|
|
|
TestSignatures sigs;
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
|
|
|
|
ExportAsMain(f);
|
2017-01-09 13:57:26 +00:00
|
|
|
byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(1)),
|
2016-11-08 10:33:42 +00:00
|
|
|
WASM_STORE_MEM(MachineType::Int32(), WASM_I32V(index),
|
|
|
|
WASM_I32V(value))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-11-08 10:33:42 +00:00
|
|
|
TestModuleException(&zone, builder);
|
|
|
|
}
|
|
|
|
Cleanup();
|
2016-09-28 20:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Run_WasmModule_GrowMemOobFixedIndex) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
static const int kPageSize = 0x10000;
|
|
|
|
// Initial memory size = 16 + GrowMemory(10)
|
|
|
|
static const int index = kPageSize * 26 + 4;
|
|
|
|
int value = 0xaced;
|
|
|
|
TestSignatures sigs;
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
Zone zone(isolate->allocator(), ZONE_NAME);
|
2016-09-28 20:55:42 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
|
|
|
|
ExportAsMain(f);
|
|
|
|
byte code[] = {WASM_GROW_MEMORY(WASM_GET_LOCAL(0)), WASM_DROP,
|
|
|
|
WASM_STORE_MEM(MachineType::Int32(), WASM_I32V(index),
|
|
|
|
WASM_I32V(value)),
|
|
|
|
WASM_LOAD_MEM(MachineType::Int32(), WASM_I32V(index))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-09-28 20:55:42 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
HandleScope scope(isolate);
|
|
|
|
ZoneBuffer buffer(&zone);
|
|
|
|
builder->WriteTo(buffer);
|
|
|
|
testing::SetupIsolateForWasmModule(isolate);
|
2016-09-28 20:55:42 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
ErrorThrower thrower(isolate, "Test");
|
|
|
|
Handle<JSObject> instance = testing::CompileInstantiateWasmModuleForTesting(
|
|
|
|
isolate, &thrower, buffer.begin(), buffer.end(),
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
CHECK(!instance.is_null());
|
|
|
|
|
|
|
|
// Initial memory size is 16 pages, should trap till index > MemSize on
|
|
|
|
// consecutive GrowMem calls
|
|
|
|
for (uint32_t i = 1; i < 5; i++) {
|
|
|
|
Handle<Object> params[1] = {Handle<Object>(Smi::FromInt(i), isolate)};
|
|
|
|
v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
|
|
|
|
testing::RunWasmModuleForTesting(isolate, instance, 1, params,
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
CHECK(try_catch.HasCaught());
|
|
|
|
isolate->clear_pending_exception();
|
|
|
|
}
|
2016-09-28 20:55:42 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
Handle<Object> params[1] = {Handle<Object>(Smi::FromInt(1), isolate)};
|
|
|
|
int32_t result = testing::RunWasmModuleForTesting(
|
|
|
|
isolate, instance, 1, params, ModuleOrigin::kWasmOrigin);
|
|
|
|
CHECK(result == 0xaced);
|
2016-09-28 20:55:42 +00:00
|
|
|
}
|
2016-11-08 10:33:42 +00:00
|
|
|
Cleanup();
|
2016-09-28 20:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Run_WasmModule_GrowMemOobVariableIndex) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
static const int kPageSize = 0x10000;
|
|
|
|
int value = 0xaced;
|
|
|
|
TestSignatures sigs;
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
2016-09-28 20:55:42 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
|
|
|
|
ExportAsMain(f);
|
2017-01-09 13:57:26 +00:00
|
|
|
byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(1)), WASM_DROP,
|
2016-11-08 10:33:42 +00:00
|
|
|
WASM_STORE_MEM(MachineType::Int32(), WASM_GET_LOCAL(0),
|
|
|
|
WASM_I32V(value)),
|
|
|
|
WASM_LOAD_MEM(MachineType::Int32(), WASM_GET_LOCAL(0))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f->EmitCode(code, sizeof(code));
|
2016-09-28 20:55:42 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
HandleScope scope(isolate);
|
|
|
|
ZoneBuffer buffer(&zone);
|
|
|
|
builder->WriteTo(buffer);
|
|
|
|
testing::SetupIsolateForWasmModule(isolate);
|
2016-09-28 20:55:42 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
ErrorThrower thrower(isolate, "Test");
|
|
|
|
Handle<JSObject> instance = testing::CompileInstantiateWasmModuleForTesting(
|
|
|
|
isolate, &thrower, buffer.begin(), buffer.end(),
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
|
|
|
|
CHECK(!instance.is_null());
|
|
|
|
|
|
|
|
// Initial memory size is 16 pages, should trap till index > MemSize on
|
|
|
|
// consecutive GrowMem calls
|
|
|
|
for (int i = 1; i < 5; i++) {
|
|
|
|
Handle<Object> params[1] = {
|
|
|
|
Handle<Object>(Smi::FromInt((16 + i) * kPageSize - 3), isolate)};
|
|
|
|
v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
|
|
|
|
testing::RunWasmModuleForTesting(isolate, instance, 1, params,
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
CHECK(try_catch.HasCaught());
|
|
|
|
isolate->clear_pending_exception();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 1; i < 5; i++) {
|
|
|
|
Handle<Object> params[1] = {
|
|
|
|
Handle<Object>(Smi::FromInt((20 + i) * kPageSize - 4), isolate)};
|
|
|
|
int32_t result = testing::RunWasmModuleForTesting(
|
|
|
|
isolate, instance, 1, params, ModuleOrigin::kWasmOrigin);
|
|
|
|
CHECK(result == 0xaced);
|
|
|
|
}
|
2016-09-28 20:55:42 +00:00
|
|
|
|
|
|
|
v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
|
2016-11-08 10:33:42 +00:00
|
|
|
Handle<Object> params[1] = {
|
|
|
|
Handle<Object>(Smi::FromInt(25 * kPageSize), isolate)};
|
2016-09-28 20:55:42 +00:00
|
|
|
testing::RunWasmModuleForTesting(isolate, instance, 1, params,
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
CHECK(try_catch.HasCaught());
|
|
|
|
isolate->clear_pending_exception();
|
|
|
|
}
|
2016-11-08 10:33:42 +00:00
|
|
|
Cleanup();
|
2016-09-28 20:55:42 +00:00
|
|
|
}
|
2016-10-06 15:43:10 +00:00
|
|
|
|
|
|
|
TEST(Run_WasmModule_Global_init) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
TestSignatures sigs;
|
2016-10-06 15:43:10 +00:00
|
|
|
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
2016-11-08 10:33:42 +00:00
|
|
|
uint32_t global1 =
|
2016-12-21 13:43:00 +00:00
|
|
|
builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(777777));
|
2016-11-08 10:33:42 +00:00
|
|
|
uint32_t global2 =
|
2016-12-21 13:43:00 +00:00
|
|
|
builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(222222));
|
2016-11-08 10:33:42 +00:00
|
|
|
WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_v());
|
|
|
|
byte code[] = {
|
|
|
|
WASM_I32_ADD(WASM_GET_GLOBAL(global1), WASM_GET_GLOBAL(global2))};
|
2017-01-13 11:32:17 +00:00
|
|
|
f1->EmitCode(code, sizeof(code));
|
2016-10-06 15:43:10 +00:00
|
|
|
ExportAsMain(f1);
|
2016-11-08 10:33:42 +00:00
|
|
|
TestModule(&zone, builder, 999999);
|
2016-10-06 15:43:10 +00:00
|
|
|
}
|
2016-11-08 10:33:42 +00:00
|
|
|
Cleanup();
|
|
|
|
}
|
2016-10-06 15:43:10 +00:00
|
|
|
|
2016-11-08 10:33:42 +00:00
|
|
|
template <typename CType>
|
2016-12-21 13:43:00 +00:00
|
|
|
static void RunWasmModuleGlobalInitTest(ValueType type, CType expected) {
|
2016-11-08 10:33:42 +00:00
|
|
|
{
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
TestSignatures sigs;
|
2016-10-06 15:43:10 +00:00
|
|
|
|
2016-12-21 13:43:00 +00:00
|
|
|
ValueType types[] = {type};
|
2016-11-08 10:33:42 +00:00
|
|
|
FunctionSig sig(1, 0, types);
|
|
|
|
|
|
|
|
for (int padding = 0; padding < 5; padding++) {
|
|
|
|
// Test with a simple initializer
|
|
|
|
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
|
|
|
|
|
|
|
|
for (int i = 0; i < padding; i++) { // pad global before
|
2016-12-21 13:43:00 +00:00
|
|
|
builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(i + 20000));
|
2016-11-08 10:33:42 +00:00
|
|
|
}
|
|
|
|
uint32_t global =
|
|
|
|
builder->AddGlobal(type, false, false, WasmInitExpr(expected));
|
|
|
|
for (int i = 0; i < padding; i++) { // pad global after
|
2016-12-21 13:43:00 +00:00
|
|
|
builder->AddGlobal(kWasmI32, false, false, WasmInitExpr(i + 30000));
|
2016-11-08 10:33:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WasmFunctionBuilder* f1 = builder->AddFunction(&sig);
|
|
|
|
byte code[] = {WASM_GET_GLOBAL(global)};
|
2017-01-13 11:32:17 +00:00
|
|
|
f1->EmitCode(code, sizeof(code));
|
2016-11-08 10:33:42 +00:00
|
|
|
ExportAsMain(f1);
|
|
|
|
TestModule(&zone, builder, expected);
|
2016-10-06 15:43:10 +00:00
|
|
|
}
|
|
|
|
}
|
2016-11-08 10:33:42 +00:00
|
|
|
Cleanup();
|
2016-10-06 15:43:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Run_WasmModule_Global_i32) {
|
2016-12-21 13:43:00 +00:00
|
|
|
RunWasmModuleGlobalInitTest<int32_t>(kWasmI32, -983489);
|
|
|
|
RunWasmModuleGlobalInitTest<int32_t>(kWasmI32, 11223344);
|
2016-10-06 15:43:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Run_WasmModule_Global_f32) {
|
2016-12-21 13:43:00 +00:00
|
|
|
RunWasmModuleGlobalInitTest<float>(kWasmF32, -983.9f);
|
|
|
|
RunWasmModuleGlobalInitTest<float>(kWasmF32, 1122.99f);
|
2016-10-06 15:43:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Run_WasmModule_Global_f64) {
|
2016-12-21 13:43:00 +00:00
|
|
|
RunWasmModuleGlobalInitTest<double>(kWasmF64, -833.9);
|
|
|
|
RunWasmModuleGlobalInitTest<double>(kWasmF64, 86374.25);
|
2016-10-06 15:43:10 +00:00
|
|
|
}
|
2016-11-09 11:38:30 +00:00
|
|
|
|
|
|
|
TEST(InitDataAtTheUpperLimit) {
|
|
|
|
{
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
testing::SetupIsolateForWasmModule(isolate);
|
|
|
|
|
|
|
|
ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
|
|
|
|
|
|
|
|
const byte data[] = {
|
|
|
|
WASM_MODULE_HEADER, // --
|
|
|
|
kMemorySectionCode, // --
|
|
|
|
U32V_1(4), // section size
|
|
|
|
ENTRY_COUNT(1), // --
|
|
|
|
kResizableMaximumFlag, // --
|
|
|
|
1, // initial size
|
|
|
|
2, // maximum size
|
|
|
|
kDataSectionCode, // --
|
|
|
|
U32V_1(9), // section size
|
|
|
|
ENTRY_COUNT(1), // --
|
|
|
|
0, // linear memory index
|
|
|
|
WASM_I32V_3(0xffff), // destination offset
|
|
|
|
kExprEnd,
|
|
|
|
U32V_1(1), // source size
|
|
|
|
'c' // data bytes
|
|
|
|
};
|
|
|
|
|
|
|
|
testing::CompileInstantiateWasmModuleForTesting(isolate, &thrower, data,
|
|
|
|
data + arraysize(data),
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
if (thrower.error()) {
|
|
|
|
thrower.Reify()->Print();
|
|
|
|
CHECK(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Cleanup();
|
|
|
|
}
|
2016-11-11 13:02:59 +00:00
|
|
|
|
|
|
|
TEST(EmptyMemoryNonEmptyDataSegment) {
|
|
|
|
{
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
testing::SetupIsolateForWasmModule(isolate);
|
|
|
|
|
|
|
|
ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
|
|
|
|
|
|
|
|
const byte data[] = {
|
|
|
|
WASM_MODULE_HEADER, // --
|
|
|
|
kMemorySectionCode, // --
|
|
|
|
U32V_1(4), // section size
|
|
|
|
ENTRY_COUNT(1), // --
|
|
|
|
kResizableMaximumFlag, // --
|
|
|
|
0, // initial size
|
|
|
|
0, // maximum size
|
|
|
|
kDataSectionCode, // --
|
|
|
|
U32V_1(7), // section size
|
|
|
|
ENTRY_COUNT(1), // --
|
|
|
|
0, // linear memory index
|
|
|
|
WASM_I32V_1(8), // destination offset
|
|
|
|
kExprEnd,
|
|
|
|
U32V_1(1), // source size
|
|
|
|
'c' // data bytes
|
|
|
|
};
|
|
|
|
|
|
|
|
testing::CompileInstantiateWasmModuleForTesting(isolate, &thrower, data,
|
|
|
|
data + arraysize(data),
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
// It should not be possible to instantiate this module.
|
|
|
|
CHECK(thrower.error());
|
|
|
|
}
|
|
|
|
Cleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(EmptyMemoryEmptyDataSegment) {
|
|
|
|
{
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
testing::SetupIsolateForWasmModule(isolate);
|
|
|
|
|
|
|
|
ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
|
|
|
|
|
|
|
|
const byte data[] = {
|
|
|
|
WASM_MODULE_HEADER, // --
|
|
|
|
kMemorySectionCode, // --
|
|
|
|
U32V_1(4), // section size
|
|
|
|
ENTRY_COUNT(1), // --
|
|
|
|
kResizableMaximumFlag, // --
|
|
|
|
0, // initial size
|
|
|
|
0, // maximum size
|
|
|
|
kDataSectionCode, // --
|
|
|
|
U32V_1(6), // section size
|
|
|
|
ENTRY_COUNT(1), // --
|
|
|
|
0, // linear memory index
|
|
|
|
WASM_I32V_1(24), // destination offset
|
|
|
|
kExprEnd,
|
|
|
|
U32V_1(0), // source size
|
|
|
|
};
|
|
|
|
|
|
|
|
testing::CompileInstantiateWasmModuleForTesting(isolate, &thrower, data,
|
|
|
|
data + arraysize(data),
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
// It should be possible to instantiate this module.
|
|
|
|
CHECK(!thrower.error());
|
|
|
|
}
|
|
|
|
Cleanup();
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(MemoryWithOOBEmptyDataSegment) {
|
|
|
|
{
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
testing::SetupIsolateForWasmModule(isolate);
|
|
|
|
|
|
|
|
ErrorThrower thrower(isolate, "Run_WasmModule_InitDataAtTheUpperLimit");
|
|
|
|
|
|
|
|
const byte data[] = {
|
|
|
|
WASM_MODULE_HEADER, // --
|
|
|
|
kMemorySectionCode, // --
|
|
|
|
U32V_1(4), // section size
|
|
|
|
ENTRY_COUNT(1), // --
|
|
|
|
kResizableMaximumFlag, // --
|
|
|
|
1, // initial size
|
|
|
|
1, // maximum size
|
|
|
|
kDataSectionCode, // --
|
|
|
|
U32V_1(9), // section size
|
|
|
|
ENTRY_COUNT(1), // --
|
|
|
|
0, // linear memory index
|
|
|
|
WASM_I32V_4(0x2468ace), // destination offset
|
|
|
|
kExprEnd,
|
|
|
|
U32V_1(0), // source size
|
|
|
|
};
|
|
|
|
|
|
|
|
testing::CompileInstantiateWasmModuleForTesting(isolate, &thrower, data,
|
|
|
|
data + arraysize(data),
|
|
|
|
ModuleOrigin::kWasmOrigin);
|
|
|
|
// It should be possible to instantiate this module.
|
|
|
|
CHECK(!thrower.error());
|
|
|
|
}
|
|
|
|
Cleanup();
|
|
|
|
}
|