Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Unified Diff: test/unittests/value-serializer-unittest.cc

Issue 2748473004: [wasm] Transferrable modules (Closed)
Patch Set: feedback Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « test/cctest/wasm/test-run-wasm-module.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/unittests/value-serializer-unittest.cc
diff --git a/test/unittests/value-serializer-unittest.cc b/test/unittests/value-serializer-unittest.cc
index c0037efb01709e9c401992d89292422494bf18c1..9f49c6498af92304c13cef6577306a4962111946 100644
--- a/test/unittests/value-serializer-unittest.cc
+++ b/test/unittests/value-serializer-unittest.cc
@@ -74,6 +74,9 @@ class ValueSerializerTest : public TestWithIsolate {
return deserialization_context_;
}
+ bool ExpectInlineWasm() const { return expect_inline_wasm_; }
+ void SetExpectInlineWasm(bool value) { expect_inline_wasm_ = value; }
+
// Overridden in more specific fixtures.
virtual ValueSerializer::Delegate* GetSerializerDelegate() { return nullptr; }
virtual void BeforeEncode(ValueSerializer*) {}
@@ -172,6 +175,7 @@ class ValueSerializerTest : public TestWithIsolate {
static_cast<int>(data.size()),
GetDeserializerDelegate());
deserializer.SetSupportsLegacyWireFormat(true);
+ deserializer.SetExpectInlineWasm(ExpectInlineWasm());
BeforeDecode(&deserializer);
ASSERT_TRUE(deserializer.ReadHeader(context).FromMaybe(false));
Local<Value> result;
@@ -196,6 +200,7 @@ class ValueSerializerTest : public TestWithIsolate {
static_cast<int>(data.size()),
GetDeserializerDelegate());
deserializer.SetSupportsLegacyWireFormat(true);
+ deserializer.SetExpectInlineWasm(ExpectInlineWasm());
BeforeDecode(&deserializer);
ASSERT_TRUE(deserializer.ReadHeader(context).FromMaybe(false));
ASSERT_EQ(0u, deserializer.GetWireFormatVersion());
@@ -219,6 +224,7 @@ class ValueSerializerTest : public TestWithIsolate {
static_cast<int>(data.size()),
GetDeserializerDelegate());
deserializer.SetSupportsLegacyWireFormat(true);
+ deserializer.SetExpectInlineWasm(ExpectInlineWasm());
BeforeDecode(&deserializer);
Maybe<bool> header_result = deserializer.ReadHeader(context);
if (header_result.IsNothing()) {
@@ -275,6 +281,7 @@ class ValueSerializerTest : public TestWithIsolate {
Local<Context> deserialization_context_;
Local<FunctionTemplate> host_object_constructor_template_;
i::Isolate* isolate_;
+ bool expect_inline_wasm_ = false;
DISALLOW_COPY_AND_ASSIGN(ValueSerializerTest);
};
@@ -2594,7 +2601,44 @@ TEST_F(ValueSerializerTestWithHostArrayBufferView, RoundTripUint8ArrayInput) {
// mostly checks that the logic to embed it in structured clone serialization
// works correctly.
+// A simple module which exports an "increment" function.
+// Copied from test/mjsunit/wasm/incrementer.wasm.
+const unsigned char kIncrementerWasm[] = {
+ 0, 97, 115, 109, 1, 0, 0, 0, 1, 6, 1, 96, 1, 127, 1, 127,
+ 3, 2, 1, 0, 7, 13, 1, 9, 105, 110, 99, 114, 101, 109, 101, 110,
+ 116, 0, 0, 10, 9, 1, 7, 0, 32, 0, 65, 1, 106, 11,
+};
+
class ValueSerializerTestWithWasm : public ValueSerializerTest {
+ public:
+ static const char* kUnsupportedSerialization;
+
+ ValueSerializerTestWithWasm()
+ : serialize_delegate_(&transfer_modules_),
+ deserialize_delegate_(&transfer_modules_) {}
+
+ void Reset() {
+ current_serializer_delegate_ = nullptr;
+ transfer_modules_.clear();
+ SetExpectInlineWasm(false);
+ }
+
+ void EnableTransferSerialization() {
+ current_serializer_delegate_ = &serialize_delegate_;
+ }
+
+ void EnableTransferDeserialization() {
+ current_deserializer_delegate_ = &deserialize_delegate_;
+ }
+
+ void EnableThrowingSerializer() {
+ current_serializer_delegate_ = &throwing_serializer_;
+ }
+
+ void EnableDefaultDeserializer() {
+ current_deserializer_delegate_ = &default_deserializer_;
+ }
+
protected:
static void SetUpTestCase() {
g_saved_flag = i::FLAG_expose_wasm;
@@ -2608,32 +2652,243 @@ class ValueSerializerTestWithWasm : public ValueSerializerTest {
g_saved_flag = false;
}
+ class ThrowingSerializer : public ValueSerializer::Delegate {
+ public:
+ Maybe<uint32_t> GetWasmModuleTransferId(
+ Isolate* isolate, Local<WasmCompiledModule> module) override {
+ isolate->ThrowException(Exception::Error(
+ String::NewFromOneByte(
+ isolate,
+ reinterpret_cast<const uint8_t*>(kUnsupportedSerialization),
+ NewStringType::kNormal)
+ .ToLocalChecked()));
+ return Nothing<uint32_t>();
+ }
+
+ void ThrowDataCloneError(Local<String> message) override { UNREACHABLE(); }
+ };
+
+ class SerializeToTransfer : public ValueSerializer::Delegate {
+ public:
+ SerializeToTransfer(
+ std::vector<WasmCompiledModule::TransferrableModule>* modules)
+ : modules_(modules) {}
+ Maybe<uint32_t> GetWasmModuleTransferId(
+ Isolate* isolate, Local<WasmCompiledModule> module) override {
+ modules_->push_back(module->GetTransferrableModule());
+ return Just(static_cast<uint32_t>(modules_->size()) - 1);
+ }
+
+ void ThrowDataCloneError(Local<String> message) override { UNREACHABLE(); }
+
+ private:
+ std::vector<WasmCompiledModule::TransferrableModule>* modules_;
+ };
+
+ class DeserializeFromTransfer : public ValueDeserializer::Delegate {
+ public:
+ DeserializeFromTransfer(
+ std::vector<WasmCompiledModule::TransferrableModule>* modules)
+ : modules_(modules) {}
+
+ MaybeLocal<WasmCompiledModule> GetWasmModuleFromId(Isolate* isolate,
+ uint32_t id) override {
+ return WasmCompiledModule::FromTransferrableModule(isolate,
+ modules_->at(id));
+ }
+
+ private:
+ std::vector<WasmCompiledModule::TransferrableModule>* modules_;
+ };
+
+ ValueSerializer::Delegate* GetSerializerDelegate() override {
+ return current_serializer_delegate_;
+ }
+
+ ValueDeserializer::Delegate* GetDeserializerDelegate() override {
+ return current_deserializer_delegate_;
+ }
+
+ Local<WasmCompiledModule> MakeWasm() {
+ return WasmCompiledModule::DeserializeOrCompile(
+ isolate(), {nullptr, 0},
+ {kIncrementerWasm, sizeof(kIncrementerWasm)})
+ .ToLocalChecked();
+ }
+
+ void ExpectPass() {
+ RoundTripTest(
+ [this]() { return MakeWasm(); },
+ [this](Local<Value> value) {
+ ASSERT_TRUE(value->IsWebAssemblyCompiledModule());
+ EXPECT_TRUE(EvaluateScriptForResultBool(
+ "new WebAssembly.Instance(result).exports.increment(8) === 9"));
+ });
+ }
+
+ void ExpectFail() {
+ EncodeTest(
+ [this]() { return MakeWasm(); },
+ [this](const std::vector<uint8_t>& data) { InvalidDecodeTest(data); });
+ }
+
+ Local<Value> GetComplexObjectWithDuplicate() {
+ Local<Value> wasm_module = MakeWasm();
+ serialization_context()
+ ->Global()
+ ->CreateDataProperty(serialization_context(),
+ StringFromUtf8("wasm_module"), wasm_module)
+ .FromMaybe(false);
+ Local<Script> script =
+ Script::Compile(
+ serialization_context(),
+ StringFromUtf8("({mod1: wasm_module, num: 2, mod2: wasm_module})"))
+ .ToLocalChecked();
+ return script->Run(serialization_context()).ToLocalChecked();
+ }
+
+ void VerifyComplexObject(Local<Value> value) {
+ ASSERT_TRUE(value->IsObject());
+ EXPECT_TRUE(EvaluateScriptForResultBool(
+ "result.mod1 instanceof WebAssembly.Module"));
+ EXPECT_TRUE(EvaluateScriptForResultBool(
+ "result.mod2 instanceof WebAssembly.Module"));
+ EXPECT_TRUE(EvaluateScriptForResultBool("result.num === 2"));
+ }
+
+ Local<Value> GetComplexObjectWithMany() {
+ Local<Value> wasm_module1 = MakeWasm();
+ Local<Value> wasm_module2 = MakeWasm();
+ serialization_context()
+ ->Global()
+ ->CreateDataProperty(serialization_context(),
+ StringFromUtf8("wasm_module1"), wasm_module1)
+ .FromMaybe(false);
+ serialization_context()
+ ->Global()
+ ->CreateDataProperty(serialization_context(),
+ StringFromUtf8("wasm_module2"), wasm_module2)
+ .FromMaybe(false);
+ Local<Script> script =
+ Script::Compile(
+ serialization_context(),
+ StringFromUtf8(
+ "({mod1: wasm_module1, num: 2, mod2: wasm_module2})"))
+ .ToLocalChecked();
+ return script->Run(serialization_context()).ToLocalChecked();
+ }
+
private:
static bool g_saved_flag;
+ std::vector<WasmCompiledModule::TransferrableModule> transfer_modules_;
+ SerializeToTransfer serialize_delegate_;
+ DeserializeFromTransfer deserialize_delegate_;
+ ValueSerializer::Delegate* current_serializer_delegate_ = nullptr;
+ ValueDeserializer::Delegate* current_deserializer_delegate_ = nullptr;
+ ThrowingSerializer throwing_serializer_;
+ ValueDeserializer::Delegate default_deserializer_;
};
bool ValueSerializerTestWithWasm::g_saved_flag = false;
+const char* ValueSerializerTestWithWasm::kUnsupportedSerialization =
+ "Wasm Serialization Not Supported";
+
+// The default implementation of the serialization
+// delegate throws when trying to serialize wasm. The
+// embedder must decide serialization policy.
+TEST_F(ValueSerializerTestWithWasm, DefaultSerializationDelegate) {
+ EnableThrowingSerializer();
+ InvalidEncodeTest(
+ [this]() { return MakeWasm(); },
+ [](Local<Message> message) {
+ size_t msg_len = static_cast<size_t>(message->Get()->Length());
+ std::unique_ptr<char[]> buff(new char[msg_len + 1]);
+ message->Get()->WriteOneByte(reinterpret_cast<uint8_t*>(buff.get()));
+ // the message ends with the custom error string
+ size_t custom_msg_len = strlen(kUnsupportedSerialization);
+ ASSERT_GE(msg_len, custom_msg_len);
+ size_t start_pos = msg_len - custom_msg_len;
+ ASSERT_EQ(strcmp(&buff.get()[start_pos], kUnsupportedSerialization), 0);
+ });
+}
-// A simple module which exports an "increment" function.
-// Copied from test/mjsunit/wasm/incrementer.wasm.
-const unsigned char kIncrementerWasm[] = {
- 0, 97, 115, 109, 1, 0, 0, 0, 1, 6, 1, 96, 1, 127, 1, 127,
- 3, 2, 1, 0, 7, 13, 1, 9, 105, 110, 99, 114, 101, 109, 101, 110,
- 116, 0, 0, 10, 9, 1, 7, 0, 32, 0, 65, 1, 106, 11,
-};
+// The default deserializer throws if wasm transfer is attempted
+TEST_F(ValueSerializerTestWithWasm, DefaultDeserializationDelegate) {
+ EnableTransferSerialization();
+ EnableDefaultDeserializer();
+ EncodeTest(
+ [this]() { return MakeWasm(); },
+ [this](const std::vector<uint8_t>& data) { InvalidDecodeTest(data); });
+}
-TEST_F(ValueSerializerTestWithWasm, RoundTripWasmModule) {
+// We only want to allow deserialization through
+// transferred modules - which requres both serializer
+// and deserializer to understand that - or through
+// explicitly allowing inlined data, which requires
+// deserializer opt-in (we default the serializer to
+// inlined data because we don't trust that data on the
+// receiving end anyway).
+
+TEST_F(ValueSerializerTestWithWasm, RoundtripWasmTransfer) {
+ EnableTransferSerialization();
+ EnableTransferDeserialization();
+ ExpectPass();
+}
+
+TEST_F(ValueSerializerTestWithWasm, RountripWasmInline) {
+ SetExpectInlineWasm(true);
+ ExpectPass();
+}
+
+TEST_F(ValueSerializerTestWithWasm, CannotDeserializeWasmInlineData) {
+ ExpectFail();
+}
+
+TEST_F(ValueSerializerTestWithWasm, CannotTransferWasmWhenExpectingInline) {
+ EnableTransferSerialization();
+ SetExpectInlineWasm(true);
+ ExpectFail();
+}
+
+TEST_F(ValueSerializerTestWithWasm, ComplexObjectDuplicateTransfer) {
+ EnableTransferSerialization();
+ EnableTransferDeserialization();
RoundTripTest(
- [this]() {
- return WasmCompiledModule::DeserializeOrCompile(
- isolate(), {nullptr, 0},
- {kIncrementerWasm, sizeof(kIncrementerWasm)})
- .ToLocalChecked();
- },
+ [this]() { return GetComplexObjectWithDuplicate(); },
[this](Local<Value> value) {
- ASSERT_TRUE(value->IsWebAssemblyCompiledModule());
- EXPECT_TRUE(EvaluateScriptForResultBool(
- "new WebAssembly.Instance(result).exports.increment(8) === 9"));
+ VerifyComplexObject(value);
+ EXPECT_TRUE(EvaluateScriptForResultBool("result.mod1 === result.mod2"));
+ });
+}
+
+TEST_F(ValueSerializerTestWithWasm, ComplexObjectDuplicateInline) {
+ SetExpectInlineWasm(true);
+ RoundTripTest(
+ [this]() { return GetComplexObjectWithDuplicate(); },
+ [this](Local<Value> value) {
+ VerifyComplexObject(value);
+ EXPECT_TRUE(EvaluateScriptForResultBool("result.mod1 === result.mod2"));
+ });
+}
+
+TEST_F(ValueSerializerTestWithWasm, ComplexObjectWithManyTransfer) {
+ EnableTransferSerialization();
+ EnableTransferDeserialization();
+ RoundTripTest(
+ [this]() { return GetComplexObjectWithMany(); },
+ [this](Local<Value> value) {
+ VerifyComplexObject(value);
+ EXPECT_TRUE(EvaluateScriptForResultBool("result.mod1 != result.mod2"));
+ });
+}
+
+TEST_F(ValueSerializerTestWithWasm, ComplexObjectWithManyInline) {
+ SetExpectInlineWasm(true);
+ RoundTripTest(
+ [this]() { return GetComplexObjectWithMany(); },
+ [this](Local<Value> value) {
+ VerifyComplexObject(value);
+ EXPECT_TRUE(EvaluateScriptForResultBool("result.mod1 != result.mod2"));
});
}
« no previous file with comments | « test/cctest/wasm/test-run-wasm-module.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698