LCOV - code coverage report
Current view: top level - test/cctest/wasm - test-wasm-serialization.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 118 118 100.0 %
Date: 2019-04-19 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          48 :   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          48 :   WasmSerializationTest() : zone_(&allocator_, ZONE_NAME) {
      51             :     // Don't call here if we move to gtest.
      52          24 :     SetUp();
      53          24 :   }
      54             : 
      55          32 :   static void BuildWireBytes(Zone* zone, ZoneBuffer* buffer) {
      56          32 :     WasmModuleBuilder* builder = new (zone) WasmModuleBuilder(zone);
      57          32 :     TestSignatures sigs;
      58             : 
      59          32 :     WasmFunctionBuilder* f = builder->AddFunction(sigs.i_i());
      60          32 :     byte code[] = {WASM_GET_LOCAL(0), kExprI32Const, 1, kExprI32Add};
      61          32 :     EMIT_CODE_WITH_END(f, code);
      62          64 :     builder->AddExport(CStrVector(kFunctionName), f);
      63             : 
      64          32 :     builder->WriteTo(*buffer);
      65          32 :   }
      66             : 
      67           4 :   void ClearSerializedData() { serialized_bytes_ = {nullptr, 0}; }
      68             : 
      69             :   void InvalidateVersion() {
      70             :     uint32_t* slot = reinterpret_cast<uint32_t*>(
      71             :         const_cast<uint8_t*>(serialized_bytes_.data()) +
      72             :         SerializedCodeData::kVersionHashOffset);
      73           8 :     *slot = Version::Hash() + 1;
      74             :   }
      75             : 
      76             :   void InvalidateWireBytes() {
      77           4 :     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             :         const_cast<uint8_t*>(serialized_bytes_.data()) +
      83             :         SerializedCodeData::kPayloadLengthOffset);
      84           4 :     *slot = 0u;
      85             :   }
      86             : 
      87          24 :   v8::MaybeLocal<v8::WasmModuleObject> Deserialize() {
      88          24 :     ErrorThrower thrower(current_isolate(), "");
      89             :     v8::MaybeLocal<v8::WasmModuleObject> deserialized =
      90             :         v8::WasmModuleObject::DeserializeOrCompile(
      91          24 :             current_isolate_v8(), serialized_bytes_, wire_bytes_);
      92          48 :     return deserialized;
      93             :   }
      94             : 
      95          16 :   void DeserializeAndRun() {
      96          16 :     ErrorThrower thrower(current_isolate(), "");
      97             :     v8::Local<v8::WasmModuleObject> deserialized_module;
      98          32 :     CHECK(Deserialize().ToLocal(&deserialized_module));
      99             :     Handle<WasmModuleObject> module_object = Handle<WasmModuleObject>::cast(
     100             :         v8::Utils::OpenHandle(*deserialized_module));
     101             :     {
     102             :       DisallowHeapAllocation assume_no_gc;
     103             :       Vector<const byte> deserialized_module_wire_bytes =
     104          32 :           module_object->native_module()->wire_bytes();
     105          16 :       CHECK_EQ(deserialized_module_wire_bytes.size(), wire_bytes_.size());
     106          16 :       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          32 :             ->SyncInstantiate(current_isolate(), &thrower, module_object,
     114             :                               Handle<JSReceiver>::null(),
     115          32 :                               MaybeHandle<JSArrayBuffer>())
     116          16 :             .ToHandleChecked();
     117             :     Handle<Object> params[1] = {
     118             :         Handle<Object>(Smi::FromInt(41), current_isolate())};
     119          16 :     int32_t result = testing::CallWasmFunctionForTesting(
     120          16 :         current_isolate(), instance, &thrower, kFunctionName, 1, params);
     121          16 :     CHECK_EQ(42, result);
     122          16 :   }
     123             : 
     124             :   Isolate* current_isolate() {
     125             :     return reinterpret_cast<Isolate*>(current_isolate_v8_);
     126             :   }
     127             : 
     128          48 :   ~WasmSerializationTest() {
     129             :     // Don't call from here if we move to gtest
     130             :     TearDown();
     131          24 :   }
     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          24 :   void SetUp() {
     141          24 :     ZoneBuffer buffer(&zone_);
     142          24 :     WasmSerializationTest::BuildWireBytes(zone(), &buffer);
     143             : 
     144             :     Isolate* serialization_isolate = CcTest::InitIsolateOnce();
     145          24 :     ErrorThrower thrower(serialization_isolate, "");
     146             :     {
     147             :       HandleScope scope(serialization_isolate);
     148          24 :       testing::SetupIsolateForWasmModule(serialization_isolate);
     149             : 
     150          24 :       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          24 :               ModuleWireBytes(buffer.begin(), buffer.end()));
     155             :       Handle<WasmModuleObject> module_object =
     156             :           maybe_module_object.ToHandleChecked();
     157             : 
     158             :       v8::Local<v8::Object> v8_module_obj =
     159             :           v8::Utils::ToLocal(Handle<JSObject>::cast(module_object));
     160          24 :       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          24 :           v8_module_object->GetCompiledModule();
     166             :       v8::MemorySpan<const uint8_t> uncompiled_bytes =
     167          24 :           compiled_module.GetWireBytesRef();
     168             :       uint8_t* bytes_copy = zone()->NewArray<uint8_t>(uncompiled_bytes.size());
     169             :       memcpy(bytes_copy, uncompiled_bytes.data(), uncompiled_bytes.size());
     170          24 :       wire_bytes_ = {bytes_copy, uncompiled_bytes.size()};
     171             :       // keep alive data_ until the end
     172          48 :       data_ = compiled_module.Serialize();
     173             :     }
     174             : 
     175          24 :     serialized_bytes_ = {data_.buffer.get(), data_.size};
     176             : 
     177             :     v8::Isolate::CreateParams create_params;
     178             :     create_params.array_buffer_allocator =
     179          24 :         serialization_isolate->array_buffer_allocator();
     180             : 
     181          24 :     current_isolate_v8_ = v8::Isolate::New(create_params);
     182          48 :     v8::HandleScope new_scope(current_isolate_v8());
     183             :     v8::Local<v8::Context> deserialization_context =
     184          24 :         v8::Context::New(current_isolate_v8());
     185          24 :     deserialization_context->Enter();
     186          24 :     testing::SetupIsolateForWasmModule(current_isolate());
     187          24 :   }
     188             : 
     189             :   void TearDown() {
     190          24 :     current_isolate_v8()->Dispose();
     191          24 :     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       26660 : TEST(DeserializeValidModule) {
     205           8 :   WasmSerializationTest test;
     206             :   {
     207             :     HandleScope scope(test.current_isolate());
     208           4 :     test.DeserializeAndRun();
     209             :   }
     210             :   Cleanup(test.current_isolate());
     211             :   Cleanup();
     212           4 : }
     213             : 
     214       26660 : TEST(DeserializeMismatchingVersion) {
     215           8 :   WasmSerializationTest test;
     216             :   {
     217             :     HandleScope scope(test.current_isolate());
     218             :     test.InvalidateVersion();
     219           4 :     test.DeserializeAndRun();
     220             :   }
     221             :   Cleanup(test.current_isolate());
     222             :   Cleanup();
     223           4 : }
     224             : 
     225       26660 : TEST(DeserializeNoSerializedData) {
     226           8 :   WasmSerializationTest test;
     227             :   {
     228             :     HandleScope scope(test.current_isolate());
     229             :     test.ClearSerializedData();
     230           4 :     test.DeserializeAndRun();
     231             :   }
     232             :   Cleanup(test.current_isolate());
     233             :   Cleanup();
     234           4 : }
     235             : 
     236       26660 : TEST(DeserializeInvalidLength) {
     237           8 :   WasmSerializationTest test;
     238             :   {
     239             :     HandleScope scope(test.current_isolate());
     240             :     test.InvalidateLength();
     241           4 :     test.DeserializeAndRun();
     242             :   }
     243             :   Cleanup(test.current_isolate());
     244             :   Cleanup();
     245           4 : }
     246             : 
     247       26660 : TEST(DeserializeWireBytesAndSerializedDataInvalid) {
     248           8 :   WasmSerializationTest test;
     249             :   {
     250             :     HandleScope scope(test.current_isolate());
     251             :     test.InvalidateVersion();
     252             :     test.InvalidateWireBytes();
     253           4 :     test.Deserialize();
     254             :   }
     255             :   Cleanup(test.current_isolate());
     256             :   Cleanup();
     257           4 : }
     258             : 
     259           8 : bool False(v8::Local<v8::Context> context, v8::Local<v8::String> source) {
     260           8 :   return false;
     261             : }
     262             : 
     263       26660 : TEST(BlockWasmCodeGenAtDeserialization) {
     264           8 :   WasmSerializationTest test;
     265             :   {
     266             :     HandleScope scope(test.current_isolate());
     267           4 :     test.current_isolate_v8()->SetAllowCodeGenerationFromStringsCallback(False);
     268           4 :     v8::MaybeLocal<v8::WasmModuleObject> nothing = test.Deserialize();
     269           4 :     CHECK(nothing.IsEmpty());
     270             :   }
     271             :   Cleanup(test.current_isolate());
     272             :   Cleanup();
     273           4 : }
     274             : 
     275             : namespace {
     276             : 
     277           8 : void TestTransferrableWasmModules(bool should_share) {
     278           8 :   i::wasm::WasmEngine::InitializeOncePerProcess();
     279          16 :   v8::internal::AccountingAllocator allocator;
     280          16 :   Zone zone(&allocator, ZONE_NAME);
     281             : 
     282             :   ZoneBuffer buffer(&zone);
     283           8 :   WasmSerializationTest::BuildWireBytes(&zone, &buffer);
     284             : 
     285             :   v8::Isolate::CreateParams create_params;
     286           8 :   create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
     287           8 :   v8::Isolate* from_isolate = v8::Isolate::New(create_params);
     288           8 :   std::vector<v8::WasmModuleObject::TransferrableModule> store;
     289           8 :   std::shared_ptr<NativeModule> original_native_module;
     290             :   {
     291          16 :     v8::HandleScope scope(from_isolate);
     292           8 :     LocalContext env(from_isolate);
     293             : 
     294             :     Isolate* from_i_isolate = reinterpret_cast<Isolate*>(from_isolate);
     295           8 :     testing::SetupIsolateForWasmModule(from_i_isolate);
     296           8 :     ErrorThrower thrower(from_i_isolate, "TestTransferrableWasmModules");
     297           8 :     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           8 :             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             :             v8::Utils::ToLocal(Handle<JSObject>::cast(module_object)));
     307          16 :     store.push_back(v8_module->GetTransferrableModule());
     308             :     original_native_module = module_object->shared_native_module();
     309             :   }
     310             : 
     311             :   {
     312           8 :     v8::Isolate* to_isolate = v8::Isolate::New(create_params);
     313             :     {
     314          16 :       v8::HandleScope scope(to_isolate);
     315           8 :       LocalContext env(to_isolate);
     316             : 
     317             :       v8::MaybeLocal<v8::WasmModuleObject> transferred_module =
     318           8 :           v8::WasmModuleObject::FromTransferrableModule(to_isolate, store[0]);
     319           8 :       CHECK(!transferred_module.IsEmpty());
     320             :       Handle<WasmModuleObject> module_object = Handle<WasmModuleObject>::cast(
     321             :           v8::Utils::OpenHandle(*transferred_module.ToLocalChecked()));
     322             :       std::shared_ptr<NativeModule> transferred_native_module =
     323             :           module_object->shared_native_module();
     324             :       bool is_sharing = (original_native_module == transferred_native_module);
     325           8 :       CHECK_EQ(should_share, is_sharing);
     326             :     }
     327           8 :     to_isolate->Dispose();
     328             :   }
     329             :   original_native_module.reset();
     330           8 :   from_isolate->Dispose();
     331           8 : }
     332             : 
     333             : }  // namespace
     334             : 
     335       26660 : UNINITIALIZED_TEST(TransferrableWasmModulesCloned) {
     336             :   FlagScope<bool> flag_scope_code(&FLAG_wasm_shared_code, false);
     337           4 :   TestTransferrableWasmModules(false);
     338           4 : }
     339             : 
     340       26660 : 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           4 :   TestTransferrableWasmModules(true);
     344           4 : }
     345             : 
     346             : #undef EMIT_CODE_WITH_END
     347             : 
     348             : }  // namespace test_wasm_serialization
     349             : }  // namespace wasm
     350             : }  // namespace internal
     351       79968 : }  // namespace v8

Generated by: LCOV version 1.10