V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
module-compiler.cc
1 // Copyright 2017 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/module-compiler.h"
6 
7 #include "src/api.h"
8 #include "src/asmjs/asm-js.h"
9 #include "src/base/template-utils.h"
10 #include "src/base/utils/random-number-generator.h"
11 #include "src/compiler/wasm-compiler.h"
12 #include "src/counters.h"
13 #include "src/identity-map.h"
14 #include "src/property-descriptor.h"
15 #include "src/task-utils.h"
16 #include "src/tracing/trace-event.h"
17 #include "src/trap-handler/trap-handler.h"
18 #include "src/wasm/module-decoder.h"
19 #include "src/wasm/streaming-decoder.h"
20 #include "src/wasm/wasm-code-manager.h"
21 #include "src/wasm/wasm-engine.h"
22 #include "src/wasm/wasm-import-wrapper-cache-inl.h"
23 #include "src/wasm/wasm-js.h"
24 #include "src/wasm/wasm-limits.h"
25 #include "src/wasm/wasm-memory.h"
26 #include "src/wasm/wasm-objects-inl.h"
27 #include "src/wasm/wasm-result.h"
28 #include "src/wasm/wasm-serialization.h"
29 
30 #define TRACE(...) \
31  do { \
32  if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
33  } while (false)
34 
35 #define TRACE_COMPILE(...) \
36  do { \
37  if (FLAG_trace_wasm_compiler) PrintF(__VA_ARGS__); \
38  } while (false)
39 
40 #define TRACE_STREAMING(...) \
41  do { \
42  if (FLAG_trace_wasm_streaming) PrintF(__VA_ARGS__); \
43  } while (false)
44 
45 #define TRACE_LAZY(...) \
46  do { \
47  if (FLAG_trace_wasm_lazy_compilation) PrintF(__VA_ARGS__); \
48  } while (false)
49 
50 namespace v8 {
51 namespace internal {
52 namespace wasm {
53 
54 namespace {
55 
56 // Callbacks will receive either {kFailedCompilation} or both
57 // {kFinishedBaselineCompilation} and {kFinishedTopTierCompilation}, in that
58 // order. If tier up is off, both events are delivered right after each other.
59 enum class CompilationEvent : uint8_t {
60  kFinishedBaselineCompilation,
61  kFinishedTopTierCompilation,
62  kFailedCompilation
63 };
64 
65 enum class CompileMode : uint8_t { kRegular, kTiering };
66 
67 // The {CompilationStateImpl} keeps track of the compilation state of the
68 // owning NativeModule, i.e. which functions are left to be compiled.
69 // It contains a task manager to allow parallel and asynchronous background
70 // compilation of functions.
71 // It's public interface {CompilationState} lives in compilation-environment.h.
72 class CompilationStateImpl {
73  public:
74  using callback_t = std::function<void(CompilationEvent, const VoidResult*)>;
75 
76  CompilationStateImpl(internal::Isolate*, NativeModule*);
77  ~CompilationStateImpl();
78 
79  // Cancel all background compilation and wait for all tasks to finish. Call
80  // this before destructing this object.
81  void CancelAndWait();
82 
83  // Set the number of compilations unit expected to be executed. Needs to be
84  // set before {AddCompilationUnits} is run, which triggers background
85  // compilation.
86  void SetNumberOfFunctionsToCompile(size_t num_functions);
87 
88  // Set the callback function to be called on compilation events. Needs to be
89  // set before {AddCompilationUnits} is run.
90  void SetCallback(callback_t callback);
91 
92  // Inserts new functions to compile and kicks off compilation.
93  void AddCompilationUnits(
94  std::vector<std::unique_ptr<WasmCompilationUnit>>& baseline_units,
95  std::vector<std::unique_ptr<WasmCompilationUnit>>& tiering_units);
96  std::unique_ptr<WasmCompilationUnit> GetNextCompilationUnit();
97  std::unique_ptr<WasmCompilationUnit> GetNextExecutedUnit();
98 
99  bool HasCompilationUnitToFinish();
100 
101  void OnFinishedUnit();
102  void ScheduleUnitForFinishing(std::unique_ptr<WasmCompilationUnit> unit,
103  ExecutionTier tier);
104  void ScheduleCodeLogging(WasmCode*);
105 
106  void OnBackgroundTaskStopped(const WasmFeatures& detected);
107  void PublishDetectedFeatures(Isolate* isolate, const WasmFeatures& detected);
108  void RestartBackgroundTasks(size_t max = std::numeric_limits<size_t>::max());
109  // Only one foreground thread (finisher) is allowed to run at a time.
110  // {SetFinisherIsRunning} returns whether the flag changed its state.
111  bool SetFinisherIsRunning(bool value);
112  void ScheduleFinisherTask();
113 
114  void Abort();
115 
116  void SetError(uint32_t func_index, const ResultBase& error_result);
117 
118  Isolate* isolate() const { return isolate_; }
119 
120  bool failed() const {
121  base::MutexGuard guard(&mutex_);
122  return compile_error_ != nullptr;
123  }
124 
125  bool baseline_compilation_finished() const {
126  return outstanding_baseline_units_ == 0 ||
127  (compile_mode_ == CompileMode::kTiering &&
128  outstanding_tiering_units_ == 0);
129  }
130 
131  bool has_outstanding_units() const {
132  return outstanding_tiering_units_ > 0 || outstanding_baseline_units_ > 0;
133  }
134 
135  CompileMode compile_mode() const { return compile_mode_; }
136  WasmFeatures* detected_features() { return &detected_features_; }
137 
138  // Call {GetCompileError} from foreground threads only, since we access
139  // NativeModule::wire_bytes, which is set from the foreground thread once the
140  // stream has finished.
141  VoidResult GetCompileError() {
142  DCHECK_NOT_NULL(compile_error_);
143  std::ostringstream error;
144  error << "Compiling wasm function \"";
145  wasm::ModuleWireBytes wire_bytes(native_module_->wire_bytes());
146  wasm::WireBytesRef name_ref = native_module_->module()->LookupFunctionName(
147  wire_bytes, compile_error_->func_index);
148  if (name_ref.is_set()) {
149  wasm::WasmName name = wire_bytes.GetNameOrNull(name_ref);
150  error.write(name.start(), name.length());
151  } else {
152  error << "wasm-function[" << compile_error_->func_index << "]";
153  }
154  error << "\" failed: " << compile_error_->result.error_msg();
155  return VoidResult::Error(compile_error_->result.error_offset(),
156  error.str());
157  }
158 
159  std::shared_ptr<WireBytesStorage> GetSharedWireBytesStorage() const {
160  base::MutexGuard guard(&mutex_);
161  DCHECK_NOT_NULL(wire_bytes_storage_);
162  return wire_bytes_storage_;
163  }
164 
165  void SetWireBytesStorage(
166  std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
167  base::MutexGuard guard(&mutex_);
168  wire_bytes_storage_ = wire_bytes_storage;
169  }
170 
171  std::shared_ptr<WireBytesStorage> GetWireBytesStorage() {
172  base::MutexGuard guard(&mutex_);
173  return wire_bytes_storage_;
174  }
175 
176  private:
177  struct CompilationError {
178  uint32_t const func_index;
179  VoidResult const result;
180  CompilationError(uint32_t func_index, const ResultBase& compile_result)
181  : func_index(func_index),
182  result(VoidResult::ErrorFrom(compile_result)) {}
183  };
184 
185  class LogCodesTask : public CancelableTask {
186  public:
187  LogCodesTask(CancelableTaskManager* manager,
188  CompilationStateImpl* compilation_state, Isolate* isolate)
189  : CancelableTask(manager),
190  compilation_state_(compilation_state),
191  isolate_(isolate) {
192  // This task should only be created if we should actually log code.
193  DCHECK(WasmCode::ShouldBeLogged(isolate));
194  }
195 
196  // Hold the compilation state {mutex_} when calling this method.
197  void AddCode(WasmCode* code) { code_to_log_.push_back(code); }
198 
199  void RunInternal() override {
200  // Remove this task from the {CompilationStateImpl}. The next compilation
201  // that finishes will allocate and schedule a new task.
202  {
203  base::MutexGuard guard(&compilation_state_->mutex_);
204  DCHECK_EQ(this, compilation_state_->log_codes_task_);
205  compilation_state_->log_codes_task_ = nullptr;
206  }
207  // If by now we shouldn't log code any more, don't log it.
208  if (!WasmCode::ShouldBeLogged(isolate_)) return;
209  for (WasmCode* code : code_to_log_) {
210  code->LogCode(isolate_);
211  }
212  }
213 
214  private:
215  CompilationStateImpl* const compilation_state_;
216  Isolate* const isolate_;
217  std::vector<WasmCode*> code_to_log_;
218  };
219 
220  void NotifyOnEvent(CompilationEvent event, const VoidResult* error_result);
221 
222  std::vector<std::unique_ptr<WasmCompilationUnit>>& finish_units() {
223  return baseline_compilation_finished() ? tiering_finish_units_
224  : baseline_finish_units_;
225  }
226 
227  // TODO(mstarzinger): Get rid of the Isolate field to make sure the
228  // {CompilationStateImpl} can be shared across multiple Isolates.
229  Isolate* const isolate_;
230  NativeModule* const native_module_;
231  const CompileMode compile_mode_;
232  // Store the value of {WasmCode::ShouldBeLogged()} at creation time of the
233  // compilation state.
234  // TODO(wasm): We might lose log events if logging is enabled while
235  // compilation is running.
236  bool const should_log_code_;
237 
238  // This mutex protects all information of this {CompilationStateImpl} which is
239  // being accessed concurrently.
240  mutable base::Mutex mutex_;
241 
243  // Protected by {mutex_}:
244 
245  std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_compilation_units_;
246  std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_compilation_units_;
247 
248  bool finisher_is_running_ = false;
249  size_t num_background_tasks_ = 0;
250  std::unique_ptr<CompilationError> compile_error_;
251 
252  std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_finish_units_;
253  std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_finish_units_;
254 
255  // Features detected to be used in this module. Features can be detected
256  // as a module is being compiled.
257  WasmFeatures detected_features_ = kNoWasmFeatures;
258 
259  // The foreground task to log finished wasm code. Is {nullptr} if no such task
260  // is currently scheduled.
261  LogCodesTask* log_codes_task_ = nullptr;
262 
263  // Abstraction over the storage of the wire bytes. Held in a shared_ptr so
264  // that background compilation jobs can keep the storage alive while
265  // compiling.
266  std::shared_ptr<WireBytesStorage> wire_bytes_storage_;
267 
268  // End of fields protected by {mutex_}.
270 
271  // Callback function to be called on compilation events.
272  callback_t callback_;
273 
274  CancelableTaskManager background_task_manager_;
275  CancelableTaskManager foreground_task_manager_;
276  std::shared_ptr<v8::TaskRunner> foreground_task_runner_;
277 
278  const size_t max_background_tasks_ = 0;
279 
280  size_t outstanding_baseline_units_ = 0;
281  size_t outstanding_tiering_units_ = 0;
282 };
283 
284 void UpdateFeatureUseCounts(Isolate* isolate, const WasmFeatures& detected) {
285  if (detected.threads) {
286  isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmThreadOpcodes);
287  }
288 }
289 
290 class JSToWasmWrapperCache {
291  public:
292  Handle<Code> GetOrCompileJSToWasmWrapper(Isolate* isolate, FunctionSig* sig,
293  bool is_import) {
294  std::pair<bool, FunctionSig> key(is_import, *sig);
295  Handle<Code>& cached = cache_[key];
296  if (cached.is_null()) {
297  cached = compiler::CompileJSToWasmWrapper(isolate, sig, is_import)
298  .ToHandleChecked();
299  }
300  return cached;
301  }
302 
303  private:
304  // We generate different code for calling imports than calling wasm functions
305  // in this module. Both are cached separately.
306  using CacheKey = std::pair<bool, FunctionSig>;
307  std::unordered_map<CacheKey, Handle<Code>, base::hash<CacheKey>> cache_;
308 };
309 
310 // A helper class to simplify instantiating a module from a module object.
311 // It closes over the {Isolate}, the {ErrorThrower}, etc.
312 class InstanceBuilder {
313  public:
314  InstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
315  Handle<WasmModuleObject> module_object,
316  MaybeHandle<JSReceiver> ffi,
317  MaybeHandle<JSArrayBuffer> memory);
318 
319  // Build an instance, in all of its glory.
320  MaybeHandle<WasmInstanceObject> Build();
321  // Run the start function, if any.
322  bool ExecuteStartFunction();
323 
324  private:
325  // Represents the initialized state of a table.
326  struct TableInstance {
327  Handle<WasmTableObject> table_object; // WebAssembly.Table instance
328  Handle<FixedArray> js_wrappers; // JSFunctions exported
329  size_t table_size;
330  };
331 
332  // A pre-evaluated value to use in import binding.
333  struct SanitizedImport {
334  Handle<String> module_name;
335  Handle<String> import_name;
336  Handle<Object> value;
337  };
338 
339  Isolate* isolate_;
340  const WasmFeatures enabled_;
341  const WasmModule* const module_;
342  ErrorThrower* thrower_;
343  Handle<WasmModuleObject> module_object_;
344  MaybeHandle<JSReceiver> ffi_;
345  MaybeHandle<JSArrayBuffer> memory_;
346  Handle<JSArrayBuffer> globals_;
347  std::vector<TableInstance> table_instances_;
348  std::vector<Handle<JSFunction>> js_wrappers_;
349  std::vector<Handle<WasmExceptionObject>> exception_wrappers_;
350  Handle<WasmExportedFunction> start_function_;
351  JSToWasmWrapperCache js_to_wasm_cache_;
352  std::vector<SanitizedImport> sanitized_imports_;
353 
354  UseTrapHandler use_trap_handler() const {
355  return module_object_->native_module()->use_trap_handler() ? kUseTrapHandler
356  : kNoTrapHandler;
357  }
358 
359 // Helper routines to print out errors with imports.
360 #define ERROR_THROWER_WITH_MESSAGE(TYPE) \
361  void Report##TYPE(const char* error, uint32_t index, \
362  Handle<String> module_name, Handle<String> import_name) { \
363  thrower_->TYPE("Import #%d module=\"%s\" function=\"%s\" error: %s", \
364  index, module_name->ToCString().get(), \
365  import_name->ToCString().get(), error); \
366  } \
367  \
368  MaybeHandle<Object> Report##TYPE(const char* error, uint32_t index, \
369  Handle<String> module_name) { \
370  thrower_->TYPE("Import #%d module=\"%s\" error: %s", index, \
371  module_name->ToCString().get(), error); \
372  return MaybeHandle<Object>(); \
373  }
374 
375  ERROR_THROWER_WITH_MESSAGE(LinkError)
376  ERROR_THROWER_WITH_MESSAGE(TypeError)
377 
378 #undef ERROR_THROWER_WITH_MESSAGE
379 
380  // Look up an import value in the {ffi_} object.
381  MaybeHandle<Object> LookupImport(uint32_t index, Handle<String> module_name,
382  Handle<String> import_name);
383 
384  // Look up an import value in the {ffi_} object specifically for linking an
385  // asm.js module. This only performs non-observable lookups, which allows
386  // falling back to JavaScript proper (and hence re-executing all lookups) if
387  // module instantiation fails.
388  MaybeHandle<Object> LookupImportAsm(uint32_t index,
389  Handle<String> import_name);
390 
391  uint32_t EvalUint32InitExpr(const WasmInitExpr& expr);
392 
393  // Load data segments into the memory.
394  void LoadDataSegments(Handle<WasmInstanceObject> instance);
395 
396  void WriteGlobalValue(const WasmGlobal& global, double value);
397  void WriteGlobalValue(const WasmGlobal& global,
398  Handle<WasmGlobalObject> value);
399 
400  void SanitizeImports();
401 
402  // Find the imported memory buffer if there is one. This is used to see if we
403  // need to recompile with bounds checks before creating the instance.
404  MaybeHandle<JSArrayBuffer> FindImportedMemoryBuffer() const;
405 
406  // Process the imports, including functions, tables, globals, and memory, in
407  // order, loading them from the {ffi_} object. Returns the number of imported
408  // functions.
409  int ProcessImports(Handle<WasmInstanceObject> instance);
410 
411  template <typename T>
412  T* GetRawGlobalPtr(const WasmGlobal& global);
413 
414  // Process initialization of globals.
415  void InitGlobals();
416 
417  // Allocate memory for a module instance as a new JSArrayBuffer.
418  Handle<JSArrayBuffer> AllocateMemory(uint32_t num_pages);
419 
420  bool NeedsWrappers() const;
421 
422  // Process the exports, creating wrappers for functions, tables, memories,
423  // and globals.
424  void ProcessExports(Handle<WasmInstanceObject> instance);
425 
426  void InitializeTables(Handle<WasmInstanceObject> instance);
427 
428  void LoadTableSegments(Handle<WasmInstanceObject> instance);
429 
430  // Creates new exception tags for all exceptions. Note that some tags might
431  // already exist if they were imported, those tags will be re-used.
432  void InitializeExceptions(Handle<WasmInstanceObject> instance);
433 };
434 
435 CompilationStateImpl* Impl(CompilationState* compilation_state) {
436  return reinterpret_cast<CompilationStateImpl*>(compilation_state);
437 }
438 
439 } // namespace
440 
442 // PIMPL implementation of {CompilationState}.
443 
444 void CompilationState::CancelAndWait() { Impl(this)->CancelAndWait(); }
445 
446 void CompilationState::SetError(uint32_t func_index,
447  const ResultBase& error_result) {
448  Impl(this)->SetError(func_index, error_result);
449 }
450 
451 void CompilationState::SetWireBytesStorage(
452  std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
453  Impl(this)->SetWireBytesStorage(std::move(wire_bytes_storage));
454 }
455 
456 std::shared_ptr<WireBytesStorage> CompilationState::GetWireBytesStorage() {
457  return Impl(this)->GetWireBytesStorage();
458 }
459 
460 CompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); }
461 
462 // static
463 std::unique_ptr<CompilationState> CompilationState::New(
464  Isolate* isolate, NativeModule* native_module) {
465  return std::unique_ptr<CompilationState>(reinterpret_cast<CompilationState*>(
466  new CompilationStateImpl(isolate, native_module)));
467 }
468 
469 // End of PIMPL implementation of {CompilationState}.
471 
472 MaybeHandle<WasmInstanceObject> InstantiateToInstanceObject(
473  Isolate* isolate, ErrorThrower* thrower,
474  Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
475  MaybeHandle<JSArrayBuffer> memory) {
476  InstanceBuilder builder(isolate, thrower, module_object, imports, memory);
477  auto instance = builder.Build();
478  if (!instance.is_null() && builder.ExecuteStartFunction()) {
479  return instance;
480  }
481  DCHECK(isolate->has_pending_exception() || thrower->error());
482  return {};
483 }
484 
485 WasmCode* LazyCompileFunction(Isolate* isolate, NativeModule* native_module,
486  int func_index) {
487  base::ElapsedTimer compilation_timer;
488  DCHECK(!native_module->has_code(static_cast<uint32_t>(func_index)));
489 
490  compilation_timer.Start();
491 
492  TRACE_LAZY("Compiling wasm-function#%d.\n", func_index);
493 
494  const uint8_t* module_start = native_module->wire_bytes().start();
495 
496  const WasmFunction* func = &native_module->module()->functions[func_index];
497  FunctionBody func_body{func->sig, func->code.offset(),
498  module_start + func->code.offset(),
499  module_start + func->code.end_offset()};
500 
501  WasmCompilationUnit unit(isolate->wasm_engine(), native_module, func_index);
502  CompilationEnv env = native_module->CreateCompilationEnv();
503  unit.ExecuteCompilation(
504  &env, native_module->compilation_state()->GetWireBytesStorage(),
505  isolate->counters(),
506  Impl(native_module->compilation_state())->detected_features());
507 
508  // If there is a pending error, something really went wrong. The module was
509  // verified before starting execution with lazy compilation.
510  // This might be OOM, but then we cannot continue execution anyway.
511  // TODO(clemensh): According to the spec, we can actually skip validation at
512  // module creation time, and return a function that always traps here.
513  CHECK(!unit.failed());
514 
515  WasmCode* code = unit.result();
516 
517  if (WasmCode::ShouldBeLogged(isolate)) code->LogCode(isolate);
518 
519  int64_t func_size =
520  static_cast<int64_t>(func->code.end_offset() - func->code.offset());
521  int64_t compilation_time = compilation_timer.Elapsed().InMicroseconds();
522 
523  auto counters = isolate->counters();
524  counters->wasm_lazily_compiled_functions()->Increment();
525 
526  counters->wasm_lazy_compilation_throughput()->AddSample(
527  compilation_time != 0 ? static_cast<int>(func_size / compilation_time)
528  : 0);
529 
530  return code;
531 }
532 
533 Address CompileLazy(Isolate* isolate, NativeModule* native_module,
534  uint32_t func_index) {
535  HistogramTimerScope lazy_time_scope(
536  isolate->counters()->wasm_lazy_compilation_time());
537 
538  DCHECK(!native_module->lazy_compile_frozen());
539 
540  NativeModuleModificationScope native_module_modification_scope(native_module);
541 
542  WasmCode* result = LazyCompileFunction(isolate, native_module, func_index);
543  DCHECK_NOT_NULL(result);
544  DCHECK_EQ(func_index, result->index());
545 
546  return result->instruction_start();
547 }
548 
549 namespace {
550 
551 // The {CompilationUnitBuilder} builds compilation units and stores them in an
552 // internal buffer. The buffer is moved into the working queue of the
553 // {CompilationStateImpl} when {Commit} is called.
554 class CompilationUnitBuilder {
555  public:
556  explicit CompilationUnitBuilder(NativeModule* native_module,
557  WasmEngine* wasm_engine)
558  : native_module_(native_module), wasm_engine_(wasm_engine) {}
559 
560  void AddUnit(uint32_t func_index) {
561  switch (compilation_state()->compile_mode()) {
562  case CompileMode::kTiering:
563  tiering_units_.emplace_back(
564  CreateUnit(func_index, ExecutionTier::kOptimized));
565  baseline_units_.emplace_back(
566  CreateUnit(func_index, ExecutionTier::kBaseline));
567  return;
568  case CompileMode::kRegular:
569  baseline_units_.emplace_back(CreateUnit(
570  func_index, WasmCompilationUnit::GetDefaultExecutionTier()));
571  return;
572  }
573  UNREACHABLE();
574  }
575 
576  bool Commit() {
577  if (baseline_units_.empty() && tiering_units_.empty()) return false;
578  compilation_state()->AddCompilationUnits(baseline_units_, tiering_units_);
579  Clear();
580  return true;
581  }
582 
583  void Clear() {
584  baseline_units_.clear();
585  tiering_units_.clear();
586  }
587 
588  private:
589  std::unique_ptr<WasmCompilationUnit> CreateUnit(uint32_t func_index,
590  ExecutionTier tier) {
591  return base::make_unique<WasmCompilationUnit>(wasm_engine_, native_module_,
592  func_index, tier);
593  }
594 
595  CompilationStateImpl* compilation_state() const {
596  return Impl(native_module_->compilation_state());
597  }
598 
599  NativeModule* const native_module_;
600  WasmEngine* const wasm_engine_;
601  std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_units_;
602  std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_units_;
603 };
604 
605 bool compile_lazy(const WasmModule* module) {
606  return FLAG_wasm_lazy_compilation ||
607  (FLAG_asm_wasm_lazy_compilation && module->origin == kAsmJsOrigin);
608 }
609 
610 byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) {
611  return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset;
612 }
613 
614 void RecordStats(const Code code, Counters* counters) {
615  counters->wasm_generated_code_size()->Increment(code->body_size());
616  counters->wasm_reloc_size()->Increment(code->relocation_info()->length());
617 }
618 
619 bool in_bounds(uint32_t offset, size_t size, size_t upper) {
620  return offset + size <= upper && offset + size >= offset;
621 }
622 
623 using WasmInstanceMap =
624  IdentityMap<Handle<WasmInstanceObject>, FreeStoreAllocationPolicy>;
625 
626 double MonotonicallyIncreasingTimeInMs() {
627  return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
628  base::Time::kMillisecondsPerSecond;
629 }
630 
631 // Run by each compilation task and by the main thread (i.e. in both
632 // foreground and background threads). The no_finisher_callback is called
633 // within the result_mutex_ lock when no finishing task is running, i.e. when
634 // the finisher_is_running_ flag is not set.
635 bool FetchAndExecuteCompilationUnit(CompilationEnv* env,
636  CompilationStateImpl* compilation_state,
637  WasmFeatures* detected,
638  Counters* counters) {
639  DisallowHeapAccess no_heap_access;
640 
641  std::unique_ptr<WasmCompilationUnit> unit =
642  compilation_state->GetNextCompilationUnit();
643  if (unit == nullptr) return false;
644 
645  // Get the tier before starting compilation, as compilation can switch tiers
646  // if baseline bails out.
647  ExecutionTier tier = unit->tier();
648  unit->ExecuteCompilation(env, compilation_state->GetSharedWireBytesStorage(),
649  counters, detected);
650  if (!unit->failed()) compilation_state->ScheduleCodeLogging(unit->result());
651  compilation_state->ScheduleUnitForFinishing(std::move(unit), tier);
652 
653  return true;
654 }
655 
656 void InitializeCompilationUnits(NativeModule* native_module,
657  WasmEngine* wasm_engine) {
658  ModuleWireBytes wire_bytes(native_module->wire_bytes());
659  const WasmModule* module = native_module->module();
660  CompilationUnitBuilder builder(native_module, wasm_engine);
661  uint32_t start = module->num_imported_functions;
662  uint32_t end = start + module->num_declared_functions;
663  for (uint32_t i = start; i < end; ++i) {
664  builder.AddUnit(i);
665  }
666  builder.Commit();
667 }
668 
669 void FinishCompilationUnits(CompilationStateImpl* compilation_state) {
670  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "FinishCompilationUnits");
671  while (!compilation_state->failed()) {
672  std::unique_ptr<WasmCompilationUnit> unit =
673  compilation_state->GetNextExecutedUnit();
674  if (unit == nullptr) break;
675 
676  if (unit->failed()) {
677  compilation_state->Abort();
678  break;
679  }
680 
681  // Update the compilation state.
682  compilation_state->OnFinishedUnit();
683  }
684 }
685 
686 void CompileInParallel(Isolate* isolate, NativeModule* native_module) {
687  // Data structures for the parallel compilation.
688 
689  //-----------------------------------------------------------------------
690  // For parallel compilation:
691  // 1) The main thread allocates a compilation unit for each wasm function
692  // and stores them in the vector {compilation_units} within the
693  // {compilation_state}. By adding units to the {compilation_state}, new
694  // {BackgroundCompileTasks} instances are spawned which run on
695  // the background threads.
696  // 2.a) The background threads and the main thread pick one compilation
697  // unit at a time and execute the parallel phase of the compilation
698  // unit. After finishing the execution of the parallel phase, the
699  // result is enqueued in {baseline_finish_units_}.
700  // 2.b) If {baseline_finish_units_} contains a compilation unit, the main
701  // thread dequeues it and finishes the compilation.
702  // 3) After the parallel phase of all compilation units has started, the
703  // main thread continues to finish all compilation units as long as
704  // baseline-compilation units are left to be processed.
705  // 4) If tier-up is enabled, the main thread restarts background tasks
706  // that take care of compiling and finishing the top-tier compilation
707  // units.
708 
709  // Turn on the {CanonicalHandleScope} so that the background threads can
710  // use the node cache.
711  CanonicalHandleScope canonical(isolate);
712 
713  CompilationStateImpl* compilation_state =
714  Impl(native_module->compilation_state());
715  // Make sure that no foreground task is spawned for finishing
716  // the compilation units. This foreground thread will be
717  // responsible for finishing compilation.
718  compilation_state->SetFinisherIsRunning(true);
719  uint32_t num_wasm_functions =
720  native_module->num_functions() - native_module->num_imported_functions();
721  compilation_state->SetNumberOfFunctionsToCompile(num_wasm_functions);
722 
723  // 1) The main thread allocates a compilation unit for each wasm function
724  // and stores them in the vector {compilation_units} within the
725  // {compilation_state}. By adding units to the {compilation_state}, new
726  // {BackgroundCompileTask} instances are spawned which run on
727  // background threads.
728  InitializeCompilationUnits(native_module, isolate->wasm_engine());
729 
730  // 2.a) The background threads and the main thread pick one compilation
731  // unit at a time and execute the parallel phase of the compilation
732  // unit. After finishing the execution of the parallel phase, the
733  // result is enqueued in {baseline_finish_units_}.
734  // The foreground task bypasses waiting on memory threshold, because
735  // its results will immediately be converted to code (below).
736  WasmFeatures detected_features;
737  CompilationEnv env = native_module->CreateCompilationEnv();
738  while (FetchAndExecuteCompilationUnit(&env, compilation_state,
739  &detected_features,
740  isolate->counters()) &&
741  !compilation_state->baseline_compilation_finished()) {
742  // 2.b) If {baseline_finish_units_} contains a compilation unit, the main
743  // thread dequeues it and finishes the compilation unit. Compilation
744  // units are finished concurrently to the background threads to save
745  // memory.
746  FinishCompilationUnits(compilation_state);
747 
748  if (compilation_state->failed()) break;
749  }
750 
751  while (!compilation_state->failed()) {
752  // 3) After the parallel phase of all compilation units has started, the
753  // main thread continues to finish compilation units as long as
754  // baseline compilation units are left to be processed. If compilation
755  // already failed, all background tasks have already been canceled
756  // in {FinishCompilationUnits}, and there are no units to finish.
757  FinishCompilationUnits(compilation_state);
758 
759  if (compilation_state->baseline_compilation_finished()) break;
760  }
761 
762  // Publish features from the foreground and background tasks.
763  compilation_state->PublishDetectedFeatures(isolate, detected_features);
764 
765  // 4) If tiering-compilation is enabled, we need to set the finisher
766  // to false, such that the background threads will spawn a foreground
767  // thread to finish the top-tier compilation units.
768  if (!compilation_state->failed() &&
769  compilation_state->compile_mode() == CompileMode::kTiering) {
770  compilation_state->SetFinisherIsRunning(false);
771  }
772 }
773 
774 void CompileSequentially(Isolate* isolate, NativeModule* native_module,
775  ErrorThrower* thrower) {
776  DCHECK(!thrower->error());
777 
778  ModuleWireBytes wire_bytes(native_module->wire_bytes());
779  const WasmModule* module = native_module->module();
780  WasmFeatures detected = kNoWasmFeatures;
781  for (uint32_t i = 0; i < module->functions.size(); ++i) {
782  const WasmFunction& func = module->functions[i];
783  if (func.imported) continue; // Imports are compiled at instantiation time.
784 
785  // Compile the function.
786  bool success = WasmCompilationUnit::CompileWasmFunction(
787  isolate, native_module, &detected, &func);
788  if (!success) {
789  thrower->CompileFailed(
790  Impl(native_module->compilation_state())->GetCompileError());
791  break;
792  }
793  }
794  UpdateFeatureUseCounts(isolate, detected);
795 }
796 
797 void ValidateSequentially(Isolate* isolate, NativeModule* native_module,
798  ErrorThrower* thrower) {
799  DCHECK(!thrower->error());
800 
801  ModuleWireBytes wire_bytes(native_module->wire_bytes());
802  const WasmModule* module = native_module->module();
803  uint32_t start = module->num_imported_functions;
804  uint32_t end = start + module->num_declared_functions;
805  for (uint32_t i = start; i < end; ++i) {
806  const WasmFunction& func = module->functions[i];
807 
808  const byte* base = wire_bytes.start();
809  FunctionBody body{func.sig, func.code.offset(), base + func.code.offset(),
810  base + func.code.end_offset()};
811  DecodeResult result;
812  {
813  auto time_counter = SELECT_WASM_COUNTER(
814  isolate->counters(), module->origin, wasm_decode, function_time);
815 
816  TimedHistogramScope wasm_decode_function_time_scope(time_counter);
817  WasmFeatures detected;
818  result = VerifyWasmCode(isolate->allocator(),
819  native_module->enabled_features(), module,
820  &detected, body);
821  }
822  if (result.failed()) {
823  TruncatedUserString<> name(wire_bytes.GetNameOrNull(&func, module));
824  thrower->CompileError("Compiling function #%d:%.*s failed: %s @+%u", i,
825  name.length(), name.start(),
826  result.error_msg().c_str(), result.error_offset());
827  break;
828  }
829  }
830 }
831 
832 void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
833  const WasmModule* wasm_module,
834  NativeModule* native_module) {
835  ModuleWireBytes wire_bytes(native_module->wire_bytes());
836 
837  if (compile_lazy(wasm_module)) {
838  if (wasm_module->origin == kWasmOrigin) {
839  // Validate wasm modules for lazy compilation. Don't validate asm.js
840  // modules, they are valid by construction (otherwise a CHECK will fail
841  // during lazy compilation).
842  // TODO(clemensh): According to the spec, we can actually skip validation
843  // at module creation time, and return a function that always traps at
844  // (lazy) compilation time.
845  ValidateSequentially(isolate, native_module, thrower);
846  if (thrower->error()) return;
847  }
848 
849  native_module->SetLazyBuiltin(BUILTIN_CODE(isolate, WasmCompileLazy));
850  } else {
851  size_t funcs_to_compile =
852  wasm_module->functions.size() - wasm_module->num_imported_functions;
853  bool compile_parallel =
854  !FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks > 0 &&
855  funcs_to_compile > 1 &&
856  V8::GetCurrentPlatform()->NumberOfWorkerThreads() > 0;
857 
858  if (compile_parallel) {
859  CompileInParallel(isolate, native_module);
860  } else {
861  CompileSequentially(isolate, native_module, thrower);
862  }
863  auto* compilation_state = Impl(native_module->compilation_state());
864  if (compilation_state->failed()) {
865  thrower->CompileFailed(compilation_state->GetCompileError());
866  }
867  }
868 }
869 
870 // The runnable task that finishes compilation in foreground (e.g. updating
871 // the NativeModule, the code table, etc.).
872 class FinishCompileTask : public CancelableTask {
873  public:
874  explicit FinishCompileTask(CompilationStateImpl* compilation_state,
875  CancelableTaskManager* task_manager)
876  : CancelableTask(task_manager), compilation_state_(compilation_state) {}
877 
878  void RunInternal() override {
879  Isolate* isolate = compilation_state_->isolate();
880  HandleScope scope(isolate);
881  SaveContext saved_context(isolate);
882  isolate->set_context(Context());
883 
884  TRACE_COMPILE("(4a) Finishing compilation units...\n");
885  if (compilation_state_->failed()) {
886  compilation_state_->SetFinisherIsRunning(false);
887  return;
888  }
889 
890  // We execute for 1 ms and then reschedule the task, same as the GC.
891  double deadline = MonotonicallyIncreasingTimeInMs() + 1.0;
892  while (true) {
893  compilation_state_->RestartBackgroundTasks();
894 
895  std::unique_ptr<WasmCompilationUnit> unit =
896  compilation_state_->GetNextExecutedUnit();
897 
898  if (unit == nullptr) {
899  // It might happen that a background task just scheduled a unit to be
900  // finished, but did not start a finisher task since the flag was still
901  // set. Check for this case, and continue if there is more work.
902  compilation_state_->SetFinisherIsRunning(false);
903  if (compilation_state_->HasCompilationUnitToFinish() &&
904  compilation_state_->SetFinisherIsRunning(true)) {
905  continue;
906  }
907  break;
908  }
909 
910  DCHECK_IMPLIES(unit->failed(), compilation_state_->failed());
911  if (unit->failed()) break;
912 
913  // Update the compilation state, and possibly notify
914  // threads waiting for events.
915  compilation_state_->OnFinishedUnit();
916 
917  if (deadline < MonotonicallyIncreasingTimeInMs()) {
918  // We reached the deadline. We reschedule this task and return
919  // immediately. Since we rescheduled this task already, we do not set
920  // the FinisherIsRunning flag to false.
921  compilation_state_->ScheduleFinisherTask();
922  return;
923  }
924  }
925  }
926 
927  private:
928  CompilationStateImpl* compilation_state_;
929 };
930 
931 // The runnable task that performs compilations in the background.
932 class BackgroundCompileTask : public CancelableTask {
933  public:
934  explicit BackgroundCompileTask(CancelableTaskManager* task_manager,
935  NativeModule* native_module,
936  Counters* counters)
937  : CancelableTask(task_manager),
938  native_module_(native_module),
939  counters_(counters) {}
940 
941  void RunInternal() override {
942  TRACE_COMPILE("(3b) Compiling...\n");
943  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
944  "BackgroundCompileTask::RunInternal");
945  // The number of currently running background tasks is reduced in
946  // {OnBackgroundTaskStopped}.
947  CompilationEnv env = native_module_->CreateCompilationEnv();
948  auto* compilation_state = Impl(native_module_->compilation_state());
949  WasmFeatures detected_features = kNoWasmFeatures;
950  while (!compilation_state->failed()) {
951  if (!FetchAndExecuteCompilationUnit(&env, compilation_state,
952  &detected_features, counters_)) {
953  break;
954  }
955  }
956  compilation_state->OnBackgroundTaskStopped(detected_features);
957  }
958 
959  private:
960  NativeModule* const native_module_;
961  Counters* const counters_;
962 };
963 
964 } // namespace
965 
966 std::unique_ptr<NativeModule> CompileToNativeModule(
967  Isolate* isolate, const WasmFeatures& enabled, ErrorThrower* thrower,
968  std::shared_ptr<const WasmModule> module, const ModuleWireBytes& wire_bytes,
969  Handle<FixedArray>* export_wrappers_out) {
970  const WasmModule* wasm_module = module.get();
971  TimedHistogramScope wasm_compile_module_time_scope(SELECT_WASM_COUNTER(
972  isolate->counters(), wasm_module->origin, wasm_compile, module_time));
973 
974  // Embedder usage count for declared shared memories.
975  if (wasm_module->has_shared_memory) {
976  isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
977  }
978  int export_wrapper_size = static_cast<int>(module->num_exported_functions);
979 
980  // TODO(wasm): only save the sections necessary to deserialize a
981  // {WasmModule}. E.g. function bodies could be omitted.
982  OwnedVector<uint8_t> wire_bytes_copy =
983  OwnedVector<uint8_t>::Of(wire_bytes.module_bytes());
984 
985  // Create and compile the native module.
986  size_t code_size_estimate =
987  wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
988 
989  // Create a new {NativeModule} first.
990  auto native_module = isolate->wasm_engine()->code_manager()->NewNativeModule(
991  isolate, enabled, code_size_estimate,
992  wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
993  native_module->SetWireBytes(std::move(wire_bytes_copy));
994  native_module->SetRuntimeStubs(isolate);
995 
996  CompileNativeModule(isolate, thrower, wasm_module, native_module.get());
997  if (thrower->error()) return {};
998 
999  // Compile JS->wasm wrappers for exported functions.
1000  *export_wrappers_out =
1001  isolate->factory()->NewFixedArray(export_wrapper_size, TENURED);
1002  CompileJsToWasmWrappers(isolate, native_module.get(), *export_wrappers_out);
1003 
1004  // Log the code within the generated module for profiling.
1005  native_module->LogWasmCodes(isolate);
1006 
1007  return native_module;
1008 }
1009 
1010 InstanceBuilder::InstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
1011  Handle<WasmModuleObject> module_object,
1012  MaybeHandle<JSReceiver> ffi,
1013  MaybeHandle<JSArrayBuffer> memory)
1014  : isolate_(isolate),
1015  enabled_(module_object->native_module()->enabled_features()),
1016  module_(module_object->module()),
1017  thrower_(thrower),
1018  module_object_(module_object),
1019  ffi_(ffi),
1020  memory_(memory) {
1021  sanitized_imports_.reserve(module_->import_table.size());
1022 }
1023 
1024 // Build an instance, in all of its glory.
1025 MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
1026  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "InstanceBuilder::Build");
1027  // Check that an imports argument was provided, if the module requires it.
1028  // No point in continuing otherwise.
1029  if (!module_->import_table.empty() && ffi_.is_null()) {
1030  thrower_->TypeError(
1031  "Imports argument must be present and must be an object");
1032  return {};
1033  }
1034 
1035  SanitizeImports();
1036  if (thrower_->error()) return {};
1037 
1038  // TODO(6792): No longer needed once WebAssembly code is off heap.
1039  CodeSpaceMemoryModificationScope modification_scope(isolate_->heap());
1040  // From here on, we expect the build pipeline to run without exiting to JS.
1041  DisallowJavascriptExecution no_js(isolate_);
1042  // Record build time into correct bucket, then build instance.
1043  TimedHistogramScope wasm_instantiate_module_time_scope(SELECT_WASM_COUNTER(
1044  isolate_->counters(), module_->origin, wasm_instantiate, module_time));
1045 
1046  //--------------------------------------------------------------------------
1047  // Allocate the memory array buffer.
1048  //--------------------------------------------------------------------------
1049  // We allocate the memory buffer before cloning or reusing the compiled module
1050  // so we will know whether we need to recompile with bounds checks.
1051  uint32_t initial_pages = module_->initial_pages;
1052  auto initial_pages_counter = SELECT_WASM_COUNTER(
1053  isolate_->counters(), module_->origin, wasm, min_mem_pages_count);
1054  initial_pages_counter->AddSample(initial_pages);
1055  // Asm.js has memory_ already set at this point, so we don't want to
1056  // overwrite it.
1057  if (memory_.is_null()) {
1058  memory_ = FindImportedMemoryBuffer();
1059  }
1060  if (!memory_.is_null()) {
1061  // Set externally passed ArrayBuffer non neuterable.
1062  Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
1063  memory->set_is_neuterable(false);
1064 
1065  DCHECK_IMPLIES(use_trap_handler(), module_->origin == kAsmJsOrigin ||
1066  memory->is_wasm_memory() ||
1067  memory->backing_store() == nullptr);
1068  } else if (initial_pages > 0 || use_trap_handler()) {
1069  // We need to unconditionally create a guard region if using trap handlers,
1070  // even when the size is zero to prevent null-dereference issues
1071  // (e.g. https://crbug.com/769637).
1072  // Allocate memory if the initial size is more than 0 pages.
1073  memory_ = AllocateMemory(initial_pages);
1074  if (memory_.is_null()) {
1075  // failed to allocate memory
1076  DCHECK(isolate_->has_pending_exception() || thrower_->error());
1077  return {};
1078  }
1079  }
1080 
1081  //--------------------------------------------------------------------------
1082  // Recompile module if using trap handlers but could not get guarded memory
1083  //--------------------------------------------------------------------------
1084  if (module_->origin == kWasmOrigin && use_trap_handler()) {
1085  // Make sure the memory has suitable guard regions.
1086  WasmMemoryTracker* const memory_tracker =
1087  isolate_->wasm_engine()->memory_tracker();
1088 
1089  if (!memory_tracker->HasFullGuardRegions(
1090  memory_.ToHandleChecked()->backing_store())) {
1091  if (!FLAG_wasm_trap_handler_fallback) {
1092  thrower_->LinkError(
1093  "Provided memory is lacking guard regions but fallback was "
1094  "disabled.");
1095  return {};
1096  }
1097 
1098  TRACE("Recompiling module without bounds checks\n");
1099  constexpr bool allow_trap_handler = false;
1100  // TODO(wasm): Fix this before enabling the trap handler fallback.
1101  USE(allow_trap_handler);
1102  // Disable trap handlers on this native module.
1103  NativeModule* native_module = module_object_->native_module();
1104  native_module->DisableTrapHandler();
1105 
1106  // Recompile all functions in this native module.
1107  ErrorThrower thrower(isolate_, "recompile");
1108  CompileNativeModule(isolate_, &thrower, module_, native_module);
1109  if (thrower.error()) {
1110  return {};
1111  }
1112  DCHECK(!native_module->use_trap_handler());
1113  }
1114  }
1115 
1116  //--------------------------------------------------------------------------
1117  // Create the WebAssembly.Instance object.
1118  //--------------------------------------------------------------------------
1119  NativeModule* native_module = module_object_->native_module();
1120  TRACE("New module instantiation for %p\n", native_module);
1121  Handle<WasmInstanceObject> instance =
1122  WasmInstanceObject::New(isolate_, module_object_);
1123  NativeModuleModificationScope native_modification_scope(native_module);
1124 
1125  //--------------------------------------------------------------------------
1126  // Set up the globals for the new instance.
1127  //--------------------------------------------------------------------------
1128  uint32_t globals_buffer_size = module_->globals_buffer_size;
1129  if (globals_buffer_size > 0) {
1130  void* backing_store =
1131  isolate_->array_buffer_allocator()->Allocate(globals_buffer_size);
1132  if (backing_store == nullptr) {
1133  thrower_->RangeError("Out of memory: wasm globals");
1134  return {};
1135  }
1136  globals_ =
1137  isolate_->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, TENURED);
1138  constexpr bool is_external = false;
1139  constexpr bool is_wasm_memory = false;
1140  JSArrayBuffer::Setup(globals_, isolate_, is_external, backing_store,
1141  globals_buffer_size, SharedFlag::kNotShared,
1142  is_wasm_memory);
1143  if (globals_.is_null()) {
1144  thrower_->RangeError("Out of memory: wasm globals");
1145  return {};
1146  }
1147  instance->set_globals_start(
1148  reinterpret_cast<byte*>(globals_->backing_store()));
1149  instance->set_globals_buffer(*globals_);
1150  }
1151 
1152  //--------------------------------------------------------------------------
1153  // Set up the array of references to imported globals' array buffers.
1154  //--------------------------------------------------------------------------
1155  if (module_->num_imported_mutable_globals > 0) {
1156  // TODO(binji): This allocates one slot for each mutable global, which is
1157  // more than required if multiple globals are imported from the same
1158  // module.
1159  Handle<FixedArray> buffers_array = isolate_->factory()->NewFixedArray(
1160  module_->num_imported_mutable_globals, TENURED);
1161  instance->set_imported_mutable_globals_buffers(*buffers_array);
1162  }
1163 
1164  //--------------------------------------------------------------------------
1165  // Set up the exception table used for exception tag checks.
1166  //--------------------------------------------------------------------------
1167  int exceptions_count = static_cast<int>(module_->exceptions.size());
1168  if (exceptions_count > 0) {
1169  Handle<FixedArray> exception_table =
1170  isolate_->factory()->NewFixedArray(exceptions_count, TENURED);
1171  instance->set_exceptions_table(*exception_table);
1172  exception_wrappers_.resize(exceptions_count);
1173  }
1174 
1175  //--------------------------------------------------------------------------
1176  // Reserve the metadata for indirect function tables.
1177  //--------------------------------------------------------------------------
1178  int table_count = static_cast<int>(module_->tables.size());
1179  table_instances_.resize(table_count);
1180 
1181  //--------------------------------------------------------------------------
1182  // Process the imports for the module.
1183  //--------------------------------------------------------------------------
1184  int num_imported_functions = ProcessImports(instance);
1185  if (num_imported_functions < 0) return {};
1186 
1187  //--------------------------------------------------------------------------
1188  // Process the initialization for the module's globals.
1189  //--------------------------------------------------------------------------
1190  InitGlobals();
1191 
1192  //--------------------------------------------------------------------------
1193  // Initialize the indirect tables.
1194  //--------------------------------------------------------------------------
1195  if (table_count > 0) {
1196  InitializeTables(instance);
1197  }
1198 
1199  //--------------------------------------------------------------------------
1200  // Initialize the exceptions table.
1201  //--------------------------------------------------------------------------
1202  if (exceptions_count > 0) {
1203  InitializeExceptions(instance);
1204  }
1205 
1206  //--------------------------------------------------------------------------
1207  // Create the WebAssembly.Memory object.
1208  //--------------------------------------------------------------------------
1209  if (module_->has_memory) {
1210  if (!instance->has_memory_object()) {
1211  // No memory object exists. Create one.
1212  Handle<WasmMemoryObject> memory_object = WasmMemoryObject::New(
1213  isolate_, memory_,
1214  module_->maximum_pages != 0 ? module_->maximum_pages : -1);
1215  instance->set_memory_object(*memory_object);
1216  }
1217 
1218  // Add the instance object to the list of instances for this memory.
1219  Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate_);
1220  WasmMemoryObject::AddInstance(isolate_, memory_object, instance);
1221 
1222  if (!memory_.is_null()) {
1223  // Double-check the {memory} array buffer matches the instance.
1224  Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
1225  CHECK_EQ(instance->memory_size(), memory->byte_length());
1226  CHECK_EQ(instance->memory_start(), memory->backing_store());
1227  }
1228  }
1229 
1230  //--------------------------------------------------------------------------
1231  // Check that indirect function table segments are within bounds.
1232  //--------------------------------------------------------------------------
1233  for (const WasmTableInit& table_init : module_->table_inits) {
1234  if (!table_init.active) continue;
1235  DCHECK(table_init.table_index < table_instances_.size());
1236  uint32_t base = EvalUint32InitExpr(table_init.offset);
1237  size_t table_size = table_instances_[table_init.table_index].table_size;
1238  if (!in_bounds(base, table_init.entries.size(), table_size)) {
1239  thrower_->LinkError("table initializer is out of bounds");
1240  return {};
1241  }
1242  }
1243 
1244  //--------------------------------------------------------------------------
1245  // Check that memory segments are within bounds.
1246  //--------------------------------------------------------------------------
1247  for (const WasmDataSegment& seg : module_->data_segments) {
1248  if (!seg.active) continue;
1249  uint32_t base = EvalUint32InitExpr(seg.dest_addr);
1250  if (!in_bounds(base, seg.source.length(), instance->memory_size())) {
1251  thrower_->LinkError("data segment is out of bounds");
1252  return {};
1253  }
1254  }
1255 
1256  //--------------------------------------------------------------------------
1257  // Set up the exports object for the new instance.
1258  //--------------------------------------------------------------------------
1259  ProcessExports(instance);
1260  if (thrower_->error()) return {};
1261 
1262  //--------------------------------------------------------------------------
1263  // Initialize the indirect function tables.
1264  //--------------------------------------------------------------------------
1265  if (table_count > 0) {
1266  LoadTableSegments(instance);
1267  }
1268 
1269  //--------------------------------------------------------------------------
1270  // Initialize the memory by loading data segments.
1271  //--------------------------------------------------------------------------
1272  if (module_->data_segments.size() > 0) {
1273  LoadDataSegments(instance);
1274  }
1275 
1276  //--------------------------------------------------------------------------
1277  // Debugging support.
1278  //--------------------------------------------------------------------------
1279  // Set all breakpoints that were set on the shared module.
1280  WasmModuleObject::SetBreakpointsOnNewInstance(module_object_, instance);
1281 
1282  if (FLAG_wasm_interpret_all && module_->origin == kWasmOrigin) {
1283  Handle<WasmDebugInfo> debug_info =
1284  WasmInstanceObject::GetOrCreateDebugInfo(instance);
1285  std::vector<int> func_indexes;
1286  for (int func_index = num_imported_functions,
1287  num_wasm_functions = static_cast<int>(module_->functions.size());
1288  func_index < num_wasm_functions; ++func_index) {
1289  func_indexes.push_back(func_index);
1290  }
1291  WasmDebugInfo::RedirectToInterpreter(debug_info, VectorOf(func_indexes));
1292  }
1293 
1294  //--------------------------------------------------------------------------
1295  // Create a wrapper for the start function.
1296  //--------------------------------------------------------------------------
1297  if (module_->start_function_index >= 0) {
1298  int start_index = module_->start_function_index;
1299  auto& function = module_->functions[start_index];
1300  Handle<Code> wrapper_code = js_to_wasm_cache_.GetOrCompileJSToWasmWrapper(
1301  isolate_, function.sig, function.imported);
1302  // TODO(clemensh): Don't generate an exported function for the start
1303  // function. Use CWasmEntry instead.
1304  start_function_ = WasmExportedFunction::New(
1305  isolate_, instance, MaybeHandle<String>(), start_index,
1306  static_cast<int>(function.sig->parameter_count()), wrapper_code);
1307  }
1308 
1309  DCHECK(!isolate_->has_pending_exception());
1310  TRACE("Successfully built instance for module %p\n",
1311  module_object_->native_module());
1312  return instance;
1313 }
1314 
1315 bool InstanceBuilder::ExecuteStartFunction() {
1316  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
1317  "InstanceBuilder::ExecuteStartFunction");
1318  if (start_function_.is_null()) return true; // No start function.
1319 
1320  HandleScope scope(isolate_);
1321  // Call the JS function.
1322  Handle<Object> undefined = isolate_->factory()->undefined_value();
1323  MaybeHandle<Object> retval =
1324  Execution::Call(isolate_, start_function_, undefined, 0, nullptr);
1325 
1326  if (retval.is_null()) {
1327  DCHECK(isolate_->has_pending_exception());
1328  return false;
1329  }
1330  return true;
1331 }
1332 
1333 // Look up an import value in the {ffi_} object.
1334 MaybeHandle<Object> InstanceBuilder::LookupImport(uint32_t index,
1335  Handle<String> module_name,
1336 
1337  Handle<String> import_name) {
1338  // We pre-validated in the js-api layer that the ffi object is present, and
1339  // a JSObject, if the module has imports.
1340  DCHECK(!ffi_.is_null());
1341 
1342  // Look up the module first.
1343  MaybeHandle<Object> result = Object::GetPropertyOrElement(
1344  isolate_, ffi_.ToHandleChecked(), module_name);
1345  if (result.is_null()) {
1346  return ReportTypeError("module not found", index, module_name);
1347  }
1348 
1349  Handle<Object> module = result.ToHandleChecked();
1350 
1351  // Look up the value in the module.
1352  if (!module->IsJSReceiver()) {
1353  return ReportTypeError("module is not an object or function", index,
1354  module_name);
1355  }
1356 
1357  result = Object::GetPropertyOrElement(isolate_, module, import_name);
1358  if (result.is_null()) {
1359  ReportLinkError("import not found", index, module_name, import_name);
1360  return MaybeHandle<JSFunction>();
1361  }
1362 
1363  return result;
1364 }
1365 
1366 // Look up an import value in the {ffi_} object specifically for linking an
1367 // asm.js module. This only performs non-observable lookups, which allows
1368 // falling back to JavaScript proper (and hence re-executing all lookups) if
1369 // module instantiation fails.
1370 MaybeHandle<Object> InstanceBuilder::LookupImportAsm(
1371  uint32_t index, Handle<String> import_name) {
1372  // Check that a foreign function interface object was provided.
1373  if (ffi_.is_null()) {
1374  return ReportLinkError("missing imports object", index, import_name);
1375  }
1376 
1377  // Perform lookup of the given {import_name} without causing any observable
1378  // side-effect. We only accept accesses that resolve to data properties,
1379  // which is indicated by the asm.js spec in section 7 ("Linking") as well.
1380  Handle<Object> result;
1381  LookupIterator it = LookupIterator::PropertyOrElement(
1382  isolate_, ffi_.ToHandleChecked(), import_name);
1383  switch (it.state()) {
1384  case LookupIterator::ACCESS_CHECK:
1385  case LookupIterator::INTEGER_INDEXED_EXOTIC:
1386  case LookupIterator::INTERCEPTOR:
1387  case LookupIterator::JSPROXY:
1388  case LookupIterator::ACCESSOR:
1389  case LookupIterator::TRANSITION:
1390  return ReportLinkError("not a data property", index, import_name);
1391  case LookupIterator::NOT_FOUND:
1392  // Accepting missing properties as undefined does not cause any
1393  // observable difference from JavaScript semantics, we are lenient.
1394  result = isolate_->factory()->undefined_value();
1395  break;
1396  case LookupIterator::DATA:
1397  result = it.GetDataValue();
1398  break;
1399  }
1400 
1401  return result;
1402 }
1403 
1404 uint32_t InstanceBuilder::EvalUint32InitExpr(const WasmInitExpr& expr) {
1405  switch (expr.kind) {
1406  case WasmInitExpr::kI32Const:
1407  return expr.val.i32_const;
1408  case WasmInitExpr::kGlobalIndex: {
1409  uint32_t offset = module_->globals[expr.val.global_index].offset;
1410  return ReadLittleEndianValue<uint32_t>(
1411  reinterpret_cast<Address>(raw_buffer_ptr(globals_, offset)));
1412  }
1413  default:
1414  UNREACHABLE();
1415  }
1416 }
1417 
1418 // Load data segments into the memory.
1419 void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
1420  Vector<const uint8_t> wire_bytes =
1421  module_object_->native_module()->wire_bytes();
1422  for (const WasmDataSegment& segment : module_->data_segments) {
1423  uint32_t source_size = segment.source.length();
1424  // Segments of size == 0 are just nops.
1425  if (source_size == 0) continue;
1426  // Passive segments are not copied during instantiation.
1427  if (!segment.active) continue;
1428  uint32_t dest_offset = EvalUint32InitExpr(segment.dest_addr);
1429  DCHECK(in_bounds(dest_offset, source_size, instance->memory_size()));
1430  byte* dest = instance->memory_start() + dest_offset;
1431  const byte* src = wire_bytes.start() + segment.source.offset();
1432  memcpy(dest, src, source_size);
1433  }
1434 }
1435 
1436 void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, double num) {
1437  TRACE("init [globals_start=%p + %u] = %lf, type = %s\n",
1438  reinterpret_cast<void*>(raw_buffer_ptr(globals_, 0)), global.offset,
1439  num, ValueTypes::TypeName(global.type));
1440  switch (global.type) {
1441  case kWasmI32:
1442  WriteLittleEndianValue<int32_t>(GetRawGlobalPtr<int32_t>(global),
1443  static_cast<int32_t>(num));
1444  break;
1445  case kWasmI64:
1446  // TODO(titzer): initialization of imported i64 globals.
1447  UNREACHABLE();
1448  break;
1449  case kWasmF32:
1450  WriteLittleEndianValue<float>(GetRawGlobalPtr<float>(global),
1451  static_cast<float>(num));
1452  break;
1453  case kWasmF64:
1454  WriteLittleEndianValue<double>(GetRawGlobalPtr<double>(global),
1455  static_cast<double>(num));
1456  break;
1457  default:
1458  UNREACHABLE();
1459  }
1460 }
1461 
1462 void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global,
1463  Handle<WasmGlobalObject> value) {
1464  TRACE("init [globals_start=%p + %u] = ",
1465  reinterpret_cast<void*>(raw_buffer_ptr(globals_, 0)), global.offset);
1466  switch (global.type) {
1467  case kWasmI32: {
1468  int32_t num = value->GetI32();
1469  WriteLittleEndianValue<int32_t>(GetRawGlobalPtr<int32_t>(global), num);
1470  TRACE("%d", num);
1471  break;
1472  }
1473  case kWasmI64: {
1474  int64_t num = value->GetI64();
1475  WriteLittleEndianValue<int64_t>(GetRawGlobalPtr<int64_t>(global), num);
1476  TRACE("%" PRId64, num);
1477  break;
1478  }
1479  case kWasmF32: {
1480  float num = value->GetF32();
1481  WriteLittleEndianValue<float>(GetRawGlobalPtr<float>(global), num);
1482  TRACE("%f", num);
1483  break;
1484  }
1485  case kWasmF64: {
1486  double num = value->GetF64();
1487  WriteLittleEndianValue<double>(GetRawGlobalPtr<double>(global), num);
1488  TRACE("%lf", num);
1489  break;
1490  }
1491  default:
1492  UNREACHABLE();
1493  }
1494  TRACE(", type = %s (from WebAssembly.Global)\n",
1495  ValueTypes::TypeName(global.type));
1496 }
1497 
1498 void InstanceBuilder::SanitizeImports() {
1499  Vector<const uint8_t> wire_bytes =
1500  module_object_->native_module()->wire_bytes();
1501  for (size_t index = 0; index < module_->import_table.size(); ++index) {
1502  const WasmImport& import = module_->import_table[index];
1503 
1504  Handle<String> module_name;
1505  MaybeHandle<String> maybe_module_name =
1506  WasmModuleObject::ExtractUtf8StringFromModuleBytes(isolate_, wire_bytes,
1507  import.module_name);
1508  if (!maybe_module_name.ToHandle(&module_name)) {
1509  thrower_->LinkError("Could not resolve module name for import %zu",
1510  index);
1511  return;
1512  }
1513 
1514  Handle<String> import_name;
1515  MaybeHandle<String> maybe_import_name =
1516  WasmModuleObject::ExtractUtf8StringFromModuleBytes(isolate_, wire_bytes,
1517  import.field_name);
1518  if (!maybe_import_name.ToHandle(&import_name)) {
1519  thrower_->LinkError("Could not resolve import name for import %zu",
1520  index);
1521  return;
1522  }
1523 
1524  int int_index = static_cast<int>(index);
1525  MaybeHandle<Object> result =
1526  module_->origin == kAsmJsOrigin
1527  ? LookupImportAsm(int_index, import_name)
1528  : LookupImport(int_index, module_name, import_name);
1529  if (thrower_->error()) {
1530  thrower_->LinkError("Could not find value for import %zu", index);
1531  return;
1532  }
1533  Handle<Object> value = result.ToHandleChecked();
1534  sanitized_imports_.push_back({module_name, import_name, value});
1535  }
1536 }
1537 
1538 MaybeHandle<JSArrayBuffer> InstanceBuilder::FindImportedMemoryBuffer() const {
1539  DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
1540  for (size_t index = 0; index < module_->import_table.size(); index++) {
1541  const WasmImport& import = module_->import_table[index];
1542 
1543  if (import.kind == kExternalMemory) {
1544  const auto& value = sanitized_imports_[index].value;
1545  if (!value->IsWasmMemoryObject()) {
1546  return {};
1547  }
1548  auto memory = Handle<WasmMemoryObject>::cast(value);
1549  Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate_);
1550  return buffer;
1551  }
1552  }
1553  return {};
1554 }
1555 
1556 // Process the imports, including functions, tables, globals, and memory, in
1557 // order, loading them from the {ffi_} object. Returns the number of imported
1558 // functions.
1559 int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
1560  int num_imported_functions = 0;
1561  int num_imported_tables = 0;
1562  int num_imported_mutable_globals = 0;
1563 
1564  DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
1565  int num_imports = static_cast<int>(module_->import_table.size());
1566  NativeModule* native_module = instance->module_object()->native_module();
1567  for (int index = 0; index < num_imports; ++index) {
1568  const WasmImport& import = module_->import_table[index];
1569 
1570  Handle<String> module_name = sanitized_imports_[index].module_name;
1571  Handle<String> import_name = sanitized_imports_[index].import_name;
1572  Handle<Object> value = sanitized_imports_[index].value;
1573 
1574  switch (import.kind) {
1575  case kExternalFunction: {
1576  // Function imports must be callable.
1577  if (!value->IsCallable()) {
1578  ReportLinkError("function import requires a callable", index,
1579  module_name, import_name);
1580  return -1;
1581  }
1582  uint32_t func_index = import.index;
1583  DCHECK_EQ(num_imported_functions, func_index);
1584  auto js_receiver = Handle<JSReceiver>::cast(value);
1585  FunctionSig* expected_sig = module_->functions[func_index].sig;
1586  auto kind = compiler::GetWasmImportCallKind(js_receiver, expected_sig);
1587  switch (kind) {
1588  case compiler::WasmImportCallKind::kLinkError:
1589  ReportLinkError(
1590  "imported function does not match the expected type", index,
1591  module_name, import_name);
1592  return -1;
1593  case compiler::WasmImportCallKind::kWasmToWasm: {
1594  // The imported function is a WASM function from another instance.
1595  auto imported_function = Handle<WasmExportedFunction>::cast(value);
1596  Handle<WasmInstanceObject> imported_instance(
1597  imported_function->instance(), isolate_);
1598  // The import reference is the instance object itself.
1599  Address imported_target = imported_function->GetWasmCallTarget();
1600  ImportedFunctionEntry entry(instance, func_index);
1601  entry.SetWasmToWasm(*imported_instance, imported_target);
1602  break;
1603  }
1604  default: {
1605  // The imported function is a callable.
1606  WasmCode* wasm_code =
1607  native_module->import_wrapper_cache()->GetOrCompile(
1608  isolate_, kind, expected_sig);
1609  ImportedFunctionEntry entry(instance, func_index);
1610  if (wasm_code->kind() == WasmCode::kWasmToJsWrapper) {
1611  // Wasm to JS wrappers are treated specially in the import table.
1612  entry.SetWasmToJs(isolate_, js_receiver, wasm_code);
1613  } else {
1614  // Wasm math intrinsics are compiled as regular Wasm functions.
1615  DCHECK(kind >=
1616  compiler::WasmImportCallKind::kFirstMathIntrinsic &&
1617  kind <= compiler::WasmImportCallKind::kLastMathIntrinsic);
1618  entry.SetWasmToWasm(*instance, wasm_code->instruction_start());
1619  }
1620  break;
1621  }
1622  }
1623  num_imported_functions++;
1624  break;
1625  }
1626  case kExternalTable: {
1627  if (!value->IsWasmTableObject()) {
1628  ReportLinkError("table import requires a WebAssembly.Table", index,
1629  module_name, import_name);
1630  return -1;
1631  }
1632  uint32_t table_num = import.index;
1633  DCHECK_EQ(table_num, num_imported_tables);
1634  const WasmTable& table = module_->tables[table_num];
1635  TableInstance& table_instance = table_instances_[table_num];
1636  table_instance.table_object = Handle<WasmTableObject>::cast(value);
1637  instance->set_table_object(*table_instance.table_object);
1638  table_instance.js_wrappers = Handle<FixedArray>(
1639  table_instance.table_object->functions(), isolate_);
1640 
1641  int imported_table_size = table_instance.js_wrappers->length();
1642  if (imported_table_size < static_cast<int>(table.initial_size)) {
1643  thrower_->LinkError(
1644  "table import %d is smaller than initial %d, got %u", index,
1645  table.initial_size, imported_table_size);
1646  return -1;
1647  }
1648 
1649  if (table.has_maximum_size) {
1650  int64_t imported_maximum_size =
1651  table_instance.table_object->maximum_length()->Number();
1652  if (imported_maximum_size < 0) {
1653  thrower_->LinkError(
1654  "table import %d has no maximum length, expected %d", index,
1655  table.maximum_size);
1656  return -1;
1657  }
1658  if (imported_maximum_size > table.maximum_size) {
1659  thrower_->LinkError(
1660  " table import %d has a larger maximum size %" PRIx64
1661  " than the module's declared maximum %u",
1662  index, imported_maximum_size, table.maximum_size);
1663  return -1;
1664  }
1665  }
1666 
1667  // Allocate a new dispatch table.
1668  if (!instance->has_indirect_function_table()) {
1669  WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
1670  instance, imported_table_size);
1671  table_instances_[table_num].table_size = imported_table_size;
1672  }
1673  // Initialize the dispatch table with the (foreign) JS functions
1674  // that are already in the table.
1675  for (int i = 0; i < imported_table_size; ++i) {
1676  Handle<Object> val(table_instance.js_wrappers->get(i), isolate_);
1677  // TODO(mtrofin): this is the same logic as WasmTableObject::Set:
1678  // insert in the local table a wrapper from the other module, and add
1679  // a reference to the owning instance of the other module.
1680  if (!val->IsJSFunction()) continue;
1681  if (!WasmExportedFunction::IsWasmExportedFunction(*val)) {
1682  thrower_->LinkError("table import %d[%d] is not a wasm function",
1683  index, i);
1684  return -1;
1685  }
1686  auto target_func = Handle<WasmExportedFunction>::cast(val);
1687  Handle<WasmInstanceObject> target_instance =
1688  handle(target_func->instance(), isolate_);
1689  // Look up the signature's canonical id. If there is no canonical
1690  // id, then the signature does not appear at all in this module,
1691  // so putting {-1} in the table will cause checks to always fail.
1692  FunctionSig* sig = target_func->sig();
1693  IndirectFunctionTableEntry(instance, i)
1694  .Set(module_->signature_map.Find(*sig), target_instance,
1695  target_func->function_index());
1696  }
1697  num_imported_tables++;
1698  break;
1699  }
1700  case kExternalMemory: {
1701  // Validation should have failed if more than one memory object was
1702  // provided.
1703  DCHECK(!instance->has_memory_object());
1704  if (!value->IsWasmMemoryObject()) {
1705  ReportLinkError("memory import must be a WebAssembly.Memory object",
1706  index, module_name, import_name);
1707  return -1;
1708  }
1709  auto memory = Handle<WasmMemoryObject>::cast(value);
1710  instance->set_memory_object(*memory);
1711  Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate_);
1712  // memory_ should have already been assigned in Build().
1713  DCHECK_EQ(*memory_.ToHandleChecked(), *buffer);
1714  uint32_t imported_cur_pages =
1715  static_cast<uint32_t>(buffer->byte_length() / kWasmPageSize);
1716  if (imported_cur_pages < module_->initial_pages) {
1717  thrower_->LinkError(
1718  "memory import %d is smaller than initial %u, got %u", index,
1719  module_->initial_pages, imported_cur_pages);
1720  }
1721  int32_t imported_maximum_pages = memory->maximum_pages();
1722  if (module_->has_maximum_pages) {
1723  if (imported_maximum_pages < 0) {
1724  thrower_->LinkError(
1725  "memory import %d has no maximum limit, expected at most %u",
1726  index, imported_maximum_pages);
1727  return -1;
1728  }
1729  if (static_cast<uint32_t>(imported_maximum_pages) >
1730  module_->maximum_pages) {
1731  thrower_->LinkError(
1732  "memory import %d has a larger maximum size %u than the "
1733  "module's declared maximum %u",
1734  index, imported_maximum_pages, module_->maximum_pages);
1735  return -1;
1736  }
1737  }
1738  if (module_->has_shared_memory != buffer->is_shared()) {
1739  thrower_->LinkError(
1740  "mismatch in shared state of memory, declared = %d, imported = "
1741  "%d",
1742  module_->has_shared_memory, buffer->is_shared());
1743  return -1;
1744  }
1745 
1746  break;
1747  }
1748  case kExternalGlobal: {
1749  // Immutable global imports are converted to numbers and written into
1750  // the {globals_} array buffer.
1751  //
1752  // Mutable global imports instead have their backing array buffers
1753  // referenced by this instance, and store the address of the imported
1754  // global in the {imported_mutable_globals_} array.
1755  const WasmGlobal& global = module_->globals[import.index];
1756 
1757  // The mutable-global proposal allows importing i64 values, but only if
1758  // they are passed as a WebAssembly.Global object.
1759  if (global.type == kWasmI64 &&
1760  !(enabled_.mut_global && value->IsWasmGlobalObject())) {
1761  ReportLinkError("global import cannot have type i64", index,
1762  module_name, import_name);
1763  return -1;
1764  }
1765  if (module_->origin == kAsmJsOrigin) {
1766  // Accepting {JSFunction} on top of just primitive values here is a
1767  // workaround to support legacy asm.js code with broken binding. Note
1768  // that using {NaN} (or Smi::kZero) here is what using the observable
1769  // conversion via {ToPrimitive} would produce as well.
1770  // TODO(mstarzinger): Still observable if Function.prototype.valueOf
1771  // or friends are patched, we might need to check for that as well.
1772  if (value->IsJSFunction()) value = isolate_->factory()->nan_value();
1773  if (value->IsPrimitive() && !value->IsSymbol()) {
1774  if (global.type == kWasmI32) {
1775  value = Object::ToInt32(isolate_, value).ToHandleChecked();
1776  } else {
1777  value = Object::ToNumber(isolate_, value).ToHandleChecked();
1778  }
1779  }
1780  }
1781  if (enabled_.mut_global) {
1782  if (value->IsWasmGlobalObject()) {
1783  auto global_object = Handle<WasmGlobalObject>::cast(value);
1784  if (global_object->type() != global.type) {
1785  ReportLinkError(
1786  "imported global does not match the expected type", index,
1787  module_name, import_name);
1788  return -1;
1789  }
1790  if (global_object->is_mutable() != global.mutability) {
1791  ReportLinkError(
1792  "imported global does not match the expected mutability",
1793  index, module_name, import_name);
1794  return -1;
1795  }
1796  if (global.mutability) {
1797  Handle<JSArrayBuffer> buffer(global_object->array_buffer(),
1798  isolate_);
1799  int index = num_imported_mutable_globals++;
1800  instance->imported_mutable_globals_buffers()->set(index, *buffer);
1801  // It is safe in this case to store the raw pointer to the buffer
1802  // since the backing store of the JSArrayBuffer will not be
1803  // relocated.
1804  instance->imported_mutable_globals()[index] =
1805  reinterpret_cast<Address>(
1806  raw_buffer_ptr(buffer, global_object->offset()));
1807  } else {
1808  WriteGlobalValue(global, global_object);
1809  }
1810  } else if (value->IsNumber()) {
1811  if (global.mutability) {
1812  ReportLinkError(
1813  "imported mutable global must be a WebAssembly.Global object",
1814  index, module_name, import_name);
1815  return -1;
1816  }
1817  WriteGlobalValue(global, value->Number());
1818  } else {
1819  ReportLinkError(
1820  "global import must be a number or WebAssembly.Global object",
1821  index, module_name, import_name);
1822  return -1;
1823  }
1824  } else {
1825  if (value->IsNumber()) {
1826  WriteGlobalValue(global, value->Number());
1827  } else {
1828  ReportLinkError("global import must be a number", index,
1829  module_name, import_name);
1830  return -1;
1831  }
1832  }
1833  break;
1834  }
1835  case kExternalException: {
1836  if (!value->IsWasmExceptionObject()) {
1837  ReportLinkError("exception import requires a WebAssembly.Exception",
1838  index, module_name, import_name);
1839  return -1;
1840  }
1841  Handle<WasmExceptionObject> imported_exception =
1842  Handle<WasmExceptionObject>::cast(value);
1843  if (!imported_exception->IsSignatureEqual(
1844  module_->exceptions[import.index].sig)) {
1845  ReportLinkError("imported exception does not match the expected type",
1846  index, module_name, import_name);
1847  return -1;
1848  }
1849  Object* exception_tag = imported_exception->exception_tag();
1850  DCHECK(instance->exceptions_table()->get(import.index)->IsUndefined());
1851  instance->exceptions_table()->set(import.index, exception_tag);
1852  exception_wrappers_[import.index] = imported_exception;
1853  break;
1854  }
1855  default:
1856  UNREACHABLE();
1857  break;
1858  }
1859  }
1860 
1861  DCHECK_EQ(module_->num_imported_mutable_globals,
1862  num_imported_mutable_globals);
1863 
1864  return num_imported_functions;
1865 }
1866 
1867 template <typename T>
1868 T* InstanceBuilder::GetRawGlobalPtr(const WasmGlobal& global) {
1869  return reinterpret_cast<T*>(raw_buffer_ptr(globals_, global.offset));
1870 }
1871 
1872 // Process initialization of globals.
1873 void InstanceBuilder::InitGlobals() {
1874  for (auto global : module_->globals) {
1875  if (global.mutability && global.imported) {
1876  continue;
1877  }
1878 
1879  switch (global.init.kind) {
1880  case WasmInitExpr::kI32Const:
1881  WriteLittleEndianValue<int32_t>(GetRawGlobalPtr<int32_t>(global),
1882  global.init.val.i32_const);
1883  break;
1884  case WasmInitExpr::kI64Const:
1885  WriteLittleEndianValue<int64_t>(GetRawGlobalPtr<int64_t>(global),
1886  global.init.val.i64_const);
1887  break;
1888  case WasmInitExpr::kF32Const:
1889  WriteLittleEndianValue<float>(GetRawGlobalPtr<float>(global),
1890  global.init.val.f32_const);
1891  break;
1892  case WasmInitExpr::kF64Const:
1893  WriteLittleEndianValue<double>(GetRawGlobalPtr<double>(global),
1894  global.init.val.f64_const);
1895  break;
1896  case WasmInitExpr::kGlobalIndex: {
1897  // Initialize with another global.
1898  uint32_t new_offset = global.offset;
1899  uint32_t old_offset =
1900  module_->globals[global.init.val.global_index].offset;
1901  TRACE("init [globals+%u] = [globals+%d]\n", global.offset, old_offset);
1902  size_t size = (global.type == kWasmI64 || global.type == kWasmF64)
1903  ? sizeof(double)
1904  : sizeof(int32_t);
1905  memcpy(raw_buffer_ptr(globals_, new_offset),
1906  raw_buffer_ptr(globals_, old_offset), size);
1907  break;
1908  }
1909  case WasmInitExpr::kNone:
1910  // Happens with imported globals.
1911  break;
1912  default:
1913  UNREACHABLE();
1914  break;
1915  }
1916  }
1917 }
1918 
1919 // Allocate memory for a module instance as a new JSArrayBuffer.
1920 Handle<JSArrayBuffer> InstanceBuilder::AllocateMemory(uint32_t num_pages) {
1921  if (num_pages > max_mem_pages()) {
1922  thrower_->RangeError("Out of memory: wasm memory too large");
1923  return Handle<JSArrayBuffer>::null();
1924  }
1925  const bool is_shared_memory = module_->has_shared_memory && enabled_.threads;
1926  SharedFlag shared_flag =
1927  is_shared_memory ? SharedFlag::kShared : SharedFlag::kNotShared;
1928  Handle<JSArrayBuffer> mem_buffer;
1929  if (!NewArrayBuffer(isolate_, num_pages * kWasmPageSize, shared_flag)
1930  .ToHandle(&mem_buffer)) {
1931  thrower_->RangeError("Out of memory: wasm memory");
1932  }
1933  return mem_buffer;
1934 }
1935 
1936 bool InstanceBuilder::NeedsWrappers() const {
1937  if (module_->num_exported_functions > 0) return true;
1938  for (auto& table_instance : table_instances_) {
1939  if (!table_instance.js_wrappers.is_null()) return true;
1940  }
1941  for (auto& table : module_->tables) {
1942  if (table.exported) return true;
1943  }
1944  return false;
1945 }
1946 
1947 // Process the exports, creating wrappers for functions, tables, memories,
1948 // globals, and exceptions.
1949 void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
1950  Handle<FixedArray> export_wrappers(module_object_->export_wrappers(),
1951  isolate_);
1952  if (NeedsWrappers()) {
1953  // Fill the table to cache the exported JSFunction wrappers.
1954  js_wrappers_.insert(js_wrappers_.begin(), module_->functions.size(),
1955  Handle<JSFunction>::null());
1956 
1957  // If an imported WebAssembly function gets exported, the exported function
1958  // has to be identical to to imported function. Therefore we put all
1959  // imported WebAssembly functions into the js_wrappers_ list.
1960  for (int index = 0, end = static_cast<int>(module_->import_table.size());
1961  index < end; ++index) {
1962  const WasmImport& import = module_->import_table[index];
1963  if (import.kind == kExternalFunction) {
1964  Handle<Object> value = sanitized_imports_[index].value;
1965  if (WasmExportedFunction::IsWasmExportedFunction(*value)) {
1966  js_wrappers_[import.index] = Handle<JSFunction>::cast(value);
1967  }
1968  }
1969  }
1970  }
1971 
1972  Handle<JSObject> exports_object;
1973  bool is_asm_js = false;
1974  switch (module_->origin) {
1975  case kWasmOrigin: {
1976  // Create the "exports" object.
1977  exports_object = isolate_->factory()->NewJSObjectWithNullProto();
1978  break;
1979  }
1980  case kAsmJsOrigin: {
1981  Handle<JSFunction> object_function = Handle<JSFunction>(
1982  isolate_->native_context()->object_function(), isolate_);
1983  exports_object = isolate_->factory()->NewJSObject(object_function);
1984  is_asm_js = true;
1985  break;
1986  }
1987  default:
1988  UNREACHABLE();
1989  }
1990  instance->set_exports_object(*exports_object);
1991 
1992  Handle<String> single_function_name =
1993  isolate_->factory()->InternalizeUtf8String(AsmJs::kSingleFunctionName);
1994 
1995  PropertyDescriptor desc;
1996  desc.set_writable(is_asm_js);
1997  desc.set_enumerable(true);
1998  desc.set_configurable(is_asm_js);
1999 
2000  // Process each export in the export table.
2001  int export_index = 0; // Index into {export_wrappers}.
2002  for (const WasmExport& exp : module_->export_table) {
2003  Handle<String> name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
2004  isolate_, module_object_, exp.name)
2005  .ToHandleChecked();
2006  Handle<JSObject> export_to;
2007  if (is_asm_js && exp.kind == kExternalFunction &&
2008  String::Equals(isolate_, name, single_function_name)) {
2009  export_to = instance;
2010  } else {
2011  export_to = exports_object;
2012  }
2013 
2014  switch (exp.kind) {
2015  case kExternalFunction: {
2016  // Wrap and export the code as a JSFunction.
2017  const WasmFunction& function = module_->functions[exp.index];
2018  Handle<JSFunction> js_function = js_wrappers_[exp.index];
2019  if (js_function.is_null()) {
2020  // Wrap the exported code as a JSFunction.
2021  Handle<Code> export_code =
2022  export_wrappers->GetValueChecked<Code>(isolate_, export_index);
2023  MaybeHandle<String> func_name;
2024  if (is_asm_js) {
2025  // For modules arising from asm.js, honor the names section.
2026  WireBytesRef func_name_ref = module_->LookupFunctionName(
2027  module_object_->native_module()->wire_bytes(),
2028  function.func_index);
2029  func_name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
2030  isolate_, module_object_, func_name_ref)
2031  .ToHandleChecked();
2032  }
2033  js_function = WasmExportedFunction::New(
2034  isolate_, instance, func_name, function.func_index,
2035  static_cast<int>(function.sig->parameter_count()), export_code);
2036  js_wrappers_[exp.index] = js_function;
2037  }
2038  desc.set_value(js_function);
2039  export_index++;
2040  break;
2041  }
2042  case kExternalTable: {
2043  // Export a table as a WebAssembly.Table object.
2044  TableInstance& table_instance = table_instances_[exp.index];
2045  const WasmTable& table = module_->tables[exp.index];
2046  if (table_instance.table_object.is_null()) {
2047  uint32_t maximum = table.has_maximum_size ? table.maximum_size
2048  : FLAG_wasm_max_table_size;
2049  table_instance.table_object =
2050  WasmTableObject::New(isolate_, table.initial_size, maximum,
2051  &table_instance.js_wrappers);
2052  }
2053  desc.set_value(table_instance.table_object);
2054  break;
2055  }
2056  case kExternalMemory: {
2057  // Export the memory as a WebAssembly.Memory object. A WasmMemoryObject
2058  // should already be available if the module has memory, since we always
2059  // create or import it when building an WasmInstanceObject.
2060  DCHECK(instance->has_memory_object());
2061  desc.set_value(
2062  Handle<WasmMemoryObject>(instance->memory_object(), isolate_));
2063  break;
2064  }
2065  case kExternalGlobal: {
2066  const WasmGlobal& global = module_->globals[exp.index];
2067  if (enabled_.mut_global) {
2068  Handle<JSArrayBuffer> buffer;
2069  uint32_t offset;
2070 
2071  if (global.mutability && global.imported) {
2072  Handle<FixedArray> buffers_array(
2073  instance->imported_mutable_globals_buffers(), isolate_);
2074  buffer = buffers_array->GetValueChecked<JSArrayBuffer>(
2075  isolate_, global.index);
2076  Address global_addr =
2077  instance->imported_mutable_globals()[global.index];
2078 
2079  size_t buffer_size = buffer->byte_length();
2080  Address backing_store =
2081  reinterpret_cast<Address>(buffer->backing_store());
2082  CHECK(global_addr >= backing_store &&
2083  global_addr < backing_store + buffer_size);
2084  offset = static_cast<uint32_t>(global_addr - backing_store);
2085  } else {
2086  buffer = handle(instance->globals_buffer(), isolate_);
2087  offset = global.offset;
2088  }
2089 
2090  // Since the global's array buffer is always provided, allocation
2091  // should never fail.
2092  Handle<WasmGlobalObject> global_obj =
2093  WasmGlobalObject::New(isolate_, buffer, global.type, offset,
2094  global.mutability)
2095  .ToHandleChecked();
2096  desc.set_value(global_obj);
2097  } else {
2098  // Export the value of the global variable as a number.
2099  double num = 0;
2100  switch (global.type) {
2101  case kWasmI32:
2102  num = ReadLittleEndianValue<int32_t>(
2103  GetRawGlobalPtr<int32_t>(global));
2104  break;
2105  case kWasmF32:
2106  num =
2107  ReadLittleEndianValue<float>(GetRawGlobalPtr<float>(global));
2108  break;
2109  case kWasmF64:
2110  num = ReadLittleEndianValue<double>(
2111  GetRawGlobalPtr<double>(global));
2112  break;
2113  case kWasmI64:
2114  thrower_->LinkError(
2115  "export of globals of type I64 is not allowed.");
2116  return;
2117  default:
2118  UNREACHABLE();
2119  }
2120  desc.set_value(isolate_->factory()->NewNumber(num));
2121  }
2122  break;
2123  }
2124  case kExternalException: {
2125  const WasmException& exception = module_->exceptions[exp.index];
2126  Handle<WasmExceptionObject> wrapper = exception_wrappers_[exp.index];
2127  if (wrapper.is_null()) {
2128  Handle<HeapObject> exception_tag(
2129  HeapObject::cast(instance->exceptions_table()->get(exp.index)),
2130  isolate_);
2131  wrapper =
2132  WasmExceptionObject::New(isolate_, exception.sig, exception_tag);
2133  exception_wrappers_[exp.index] = wrapper;
2134  }
2135  desc.set_value(wrapper);
2136  break;
2137  }
2138  default:
2139  UNREACHABLE();
2140  break;
2141  }
2142 
2143  v8::Maybe<bool> status = JSReceiver::DefineOwnProperty(
2144  isolate_, export_to, name, &desc, kThrowOnError);
2145  if (!status.IsJust()) {
2146  TruncatedUserString<> trunc_name(name->GetCharVector<uint8_t>());
2147  thrower_->LinkError("export of %.*s failed.", trunc_name.length(),
2148  trunc_name.start());
2149  return;
2150  }
2151  }
2152  DCHECK_EQ(export_index, export_wrappers->length());
2153 
2154  if (module_->origin == kWasmOrigin) {
2155  v8::Maybe<bool> success =
2156  JSReceiver::SetIntegrityLevel(exports_object, FROZEN, kDontThrow);
2157  DCHECK(success.FromMaybe(false));
2158  USE(success);
2159  }
2160 }
2161 
2162 void InstanceBuilder::InitializeTables(Handle<WasmInstanceObject> instance) {
2163  size_t table_count = module_->tables.size();
2164  for (size_t index = 0; index < table_count; ++index) {
2165  const WasmTable& table = module_->tables[index];
2166  TableInstance& table_instance = table_instances_[index];
2167 
2168  if (!instance->has_indirect_function_table() &&
2169  table.type == kWasmAnyFunc) {
2170  WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
2171  instance, table.initial_size);
2172  table_instance.table_size = table.initial_size;
2173  }
2174  }
2175 }
2176 
2177 void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
2178  NativeModule* native_module = module_object_->native_module();
2179  for (auto& table_init : module_->table_inits) {
2180  // Passive segments are not copied during instantiation.
2181  if (!table_init.active) continue;
2182 
2183  uint32_t base = EvalUint32InitExpr(table_init.offset);
2184  uint32_t num_entries = static_cast<uint32_t>(table_init.entries.size());
2185  uint32_t index = table_init.table_index;
2186  TableInstance& table_instance = table_instances_[index];
2187  DCHECK(in_bounds(base, num_entries, table_instance.table_size));
2188  for (uint32_t i = 0; i < num_entries; ++i) {
2189  uint32_t func_index = table_init.entries[i];
2190  const WasmFunction* function = &module_->functions[func_index];
2191  int table_index = static_cast<int>(i + base);
2192 
2193  // Update the local dispatch table first.
2194  uint32_t sig_id = module_->signature_ids[function->sig_index];
2195  IndirectFunctionTableEntry(instance, table_index)
2196  .Set(sig_id, instance, func_index);
2197 
2198  if (!table_instance.table_object.is_null()) {
2199  // Update the table object's other dispatch tables.
2200  if (js_wrappers_[func_index].is_null()) {
2201  // No JSFunction entry yet exists for this function. Create one.
2202  // TODO(titzer): We compile JS->wasm wrappers for functions are
2203  // not exported but are in an exported table. This should be done
2204  // at module compile time and cached instead.
2205 
2206  Handle<Code> wrapper_code =
2207  js_to_wasm_cache_.GetOrCompileJSToWasmWrapper(
2208  isolate_, function->sig, function->imported);
2209  MaybeHandle<String> func_name;
2210  if (module_->origin == kAsmJsOrigin) {
2211  // For modules arising from asm.js, honor the names section.
2212  WireBytesRef func_name_ref = module_->LookupFunctionName(
2213  native_module->wire_bytes(), func_index);
2214  func_name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
2215  isolate_, module_object_, func_name_ref)
2216  .ToHandleChecked();
2217  }
2218  Handle<WasmExportedFunction> js_function = WasmExportedFunction::New(
2219  isolate_, instance, func_name, func_index,
2220  static_cast<int>(function->sig->parameter_count()), wrapper_code);
2221  js_wrappers_[func_index] = js_function;
2222  }
2223  table_instance.js_wrappers->set(table_index, *js_wrappers_[func_index]);
2224  // UpdateDispatchTables() updates all other dispatch tables, since
2225  // we have not yet added the dispatch table we are currently building.
2226  WasmTableObject::UpdateDispatchTables(
2227  isolate_, table_instance.table_object, table_index, function->sig,
2228  instance, func_index);
2229  }
2230  }
2231  }
2232 
2233  int table_count = static_cast<int>(module_->tables.size());
2234  for (int index = 0; index < table_count; ++index) {
2235  TableInstance& table_instance = table_instances_[index];
2236 
2237  // Add the new dispatch table at the end to avoid redundant lookups.
2238  if (!table_instance.table_object.is_null()) {
2239  WasmTableObject::AddDispatchTable(isolate_, table_instance.table_object,
2240  instance, index);
2241  }
2242  }
2243 }
2244 
2245 void InstanceBuilder::InitializeExceptions(
2246  Handle<WasmInstanceObject> instance) {
2247  Handle<FixedArray> exceptions_table(instance->exceptions_table(), isolate_);
2248  for (int index = 0; index < exceptions_table->length(); ++index) {
2249  if (!exceptions_table->get(index)->IsUndefined(isolate_)) continue;
2250  // TODO(mstarzinger): Tags provide an object identity for each exception,
2251  // using {JSObject} here is gigantic hack and we should use a dedicated
2252  // object with a much lighter footprint for this purpose here.
2253  Handle<HeapObject> exception_tag =
2254  isolate_->factory()->NewJSObjectWithNullProto();
2255  exceptions_table->set(index, *exception_tag);
2256  }
2257 }
2258 
2259 AsyncCompileJob::AsyncCompileJob(
2260  Isolate* isolate, const WasmFeatures& enabled,
2261  std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
2262  std::shared_ptr<CompilationResultResolver> resolver)
2263  : isolate_(isolate),
2264  enabled_features_(enabled),
2265  bytes_copy_(std::move(bytes_copy)),
2266  wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length),
2267  resolver_(std::move(resolver)) {
2268  v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
2269  v8::Platform* platform = V8::GetCurrentPlatform();
2270  foreground_task_runner_ = platform->GetForegroundTaskRunner(v8_isolate);
2271  // The handle for the context must be deferred.
2272  DeferredHandleScope deferred(isolate);
2273  native_context_ = Handle<Context>(context->native_context(), isolate);
2274  DCHECK(native_context_->IsNativeContext());
2275  deferred_handles_.push_back(deferred.Detach());
2276 }
2277 
2278 void AsyncCompileJob::Start() {
2279  DoAsync<DecodeModule>(isolate_->counters()); // --
2280 }
2281 
2282 void AsyncCompileJob::Abort() {
2283  // Removing this job will trigger the destructor, which will cancel all
2284  // compilation.
2285  isolate_->wasm_engine()->RemoveCompileJob(this);
2286 }
2287 
2289  public:
2291 
2292  bool ProcessModuleHeader(Vector<const uint8_t> bytes,
2293  uint32_t offset) override;
2294 
2295  bool ProcessSection(SectionCode section_code, Vector<const uint8_t> bytes,
2296  uint32_t offset) override;
2297 
2298  bool ProcessCodeSectionHeader(size_t functions_count, uint32_t offset,
2299  std::shared_ptr<WireBytesStorage>) override;
2300 
2301  bool ProcessFunctionBody(Vector<const uint8_t> bytes,
2302  uint32_t offset) override;
2303 
2304  void OnFinishedChunk() override;
2305 
2306  void OnFinishedStream(OwnedVector<uint8_t> bytes) override;
2307 
2308  void OnError(DecodeResult result) override;
2309 
2310  void OnAbort() override;
2311 
2312  bool Deserialize(Vector<const uint8_t> wire_bytes,
2313  Vector<const uint8_t> module_bytes) override;
2314 
2315  private:
2316  // Finishes the AsyncCompileJob with an error.
2317  void FinishAsyncCompileJobWithError(ResultBase result);
2318 
2319  void CommitCompilationUnits();
2320 
2321  ModuleDecoder decoder_;
2322  AsyncCompileJob* job_;
2323  std::unique_ptr<CompilationUnitBuilder> compilation_unit_builder_;
2324  uint32_t next_function_ = 0;
2325 };
2326 
2327 std::shared_ptr<StreamingDecoder> AsyncCompileJob::CreateStreamingDecoder() {
2328  DCHECK_NULL(stream_);
2329  stream_.reset(
2330  new StreamingDecoder(base::make_unique<AsyncStreamingProcessor>(this)));
2331  return stream_;
2332 }
2333 
2334 AsyncCompileJob::~AsyncCompileJob() {
2335  background_task_manager_.CancelAndWait();
2336  if (native_module_) Impl(native_module_->compilation_state())->Abort();
2337  // Tell the streaming decoder that the AsyncCompileJob is not available
2338  // anymore.
2339  // TODO(ahaas): Is this notification really necessary? Check
2340  // https://crbug.com/888170.
2341  if (stream_) stream_->NotifyCompilationEnded();
2342  CancelPendingForegroundTask();
2343  for (auto d : deferred_handles_) delete d;
2344 }
2345 
2346 void AsyncCompileJob::PrepareRuntimeObjects(
2347  std::shared_ptr<const WasmModule> module) {
2348  // Embedder usage count for declared shared memories.
2349  if (module->has_shared_memory) {
2350  isolate_->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
2351  }
2352 
2353  // Create heap objects for script and module bytes to be stored in the
2354  // module object. Asm.js is not compiled asynchronously.
2355  Handle<Script> script =
2356  CreateWasmScript(isolate_, wire_bytes_, module->source_map_url);
2357  Handle<ByteArray> asm_js_offset_table;
2358 
2359  // TODO(wasm): Improve efficiency of storing module wire bytes. Only store
2360  // relevant sections, not function bodies
2361 
2362  // Create the module object and populate with compiled functions and
2363  // information needed at instantiation time.
2364  // TODO(clemensh): For the same module (same bytes / same hash), we should
2365  // only have one {WasmModuleObject}. Otherwise, we might only set
2366  // breakpoints on a (potentially empty) subset of the instances.
2367  // Create the module object.
2368  module_object_ =
2369  WasmModuleObject::New(isolate_, enabled_features_, std::move(module),
2370  {std::move(bytes_copy_), wire_bytes_.length()},
2371  script, asm_js_offset_table);
2372  native_module_ = module_object_->native_module();
2373 
2374  {
2375  DeferredHandleScope deferred(isolate_);
2376  module_object_ = handle(*module_object_, isolate_);
2377  deferred_handles_.push_back(deferred.Detach());
2378  }
2379 }
2380 
2381 // This function assumes that it is executed in a HandleScope, and that a
2382 // context is set on the isolate.
2383 void AsyncCompileJob::FinishCompile(bool compile_wrappers) {
2384  DCHECK(!isolate_->context().is_null());
2385  // Finish the wasm script now and make it public to the debugger.
2386  Handle<Script> script(module_object_->script(), isolate_);
2387  if (script->type() == Script::TYPE_WASM &&
2388  module_object_->module()->source_map_url.size() != 0) {
2389  MaybeHandle<String> src_map_str = isolate_->factory()->NewStringFromUtf8(
2390  CStrVector(module_object_->module()->source_map_url.c_str()), TENURED);
2391  script->set_source_mapping_url(*src_map_str.ToHandleChecked());
2392  }
2393  isolate_->debug()->OnAfterCompile(script);
2394 
2395  // We can only update the feature counts once the entire compile is done.
2396  auto compilation_state = Impl(native_module_->compilation_state());
2397  compilation_state->PublishDetectedFeatures(
2398  isolate_, *compilation_state->detected_features());
2399 
2400  // TODO(bbudge) Allow deserialization without wrapper compilation, so we can
2401  // just compile wrappers here.
2402  if (compile_wrappers) {
2403  DoSync<CompileWrappers>();
2404  } else {
2405  // TODO(wasm): compiling wrappers should be made async as well.
2406  DoSync<AsyncCompileJob::FinishModule>();
2407  }
2408 }
2409 
2410 void AsyncCompileJob::AsyncCompileFailed(Handle<Object> error_reason) {
2411  // {job} keeps the {this} pointer alive.
2412  std::shared_ptr<AsyncCompileJob> job =
2413  isolate_->wasm_engine()->RemoveCompileJob(this);
2414  resolver_->OnCompilationFailed(error_reason);
2415 }
2416 
2417 void AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) {
2418  resolver_->OnCompilationSucceeded(result);
2419 }
2420 
2422  public:
2423  explicit CompilationStateCallback(AsyncCompileJob* job) : job_(job) {}
2424 
2425  void operator()(CompilationEvent event, const VoidResult* error_result) {
2426  // This callback is only being called from a foreground task.
2427  switch (event) {
2428  case CompilationEvent::kFinishedBaselineCompilation:
2429  DCHECK(!last_event_.has_value());
2430  if (job_->DecrementAndCheckFinisherCount()) {
2431  SaveContext saved_context(job_->isolate());
2432  job_->isolate()->set_context(*job_->native_context_);
2433  job_->FinishCompile(true);
2434  }
2435  break;
2436  case CompilationEvent::kFinishedTopTierCompilation:
2437  DCHECK_EQ(CompilationEvent::kFinishedBaselineCompilation, last_event_);
2438  // Notify embedder that compilation is finished.
2439  if (job_->stream_ && job_->stream_->module_compiled_callback()) {
2440  job_->stream_->module_compiled_callback()(job_->module_object_);
2441  }
2442  // If a foreground task or a finisher is pending, we rely on
2443  // FinishModule to remove the job.
2444  if (!job_->pending_foreground_task_ &&
2445  job_->outstanding_finishers_.load() == 0) {
2446  job_->isolate_->wasm_engine()->RemoveCompileJob(job_);
2447  }
2448  break;
2449  case CompilationEvent::kFailedCompilation:
2450  DCHECK(!last_event_.has_value());
2451  DCHECK_NOT_NULL(error_result);
2452  // Tier-up compilation should not fail if baseline compilation
2453  // did not fail.
2454  DCHECK(!Impl(job_->native_module_->compilation_state())
2455  ->baseline_compilation_finished());
2456 
2457  {
2458  SaveContext saved_context(job_->isolate());
2459  job_->isolate()->set_context(*job_->native_context_);
2460  ErrorThrower thrower(job_->isolate(), "AsyncCompilation");
2461  thrower.CompileFailed(*error_result);
2462  Handle<Object> error = thrower.Reify();
2463 
2464  DeferredHandleScope deferred(job_->isolate());
2465  error = handle(*error, job_->isolate());
2466  job_->deferred_handles_.push_back(deferred.Detach());
2467 
2468  job_->DoSync<CompileFailed, kUseExistingForegroundTask>(error);
2469  }
2470 
2471  break;
2472  default:
2473  UNREACHABLE();
2474  }
2475 #ifdef DEBUG
2476  last_event_ = event;
2477 #endif
2478  }
2479 
2480  private:
2481  AsyncCompileJob* job_;
2482 #ifdef DEBUG
2484 #endif
2485 };
2486 
2487 // A closure to run a compilation step (either as foreground or background
2488 // task) and schedule the next step(s), if any.
2490  public:
2491  virtual ~CompileStep() = default;
2492 
2493  void Run(AsyncCompileJob* job, bool on_foreground) {
2494  if (on_foreground) {
2495  HandleScope scope(job->isolate_);
2496  SaveContext saved_context(job->isolate_);
2497  job->isolate_->set_context(*job->native_context_);
2498  RunInForeground(job);
2499  } else {
2500  RunInBackground(job);
2501  }
2502  }
2503 
2504  virtual void RunInForeground(AsyncCompileJob*) { UNREACHABLE(); }
2505  virtual void RunInBackground(AsyncCompileJob*) { UNREACHABLE(); }
2506 };
2507 
2509  public:
2510  CompileTask(AsyncCompileJob* job, bool on_foreground)
2511  // We only manage the background tasks with the {CancelableTaskManager} of
2512  // the {AsyncCompileJob}. Foreground tasks are managed by the system's
2513  // {CancelableTaskManager}. Background tasks cannot spawn tasks managed by
2514  // their own task manager.
2515  : CancelableTask(on_foreground ? job->isolate_->cancelable_task_manager()
2516  : &job->background_task_manager_),
2517  job_(job),
2518  on_foreground_(on_foreground) {}
2519 
2520  ~CompileTask() override {
2521  if (job_ != nullptr && on_foreground_) ResetPendingForegroundTask();
2522  }
2523 
2524  void RunInternal() final {
2525  if (!job_) return;
2526  if (on_foreground_) ResetPendingForegroundTask();
2527  job_->step_->Run(job_, on_foreground_);
2528  // After execution, reset {job_} such that we don't try to reset the pending
2529  // foreground task when the task is deleted.
2530  job_ = nullptr;
2531  }
2532 
2533  void Cancel() {
2534  DCHECK_NOT_NULL(job_);
2535  job_ = nullptr;
2536  }
2537 
2538  private:
2539  // {job_} will be cleared to cancel a pending task.
2540  AsyncCompileJob* job_;
2541  bool on_foreground_;
2542 
2543  void ResetPendingForegroundTask() const {
2544  DCHECK_EQ(this, job_->pending_foreground_task_);
2545  job_->pending_foreground_task_ = nullptr;
2546  }
2547 };
2548 
2549 void AsyncCompileJob::StartForegroundTask() {
2550  DCHECK_NULL(pending_foreground_task_);
2551 
2552  auto new_task = base::make_unique<CompileTask>(this, true);
2553  pending_foreground_task_ = new_task.get();
2554  foreground_task_runner_->PostTask(std::move(new_task));
2555 }
2556 
2557 void AsyncCompileJob::ExecuteForegroundTaskImmediately() {
2558  DCHECK_NULL(pending_foreground_task_);
2559 
2560  auto new_task = base::make_unique<CompileTask>(this, true);
2561  pending_foreground_task_ = new_task.get();
2562  new_task->Run();
2563 }
2564 
2565 void AsyncCompileJob::CancelPendingForegroundTask() {
2566  if (!pending_foreground_task_) return;
2567  pending_foreground_task_->Cancel();
2568  pending_foreground_task_ = nullptr;
2569 }
2570 
2571 void AsyncCompileJob::StartBackgroundTask() {
2572  auto task = base::make_unique<CompileTask>(this, false);
2573 
2574  // If --wasm-num-compilation-tasks=0 is passed, do only spawn foreground
2575  // tasks. This is used to make timing deterministic.
2576  if (FLAG_wasm_num_compilation_tasks > 0) {
2577  V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
2578  } else {
2579  foreground_task_runner_->PostTask(std::move(task));
2580  }
2581 }
2582 
2583 template <typename Step,
2584  AsyncCompileJob::UseExistingForegroundTask use_existing_fg_task,
2585  typename... Args>
2586 void AsyncCompileJob::DoSync(Args&&... args) {
2587  NextStep<Step>(std::forward<Args>(args)...);
2588  if (use_existing_fg_task && pending_foreground_task_ != nullptr) return;
2589  StartForegroundTask();
2590 }
2591 
2592 template <typename Step, typename... Args>
2593 void AsyncCompileJob::DoImmediately(Args&&... args) {
2594  NextStep<Step>(std::forward<Args>(args)...);
2595  ExecuteForegroundTaskImmediately();
2596 }
2597 
2598 template <typename Step, typename... Args>
2599 void AsyncCompileJob::DoAsync(Args&&... args) {
2600  NextStep<Step>(std::forward<Args>(args)...);
2601  StartBackgroundTask();
2602 }
2603 
2604 template <typename Step, typename... Args>
2605 void AsyncCompileJob::NextStep(Args&&... args) {
2606  step_.reset(new Step(std::forward<Args>(args)...));
2607 }
2608 
2609 //==========================================================================
2610 // Step 1: (async) Decode the module.
2611 //==========================================================================
2613  public:
2614  explicit DecodeModule(Counters* counters) : counters_(counters) {}
2615 
2616  void RunInBackground(AsyncCompileJob* job) override {
2617  ModuleResult result;
2618  {
2619  DisallowHandleAllocation no_handle;
2620  DisallowHeapAllocation no_allocation;
2621  // Decode the module bytes.
2622  TRACE_COMPILE("(1) Decoding module...\n");
2623  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
2624  "AsyncCompileJob::DecodeModule");
2625  result = DecodeWasmModule(
2626  job->enabled_features_, job->wire_bytes_.start(),
2627  job->wire_bytes_.end(), false, kWasmOrigin, counters_,
2628  job->isolate()->wasm_engine()->allocator());
2629  }
2630  if (result.failed()) {
2631  // Decoding failure; reject the promise and clean up.
2632  job->DoSync<DecodeFail>(std::move(result));
2633  } else {
2634  // Decode passed.
2635  job->DoSync<PrepareAndStartCompile>(std::move(result).value(), true);
2636  }
2637  }
2638 
2639  private:
2640  Counters* const counters_;
2641 };
2642 
2643 //==========================================================================
2644 // Step 1b: (sync) Fail decoding the module.
2645 //==========================================================================
2647  public:
2648  explicit DecodeFail(ModuleResult result) : result_(std::move(result)) {}
2649 
2650  private:
2651  ModuleResult result_;
2652  void RunInForeground(AsyncCompileJob* job) override {
2653  TRACE_COMPILE("(1b) Decoding failed.\n");
2654  ErrorThrower thrower(job->isolate_, "AsyncCompile");
2655  thrower.CompileFailed("Wasm decoding failed", result_);
2656  // {job_} is deleted in AsyncCompileFailed, therefore the {return}.
2657  return job->AsyncCompileFailed(thrower.Reify());
2658  }
2659 };
2660 
2661 //==========================================================================
2662 // Step 2 (sync): Create heap-allocated data and start compile.
2663 //==========================================================================
2665  public:
2666  PrepareAndStartCompile(std::shared_ptr<const WasmModule> module,
2667  bool start_compilation)
2668  : module_(std::move(module)), start_compilation_(start_compilation) {}
2669 
2670  private:
2671  std::shared_ptr<const WasmModule> module_;
2672  bool start_compilation_;
2673 
2674  void RunInForeground(AsyncCompileJob* job) override {
2675  TRACE_COMPILE("(2) Prepare and start compile...\n");
2676 
2677  // Make sure all compilation tasks stopped running. Decoding (async step)
2678  // is done.
2679  job->background_task_manager_.CancelAndWait();
2680 
2681  job->PrepareRuntimeObjects(module_);
2682 
2683  size_t num_functions =
2684  module_->functions.size() - module_->num_imported_functions;
2685 
2686  if (num_functions == 0) {
2687  // Degenerate case of an empty module.
2688  job->FinishCompile(true);
2689  return;
2690  }
2691 
2692  CompilationStateImpl* compilation_state =
2693  Impl(job->native_module_->compilation_state());
2694  compilation_state->SetCallback(CompilationStateCallback{job});
2695  if (start_compilation_) {
2696  // TODO(ahaas): Try to remove the {start_compilation_} check when
2697  // streaming decoding is done in the background. If
2698  // InitializeCompilationUnits always returns 0 for streaming compilation,
2699  // then DoAsync would do the same as NextStep already.
2700 
2701  compilation_state->SetNumberOfFunctionsToCompile(
2702  module_->num_declared_functions);
2703  // Add compilation units and kick off compilation.
2704  InitializeCompilationUnits(job->native_module_,
2705  job->isolate()->wasm_engine());
2706  }
2707  }
2708 };
2709 
2710 //==========================================================================
2711 // Step 4b (sync): Compilation failed. Reject Promise.
2712 //==========================================================================
2714  public:
2715  explicit CompileFailed(Handle<Object> error_reason)
2716  : error_reason_(error_reason) {}
2717 
2718  void RunInForeground(AsyncCompileJob* job) override {
2719  TRACE_COMPILE("(4b) Compilation Failed...\n");
2720  return job->AsyncCompileFailed(error_reason_);
2721  }
2722 
2723  private:
2724  Handle<Object> error_reason_;
2725 };
2726 
2727 //==========================================================================
2728 // Step 5 (sync): Compile JS->wasm wrappers.
2729 //==========================================================================
2731  // TODO(wasm): Compile all wrappers here, including the start function wrapper
2732  // and the wrappers for the function table elements.
2733  void RunInForeground(AsyncCompileJob* job) override {
2734  TRACE_COMPILE("(5) Compile wrappers...\n");
2735  // Compile JS->wasm wrappers for exported functions.
2736  CompileJsToWasmWrappers(
2737  job->isolate_, job->module_object_->native_module(),
2738  handle(job->module_object_->export_wrappers(), job->isolate_));
2739  job->DoSync<FinishModule>();
2740  }
2741 };
2742 
2743 //==========================================================================
2744 // Step 6 (sync): Finish the module and resolve the promise.
2745 //==========================================================================
2747  void RunInForeground(AsyncCompileJob* job) override {
2748  TRACE_COMPILE("(6) Finish module...\n");
2749  job->AsyncCompileSucceeded(job->module_object_);
2750 
2751  size_t num_functions = job->native_module_->num_functions() -
2752  job->native_module_->num_imported_functions();
2753  auto* compilation_state = Impl(job->native_module_->compilation_state());
2754  if (compilation_state->compile_mode() == CompileMode::kRegular ||
2755  num_functions == 0) {
2756  // If we do not tier up, the async compile job is done here and
2757  // can be deleted.
2758  job->isolate_->wasm_engine()->RemoveCompileJob(job);
2759  return;
2760  }
2761  DCHECK_EQ(CompileMode::kTiering, compilation_state->compile_mode());
2762  if (!compilation_state->has_outstanding_units()) {
2763  job->isolate_->wasm_engine()->RemoveCompileJob(job);
2764  }
2765  }
2766 };
2767 
2768 AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
2769  : decoder_(job->enabled_features_),
2770  job_(job),
2771  compilation_unit_builder_(nullptr) {}
2772 
2773 void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(ResultBase error) {
2774  DCHECK(error.failed());
2775  // Make sure all background tasks stopped executing before we change the state
2776  // of the AsyncCompileJob to DecodeFail.
2777  job_->background_task_manager_.CancelAndWait();
2778 
2779  // Create a ModuleResult from the result we got as parameter. Since there was
2780  // an error, we don't have to provide a real wasm module to the ModuleResult.
2781  ModuleResult result = ModuleResult::ErrorFrom(std::move(error));
2782 
2783  // Check if there is already a CompiledModule, in which case we have to clean
2784  // up the CompilationStateImpl as well.
2785  if (job_->native_module_) {
2786  Impl(job_->native_module_->compilation_state())->Abort();
2787 
2788  job_->DoSync<AsyncCompileJob::DecodeFail,
2789  AsyncCompileJob::kUseExistingForegroundTask>(
2790  std::move(result));
2791 
2792  // Clear the {compilation_unit_builder_} if it exists. This is needed
2793  // because there is a check in the destructor of the
2794  // {CompilationUnitBuilder} that it is empty.
2795  if (compilation_unit_builder_) compilation_unit_builder_->Clear();
2796  } else {
2797  job_->DoSync<AsyncCompileJob::DecodeFail>(std::move(result));
2798  }
2799 }
2800 
2801 // Process the module header.
2802 bool AsyncStreamingProcessor::ProcessModuleHeader(Vector<const uint8_t> bytes,
2803  uint32_t offset) {
2804  TRACE_STREAMING("Process module header...\n");
2805  decoder_.StartDecoding(job_->isolate()->counters(),
2806  job_->isolate()->wasm_engine()->allocator());
2807  decoder_.DecodeModuleHeader(bytes, offset);
2808  if (!decoder_.ok()) {
2809  FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false));
2810  return false;
2811  }
2812  return true;
2813 }
2814 
2815 // Process all sections except for the code section.
2816 bool AsyncStreamingProcessor::ProcessSection(SectionCode section_code,
2817  Vector<const uint8_t> bytes,
2818  uint32_t offset) {
2819  TRACE_STREAMING("Process section %d ...\n", section_code);
2820  if (compilation_unit_builder_) {
2821  // We reached a section after the code section, we do not need the
2822  // compilation_unit_builder_ anymore.
2823  CommitCompilationUnits();
2824  compilation_unit_builder_.reset();
2825  }
2826  if (section_code == SectionCode::kUnknownSectionCode) {
2827  Decoder decoder(bytes, offset);
2828  section_code = ModuleDecoder::IdentifyUnknownSection(
2829  decoder, bytes.start() + bytes.length());
2830  if (section_code == SectionCode::kUnknownSectionCode) {
2831  // Skip unknown sections that we do not know how to handle.
2832  return true;
2833  }
2834  // Remove the unknown section tag from the payload bytes.
2835  offset += decoder.position();
2836  bytes = bytes.SubVector(decoder.position(), bytes.size());
2837  }
2838  constexpr bool verify_functions = false;
2839  decoder_.DecodeSection(section_code, bytes, offset, verify_functions);
2840  if (!decoder_.ok()) {
2841  FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false));
2842  return false;
2843  }
2844  return true;
2845 }
2846 
2847 // Start the code section.
2848 bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
2849  size_t functions_count, uint32_t offset,
2850  std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
2851  TRACE_STREAMING("Start the code section with %zu functions...\n",
2852  functions_count);
2853  if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(functions_count),
2854  offset)) {
2855  FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false));
2856  return false;
2857  }
2858  // Execute the PrepareAndStartCompile step immediately and not in a separate
2859  // task.
2860  job_->DoImmediately<AsyncCompileJob::PrepareAndStartCompile>(
2861  decoder_.shared_module(), false);
2862  job_->native_module_->compilation_state()->SetWireBytesStorage(
2863  std::move(wire_bytes_storage));
2864 
2865  auto* compilation_state = Impl(job_->native_module_->compilation_state());
2866  compilation_state->SetNumberOfFunctionsToCompile(functions_count);
2867 
2868  // Set outstanding_finishers_ to 2, because both the AsyncCompileJob and the
2869  // AsyncStreamingProcessor have to finish.
2870  job_->outstanding_finishers_.store(2);
2871  compilation_unit_builder_.reset(new CompilationUnitBuilder(
2872  job_->native_module_, job_->isolate()->wasm_engine()));
2873  return true;
2874 }
2875 
2876 // Process a function body.
2877 bool AsyncStreamingProcessor::ProcessFunctionBody(Vector<const uint8_t> bytes,
2878  uint32_t offset) {
2879  TRACE_STREAMING("Process function body %d ...\n", next_function_);
2880 
2881  decoder_.DecodeFunctionBody(
2882  next_function_, static_cast<uint32_t>(bytes.length()), offset, false);
2883 
2884  uint32_t index = next_function_ + decoder_.module()->num_imported_functions;
2885  compilation_unit_builder_->AddUnit(index);
2886  ++next_function_;
2887  // This method always succeeds. The return value is necessary to comply with
2888  // the StreamingProcessor interface.
2889  return true;
2890 }
2891 
2892 void AsyncStreamingProcessor::CommitCompilationUnits() {
2893  DCHECK(compilation_unit_builder_);
2894  compilation_unit_builder_->Commit();
2895 }
2896 
2897 void AsyncStreamingProcessor::OnFinishedChunk() {
2898  TRACE_STREAMING("FinishChunk...\n");
2899  if (compilation_unit_builder_) CommitCompilationUnits();
2900 }
2901 
2902 // Finish the processing of the stream.
2903 void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) {
2904  TRACE_STREAMING("Finish stream...\n");
2905  ModuleResult result = decoder_.FinishDecoding(false);
2906  DCHECK(result.ok());
2907  bool needs_finish = job_->DecrementAndCheckFinisherCount();
2908  if (job_->native_module_ == nullptr) {
2909  // We are processing a WebAssembly module without code section. Create the
2910  // runtime objects now (would otherwise happen in {PrepareAndStartCompile}).
2911  job_->PrepareRuntimeObjects(std::move(result).value());
2912  DCHECK(needs_finish);
2913  }
2914  job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector());
2915  job_->native_module_->SetWireBytes(std::move(bytes));
2916  if (needs_finish) {
2917  HandleScope scope(job_->isolate_);
2918  SaveContext saved_context(job_->isolate_);
2919  job_->isolate_->set_context(*job_->native_context_);
2920  job_->FinishCompile(true);
2921  }
2922 }
2923 
2924 // Report an error detected in the StreamingDecoder.
2925 void AsyncStreamingProcessor::OnError(DecodeResult result) {
2926  TRACE_STREAMING("Stream error...\n");
2927  FinishAsyncCompileJobWithError(std::move(result));
2928 }
2929 
2930 void AsyncStreamingProcessor::OnAbort() {
2931  TRACE_STREAMING("Abort stream...\n");
2932  job_->Abort();
2933 }
2934 
2935 bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes,
2936  Vector<const uint8_t> wire_bytes) {
2937  // DeserializeNativeModule and FinishCompile assume that they are executed in
2938  // a HandleScope, and that a context is set on the isolate.
2939  HandleScope scope(job_->isolate_);
2940  SaveContext saved_context(job_->isolate_);
2941  job_->isolate_->set_context(*job_->native_context_);
2942 
2943  MaybeHandle<WasmModuleObject> result =
2944  DeserializeNativeModule(job_->isolate_, module_bytes, wire_bytes);
2945  if (result.is_null()) return false;
2946 
2947  job_->module_object_ = result.ToHandleChecked();
2948  {
2949  DeferredHandleScope deferred(job_->isolate_);
2950  job_->module_object_ = handle(*job_->module_object_, job_->isolate_);
2951  job_->deferred_handles_.push_back(deferred.Detach());
2952  }
2953  job_->native_module_ = job_->module_object_->native_module();
2954  auto owned_wire_bytes = OwnedVector<uint8_t>::Of(wire_bytes);
2955  job_->wire_bytes_ = ModuleWireBytes(owned_wire_bytes.as_vector());
2956  job_->native_module_->SetWireBytes(std::move(owned_wire_bytes));
2957  job_->FinishCompile(false);
2958  return true;
2959 }
2960 
2961 CompilationStateImpl::CompilationStateImpl(internal::Isolate* isolate,
2962  NativeModule* native_module)
2963  : isolate_(isolate),
2964  native_module_(native_module),
2965  compile_mode_(FLAG_wasm_tier_up &&
2966  native_module->module()->origin == kWasmOrigin
2967  ? CompileMode::kTiering
2968  : CompileMode::kRegular),
2969  should_log_code_(WasmCode::ShouldBeLogged(isolate)),
2970  max_background_tasks_(std::max(
2971  1, std::min(FLAG_wasm_num_compilation_tasks,
2972  V8::GetCurrentPlatform()->NumberOfWorkerThreads()))) {
2973  v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
2974  v8::Platform* platform = V8::GetCurrentPlatform();
2975  foreground_task_runner_ = platform->GetForegroundTaskRunner(v8_isolate);
2976 }
2977 
2978 CompilationStateImpl::~CompilationStateImpl() {
2979  DCHECK(background_task_manager_.canceled());
2980  DCHECK(foreground_task_manager_.canceled());
2981 }
2982 
2983 void CompilationStateImpl::CancelAndWait() {
2984  background_task_manager_.CancelAndWait();
2985  foreground_task_manager_.CancelAndWait();
2986 }
2987 
2988 void CompilationStateImpl::SetNumberOfFunctionsToCompile(size_t num_functions) {
2989  DCHECK(!failed());
2990  outstanding_baseline_units_ = num_functions;
2991 
2992  if (compile_mode_ == CompileMode::kTiering) {
2993  outstanding_tiering_units_ = num_functions;
2994  }
2995 }
2996 
2997 void CompilationStateImpl::SetCallback(callback_t callback) {
2998  DCHECK_NULL(callback_);
2999  callback_ = std::move(callback);
3000 }
3001 
3002 void CompilationStateImpl::AddCompilationUnits(
3003  std::vector<std::unique_ptr<WasmCompilationUnit>>& baseline_units,
3004  std::vector<std::unique_ptr<WasmCompilationUnit>>& tiering_units) {
3005  {
3006  base::MutexGuard guard(&mutex_);
3007 
3008  if (compile_mode_ == CompileMode::kTiering) {
3009  DCHECK_EQ(baseline_units.size(), tiering_units.size());
3010  DCHECK_EQ(tiering_units.back()->tier(), ExecutionTier::kOptimized);
3011  tiering_compilation_units_.insert(
3012  tiering_compilation_units_.end(),
3013  std::make_move_iterator(tiering_units.begin()),
3014  std::make_move_iterator(tiering_units.end()));
3015  } else {
3016  DCHECK(tiering_compilation_units_.empty());
3017  }
3018 
3019  baseline_compilation_units_.insert(
3020  baseline_compilation_units_.end(),
3021  std::make_move_iterator(baseline_units.begin()),
3022  std::make_move_iterator(baseline_units.end()));
3023  }
3024 
3025  RestartBackgroundTasks();
3026 }
3027 
3028 std::unique_ptr<WasmCompilationUnit>
3029 CompilationStateImpl::GetNextCompilationUnit() {
3030  base::MutexGuard guard(&mutex_);
3031 
3032  std::vector<std::unique_ptr<WasmCompilationUnit>>& units =
3033  baseline_compilation_units_.empty() ? tiering_compilation_units_
3034  : baseline_compilation_units_;
3035 
3036  if (!units.empty()) {
3037  std::unique_ptr<WasmCompilationUnit> unit = std::move(units.back());
3038  units.pop_back();
3039  return unit;
3040  }
3041 
3042  return std::unique_ptr<WasmCompilationUnit>();
3043 }
3044 
3045 std::unique_ptr<WasmCompilationUnit>
3046 CompilationStateImpl::GetNextExecutedUnit() {
3047  base::MutexGuard guard(&mutex_);
3048  std::vector<std::unique_ptr<WasmCompilationUnit>>& units = finish_units();
3049  if (units.empty()) return {};
3050  std::unique_ptr<WasmCompilationUnit> ret = std::move(units.back());
3051  units.pop_back();
3052  return ret;
3053 }
3054 
3055 bool CompilationStateImpl::HasCompilationUnitToFinish() {
3056  base::MutexGuard guard(&mutex_);
3057  return !finish_units().empty();
3058 }
3059 
3060 void CompilationStateImpl::OnFinishedUnit() {
3061  // If we are *not* compiling in tiering mode, then all units are counted as
3062  // baseline units.
3063  bool is_tiering_mode = compile_mode_ == CompileMode::kTiering;
3064  bool is_tiering_unit = is_tiering_mode && outstanding_baseline_units_ == 0;
3065 
3066  // Sanity check: If we are not in tiering mode, there cannot be outstanding
3067  // tiering units.
3068  DCHECK_IMPLIES(!is_tiering_mode, outstanding_tiering_units_ == 0);
3069 
3070  if (is_tiering_unit) {
3071  DCHECK_LT(0, outstanding_tiering_units_);
3072  --outstanding_tiering_units_;
3073  if (outstanding_tiering_units_ == 0) {
3074  // We currently finish all baseline units before finishing tiering units.
3075  DCHECK_EQ(0, outstanding_baseline_units_);
3076  NotifyOnEvent(CompilationEvent::kFinishedTopTierCompilation, nullptr);
3077  }
3078  } else {
3079  DCHECK_LT(0, outstanding_baseline_units_);
3080  --outstanding_baseline_units_;
3081  if (outstanding_baseline_units_ == 0) {
3082  NotifyOnEvent(CompilationEvent::kFinishedBaselineCompilation, nullptr);
3083  // If we are not tiering, then we also trigger the "top tier finished"
3084  // event when baseline compilation is finished.
3085  if (!is_tiering_mode) {
3086  NotifyOnEvent(CompilationEvent::kFinishedTopTierCompilation, nullptr);
3087  }
3088  }
3089  }
3090 }
3091 
3092 void CompilationStateImpl::ScheduleUnitForFinishing(
3093  std::unique_ptr<WasmCompilationUnit> unit, ExecutionTier tier) {
3094  base::MutexGuard guard(&mutex_);
3095  if (compile_mode_ == CompileMode::kTiering &&
3096  tier == ExecutionTier::kOptimized) {
3097  tiering_finish_units_.push_back(std::move(unit));
3098  } else {
3099  baseline_finish_units_.push_back(std::move(unit));
3100  }
3101 
3102  if (!finisher_is_running_ && !compile_error_) {
3103  ScheduleFinisherTask();
3104  // We set the flag here so that not more than one finisher is started.
3105  finisher_is_running_ = true;
3106  }
3107 }
3108 
3109 void CompilationStateImpl::ScheduleCodeLogging(WasmCode* code) {
3110  if (!should_log_code_) return;
3111  base::MutexGuard guard(&mutex_);
3112  if (log_codes_task_ == nullptr) {
3113  auto new_task = base::make_unique<LogCodesTask>(&foreground_task_manager_,
3114  this, isolate_);
3115  log_codes_task_ = new_task.get();
3116  foreground_task_runner_->PostTask(std::move(new_task));
3117  }
3118  log_codes_task_->AddCode(code);
3119 }
3120 
3121 void CompilationStateImpl::OnBackgroundTaskStopped(
3122  const WasmFeatures& detected) {
3123  base::MutexGuard guard(&mutex_);
3124  DCHECK_LE(1, num_background_tasks_);
3125  --num_background_tasks_;
3126  UnionFeaturesInto(&detected_features_, detected);
3127 }
3128 
3129 void CompilationStateImpl::PublishDetectedFeatures(
3130  Isolate* isolate, const WasmFeatures& detected) {
3131  // Notifying the isolate of the feature counts must take place under
3132  // the mutex, because even if we have finished baseline compilation,
3133  // tiering compilations may still occur in the background.
3134  base::MutexGuard guard(&mutex_);
3135  UnionFeaturesInto(&detected_features_, detected);
3136  UpdateFeatureUseCounts(isolate, detected_features_);
3137 }
3138 
3139 void CompilationStateImpl::RestartBackgroundTasks(size_t max) {
3140  size_t num_restart;
3141  {
3142  base::MutexGuard guard(&mutex_);
3143  // No need to restart tasks if compilation already failed.
3144  if (compile_error_) return;
3145 
3146  DCHECK_LE(num_background_tasks_, max_background_tasks_);
3147  if (num_background_tasks_ == max_background_tasks_) return;
3148  size_t num_compilation_units =
3149  baseline_compilation_units_.size() + tiering_compilation_units_.size();
3150  size_t stopped_tasks = max_background_tasks_ - num_background_tasks_;
3151  num_restart = std::min(max, std::min(num_compilation_units, stopped_tasks));
3152  num_background_tasks_ += num_restart;
3153  }
3154 
3155  for (; num_restart > 0; --num_restart) {
3156  auto task = base::make_unique<BackgroundCompileTask>(
3157  &background_task_manager_, native_module_, isolate_->counters());
3158 
3159  // If --wasm-num-compilation-tasks=0 is passed, do only spawn foreground
3160  // tasks. This is used to make timing deterministic.
3161  if (FLAG_wasm_num_compilation_tasks > 0) {
3162  V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
3163  } else {
3164  foreground_task_runner_->PostTask(std::move(task));
3165  }
3166  }
3167 }
3168 
3169 bool CompilationStateImpl::SetFinisherIsRunning(bool value) {
3170  base::MutexGuard guard(&mutex_);
3171  if (finisher_is_running_ == value) return false;
3172  finisher_is_running_ = value;
3173  return true;
3174 }
3175 
3176 void CompilationStateImpl::ScheduleFinisherTask() {
3177  foreground_task_runner_->PostTask(
3178  base::make_unique<FinishCompileTask>(this, &foreground_task_manager_));
3179 }
3180 
3181 void CompilationStateImpl::Abort() {
3182  {
3183  base::MutexGuard guard(&mutex_);
3184  if (!compile_error_) {
3185  compile_error_ = base::make_unique<CompilationError>(
3186  0, VoidResult::Error(0, "Compilation aborted"));
3187  }
3188  }
3189  background_task_manager_.CancelAndWait();
3190 }
3191 
3192 void CompilationStateImpl::SetError(uint32_t func_index,
3193  const ResultBase& error_result) {
3194  DCHECK(error_result.failed());
3195  base::MutexGuard guard(&mutex_);
3196  // Ignore all but the first error.
3197  if (compile_error_) return;
3198  compile_error_ =
3199  base::make_unique<CompilationError>(func_index, error_result);
3200  // Schedule a foreground task to call the callback and notify users about the
3201  // compile error.
3202  foreground_task_runner_->PostTask(
3203  MakeCancelableTask(&foreground_task_manager_, [this] {
3204  VoidResult error_result = GetCompileError();
3205  NotifyOnEvent(CompilationEvent::kFailedCompilation, &error_result);
3206  }));
3207 }
3208 
3209 void CompilationStateImpl::NotifyOnEvent(CompilationEvent event,
3210  const VoidResult* error_result) {
3211  HandleScope scope(isolate_);
3212  if (callback_) callback_(event, error_result);
3213 }
3214 
3215 void CompileJsToWasmWrappers(Isolate* isolate, NativeModule* native_module,
3216  Handle<FixedArray> export_wrappers) {
3217  JSToWasmWrapperCache js_to_wasm_cache;
3218  int wrapper_index = 0;
3219  const WasmModule* module = native_module->module();
3220 
3221  // TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an
3222  // optimization we keep the code space unlocked to avoid repeated unlocking
3223  // because many such wrapper are allocated in sequence below.
3224  CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
3225  for (auto exp : module->export_table) {
3226  if (exp.kind != kExternalFunction) continue;
3227  auto& function = module->functions[exp.index];
3228  Handle<Code> wrapper_code = js_to_wasm_cache.GetOrCompileJSToWasmWrapper(
3229  isolate, function.sig, function.imported);
3230  export_wrappers->set(wrapper_index, *wrapper_code);
3231  RecordStats(*wrapper_code, isolate->counters());
3232  ++wrapper_index;
3233  }
3234 }
3235 
3236 Handle<Script> CreateWasmScript(Isolate* isolate,
3237  const ModuleWireBytes& wire_bytes,
3238  const std::string& source_map_url) {
3239  Handle<Script> script =
3240  isolate->factory()->NewScript(isolate->factory()->empty_string());
3241  script->set_context_data(isolate->native_context()->debug_context_id());
3242  script->set_type(Script::TYPE_WASM);
3243 
3244  int hash = StringHasher::HashSequentialString(
3245  reinterpret_cast<const char*>(wire_bytes.start()),
3246  static_cast<int>(wire_bytes.length()), kZeroHashSeed);
3247 
3248  const int kBufferSize = 32;
3249  char buffer[kBufferSize];
3250 
3251  int name_chars = SNPrintF(ArrayVector(buffer), "wasm-%08x", hash);
3252  DCHECK(name_chars >= 0 && name_chars < kBufferSize);
3253  MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
3254  Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), name_chars),
3255  TENURED);
3256  script->set_name(*name_str.ToHandleChecked());
3257 
3258  if (source_map_url.size() != 0) {
3259  MaybeHandle<String> src_map_str = isolate->factory()->NewStringFromUtf8(
3260  CStrVector(source_map_url.c_str()), TENURED);
3261  script->set_source_mapping_url(*src_map_str.ToHandleChecked());
3262  }
3263  return script;
3264 }
3265 
3266 } // namespace wasm
3267 } // namespace internal
3268 } // namespace v8
3269 
3270 #undef TRACE
3271 #undef TRACE_COMPILE
3272 #undef TRACE_STREAMING
3273 #undef TRACE_LAZY
STL namespace.
Definition: v8.h:56
Definition: libplatform.h:13
V8_INLINE T FromMaybe(const T &default_value) const
Definition: v8.h:8692
virtual std::shared_ptr< v8::TaskRunner > GetForegroundTaskRunner(Isolate *isolate)=0