LCOV - code coverage report
Current view: top level - test/cctest/wasm - test-wasm-shared-engine.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 185 189 97.9 %
Date: 2019-04-17 Functions: 33 39 84.6 %

          Line data    Source code
       1             : // Copyright 2018 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 <memory>
       6             : 
       7             : #include "src/microtask-queue.h"
       8             : #include "src/objects-inl.h"
       9             : #include "src/wasm/function-compiler.h"
      10             : #include "src/wasm/wasm-engine.h"
      11             : #include "src/wasm/wasm-module-builder.h"
      12             : #include "src/wasm/wasm-module.h"
      13             : #include "src/wasm/wasm-objects-inl.h"
      14             : 
      15             : #include "test/cctest/cctest.h"
      16             : #include "test/common/wasm/test-signatures.h"
      17             : #include "test/common/wasm/wasm-macro-gen.h"
      18             : #include "test/common/wasm/wasm-module-runner.h"
      19             : 
      20             : namespace v8 {
      21             : namespace internal {
      22             : namespace wasm {
      23             : namespace test_wasm_shared_engine {
      24             : 
      25             : // Helper class representing a WebAssembly engine that is capable of being
      26             : // shared between multiple Isolates, sharing the underlying generated code.
      27             : class SharedEngine {
      28             :  public:
      29          28 :   explicit SharedEngine(size_t max_committed = kMaxWasmCodeMemory)
      30          28 :       : wasm_engine_(base::make_unique<WasmEngine>()) {}
      31          56 :   ~SharedEngine() {
      32             :     // Ensure no remaining uses exist.
      33          28 :     CHECK(wasm_engine_.unique());
      34          28 :   }
      35             : 
      36             :   WasmEngine* engine() const { return wasm_engine_.get(); }
      37             :   WasmCodeManager* code_manager() const { return engine()->code_manager(); }
      38             : 
      39             :   int NumberOfExportedEngineUses() const {
      40             :     // This class holds one implicit use itself, which we discount.
      41          24 :     return static_cast<int>(wasm_engine_.use_count()) - 1;
      42             :   }
      43             : 
      44             :   std::shared_ptr<WasmEngine> ExportEngineForSharing() { return wasm_engine_; }
      45             : 
      46             :  private:
      47             :   std::shared_ptr<WasmEngine> wasm_engine_;
      48             : };
      49             : 
      50             : // Helper type definition representing a WebAssembly module shared between
      51             : // multiple Isolates with implicit reference counting.
      52             : using SharedModule = std::shared_ptr<NativeModule>;
      53             : 
      54             : // Helper class representing an Isolate based on a given shared WebAssembly
      55             : // engine available at construction time.
      56             : class SharedEngineIsolate {
      57             :  public:
      58          84 :   explicit SharedEngineIsolate(SharedEngine* engine)
      59          84 :       : isolate_(v8::Isolate::Allocate()) {
      60         168 :     isolate()->SetWasmEngine(engine->ExportEngineForSharing());
      61             :     v8::Isolate::CreateParams create_params;
      62          84 :     create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
      63          84 :     v8::Isolate::Initialize(isolate_, create_params);
      64         168 :     v8::HandleScope handle_scope(v8_isolate());
      65         168 :     v8::Context::New(v8_isolate())->Enter();
      66          84 :     testing::SetupIsolateForWasmModule(isolate());
      67          84 :     zone_.reset(new Zone(isolate()->allocator(), ZONE_NAME));
      68          84 :   }
      69         166 :   ~SharedEngineIsolate() {
      70          83 :     zone_.reset();
      71          84 :     isolate_->Dispose();
      72          83 :   }
      73             : 
      74             :   Zone* zone() const { return zone_.get(); }
      75             :   v8::Isolate* v8_isolate() { return isolate_; }
      76             :   Isolate* isolate() { return reinterpret_cast<Isolate*>(isolate_); }
      77             : 
      78          28 :   Handle<WasmInstanceObject> CompileAndInstantiate(ZoneBuffer* buffer) {
      79          28 :     ErrorThrower thrower(isolate(), "CompileAndInstantiate");
      80             :     MaybeHandle<WasmInstanceObject> instance =
      81             :         testing::CompileAndInstantiateForTesting(
      82             :             isolate(), &thrower,
      83          28 :             ModuleWireBytes(buffer->begin(), buffer->end()));
      84          28 :     return instance.ToHandleChecked();
      85             :   }
      86             : 
      87          36 :   Handle<WasmInstanceObject> ImportInstance(SharedModule shared_module) {
      88             :     Handle<WasmModuleObject> module_object =
      89          72 :         isolate()->wasm_engine()->ImportNativeModule(isolate(), shared_module);
      90          36 :     ErrorThrower thrower(isolate(), "ImportInstance");
      91             :     MaybeHandle<WasmInstanceObject> instance =
      92             :         isolate()->wasm_engine()->SyncInstantiate(isolate(), &thrower,
      93          36 :                                                   module_object, {}, {});
      94          36 :     return instance.ToHandleChecked();
      95             :   }
      96             : 
      97          12 :   SharedModule ExportInstance(Handle<WasmInstanceObject> instance) {
      98          12 :     return instance->module_object()->shared_native_module();
      99             :   }
     100             : 
     101             :   int32_t Run(Handle<WasmInstanceObject> instance) {
     102        2044 :     return testing::RunWasmModuleForTesting(isolate(), instance, 0, nullptr);
     103             :   }
     104             : 
     105             :  private:
     106             :   v8::Isolate* isolate_;
     107             :   std::unique_ptr<Zone> zone_;
     108             : };
     109             : 
     110             : // Helper class representing a Thread running its own instance of an Isolate
     111             : // with a shared WebAssembly engine available at construction time.
     112          96 : class SharedEngineThread : public v8::base::Thread {
     113             :  public:
     114          48 :   SharedEngineThread(SharedEngine* engine,
     115             :                      std::function<void(SharedEngineIsolate&)> callback)
     116             :       : Thread(Options("SharedEngineThread")),
     117             :         engine_(engine),
     118          96 :         callback_(callback) {}
     119             : 
     120          48 :   void Run() override {
     121          95 :     SharedEngineIsolate isolate(engine_);
     122             :     callback_(isolate);
     123          47 :   }
     124             : 
     125             :  private:
     126             :   SharedEngine* engine_;
     127             :   std::function<void(SharedEngineIsolate&)> callback_;
     128             : };
     129             : 
     130             : namespace {
     131             : 
     132          36 : ZoneBuffer* BuildReturnConstantModule(Zone* zone, int constant) {
     133          36 :   TestSignatures sigs;
     134             :   ZoneBuffer* buffer = new (zone) ZoneBuffer(zone);
     135          36 :   WasmModuleBuilder* builder = new (zone) WasmModuleBuilder(zone);
     136          36 :   WasmFunctionBuilder* f = builder->AddFunction(sigs.i_v());
     137          36 :   f->builder()->AddExport(CStrVector("main"), f);
     138          36 :   byte code[] = {WASM_I32V_2(constant)};
     139          36 :   f->EmitCode(code, sizeof(code));
     140          36 :   f->Emit(kExprEnd);
     141          36 :   builder->WriteTo(*buffer);
     142          36 :   return buffer;
     143             : }
     144             : 
     145          14 : class MockInstantiationResolver : public InstantiationResultResolver {
     146             :  public:
     147             :   explicit MockInstantiationResolver(Handle<Object>* out_instance)
     148           8 :       : out_instance_(out_instance) {}
     149           8 :   void OnInstantiationSucceeded(Handle<WasmInstanceObject> result) override {
     150          16 :     *out_instance_->location() = result->ptr();
     151           8 :   }
     152           0 :   void OnInstantiationFailed(Handle<Object> error_reason) override {
     153           0 :     UNREACHABLE();
     154             :   }
     155             : 
     156             :  private:
     157             :   Handle<Object>* out_instance_;
     158             : };
     159             : 
     160          14 : class MockCompilationResolver : public CompilationResultResolver {
     161             :  public:
     162             :   MockCompilationResolver(SharedEngineIsolate& isolate,
     163             :                           Handle<Object>* out_instance)
     164           8 :       : isolate_(isolate), out_instance_(out_instance) {}
     165           8 :   void OnCompilationSucceeded(Handle<WasmModuleObject> result) override {
     166          16 :     isolate_.isolate()->wasm_engine()->AsyncInstantiate(
     167           8 :         isolate_.isolate(),
     168             :         base::make_unique<MockInstantiationResolver>(out_instance_), result,
     169           8 :         {});
     170           8 :   }
     171           0 :   void OnCompilationFailed(Handle<Object> error_reason) override {
     172           0 :     UNREACHABLE();
     173             :   }
     174             : 
     175             :  private:
     176             :   SharedEngineIsolate& isolate_;
     177             :   Handle<Object>* out_instance_;
     178             : };
     179             : 
     180          21 : void PumpMessageLoop(SharedEngineIsolate& isolate) {
     181          21 :   v8::platform::PumpMessageLoop(i::V8::GetCurrentPlatform(),
     182             :                                 isolate.v8_isolate(),
     183          21 :                                 platform::MessageLoopBehavior::kWaitForWork);
     184             :   isolate.isolate()->default_microtask_queue()->RunMicrotasks(
     185          20 :       isolate.isolate());
     186          21 : }
     187             : 
     188           8 : Handle<WasmInstanceObject> CompileAndInstantiateAsync(
     189             :     SharedEngineIsolate& isolate, ZoneBuffer* buffer) {
     190           8 :   Handle<Object> maybe_instance = handle(Smi::kZero, isolate.isolate());
     191           8 :   auto enabled_features = WasmFeaturesFromIsolate(isolate.isolate());
     192          16 :   isolate.isolate()->wasm_engine()->AsyncCompile(
     193             :       isolate.isolate(), enabled_features,
     194           8 :       base::make_unique<MockCompilationResolver>(isolate, &maybe_instance),
     195           8 :       ModuleWireBytes(buffer->begin(), buffer->end()), true);
     196          29 :   while (!maybe_instance->IsWasmInstanceObject()) PumpMessageLoop(isolate);
     197             :   Handle<WasmInstanceObject> instance =
     198             :       Handle<WasmInstanceObject>::cast(maybe_instance);
     199           8 :   return instance;
     200             : }
     201             : 
     202             : }  // namespace
     203             : 
     204       26643 : TEST(SharedEngineUseCount) {
     205           8 :   SharedEngine engine;
     206           4 :   CHECK_EQ(0, engine.NumberOfExportedEngineUses());
     207             :   {
     208           8 :     SharedEngineIsolate isolate(&engine);
     209           4 :     CHECK_EQ(1, engine.NumberOfExportedEngineUses());
     210             :   }
     211           4 :   CHECK_EQ(0, engine.NumberOfExportedEngineUses());
     212             :   {
     213           8 :     SharedEngineIsolate isolate1(&engine);
     214           4 :     CHECK_EQ(1, engine.NumberOfExportedEngineUses());
     215           8 :     SharedEngineIsolate isolate2(&engine);
     216           4 :     CHECK_EQ(2, engine.NumberOfExportedEngineUses());
     217             :   }
     218           4 :   CHECK_EQ(0, engine.NumberOfExportedEngineUses());
     219           4 : }
     220             : 
     221       26643 : TEST(SharedEngineRunSeparated) {
     222           8 :   SharedEngine engine;
     223             :   {
     224           8 :     SharedEngineIsolate isolate(&engine);
     225             :     HandleScope scope(isolate.isolate());
     226           4 :     ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
     227           4 :     Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
     228           4 :     CHECK_EQ(23, isolate.Run(instance));
     229             :   }
     230             :   {
     231           8 :     SharedEngineIsolate isolate(&engine);
     232             :     HandleScope scope(isolate.isolate());
     233           4 :     ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 42);
     234           4 :     Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
     235           4 :     CHECK_EQ(42, isolate.Run(instance));
     236             :   }
     237           4 : }
     238             : 
     239       26643 : TEST(SharedEngineRunImported) {
     240           8 :   SharedEngine engine;
     241           4 :   SharedModule module;
     242             :   {
     243           8 :     SharedEngineIsolate isolate(&engine);
     244             :     HandleScope scope(isolate.isolate());
     245           4 :     ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
     246           4 :     Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
     247           8 :     module = isolate.ExportInstance(instance);
     248           4 :     CHECK_EQ(23, isolate.Run(instance));
     249             :   }
     250             :   {
     251           8 :     SharedEngineIsolate isolate(&engine);
     252             :     HandleScope scope(isolate.isolate());
     253           8 :     Handle<WasmInstanceObject> instance = isolate.ImportInstance(module);
     254           4 :     CHECK_EQ(23, isolate.Run(instance));
     255             :   }
     256           4 : }
     257             : 
     258       26643 : TEST(SharedEngineRunThreadedBuildingSync) {
     259           8 :   SharedEngine engine;
     260           4 :   SharedEngineThread thread1(&engine, [](SharedEngineIsolate& isolate) {
     261             :     HandleScope scope(isolate.isolate());
     262           4 :     ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
     263           4 :     Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
     264           4 :     CHECK_EQ(23, isolate.Run(instance));
     265          16 :   });
     266           4 :   SharedEngineThread thread2(&engine, [](SharedEngineIsolate& isolate) {
     267             :     HandleScope scope(isolate.isolate());
     268           4 :     ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 42);
     269           4 :     Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
     270           4 :     CHECK_EQ(42, isolate.Run(instance));
     271          16 :   });
     272           4 :   thread1.Start();
     273           4 :   thread2.Start();
     274           4 :   thread1.Join();
     275           4 :   thread2.Join();
     276           4 : }
     277             : 
     278       26643 : TEST(SharedEngineRunThreadedBuildingAsync) {
     279           8 :   SharedEngine engine;
     280           4 :   SharedEngineThread thread1(&engine, [](SharedEngineIsolate& isolate) {
     281             :     HandleScope scope(isolate.isolate());
     282           4 :     ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
     283             :     Handle<WasmInstanceObject> instance =
     284           4 :         CompileAndInstantiateAsync(isolate, buffer);
     285           4 :     CHECK_EQ(23, isolate.Run(instance));
     286          16 :   });
     287           4 :   SharedEngineThread thread2(&engine, [](SharedEngineIsolate& isolate) {
     288             :     HandleScope scope(isolate.isolate());
     289           4 :     ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 42);
     290             :     Handle<WasmInstanceObject> instance =
     291           4 :         CompileAndInstantiateAsync(isolate, buffer);
     292           4 :     CHECK_EQ(42, isolate.Run(instance));
     293          16 :   });
     294           4 :   thread1.Start();
     295           4 :   thread2.Start();
     296           4 :   thread1.Join();
     297           4 :   thread2.Join();
     298           4 : }
     299             : 
     300       26643 : TEST(SharedEngineRunThreadedExecution) {
     301           8 :   SharedEngine engine;
     302           4 :   SharedModule module;
     303             :   {
     304           8 :     SharedEngineIsolate isolate(&engine);
     305             :     HandleScope scope(isolate.isolate());
     306           4 :     ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
     307           4 :     Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
     308           8 :     module = isolate.ExportInstance(instance);
     309             :   }
     310          16 :   SharedEngineThread thread1(&engine, [module](SharedEngineIsolate& isolate) {
     311             :     HandleScope scope(isolate.isolate());
     312           8 :     Handle<WasmInstanceObject> instance = isolate.ImportInstance(module);
     313           4 :     CHECK_EQ(23, isolate.Run(instance));
     314          20 :   });
     315          16 :   SharedEngineThread thread2(&engine, [module](SharedEngineIsolate& isolate) {
     316             :     HandleScope scope(isolate.isolate());
     317           8 :     Handle<WasmInstanceObject> instance = isolate.ImportInstance(module);
     318           4 :     CHECK_EQ(23, isolate.Run(instance));
     319          20 :   });
     320           4 :   thread1.Start();
     321           4 :   thread2.Start();
     322           4 :   thread1.Join();
     323           4 :   thread2.Join();
     324           4 : }
     325             : 
     326       26643 : TEST(SharedEngineRunThreadedTierUp) {
     327           8 :   SharedEngine engine;
     328           4 :   SharedModule module;
     329             :   {
     330           8 :     SharedEngineIsolate isolate(&engine);
     331             :     HandleScope scope(isolate.isolate());
     332           4 :     ZoneBuffer* buffer = BuildReturnConstantModule(isolate.zone(), 23);
     333           4 :     Handle<WasmInstanceObject> instance = isolate.CompileAndInstantiate(buffer);
     334           8 :     module = isolate.ExportInstance(instance);
     335             :   }
     336             :   constexpr int kNumberOfThreads = 5;
     337             :   std::list<SharedEngineThread> threads;
     338          44 :   for (int i = 0; i < kNumberOfThreads; ++i) {
     339         120 :     threads.emplace_back(&engine, [module](SharedEngineIsolate& isolate) {
     340             :       constexpr int kNumberOfIterations = 100;
     341             :       HandleScope scope(isolate.isolate());
     342          40 :       Handle<WasmInstanceObject> instance = isolate.ImportInstance(module);
     343        4020 :       for (int j = 0; j < kNumberOfIterations; ++j) {
     344        2000 :         CHECK_EQ(23, isolate.Run(instance));
     345             :       }
     346          40 :     });
     347             :   }
     348          24 :   threads.emplace_back(&engine, [module](SharedEngineIsolate& isolate) {
     349             :     HandleScope scope(isolate.isolate());
     350           8 :     Handle<WasmInstanceObject> instance = isolate.ImportInstance(module);
     351           4 :     WasmFeatures detected = kNoWasmFeatures;
     352             :     WasmCompilationUnit::CompileWasmFunction(
     353             :         isolate.isolate(), module.get(), &detected,
     354           4 :         &module->module()->functions[0], ExecutionTier::kTurbofan);
     355           4 :     CHECK_EQ(23, isolate.Run(instance));
     356           8 :   });
     357          28 :   for (auto& thread : threads) thread.Start();
     358          28 :   for (auto& thread : threads) thread.Join();
     359           4 : }
     360             : 
     361             : }  // namespace test_wasm_shared_engine
     362             : }  // namespace wasm
     363             : }  // namespace internal
     364       79917 : }  // namespace v8

Generated by: LCOV version 1.10