LCOV - code coverage report
Current view: top level - test/cctest/wasm - test-wasm-serialization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 142 142 100.0 %
Date: 2019-01-20 Functions: 18 18 100.0 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <stdlib.h>
       6             : #include <string.h>
       7             : 
       8             : #include "src/api-inl.h"
       9             : #include "src/objects-inl.h"
      10             : #include "src/snapshot/code-serializer.h"
      11             : #include "src/version.h"
      12             : #include "src/wasm/module-decoder.h"
      13             : #include "src/wasm/wasm-engine.h"
      14             : #include "src/wasm/wasm-memory.h"
      15             : #include "src/wasm/wasm-module-builder.h"
      16             : #include "src/wasm/wasm-module.h"
      17             : #include "src/wasm/wasm-objects-inl.h"
      18             : #include "src/wasm/wasm-opcodes.h"
      19             : 
      20             : #include "test/cctest/cctest.h"
      21             : #include "test/common/wasm/flag-utils.h"
      22             : #include "test/common/wasm/test-signatures.h"
      23             : #include "test/common/wasm/wasm-macro-gen.h"
      24             : #include "test/common/wasm/wasm-module-runner.h"
      25             : 
      26             : namespace v8 {
      27             : namespace internal {
      28             : namespace wasm {
      29             : namespace test_wasm_serialization {
      30             : 
      31             : namespace {
      32             : void Cleanup(Isolate* isolate = CcTest::InitIsolateOnce()) {
      33             :   // By sending a low memory notifications, we will try hard to collect all
      34             :   // garbage and will therefore also invoke all weak callbacks of actually
      35             :   // unreachable persistent handles.
      36          60 :   reinterpret_cast<v8::Isolate*>(isolate)->LowMemoryNotification();
      37             : }
      38             : 
      39             : #define EMIT_CODE_WITH_END(f, code)  \
      40             :   do {                               \
      41             :     f->EmitCode(code, sizeof(code)); \
      42             :     f->Emit(kExprEnd);               \
      43             :   } while (false)
      44             : 
      45             : }  // namespace
      46             : 
      47             : // Approximate gtest TEST_F style, in case we adopt gtest.
      48             : class WasmSerializationTest {
      49             :  public:
      50          30 :   WasmSerializationTest() : zone_(&allocator_, ZONE_NAME) {
      51             :     // Don't call here if we move to gtest.
      52          30 :     SetUp();
      53          30 :   }
      54             : 
      55          40 :   static void BuildWireBytes(Zone* zone, ZoneBuffer* buffer) {
      56          40 :     WasmModuleBuilder* builder = new (zone) WasmModuleBuilder(zone);
      57          40 :     TestSignatures sigs;
      58             : 
      59          40 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
      60          40 :     byte code[] = {WASM_GET_LOCAL(0), kExprI32Const, 1, kExprI32Add};
      61          40 :     EMIT_CODE_WITH_END(f, code);
      62          80 :     builder->AddExport(CStrVector(kFunctionName), f);
      63             : 
      64          40 :     builder->WriteTo(*buffer);
      65          40 :   }
      66             : 
      67           5 :   void ClearSerializedData() { serialized_bytes_ = {nullptr, 0}; }
      68             : 
      69             :   void InvalidateVersion() {
      70             :     uint32_t* slot = reinterpret_cast<uint32_t*>(
      71          10 :         const_cast<uint8_t*>(serialized_bytes_.data()) +
      72             :         SerializedCodeData::kVersionHashOffset);
      73          10 :     *slot = Version::Hash() + 1;
      74             :   }
      75             : 
      76             :   void InvalidateWireBytes() {
      77           5 :     memset(const_cast<uint8_t*>(wire_bytes_.data()), 0, wire_bytes_.size() / 2);
      78             :   }
      79             : 
      80             :   void InvalidateLength() {
      81             :     uint32_t* slot = reinterpret_cast<uint32_t*>(
      82           5 :         const_cast<uint8_t*>(serialized_bytes_.data()) +
      83             :         SerializedCodeData::kPayloadLengthOffset);
      84           5 :     *slot = 0u;
      85             :   }
      86             : 
      87          30 :   v8::MaybeLocal<v8::WasmModuleObject> Deserialize() {
      88             :     ErrorThrower thrower(current_isolate(), "");
      89             :     v8::MaybeLocal<v8::WasmModuleObject> deserialized =
      90             :         v8::WasmModuleObject::DeserializeOrCompile(
      91          30 :             current_isolate_v8(), serialized_bytes_, wire_bytes_);
      92          30 :     return deserialized;
      93             :   }
      94             : 
      95          80 :   void DeserializeAndRun() {
      96             :     ErrorThrower thrower(current_isolate(), "");
      97             :     v8::Local<v8::WasmModuleObject> deserialized_module;
      98          40 :     CHECK(Deserialize().ToLocal(&deserialized_module));
      99             :     Handle<WasmModuleObject> module_object = Handle<WasmModuleObject>::cast(
     100          20 :         v8::Utils::OpenHandle(*deserialized_module));
     101             :     {
     102             :       DisallowHeapAllocation assume_no_gc;
     103             :       Vector<const byte> deserialized_module_wire_bytes =
     104          40 :           module_object->native_module()->wire_bytes();
     105          20 :       CHECK_EQ(deserialized_module_wire_bytes.size(), wire_bytes_.size());
     106          20 :       CHECK_EQ(memcmp(deserialized_module_wire_bytes.start(),
     107             :                       wire_bytes_.data(), wire_bytes_.size()),
     108             :                0);
     109             :     }
     110             :     Handle<WasmInstanceObject> instance =
     111             :         current_isolate()
     112             :             ->wasm_engine()
     113             :             ->SyncInstantiate(current_isolate(), &thrower, module_object,
     114             :                               Handle<JSReceiver>::null(),
     115          40 :                               MaybeHandle<JSArrayBuffer>())
     116          40 :             .ToHandleChecked();
     117             :     Handle<Object> params[1] = {
     118             :         Handle<Object>(Smi::FromInt(41), current_isolate())};
     119             :     int32_t result = testing::CallWasmFunctionForTesting(
     120          40 :         current_isolate(), instance, &thrower, kFunctionName, 1, params);
     121          20 :     CHECK_EQ(42, result);
     122          20 :   }
     123             : 
     124             :   Isolate* current_isolate() {
     125             :     return reinterpret_cast<Isolate*>(current_isolate_v8_);
     126             :   }
     127             : 
     128          60 :   ~WasmSerializationTest() {
     129             :     // Don't call from here if we move to gtest
     130             :     TearDown();
     131          30 :   }
     132             : 
     133             :   v8::Isolate* current_isolate_v8() { return current_isolate_v8_; }
     134             : 
     135             :  private:
     136             :   static const char* kFunctionName;
     137             : 
     138             :   Zone* zone() { return &zone_; }
     139             : 
     140          90 :   void SetUp() {
     141          30 :     ZoneBuffer buffer(&zone_);
     142          30 :     WasmSerializationTest::BuildWireBytes(zone(), &buffer);
     143             : 
     144          60 :     Isolate* serialization_isolate = CcTest::InitIsolateOnce();
     145             :     ErrorThrower thrower(serialization_isolate, "");
     146             :     {
     147             :       HandleScope scope(serialization_isolate);
     148          30 :       testing::SetupIsolateForWasmModule(serialization_isolate);
     149             : 
     150          30 :       auto enabled_features = WasmFeaturesFromIsolate(serialization_isolate);
     151             :       MaybeHandle<WasmModuleObject> maybe_module_object =
     152             :           serialization_isolate->wasm_engine()->SyncCompile(
     153             :               serialization_isolate, enabled_features, &thrower,
     154          60 :               ModuleWireBytes(buffer.begin(), buffer.end()));
     155             :       Handle<WasmModuleObject> module_object =
     156          30 :           maybe_module_object.ToHandleChecked();
     157             : 
     158             :       v8::Local<v8::Object> v8_module_obj =
     159          30 :           v8::Utils::ToLocal(Handle<JSObject>::cast(module_object));
     160          30 :       CHECK(v8_module_obj->IsWebAssemblyCompiledModule());
     161             : 
     162             :       v8::Local<v8::WasmModuleObject> v8_module_object =
     163             :           v8_module_obj.As<v8::WasmModuleObject>();
     164             :       v8::CompiledWasmModule compiled_module =
     165          30 :           v8_module_object->GetCompiledModule();
     166             :       v8::MemorySpan<const uint8_t> uncompiled_bytes =
     167          30 :           compiled_module.GetWireBytesRef();
     168             :       uint8_t* bytes_copy = zone()->NewArray<uint8_t>(uncompiled_bytes.size());
     169          30 :       memcpy(bytes_copy, uncompiled_bytes.data(), uncompiled_bytes.size());
     170          30 :       wire_bytes_ = {bytes_copy, uncompiled_bytes.size()};
     171             :       // keep alive data_ until the end
     172          60 :       data_ = compiled_module.Serialize();
     173             :     }
     174             : 
     175          60 :     serialized_bytes_ = {data_.buffer.get(), data_.size};
     176             : 
     177             :     v8::Isolate::CreateParams create_params;
     178             :     create_params.array_buffer_allocator =
     179          30 :         serialization_isolate->array_buffer_allocator();
     180             : 
     181          30 :     current_isolate_v8_ = v8::Isolate::New(create_params);
     182          60 :     v8::HandleScope new_scope(current_isolate_v8());
     183             :     v8::Local<v8::Context> deserialization_context =
     184          30 :         v8::Context::New(current_isolate_v8());
     185          30 :     deserialization_context->Enter();
     186          60 :     testing::SetupIsolateForWasmModule(current_isolate());
     187          30 :   }
     188             : 
     189          30 :   void TearDown() {
     190          30 :     current_isolate_v8()->Dispose();
     191          30 :     current_isolate_v8_ = nullptr;
     192             :   }
     193             : 
     194             :   v8::internal::AccountingAllocator allocator_;
     195             :   Zone zone_;
     196             :   v8::OwnedBuffer data_;
     197             :   v8::MemorySpan<const uint8_t> wire_bytes_ = {nullptr, 0};
     198             :   v8::MemorySpan<const uint8_t> serialized_bytes_ = {nullptr, 0};
     199             :   v8::Isolate* current_isolate_v8_;
     200             : };
     201             : 
     202             : const char* WasmSerializationTest::kFunctionName = "increment";
     203             : 
     204       28342 : TEST(DeserializeValidModule) {
     205           5 :   WasmSerializationTest test;
     206             :   {
     207           5 :     HandleScope scope(test.current_isolate());
     208           5 :     test.DeserializeAndRun();
     209             :   }
     210           5 :   Cleanup(test.current_isolate());
     211          10 :   Cleanup();
     212           5 : }
     213             : 
     214       28342 : TEST(DeserializeMismatchingVersion) {
     215           5 :   WasmSerializationTest test;
     216             :   {
     217           5 :     HandleScope scope(test.current_isolate());
     218             :     test.InvalidateVersion();
     219           5 :     test.DeserializeAndRun();
     220             :   }
     221           5 :   Cleanup(test.current_isolate());
     222          10 :   Cleanup();
     223           5 : }
     224             : 
     225       28342 : TEST(DeserializeNoSerializedData) {
     226           5 :   WasmSerializationTest test;
     227             :   {
     228           5 :     HandleScope scope(test.current_isolate());
     229             :     test.ClearSerializedData();
     230           5 :     test.DeserializeAndRun();
     231             :   }
     232           5 :   Cleanup(test.current_isolate());
     233          10 :   Cleanup();
     234           5 : }
     235             : 
     236       28342 : TEST(DeserializeInvalidLength) {
     237           5 :   WasmSerializationTest test;
     238             :   {
     239           5 :     HandleScope scope(test.current_isolate());
     240             :     test.InvalidateLength();
     241           5 :     test.DeserializeAndRun();
     242             :   }
     243           5 :   Cleanup(test.current_isolate());
     244          10 :   Cleanup();
     245           5 : }
     246             : 
     247       28342 : TEST(DeserializeWireBytesAndSerializedDataInvalid) {
     248           5 :   WasmSerializationTest test;
     249             :   {
     250           5 :     HandleScope scope(test.current_isolate());
     251             :     test.InvalidateVersion();
     252             :     test.InvalidateWireBytes();
     253           5 :     test.Deserialize();
     254             :   }
     255           5 :   Cleanup(test.current_isolate());
     256          10 :   Cleanup();
     257           5 : }
     258             : 
     259          10 : bool False(v8::Local<v8::Context> context, v8::Local<v8::String> source) {
     260          10 :   return false;
     261             : }
     262             : 
     263       28342 : TEST(BlockWasmCodeGenAtDeserialization) {
     264           5 :   WasmSerializationTest test;
     265             :   {
     266           5 :     HandleScope scope(test.current_isolate());
     267           5 :     test.current_isolate_v8()->SetAllowCodeGenerationFromStringsCallback(False);
     268           5 :     v8::MaybeLocal<v8::WasmModuleObject> nothing = test.Deserialize();
     269           5 :     CHECK(nothing.IsEmpty());
     270             :   }
     271           5 :   Cleanup(test.current_isolate());
     272          10 :   Cleanup();
     273           5 : }
     274             : 
     275             : namespace {
     276             : 
     277          10 : void TestTransferrableWasmModules(bool should_share) {
     278          10 :   i::wasm::WasmEngine::InitializeOncePerProcess();
     279          10 :   v8::internal::AccountingAllocator allocator;
     280          20 :   Zone zone(&allocator, ZONE_NAME);
     281             : 
     282             :   ZoneBuffer buffer(&zone);
     283          10 :   WasmSerializationTest::BuildWireBytes(&zone, &buffer);
     284             : 
     285             :   v8::Isolate::CreateParams create_params;
     286          10 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     287          10 :   v8::Isolate* from_isolate = v8::Isolate::New(create_params);
     288          10 :   std::vector<v8::WasmModuleObject::TransferrableModule> store;
     289             :   std::shared_ptr<NativeModule> original_native_module;
     290             :   {
     291          10 :     v8::HandleScope scope(from_isolate);
     292          10 :     LocalContext env(from_isolate);
     293             : 
     294             :     Isolate* from_i_isolate = reinterpret_cast<Isolate*>(from_isolate);
     295          10 :     testing::SetupIsolateForWasmModule(from_i_isolate);
     296          10 :     ErrorThrower thrower(from_i_isolate, "TestTransferrableWasmModules");
     297          10 :     auto enabled_features = WasmFeaturesFromIsolate(from_i_isolate);
     298             :     MaybeHandle<WasmModuleObject> maybe_module_object =
     299             :         from_i_isolate->wasm_engine()->SyncCompile(
     300             :             from_i_isolate, enabled_features, &thrower,
     301          20 :             ModuleWireBytes(buffer.begin(), buffer.end()));
     302             :     Handle<WasmModuleObject> module_object =
     303             :         maybe_module_object.ToHandleChecked();
     304             :     v8::Local<v8::WasmModuleObject> v8_module =
     305             :         v8::Local<v8::WasmModuleObject>::Cast(
     306          10 :             v8::Utils::ToLocal(Handle<JSObject>::cast(module_object)));
     307          20 :     store.push_back(v8_module->GetTransferrableModule());
     308          30 :     original_native_module = module_object->shared_native_module();
     309             :   }
     310             : 
     311             :   {
     312          10 :     v8::Isolate* to_isolate = v8::Isolate::New(create_params);
     313             :     {
     314          10 :       v8::HandleScope scope(to_isolate);
     315          10 :       LocalContext env(to_isolate);
     316             : 
     317             :       v8::MaybeLocal<v8::WasmModuleObject> transferred_module =
     318          10 :           v8::WasmModuleObject::FromTransferrableModule(to_isolate, store[0]);
     319          10 :       CHECK(!transferred_module.IsEmpty());
     320             :       Handle<WasmModuleObject> module_object = Handle<WasmModuleObject>::cast(
     321          10 :           v8::Utils::OpenHandle(*transferred_module.ToLocalChecked()));
     322             :       std::shared_ptr<NativeModule> transferred_native_module =
     323          10 :           module_object->shared_native_module();
     324             :       bool is_sharing = (original_native_module == transferred_native_module);
     325          20 :       CHECK_EQ(should_share, is_sharing);
     326             :     }
     327          10 :     to_isolate->Dispose();
     328             :   }
     329             :   original_native_module.reset();
     330          20 :   from_isolate->Dispose();
     331          10 : }
     332             : 
     333             : }  // namespace
     334             : 
     335       28342 : UNINITIALIZED_TEST(TransferrableWasmModulesCloned) {
     336             :   FlagScope<bool> flag_scope_code(&FLAG_wasm_shared_code, false);
     337           5 :   TestTransferrableWasmModules(false);
     338           5 : }
     339             : 
     340       28342 : UNINITIALIZED_TEST(TransferrableWasmModulesShared) {
     341             :   FlagScope<bool> flag_scope_engine(&FLAG_wasm_shared_engine, true);
     342             :   FlagScope<bool> flag_scope_code(&FLAG_wasm_shared_code, true);
     343           5 :   TestTransferrableWasmModules(true);
     344           5 : }
     345             : 
     346             : #undef EMIT_CODE_WITH_END
     347             : 
     348             : }  // namespace test_wasm_serialization
     349             : }  // namespace wasm
     350             : }  // namespace internal
     351       85011 : }  // namespace v8

Generated by: LCOV version 1.10