LCOV - code coverage report
Current view: top level - src/wasm - wasm-engine.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 108 136 79.4 %
Date: 2019-01-20 Functions: 25 29 86.2 %

          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 "src/wasm/wasm-engine.h"
       6             : 
       7             : #include "src/code-tracer.h"
       8             : #include "src/compilation-statistics.h"
       9             : #include "src/objects-inl.h"
      10             : #include "src/objects/heap-number.h"
      11             : #include "src/objects/js-promise.h"
      12             : #include "src/wasm/function-compiler.h"
      13             : #include "src/wasm/module-compiler.h"
      14             : #include "src/wasm/module-decoder.h"
      15             : #include "src/wasm/module-instantiate.h"
      16             : #include "src/wasm/streaming-decoder.h"
      17             : #include "src/wasm/wasm-objects-inl.h"
      18             : 
      19             : namespace v8 {
      20             : namespace internal {
      21             : namespace wasm {
      22             : 
      23       61326 : WasmEngine::WasmEngine()
      24      183978 :     : code_manager_(&memory_tracker_, FLAG_wasm_max_code_space * MB) {}
      25             : 
      26       63766 : WasmEngine::~WasmEngine() {
      27             :   // All AsyncCompileJobs have been canceled.
      28             :   DCHECK(jobs_.empty());
      29             :   // All Isolates have been deregistered.
      30             :   DCHECK(isolates_.empty());
      31       31883 : }
      32             : 
      33      142256 : bool WasmEngine::SyncValidate(Isolate* isolate, const WasmFeatures& enabled,
      34             :                               const ModuleWireBytes& bytes) {
      35             :   // TODO(titzer): remove dependency on the isolate.
      36      284512 :   if (bytes.start() == nullptr || bytes.length() == 0) return false;
      37             :   ModuleResult result =
      38             :       DecodeWasmModule(enabled, bytes.start(), bytes.end(), true, kWasmOrigin,
      39      426768 :                        isolate->counters(), allocator());
      40      142256 :   return result.ok();
      41             : }
      42             : 
      43        2985 : MaybeHandle<AsmWasmData> WasmEngine::SyncCompileTranslatedAsmJs(
      44             :     Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes,
      45             :     Vector<const byte> asm_js_offset_table_bytes,
      46             :     Handle<HeapNumber> uses_bitset) {
      47             :   ModuleResult result =
      48             :       DecodeWasmModule(kAsmjsWasmFeatures, bytes.start(), bytes.end(), false,
      49        8955 :                        kAsmJsOrigin, isolate->counters(), allocator());
      50        2985 :   CHECK(!result.failed());
      51             : 
      52             :   // Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
      53             :   // in {CompileToNativeModule}.
      54             :   Handle<FixedArray> export_wrappers;
      55             :   std::unique_ptr<NativeModule> native_module =
      56             :       CompileToNativeModule(isolate, kAsmjsWasmFeatures, thrower,
      57        5970 :                             std::move(result).value(), bytes, &export_wrappers);
      58        2985 :   if (!native_module) return {};
      59             : 
      60             :   // Create heap objects for asm.js offset table to be stored in the module
      61             :   // object.
      62             :   Handle<ByteArray> asm_js_offset_table =
      63        2985 :       isolate->factory()->NewByteArray(asm_js_offset_table_bytes.length());
      64             :   asm_js_offset_table->copy_in(0, asm_js_offset_table_bytes.start(),
      65        2985 :                                asm_js_offset_table_bytes.length());
      66             : 
      67             :   return AsmWasmData::New(isolate, std::move(native_module), export_wrappers,
      68        8955 :                           asm_js_offset_table, uses_bitset);
      69             : }
      70             : 
      71        5636 : Handle<WasmModuleObject> WasmEngine::FinalizeTranslatedAsmJs(
      72             :     Isolate* isolate, Handle<AsmWasmData> asm_wasm_data,
      73             :     Handle<Script> script) {
      74             :   std::shared_ptr<NativeModule> native_module =
      75       11272 :       asm_wasm_data->managed_native_module()->get();
      76             :   Handle<FixedArray> export_wrappers =
      77       11272 :       handle(asm_wasm_data->export_wrappers(), isolate);
      78             :   size_t code_size_estimate =
      79             :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(
      80       11272 :           native_module->module());
      81             : 
      82             :   Handle<WasmModuleObject> module_object =
      83             :       WasmModuleObject::New(isolate, std::move(native_module), script,
      84       11272 :                             export_wrappers, code_size_estimate);
      85       11272 :   module_object->set_asm_js_offset_table(asm_wasm_data->asm_js_offset_table());
      86       11272 :   return module_object;
      87             : }
      88             : 
      89      167330 : MaybeHandle<WasmModuleObject> WasmEngine::SyncCompile(
      90      150488 :     Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
      91             :     const ModuleWireBytes& bytes) {
      92             :   ModuleResult result =
      93             :       DecodeWasmModule(enabled, bytes.start(), bytes.end(), false, kWasmOrigin,
      94      502007 :                        isolate->counters(), allocator());
      95      167347 :   if (result.failed()) {
      96             :     thrower->CompileFailed("Wasm decoding failed", result.error());
      97       10167 :     return {};
      98             :   }
      99             : 
     100             :   // Transfer ownership of the WasmModule to the {Managed<WasmModule>} generated
     101             :   // in {CompileToModuleObject}.
     102             :   Handle<FixedArray> export_wrappers;
     103             :   std::unique_ptr<NativeModule> native_module =
     104             :       CompileToNativeModule(isolate, enabled, thrower,
     105      314362 :                             std::move(result).value(), bytes, &export_wrappers);
     106      157182 :   if (!native_module) return {};
     107             : 
     108             :   Handle<Script> script =
     109      150494 :       CreateWasmScript(isolate, bytes, native_module->module()->source_map_url);
     110             :   size_t code_size_estimate =
     111             :       wasm::WasmCodeManager::EstimateNativeModuleCodeSize(
     112      150491 :           native_module->module());
     113             : 
     114             :   // Create the module object.
     115             :   // TODO(clemensh): For the same module (same bytes / same hash), we should
     116             :   // only have one WasmModuleObject. Otherwise, we might only set
     117             :   // breakpoints on a (potentially empty) subset of the instances.
     118             : 
     119             :   // Create the compiled module object and populate with compiled functions
     120             :   // and information needed at instantiation time. This object needs to be
     121             :   // serializable. Instantiation may occur off a deserialized version of this
     122             :   // object.
     123             :   Handle<WasmModuleObject> module_object =
     124             :       WasmModuleObject::New(isolate, std::move(native_module), script,
     125      300980 :                             export_wrappers, code_size_estimate);
     126             : 
     127             :   // Finish the Wasm script now and make it public to the debugger.
     128      150488 :   isolate->debug()->OnAfterCompile(script);
     129      317843 :   return module_object;
     130             : }
     131             : 
     132      150012 : MaybeHandle<WasmInstanceObject> WasmEngine::SyncInstantiate(
     133             :     Isolate* isolate, ErrorThrower* thrower,
     134             :     Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
     135             :     MaybeHandle<JSArrayBuffer> memory) {
     136             :   return InstantiateToInstanceObject(isolate, thrower, module_object, imports,
     137      152596 :                                      memory);
     138             : }
     139             : 
     140        2584 : void WasmEngine::AsyncInstantiate(
     141             :     Isolate* isolate, std::unique_ptr<InstantiationResultResolver> resolver,
     142             :     Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports) {
     143             :   ErrorThrower thrower(isolate, "WebAssembly Instantiation");
     144             :   // Instantiate a TryCatch so that caught exceptions won't progagate out.
     145             :   // They will still be set as pending exceptions on the isolate.
     146             :   // TODO(clemensh): Avoid TryCatch, use Execution::TryCall internally to invoke
     147             :   // start function and report thrown exception explicitly via out argument.
     148        3745 :   v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
     149        2584 :   catcher.SetVerbose(false);
     150        2584 :   catcher.SetCaptureMessage(false);
     151             : 
     152             :   MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
     153             :       isolate, &thrower, module_object, imports, Handle<JSArrayBuffer>::null());
     154             : 
     155        2584 :   if (!instance_object.is_null()) {
     156        2846 :     resolver->OnInstantiationSucceeded(instance_object.ToHandleChecked());
     157        4007 :     return;
     158             :   }
     159             : 
     160        1161 :   if (isolate->has_pending_exception()) {
     161             :     // The JS code executed during instantiation has thrown an exception.
     162             :     // We have to move the exception to the promise chain.
     163             :     Handle<Object> exception(isolate->pending_exception(), isolate);
     164          45 :     isolate->clear_pending_exception();
     165             :     DCHECK(*isolate->external_caught_exception_address());
     166          45 :     *isolate->external_caught_exception_address() = false;
     167          45 :     resolver->OnInstantiationFailed(exception);
     168          45 :     thrower.Reset();
     169             :   } else {
     170             :     DCHECK(thrower.error());
     171        1116 :     resolver->OnInstantiationFailed(thrower.Reify());
     172        1161 :   }
     173             : }
     174             : 
     175        2470 : void WasmEngine::AsyncCompile(
     176             :     Isolate* isolate, const WasmFeatures& enabled,
     177             :     std::shared_ptr<CompilationResultResolver> resolver,
     178             :     const ModuleWireBytes& bytes, bool is_shared) {
     179        2470 :   if (!FLAG_wasm_async_compilation) {
     180             :     // Asynchronous compilation disabled; fall back on synchronous compilation.
     181             :     ErrorThrower thrower(isolate, "WasmCompile");
     182             :     MaybeHandle<WasmModuleObject> module_object;
     183           0 :     if (is_shared) {
     184             :       // Make a copy of the wire bytes to avoid concurrent modification.
     185           0 :       std::unique_ptr<uint8_t[]> copy(new uint8_t[bytes.length()]);
     186             :       memcpy(copy.get(), bytes.start(), bytes.length());
     187           0 :       ModuleWireBytes bytes_copy(copy.get(), copy.get() + bytes.length());
     188           0 :       module_object = SyncCompile(isolate, enabled, &thrower, bytes_copy);
     189             :     } else {
     190             :       // The wire bytes are not shared, OK to use them directly.
     191           0 :       module_object = SyncCompile(isolate, enabled, &thrower, bytes);
     192             :     }
     193           0 :     if (thrower.error()) {
     194           0 :       resolver->OnCompilationFailed(thrower.Reify());
     195           0 :       return;
     196             :     }
     197           0 :     Handle<WasmModuleObject> module = module_object.ToHandleChecked();
     198           0 :     resolver->OnCompilationSucceeded(module);
     199           0 :     return;
     200             :   }
     201             : 
     202        2470 :   if (FLAG_wasm_test_streaming) {
     203             :     std::shared_ptr<StreamingDecoder> streaming_decoder =
     204             :         StartStreamingCompilation(isolate, enabled,
     205             :                                   handle(isolate->context(), isolate),
     206         418 :                                   std::move(resolver));
     207         209 :     streaming_decoder->OnBytesReceived(bytes.module_bytes());
     208         209 :     streaming_decoder->Finish();
     209             :     return;
     210             :   }
     211             :   // Make a copy of the wire bytes in case the user program changes them
     212             :   // during asynchronous compilation.
     213        2261 :   std::unique_ptr<byte[]> copy(new byte[bytes.length()]);
     214             :   memcpy(copy.get(), bytes.start(), bytes.length());
     215             : 
     216             :   AsyncCompileJob* job = CreateAsyncCompileJob(
     217             :       isolate, enabled, std::move(copy), bytes.length(),
     218        6783 :       handle(isolate->context(), isolate), std::move(resolver));
     219        2261 :   job->Start();
     220             : }
     221             : 
     222         424 : std::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation(
     223             :     Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context,
     224             :     std::shared_ptr<CompilationResultResolver> resolver) {
     225             :   AsyncCompileJob* job =
     226             :       CreateAsyncCompileJob(isolate, enabled, std::unique_ptr<byte[]>(nullptr),
     227        1272 :                             0, context, std::move(resolver));
     228         424 :   return job->CreateStreamingDecoder();
     229             : }
     230             : 
     231          18 : void WasmEngine::CompileFunction(Isolate* isolate, NativeModule* native_module,
     232             :                                  uint32_t function_index, ExecutionTier tier) {
     233             :   // Note we assume that "one-off" compilations can discard detected features.
     234          18 :   WasmFeatures detected = kNoWasmFeatures;
     235             :   WasmCompilationUnit::CompileWasmFunction(
     236             :       isolate, native_module, &detected,
     237          54 :       &native_module->module()->functions[function_index], tier);
     238          18 : }
     239             : 
     240           0 : std::shared_ptr<NativeModule> WasmEngine::ExportNativeModule(
     241             :     Handle<WasmModuleObject> module_object) {
     242           0 :   return module_object->shared_native_module();
     243             : }
     244             : 
     245         153 : Handle<WasmModuleObject> WasmEngine::ImportNativeModule(
     246             :     Isolate* isolate, std::shared_ptr<NativeModule> shared_module) {
     247         306 :   ModuleWireBytes wire_bytes(shared_module->wire_bytes());
     248             :   const WasmModule* module = shared_module->module();
     249             :   Handle<Script> script =
     250         153 :       CreateWasmScript(isolate, wire_bytes, module->source_map_url);
     251             :   size_t code_size = shared_module->committed_code_space();
     252             :   Handle<WasmModuleObject> module_object = WasmModuleObject::New(
     253         306 :       isolate, std::move(shared_module), script, code_size);
     254             :   CompileJsToWasmWrappers(isolate, module_object->native_module()->module(),
     255         459 :                           handle(module_object->export_wrappers(), isolate));
     256         153 :   return module_object;
     257             : }
     258             : 
     259           0 : CompilationStatistics* WasmEngine::GetOrCreateTurboStatistics() {
     260           0 :   base::MutexGuard guard(&mutex_);
     261           0 :   if (compilation_stats_ == nullptr) {
     262           0 :     compilation_stats_.reset(new CompilationStatistics());
     263             :   }
     264           0 :   return compilation_stats_.get();
     265             : }
     266             : 
     267           0 : void WasmEngine::DumpAndResetTurboStatistics() {
     268           0 :   base::MutexGuard guard(&mutex_);
     269           0 :   if (compilation_stats_ != nullptr) {
     270           0 :     StdoutStream os;
     271           0 :     os << AsPrintableStatistics{*compilation_stats_.get(), false} << std::endl;
     272             :   }
     273             :   compilation_stats_.reset();
     274           0 : }
     275             : 
     276           0 : CodeTracer* WasmEngine::GetCodeTracer() {
     277           0 :   base::MutexGuard guard(&mutex_);
     278           0 :   if (code_tracer_ == nullptr) code_tracer_.reset(new CodeTracer(-1));
     279           0 :   return code_tracer_.get();
     280             : }
     281             : 
     282        2685 : AsyncCompileJob* WasmEngine::CreateAsyncCompileJob(
     283             :     Isolate* isolate, const WasmFeatures& enabled,
     284             :     std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
     285             :     std::shared_ptr<CompilationResultResolver> resolver) {
     286             :   AsyncCompileJob* job =
     287             :       new AsyncCompileJob(isolate, enabled, std::move(bytes_copy), length,
     288       10740 :                           context, std::move(resolver));
     289             :   // Pass ownership to the unique_ptr in {jobs_}.
     290        2685 :   base::MutexGuard guard(&mutex_);
     291        2685 :   jobs_[job] = std::unique_ptr<AsyncCompileJob>(job);
     292        5370 :   return job;
     293             : }
     294             : 
     295        2674 : std::unique_ptr<AsyncCompileJob> WasmEngine::RemoveCompileJob(
     296             :     AsyncCompileJob* job) {
     297        2674 :   base::MutexGuard guard(&mutex_);
     298             :   auto item = jobs_.find(job);
     299             :   DCHECK(item != jobs_.end());
     300             :   std::unique_ptr<AsyncCompileJob> result = std::move(item->second);
     301             :   jobs_.erase(item);
     302        2674 :   return result;
     303             : }
     304             : 
     305       53798 : bool WasmEngine::HasRunningCompileJob(Isolate* isolate) {
     306       53798 :   base::MutexGuard guard(&mutex_);
     307             :   DCHECK_EQ(1, isolates_.count(isolate));
     308      107596 :   for (auto& entry : jobs_) {
     309        3398 :     if (entry.first->isolate() == isolate) return true;
     310             :   }
     311             :   return false;
     312             : }
     313             : 
     314       62877 : void WasmEngine::DeleteCompileJobsOnIsolate(Isolate* isolate) {
     315       62877 :   base::MutexGuard guard(&mutex_);
     316             :   DCHECK_EQ(1, isolates_.count(isolate));
     317      125771 :   for (auto it = jobs_.begin(); it != jobs_.end();) {
     318          15 :     if (it->first->isolate() == isolate) {
     319             :       it = jobs_.erase(it);
     320             :     } else {
     321             :       ++it;
     322             :     }
     323             :   }
     324       62878 : }
     325             : 
     326       62883 : void WasmEngine::AddIsolate(Isolate* isolate) {
     327       62883 :   base::MutexGuard guard(&mutex_);
     328             :   DCHECK_EQ(0, isolates_.count(isolate));
     329             :   isolates_.insert(isolate);
     330       62883 : }
     331             : 
     332       62868 : void WasmEngine::RemoveIsolate(Isolate* isolate) {
     333       62868 :   base::MutexGuard guard(&mutex_);
     334             :   DCHECK_EQ(1, isolates_.count(isolate));
     335             :   isolates_.erase(isolate);
     336       62868 : }
     337             : 
     338             : namespace {
     339             : 
     340      155946 : DEFINE_LAZY_LEAKY_OBJECT_GETTER(std::shared_ptr<WasmEngine>,
     341             :                                 GetSharedWasmEngine);
     342             : 
     343             : }  // namespace
     344             : 
     345             : // static
     346       61291 : void WasmEngine::InitializeOncePerProcess() {
     347      122582 :   if (!FLAG_wasm_shared_engine) return;
     348      122582 :   *GetSharedWasmEngine() = std::make_shared<WasmEngine>();
     349             : }
     350             : 
     351             : // static
     352       31878 : void WasmEngine::GlobalTearDown() {
     353       63756 :   if (!FLAG_wasm_shared_engine) return;
     354       31878 :   GetSharedWasmEngine()->reset();
     355             : }
     356             : 
     357             : // static
     358       62777 : std::shared_ptr<WasmEngine> WasmEngine::GetWasmEngine() {
     359       62777 :   if (FLAG_wasm_shared_engine) return *GetSharedWasmEngine();
     360             :   return std::make_shared<WasmEngine>();
     361             : }
     362             : 
     363             : // {max_mem_pages} is declared in wasm-limits.h.
     364     2007389 : uint32_t max_mem_pages() {
     365             :   STATIC_ASSERT(kV8MaxWasmMemoryPages <= kMaxUInt32);
     366     4014778 :   return std::min(uint32_t{kV8MaxWasmMemoryPages}, FLAG_wasm_max_mem_pages);
     367             : }
     368             : 
     369             : }  // namespace wasm
     370             : }  // namespace internal
     371      183867 : }  // namespace v8

Generated by: LCOV version 1.10