summaryrefslogtreecommitdiff
path: root/deps/v8/test/cctest/wasm/test-wasm-serialization.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/test/cctest/wasm/test-wasm-serialization.cc')
-rw-r--r--deps/v8/test/cctest/wasm/test-wasm-serialization.cc319
1 files changed, 319 insertions, 0 deletions
diff --git a/deps/v8/test/cctest/wasm/test-wasm-serialization.cc b/deps/v8/test/cctest/wasm/test-wasm-serialization.cc
new file mode 100644
index 0000000000..9475332ad0
--- /dev/null
+++ b/deps/v8/test/cctest/wasm/test-wasm-serialization.cc
@@ -0,0 +1,319 @@
+// 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>
+
+#include "src/api.h"
+#include "src/objects-inl.h"
+#include "src/snapshot/code-serializer.h"
+#include "src/version.h"
+#include "src/wasm/module-decoder.h"
+#include "src/wasm/wasm-engine.h"
+#include "src/wasm/wasm-memory.h"
+#include "src/wasm/wasm-module-builder.h"
+#include "src/wasm/wasm-module.h"
+#include "src/wasm/wasm-objects-inl.h"
+#include "src/wasm/wasm-opcodes.h"
+
+#include "test/cctest/cctest.h"
+#include "test/common/wasm/flag-utils.h"
+#include "test/common/wasm/test-signatures.h"
+#include "test/common/wasm/wasm-macro-gen.h"
+#include "test/common/wasm/wasm-module-runner.h"
+
+namespace v8 {
+namespace internal {
+namespace wasm {
+namespace test_wasm_serialization {
+
+namespace {
+void Cleanup(Isolate* isolate = CcTest::InitIsolateOnce()) {
+ // 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.
+ reinterpret_cast<v8::Isolate*>(isolate)->LowMemoryNotification();
+}
+
+#define EMIT_CODE_WITH_END(f, code) \
+ do { \
+ f->EmitCode(code, sizeof(code)); \
+ f->Emit(kExprEnd); \
+ } while (false)
+
+} // namespace
+
+// 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();
+ }
+
+ 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);
+ builder->AddExport(CStrVector(kFunctionName), f);
+
+ builder->WriteTo(*buffer);
+ }
+
+ void ClearSerializedData() { serialized_bytes_ = {nullptr, 0}; }
+
+ void InvalidateVersion() {
+ uint32_t* slot = reinterpret_cast<uint32_t*>(
+ const_cast<uint8_t*>(serialized_bytes_.start) +
+ SerializedCodeData::kVersionHashOffset);
+ *slot = Version::Hash() + 1;
+ }
+
+ void InvalidateWireBytes() {
+ memset(const_cast<uint8_t*>(wire_bytes_.start), 0, wire_bytes_.size / 2);
+ }
+
+ void InvalidateLength() {
+ uint32_t* slot = reinterpret_cast<uint32_t*>(
+ const_cast<uint8_t*>(serialized_bytes_.start) +
+ SerializedCodeData::kPayloadLengthOffset);
+ *slot = 0u;
+ }
+
+ 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;
+ }
+
+ void DeserializeAndRun() {
+ ErrorThrower thrower(current_isolate(), "");
+ v8::Local<v8::WasmCompiledModule> deserialized_module;
+ CHECK(Deserialize().ToLocal(&deserialized_module));
+ Handle<WasmModuleObject> module_object = Handle<WasmModuleObject>::cast(
+ v8::Utils::OpenHandle(*deserialized_module));
+ {
+ DisallowHeapAllocation assume_no_gc;
+ Vector<const byte> deserialized_module_wire_bytes =
+ module_object->native_module()->wire_bytes();
+ CHECK_EQ(deserialized_module_wire_bytes.size(), wire_bytes_.size);
+ CHECK_EQ(memcmp(deserialized_module_wire_bytes.start(), wire_bytes_.start,
+ wire_bytes_.size),
+ 0);
+ }
+ Handle<WasmInstanceObject> instance =
+ current_isolate()
+ ->wasm_engine()
+ ->SyncInstantiate(current_isolate(), &thrower, module_object,
+ Handle<JSReceiver>::null(),
+ MaybeHandle<JSArrayBuffer>())
+ .ToHandleChecked();
+ Handle<Object> params[1] = {
+ Handle<Object>(Smi::FromInt(41), current_isolate())};
+ int32_t result = testing::CallWasmFunctionForTesting(
+ current_isolate(), instance, &thrower, kFunctionName, 1, params);
+ CHECK_EQ(42, result);
+ }
+
+ Isolate* current_isolate() {
+ return reinterpret_cast<Isolate*>(current_isolate_v8_);
+ }
+
+ ~WasmSerializationTest() {
+ // Don't call from here if we move to gtest
+ TearDown();
+ }
+
+ v8::Isolate* current_isolate_v8() { return current_isolate_v8_; }
+
+ private:
+ static const char* kFunctionName;
+
+ Zone* zone() { return &zone_; }
+
+ void SetUp() {
+ ZoneBuffer buffer(&zone_);
+ WasmSerializationTest::BuildWireBytes(zone(), &buffer);
+
+ Isolate* serialization_isolate = CcTest::InitIsolateOnce();
+ ErrorThrower thrower(serialization_isolate, "");
+ {
+ HandleScope scope(serialization_isolate);
+ testing::SetupIsolateForWasmModule(serialization_isolate);
+
+ MaybeHandle<WasmModuleObject> maybe_module_object =
+ serialization_isolate->wasm_engine()->SyncCompile(
+ serialization_isolate, &thrower,
+ ModuleWireBytes(buffer.begin(), buffer.end()));
+ Handle<WasmModuleObject> module_object =
+ maybe_module_object.ToHandleChecked();
+
+ v8::Local<v8::Object> v8_module_obj =
+ v8::Utils::ToLocal(Handle<JSObject>::cast(module_object));
+ CHECK(v8_module_obj->IsWebAssemblyCompiledModule());
+
+ v8::Local<v8::WasmCompiledModule> v8_compiled_module =
+ v8_module_obj.As<v8::WasmCompiledModule>();
+ v8::WasmCompiledModule::BufferReference uncompiled_bytes =
+ v8_compiled_module->GetWasmWireBytesRef();
+ uint8_t* bytes_copy = zone()->NewArray<uint8_t>(uncompiled_bytes.size);
+ memcpy(bytes_copy, uncompiled_bytes.start, uncompiled_bytes.size);
+ wire_bytes_ = {bytes_copy, uncompiled_bytes.size};
+ // keep alive data_ until the end
+ data_ = v8_compiled_module->Serialize();
+ }
+
+ 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());
+ }
+
+ void TearDown() {
+ current_isolate_v8()->Dispose();
+ current_isolate_v8_ = nullptr;
+ }
+
+ v8::internal::AccountingAllocator allocator_;
+ Zone zone_;
+ v8::WasmCompiledModule::SerializedModule data_;
+ v8::WasmCompiledModule::BufferReference wire_bytes_ = {nullptr, 0};
+ v8::WasmCompiledModule::BufferReference serialized_bytes_ = {nullptr, 0};
+ v8::Isolate* current_isolate_v8_;
+};
+
+const char* WasmSerializationTest::kFunctionName = "increment";
+
+TEST(DeserializeValidModule) {
+ WasmSerializationTest test;
+ {
+ HandleScope scope(test.current_isolate());
+ test.DeserializeAndRun();
+ }
+ Cleanup(test.current_isolate());
+ Cleanup();
+}
+
+TEST(DeserializeMismatchingVersion) {
+ WasmSerializationTest test;
+ {
+ HandleScope scope(test.current_isolate());
+ test.InvalidateVersion();
+ test.DeserializeAndRun();
+ }
+ Cleanup(test.current_isolate());
+ Cleanup();
+}
+
+TEST(DeserializeNoSerializedData) {
+ WasmSerializationTest test;
+ {
+ HandleScope scope(test.current_isolate());
+ test.ClearSerializedData();
+ test.DeserializeAndRun();
+ }
+ Cleanup(test.current_isolate());
+ Cleanup();
+}
+
+TEST(DeserializeInvalidLength) {
+ WasmSerializationTest test;
+ {
+ HandleScope scope(test.current_isolate());
+ test.InvalidateLength();
+ test.DeserializeAndRun();
+ }
+ Cleanup(test.current_isolate());
+ Cleanup();
+}
+
+TEST(DeserializeWireBytesAndSerializedDataInvalid) {
+ WasmSerializationTest test;
+ {
+ HandleScope scope(test.current_isolate());
+ test.InvalidateVersion();
+ test.InvalidateWireBytes();
+ test.Deserialize();
+ }
+ Cleanup(test.current_isolate());
+ Cleanup();
+}
+
+bool False(v8::Local<v8::Context> context, v8::Local<v8::String> source) {
+ return false;
+}
+
+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();
+}
+
+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 =
+ from_isolate->wasm_engine()->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());
+ }
+ to_isolate->Dispose();
+ }
+}
+
+#undef EMIT_CODE_WITH_END
+
+} // namespace test_wasm_serialization
+} // namespace wasm
+} // namespace internal
+} // namespace v8