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>
|
|
|
|
|
2017-09-11 11:40:20 +00:00
|
|
|
#include "src/api.h"
|
2017-02-13 09:52:26 +00:00
|
|
|
#include "src/objects-inl.h"
|
2016-10-14 14:24:59 +00:00
|
|
|
#include "src/snapshot/code-serializer.h"
|
|
|
|
#include "src/version.h"
|
2017-09-28 11:02:36 +00:00
|
|
|
#include "src/wasm/module-compiler.h"
|
2016-08-16 08:07:11 +00:00
|
|
|
#include "src/wasm/module-decoder.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"
|
2017-08-30 13:53:15 +00:00
|
|
|
#include "src/wasm/wasm-objects-inl.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"
|
2017-04-25 11:29:17 +00:00
|
|
|
#include "test/common/wasm/wasm-macro-gen.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
|
|
|
|
2017-09-01 12:57:34 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace wasm {
|
2015-12-11 12:26:16 +00:00
|
|
|
|
|
|
|
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);
|
2017-06-09 18:37:54 +00:00
|
|
|
int32_t result =
|
|
|
|
testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end());
|
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));
|
2017-06-09 18:37:54 +00:00
|
|
|
testing::CompileAndRunWasmModule(isolate, buffer.begin(), buffer.end());
|
2016-09-28 20:55:42 +00:00
|
|
|
CHECK(try_catch.HasCaught());
|
|
|
|
isolate->clear_pending_exception();
|
|
|
|
}
|
|
|
|
|
2017-05-12 11:06:25 +00:00
|
|
|
void ExportAsMain(WasmFunctionBuilder* f) {
|
|
|
|
f->builder()->AddExport(CStrVector("main"), f);
|
|
|
|
}
|
2016-08-16 08:07:11 +00:00
|
|
|
|
2017-01-15 21:18:53 +00:00
|
|
|
#define EMIT_CODE_WITH_END(f, code) \
|
|
|
|
do { \
|
|
|
|
f->EmitCode(code, sizeof(code)); \
|
|
|
|
f->Emit(kExprEnd); \
|
|
|
|
} while (false)
|
|
|
|
|
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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f1, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f2, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f1, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f2, 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
|
|
|
|
2017-01-19 17:30:30 +00:00
|
|
|
static void BuildWireBytes(Zone* zone, ZoneBuffer* buffer) {
|
|
|
|
WasmModuleBuilder* builder = new (zone) WasmModuleBuilder(zone);
|
|
|
|
TestSignatures sigs;
|
|
|
|
|
|
|
|
WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
|
|
|
|
byte code[] = {WASM_GET_LOCAL(0), kExprI32Const, 1, kExprI32Add};
|
|
|
|
EMIT_CODE_WITH_END(f, code);
|
2017-05-12 11:06:25 +00:00
|
|
|
builder->AddExport(CStrVector(kFunctionName), f);
|
2017-01-19 17:30:30 +00:00
|
|
|
|
|
|
|
builder->WriteTo(*buffer);
|
|
|
|
}
|
|
|
|
|
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() {
|
2017-03-07 16:36:51 +00:00
|
|
|
uint32_t* slot = reinterpret_cast<uint32_t*>(
|
|
|
|
const_cast<uint8_t*>(serialized_bytes_.first) +
|
|
|
|
SerializedCodeData::kVersionHashOffset);
|
|
|
|
*slot = Version::Hash() + 1;
|
2016-10-18 04:35:14 +00:00
|
|
|
}
|
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
|
|
|
|
2017-03-07 16:36:51 +00:00
|
|
|
void InvalidateLength() {
|
|
|
|
uint32_t* slot = reinterpret_cast<uint32_t*>(
|
|
|
|
const_cast<uint8_t*>(serialized_bytes_.first) +
|
|
|
|
SerializedCodeData::kPayloadLengthOffset);
|
|
|
|
*slot = 0xfefefefeu;
|
|
|
|
}
|
|
|
|
|
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;
|
2017-07-07 12:27:56 +00:00
|
|
|
Handle<WasmCompiledModule> compiled_part(module_object->compiled_module(),
|
|
|
|
current_isolate());
|
2016-10-18 04:35:14 +00:00
|
|
|
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 =
|
2017-02-20 10:41:57 +00:00
|
|
|
SyncInstantiate(current_isolate(), &thrower, module_object,
|
|
|
|
Handle<JSReceiver>::null(),
|
|
|
|
MaybeHandle<JSArrayBuffer>())
|
2016-10-18 04:35:14 +00:00
|
|
|
.ToHandleChecked();
|
|
|
|
Handle<Object> params[1] = {
|
|
|
|
Handle<Object>(Smi::FromInt(41), current_isolate())};
|
|
|
|
int32_t result = testing::CallWasmFunctionForTesting(
|
2017-06-21 09:24:03 +00:00
|
|
|
current_isolate(), instance, &thrower, kFunctionName, 1, params);
|
2017-09-19 11:02:31 +00:00
|
|
|
CHECK_EQ(42, result);
|
2016-10-18 04:35:14 +00:00
|
|
|
}
|
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();
|
|
|
|
}
|
|
|
|
|
2017-01-19 17:30:30 +00:00
|
|
|
v8::Isolate* current_isolate_v8() { return current_isolate_v8_; }
|
|
|
|
|
2016-10-18 04:35:14 +00:00
|
|
|
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_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetUp() {
|
|
|
|
ZoneBuffer buffer(&zone_);
|
2017-01-19 17:30:30 +00:00
|
|
|
WasmSerializationTest::BuildWireBytes(zone(), &buffer);
|
2016-10-18 04:35:14 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2017-02-20 10:41:57 +00:00
|
|
|
MaybeHandle<WasmModuleObject> module_object =
|
|
|
|
SyncCompile(serialization_isolate, &thrower,
|
|
|
|
ModuleWireBytes(buffer.begin(), buffer.end()));
|
2016-10-18 04:35:14 +00:00
|
|
|
|
2017-02-20 10:41:57 +00:00
|
|
|
MaybeHandle<WasmCompiledModule> compiled_module(
|
|
|
|
module_object.ToHandleChecked()->compiled_module(),
|
|
|
|
serialization_isolate);
|
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
|
|
|
}
|
|
|
|
|
2017-03-07 16:36:51 +00:00
|
|
|
TEST(DeserializeInvalidLength) {
|
|
|
|
WasmSerializationTest test;
|
|
|
|
{
|
|
|
|
HandleScope scope(test.current_isolate());
|
|
|
|
test.InvalidateLength();
|
|
|
|
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
|
|
|
|
2017-03-23 01:47:17 +00:00
|
|
|
std::unique_ptr<const uint8_t[]> CreatePayload(const uint8_t* start,
|
|
|
|
size_t size) {
|
|
|
|
uint8_t* ret = new uint8_t[size];
|
|
|
|
memcpy(ret, start, size);
|
|
|
|
return std::unique_ptr<const uint8_t[]>(const_cast<const uint8_t*>(ret));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ModuleBuilder) {
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
ZoneBuffer buffer(&zone);
|
|
|
|
WasmSerializationTest::BuildWireBytes(&zone, &buffer);
|
|
|
|
CHECK_GT(buffer.size(), 0);
|
|
|
|
size_t third = buffer.size() / 3;
|
|
|
|
size_t first_mark = third - 2;
|
|
|
|
size_t second_mark = buffer.size() - 2 - third;
|
2017-09-19 11:02:31 +00:00
|
|
|
CHECK_LT(0, first_mark);
|
2017-03-23 01:47:17 +00:00
|
|
|
CHECK(first_mark < second_mark);
|
|
|
|
CHECK(second_mark < buffer.size());
|
|
|
|
Isolate* i_isolate = CcTest::InitIsolateOnce();
|
|
|
|
v8::WasmModuleObjectBuilder builder(CcTest::isolate());
|
|
|
|
std::unique_ptr<const uint8_t[]> first_part =
|
|
|
|
CreatePayload(buffer.begin(), first_mark);
|
|
|
|
std::unique_ptr<const uint8_t[]> second_part =
|
|
|
|
CreatePayload(buffer.begin() + first_mark, second_mark - first_mark);
|
|
|
|
std::unique_ptr<const uint8_t[]> third_part =
|
|
|
|
CreatePayload(buffer.begin() + second_mark, buffer.size() - second_mark);
|
2017-04-04 16:22:46 +00:00
|
|
|
builder.OnBytesReceived(first_part.get(), first_mark);
|
|
|
|
builder.OnBytesReceived(second_part.get(), second_mark - first_mark);
|
|
|
|
builder.OnBytesReceived(third_part.get(), buffer.size() - second_mark);
|
2017-03-23 01:47:17 +00:00
|
|
|
{
|
|
|
|
HandleScope scope(i_isolate);
|
|
|
|
v8::MaybeLocal<v8::WasmCompiledModule> maybe_module = builder.Finish();
|
|
|
|
CHECK(!maybe_module.IsEmpty());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(FailingModuleBuilder) {
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
ZoneBuffer buffer(&zone);
|
|
|
|
WasmSerializationTest::BuildWireBytes(&zone, &buffer);
|
|
|
|
CHECK_GT(buffer.size(), 0);
|
|
|
|
size_t third = buffer.size() / 3;
|
|
|
|
size_t first_mark = third - 2;
|
|
|
|
size_t second_mark = buffer.size() - 2 - third;
|
2017-09-19 11:02:31 +00:00
|
|
|
CHECK_LT(0, first_mark);
|
2017-03-23 01:47:17 +00:00
|
|
|
CHECK(first_mark < second_mark);
|
|
|
|
CHECK(second_mark < buffer.size());
|
|
|
|
Isolate* i_isolate = CcTest::InitIsolateOnce();
|
|
|
|
v8::WasmModuleObjectBuilder builder(CcTest::isolate());
|
|
|
|
std::unique_ptr<const uint8_t[]> first_part =
|
|
|
|
CreatePayload(buffer.begin(), first_mark);
|
2017-04-04 16:22:46 +00:00
|
|
|
builder.OnBytesReceived(first_part.get(), first_mark);
|
2017-03-23 01:47:17 +00:00
|
|
|
{
|
|
|
|
HandleScope scope(i_isolate);
|
|
|
|
v8::MaybeLocal<v8::WasmCompiledModule> maybe_module = builder.Finish();
|
|
|
|
CHECK(maybe_module.IsEmpty());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-13 12:43:18 +00:00
|
|
|
bool False(v8::Local<v8::Context> context, v8::Local<v8::String> source) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-01-19 17:30:30 +00:00
|
|
|
|
|
|
|
TEST(BlockWasmCodeGen) {
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
ZoneBuffer buffer(&zone);
|
|
|
|
WasmSerializationTest::BuildWireBytes(&zone, &buffer);
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
testing::SetupIsolateForWasmModule(isolate);
|
|
|
|
CcTest::isolate()->SetAllowCodeGenerationFromStringsCallback(False);
|
|
|
|
|
|
|
|
ErrorThrower thrower(isolate, "block codegen");
|
2017-02-20 10:41:57 +00:00
|
|
|
MaybeHandle<WasmModuleObject> ret = wasm::SyncCompile(
|
|
|
|
isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()));
|
2017-01-19 17:30:30 +00:00
|
|
|
CHECK(ret.is_null());
|
|
|
|
CHECK(thrower.error());
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BlockWasmCodeGenAtDeserialization) {
|
|
|
|
WasmSerializationTest test;
|
|
|
|
{
|
|
|
|
HandleScope scope(test.current_isolate());
|
|
|
|
test.current_isolate_v8()->SetAllowCodeGenerationFromStringsCallback(False);
|
|
|
|
v8::MaybeLocal<v8::WasmCompiledModule> nothing = test.Deserialize();
|
|
|
|
CHECK(nothing.IsEmpty());
|
|
|
|
}
|
|
|
|
Cleanup(test.current_isolate());
|
|
|
|
Cleanup();
|
|
|
|
}
|
|
|
|
|
Reland of [wasm] Transferrable modules (patchset #1 id:1 of https://codereview.chromium.org/2762163002/ )
Reason for revert:
Temporarily disabled tests on chromium side (https://codereview.chromium.org/2764933002)
Original issue's description:
> Revert of [wasm] Transferrable modules (patchset #13 id:280001 of https://codereview.chromium.org/2748473004/ )
>
> Reason for revert:
> Breaks layout tests:
> https://build.chromium.org/p/client.v8.fyi/builders/V8-Blink%20Linux%2064/builds/14312
>
> See https://github.com/v8/v8/wiki/Blink-layout-tests
>
> Original issue's description:
> > [wasm] Transferrable modules
> >
> > We want to restrict structured cloning in Chrome to:
> > - postMessage senders and receivers that are co-located
> > in the same process
> > - indexedDB (just https).
> >
> > For context, on the Chrome side, we will achieve the postMessage part
> > by using a mechanism similar to transferrables: the
> > SerializedScriptValue will have a list of wasm modules, separate from
> > the serialized data stream; and this list won't be copied cross
> > process boundaries. The IDB part is achieved by explicitly opting in
> > reading/writing to the serialization stream. To block attack vectors
> > in IPC cases, the default for deserialization will be to expect data
> > in the wasm transfers list.
> >
> > This change is the V8 side necessary to enabling this design. We
> > introduce TransferrableModule, an opaque datatype exposed to the
> > embedder. Internally, TransferrableModules are just serialized data,
> > because we don't have a better mechanism, at the moment, for
> > de-contextualizing/re-contextualizing wasm modules (wrt Isolate and
> > Context).
> >
> > The chrome defaults will be implemented in the
> > serialization/deserialization delegates on that side. For the v8 side
> > of things, in the absence of a serialization delegate, the V8
> > serializer will write to serialization stream. In the absence of a
> > deserialization delegate, the deserializer won't work. This asymmetry
> > is intentional - it communicates to the embedder the need to make a
> > policy decision, otherwise wasm serialization/deserialization won't
> > work "out of the box".
> >
> > BUG=v8:6079
> >
> > Review-Url: https://codereview.chromium.org/2748473004
> > Cr-Commit-Position: refs/heads/master@{#43955}
> > Committed: https://chromium.googlesource.com/v8/v8/+/99743ad460ea5b9795ba9d70a074e75d7362a3d1
>
> TBR=jbroman@chromium.org,bradnelson@chromium.org,mtrofin@chromium.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=v8:6079
>
> Review-Url: https://codereview.chromium.org/2762163002
> Cr-Commit-Position: refs/heads/master@{#43981}
> Committed: https://chromium.googlesource.com/v8/v8/+/e538b70e1a45289dfe0fa9789563f023a5e9c22b
TBR=jbroman@chromium.org,bradnelson@chromium.org,machenbach@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:6079
Review-Url: https://codereview.chromium.org/2762273002
Cr-Commit-Position: refs/heads/master@{#43994}
2017-03-21 17:48:05 +00:00
|
|
|
TEST(TransferrableWasmModules) {
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
|
|
Zone zone(&allocator, ZONE_NAME);
|
|
|
|
|
|
|
|
ZoneBuffer buffer(&zone);
|
|
|
|
WasmSerializationTest::BuildWireBytes(&zone, &buffer);
|
|
|
|
|
|
|
|
Isolate* from_isolate = CcTest::InitIsolateOnce();
|
|
|
|
ErrorThrower thrower(from_isolate, "");
|
|
|
|
std::vector<v8::WasmCompiledModule::TransferrableModule> store;
|
|
|
|
{
|
|
|
|
HandleScope scope(from_isolate);
|
|
|
|
testing::SetupIsolateForWasmModule(from_isolate);
|
|
|
|
|
|
|
|
MaybeHandle<WasmModuleObject> module_object = SyncCompile(
|
|
|
|
from_isolate, &thrower, ModuleWireBytes(buffer.begin(), buffer.end()));
|
|
|
|
v8::Local<v8::WasmCompiledModule> v8_module =
|
|
|
|
v8::Local<v8::WasmCompiledModule>::Cast(v8::Utils::ToLocal(
|
|
|
|
Handle<JSObject>::cast(module_object.ToHandleChecked())));
|
|
|
|
store.push_back(v8_module->GetTransferrableModule());
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
v8::Isolate::CreateParams create_params;
|
|
|
|
create_params.array_buffer_allocator =
|
|
|
|
from_isolate->array_buffer_allocator();
|
|
|
|
v8::Isolate* to_isolate = v8::Isolate::New(create_params);
|
|
|
|
v8::HandleScope new_scope(to_isolate);
|
|
|
|
v8::Local<v8::Context> deserialization_context =
|
|
|
|
v8::Context::New(to_isolate);
|
|
|
|
deserialization_context->Enter();
|
|
|
|
v8::MaybeLocal<v8::WasmCompiledModule> mod =
|
|
|
|
v8::WasmCompiledModule::FromTransferrableModule(to_isolate, store[0]);
|
|
|
|
CHECK(!mod.IsEmpty());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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 =
|
2017-06-09 18:37:54 +00:00
|
|
|
SyncCompileAndInstantiate(isolate, &thrower,
|
|
|
|
ModuleWireBytes(buffer.begin(), buffer.end()),
|
|
|
|
{}, {})
|
|
|
|
.ToHandleChecked();
|
2016-11-08 10:33:42 +00:00
|
|
|
|
2017-03-31 07:46:36 +00:00
|
|
|
Handle<JSArrayBuffer> memory(instance->memory_buffer(), isolate);
|
2016-11-08 10:33:42 +00:00
|
|
|
int32_t* memory_array = reinterpret_cast<int32_t*>(memory->backing_store());
|
|
|
|
|
|
|
|
InterruptThread thread(isolate, memory_array);
|
|
|
|
thread.Start();
|
2017-06-21 09:24:03 +00:00
|
|
|
testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr);
|
2016-11-08 10:33:42 +00:00
|
|
|
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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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");
|
2017-06-09 18:37:54 +00:00
|
|
|
Handle<WasmInstanceObject> instance =
|
|
|
|
SyncCompileAndInstantiate(isolate, &thrower,
|
|
|
|
ModuleWireBytes(buffer.begin(), buffer.end()),
|
|
|
|
{}, {})
|
|
|
|
.ToHandleChecked();
|
2016-11-08 10:33:42 +00:00
|
|
|
|
|
|
|
// 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));
|
2017-06-21 09:24:03 +00:00
|
|
|
testing::RunWasmModuleForTesting(isolate, instance, 1, params);
|
2016-11-08 10:33:42 +00:00
|
|
|
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)};
|
2017-06-21 09:24:03 +00:00
|
|
|
int32_t result =
|
|
|
|
testing::RunWasmModuleForTesting(isolate, instance, 1, params);
|
2017-09-19 11:02:31 +00:00
|
|
|
CHECK_EQ(0xaced, result);
|
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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f, 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");
|
2017-06-09 18:37:54 +00:00
|
|
|
Handle<WasmInstanceObject> instance =
|
|
|
|
SyncCompileAndInstantiate(isolate, &thrower,
|
|
|
|
ModuleWireBytes(buffer.begin(), buffer.end()),
|
|
|
|
{}, {})
|
|
|
|
.ToHandleChecked();
|
2016-11-08 10:33:42 +00:00
|
|
|
|
|
|
|
// 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));
|
2017-06-21 09:24:03 +00:00
|
|
|
testing::RunWasmModuleForTesting(isolate, instance, 1, params);
|
2016-11-08 10:33:42 +00:00
|
|
|
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)};
|
2017-06-21 09:24:03 +00:00
|
|
|
int32_t result =
|
|
|
|
testing::RunWasmModuleForTesting(isolate, instance, 1, params);
|
2017-09-19 11:02:31 +00:00
|
|
|
CHECK_EQ(0xaced, result);
|
2016-11-08 10:33:42 +00:00
|
|
|
}
|
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)};
|
2017-06-21 09:24:03 +00:00
|
|
|
testing::RunWasmModuleForTesting(isolate, instance, 1, params);
|
2016-09-28 20:55:42 +00:00
|
|
|
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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f1, 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-15 21:18:53 +00:00
|
|
|
EMIT_CODE_WITH_END(f1, 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
|
|
|
|
};
|
|
|
|
|
2017-06-09 18:37:54 +00:00
|
|
|
SyncCompileAndInstantiate(isolate, &thrower,
|
|
|
|
ModuleWireBytes(data, data + arraysize(data)), {},
|
|
|
|
{});
|
2016-11-09 11:38:30 +00:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
2017-06-09 18:37:54 +00:00
|
|
|
SyncCompileAndInstantiate(isolate, &thrower,
|
|
|
|
ModuleWireBytes(data, data + arraysize(data)), {},
|
|
|
|
{});
|
2016-11-11 13:02:59 +00:00
|
|
|
// 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
|
2017-01-23 17:21:39 +00:00
|
|
|
WASM_I32V_1(0), // destination offset
|
2016-11-11 13:02:59 +00:00
|
|
|
kExprEnd,
|
|
|
|
U32V_1(0), // source size
|
|
|
|
};
|
|
|
|
|
2017-06-09 18:37:54 +00:00
|
|
|
SyncCompileAndInstantiate(isolate, &thrower,
|
|
|
|
ModuleWireBytes(data, data + arraysize(data)), {},
|
|
|
|
{});
|
2016-11-11 13:02:59 +00:00
|
|
|
// 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
|
|
|
|
};
|
|
|
|
|
2017-06-09 18:37:54 +00:00
|
|
|
SyncCompileAndInstantiate(isolate, &thrower,
|
|
|
|
ModuleWireBytes(data, data + arraysize(data)), {},
|
|
|
|
{});
|
2017-01-23 17:21:39 +00:00
|
|
|
// It should not be possible to instantiate this module.
|
|
|
|
CHECK(thrower.error());
|
2016-11-11 13:02:59 +00:00
|
|
|
}
|
|
|
|
Cleanup();
|
|
|
|
}
|
2017-03-17 01:12:07 +00:00
|
|
|
|
|
|
|
TEST(Run_WasmModule_Buffer_Externalized_GrowMem) {
|
|
|
|
{
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
// Initial memory size = 16 + GrowWebAssemblyMemory(4) + GrowMemory(6)
|
|
|
|
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);
|
|
|
|
byte code[] = {WASM_GROW_MEMORY(WASM_I32V_1(6)), WASM_DROP,
|
|
|
|
WASM_MEMORY_SIZE};
|
|
|
|
EMIT_CODE_WITH_END(f, code);
|
|
|
|
|
|
|
|
ZoneBuffer buffer(&zone);
|
|
|
|
builder->WriteTo(buffer);
|
|
|
|
testing::SetupIsolateForWasmModule(isolate);
|
|
|
|
ErrorThrower thrower(isolate, "Test");
|
|
|
|
const Handle<WasmInstanceObject> instance =
|
2017-06-09 18:37:54 +00:00
|
|
|
SyncCompileAndInstantiate(isolate, &thrower,
|
|
|
|
ModuleWireBytes(buffer.begin(), buffer.end()),
|
|
|
|
{}, {})
|
|
|
|
.ToHandleChecked();
|
2017-03-31 07:46:36 +00:00
|
|
|
Handle<JSArrayBuffer> memory(instance->memory_buffer(), isolate);
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
Handle<WasmMemoryObject> mem_obj(instance->memory_object(), isolate);
|
2017-06-12 22:39:23 +00:00
|
|
|
void* const old_allocation_base = memory->allocation_base();
|
|
|
|
size_t const old_allocation_length = memory->allocation_length();
|
2017-03-17 01:12:07 +00:00
|
|
|
|
[wasm] Introduce the WasmContext
The WasmContext struct introduced in this CL is used to store the
mem_size and mem_start address of the wasm memory. These variables can
be accessed at C++ level at graph build time (e.g., initialized during
instance building). When the GrowMemory runtime is invoked, the context
variables can be changed in the WasmContext at C++ level so that the
generated code will load the correct values.
This requires to insert a relocatable pointer only in the
JSToWasmWrapper (and in the other wasm entry points), the value is then
passed from function to function as an automatically added additional
parameter. The WasmContext is then dropped when creating an Interpreter
Entry or when invoking a JavaScript function. This removes the need of
patching the generated code at runtime (i.e., when the memory grows)
with respect to WASM_MEMORY_REFERENCE and WASM_MEMORY_SIZE_REFERENCE.
However, we still need to patch the code at instance build time to patch
the JSToWasmWrappers; in fact the address of the WasmContext is not
known during compilation, but only when the instance is built.
The WasmContext address is passed as the first parameter. This has the
advantage of not having to move the WasmContext around if the function
does not use many registers. This CL also changes the wasm calling
convention so that the first parameter register is different from the
return value register. The WasmContext is attached to every
WasmMemoryObject, to share the same context with multiple instances
sharing the same memory. Moreover, the nodes representing the
WasmContext variables are cached in the SSA environment, similarly to
other local variables that might change during execution. The nodes are
created when initializing the SSA environment and refreshed every time a
grow_memory or a function call happens, so that we are sure that they
always represent the correct mem_size and mem_start variables.
This CL also removes the WasmMemorySize runtime (since it's now possible
to directly retrieve mem_size from the context) and simplifies the
GrowMemory runtime (since every instance now has a memory_object).
R=ahaas@chromium.org,clemensh@chromium.org
CC=gdeepti@chromium.org
Change-Id: I3f058e641284f5a1bbbfc35a64c88da6ff08e240
Reviewed-on: https://chromium-review.googlesource.com/671008
Commit-Queue: Enrico Bacis <enricobacis@google.com>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48209}
2017-09-28 14:59:37 +00:00
|
|
|
// Fake the Embedder flow by externalizing the memory object, and grow.
|
2017-05-19 19:54:43 +00:00
|
|
|
v8::Utils::ToLocal(memory)->Externalize();
|
|
|
|
|
2017-03-31 07:46:36 +00:00
|
|
|
uint32_t result = WasmMemoryObject::Grow(isolate, mem_obj, 4);
|
2017-09-11 19:36:50 +00:00
|
|
|
bool free_memory = !memory->has_guard_region();
|
|
|
|
if (!free_memory) {
|
|
|
|
// current_pages = Initial memory size(16) + GrowWebAssemblyMemory(4)
|
|
|
|
const uint32_t current_pages = 20;
|
|
|
|
i::WasmMemoryObject::SetupNewBufferWithSameBackingStore(isolate, mem_obj,
|
|
|
|
current_pages);
|
|
|
|
}
|
2017-05-19 19:54:43 +00:00
|
|
|
wasm::DetachWebAssemblyMemoryBuffer(isolate, memory, free_memory);
|
2017-03-17 01:12:07 +00:00
|
|
|
CHECK_EQ(16, result);
|
2017-07-07 12:27:56 +00:00
|
|
|
memory = handle(mem_obj->array_buffer());
|
2017-03-17 01:12:07 +00:00
|
|
|
instance->set_memory_buffer(*memory);
|
|
|
|
// Externalize should make no difference without the JS API as in this case
|
|
|
|
// the buffer is not detached.
|
2017-05-19 19:54:43 +00:00
|
|
|
v8::Utils::ToLocal(memory)->Externalize();
|
2017-06-21 09:24:03 +00:00
|
|
|
result = testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr);
|
2017-03-17 01:12:07 +00:00
|
|
|
CHECK_EQ(kExpectedValue, result);
|
|
|
|
// Free the buffer as the tracker does not know about it.
|
2017-05-19 19:54:43 +00:00
|
|
|
const v8::ArrayBuffer::Allocator::AllocationMode allocation_mode =
|
|
|
|
memory->allocation_mode();
|
2017-06-12 22:39:23 +00:00
|
|
|
CHECK_NOT_NULL(memory->allocation_base());
|
2017-05-19 19:54:43 +00:00
|
|
|
isolate->array_buffer_allocator()->Free(memory->allocation_base(),
|
|
|
|
memory->allocation_length(),
|
|
|
|
allocation_mode);
|
2017-09-11 19:36:50 +00:00
|
|
|
if (free_memory) {
|
|
|
|
// GrowMemory without guard pages enabled allocates an extra buffer,
|
|
|
|
// that needs to be freed as well
|
|
|
|
isolate->array_buffer_allocator()->Free(
|
|
|
|
old_allocation_base, old_allocation_length, allocation_mode);
|
|
|
|
}
|
2017-05-19 19:54:43 +00:00
|
|
|
memory->set_allocation_base(nullptr);
|
|
|
|
memory->set_allocation_length(0);
|
2017-03-17 01:12:07 +00:00
|
|
|
}
|
|
|
|
Cleanup();
|
|
|
|
}
|
2017-05-10 17:28:45 +00:00
|
|
|
|
|
|
|
TEST(Run_WasmModule_Buffer_Externalized_GrowMemMemSize) {
|
|
|
|
{
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
void* backing_store =
|
|
|
|
isolate->array_buffer_allocator()->Allocate(16 * WasmModule::kPageSize);
|
|
|
|
Handle<JSArrayBuffer> buffer = wasm::SetupArrayBuffer(
|
2017-05-19 19:54:43 +00:00
|
|
|
isolate, backing_store, 16 * WasmModule::kPageSize, backing_store,
|
|
|
|
16 * WasmModule::kPageSize, false, false);
|
2017-05-10 17:28:45 +00:00
|
|
|
Handle<WasmMemoryObject> mem_obj =
|
|
|
|
WasmMemoryObject::New(isolate, buffer, 100);
|
|
|
|
v8::Utils::ToLocal(buffer)->Externalize();
|
|
|
|
int32_t result = WasmMemoryObject::Grow(isolate, mem_obj, 0);
|
|
|
|
wasm::DetachWebAssemblyMemoryBuffer(isolate, buffer, false);
|
|
|
|
CHECK_EQ(16, result);
|
|
|
|
|
|
|
|
isolate->array_buffer_allocator()->Free(backing_store,
|
|
|
|
16 * WasmModule::kPageSize);
|
|
|
|
}
|
|
|
|
Cleanup();
|
|
|
|
}
|
2017-06-12 22:39:23 +00:00
|
|
|
|
|
|
|
TEST(Run_WasmModule_Buffer_Externalized_Detach) {
|
|
|
|
{
|
|
|
|
// Regression test for
|
|
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=731046
|
|
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
void* backing_store =
|
|
|
|
isolate->array_buffer_allocator()->Allocate(16 * WasmModule::kPageSize);
|
|
|
|
Handle<JSArrayBuffer> buffer = wasm::SetupArrayBuffer(
|
|
|
|
isolate, backing_store, 16 * WasmModule::kPageSize, backing_store,
|
|
|
|
16 * WasmModule::kPageSize, false, false);
|
|
|
|
v8::Utils::ToLocal(buffer)->Externalize();
|
|
|
|
wasm::DetachWebAssemblyMemoryBuffer(isolate, buffer, true);
|
|
|
|
isolate->array_buffer_allocator()->Free(backing_store,
|
|
|
|
16 * WasmModule::kPageSize);
|
|
|
|
}
|
|
|
|
Cleanup();
|
|
|
|
}
|
2017-09-01 12:57:34 +00:00
|
|
|
|
2017-09-08 13:59:05 +00:00
|
|
|
#undef EMIT_CODE_WITH_END
|
|
|
|
|
2017-09-01 12:57:34 +00:00
|
|
|
} // namespace wasm
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|