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