Line data Source code
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 <atomic>
8 :
9 : #include "src/api.h"
10 : #include "src/asmjs/asm-js.h"
11 : #include "src/assembler-inl.h"
12 : #include "src/base/template-utils.h"
13 : #include "src/base/utils/random-number-generator.h"
14 : #include "src/code-stubs.h"
15 : #include "src/compiler/wasm-compiler.h"
16 : #include "src/counters.h"
17 : #include "src/property-descriptor.h"
18 : #include "src/wasm/compilation-manager.h"
19 : #include "src/wasm/module-decoder.h"
20 : #include "src/wasm/wasm-code-specialization.h"
21 : #include "src/wasm/wasm-js.h"
22 : #include "src/wasm/wasm-memory.h"
23 : #include "src/wasm/wasm-objects-inl.h"
24 : #include "src/wasm/wasm-result.h"
25 :
26 : #define TRACE(...) \
27 : do { \
28 : if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \
29 : } while (false)
30 :
31 : #define TRACE_CHAIN(instance) \
32 : do { \
33 : instance->PrintInstancesChain(); \
34 : } while (false)
35 :
36 : #define TRACE_COMPILE(...) \
37 : do { \
38 : if (FLAG_trace_wasm_compiler) PrintF(__VA_ARGS__); \
39 : } while (false)
40 :
41 : #define TRACE_STREAMING(...) \
42 : do { \
43 : if (FLAG_trace_wasm_streaming) PrintF(__VA_ARGS__); \
44 : } while (false)
45 : static const int kInvalidSigIndex = -1;
46 :
47 : namespace v8 {
48 : namespace internal {
49 : namespace wasm {
50 :
51 : // A class compiling an entire module.
52 461427 : class ModuleCompiler {
53 : public:
54 : ModuleCompiler(Isolate* isolate, WasmModule* module,
55 : Handle<Code> centry_stub);
56 :
57 : // The actual runnable task that performs compilations in the background.
58 47041 : class CompilationTask : public CancelableTask {
59 : public:
60 : ModuleCompiler* compiler_;
61 : explicit CompilationTask(ModuleCompiler* compiler)
62 : : CancelableTask(&compiler->background_task_manager_),
63 23548 : compiler_(compiler) {}
64 :
65 22196 : void RunInternal() override {
66 196954 : while (compiler_->executed_units_.CanAcceptWork() &&
67 174758 : compiler_->FetchAndExecuteCompilationUnit()) {
68 : }
69 :
70 22205 : compiler_->OnBackgroundTaskStopped();
71 22198 : }
72 : };
73 :
74 : // The CompilationUnitBuilder builds compilation units and stores them in an
75 : // internal buffer. The buffer is moved into the working queue of the
76 : // ModuleCompiler when {Commit} is called.
77 : class CompilationUnitBuilder {
78 : public:
79 : explicit CompilationUnitBuilder(ModuleCompiler* compiler)
80 3619 : : compiler_(compiler) {}
81 :
82 3619 : ~CompilationUnitBuilder() { DCHECK(units_.empty()); }
83 :
84 38744 : void AddUnit(compiler::ModuleEnv* module_env, const WasmFunction* function,
85 : uint32_t buffer_offset, Vector<const uint8_t> bytes,
86 : WasmName name) {
87 : units_.emplace_back(new compiler::WasmCompilationUnit(
88 : compiler_->isolate_, module_env,
89 : wasm::FunctionBody{function->sig, buffer_offset, bytes.begin(),
90 : bytes.end()},
91 : name, function->func_index, compiler_->centry_stub_,
92 116232 : compiler_->counters()));
93 38744 : }
94 :
95 3677 : void Commit() {
96 : {
97 : base::LockGuard<base::Mutex> guard(
98 3677 : &compiler_->compilation_units_mutex_);
99 : compiler_->compilation_units_.insert(
100 : compiler_->compilation_units_.end(),
101 : std::make_move_iterator(units_.begin()),
102 7354 : std::make_move_iterator(units_.end()));
103 : }
104 : units_.clear();
105 3677 : }
106 :
107 : void Clear() { units_.clear(); }
108 :
109 : private:
110 : ModuleCompiler* compiler_;
111 : std::vector<std::unique_ptr<compiler::WasmCompilationUnit>> units_;
112 : };
113 :
114 153809 : class CodeGenerationSchedule {
115 : public:
116 : explicit CodeGenerationSchedule(
117 : base::RandomNumberGenerator* random_number_generator,
118 : size_t max_memory = 0);
119 :
120 : void Schedule(std::unique_ptr<compiler::WasmCompilationUnit>&& item);
121 :
122 : bool IsEmpty() const { return schedule_.empty(); }
123 :
124 : std::unique_ptr<compiler::WasmCompilationUnit> GetNext();
125 :
126 : bool CanAcceptWork() const;
127 :
128 : bool ShouldIncreaseWorkload() const;
129 :
130 3619 : void EnableThrottling() { throttle_ = true; }
131 :
132 : private:
133 : size_t GetRandomIndexInSchedule();
134 :
135 : base::RandomNumberGenerator* random_number_generator_ = nullptr;
136 : std::vector<std::unique_ptr<compiler::WasmCompilationUnit>> schedule_;
137 : const size_t max_memory_;
138 : bool throttle_ = false;
139 : base::AtomicNumber<size_t> allocated_memory_{0};
140 : };
141 :
142 546061 : Counters* counters() const { return async_counters_.get(); }
143 :
144 : // Run by each compilation task and by the main thread (i.e. in both
145 : // foreground and background threads). The no_finisher_callback is called
146 : // within the result_mutex_ lock when no finishing task is running, i.e. when
147 : // the finisher_is_running_ flag is not set.
148 : bool FetchAndExecuteCompilationUnit(
149 : std::function<void()> no_finisher_callback = nullptr);
150 :
151 : void OnBackgroundTaskStopped();
152 :
153 : void EnableThrottling() { executed_units_.EnableThrottling(); }
154 :
155 : bool CanAcceptWork() const { return executed_units_.CanAcceptWork(); }
156 :
157 : bool ShouldIncreaseWorkload() const {
158 36 : return executed_units_.ShouldIncreaseWorkload();
159 : }
160 :
161 : size_t InitializeCompilationUnits(const std::vector<WasmFunction>& functions,
162 : const ModuleWireBytes& wire_bytes,
163 : compiler::ModuleEnv* module_env);
164 :
165 : void RestartCompilationTasks();
166 :
167 : size_t FinishCompilationUnits(std::vector<Handle<Code>>& results,
168 : ErrorThrower* thrower);
169 :
170 : bool IsFinisherRunning() const { return finisher_is_running_; }
171 :
172 : void SetFinisherIsRunning(bool value);
173 :
174 : MaybeHandle<Code> FinishCompilationUnit(ErrorThrower* thrower,
175 : int* func_index);
176 :
177 : void CompileInParallel(const ModuleWireBytes& wire_bytes,
178 : compiler::ModuleEnv* module_env,
179 : std::vector<Handle<Code>>& results,
180 : ErrorThrower* thrower);
181 :
182 : void CompileSequentially(const ModuleWireBytes& wire_bytes,
183 : compiler::ModuleEnv* module_env,
184 : std::vector<Handle<Code>>& results,
185 : ErrorThrower* thrower);
186 :
187 : void ValidateSequentially(const ModuleWireBytes& wire_bytes,
188 : compiler::ModuleEnv* module_env,
189 : ErrorThrower* thrower);
190 :
191 : static MaybeHandle<WasmModuleObject> CompileToModuleObject(
192 : Isolate* isolate, ErrorThrower* thrower,
193 : std::unique_ptr<WasmModule> module, const ModuleWireBytes& wire_bytes,
194 : Handle<Script> asm_js_script,
195 : Vector<const byte> asm_js_offset_table_bytes);
196 :
197 : private:
198 : MaybeHandle<WasmModuleObject> CompileToModuleObjectInternal(
199 : ErrorThrower* thrower, std::unique_ptr<WasmModule> module,
200 : const ModuleWireBytes& wire_bytes, Handle<Script> asm_js_script,
201 : Vector<const byte> asm_js_offset_table_bytes);
202 :
203 : Isolate* isolate_;
204 : WasmModule* module_;
205 : const std::shared_ptr<Counters> async_counters_;
206 : std::vector<std::unique_ptr<compiler::WasmCompilationUnit>>
207 : compilation_units_;
208 : base::Mutex compilation_units_mutex_;
209 : CodeGenerationSchedule executed_units_;
210 : base::Mutex result_mutex_;
211 : const size_t num_background_tasks_;
212 : // This flag should only be set while holding result_mutex_.
213 : bool finisher_is_running_ = false;
214 : CancelableTaskManager background_task_manager_;
215 : size_t stopped_compilation_tasks_ = 0;
216 : base::Mutex tasks_mutex_;
217 : Handle<Code> centry_stub_;
218 : };
219 :
220 906318 : class JSToWasmWrapperCache {
221 : public:
222 : void SetContextAddress(Address context_address) {
223 : // Prevent to have different context addresses in the cache.
224 : DCHECK(code_cache_.empty());
225 152712 : context_address_ = context_address;
226 : }
227 :
228 187576 : Handle<Code> CloneOrCompileJSToWasmWrapper(Isolate* isolate,
229 : wasm::WasmModule* module,
230 : Handle<Code> wasm_code,
231 : uint32_t index) {
232 187576 : const wasm::WasmFunction* func = &module->functions[index];
233 187576 : int cached_idx = sig_map_.Find(func->sig);
234 187576 : if (cached_idx >= 0) {
235 62984 : Handle<Code> code = isolate->factory()->CopyCode(code_cache_[cached_idx]);
236 : // Now patch the call to wasm code.
237 58514 : for (RelocIterator it(*code, RelocInfo::kCodeTargetMask);; it.next()) {
238 : DCHECK(!it.done());
239 : Code* target =
240 58514 : Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
241 87571 : if (target->kind() == Code::WASM_FUNCTION ||
242 29057 : target->kind() == Code::WASM_TO_JS_FUNCTION ||
243 87381 : target->builtin_index() == Builtins::kIllegal ||
244 : target->builtin_index() == Builtins::kWasmCompileLazy) {
245 : it.rinfo()->set_target_address(isolate,
246 31492 : wasm_code->instruction_start());
247 : break;
248 : }
249 27022 : }
250 31492 : return code;
251 : }
252 :
253 : Handle<Code> code = compiler::CompileJSToWasmWrapper(
254 156084 : isolate, module, wasm_code, index, context_address_);
255 156084 : uint32_t new_cache_idx = sig_map_.FindOrInsert(func->sig);
256 : DCHECK_EQ(code_cache_.size(), new_cache_idx);
257 : USE(new_cache_idx);
258 156084 : code_cache_.push_back(code);
259 156084 : return code;
260 : }
261 :
262 : private:
263 : // sig_map_ maps signatures to an index in code_cache_.
264 : wasm::SignatureMap sig_map_;
265 : std::vector<Handle<Code>> code_cache_;
266 : Address context_address_ = nullptr;
267 : };
268 :
269 : // A helper class to simplify instantiating a module from a compiled module.
270 : // It closes over the {Isolate}, the {ErrorThrower}, the {WasmCompiledModule},
271 : // etc.
272 462444 : class InstanceBuilder {
273 : public:
274 : InstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
275 : Handle<WasmModuleObject> module_object,
276 : MaybeHandle<JSReceiver> ffi,
277 : MaybeHandle<JSArrayBuffer> memory,
278 : WeakCallbackInfo<void>::Callback instance_finalizer_callback);
279 :
280 : // Build an instance, in all of its glory.
281 : MaybeHandle<WasmInstanceObject> Build();
282 :
283 : private:
284 : // Represents the initialized state of a table.
285 : struct TableInstance {
286 : Handle<WasmTableObject> table_object; // WebAssembly.Table instance
287 : Handle<FixedArray> js_wrappers; // JSFunctions exported
288 : Handle<FixedArray> function_table; // internal code array
289 : Handle<FixedArray> signature_table; // internal sig array
290 : };
291 :
292 : // A pre-evaluated value to use in import binding.
293 : struct SanitizedImport {
294 : Handle<String> module_name;
295 : Handle<String> import_name;
296 : Handle<Object> value;
297 : };
298 :
299 : Isolate* isolate_;
300 : WasmModule* const module_;
301 : const std::shared_ptr<Counters> async_counters_;
302 : ErrorThrower* thrower_;
303 : Handle<WasmModuleObject> module_object_;
304 : MaybeHandle<JSReceiver> ffi_;
305 : MaybeHandle<JSArrayBuffer> memory_;
306 : Handle<JSArrayBuffer> globals_;
307 : Handle<WasmCompiledModule> compiled_module_;
308 : std::vector<TableInstance> table_instances_;
309 : std::vector<Handle<JSFunction>> js_wrappers_;
310 : JSToWasmWrapperCache js_to_wasm_cache_;
311 : WeakCallbackInfo<void>::Callback instance_finalizer_callback_;
312 : std::vector<SanitizedImport> sanitized_imports_;
313 :
314 : const std::shared_ptr<Counters>& async_counters() const {
315 : return async_counters_;
316 : }
317 468921 : Counters* counters() const { return async_counters().get(); }
318 :
319 : // Helper routines to print out errors with imports.
320 : #define ERROR_THROWER_WITH_MESSAGE(TYPE) \
321 : void Report##TYPE(const char* error, uint32_t index, \
322 : Handle<String> module_name, Handle<String> import_name) { \
323 : thrower_->TYPE("Import #%d module=\"%s\" function=\"%s\" error: %s", \
324 : index, module_name->ToCString().get(), \
325 : import_name->ToCString().get(), error); \
326 : } \
327 : \
328 : MaybeHandle<Object> Report##TYPE(const char* error, uint32_t index, \
329 : Handle<String> module_name) { \
330 : thrower_->TYPE("Import #%d module=\"%s\" error: %s", index, \
331 : module_name->ToCString().get(), error); \
332 : return MaybeHandle<Object>(); \
333 : }
334 :
335 4538 : ERROR_THROWER_WITH_MESSAGE(LinkError)
336 640 : ERROR_THROWER_WITH_MESSAGE(TypeError)
337 :
338 : // Look up an import value in the {ffi_} object.
339 : MaybeHandle<Object> LookupImport(uint32_t index, Handle<String> module_name,
340 : Handle<String> import_name);
341 :
342 : // Look up an import value in the {ffi_} object specifically for linking an
343 : // asm.js module. This only performs non-observable lookups, which allows
344 : // falling back to JavaScript proper (and hence re-executing all lookups) if
345 : // module instantiation fails.
346 : MaybeHandle<Object> LookupImportAsm(uint32_t index,
347 : Handle<String> import_name);
348 :
349 : uint32_t EvalUint32InitExpr(const WasmInitExpr& expr);
350 :
351 : // Load data segments into the memory.
352 : void LoadDataSegments(Address mem_addr, size_t mem_size);
353 :
354 : void WriteGlobalValue(WasmGlobal& global, Handle<Object> value);
355 :
356 : void SanitizeImports();
357 :
358 : Handle<FixedArray> SetupWasmToJSImportsTable(
359 : Handle<WasmInstanceObject> instance);
360 :
361 : // Process the imports, including functions, tables, globals, and memory, in
362 : // order, loading them from the {ffi_} object. Returns the number of imported
363 : // functions.
364 : int ProcessImports(Handle<FixedArray> code_table,
365 : Handle<WasmInstanceObject> instance);
366 :
367 : template <typename T>
368 : T* GetRawGlobalPtr(WasmGlobal& global);
369 :
370 : // Process initialization of globals.
371 : void InitGlobals();
372 :
373 : // Allocate memory for a module instance as a new JSArrayBuffer.
374 : Handle<JSArrayBuffer> AllocateMemory(uint32_t num_pages);
375 :
376 : bool NeedsWrappers() const;
377 :
378 : // Process the exports, creating wrappers for functions, tables, memories,
379 : // and globals.
380 : void ProcessExports(Handle<WasmInstanceObject> instance,
381 : Handle<WasmCompiledModule> compiled_module);
382 :
383 : void InitializeTables(Handle<WasmInstanceObject> instance,
384 : CodeSpecialization* code_specialization);
385 :
386 : void LoadTableSegments(Handle<FixedArray> code_table,
387 : Handle<WasmInstanceObject> instance);
388 : };
389 :
390 : // TODO(titzer): move to wasm-objects.cc
391 111452 : static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
392 : DisallowHeapAllocation no_gc;
393 : JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter());
394 55726 : WasmInstanceObject* owner = reinterpret_cast<WasmInstanceObject*>(*p);
395 : Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate());
396 : // If a link to shared memory instances exists, update the list of memory
397 : // instances before the instance is destroyed.
398 : WasmCompiledModule* compiled_module = owner->compiled_module();
399 : TRACE("Finalizing %d {\n", compiled_module->instance_id());
400 : DCHECK(compiled_module->has_weak_wasm_module());
401 : WeakCell* weak_wasm_module = compiled_module->ptr_to_weak_wasm_module();
402 :
403 55726 : if (trap_handler::UseTrapHandler()) {
404 15313 : Handle<FixedArray> code_table = compiled_module->code_table();
405 100408 : for (int i = 0; i < code_table->length(); ++i) {
406 34891 : Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
407 : int index = code->trap_handler_index()->value();
408 34891 : if (index >= 0) {
409 456 : trap_handler::ReleaseHandlerData(index);
410 456 : code->set_trap_handler_index(Smi::FromInt(trap_handler::kInvalidIndex));
411 : }
412 : }
413 : }
414 :
415 : // Since the order of finalizers is not guaranteed, it can be the case
416 : // that {instance->compiled_module()->module()}, which is a
417 : // {Managed<WasmModule>} has been collected earlier in this GC cycle.
418 : // Weak references to this instance won't be cleared until
419 : // the next GC cycle, so we need to manually break some links (such as
420 : // the weak references from {WasmMemoryObject::instances}.
421 55726 : if (owner->has_memory_object()) {
422 : Handle<WasmMemoryObject> memory(owner->memory_object(), isolate);
423 : Handle<WasmInstanceObject> instance(owner, isolate);
424 3143 : WasmMemoryObject::RemoveInstance(isolate, memory, instance);
425 : }
426 :
427 : // weak_wasm_module may have been cleared, meaning the module object
428 : // was GC-ed. In that case, there won't be any new instances created,
429 : // and we don't need to maintain the links between instances.
430 55726 : if (!weak_wasm_module->cleared()) {
431 : WasmModuleObject* wasm_module =
432 : WasmModuleObject::cast(weak_wasm_module->value());
433 : WasmCompiledModule* current_template = wasm_module->compiled_module();
434 :
435 : TRACE("chain before {\n");
436 1108 : TRACE_CHAIN(current_template);
437 : TRACE("}\n");
438 :
439 : DCHECK(!current_template->has_weak_prev_instance());
440 1108 : WeakCell* next = compiled_module->maybe_ptr_to_weak_next_instance();
441 1108 : WeakCell* prev = compiled_module->maybe_ptr_to_weak_prev_instance();
442 :
443 1108 : if (current_template == compiled_module) {
444 589 : if (next == nullptr) {
445 460 : WasmCompiledModule::Reset(isolate, compiled_module);
446 : } else {
447 : WasmCompiledModule* next_compiled_module =
448 : WasmCompiledModule::cast(next->value());
449 : WasmModuleObject::cast(wasm_module)
450 129 : ->set_compiled_module(next_compiled_module);
451 : DCHECK_NULL(prev);
452 : next_compiled_module->reset_weak_prev_instance();
453 : }
454 : } else {
455 : DCHECK(!(prev == nullptr && next == nullptr));
456 : // the only reason prev or next would be cleared is if the
457 : // respective objects got collected, but if that happened,
458 : // we would have relinked the list.
459 519 : if (prev != nullptr) {
460 : DCHECK(!prev->cleared());
461 519 : if (next == nullptr) {
462 : WasmCompiledModule::cast(prev->value())->reset_weak_next_instance();
463 : } else {
464 : WasmCompiledModule::cast(prev->value())
465 : ->set_ptr_to_weak_next_instance(next);
466 : }
467 : }
468 519 : if (next != nullptr) {
469 : DCHECK(!next->cleared());
470 189 : if (prev == nullptr) {
471 : WasmCompiledModule::cast(next->value())->reset_weak_prev_instance();
472 : } else {
473 : WasmCompiledModule::cast(next->value())
474 : ->set_ptr_to_weak_prev_instance(prev);
475 : }
476 : }
477 : }
478 : TRACE("chain after {\n");
479 1108 : TRACE_CHAIN(wasm_module->compiled_module());
480 : TRACE("}\n");
481 : }
482 : compiled_module->reset_weak_owning_instance();
483 55726 : GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
484 : TRACE("}\n");
485 55726 : }
486 :
487 147392 : bool SyncValidate(Isolate* isolate, const ModuleWireBytes& bytes) {
488 294784 : if (bytes.start() == nullptr || bytes.length() == 0) return false;
489 : ModuleResult result = SyncDecodeWasmModule(isolate, bytes.start(),
490 294784 : bytes.end(), true, kWasmOrigin);
491 147392 : return result.ok();
492 : }
493 :
494 3547 : MaybeHandle<WasmModuleObject> SyncCompileTranslatedAsmJs(
495 : Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes,
496 : Handle<Script> asm_js_script,
497 : Vector<const byte> asm_js_offset_table_bytes) {
498 : ModuleResult result = SyncDecodeWasmModule(isolate, bytes.start(),
499 7094 : bytes.end(), false, kAsmJsOrigin);
500 3547 : if (result.failed()) {
501 : thrower->CompileFailed("Wasm decoding failed", result);
502 0 : return {};
503 : }
504 :
505 : // Transfer ownership of the WasmModule to the {WasmModuleWrapper} generated
506 : // in {CompileToModuleObject}.
507 : return ModuleCompiler::CompileToModuleObject(
508 : isolate, thrower, std::move(result.val), bytes, asm_js_script,
509 7094 : asm_js_offset_table_bytes);
510 : }
511 :
512 156720 : MaybeHandle<WasmModuleObject> SyncCompile(Isolate* isolate,
513 : ErrorThrower* thrower,
514 : const ModuleWireBytes& bytes) {
515 : // TODO(titzer): only make a copy of the bytes if SharedArrayBuffer
516 156720 : std::unique_ptr<byte[]> copy(new byte[bytes.length()]);
517 : memcpy(copy.get(), bytes.start(), bytes.length());
518 156720 : ModuleWireBytes bytes_copy(copy.get(), copy.get() + bytes.length());
519 :
520 : ModuleResult result = SyncDecodeWasmModule(
521 470160 : isolate, bytes_copy.start(), bytes_copy.end(), false, kWasmOrigin);
522 156720 : if (result.failed()) {
523 : thrower->CompileFailed("Wasm decoding failed", result);
524 6713 : return {};
525 : }
526 :
527 : // Transfer ownership of the WasmModule to the {WasmModuleWrapper} generated
528 : // in {CompileToModuleObject}.
529 : return ModuleCompiler::CompileToModuleObject(
530 : isolate, thrower, std::move(result.val), bytes_copy, Handle<Script>(),
531 300014 : Vector<const byte>());
532 : }
533 :
534 154148 : MaybeHandle<WasmInstanceObject> SyncInstantiate(
535 : Isolate* isolate, ErrorThrower* thrower,
536 : Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
537 : MaybeHandle<JSArrayBuffer> memory) {
538 : InstanceBuilder builder(isolate, thrower, module_object, imports, memory,
539 154148 : &InstanceFinalizer);
540 154148 : return builder.Build();
541 : }
542 :
543 300 : MaybeHandle<WasmInstanceObject> SyncCompileAndInstantiate(
544 : Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes,
545 : MaybeHandle<JSReceiver> imports, MaybeHandle<JSArrayBuffer> memory) {
546 300 : MaybeHandle<WasmModuleObject> module = SyncCompile(isolate, thrower, bytes);
547 : DCHECK_EQ(thrower->error(), module.is_null());
548 300 : if (module.is_null()) return {};
549 :
550 : return SyncInstantiate(isolate, thrower, module.ToHandleChecked(),
551 : Handle<JSReceiver>::null(),
552 300 : Handle<JSArrayBuffer>::null());
553 : }
554 :
555 261 : void RejectPromise(Isolate* isolate, Handle<Context> context,
556 : ErrorThrower& thrower, Handle<JSPromise> promise) {
557 : Local<Promise::Resolver> resolver =
558 : Utils::PromiseToLocal(promise).As<Promise::Resolver>();
559 : auto maybe = resolver->Reject(Utils::ToLocal(context),
560 261 : Utils::ToLocal(thrower.Reify()));
561 261 : CHECK_IMPLIES(!maybe.FromMaybe(false), isolate->has_scheduled_exception());
562 261 : }
563 :
564 615 : void ResolvePromise(Isolate* isolate, Handle<Context> context,
565 : Handle<JSPromise> promise, Handle<Object> result) {
566 : Local<Promise::Resolver> resolver =
567 : Utils::PromiseToLocal(promise).As<Promise::Resolver>();
568 : auto maybe =
569 615 : resolver->Resolve(Utils::ToLocal(context), Utils::ToLocal(result));
570 615 : CHECK_IMPLIES(!maybe.FromMaybe(false), isolate->has_scheduled_exception());
571 615 : }
572 :
573 0 : void AsyncInstantiate(Isolate* isolate, Handle<JSPromise> promise,
574 : Handle<WasmModuleObject> module_object,
575 : MaybeHandle<JSReceiver> imports) {
576 : ErrorThrower thrower(isolate, nullptr);
577 : MaybeHandle<WasmInstanceObject> instance_object = SyncInstantiate(
578 0 : isolate, &thrower, module_object, imports, Handle<JSArrayBuffer>::null());
579 0 : if (thrower.error()) {
580 0 : RejectPromise(isolate, handle(isolate->context()), thrower, promise);
581 0 : return;
582 : }
583 : ResolvePromise(isolate, handle(isolate->context()), promise,
584 0 : instance_object.ToHandleChecked());
585 : }
586 :
587 1586 : void AsyncCompile(Isolate* isolate, Handle<JSPromise> promise,
588 : const ModuleWireBytes& bytes) {
589 793 : if (!FLAG_wasm_async_compilation) {
590 : ErrorThrower thrower(isolate, "WasmCompile");
591 : // Compile the module.
592 : MaybeHandle<WasmModuleObject> module_object =
593 530 : SyncCompile(isolate, &thrower, bytes);
594 530 : if (thrower.error()) {
595 30 : RejectPromise(isolate, handle(isolate->context()), thrower, promise);
596 30 : return;
597 : }
598 : Handle<WasmModuleObject> module = module_object.ToHandleChecked();
599 500 : ResolvePromise(isolate, handle(isolate->context()), promise, module);
600 500 : return;
601 : }
602 :
603 263 : if (FLAG_wasm_test_streaming) {
604 : std::shared_ptr<StreamingDecoder> streaming_decoder =
605 : isolate->wasm_compilation_manager()->StartStreamingCompilation(
606 200 : isolate, handle(isolate->context()), promise);
607 200 : streaming_decoder->OnBytesReceived(bytes.module_bytes());
608 200 : streaming_decoder->Finish();
609 : return;
610 : }
611 : // Make a copy of the wire bytes in case the user program changes them
612 : // during asynchronous compilation.
613 63 : std::unique_ptr<byte[]> copy(new byte[bytes.length()]);
614 : memcpy(copy.get(), bytes.start(), bytes.length());
615 : isolate->wasm_compilation_manager()->StartAsyncCompileJob(
616 : isolate, std::move(copy), bytes.length(), handle(isolate->context()),
617 126 : promise);
618 : }
619 :
620 11477 : Handle<Code> CompileLazy(Isolate* isolate) {
621 : HistogramTimerScope lazy_time_scope(
622 11477 : isolate->counters()->wasm_lazy_compilation_time());
623 :
624 : // Find the wasm frame which triggered the lazy compile, to get the wasm
625 : // instance.
626 11477 : StackFrameIterator it(isolate);
627 : // First frame: C entry stub.
628 : DCHECK(!it.done());
629 : DCHECK_EQ(StackFrame::EXIT, it.frame()->type());
630 11477 : it.Advance();
631 : // Second frame: WasmCompileLazy builtin.
632 : DCHECK(!it.done());
633 11477 : Handle<Code> lazy_compile_code(it.frame()->LookupCode(), isolate);
634 : DCHECK_EQ(Builtins::kWasmCompileLazy, lazy_compile_code->builtin_index());
635 : Handle<WasmInstanceObject> instance;
636 : Handle<FixedArray> exp_deopt_data;
637 : int func_index = -1;
638 11477 : if (lazy_compile_code->deoptimization_data()->length() > 0) {
639 : // Then it's an indirect call or via JS->wasm wrapper.
640 : DCHECK_LE(2, lazy_compile_code->deoptimization_data()->length());
641 : exp_deopt_data = handle(lazy_compile_code->deoptimization_data(), isolate);
642 : auto* weak_cell = WeakCell::cast(exp_deopt_data->get(0));
643 : instance = handle(WasmInstanceObject::cast(weak_cell->value()), isolate);
644 : func_index = Smi::ToInt(exp_deopt_data->get(1));
645 : }
646 11477 : it.Advance();
647 : // Third frame: The calling wasm code or js-to-wasm wrapper.
648 : DCHECK(!it.done());
649 : DCHECK(it.frame()->is_js_to_wasm() || it.frame()->is_wasm_compiled());
650 11477 : Handle<Code> caller_code = handle(it.frame()->LookupCode(), isolate);
651 22954 : if (it.frame()->is_js_to_wasm()) {
652 : DCHECK(!instance.is_null());
653 3701 : } else if (instance.is_null()) {
654 : // Then this is a direct call (otherwise we would have attached the instance
655 : // via deopt data to the lazy compile stub). Just use the instance of the
656 : // caller.
657 : instance =
658 2963 : handle(WasmInstanceObject::GetOwningInstance(*caller_code), isolate);
659 : }
660 : int offset =
661 34431 : static_cast<int>(it.frame()->pc() - caller_code->instruction_start());
662 : // Only patch the caller code if this is *no* indirect call.
663 : // exp_deopt_data will be null if the called function is not exported at all,
664 : // and its length will be <= 2 if all entries in tables were already patched.
665 : // Note that this check is conservative: If the first call to an exported
666 : // function is direct, we will just patch the export tables, and only on the
667 : // second call we will patch the caller.
668 3701 : bool patch_caller = caller_code->kind() == Code::JS_TO_WASM_FUNCTION ||
669 12215 : exp_deopt_data.is_null() || exp_deopt_data->length() <= 2;
670 :
671 : Handle<Code> compiled_code = WasmCompiledModule::CompileLazy(
672 11477 : isolate, instance, caller_code, offset, func_index, patch_caller);
673 19991 : if (!exp_deopt_data.is_null() && exp_deopt_data->length() > 2) {
674 : // See EnsureExportedLazyDeoptData: exp_deopt_data[2...(len-1)] are pairs of
675 : // <export_table, index> followed by undefined values.
676 : // Use this information here to patch all export tables.
677 : DCHECK_EQ(0, exp_deopt_data->length() % 2);
678 1154 : for (int idx = 2, end = exp_deopt_data->length(); idx < end; idx += 2) {
679 583 : if (exp_deopt_data->get(idx)->IsUndefined(isolate)) break;
680 : FixedArray* exp_table = FixedArray::cast(exp_deopt_data->get(idx));
681 583 : int exp_index = Smi::ToInt(exp_deopt_data->get(idx + 1));
682 : DCHECK(exp_table->get(exp_index) == *lazy_compile_code);
683 583 : exp_table->set(exp_index, *compiled_code);
684 : }
685 : // After processing, remove the list of exported entries, such that we don't
686 : // do the patching redundantly.
687 : Handle<FixedArray> new_deopt_data =
688 571 : isolate->factory()->CopyFixedArrayUpTo(exp_deopt_data, 2, TENURED);
689 571 : lazy_compile_code->set_deoptimization_data(*new_deopt_data);
690 : }
691 :
692 22954 : return compiled_code;
693 : }
694 :
695 11259 : compiler::ModuleEnv CreateModuleEnvFromCompiledModule(
696 : Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
697 : DisallowHeapAllocation no_gc;
698 11259 : WasmModule* module = compiled_module->module();
699 :
700 : std::vector<GlobalHandleAddress> function_tables;
701 : std::vector<GlobalHandleAddress> signature_tables;
702 :
703 22518 : int num_function_tables = static_cast<int>(module->function_tables.size());
704 14854 : for (int i = 0; i < num_function_tables; ++i) {
705 : FixedArray* ft = compiled_module->ptr_to_function_tables();
706 : FixedArray* st = compiled_module->ptr_to_signature_tables();
707 :
708 : // TODO(clemensh): defer these handles for concurrent compilation.
709 7190 : function_tables.push_back(WasmCompiledModule::GetTableValue(ft, i));
710 7190 : signature_tables.push_back(WasmCompiledModule::GetTableValue(st, i));
711 : }
712 :
713 : std::vector<Handle<Code>> empty_code;
714 :
715 : compiler::ModuleEnv result = {module, // --
716 : function_tables, // --
717 : signature_tables, // --
718 : empty_code, // --
719 11259 : BUILTIN_CODE(isolate, WasmCompileLazy)};
720 11259 : return result;
721 : }
722 :
723 11477 : void LazyCompilationOrchestrator::CompileFunction(
724 11259 : Isolate* isolate, Handle<WasmInstanceObject> instance, int func_index) {
725 : base::ElapsedTimer compilation_timer;
726 : compilation_timer.Start();
727 : Handle<WasmCompiledModule> compiled_module(instance->compiled_module(),
728 : isolate);
729 22954 : if (Code::cast(compiled_module->code_table()->get(func_index))->kind() ==
730 : Code::WASM_FUNCTION) {
731 218 : return;
732 : }
733 :
734 : compiler::ModuleEnv module_env =
735 11259 : CreateModuleEnvFromCompiledModule(isolate, compiled_module);
736 :
737 11259 : const uint8_t* module_start = compiled_module->module_bytes()->GetChars();
738 :
739 11259 : const WasmFunction* func = &module_env.module->functions[func_index];
740 11259 : FunctionBody body{func->sig, func->code.offset(),
741 11259 : module_start + func->code.offset(),
742 45036 : module_start + func->code.end_offset()};
743 : // TODO(wasm): Refactor this to only get the name if it is really needed for
744 : // tracing / debugging.
745 : std::string func_name;
746 : {
747 : WasmName name = Vector<const char>::cast(
748 22518 : compiled_module->GetRawFunctionName(func_index));
749 : // Copy to std::string, because the underlying string object might move on
750 : // the heap.
751 11259 : func_name.assign(name.start(), static_cast<size_t>(name.length()));
752 : }
753 11259 : ErrorThrower thrower(isolate, "WasmLazyCompile");
754 : compiler::WasmCompilationUnit unit(isolate, &module_env, body,
755 : CStrVector(func_name.c_str()), func_index,
756 45036 : CEntryStub(isolate, 1).GetCode());
757 11259 : unit.ExecuteCompilation();
758 11259 : MaybeHandle<Code> maybe_code = unit.FinishCompilation(&thrower);
759 :
760 : // If there is a pending error, something really went wrong. The module was
761 : // verified before starting execution with lazy compilation.
762 : // This might be OOM, but then we cannot continue execution anyway.
763 : // TODO(clemensh): According to the spec, we can actually skip validation at
764 : // module creation time, and return a function that always traps here.
765 22518 : CHECK(!thrower.error());
766 : Handle<Code> code = maybe_code.ToHandleChecked();
767 :
768 11259 : Handle<FixedArray> deopt_data = isolate->factory()->NewFixedArray(2, TENURED);
769 11259 : Handle<WeakCell> weak_instance = isolate->factory()->NewWeakCell(instance);
770 : // TODO(wasm): Introduce constants for the indexes in wasm deopt data.
771 11259 : deopt_data->set(0, *weak_instance);
772 : deopt_data->set(1, Smi::FromInt(func_index));
773 11259 : code->set_deoptimization_data(*deopt_data);
774 :
775 : DCHECK_EQ(Builtins::kWasmCompileLazy,
776 : Code::cast(compiled_module->code_table()->get(func_index))
777 : ->builtin_index());
778 22518 : compiled_module->code_table()->set(func_index, *code);
779 :
780 : // Now specialize the generated code for this instance.
781 22518 : Zone specialization_zone(isolate->allocator(), ZONE_NAME);
782 22518 : CodeSpecialization code_specialization(isolate, &specialization_zone);
783 11259 : code_specialization.RelocateDirectCalls(instance);
784 11259 : code_specialization.ApplyToWasmCode(*code, SKIP_ICACHE_FLUSH);
785 11259 : Assembler::FlushICache(isolate, code->instruction_start(),
786 22518 : code->instruction_size());
787 : int64_t func_size =
788 11259 : static_cast<int64_t>(func->code.end_offset() - func->code.offset());
789 : int64_t compilation_time = compilation_timer.Elapsed().InMicroseconds();
790 : auto counters = isolate->counters();
791 11259 : counters->wasm_lazily_compiled_functions()->Increment();
792 11259 : counters->wasm_generated_code_size()->Increment(code->body_size());
793 11259 : counters->wasm_reloc_size()->Increment(code->relocation_info()->length());
794 : counters->wasm_lazy_compilation_throughput()->AddSample(
795 11259 : compilation_time != 0 ? static_cast<int>(func_size / compilation_time)
796 33777 : : 0);
797 : }
798 :
799 158487 : int AdvanceSourcePositionTableIterator(SourcePositionTableIterator& iterator,
800 : int offset) {
801 : DCHECK(!iterator.done());
802 : int byte_pos;
803 64607 : do {
804 : byte_pos = iterator.source_position().ScriptOffset();
805 64607 : iterator.Advance();
806 129214 : } while (!iterator.done() && iterator.code_offset() <= offset);
807 29273 : return byte_pos;
808 : }
809 :
810 11477 : Handle<Code> LazyCompilationOrchestrator::CompileLazy(
811 : Isolate* isolate, Handle<WasmInstanceObject> instance, Handle<Code> caller,
812 : int call_offset, int exported_func_index, bool patch_caller) {
813 : struct NonCompiledFunction {
814 : int offset;
815 : int func_index;
816 : };
817 : std::vector<NonCompiledFunction> non_compiled_functions;
818 : int func_to_return_idx = exported_func_index;
819 : Decoder decoder(nullptr, nullptr);
820 11477 : bool is_js_to_wasm = caller->kind() == Code::JS_TO_WASM_FUNCTION;
821 : Handle<WasmCompiledModule> compiled_module(instance->compiled_module(),
822 : isolate);
823 :
824 11477 : if (is_js_to_wasm) {
825 15552 : non_compiled_functions.push_back({0, exported_func_index});
826 3701 : } else if (patch_caller) {
827 : DisallowHeapAllocation no_gc;
828 : SeqOneByteString* module_bytes = compiled_module->module_bytes();
829 : SourcePositionTableIterator source_pos_iterator(
830 3136 : caller->SourcePositionTable());
831 : DCHECK_EQ(2, caller->deoptimization_data()->length());
832 : int caller_func_index = Smi::ToInt(caller->deoptimization_data()->get(1));
833 : const byte* func_bytes =
834 3136 : module_bytes->GetChars() +
835 9408 : compiled_module->module()->functions[caller_func_index].code.offset();
836 95583 : for (RelocIterator it(*caller, RelocInfo::kCodeTargetMask); !it.done();
837 89311 : it.next()) {
838 : Code* callee =
839 89311 : Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
840 89311 : if (callee->builtin_index() != Builtins::kWasmCompileLazy) continue;
841 : // TODO(clemensh): Introduce safe_cast<T, bool> which (D)CHECKS
842 : // (depending on the bool) against limits of T and then static_casts.
843 58546 : size_t offset_l = it.rinfo()->pc() - caller->instruction_start();
844 : DCHECK_GE(kMaxInt, offset_l);
845 29273 : int offset = static_cast<int>(offset_l);
846 : int byte_pos =
847 29273 : AdvanceSourcePositionTableIterator(source_pos_iterator, offset);
848 : int called_func_index =
849 29273 : ExtractDirectCallIndex(decoder, func_bytes + byte_pos);
850 58546 : non_compiled_functions.push_back({offset, called_func_index});
851 : // Call offset one instruction after the call. Remember the last called
852 : // function before that offset.
853 29273 : if (offset < call_offset) func_to_return_idx = called_func_index;
854 : }
855 : }
856 :
857 : // TODO(clemensh): compile all functions in non_compiled_functions in
858 : // background, wait for func_to_return_idx.
859 11477 : CompileFunction(isolate, instance, func_to_return_idx);
860 :
861 11477 : if (is_js_to_wasm || patch_caller) {
862 : DisallowHeapAllocation no_gc;
863 : // Now patch the code object with all functions which are now compiled.
864 : int idx = 0;
865 128264 : for (RelocIterator it(*caller, RelocInfo::kCodeTargetMask); !it.done();
866 106440 : it.next()) {
867 : Code* callee =
868 106440 : Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
869 106440 : if (callee->builtin_index() != Builtins::kWasmCompileLazy) continue;
870 : DCHECK_GT(non_compiled_functions.size(), idx);
871 74098 : int called_func_index = non_compiled_functions[idx].func_index;
872 : // Check that the callee agrees with our assumed called_func_index.
873 : DCHECK_IMPLIES(callee->deoptimization_data()->length() > 0,
874 : Smi::ToInt(callee->deoptimization_data()->get(1)) ==
875 : called_func_index);
876 : if (is_js_to_wasm) {
877 : DCHECK_EQ(func_to_return_idx, called_func_index);
878 : } else {
879 : DCHECK_EQ(non_compiled_functions[idx].offset,
880 : it.rinfo()->pc() - caller->instruction_start());
881 : }
882 37049 : ++idx;
883 : Handle<Code> callee_compiled(
884 74098 : Code::cast(compiled_module->code_table()->get(called_func_index)));
885 37049 : if (callee_compiled->builtin_index() == Builtins::kWasmCompileLazy) {
886 : DCHECK_NE(func_to_return_idx, called_func_index);
887 : continue;
888 : }
889 : DCHECK_EQ(Code::WASM_FUNCTION, callee_compiled->kind());
890 : it.rinfo()->set_target_address(isolate,
891 13695 : callee_compiled->instruction_start());
892 : }
893 : DCHECK_EQ(non_compiled_functions.size(), idx);
894 : }
895 :
896 : Code* ret =
897 22954 : Code::cast(compiled_module->code_table()->get(func_to_return_idx));
898 : DCHECK_EQ(Code::WASM_FUNCTION, ret->kind());
899 11477 : return handle(ret, isolate);
900 : }
901 :
902 0 : ModuleCompiler::CodeGenerationSchedule::CodeGenerationSchedule(
903 : base::RandomNumberGenerator* random_number_generator, size_t max_memory)
904 : : random_number_generator_(random_number_generator),
905 307618 : max_memory_(max_memory) {
906 : DCHECK_NOT_NULL(random_number_generator_);
907 : DCHECK_GT(max_memory_, 0);
908 0 : }
909 :
910 38670 : void ModuleCompiler::CodeGenerationSchedule::Schedule(
911 : std::unique_ptr<compiler::WasmCompilationUnit>&& item) {
912 38670 : size_t cost = item->memory_cost();
913 38670 : schedule_.push_back(std::move(item));
914 : allocated_memory_.Increment(cost);
915 38671 : }
916 :
917 0 : bool ModuleCompiler::CodeGenerationSchedule::CanAcceptWork() const {
918 120252 : return (!throttle_ || allocated_memory_.Value() <= max_memory_);
919 : }
920 :
921 36 : bool ModuleCompiler::CodeGenerationSchedule::ShouldIncreaseWorkload() const {
922 : // Half the memory is unused again, we can increase the workload again.
923 72 : return (!throttle_ || allocated_memory_.Value() <= max_memory_ / 2);
924 : }
925 :
926 : std::unique_ptr<compiler::WasmCompilationUnit>
927 38441 : ModuleCompiler::CodeGenerationSchedule::GetNext() {
928 : DCHECK(!IsEmpty());
929 38441 : size_t index = GetRandomIndexInSchedule();
930 115323 : auto ret = std::move(schedule_[index]);
931 38441 : std::swap(schedule_[schedule_.size() - 1], schedule_[index]);
932 38441 : schedule_.pop_back();
933 38441 : allocated_memory_.Decrement(ret->memory_cost());
934 38441 : return ret;
935 : }
936 :
937 38441 : size_t ModuleCompiler::CodeGenerationSchedule::GetRandomIndexInSchedule() {
938 38441 : double factor = random_number_generator_->NextDouble();
939 76882 : size_t index = (size_t)(factor * schedule_.size());
940 : DCHECK_GE(index, 0);
941 : DCHECK_LT(index, schedule_.size());
942 38441 : return index;
943 : }
944 :
945 153809 : ModuleCompiler::ModuleCompiler(Isolate* isolate, WasmModule* module,
946 : Handle<Code> centry_stub)
947 : : isolate_(isolate),
948 : module_(module),
949 : async_counters_(isolate->async_counters()),
950 : executed_units_(
951 : isolate->random_number_generator(),
952 153809 : (isolate->heap()->memory_allocator()->code_range()->valid()
953 : ? isolate->heap()->memory_allocator()->code_range()->size()
954 0 : : isolate->heap()->code_space()->Capacity()) /
955 : 2),
956 : num_background_tasks_(
957 : Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
958 153809 : V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())),
959 : stopped_compilation_tasks_(num_background_tasks_),
960 922854 : centry_stub_(centry_stub) {}
961 :
962 : // The actual runnable task that performs compilations in the background.
963 22205 : void ModuleCompiler::OnBackgroundTaskStopped() {
964 22205 : base::LockGuard<base::Mutex> guard(&tasks_mutex_);
965 22205 : ++stopped_compilation_tasks_;
966 : DCHECK_LE(stopped_compilation_tasks_, num_background_tasks_);
967 22198 : }
968 :
969 : // Run by each compilation task The no_finisher_callback is called
970 : // within the result_mutex_ lock when no finishing task is running,
971 : // i.e. when the finisher_is_running_ flag is not set.
972 64531 : bool ModuleCompiler::FetchAndExecuteCompilationUnit(
973 : std::function<void()> no_finisher_callback) {
974 : DisallowHeapAllocation no_allocation;
975 : DisallowHandleAllocation no_handles;
976 : DisallowHandleDereference no_deref;
977 : DisallowCodeDependencyChange no_dependency_change;
978 :
979 64531 : std::unique_ptr<compiler::WasmCompilationUnit> unit;
980 : {
981 64531 : base::LockGuard<base::Mutex> guard(&compilation_units_mutex_);
982 64591 : if (compilation_units_.empty()) return false;
983 : unit = std::move(compilation_units_.back());
984 38671 : compilation_units_.pop_back();
985 : }
986 38671 : unit->ExecuteCompilation();
987 : {
988 38541 : base::LockGuard<base::Mutex> guard(&result_mutex_);
989 38671 : executed_units_.Schedule(std::move(unit));
990 38671 : if (no_finisher_callback != nullptr && !finisher_is_running_) {
991 199 : no_finisher_callback();
992 : // We set the flag here so that not more than one finisher is started.
993 199 : finisher_is_running_ = true;
994 : }
995 : }
996 38671 : return true;
997 : }
998 :
999 3425 : size_t ModuleCompiler::InitializeCompilationUnits(
1000 41731 : const std::vector<WasmFunction>& functions,
1001 : const ModuleWireBytes& wire_bytes, compiler::ModuleEnv* module_env) {
1002 3425 : uint32_t start = module_env->module->num_imported_functions +
1003 3425 : FLAG_skip_compiling_wasm_funcs;
1004 3425 : uint32_t num_funcs = static_cast<uint32_t>(functions.size());
1005 3425 : uint32_t funcs_to_compile = start > num_funcs ? 0 : num_funcs - start;
1006 : CompilationUnitBuilder builder(this);
1007 41731 : for (uint32_t i = start; i < num_funcs; ++i) {
1008 38306 : const WasmFunction* func = &functions[i];
1009 38306 : uint32_t buffer_offset = func->code.offset();
1010 : Vector<const uint8_t> bytes(wire_bytes.start() + func->code.offset(),
1011 76612 : func->code.end_offset() - func->code.offset());
1012 38306 : WasmName name = wire_bytes.GetName(func);
1013 38306 : builder.AddUnit(module_env, func, buffer_offset, bytes, name);
1014 : }
1015 3425 : builder.Commit();
1016 6850 : return funcs_to_compile;
1017 : }
1018 :
1019 4005 : void ModuleCompiler::RestartCompilationTasks() {
1020 4005 : base::LockGuard<base::Mutex> guard(&tasks_mutex_);
1021 23548 : for (; stopped_compilation_tasks_ > 0; --stopped_compilation_tasks_) {
1022 23548 : V8::GetCurrentPlatform()->CallOnBackgroundThread(
1023 : new CompilationTask(this),
1024 47096 : v8::Platform::ExpectedRuntime::kShortRunningTask);
1025 : }
1026 4005 : }
1027 :
1028 4466 : size_t ModuleCompiler::FinishCompilationUnits(
1029 36981 : std::vector<Handle<Code>>& results, ErrorThrower* thrower) {
1030 : size_t finished = 0;
1031 : while (true) {
1032 41447 : int func_index = -1;
1033 41447 : MaybeHandle<Code> result = FinishCompilationUnit(thrower, &func_index);
1034 41447 : if (func_index < 0) break;
1035 37111 : ++finished;
1036 : DCHECK_IMPLIES(result.is_null(), thrower->error());
1037 37111 : if (result.is_null()) break;
1038 73962 : results[func_index] = result.ToHandleChecked();
1039 : }
1040 : bool do_restart;
1041 : {
1042 4466 : base::LockGuard<base::Mutex> guard(&compilation_units_mutex_);
1043 : do_restart = !compilation_units_.empty();
1044 : }
1045 4466 : if (do_restart) RestartCompilationTasks();
1046 41447 : return finished;
1047 : }
1048 :
1049 0 : void ModuleCompiler::SetFinisherIsRunning(bool value) {
1050 195 : base::LockGuard<base::Mutex> guard(&result_mutex_);
1051 195 : finisher_is_running_ = value;
1052 0 : }
1053 :
1054 42930 : MaybeHandle<Code> ModuleCompiler::FinishCompilationUnit(ErrorThrower* thrower,
1055 : int* func_index) {
1056 : std::unique_ptr<compiler::WasmCompilationUnit> unit;
1057 : {
1058 42930 : base::LockGuard<base::Mutex> guard(&result_mutex_);
1059 42930 : if (executed_units_.IsEmpty()) return {};
1060 76882 : unit = executed_units_.GetNext();
1061 : }
1062 38441 : *func_index = unit->func_index();
1063 38441 : return unit->FinishCompilation(thrower);
1064 : }
1065 :
1066 3364 : void ModuleCompiler::CompileInParallel(const ModuleWireBytes& wire_bytes,
1067 : compiler::ModuleEnv* module_env,
1068 : std::vector<Handle<Code>>& results,
1069 : ErrorThrower* thrower) {
1070 3364 : const WasmModule* module = module_env->module;
1071 : // Data structures for the parallel compilation.
1072 :
1073 : //-----------------------------------------------------------------------
1074 : // For parallel compilation:
1075 : // 1) The main thread allocates a compilation unit for each wasm function
1076 : // and stores them in the vector {compilation_units}.
1077 : // 2) The main thread spawns {CompilationTask} instances which run on
1078 : // the background threads.
1079 : // 3.a) The background threads and the main thread pick one compilation
1080 : // unit at a time and execute the parallel phase of the compilation
1081 : // unit. After finishing the execution of the parallel phase, the
1082 : // result is enqueued in {executed_units}.
1083 : // 3.b) If {executed_units} contains a compilation unit, the main thread
1084 : // dequeues it and finishes the compilation.
1085 : // 4) After the parallel phase of all compilation units has started, the
1086 : // main thread waits for all {CompilationTask} instances to finish.
1087 : // 5) The main thread finishes the compilation.
1088 :
1089 : // Turn on the {CanonicalHandleScope} so that the background threads can
1090 : // use the node cache.
1091 3364 : CanonicalHandleScope canonical(isolate_);
1092 :
1093 : // 1) The main thread allocates a compilation unit for each wasm function
1094 : // and stores them in the vector {compilation_units}.
1095 3364 : InitializeCompilationUnits(module->functions, wire_bytes, module_env);
1096 : executed_units_.EnableThrottling();
1097 :
1098 : // 2) The main thread spawns {CompilationTask} instances which run on
1099 : // the background threads.
1100 3364 : RestartCompilationTasks();
1101 :
1102 : // 3.a) The background threads and the main thread pick one compilation
1103 : // unit at a time and execute the parallel phase of the compilation
1104 : // unit. After finishing the execution of the parallel phase, the
1105 : // result is enqueued in {executed_units}.
1106 : // The foreground task bypasses waiting on memory threshold, because
1107 : // its results will immediately be converted to code (below).
1108 12296 : while (FetchAndExecuteCompilationUnit()) {
1109 : // 3.b) If {executed_units} contains a compilation unit, the main thread
1110 : // dequeues it and finishes the compilation unit. Compilation units
1111 : // are finished concurrently to the background threads to save
1112 : // memory.
1113 1102 : FinishCompilationUnits(results, thrower);
1114 : }
1115 : // 4) After the parallel phase of all compilation units has started, the
1116 : // main thread waits for all {CompilationTask} instances to finish - which
1117 : // happens once they all realize there's no next work item to process.
1118 3364 : background_task_manager_.CancelAndWait();
1119 : // Finish all compilation units which have been executed while we waited.
1120 3364 : FinishCompilationUnits(results, thrower);
1121 3364 : }
1122 :
1123 146609 : void ModuleCompiler::CompileSequentially(const ModuleWireBytes& wire_bytes,
1124 : compiler::ModuleEnv* module_env,
1125 137964 : std::vector<Handle<Code>>& results,
1126 : ErrorThrower* thrower) {
1127 : DCHECK(!thrower->error());
1128 :
1129 146609 : const WasmModule* module = module_env->module;
1130 839896 : for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
1131 419948 : i < module->functions.size(); ++i) {
1132 419948 : const WasmFunction& func = module->functions[i];
1133 278910 : if (func.imported) continue; // Imports are compiled at instantiation time.
1134 :
1135 : // Compile the function.
1136 : MaybeHandle<Code> code = compiler::WasmCompilationUnit::CompileWasmFunction(
1137 143535 : thrower, isolate_, wire_bytes, module_env, &func);
1138 143535 : if (code.is_null()) {
1139 : TruncatedUserString<> name(wire_bytes.GetName(&func));
1140 : thrower->CompileError("Compilation of #%d:%.*s failed.", i, name.length(),
1141 5571 : name.start());
1142 : break;
1143 : }
1144 137964 : results[i] = code.ToHandleChecked();
1145 : }
1146 146609 : }
1147 :
1148 40 : void ModuleCompiler::ValidateSequentially(const ModuleWireBytes& wire_bytes,
1149 : compiler::ModuleEnv* module_env,
1150 : ErrorThrower* thrower) {
1151 : DCHECK(!thrower->error());
1152 :
1153 80 : const WasmModule* module = module_env->module;
1154 140 : for (uint32_t i = 0; i < module->functions.size(); ++i) {
1155 70 : const WasmFunction& func = module->functions[i];
1156 40 : if (func.imported) continue;
1157 :
1158 : const byte* base = wire_bytes.start();
1159 80 : FunctionBody body{func.sig, func.code.offset(), base + func.code.offset(),
1160 160 : base + func.code.end_offset()};
1161 : DecodeResult result = VerifyWasmCodeWithStats(
1162 80 : isolate_->allocator(), module, body, module->is_wasm(), counters());
1163 40 : if (result.failed()) {
1164 : TruncatedUserString<> name(wire_bytes.GetName(&func));
1165 : thrower->CompileError("Compiling function #%d:%.*s failed: %s @+%u", i,
1166 : name.length(), name.start(),
1167 10 : result.error_msg().c_str(), result.error_offset());
1168 : break;
1169 : }
1170 : }
1171 40 : }
1172 :
1173 : // static
1174 153554 : MaybeHandle<WasmModuleObject> ModuleCompiler::CompileToModuleObject(
1175 : Isolate* isolate, ErrorThrower* thrower, std::unique_ptr<WasmModule> module,
1176 : const ModuleWireBytes& wire_bytes, Handle<Script> asm_js_script,
1177 : Vector<const byte> asm_js_offset_table_bytes) {
1178 307108 : Handle<Code> centry_stub = CEntryStub(isolate, 1).GetCode();
1179 153554 : ModuleCompiler compiler(isolate, module.get(), centry_stub);
1180 : return compiler.CompileToModuleObjectInternal(thrower, std::move(module),
1181 : wire_bytes, asm_js_script,
1182 307108 : asm_js_offset_table_bytes);
1183 : }
1184 :
1185 : namespace {
1186 155062 : bool compile_lazy(const WasmModule* module) {
1187 155384 : return FLAG_wasm_lazy_compilation ||
1188 155062 : (FLAG_asm_wasm_lazy_compilation && module->is_asm_js());
1189 : }
1190 :
1191 305324 : void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) {
1192 1688864 : for (int i = 0; i < code_table->length(); ++i) {
1193 539108 : Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
1194 539108 : Assembler::FlushICache(isolate, code->instruction_start(),
1195 1078216 : code->instruction_size());
1196 : }
1197 305324 : }
1198 :
1199 11140 : byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) {
1200 11140 : return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset;
1201 : }
1202 :
1203 533509 : void RecordStats(Code* code, Counters* counters) {
1204 533509 : counters->wasm_generated_code_size()->Increment(code->body_size());
1205 533509 : counters->wasm_reloc_size()->Increment(code->relocation_info()->length());
1206 533509 : }
1207 :
1208 13250 : void RecordStats(Handle<FixedArray> functions, Counters* counters) {
1209 : DisallowHeapAllocation no_gc;
1210 84210 : for (int i = 0; i < functions->length(); ++i) {
1211 : Object* val = functions->get(i);
1212 28855 : if (val->IsCode()) RecordStats(Code::cast(val), counters);
1213 : }
1214 13250 : }
1215 144411 : Handle<Script> CreateWasmScript(Isolate* isolate,
1216 : const ModuleWireBytes& wire_bytes) {
1217 : Handle<Script> script =
1218 144411 : isolate->factory()->NewScript(isolate->factory()->empty_string());
1219 288822 : script->set_context_data(isolate->native_context()->debug_context_id());
1220 : script->set_type(Script::TYPE_WASM);
1221 :
1222 : int hash = StringHasher::HashSequentialString(
1223 : reinterpret_cast<const char*>(wire_bytes.start()),
1224 144411 : static_cast<int>(wire_bytes.length()), kZeroHashSeed);
1225 :
1226 : const int kBufferSize = 32;
1227 : char buffer[kBufferSize];
1228 144411 : int url_chars = SNPrintF(ArrayVector(buffer), "wasm://wasm/%08x", hash);
1229 : DCHECK(url_chars >= 0 && url_chars < kBufferSize);
1230 : MaybeHandle<String> url_str = isolate->factory()->NewStringFromOneByte(
1231 : Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), url_chars),
1232 288822 : TENURED);
1233 144411 : script->set_source_url(*url_str.ToHandleChecked());
1234 :
1235 144411 : int name_chars = SNPrintF(ArrayVector(buffer), "wasm-%08x", hash);
1236 : DCHECK(name_chars >= 0 && name_chars < kBufferSize);
1237 : MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
1238 : Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), name_chars),
1239 288822 : TENURED);
1240 144411 : script->set_name(*name_str.ToHandleChecked());
1241 :
1242 144411 : return script;
1243 : }
1244 :
1245 : // Ensure that the code object in <code_table> at offset <func_index> has
1246 : // deoptimization data attached. This is needed for lazy compile stubs which are
1247 : // called from JS_TO_WASM functions or via exported function tables. The deopt
1248 : // data is used to determine which function this lazy compile stub belongs to.
1249 194766 : Handle<Code> EnsureExportedLazyDeoptData(Isolate* isolate,
1250 : Handle<WasmInstanceObject> instance,
1251 : Handle<FixedArray> code_table,
1252 : int func_index) {
1253 : Handle<Code> code(Code::cast(code_table->get(func_index)), isolate);
1254 194766 : if (code->builtin_index() != Builtins::kWasmCompileLazy) {
1255 : // No special deopt data needed for compiled functions, and imported
1256 : // functions, which map to Illegal at this point (they get compiled at
1257 : // instantiation time).
1258 : DCHECK(code->kind() == Code::WASM_FUNCTION ||
1259 : code->kind() == Code::WASM_TO_JS_FUNCTION ||
1260 : code->builtin_index() == Builtins::kIllegal);
1261 178757 : return code;
1262 : }
1263 : // deopt_data:
1264 : // #0: weak instance
1265 : // #1: func_index
1266 : // might be extended later for table exports (see
1267 : // EnsureTableExportLazyDeoptData).
1268 : Handle<FixedArray> deopt_data(code->deoptimization_data());
1269 : DCHECK_EQ(0, deopt_data->length() % 2);
1270 16009 : if (deopt_data->length() == 0) {
1271 12918 : code = isolate->factory()->CopyCode(code);
1272 12918 : code_table->set(func_index, *code);
1273 12918 : deopt_data = isolate->factory()->NewFixedArray(2, TENURED);
1274 12918 : code->set_deoptimization_data(*deopt_data);
1275 12918 : if (!instance.is_null()) {
1276 : Handle<WeakCell> weak_instance =
1277 6843 : isolate->factory()->NewWeakCell(instance);
1278 6843 : deopt_data->set(0, *weak_instance);
1279 : }
1280 : deopt_data->set(1, Smi::FromInt(func_index));
1281 : }
1282 : DCHECK_IMPLIES(!instance.is_null(),
1283 : WeakCell::cast(code->deoptimization_data()->get(0))->value() ==
1284 : *instance);
1285 : DCHECK_EQ(func_index, Smi::ToInt(code->deoptimization_data()->get(1)));
1286 16009 : return code;
1287 : }
1288 :
1289 : // Ensure that the code object in <code_table> at offset <func_index> has
1290 : // deoptimization data attached. This is needed for lazy compile stubs which are
1291 : // called from JS_TO_WASM functions or via exported function tables. The deopt
1292 : // data is used to determine which function this lazy compile stub belongs to.
1293 9582 : Handle<Code> EnsureTableExportLazyDeoptData(
1294 : Isolate* isolate, Handle<WasmInstanceObject> instance,
1295 : Handle<FixedArray> code_table, int func_index,
1296 : Handle<FixedArray> export_table, int export_index,
1297 : std::unordered_map<uint32_t, uint32_t>& table_export_count) {
1298 : Handle<Code> code =
1299 9582 : EnsureExportedLazyDeoptData(isolate, instance, code_table, func_index);
1300 9582 : if (code->builtin_index() != Builtins::kWasmCompileLazy) return code;
1301 :
1302 : // deopt_data:
1303 : // #0: weak instance
1304 : // #1: func_index
1305 : // [#2: export table
1306 : // #3: export table index]
1307 : // [#4: export table
1308 : // #5: export table index]
1309 : // ...
1310 : // table_export_count counts down and determines the index for the new export
1311 : // table entry.
1312 13086 : auto table_export_entry = table_export_count.find(func_index);
1313 : DCHECK(table_export_entry != table_export_count.end());
1314 : DCHECK_LT(0, table_export_entry->second);
1315 6543 : uint32_t this_idx = 2 * table_export_entry->second;
1316 6543 : --table_export_entry->second;
1317 : Handle<FixedArray> deopt_data(code->deoptimization_data());
1318 : DCHECK_EQ(0, deopt_data->length() % 2);
1319 6543 : if (deopt_data->length() == 2) {
1320 : // Then only the "header" (#0 and #1) exists. Extend for the export table
1321 : // entries (make space for this_idx + 2 elements).
1322 : deopt_data = isolate->factory()->CopyFixedArrayAndGrow(deopt_data, this_idx,
1323 4486 : TENURED);
1324 4486 : code->set_deoptimization_data(*deopt_data);
1325 : }
1326 : DCHECK_LE(this_idx + 2, deopt_data->length());
1327 : DCHECK(deopt_data->get(this_idx)->IsUndefined(isolate));
1328 : DCHECK(deopt_data->get(this_idx + 1)->IsUndefined(isolate));
1329 13086 : deopt_data->set(this_idx, *export_table);
1330 6543 : deopt_data->set(this_idx + 1, Smi::FromInt(export_index));
1331 6543 : return code;
1332 : }
1333 :
1334 : bool in_bounds(uint32_t offset, uint32_t size, uint32_t upper) {
1335 2130 : return offset + size <= upper && offset + size >= offset;
1336 : }
1337 :
1338 : using WasmInstanceMap =
1339 : IdentityMap<Handle<WasmInstanceObject>, FreeStoreAllocationPolicy>;
1340 :
1341 133885 : Handle<Code> MakeWasmToWasmWrapper(
1342 : Isolate* isolate, Handle<WasmExportedFunction> imported_function,
1343 : FunctionSig* expected_sig, FunctionSig** sig,
1344 : WasmInstanceMap* imported_instances, Handle<WasmInstanceObject> instance) {
1345 : // TODO(wasm): cache WASM-to-WASM wrappers by signature and clone+patch.
1346 : Handle<WasmInstanceObject> imported_instance(imported_function->instance(),
1347 133885 : isolate);
1348 : imported_instances->Set(imported_instance, imported_instance);
1349 133885 : Handle<Code> wasm_code = imported_function->GetWasmCode();
1350 : WasmContext* new_wasm_context = imported_instance->wasm_context()->get();
1351 : Address new_wasm_context_address =
1352 : reinterpret_cast<Address>(new_wasm_context);
1353 133885 : *sig = imported_instance->module()
1354 267770 : ->functions[imported_function->function_index()]
1355 133885 : .sig;
1356 133885 : if (expected_sig && !expected_sig->Equals(*sig)) return Handle<Code>::null();
1357 :
1358 : Handle<Code> wrapper_code = compiler::CompileWasmToWasmWrapper(
1359 133665 : isolate, wasm_code, *sig, imported_function->function_index(),
1360 133665 : new_wasm_context_address);
1361 : // Set the deoptimization data for the WasmToWasm wrapper. This is
1362 : // needed by the interpreter to find the imported instance for
1363 : // a cross-instance call.
1364 : Factory* factory = isolate->factory();
1365 133665 : Handle<WeakCell> weak_link = factory->NewWeakCell(imported_instance);
1366 133665 : Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED);
1367 133665 : deopt_data->set(0, *weak_link);
1368 133665 : auto function_index = Smi::FromInt(imported_function->function_index());
1369 : deopt_data->set(1, function_index);
1370 133665 : wrapper_code->set_deoptimization_data(*deopt_data);
1371 133665 : return wrapper_code;
1372 : }
1373 :
1374 142795 : Handle<Code> UnwrapExportOrCompileImportWrapper(
1375 : Isolate* isolate, FunctionSig* sig, Handle<JSReceiver> target,
1376 : uint32_t import_index, ModuleOrigin origin,
1377 : WasmInstanceMap* imported_instances, Handle<FixedArray> js_imports_table,
1378 : Handle<WasmInstanceObject> instance) {
1379 142795 : if (WasmExportedFunction::IsWasmExportedFunction(*target)) {
1380 131265 : FunctionSig* unused = nullptr;
1381 : return MakeWasmToWasmWrapper(isolate,
1382 : Handle<WasmExportedFunction>::cast(target),
1383 131265 : sig, &unused, imported_instances, instance);
1384 : }
1385 : // No wasm function or being debugged. Compile a new wrapper for the new
1386 : // signature.
1387 : return compiler::CompileWasmToJSWrapper(isolate, target, sig, import_index,
1388 11530 : origin, js_imports_table);
1389 : }
1390 :
1391 1485 : double MonotonicallyIncreasingTimeInMs() {
1392 1485 : return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
1393 1485 : base::Time::kMillisecondsPerSecond;
1394 : }
1395 :
1396 56532 : void FunctionTableFinalizer(const v8::WeakCallbackInfo<void>& data) {
1397 : GlobalHandles::Destroy(reinterpret_cast<Object**>(
1398 56532 : reinterpret_cast<JSObject**>(data.GetParameter())));
1399 56532 : }
1400 :
1401 153809 : std::unique_ptr<compiler::ModuleEnv> CreateDefaultModuleEnv(
1402 3480 : Isolate* isolate, WasmModule* module, Handle<Code> illegal_builtin) {
1403 : std::vector<GlobalHandleAddress> function_tables;
1404 : std::vector<GlobalHandleAddress> signature_tables;
1405 :
1406 311098 : for (size_t i = 0; i < module->function_tables.size(); i++) {
1407 : Handle<Object> func_table =
1408 1740 : isolate->global_handles()->Create(isolate->heap()->undefined_value());
1409 : Handle<Object> sig_table =
1410 1740 : isolate->global_handles()->Create(isolate->heap()->undefined_value());
1411 : GlobalHandles::MakeWeak(func_table.location(), func_table.location(),
1412 : &FunctionTableFinalizer,
1413 1740 : v8::WeakCallbackType::kFinalizer);
1414 : GlobalHandles::MakeWeak(sig_table.location(), sig_table.location(),
1415 : &FunctionTableFinalizer,
1416 1740 : v8::WeakCallbackType::kFinalizer);
1417 3480 : function_tables.push_back(func_table.address());
1418 3480 : signature_tables.push_back(sig_table.address());
1419 : }
1420 :
1421 : std::vector<Handle<Code>> empty_code;
1422 :
1423 : compiler::ModuleEnv result = {
1424 : module, // --
1425 : function_tables, // --
1426 : signature_tables, // --
1427 : empty_code, // --
1428 : illegal_builtin // --
1429 307618 : };
1430 307618 : return std::unique_ptr<compiler::ModuleEnv>(new compiler::ModuleEnv(result));
1431 : }
1432 :
1433 : Handle<WasmCompiledModule> NewCompiledModule(
1434 : Isolate* isolate, Handle<WasmSharedModuleData> shared,
1435 : Handle<FixedArray> code_table, Handle<FixedArray> export_wrappers,
1436 : compiler::ModuleEnv* env) {
1437 : Handle<WasmCompiledModule> compiled_module =
1438 : WasmCompiledModule::New(isolate, shared, code_table, export_wrappers,
1439 147958 : env->function_tables, env->signature_tables);
1440 147958 : return compiled_module;
1441 : }
1442 :
1443 : template <typename T>
1444 255 : void ReopenHandles(Isolate* isolate, const std::vector<Handle<T>>& vec) {
1445 255 : auto& mut = const_cast<std::vector<Handle<T>>&>(vec);
1446 510 : for (size_t i = 0; i < mut.size(); i++) {
1447 0 : mut[i] = Handle<T>(*mut[i], isolate);
1448 : }
1449 255 : }
1450 :
1451 : } // namespace
1452 :
1453 153554 : MaybeHandle<WasmModuleObject> ModuleCompiler::CompileToModuleObjectInternal(
1454 297826 : ErrorThrower* thrower, std::unique_ptr<WasmModule> module,
1455 : const ModuleWireBytes& wire_bytes, Handle<Script> asm_js_script,
1456 : Vector<const byte> asm_js_offset_table_bytes) {
1457 : TimedHistogramScope wasm_compile_module_time_scope(
1458 157135 : module_->is_wasm() ? counters()->wasm_compile_wasm_module_time()
1459 307108 : : counters()->wasm_compile_asm_module_time());
1460 : // The {module> parameter is passed in to transfer ownership of the WasmModule
1461 : // to this function. The WasmModule itself existed already as an instance
1462 : // variable of the ModuleCompiler. We check here that the parameter and the
1463 : // instance variable actually point to the same object.
1464 : DCHECK_EQ(module.get(), module_);
1465 : // Check whether lazy compilation is enabled for this module.
1466 153554 : bool lazy_compile = compile_lazy(module_);
1467 :
1468 297850 : Factory* factory = isolate_->factory();
1469 :
1470 : // If lazy compile: Initialize the code table with the lazy compile builtin.
1471 : // Otherwise: Initialize with the illegal builtin. All call sites will be
1472 : // patched at instantiation.
1473 : Handle<Code> init_builtin = lazy_compile
1474 3581 : ? BUILTIN_CODE(isolate_, WasmCompileLazy)
1475 157135 : : BUILTIN_CODE(isolate_, Illegal);
1476 :
1477 153554 : auto env = CreateDefaultModuleEnv(isolate_, module_, init_builtin);
1478 :
1479 : // The {code_table} array contains import wrappers and functions (which
1480 : // are both included in {functions.size()}, and export wrappers).
1481 457081 : int code_table_size = static_cast<int>(module_->functions.size());
1482 153554 : int export_wrappers_size = static_cast<int>(module_->num_exported_functions);
1483 : Handle<FixedArray> code_table =
1484 153554 : factory->NewFixedArray(static_cast<int>(code_table_size), TENURED);
1485 : Handle<FixedArray> export_wrappers =
1486 153554 : factory->NewFixedArray(static_cast<int>(export_wrappers_size), TENURED);
1487 : // Initialize the code table.
1488 492136 : for (int i = 0, e = code_table->length(); i < e; ++i) {
1489 338582 : code_table->set(i, *init_builtin);
1490 : }
1491 :
1492 332480 : for (int i = 0, e = export_wrappers->length(); i < e; ++i) {
1493 178926 : export_wrappers->set(i, *init_builtin);
1494 : }
1495 :
1496 153554 : if (!lazy_compile) {
1497 : size_t funcs_to_compile =
1498 299946 : module_->functions.size() - module_->num_imported_functions;
1499 : bool compile_parallel =
1500 299946 : !FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks > 0 &&
1501 153337 : funcs_to_compile > 1 &&
1502 3364 : V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads() > 0;
1503 : // Avoid a race condition by collecting results into a second vector.
1504 299946 : std::vector<Handle<Code>> results(env->module->functions.size());
1505 :
1506 149973 : if (compile_parallel) {
1507 3364 : CompileInParallel(wire_bytes, env.get(), results, thrower);
1508 : } else {
1509 146609 : CompileSequentially(wire_bytes, env.get(), results, thrower);
1510 : }
1511 149973 : if (thrower->error()) return {};
1512 :
1513 : // At this point, compilation has completed. Update the code table.
1514 638260 : for (size_t i =
1515 144272 : module_->num_imported_functions + FLAG_skip_compiling_wasm_funcs;
1516 319130 : i < results.size(); ++i) {
1517 : Code* code = *results[i];
1518 349716 : code_table->set(static_cast<int>(i), code);
1519 174858 : RecordStats(code, counters());
1520 : }
1521 7162 : } else if (module_->is_wasm()) {
1522 : // Validate wasm modules for lazy compilation. Don't validate asm.js
1523 : // modules, they are valid by construction (otherwise a CHECK will fail
1524 : // during lazy compilation).
1525 : // TODO(clemensh): According to the spec, we can actually skip validation
1526 : // at module creation time, and return a function that always traps at
1527 : // (lazy) compilation time.
1528 40 : ValidateSequentially(wire_bytes, env.get(), thrower);
1529 : }
1530 147853 : if (thrower->error()) return {};
1531 :
1532 : // Create heap objects for script, module bytes and asm.js offset table to
1533 : // be stored in the shared module data.
1534 : Handle<Script> script;
1535 : Handle<ByteArray> asm_js_offset_table;
1536 147843 : if (asm_js_script.is_null()) {
1537 144296 : script = CreateWasmScript(isolate_, wire_bytes);
1538 : } else {
1539 : script = asm_js_script;
1540 : asm_js_offset_table =
1541 3547 : isolate_->factory()->NewByteArray(asm_js_offset_table_bytes.length());
1542 : asm_js_offset_table->copy_in(0, asm_js_offset_table_bytes.start(),
1543 3547 : asm_js_offset_table_bytes.length());
1544 : }
1545 : // TODO(wasm): only save the sections necessary to deserialize a
1546 : // {WasmModule}. E.g. function bodies could be omitted.
1547 : Handle<String> module_bytes =
1548 : factory
1549 : ->NewStringFromOneByte({wire_bytes.start(), wire_bytes.length()},
1550 147843 : TENURED)
1551 295686 : .ToHandleChecked();
1552 : DCHECK(module_bytes->IsSeqOneByteString());
1553 :
1554 : // The {module_wrapper} will take ownership of the {WasmModule} object,
1555 : // and it will be destroyed when the GC reclaims the wrapper object.
1556 : Handle<WasmModuleWrapper> module_wrapper =
1557 147843 : WasmModuleWrapper::From(isolate_, module.release());
1558 :
1559 : // Create the shared module data.
1560 : // TODO(clemensh): For the same module (same bytes / same hash), we should
1561 : // only have one WasmSharedModuleData. Otherwise, we might only set
1562 : // breakpoints on a (potentially empty) subset of the instances.
1563 :
1564 : Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New(
1565 : isolate_, module_wrapper, Handle<SeqOneByteString>::cast(module_bytes),
1566 147843 : script, asm_js_offset_table);
1567 147843 : if (lazy_compile) WasmSharedModuleData::PrepareForLazyCompilation(shared);
1568 :
1569 : // Create the compiled module object and populate with compiled functions
1570 : // and information needed at instantiation time. This object needs to be
1571 : // serializable. Instantiation may occur off a deserialized version of this
1572 : // object.
1573 : Handle<WasmCompiledModule> compiled_module = NewCompiledModule(
1574 147843 : isolate_, shared, code_table, export_wrappers, env.get());
1575 :
1576 : // If we created a wasm script, finish it now and make it public to the
1577 : // debugger.
1578 147843 : if (asm_js_script.is_null()) {
1579 144296 : script->set_wasm_compiled_module(*compiled_module);
1580 288592 : isolate_->debug()->OnAfterCompile(script);
1581 : }
1582 :
1583 : // Compile JS->wasm wrappers for exported functions.
1584 147843 : JSToWasmWrapperCache js_to_wasm_cache;
1585 : int wrapper_index = 0;
1586 624164 : for (auto exp : module_->export_table) {
1587 182405 : if (exp.kind != kExternalFunction) continue;
1588 : Handle<Code> wasm_code = EnsureExportedLazyDeoptData(
1589 178865 : isolate_, Handle<WasmInstanceObject>::null(), code_table, exp.index);
1590 : Handle<Code> wrapper_code = js_to_wasm_cache.CloneOrCompileJSToWasmWrapper(
1591 178865 : isolate_, module_, wasm_code, exp.index);
1592 178865 : export_wrappers->set(wrapper_index, *wrapper_code);
1593 178865 : RecordStats(*wrapper_code, counters());
1594 178865 : ++wrapper_index;
1595 : }
1596 147843 : return WasmModuleObject::New(isolate_, compiled_module);
1597 : }
1598 :
1599 154148 : InstanceBuilder::InstanceBuilder(
1600 : Isolate* isolate, ErrorThrower* thrower,
1601 : Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> ffi,
1602 : MaybeHandle<JSArrayBuffer> memory,
1603 : WeakCallbackInfo<void>::Callback instance_finalizer_callback)
1604 : : isolate_(isolate),
1605 154148 : module_(module_object->compiled_module()->module()),
1606 : async_counters_(isolate->async_counters()),
1607 : thrower_(thrower),
1608 : module_object_(module_object),
1609 : ffi_(ffi),
1610 : memory_(memory),
1611 616592 : instance_finalizer_callback_(instance_finalizer_callback) {
1612 308296 : sanitized_imports_.reserve(module_->import_table.size());
1613 154148 : }
1614 :
1615 : // Build an instance, in all of its glory.
1616 154148 : MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
1617 : // Check that an imports argument was provided, if the module requires it.
1618 : // No point in continuing otherwise.
1619 758001 : if (!module_->import_table.empty() && ffi_.is_null()) {
1620 : thrower_->TypeError(
1621 306860 : "Imports argument must be present and must be an object");
1622 99 : return {};
1623 : }
1624 :
1625 154049 : SanitizeImports();
1626 308098 : if (thrower_->error()) return {};
1627 :
1628 : // From here on, we expect the build pipeline to run without exiting to JS.
1629 : // Exception is when we run the startup function.
1630 460388 : DisallowJavascriptExecution no_js(isolate_);
1631 : // Record build time into correct bucket, then build instance.
1632 : TimedHistogramScope wasm_instantiate_module_time_scope(
1633 153863 : module_->is_wasm() ? counters()->wasm_instantiate_wasm_module_time()
1634 307726 : : counters()->wasm_instantiate_asm_module_time());
1635 153863 : Factory* factory = isolate_->factory();
1636 :
1637 : //--------------------------------------------------------------------------
1638 : // Reuse the compiled module (if no owner), otherwise clone.
1639 : //--------------------------------------------------------------------------
1640 : Handle<FixedArray> code_table;
1641 : Handle<FixedArray> wrapper_table;
1642 : // We keep around a copy of the old code table, because we'll be replacing
1643 : // imports for the new instance, and then we need the old imports to be
1644 : // able to relocate.
1645 : Handle<FixedArray> old_code_table;
1646 : MaybeHandle<WasmInstanceObject> owner;
1647 :
1648 : TRACE("Starting new module instantiation\n");
1649 : {
1650 : // Root the owner, if any, before doing any allocations, which
1651 : // may trigger GC.
1652 : // Both owner and original template need to be in sync. Even
1653 : // after we lose the original template handle, the code
1654 : // objects we copied from it have data relative to the
1655 : // instance - such as globals addresses.
1656 : Handle<WasmCompiledModule> original;
1657 : {
1658 : DisallowHeapAllocation no_gc;
1659 : original = handle(module_object_->compiled_module());
1660 153863 : if (original->has_weak_owning_instance()) {
1661 : owner = handle(WasmInstanceObject::cast(
1662 13250 : original->weak_owning_instance()->value()));
1663 : }
1664 : }
1665 : DCHECK(!original.is_null());
1666 153863 : if (original->has_weak_owning_instance()) {
1667 : // Clone, but don't insert yet the clone in the instances chain.
1668 : // We do that last. Since we are holding on to the owner instance,
1669 : // the owner + original state used for cloning and patching
1670 : // won't be mutated by possible finalizer runs.
1671 : DCHECK(!owner.is_null());
1672 : TRACE("Cloning from %d\n", original->instance_id());
1673 6625 : old_code_table = original->code_table();
1674 6625 : compiled_module_ = WasmCompiledModule::Clone(isolate_, original);
1675 6625 : code_table = compiled_module_->code_table();
1676 6625 : wrapper_table = compiled_module_->export_wrappers();
1677 : // Avoid creating too many handles in the outer scope.
1678 6625 : HandleScope scope(isolate_);
1679 :
1680 : // Clone the code for wasm functions and exports.
1681 54440 : for (int i = 0; i < code_table->length(); ++i) {
1682 20595 : Handle<Code> orig_code(Code::cast(code_table->get(i)), isolate_);
1683 20595 : switch (orig_code->kind()) {
1684 : case Code::WASM_TO_JS_FUNCTION:
1685 : // Imports will be overwritten with newly compiled wrappers.
1686 : break;
1687 : case Code::BUILTIN:
1688 : DCHECK_EQ(Builtins::kWasmCompileLazy, orig_code->builtin_index());
1689 : // If this code object has deoptimization data, then we need a
1690 : // unique copy to attach updated deoptimization data.
1691 3891 : if (orig_code->deoptimization_data()->length() > 0) {
1692 2416 : Handle<Code> code = factory->CopyCode(orig_code);
1693 : Handle<FixedArray> deopt_data =
1694 2416 : factory->NewFixedArray(2, TENURED);
1695 : deopt_data->set(1, Smi::FromInt(i));
1696 2416 : code->set_deoptimization_data(*deopt_data);
1697 2416 : code_table->set(i, *code);
1698 : }
1699 : break;
1700 : case Code::WASM_FUNCTION: {
1701 12113 : Handle<Code> code = factory->CopyCode(orig_code);
1702 12113 : code_table->set(i, *code);
1703 : break;
1704 : }
1705 : default:
1706 0 : UNREACHABLE();
1707 : }
1708 : }
1709 23145 : for (int i = 0; i < wrapper_table->length(); ++i) {
1710 8260 : Handle<Code> orig_code(Code::cast(wrapper_table->get(i)), isolate_);
1711 : DCHECK_EQ(orig_code->kind(), Code::JS_TO_WASM_FUNCTION);
1712 8260 : Handle<Code> code = factory->CopyCode(orig_code);
1713 8260 : wrapper_table->set(i, *code);
1714 : }
1715 :
1716 6625 : RecordStats(code_table, counters());
1717 6625 : RecordStats(wrapper_table, counters());
1718 : } else {
1719 : // There was no owner, so we can reuse the original.
1720 147238 : compiled_module_ = original;
1721 147238 : old_code_table = factory->CopyFixedArray(compiled_module_->code_table());
1722 147238 : code_table = compiled_module_->code_table();
1723 147238 : wrapper_table = compiled_module_->export_wrappers();
1724 : TRACE("Reusing existing instance %d\n", compiled_module_->instance_id());
1725 : }
1726 153863 : compiled_module_->set_native_context(isolate_->native_context());
1727 : }
1728 :
1729 : //--------------------------------------------------------------------------
1730 : // Allocate the instance object.
1731 : //--------------------------------------------------------------------------
1732 307726 : Zone instantiation_zone(isolate_->allocator(), ZONE_NAME);
1733 307726 : CodeSpecialization code_specialization(isolate_, &instantiation_zone);
1734 : Handle<WasmInstanceObject> instance =
1735 153863 : WasmInstanceObject::New(isolate_, compiled_module_);
1736 :
1737 : //--------------------------------------------------------------------------
1738 : // Set up the globals for the new instance.
1739 : //--------------------------------------------------------------------------
1740 : MaybeHandle<JSArrayBuffer> old_globals;
1741 153863 : uint32_t globals_size = module_->globals_size;
1742 153863 : if (globals_size > 0) {
1743 : const bool enable_guard_regions = false;
1744 : Handle<JSArrayBuffer> global_buffer =
1745 2995 : NewArrayBuffer(isolate_, globals_size, enable_guard_regions);
1746 2995 : globals_ = global_buffer;
1747 2995 : if (globals_.is_null()) {
1748 0 : thrower_->RangeError("Out of memory: wasm globals");
1749 0 : return {};
1750 : }
1751 : instance->wasm_context()->get()->globals_start =
1752 2995 : reinterpret_cast<byte*>(global_buffer->backing_store());
1753 2995 : instance->set_globals_buffer(*global_buffer);
1754 : }
1755 :
1756 : //--------------------------------------------------------------------------
1757 : // Prepare for initialization of function tables.
1758 : //--------------------------------------------------------------------------
1759 307726 : int function_table_count = static_cast<int>(module_->function_tables.size());
1760 155203 : table_instances_.reserve(module_->function_tables.size());
1761 155973 : for (int index = 0; index < function_table_count; ++index) {
1762 : table_instances_.push_back(
1763 : {Handle<WasmTableObject>::null(), Handle<FixedArray>::null(),
1764 4220 : Handle<FixedArray>::null(), Handle<FixedArray>::null()});
1765 : }
1766 :
1767 : //--------------------------------------------------------------------------
1768 : // Process the imports for the module.
1769 : //--------------------------------------------------------------------------
1770 153863 : int num_imported_functions = ProcessImports(code_table, instance);
1771 153863 : if (num_imported_functions < 0) return {};
1772 :
1773 : //--------------------------------------------------------------------------
1774 : // Process the initialization for the module's globals.
1775 : //--------------------------------------------------------------------------
1776 152914 : InitGlobals();
1777 :
1778 : //--------------------------------------------------------------------------
1779 : // Set up the indirect function tables for the new instance.
1780 : //--------------------------------------------------------------------------
1781 152914 : if (function_table_count > 0)
1782 1900 : InitializeTables(instance, &code_specialization);
1783 :
1784 : //--------------------------------------------------------------------------
1785 : // Set up the memory for the new instance.
1786 : //--------------------------------------------------------------------------
1787 152914 : uint32_t initial_pages = module_->initial_pages;
1788 : (module_->is_wasm() ? counters()->wasm_wasm_min_mem_pages_count()
1789 : : counters()->wasm_asm_min_mem_pages_count())
1790 458742 : ->AddSample(initial_pages);
1791 :
1792 152914 : if (!memory_.is_null()) {
1793 : Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
1794 : // Set externally passed ArrayBuffer non neuterable.
1795 : memory->set_is_neuterable(false);
1796 : memory->set_is_wasm_buffer(true);
1797 :
1798 : DCHECK_IMPLIES(trap_handler::UseTrapHandler(),
1799 : module_->is_asm_js() || memory->has_guard_region());
1800 150139 : } else if (initial_pages > 0) {
1801 2237 : memory_ = AllocateMemory(initial_pages);
1802 2237 : if (memory_.is_null()) return {}; // failed to allocate memory
1803 : }
1804 :
1805 : //--------------------------------------------------------------------------
1806 : // Check that indirect function table segments are within bounds.
1807 : //--------------------------------------------------------------------------
1808 459992 : for (WasmTableInit& table_init : module_->table_inits) {
1809 : DCHECK(table_init.table_index < table_instances_.size());
1810 1340 : uint32_t base = EvalUint32InitExpr(table_init.offset);
1811 : uint32_t table_size =
1812 2680 : table_instances_[table_init.table_index].function_table->length();
1813 2680 : if (!in_bounds(base, static_cast<uint32_t>(table_init.entries.size()),
1814 1340 : table_size)) {
1815 60 : thrower_->LinkError("table initializer is out of bounds");
1816 60 : return {};
1817 : }
1818 : }
1819 :
1820 : //--------------------------------------------------------------------------
1821 : // Check that memory segments are within bounds.
1822 : //--------------------------------------------------------------------------
1823 306346 : for (WasmDataSegment& seg : module_->data_segments) {
1824 790 : uint32_t base = EvalUint32InitExpr(seg.dest_addr);
1825 790 : uint32_t mem_size = 0;
1826 790 : if (!memory_.is_null()) {
1827 688 : CHECK(memory_.ToHandleChecked()->byte_length()->ToUint32(&mem_size));
1828 : }
1829 1580 : if (!in_bounds(base, seg.source.length(), mem_size)) {
1830 132 : thrower_->LinkError("data segment is out of bounds");
1831 132 : return {};
1832 : }
1833 : }
1834 :
1835 : //--------------------------------------------------------------------------
1836 : // Initialize memory.
1837 : //--------------------------------------------------------------------------
1838 : Address mem_start = nullptr;
1839 152712 : uint32_t mem_size = 0;
1840 152712 : if (!memory_.is_null()) {
1841 : Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
1842 : mem_start = static_cast<Address>(memory->backing_store());
1843 4906 : CHECK(memory->byte_length()->ToUint32(&mem_size));
1844 4906 : LoadDataSegments(mem_start, mem_size);
1845 : // Just like with globals, we need to keep both the JSArrayBuffer
1846 : // and save the start pointer.
1847 4906 : instance->set_memory_buffer(*memory);
1848 : }
1849 :
1850 : //--------------------------------------------------------------------------
1851 : // Create a memory object if there is not already one.
1852 : //--------------------------------------------------------------------------
1853 162738 : if (module_->has_memory && !instance->has_memory_object()) {
1854 : Handle<WasmMemoryObject> memory_object = WasmMemoryObject::New(
1855 : isolate_,
1856 : instance->has_memory_buffer() ? handle(instance->memory_buffer())
1857 : : Handle<JSArrayBuffer>::null(),
1858 26658 : module_->maximum_pages != 0 ? module_->maximum_pages : -1);
1859 8886 : instance->set_memory_object(*memory_object);
1860 : }
1861 :
1862 : // Set the WasmContext address in wrappers.
1863 : // TODO(wasm): the wasm context should only appear as a constant in wrappers;
1864 : // this code specialization is applied to the whole instance.
1865 : WasmContext* wasm_context = instance->wasm_context()->get();
1866 : Address wasm_context_address = reinterpret_cast<Address>(wasm_context);
1867 152712 : code_specialization.RelocateWasmContextReferences(wasm_context_address);
1868 : js_to_wasm_cache_.SetContextAddress(wasm_context_address);
1869 :
1870 : //--------------------------------------------------------------------------
1871 : // Set up the runtime support for the new instance.
1872 : //--------------------------------------------------------------------------
1873 152712 : Handle<WeakCell> weak_link = factory->NewWeakCell(instance);
1874 :
1875 515114 : for (int i = num_imported_functions + FLAG_skip_compiling_wasm_funcs,
1876 312519 : num_functions = static_cast<int>(module_->functions.size());
1877 : i < num_functions; ++i) {
1878 209690 : Handle<Code> code = handle(Code::cast(code_table->get(i)), isolate_);
1879 209690 : if (code->kind() == Code::WASM_FUNCTION) {
1880 186792 : Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED);
1881 186792 : deopt_data->set(0, *weak_link);
1882 : deopt_data->set(1, Smi::FromInt(i));
1883 186792 : code->set_deoptimization_data(*deopt_data);
1884 : continue;
1885 : }
1886 : DCHECK_EQ(Builtins::kWasmCompileLazy, code->builtin_index());
1887 : int deopt_len = code->deoptimization_data()->length();
1888 22898 : if (deopt_len == 0) continue;
1889 : DCHECK_LE(2, deopt_len);
1890 : DCHECK_EQ(i, Smi::ToInt(code->deoptimization_data()->get(1)));
1891 8395 : code->deoptimization_data()->set(0, *weak_link);
1892 : // Entries [2, deopt_len) encode information about table exports of this
1893 : // function. This is rebuilt in {LoadTableSegments}, so reset it here.
1894 8415 : for (int i = 2; i < deopt_len; ++i) {
1895 20 : code->deoptimization_data()->set_undefined(isolate_, i);
1896 : }
1897 : }
1898 :
1899 : //--------------------------------------------------------------------------
1900 : // Set up the exports object for the new instance.
1901 : //--------------------------------------------------------------------------
1902 152712 : ProcessExports(instance, compiled_module_);
1903 305424 : if (thrower_->error()) return {};
1904 :
1905 : //--------------------------------------------------------------------------
1906 : // Add instance to Memory object
1907 : //--------------------------------------------------------------------------
1908 152662 : if (instance->has_memory_object()) {
1909 9996 : Handle<WasmMemoryObject> memory(instance->memory_object(), isolate_);
1910 9996 : WasmMemoryObject::AddInstance(isolate_, memory, instance);
1911 : }
1912 :
1913 : //--------------------------------------------------------------------------
1914 : // Initialize the indirect function tables.
1915 : //--------------------------------------------------------------------------
1916 152662 : if (function_table_count > 0) LoadTableSegments(code_table, instance);
1917 :
1918 : // Patch all code with the relocations registered in code_specialization.
1919 152662 : code_specialization.RelocateDirectCalls(instance);
1920 152662 : code_specialization.ApplyToWholeInstance(*instance, SKIP_ICACHE_FLUSH);
1921 :
1922 152662 : FlushICache(isolate_, code_table);
1923 152662 : FlushICache(isolate_, wrapper_table);
1924 :
1925 : //--------------------------------------------------------------------------
1926 : // Unpack and notify signal handler of protected instructions.
1927 : //--------------------------------------------------------------------------
1928 152662 : if (trap_handler::UseTrapHandler()) {
1929 15314 : UnpackAndRegisterProtectedInstructions(isolate_, code_table);
1930 : }
1931 :
1932 : //--------------------------------------------------------------------------
1933 : // Set up and link the new instance.
1934 : //--------------------------------------------------------------------------
1935 : {
1936 : Handle<Object> global_handle =
1937 152662 : isolate_->global_handles()->Create(*instance);
1938 152662 : Handle<WeakCell> link_to_clone = factory->NewWeakCell(compiled_module_);
1939 152662 : Handle<WeakCell> link_to_owning_instance = factory->NewWeakCell(instance);
1940 : MaybeHandle<WeakCell> link_to_original;
1941 : MaybeHandle<WasmCompiledModule> original;
1942 152662 : if (!owner.is_null()) {
1943 : // prepare the data needed for publishing in a chain, but don't link
1944 : // just yet, because
1945 : // we want all the publishing to happen free from GC interruptions, and
1946 : // so we do it in
1947 : // one GC-free scope afterwards.
1948 : original = handle(owner.ToHandleChecked()->compiled_module());
1949 6625 : link_to_original = factory->NewWeakCell(original.ToHandleChecked());
1950 : }
1951 : // Publish the new instance to the instances chain.
1952 : {
1953 : DisallowHeapAllocation no_gc;
1954 152662 : if (!link_to_original.is_null()) {
1955 : compiled_module_->set_weak_next_instance(
1956 : link_to_original.ToHandleChecked());
1957 : original.ToHandleChecked()->set_weak_prev_instance(link_to_clone);
1958 : compiled_module_->set_weak_wasm_module(
1959 6625 : original.ToHandleChecked()->weak_wasm_module());
1960 : }
1961 152662 : module_object_->set_compiled_module(*compiled_module_);
1962 : compiled_module_->set_weak_owning_instance(link_to_owning_instance);
1963 : GlobalHandles::MakeWeak(
1964 : global_handle.location(), global_handle.location(),
1965 152662 : instance_finalizer_callback_, v8::WeakCallbackType::kFinalizer);
1966 : }
1967 : }
1968 :
1969 : //--------------------------------------------------------------------------
1970 : // Debugging support.
1971 : //--------------------------------------------------------------------------
1972 : // Set all breakpoints that were set on the shared module.
1973 : WasmSharedModuleData::SetBreakpointsOnNewInstance(compiled_module_->shared(),
1974 152662 : instance);
1975 :
1976 153448 : if (FLAG_wasm_interpret_all && module_->is_wasm()) {
1977 : Handle<WasmDebugInfo> debug_info =
1978 776 : WasmInstanceObject::GetOrCreateDebugInfo(instance);
1979 : std::vector<int> func_indexes;
1980 4208 : for (int func_index = num_imported_functions,
1981 1552 : num_wasm_functions = static_cast<int>(module_->functions.size());
1982 1716 : func_index < num_wasm_functions; ++func_index) {
1983 940 : func_indexes.push_back(func_index);
1984 : }
1985 : WasmDebugInfo::RedirectToInterpreter(
1986 : debug_info, Vector<int>(func_indexes.data(),
1987 2328 : static_cast<int>(func_indexes.size())));
1988 : }
1989 :
1990 : //--------------------------------------------------------------------------
1991 : // Run the start function if one was specified.
1992 : //--------------------------------------------------------------------------
1993 152662 : if (module_->start_function_index >= 0) {
1994 6319 : HandleScope scope(isolate_);
1995 6319 : int start_index = module_->start_function_index;
1996 : Handle<Code> startup_code = EnsureExportedLazyDeoptData(
1997 6319 : isolate_, instance, code_table, start_index);
1998 18957 : FunctionSig* sig = module_->functions[start_index].sig;
1999 : Handle<Code> wrapper_code = js_to_wasm_cache_.CloneOrCompileJSToWasmWrapper(
2000 6319 : isolate_, module_, startup_code, start_index);
2001 : Handle<WasmExportedFunction> startup_fct = WasmExportedFunction::New(
2002 : isolate_, instance, MaybeHandle<String>(), start_index,
2003 12638 : static_cast<int>(sig->parameter_count()), wrapper_code);
2004 6319 : RecordStats(*startup_code, counters());
2005 : // Call the JS function.
2006 : Handle<Object> undefined = factory->undefined_value();
2007 : {
2008 : // We're OK with JS execution here. The instance is fully setup.
2009 6319 : AllowJavascriptExecution allow_js(isolate_);
2010 : MaybeHandle<Object> retval =
2011 6319 : Execution::Call(isolate_, startup_fct, undefined, 0, nullptr);
2012 :
2013 6319 : if (retval.is_null()) {
2014 : DCHECK(isolate_->has_pending_exception());
2015 : // It's unfortunate that the new instance is already linked in the
2016 : // chain. However, we need to set up everything before executing the
2017 : // startup unction, such that stack trace information can be generated
2018 : // correctly already in the start function.
2019 46 : return {};
2020 6273 : }
2021 : }
2022 : }
2023 :
2024 : DCHECK(!isolate_->has_pending_exception());
2025 : TRACE("Finishing instance %d\n", compiled_module_->instance_id());
2026 152616 : TRACE_CHAIN(module_object_->compiled_module());
2027 460342 : return instance;
2028 : }
2029 :
2030 : // Look up an import value in the {ffi_} object.
2031 142324 : MaybeHandle<Object> InstanceBuilder::LookupImport(uint32_t index,
2032 : Handle<String> module_name,
2033 :
2034 : Handle<String> import_name) {
2035 : // We pre-validated in the js-api layer that the ffi object is present, and
2036 : // a JSObject, if the module has imports.
2037 : DCHECK(!ffi_.is_null());
2038 :
2039 : // Look up the module first.
2040 : MaybeHandle<Object> result =
2041 142324 : Object::GetPropertyOrElement(ffi_.ToHandleChecked(), module_name);
2042 142324 : if (result.is_null()) {
2043 0 : return ReportTypeError("module not found", index, module_name);
2044 : }
2045 :
2046 : Handle<Object> module = result.ToHandleChecked();
2047 :
2048 : // Look up the value in the module.
2049 142324 : if (!module->IsJSReceiver()) {
2050 : return ReportTypeError("module is not an object or function", index,
2051 160 : module_name);
2052 : }
2053 :
2054 142164 : result = Object::GetPropertyOrElement(module, import_name);
2055 142164 : if (result.is_null()) {
2056 0 : ReportLinkError("import not found", index, module_name, import_name);
2057 0 : return MaybeHandle<JSFunction>();
2058 : }
2059 :
2060 142164 : return result;
2061 : }
2062 :
2063 : // Look up an import value in the {ffi_} object specifically for linking an
2064 : // asm.js module. This only performs non-observable lookups, which allows
2065 : // falling back to JavaScript proper (and hence re-executing all lookups) if
2066 : // module instantiation fails.
2067 5921 : MaybeHandle<Object> InstanceBuilder::LookupImportAsm(
2068 : uint32_t index, Handle<String> import_name) {
2069 : // Check that a foreign function interface object was provided.
2070 5921 : if (ffi_.is_null()) {
2071 0 : return ReportLinkError("missing imports object", index, import_name);
2072 : }
2073 :
2074 : // Perform lookup of the given {import_name} without causing any observable
2075 : // side-effect. We only accept accesses that resolve to data properties,
2076 : // which is indicated by the asm.js spec in section 7 ("Linking") as well.
2077 : Handle<Object> result;
2078 : LookupIterator it = LookupIterator::PropertyOrElement(
2079 5921 : isolate_, ffi_.ToHandleChecked(), import_name);
2080 5921 : switch (it.state()) {
2081 : case LookupIterator::ACCESS_CHECK:
2082 : case LookupIterator::INTEGER_INDEXED_EXOTIC:
2083 : case LookupIterator::INTERCEPTOR:
2084 : case LookupIterator::JSPROXY:
2085 : case LookupIterator::ACCESSOR:
2086 : case LookupIterator::TRANSITION:
2087 26 : return ReportLinkError("not a data property", index, import_name);
2088 : case LookupIterator::NOT_FOUND:
2089 : // Accepting missing properties as undefined does not cause any
2090 : // observable difference from JavaScript semantics, we are lenient.
2091 90 : result = isolate_->factory()->undefined_value();
2092 90 : break;
2093 : case LookupIterator::DATA:
2094 5805 : result = it.GetDataValue();
2095 5805 : break;
2096 : }
2097 :
2098 5895 : return result;
2099 : }
2100 :
2101 3962 : uint32_t InstanceBuilder::EvalUint32InitExpr(const WasmInitExpr& expr) {
2102 3962 : switch (expr.kind) {
2103 : case WasmInitExpr::kI32Const:
2104 2612 : return expr.val.i32_const;
2105 : case WasmInitExpr::kGlobalIndex: {
2106 2700 : uint32_t offset = module_->globals[expr.val.global_index].offset;
2107 2700 : return *reinterpret_cast<uint32_t*>(raw_buffer_ptr(globals_, offset));
2108 : }
2109 : default:
2110 0 : UNREACHABLE();
2111 : }
2112 : }
2113 :
2114 : // Load data segments into the memory.
2115 4906 : void InstanceBuilder::LoadDataSegments(Address mem_addr, size_t mem_size) {
2116 : Handle<SeqOneByteString> module_bytes(compiled_module_->module_bytes(),
2117 4906 : isolate_);
2118 15300 : for (const WasmDataSegment& segment : module_->data_segments) {
2119 1154 : uint32_t source_size = segment.source.length();
2120 : // Segments of size == 0 are just nops.
2121 582 : if (source_size == 0) continue;
2122 572 : uint32_t dest_offset = EvalUint32InitExpr(segment.dest_addr);
2123 : DCHECK(
2124 : in_bounds(dest_offset, source_size, static_cast<uint32_t>(mem_size)));
2125 572 : byte* dest = mem_addr + dest_offset;
2126 : const byte* src = reinterpret_cast<const byte*>(
2127 1144 : module_bytes->GetCharsAddress() + segment.source.offset());
2128 572 : memcpy(dest, src, source_size);
2129 : }
2130 4906 : }
2131 :
2132 4930 : void InstanceBuilder::WriteGlobalValue(WasmGlobal& global,
2133 : Handle<Object> value) {
2134 : double num = value->Number();
2135 : TRACE("init [globals_start=%p + %u] = %lf, type = %s\n",
2136 : reinterpret_cast<void*>(raw_buffer_ptr(globals_, 0)), global.offset,
2137 : num, WasmOpcodes::TypeName(global.type));
2138 2465 : switch (global.type) {
2139 : case kWasmI32:
2140 1955 : *GetRawGlobalPtr<int32_t>(global) = static_cast<int32_t>(num);
2141 1955 : break;
2142 : case kWasmI64:
2143 : // TODO(titzer): initialization of imported i64 globals.
2144 0 : UNREACHABLE();
2145 : break;
2146 : case kWasmF32:
2147 50 : *GetRawGlobalPtr<float>(global) = static_cast<float>(num);
2148 50 : break;
2149 : case kWasmF64:
2150 460 : *GetRawGlobalPtr<double>(global) = static_cast<double>(num);
2151 460 : break;
2152 : default:
2153 0 : UNREACHABLE();
2154 : }
2155 2465 : }
2156 :
2157 154049 : void InstanceBuilder::SanitizeImports() {
2158 : Handle<SeqOneByteString> module_bytes(
2159 : module_object_->compiled_module()->module_bytes());
2160 906324 : for (size_t index = 0; index < module_->import_table.size(); ++index) {
2161 450353 : WasmImport& import = module_->import_table[index];
2162 :
2163 : Handle<String> module_name;
2164 : MaybeHandle<String> maybe_module_name =
2165 : WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
2166 148245 : isolate_, module_bytes, import.module_name);
2167 148245 : if (!maybe_module_name.ToHandle(&module_name)) {
2168 : thrower_->LinkError("Could not resolve module name for import %zu",
2169 148245 : index);
2170 0 : return;
2171 : }
2172 :
2173 : Handle<String> import_name;
2174 : MaybeHandle<String> maybe_import_name =
2175 : WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
2176 148245 : isolate_, module_bytes, import.field_name);
2177 148245 : if (!maybe_import_name.ToHandle(&import_name)) {
2178 : thrower_->LinkError("Could not resolve import name for import %zu",
2179 0 : index);
2180 0 : return;
2181 : }
2182 :
2183 : int int_index = static_cast<int>(index);
2184 : MaybeHandle<Object> result =
2185 148245 : module_->is_asm_js()
2186 5921 : ? LookupImportAsm(int_index, import_name)
2187 154166 : : LookupImport(int_index, module_name, import_name);
2188 296490 : if (thrower_->error()) {
2189 186 : thrower_->LinkError("Could not find value for import %zu", index);
2190 186 : return;
2191 : }
2192 : Handle<Object> value = result.ToHandleChecked();
2193 296118 : sanitized_imports_.push_back({module_name, import_name, value});
2194 : }
2195 : }
2196 :
2197 153863 : Handle<FixedArray> InstanceBuilder::SetupWasmToJSImportsTable(
2198 : Handle<WasmInstanceObject> instance) {
2199 : // The js_imports_table is set up so that index 0 has isolate->native_context
2200 : // and for every index, 3*index+1 has the JSReceiver, 3*index+2 has function's
2201 : // global proxy and 3*index+3 has function's context. Hence, the fixed array's
2202 : // size is 3*import_table.size+1.
2203 307726 : int size = static_cast<int>(module_->import_table.size());
2204 153863 : CHECK_LE(size, (kMaxInt - 1) / 3);
2205 : Handle<FixedArray> func_table =
2206 307726 : isolate_->factory()->NewFixedArray(3 * size + 1, TENURED);
2207 : Handle<FixedArray> js_imports_table =
2208 153863 : isolate_->global_handles()->Create(*func_table);
2209 : GlobalHandles::MakeWeak(
2210 : reinterpret_cast<Object**>(js_imports_table.location()),
2211 : js_imports_table.location(), &FunctionTableFinalizer,
2212 153863 : v8::WeakCallbackType::kFinalizer);
2213 153863 : instance->set_js_imports_table(*func_table);
2214 307726 : js_imports_table->set(0, *isolate_->native_context());
2215 153863 : return js_imports_table;
2216 : }
2217 :
2218 : // Process the imports, including functions, tables, globals, and memory, in
2219 : // order, loading them from the {ffi_} object. Returns the number of imported
2220 : // functions.
2221 153863 : int InstanceBuilder::ProcessImports(Handle<FixedArray> code_table,
2222 : Handle<WasmInstanceObject> instance) {
2223 : int num_imported_functions = 0;
2224 : int num_imported_tables = 0;
2225 153863 : Handle<FixedArray> js_imports_table = SetupWasmToJSImportsTable(instance);
2226 153863 : WasmInstanceMap imported_wasm_instances(isolate_->heap());
2227 : DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
2228 902919 : for (int index = 0; index < static_cast<int>(module_->import_table.size());
2229 : ++index) {
2230 594421 : WasmImport& import = module_->import_table[index];
2231 :
2232 296118 : Handle<String> module_name = sanitized_imports_[index].module_name;
2233 148059 : Handle<String> import_name = sanitized_imports_[index].import_name;
2234 148059 : Handle<Object> value = sanitized_imports_[index].value;
2235 :
2236 148059 : switch (import.kind) {
2237 : case kExternalFunction: {
2238 : // Function imports must be callable.
2239 142985 : if (!value->IsCallable()) {
2240 : ReportLinkError("function import requires a callable", index,
2241 190 : module_name, import_name);
2242 190 : return -1;
2243 : }
2244 :
2245 : Handle<Code> import_code = UnwrapExportOrCompileImportWrapper(
2246 142795 : isolate_, module_->functions[import.index].sig,
2247 142795 : Handle<JSReceiver>::cast(value), index, module_->origin(),
2248 285590 : &imported_wasm_instances, js_imports_table, instance);
2249 142795 : if (import_code.is_null()) {
2250 : ReportLinkError("imported function does not match the expected type",
2251 220 : index, module_name, import_name);
2252 220 : return -1;
2253 : }
2254 142575 : code_table->set(num_imported_functions, *import_code);
2255 142575 : RecordStats(*import_code, counters());
2256 142575 : num_imported_functions++;
2257 : break;
2258 : }
2259 : case kExternalTable: {
2260 1090 : if (!value->IsWasmTableObject()) {
2261 : ReportLinkError("table import requires a WebAssembly.Table", index,
2262 70 : module_name, import_name);
2263 70 : return -1;
2264 : }
2265 : WasmIndirectFunctionTable& table =
2266 1020 : module_->function_tables[num_imported_tables];
2267 1020 : TableInstance& table_instance = table_instances_[num_imported_tables];
2268 1020 : table_instance.table_object = Handle<WasmTableObject>::cast(value);
2269 : table_instance.js_wrappers = Handle<FixedArray>(
2270 2040 : table_instance.table_object->functions(), isolate_);
2271 :
2272 : int imported_cur_size = table_instance.js_wrappers->length();
2273 1020 : if (imported_cur_size < static_cast<int>(table.initial_size)) {
2274 : thrower_->LinkError(
2275 : "table import %d is smaller than initial %d, got %u", index,
2276 50 : table.initial_size, imported_cur_size);
2277 50 : return -1;
2278 : }
2279 :
2280 970 : if (table.has_maximum_size) {
2281 : int64_t imported_maximum_size =
2282 820 : table_instance.table_object->maximum_length()->Number();
2283 820 : if (imported_maximum_size < 0) {
2284 : thrower_->LinkError(
2285 : "table import %d has no maximum length, expected %d", index,
2286 10 : table.maximum_size);
2287 10 : return -1;
2288 : }
2289 810 : if (imported_maximum_size > table.maximum_size) {
2290 : thrower_->LinkError(
2291 : " table import %d has a larger maximum size %" PRIx64
2292 : " than the module's declared maximum %u",
2293 70 : index, imported_maximum_size, table.maximum_size);
2294 70 : return -1;
2295 : }
2296 : }
2297 :
2298 : // Allocate a new dispatch table and signature table.
2299 : int table_size = imported_cur_size;
2300 : table_instance.function_table =
2301 890 : isolate_->factory()->NewFixedArray(table_size);
2302 : table_instance.signature_table =
2303 890 : isolate_->factory()->NewFixedArray(table_size);
2304 2629960 : for (int i = 0; i < table_size; ++i) {
2305 : table_instance.signature_table->set(i,
2306 : Smi::FromInt(kInvalidSigIndex));
2307 : }
2308 : // Initialize the dispatch table with the (foreign) JS functions
2309 : // that are already in the table.
2310 2629070 : for (int i = 0; i < table_size; ++i) {
2311 2629070 : Handle<Object> val(table_instance.js_wrappers->get(i), isolate_);
2312 5255520 : if (!val->IsJSFunction()) continue;
2313 2620 : if (!WasmExportedFunction::IsWasmExportedFunction(*val)) {
2314 : thrower_->LinkError("table import %d[%d] is not a wasm function",
2315 0 : index, i);
2316 0 : return -1;
2317 : }
2318 : // Look up the signature's canonical id. If there is no canonical
2319 : // id, then the signature does not appear at all in this module,
2320 : // so putting {-1} in the table will cause checks to always fail.
2321 2620 : auto target = Handle<WasmExportedFunction>::cast(val);
2322 2620 : FunctionSig* sig = nullptr;
2323 : Handle<Code> code =
2324 : MakeWasmToWasmWrapper(isolate_, target, nullptr, &sig,
2325 2620 : &imported_wasm_instances, instance);
2326 2620 : int sig_index = module_->signature_map.Find(sig);
2327 : table_instance.signature_table->set(i, Smi::FromInt(sig_index));
2328 2620 : table_instance.function_table->set(i, *code);
2329 : }
2330 :
2331 890 : num_imported_tables++;
2332 890 : break;
2333 : }
2334 : case kExternalMemory: {
2335 : // Validation should have failed if more than one memory object was
2336 : // provided.
2337 : DCHECK(!instance->has_memory_object());
2338 1390 : if (!value->IsWasmMemoryObject()) {
2339 : ReportLinkError("memory import must be a WebAssembly.Memory object",
2340 130 : index, module_name, import_name);
2341 130 : return -1;
2342 : }
2343 : auto memory = Handle<WasmMemoryObject>::cast(value);
2344 1260 : instance->set_memory_object(*memory);
2345 1260 : Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate_);
2346 1260 : memory_ = buffer;
2347 : uint32_t imported_cur_pages = static_cast<uint32_t>(
2348 1260 : buffer->byte_length()->Number() / WasmModule::kPageSize);
2349 1260 : if (imported_cur_pages < module_->initial_pages) {
2350 : thrower_->LinkError(
2351 : "memory import %d is smaller than initial %u, got %u", index,
2352 30 : module_->initial_pages, imported_cur_pages);
2353 : }
2354 : int32_t imported_maximum_pages = memory->maximum_pages();
2355 1260 : if (module_->has_maximum_pages) {
2356 450 : if (imported_maximum_pages < 0) {
2357 : thrower_->LinkError(
2358 : "memory import %d has no maximum limit, expected at most %u",
2359 10 : index, imported_maximum_pages);
2360 10 : return -1;
2361 : }
2362 440 : if (static_cast<uint32_t>(imported_maximum_pages) >
2363 : module_->maximum_pages) {
2364 : thrower_->LinkError(
2365 : "memory import %d has a larger maximum size %u than the "
2366 : "module's declared maximum %u",
2367 50 : index, imported_maximum_pages, module_->maximum_pages);
2368 50 : return -1;
2369 : }
2370 : }
2371 2400 : if (module_->has_shared_memory != buffer->is_shared()) {
2372 : thrower_->LinkError(
2373 : "mismatch in shared state of memory, declared = %d, imported = "
2374 : "%d",
2375 20 : module_->has_shared_memory, buffer->is_shared());
2376 20 : return -1;
2377 : }
2378 :
2379 : break;
2380 : }
2381 : case kExternalGlobal: {
2382 : // Global imports are converted to numbers and written into the
2383 : // {globals_} array buffer.
2384 9218 : if (module_->globals[import.index].type == kWasmI64) {
2385 : ReportLinkError("global import cannot have type i64", index,
2386 0 : module_name, import_name);
2387 0 : return -1;
2388 : }
2389 2594 : if (module_->is_asm_js()) {
2390 : // Accepting {JSFunction} on top of just primitive values here is a
2391 : // workaround to support legacy asm.js code with broken binding. Note
2392 : // that using {NaN} (or Smi::kZero) here is what using the observable
2393 : // conversion via {ToPrimitive} would produce as well.
2394 : // TODO(mstarzinger): Still observable if Function.prototype.valueOf
2395 : // or friends are patched, we might need to check for that as well.
2396 1584 : if (value->IsJSFunction()) value = isolate_->factory()->nan_value();
2397 3155 : if (value->IsPrimitive() && !value->IsSymbol()) {
2398 3130 : if (module_->globals[import.index].type == kWasmI32) {
2399 1145 : value = Object::ToInt32(isolate_, value).ToHandleChecked();
2400 : } else {
2401 840 : value = Object::ToNumber(value).ToHandleChecked();
2402 : }
2403 : }
2404 : }
2405 2594 : if (!value->IsNumber()) {
2406 : ReportLinkError("global import must be a number", index, module_name,
2407 129 : import_name);
2408 129 : return -1;
2409 : }
2410 4930 : WriteGlobalValue(module_->globals[import.index], value);
2411 2465 : break;
2412 : }
2413 : default:
2414 0 : UNREACHABLE();
2415 : break;
2416 : }
2417 : }
2418 :
2419 152914 : if (!imported_wasm_instances.empty()) {
2420 131625 : WasmInstanceMap::IteratableScope iteratable_scope(&imported_wasm_instances);
2421 : Handle<FixedArray> instances_array = isolate_->factory()->NewFixedArray(
2422 131625 : imported_wasm_instances.size(), TENURED);
2423 131625 : instance->set_directly_called_instances(*instances_array);
2424 : int index = 0;
2425 264410 : for (auto it = iteratable_scope.begin(), end = iteratable_scope.end();
2426 : it != end; ++it, ++index) {
2427 132785 : instances_array->set(index, ***it);
2428 131625 : }
2429 : }
2430 :
2431 152914 : return num_imported_functions;
2432 : }
2433 :
2434 : template <typename T>
2435 : T* InstanceBuilder::GetRawGlobalPtr(WasmGlobal& global) {
2436 19340 : return reinterpret_cast<T*>(raw_buffer_ptr(globals_, global.offset));
2437 : }
2438 :
2439 : // Process initialization of globals.
2440 152914 : void InstanceBuilder::InitGlobals() {
2441 468182 : for (auto global : module_->globals) {
2442 9440 : switch (global.init.kind) {
2443 : case WasmInitExpr::kI32Const:
2444 5701 : *GetRawGlobalPtr<int32_t>(global) = global.init.val.i32_const;
2445 5701 : break;
2446 : case WasmInitExpr::kI64Const:
2447 50 : *GetRawGlobalPtr<int64_t>(global) = global.init.val.i64_const;
2448 50 : break;
2449 : case WasmInitExpr::kF32Const:
2450 166 : *GetRawGlobalPtr<float>(global) = global.init.val.f32_const;
2451 166 : break;
2452 : case WasmInitExpr::kF64Const:
2453 998 : *GetRawGlobalPtr<double>(global) = global.init.val.f64_const;
2454 998 : break;
2455 : case WasmInitExpr::kGlobalIndex: {
2456 : // Initialize with another global.
2457 : uint32_t new_offset = global.offset;
2458 : uint32_t old_offset =
2459 120 : module_->globals[global.init.val.global_index].offset;
2460 : TRACE("init [globals+%u] = [globals+%d]\n", global.offset, old_offset);
2461 60 : size_t size = (global.type == kWasmI64 || global.type == kWasmF64)
2462 : ? sizeof(double)
2463 60 : : sizeof(int32_t);
2464 180 : memcpy(raw_buffer_ptr(globals_, new_offset),
2465 180 : raw_buffer_ptr(globals_, old_offset), size);
2466 60 : break;
2467 : }
2468 : case WasmInitExpr::kNone:
2469 : // Happens with imported globals.
2470 : break;
2471 : default:
2472 0 : UNREACHABLE();
2473 : break;
2474 : }
2475 : }
2476 152914 : }
2477 :
2478 : // Allocate memory for a module instance as a new JSArrayBuffer.
2479 2237 : Handle<JSArrayBuffer> InstanceBuilder::AllocateMemory(uint32_t num_pages) {
2480 2237 : if (num_pages > FLAG_wasm_max_mem_pages) {
2481 0 : thrower_->RangeError("Out of memory: wasm memory too large");
2482 : return Handle<JSArrayBuffer>::null();
2483 : }
2484 : const bool enable_guard_regions = trap_handler::UseTrapHandler();
2485 : Handle<JSArrayBuffer> mem_buffer = NewArrayBuffer(
2486 2237 : isolate_, num_pages * WasmModule::kPageSize, enable_guard_regions);
2487 :
2488 2237 : if (mem_buffer.is_null()) {
2489 10 : thrower_->RangeError("Out of memory: wasm memory");
2490 : }
2491 2237 : return mem_buffer;
2492 : }
2493 :
2494 152712 : bool InstanceBuilder::NeedsWrappers() const {
2495 152712 : if (module_->num_exported_functions > 0) return true;
2496 4204 : for (auto& table_instance : table_instances_) {
2497 620 : if (!table_instance.js_wrappers.is_null()) return true;
2498 : }
2499 3284 : for (auto& table : module_->function_tables) {
2500 320 : if (table.exported) return true;
2501 : }
2502 : return false;
2503 : }
2504 :
2505 : // Process the exports, creating wrappers for functions, tables, memories,
2506 : // and globals.
2507 152712 : void InstanceBuilder::ProcessExports(
2508 : Handle<WasmInstanceObject> instance,
2509 : Handle<WasmCompiledModule> compiled_module) {
2510 152712 : Handle<FixedArray> wrapper_table = compiled_module->export_wrappers();
2511 152712 : if (NeedsWrappers()) {
2512 : // Fill the table to cache the exported JSFunction wrappers.
2513 : js_wrappers_.insert(js_wrappers_.begin(), module_->functions.size(),
2514 1848285 : Handle<JSFunction>::null());
2515 : }
2516 :
2517 : Handle<JSObject> exports_object;
2518 305424 : if (module_->is_wasm()) {
2519 : // Create the "exports" object.
2520 146523 : exports_object = isolate_->factory()->NewJSObjectWithNullProto();
2521 6189 : } else if (module_->is_asm_js()) {
2522 : Handle<JSFunction> object_function = Handle<JSFunction>(
2523 12378 : isolate_->native_context()->object_function(), isolate_);
2524 6189 : exports_object = isolate_->factory()->NewJSObject(object_function);
2525 : } else {
2526 0 : UNREACHABLE();
2527 : }
2528 152712 : instance->set_exports_object(*exports_object);
2529 :
2530 : Handle<String> single_function_name =
2531 152712 : isolate_->factory()->InternalizeUtf8String(AsmJs::kSingleFunctionName);
2532 :
2533 : PropertyDescriptor desc;
2534 152712 : desc.set_writable(module_->is_asm_js());
2535 : desc.set_enumerable(true);
2536 : desc.set_configurable(module_->is_asm_js());
2537 :
2538 : // Store weak references to all exported functions.
2539 : Handle<FixedArray> weak_exported_functions;
2540 152712 : if (compiled_module->has_weak_exported_functions()) {
2541 232 : weak_exported_functions = compiled_module->weak_exported_functions();
2542 : } else {
2543 : int export_count = 0;
2544 646091 : for (WasmExport& exp : module_->export_table) {
2545 188651 : if (exp.kind == kExternalFunction) ++export_count;
2546 : }
2547 152480 : weak_exported_functions = isolate_->factory()->NewFixedArray(export_count);
2548 : compiled_module->set_weak_exported_functions(weak_exported_functions);
2549 : }
2550 :
2551 : // Process each export in the export table.
2552 : int export_index = 0; // Index into {weak_exported_functions}.
2553 647079 : for (WasmExport& exp : module_->export_table) {
2554 : Handle<String> name = WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
2555 188963 : isolate_, compiled_module_, exp.name)
2556 377926 : .ToHandleChecked();
2557 : Handle<JSObject> export_to;
2558 388290 : if (module_->is_asm_js() && exp.kind == kExternalFunction &&
2559 10364 : String::Equals(name, single_function_name)) {
2560 : export_to = instance;
2561 : } else {
2562 : export_to = exports_object;
2563 : }
2564 :
2565 188963 : switch (exp.kind) {
2566 : case kExternalFunction: {
2567 : // Wrap and export the code as a JSFunction.
2568 186853 : WasmFunction& function = module_->functions[exp.index];
2569 186853 : Handle<JSFunction> js_function = js_wrappers_[exp.index];
2570 186853 : if (js_function.is_null()) {
2571 : // Wrap the exported code as a JSFunction.
2572 : Handle<Code> export_code =
2573 373330 : wrapper_table->GetValueChecked<Code>(isolate_, export_index);
2574 : MaybeHandle<String> func_name;
2575 373330 : if (module_->is_asm_js()) {
2576 : // For modules arising from asm.js, honor the names section.
2577 : func_name = WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
2578 10336 : isolate_, compiled_module_, function.name)
2579 20672 : .ToHandleChecked();
2580 : }
2581 : js_function = WasmExportedFunction::New(
2582 : isolate_, instance, func_name, function.func_index,
2583 186665 : static_cast<int>(function.sig->parameter_count()), export_code);
2584 373330 : js_wrappers_[exp.index] = js_function;
2585 : }
2586 : desc.set_value(js_function);
2587 : Handle<WeakCell> weak_export =
2588 186853 : isolate_->factory()->NewWeakCell(js_function);
2589 : DCHECK_GT(weak_exported_functions->length(), export_index);
2590 186853 : weak_exported_functions->set(export_index, *weak_export);
2591 186853 : export_index++;
2592 : break;
2593 : }
2594 : case kExternalTable: {
2595 : // Export a table as a WebAssembly.Table object.
2596 500 : TableInstance& table_instance = table_instances_[exp.index];
2597 500 : WasmIndirectFunctionTable& table = module_->function_tables[exp.index];
2598 500 : if (table_instance.table_object.is_null()) {
2599 : uint32_t maximum = table.has_maximum_size ? table.maximum_size
2600 440 : : FLAG_wasm_max_table_size;
2601 : table_instance.table_object =
2602 : WasmTableObject::New(isolate_, table.initial_size, maximum,
2603 440 : &table_instance.js_wrappers);
2604 : }
2605 : desc.set_value(table_instance.table_object);
2606 500 : break;
2607 : }
2608 : case kExternalMemory: {
2609 : // Export the memory as a WebAssembly.Memory object. A WasmMemoryObject
2610 : // should already be available if the module has memory, since we always
2611 : // create or import it when building an WasmInstanceObject.
2612 : DCHECK(instance->has_memory_object());
2613 : desc.set_value(
2614 1300 : Handle<WasmMemoryObject>(instance->memory_object(), isolate_));
2615 1300 : break;
2616 : }
2617 : case kExternalGlobal: {
2618 : // Export the value of the global variable as a number.
2619 600 : WasmGlobal& global = module_->globals[exp.index];
2620 : double num = 0;
2621 310 : switch (global.type) {
2622 : case kWasmI32:
2623 200 : num = *GetRawGlobalPtr<int32_t>(global);
2624 200 : break;
2625 : case kWasmF32:
2626 50 : num = *GetRawGlobalPtr<float>(global);
2627 50 : break;
2628 : case kWasmF64:
2629 40 : num = *GetRawGlobalPtr<double>(global);
2630 40 : break;
2631 : case kWasmI64:
2632 : thrower_->LinkError(
2633 20 : "export of globals of type I64 is not allowed.");
2634 20 : return;
2635 : default:
2636 0 : UNREACHABLE();
2637 : }
2638 290 : desc.set_value(isolate_->factory()->NewNumber(num));
2639 : break;
2640 : }
2641 : default:
2642 0 : UNREACHABLE();
2643 : break;
2644 : }
2645 :
2646 : v8::Maybe<bool> status = JSReceiver::DefineOwnProperty(
2647 188943 : isolate_, export_to, name, &desc, Object::THROW_ON_ERROR);
2648 188943 : if (!status.IsJust()) {
2649 : TruncatedUserString<> trunc_name(name->GetCharVector<uint8_t>());
2650 : thrower_->LinkError("export of %.*s failed.", trunc_name.length(),
2651 0 : trunc_name.start());
2652 : return;
2653 : }
2654 : }
2655 : DCHECK_EQ(export_index, weak_exported_functions->length());
2656 :
2657 305384 : if (module_->is_wasm()) {
2658 : v8::Maybe<bool> success = JSReceiver::SetIntegrityLevel(
2659 146503 : exports_object, FROZEN, Object::DONT_THROW);
2660 : DCHECK(success.FromMaybe(false));
2661 : USE(success);
2662 : }
2663 : }
2664 :
2665 1900 : void InstanceBuilder::InitializeTables(
2666 : Handle<WasmInstanceObject> instance,
2667 : CodeSpecialization* code_specialization) {
2668 5700 : int function_table_count = static_cast<int>(module_->function_tables.size());
2669 : Handle<FixedArray> new_function_tables =
2670 5700 : isolate_->factory()->NewFixedArray(function_table_count, TENURED);
2671 : Handle<FixedArray> new_signature_tables =
2672 1900 : isolate_->factory()->NewFixedArray(function_table_count, TENURED);
2673 1900 : Handle<FixedArray> old_function_tables = compiled_module_->function_tables();
2674 : Handle<FixedArray> old_signature_tables =
2675 1900 : compiled_module_->signature_tables();
2676 :
2677 : // These go on the instance.
2678 : Handle<FixedArray> rooted_function_tables =
2679 1900 : isolate_->factory()->NewFixedArray(function_table_count, TENURED);
2680 : Handle<FixedArray> rooted_signature_tables =
2681 1900 : isolate_->factory()->NewFixedArray(function_table_count, TENURED);
2682 :
2683 1900 : instance->set_function_tables(*rooted_function_tables);
2684 1900 : instance->set_signature_tables(*rooted_signature_tables);
2685 :
2686 : DCHECK_EQ(old_function_tables->length(), new_function_tables->length());
2687 : DCHECK_EQ(old_signature_tables->length(), new_signature_tables->length());
2688 :
2689 3800 : for (int index = 0; index < function_table_count; ++index) {
2690 1900 : WasmIndirectFunctionTable& table = module_->function_tables[index];
2691 1900 : TableInstance& table_instance = table_instances_[index];
2692 1900 : int table_size = static_cast<int>(table.initial_size);
2693 :
2694 1900 : if (table_instance.function_table.is_null()) {
2695 : // Create a new dispatch table if necessary.
2696 : table_instance.function_table =
2697 1020 : isolate_->factory()->NewFixedArray(table_size);
2698 : table_instance.signature_table =
2699 1020 : isolate_->factory()->NewFixedArray(table_size);
2700 11912 : for (int i = 0; i < table_size; ++i) {
2701 : // Fill the table with invalid signature indexes so that
2702 : // uninitialized entries will always fail the signature check.
2703 : table_instance.signature_table->set(i, Smi::FromInt(kInvalidSigIndex));
2704 : }
2705 : } else {
2706 : // Table is imported, patch table bounds check
2707 : DCHECK_LE(table_size, table_instance.function_table->length());
2708 : code_specialization->PatchTableSize(
2709 880 : table_size, table_instance.function_table->length());
2710 : }
2711 : int int_index = static_cast<int>(index);
2712 :
2713 : Handle<FixedArray> global_func_table =
2714 1900 : isolate_->global_handles()->Create(*table_instance.function_table);
2715 : Handle<FixedArray> global_sig_table =
2716 1900 : isolate_->global_handles()->Create(*table_instance.signature_table);
2717 : // Make the handles weak. The table objects are rooted on the instance, as
2718 : // they belong to it. We need the global handles in order to have stable
2719 : // pointers to embed in the instance's specialization (wasm compiled code).
2720 : // The order of finalization doesn't matter, in that the instance finalizer
2721 : // may be called before each table's finalizer, or vice-versa.
2722 : // This is because values used for embedding are only interesting should we
2723 : // {Reset} a specialization, in which case they are interesting as values,
2724 : // they are not dereferenced.
2725 : GlobalHandles::MakeWeak(
2726 : reinterpret_cast<Object**>(global_func_table.location()),
2727 : global_func_table.location(), &FunctionTableFinalizer,
2728 1900 : v8::WeakCallbackType::kFinalizer);
2729 : GlobalHandles::MakeWeak(
2730 : reinterpret_cast<Object**>(global_sig_table.location()),
2731 : global_sig_table.location(), &FunctionTableFinalizer,
2732 1900 : v8::WeakCallbackType::kFinalizer);
2733 :
2734 1900 : rooted_function_tables->set(int_index, *global_func_table);
2735 1900 : rooted_signature_tables->set(int_index, *global_sig_table);
2736 :
2737 : GlobalHandleAddress new_func_table_addr = global_func_table.address();
2738 : GlobalHandleAddress new_sig_table_addr = global_sig_table.address();
2739 : WasmCompiledModule::SetTableValue(isolate_, new_function_tables, int_index,
2740 1900 : new_func_table_addr);
2741 : WasmCompiledModule::SetTableValue(isolate_, new_signature_tables, int_index,
2742 1900 : new_sig_table_addr);
2743 :
2744 : GlobalHandleAddress old_func_table_addr =
2745 1900 : WasmCompiledModule::GetTableValue(*old_function_tables, int_index);
2746 : GlobalHandleAddress old_sig_table_addr =
2747 1900 : WasmCompiledModule::GetTableValue(*old_signature_tables, int_index);
2748 :
2749 : code_specialization->RelocatePointer(old_func_table_addr,
2750 1900 : new_func_table_addr);
2751 : code_specialization->RelocatePointer(old_sig_table_addr,
2752 1900 : new_sig_table_addr);
2753 : }
2754 :
2755 : compiled_module_->set_function_tables(new_function_tables);
2756 : compiled_module_->set_signature_tables(new_signature_tables);
2757 1900 : }
2758 :
2759 1830 : void InstanceBuilder::LoadTableSegments(Handle<FixedArray> code_table,
2760 : Handle<WasmInstanceObject> instance) {
2761 5070 : int function_table_count = static_cast<int>(module_->function_tables.size());
2762 3660 : for (int index = 0; index < function_table_count; ++index) {
2763 1830 : TableInstance& table_instance = table_instances_[index];
2764 :
2765 : Handle<FixedArray> all_dispatch_tables;
2766 1830 : if (!table_instance.table_object.is_null()) {
2767 : // Get the existing dispatch table(s) with the WebAssembly.Table object.
2768 : all_dispatch_tables =
2769 : handle(table_instance.table_object->dispatch_tables());
2770 : }
2771 :
2772 : // Count the number of table exports for each function (needed for lazy
2773 : // compilation).
2774 1830 : std::unordered_map<uint32_t, uint32_t> num_table_exports;
2775 3660 : if (compile_lazy(module_)) {
2776 425 : for (auto& table_init : module_->table_inits) {
2777 7047 : for (uint32_t func_index : table_init.entries) {
2778 : Code* code =
2779 6777 : Code::cast(code_table->get(static_cast<int>(func_index)));
2780 : // Only increase the counter for lazy compile builtins (it's not
2781 : // needed otherwise).
2782 6777 : if (code->is_wasm_code()) continue;
2783 : DCHECK_EQ(Builtins::kWasmCompileLazy, code->builtin_index());
2784 6543 : ++num_table_exports[func_index];
2785 : }
2786 : }
2787 : }
2788 :
2789 : // TODO(titzer): this does redundant work if there are multiple tables,
2790 : // since initializations are not sorted by table index.
2791 6750 : for (auto& table_init : module_->table_inits) {
2792 1260 : uint32_t base = EvalUint32InitExpr(table_init.offset);
2793 12102 : uint32_t num_entries = static_cast<uint32_t>(table_init.entries.size());
2794 : DCHECK(in_bounds(base, num_entries,
2795 : table_instance.function_table->length()));
2796 10842 : for (uint32_t i = 0; i < num_entries; ++i) {
2797 19164 : uint32_t func_index = table_init.entries[i];
2798 9582 : WasmFunction* function = &module_->functions[func_index];
2799 9582 : int table_index = static_cast<int>(i + base);
2800 19164 : uint32_t sig_index = module_->signature_ids[function->sig_index];
2801 : table_instance.signature_table->set(table_index,
2802 9582 : Smi::FromInt(sig_index));
2803 : Handle<Code> wasm_code = EnsureTableExportLazyDeoptData(
2804 : isolate_, instance, code_table, func_index,
2805 9582 : table_instance.function_table, table_index, num_table_exports);
2806 9582 : table_instance.function_table->set(table_index, *wasm_code);
2807 :
2808 9582 : if (!all_dispatch_tables.is_null()) {
2809 6180 : if (js_wrappers_[func_index].is_null()) {
2810 : // No JSFunction entry yet exists for this function. Create one.
2811 : // TODO(titzer): We compile JS->wasm wrappers for functions are
2812 : // not exported but are in an exported table. This should be done
2813 : // at module compile time and cached instead.
2814 :
2815 : Handle<Code> wrapper_code =
2816 : js_to_wasm_cache_.CloneOrCompileJSToWasmWrapper(
2817 1410 : isolate_, module_, wasm_code, func_index);
2818 : MaybeHandle<String> func_name;
2819 2820 : if (module_->is_asm_js()) {
2820 : // For modules arising from asm.js, honor the names section.
2821 : func_name = WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
2822 0 : isolate_, compiled_module_, function->name)
2823 0 : .ToHandleChecked();
2824 : }
2825 : Handle<WasmExportedFunction> js_function =
2826 : WasmExportedFunction::New(
2827 : isolate_, instance, func_name, func_index,
2828 1410 : static_cast<int>(function->sig->parameter_count()),
2829 1410 : wrapper_code);
2830 1410 : js_wrappers_[func_index] = js_function;
2831 : }
2832 : table_instance.js_wrappers->set(table_index,
2833 1590 : *js_wrappers_[func_index]);
2834 :
2835 : UpdateDispatchTables(isolate_, all_dispatch_tables, table_index,
2836 1590 : function, wasm_code);
2837 : }
2838 : }
2839 : }
2840 :
2841 : #ifdef DEBUG
2842 : // Check that the count of table exports was accurate. The entries are
2843 : // decremented on each export, so all should be zero now.
2844 : for (auto e : num_table_exports) {
2845 : DCHECK_EQ(0, e.second);
2846 : }
2847 : #endif
2848 :
2849 : // TODO(titzer): we add the new dispatch table at the end to avoid
2850 : // redundant work and also because the new instance is not yet fully
2851 : // initialized.
2852 1830 : if (!table_instance.table_object.is_null()) {
2853 : // Add the new dispatch table to the WebAssembly.Table object.
2854 : all_dispatch_tables = WasmTableObject::AddDispatchTable(
2855 : isolate_, table_instance.table_object, instance, index,
2856 1290 : table_instance.function_table, table_instance.signature_table);
2857 : }
2858 : }
2859 1830 : }
2860 :
2861 413 : AsyncCompileJob::AsyncCompileJob(Isolate* isolate,
2862 : std::unique_ptr<byte[]> bytes_copy,
2863 : size_t length, Handle<Context> context,
2864 : Handle<JSPromise> promise)
2865 : : isolate_(isolate),
2866 : async_counters_(isolate->async_counters()),
2867 : bytes_copy_(std::move(bytes_copy)),
2868 2065 : wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length) {
2869 : // The handles for the context and promise must be deferred.
2870 413 : DeferredHandleScope deferred(isolate);
2871 413 : context_ = Handle<Context>(*context);
2872 413 : module_promise_ = Handle<JSPromise>(*promise);
2873 826 : deferred_handles_.push_back(deferred.Detach());
2874 413 : }
2875 :
2876 63 : void AsyncCompileJob::Start() {
2877 63 : DoAsync<DecodeModule>(); // --
2878 63 : }
2879 :
2880 66 : void AsyncCompileJob::Abort() {
2881 66 : background_task_manager_.CancelAndWait();
2882 66 : if (num_pending_foreground_tasks_ == 0) {
2883 : // No task is pending, we can just remove the AsyncCompileJob.
2884 198 : isolate_->wasm_compilation_manager()->RemoveJob(this);
2885 : } else {
2886 : // There is still a compilation task in the task queue. We enter the
2887 : // AbortCompilation state and wait for this compilation task to abort the
2888 : // AsyncCompileJob.
2889 0 : NextStep<AbortCompilation>();
2890 : }
2891 66 : }
2892 :
2893 1400 : class AsyncStreamingProcessor final : public StreamingProcessor {
2894 : public:
2895 : explicit AsyncStreamingProcessor(AsyncCompileJob* job);
2896 :
2897 : bool ProcessModuleHeader(Vector<const uint8_t> bytes,
2898 : uint32_t offset) override;
2899 :
2900 : bool ProcessSection(SectionCode section_code, Vector<const uint8_t> bytes,
2901 : uint32_t offset) override;
2902 :
2903 : bool ProcessCodeSectionHeader(size_t functions_count,
2904 : uint32_t offset) override;
2905 :
2906 : bool ProcessFunctionBody(Vector<const uint8_t> bytes,
2907 : uint32_t offset) override;
2908 :
2909 : void OnFinishedChunk() override;
2910 :
2911 : void OnFinishedStream(std::unique_ptr<uint8_t[]> bytes,
2912 : size_t length) override;
2913 :
2914 : void OnError(DecodeResult result) override;
2915 :
2916 : void OnAbort() override;
2917 :
2918 : private:
2919 : // Finishes the AsyncCOmpileJob with an error.
2920 : void FinishAsyncCompileJobWithError(ResultBase result);
2921 :
2922 : ModuleDecoder decoder_;
2923 : AsyncCompileJob* job_;
2924 : std::unique_ptr<ModuleCompiler::CompilationUnitBuilder>
2925 : compilation_unit_builder_;
2926 : uint32_t next_function_ = 0;
2927 : };
2928 :
2929 350 : std::shared_ptr<StreamingDecoder> AsyncCompileJob::CreateStreamingDecoder() {
2930 : DCHECK_NULL(stream_);
2931 : stream_.reset(
2932 1400 : new StreamingDecoder(base::make_unique<AsyncStreamingProcessor>(this)));
2933 350 : return stream_;
2934 : }
2935 :
2936 826 : AsyncCompileJob::~AsyncCompileJob() {
2937 413 : background_task_manager_.CancelAndWait();
2938 1609 : for (auto d : deferred_handles_) delete d;
2939 413 : }
2940 :
2941 231 : void AsyncCompileJob::AsyncCompileFailed(ErrorThrower& thrower) {
2942 231 : if (stream_) stream_->NotifyError();
2943 : // {job} keeps the {this} pointer alive.
2944 : std::shared_ptr<AsyncCompileJob> job =
2945 462 : isolate_->wasm_compilation_manager()->RemoveJob(this);
2946 231 : RejectPromise(isolate_, context_, thrower, module_promise_);
2947 231 : }
2948 :
2949 115 : void AsyncCompileJob::AsyncCompileSucceeded(Handle<Object> result) {
2950 : // {job} keeps the {this} pointer alive.
2951 : std::shared_ptr<AsyncCompileJob> job =
2952 230 : isolate_->wasm_compilation_manager()->RemoveJob(this);
2953 115 : ResolvePromise(isolate_, context_, module_promise_, result);
2954 115 : }
2955 :
2956 : // A closure to run a compilation step (either as foreground or background
2957 : // task) and schedule the next step(s), if any.
2958 : class AsyncCompileJob::CompileStep {
2959 : public:
2960 : explicit CompileStep(size_t num_background_tasks = 0)
2961 1108 : : num_background_tasks_(num_background_tasks) {}
2962 :
2963 1108 : virtual ~CompileStep() {}
2964 :
2965 1416 : void Run(bool on_foreground) {
2966 1416 : if (on_foreground) {
2967 986 : HandleScope scope(job_->isolate_);
2968 986 : --job_->num_pending_foreground_tasks_;
2969 : DCHECK_EQ(0, job_->num_pending_foreground_tasks_);
2970 1972 : SaveContext saved_context(job_->isolate_);
2971 1972 : job_->isolate_->set_context(*job_->context_);
2972 986 : RunInForeground();
2973 : } else {
2974 430 : RunInBackground();
2975 : }
2976 1416 : }
2977 :
2978 0 : virtual void RunInForeground() { UNREACHABLE(); }
2979 0 : virtual void RunInBackground() { UNREACHABLE(); }
2980 :
2981 : size_t NumberOfBackgroundTasks() { return num_background_tasks_; }
2982 :
2983 : AsyncCompileJob* job_ = nullptr;
2984 : const size_t num_background_tasks_;
2985 : };
2986 :
2987 2518 : class AsyncCompileJob::CompileTask : public CancelableTask {
2988 : public:
2989 : CompileTask(AsyncCompileJob* job, bool on_foreground)
2990 : // We only manage the background tasks with the {CancelableTaskManager} of
2991 : // the {AsyncCompileJob}. Foreground tasks are managed by the system's
2992 : // {CancelableTaskManager}. Background tasks cannot spawn tasks managed by
2993 : // their own task manager.
2994 793 : : CancelableTask(on_foreground ? job->isolate_->cancelable_task_manager()
2995 : : &job->background_task_manager_),
2996 : job_(job),
2997 1259 : on_foreground_(on_foreground) {}
2998 :
2999 2444 : void RunInternal() override { job_->step_->Run(on_foreground_); }
3000 :
3001 : private:
3002 : AsyncCompileJob* job_;
3003 : bool on_foreground_;
3004 : };
3005 :
3006 793 : void AsyncCompileJob::StartForegroundTask() {
3007 793 : ++num_pending_foreground_tasks_;
3008 : DCHECK_EQ(1, num_pending_foreground_tasks_);
3009 :
3010 793 : v8::Platform* platform = V8::GetCurrentPlatform();
3011 : // TODO(ahaas): This is a CHECK to debug issue 764313.
3012 793 : CHECK(platform);
3013 : platform->CallOnForegroundThread(reinterpret_cast<v8::Isolate*>(isolate_),
3014 1586 : new CompileTask(this, true));
3015 793 : }
3016 :
3017 : template <typename Step, typename... Args>
3018 : void AsyncCompileJob::DoSync(Args&&... args) {
3019 596 : NextStep<Step>(std::forward<Args>(args)...);
3020 596 : StartForegroundTask();
3021 : }
3022 :
3023 466 : void AsyncCompileJob::StartBackgroundTask() {
3024 466 : V8::GetCurrentPlatform()->CallOnBackgroundThread(
3025 932 : new CompileTask(this, false), v8::Platform::kShortRunningTask);
3026 466 : }
3027 :
3028 288 : void AsyncCompileJob::RestartBackgroundTasks() {
3029 : size_t num_restarts = stopped_tasks_.Value();
3030 : stopped_tasks_.Decrement(num_restarts);
3031 :
3032 516 : for (size_t i = 0; i < num_restarts; ++i) {
3033 228 : StartBackgroundTask();
3034 : }
3035 288 : }
3036 :
3037 : template <typename Step, typename... Args>
3038 124 : void AsyncCompileJob::DoAsync(Args&&... args) {
3039 124 : NextStep<Step>(std::forward<Args>(args)...);
3040 124 : size_t end = step_->NumberOfBackgroundTasks();
3041 362 : for (size_t i = 0; i < end; ++i) {
3042 238 : StartBackgroundTask();
3043 : }
3044 124 : }
3045 :
3046 : template <typename Step, typename... Args>
3047 1108 : void AsyncCompileJob::NextStep(Args&&... args) {
3048 1297 : step_.reset(new Step(std::forward<Args>(args)...));
3049 1108 : step_->job_ = this;
3050 1108 : }
3051 :
3052 : //==========================================================================
3053 : // Step 1: (async) Decode the module.
3054 : //==========================================================================
3055 126 : class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
3056 : public:
3057 63 : DecodeModule() : CompileStep(1) {}
3058 :
3059 63 : void RunInBackground() override {
3060 : ModuleResult result;
3061 : {
3062 : DisallowHandleAllocation no_handle;
3063 : DisallowHeapAllocation no_allocation;
3064 : // Decode the module bytes.
3065 63 : TRACE_COMPILE("(1) Decoding module...\n");
3066 252 : result = AsyncDecodeWasmModule(job_->isolate_, job_->wire_bytes_.start(),
3067 : job_->wire_bytes_.end(), false,
3068 126 : kWasmOrigin, job_->async_counters());
3069 : }
3070 63 : if (result.failed()) {
3071 : // Decoding failure; reject the promise and clean up.
3072 1 : job_->DoSync<DecodeFail>(std::move(result));
3073 : } else {
3074 : // Decode passed.
3075 62 : job_->module_ = std::move(result.val);
3076 186 : job_->DoSync<PrepareAndStartCompile>(job_->module_.get(), true);
3077 63 : }
3078 63 : }
3079 : };
3080 :
3081 : //==========================================================================
3082 : // Step 1b: (sync) Fail decoding the module.
3083 : //==========================================================================
3084 378 : class AsyncCompileJob::DecodeFail : public CompileStep {
3085 : public:
3086 189 : explicit DecodeFail(ModuleResult result) : result_(std::move(result)) {}
3087 :
3088 : private:
3089 : ModuleResult result_;
3090 189 : void RunInForeground() override {
3091 189 : TRACE_COMPILE("(1b) Decoding failed.\n");
3092 189 : ErrorThrower thrower(job_->isolate_, "AsyncCompile");
3093 : thrower.CompileFailed("Wasm decoding failed", result_);
3094 : // {job_} is deleted in AsyncCompileFailed, therefore the {return}.
3095 189 : return job_->AsyncCompileFailed(thrower);
3096 : }
3097 : };
3098 :
3099 : //==========================================================================
3100 : // Step 2 (sync): Create heap-allocated data and start compile.
3101 : //==========================================================================
3102 512 : class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
3103 : public:
3104 : explicit PrepareAndStartCompile(WasmModule* module, bool start_compilation)
3105 256 : : module_(module), start_compilation_(start_compilation) {}
3106 :
3107 : private:
3108 : WasmModule* module_;
3109 : bool start_compilation_;
3110 :
3111 255 : void RunInForeground() override {
3112 255 : TRACE_COMPILE("(2) Prepare and start compile...\n");
3113 255 : Isolate* isolate = job_->isolate_;
3114 :
3115 : Factory* factory = isolate->factory();
3116 255 : Handle<Code> illegal_builtin = BUILTIN_CODE(isolate, Illegal);
3117 510 : job_->module_env_ =
3118 : CreateDefaultModuleEnv(isolate, module_, illegal_builtin);
3119 :
3120 : // The {code_table} array contains import wrappers and functions (which
3121 : // are both included in {functions.size()}.
3122 : // The results of compilation will be written into it.
3123 : // Initialize {code_table_} with the illegal builtin. All call sites
3124 : // will be patched at instantiation.
3125 765 : int code_table_size = static_cast<int>(module_->functions.size());
3126 255 : int export_wrapper_size = static_cast<int>(module_->num_exported_functions);
3127 255 : job_->code_table_ = factory->NewFixedArray(code_table_size, TENURED);
3128 : job_->export_wrappers_ =
3129 255 : factory->NewFixedArray(export_wrapper_size, TENURED);
3130 :
3131 256 : for (int i = 0, e = module_->num_imported_functions; i < e; ++i) {
3132 2 : job_->code_table_->set(i, *illegal_builtin);
3133 : }
3134 : // Transfer ownership of the {WasmModule} to the {ModuleCompiler}, but
3135 : // keep a pointer.
3136 510 : Handle<Code> centry_stub = CEntryStub(isolate, 1).GetCode();
3137 : {
3138 : // Now reopen the handles in a deferred scope in order to use
3139 : // them in the concurrent steps.
3140 255 : DeferredHandleScope deferred(isolate);
3141 :
3142 : centry_stub = Handle<Code>(*centry_stub, isolate);
3143 510 : job_->code_table_ = Handle<FixedArray>(*job_->code_table_, isolate);
3144 : job_->export_wrappers_ =
3145 510 : Handle<FixedArray>(*job_->export_wrappers_, isolate);
3146 255 : compiler::ModuleEnv* env = job_->module_env_.get();
3147 255 : ReopenHandles(isolate, env->function_code);
3148 : Handle<Code>* mut =
3149 : const_cast<Handle<Code>*>(&env->default_function_code);
3150 255 : *mut = Handle<Code>(**mut, isolate);
3151 :
3152 510 : job_->deferred_handles_.push_back(deferred.Detach());
3153 : }
3154 :
3155 510 : job_->compiler_.reset(new ModuleCompiler(isolate, module_, centry_stub));
3156 255 : job_->compiler_->EnableThrottling();
3157 :
3158 : DCHECK_LE(module_->num_imported_functions, module_->functions.size());
3159 : size_t num_functions =
3160 510 : module_->functions.size() - module_->num_imported_functions;
3161 255 : if (num_functions == 0) {
3162 : // Degenerate case of an empty module.
3163 0 : job_->DoSync<FinishCompile>();
3164 255 : return;
3165 : }
3166 :
3167 : // Start asynchronous compilation tasks.
3168 : size_t num_background_tasks =
3169 : Max(static_cast<size_t>(1),
3170 : Min(num_functions,
3171 : Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
3172 255 : V8::GetCurrentPlatform()
3173 510 : ->NumberOfAvailableBackgroundThreads())));
3174 :
3175 255 : if (start_compilation_) {
3176 : // TODO(ahaas): Try to remove the {start_compilation_} check when
3177 : // streaming decoding is done in the background. If
3178 : // InitializeCompilationUnits always returns 0 for streaming compilation,
3179 : // then DoAsync would do the same as NextStep already.
3180 : job_->outstanding_units_ = job_->compiler_->InitializeCompilationUnits(
3181 183 : module_->functions, job_->wire_bytes_, job_->module_env_.get());
3182 :
3183 61 : job_->DoAsync<ExecuteAndFinishCompilationUnits>(num_background_tasks);
3184 : } else {
3185 194 : job_->stopped_tasks_ = num_background_tasks;
3186 194 : job_->NextStep<ExecuteAndFinishCompilationUnits>(num_background_tasks);
3187 : }
3188 : }
3189 : };
3190 :
3191 : //==========================================================================
3192 : // Step 3 (async x K tasks): Execute compilation units.
3193 : //==========================================================================
3194 510 : class AsyncCompileJob::ExecuteAndFinishCompilationUnits : public CompileStep {
3195 : public:
3196 : explicit ExecuteAndFinishCompilationUnits(size_t num_compile_tasks)
3197 255 : : CompileStep(num_compile_tasks) {}
3198 :
3199 367 : void RunInBackground() override {
3200 199 : std::function<void()> StartFinishCompilationUnit = [this]() {
3201 398 : if (!failed_) job_->StartForegroundTask();
3202 199 : };
3203 :
3204 367 : TRACE_COMPILE("(3) Compiling...\n");
3205 3764 : while (job_->compiler_->CanAcceptWork()) {
3206 1882 : if (failed_) break;
3207 : DisallowHandleAllocation no_handle;
3208 : DisallowHeapAllocation no_allocation;
3209 1867 : if (!job_->compiler_->FetchAndExecuteCompilationUnit(
3210 5603 : StartFinishCompilationUnit)) {
3211 : finished_ = true;
3212 : break;
3213 : }
3214 : }
3215 366 : job_->stopped_tasks_.Increment(1);
3216 367 : }
3217 :
3218 197 : void RunInForeground() override {
3219 197 : TRACE_COMPILE("(4a) Finishing compilation units...\n");
3220 197 : if (failed_) {
3221 : // The job failed already, no need to do more work.
3222 0 : job_->compiler_->SetFinisherIsRunning(false);
3223 44 : return;
3224 : }
3225 197 : ErrorThrower thrower(job_->isolate_, "AsyncCompile");
3226 :
3227 : // We execute for 1 ms and then reschedule the task, same as the GC.
3228 197 : double deadline = MonotonicallyIncreasingTimeInMs() + 1.0;
3229 :
3230 : while (true) {
3231 1519 : if (!finished_ && job_->compiler_->ShouldIncreaseWorkload()) {
3232 36 : job_->RestartBackgroundTasks();
3233 : }
3234 :
3235 1483 : int func_index = -1;
3236 :
3237 : MaybeHandle<Code> result =
3238 2966 : job_->compiler_->FinishCompilationUnit(&thrower, &func_index);
3239 :
3240 1483 : if (thrower.error()) {
3241 : // An error was detected, we stop compiling and wait for the
3242 : // background tasks to finish.
3243 : failed_ = true;
3244 195 : break;
3245 1441 : } else if (result.is_null()) {
3246 : // The working queue was empty, we break the loop. If new work units
3247 : // are enqueued, the background task will start this
3248 : // FinishCompilationUnits task again.
3249 : break;
3250 : } else {
3251 : DCHECK_LE(0, func_index);
3252 2576 : job_->code_table_->set(func_index, *result.ToHandleChecked());
3253 1288 : --job_->outstanding_units_;
3254 : }
3255 :
3256 1288 : if (deadline < MonotonicallyIncreasingTimeInMs()) {
3257 : // We reached the deadline. We reschedule this task and return
3258 : // immediately. Since we rescheduled this task already, we do not set
3259 : // the FinisherIsRunning flat to false.
3260 2 : job_->StartForegroundTask();
3261 2 : return;
3262 : }
3263 : }
3264 : // This task finishes without being rescheduled. Therefore we set the
3265 : // FinisherIsRunning flag to false.
3266 195 : job_->compiler_->SetFinisherIsRunning(false);
3267 195 : if (thrower.error()) {
3268 : // Make sure all compilation tasks stopped running.
3269 42 : job_->background_task_manager_.CancelAndWait();
3270 42 : return job_->AsyncCompileFailed(thrower);
3271 : }
3272 153 : if (job_->outstanding_units_ == 0) {
3273 : // Make sure all compilation tasks stopped running.
3274 121 : job_->background_task_manager_.CancelAndWait();
3275 242 : if (job_->DecrementAndCheckFinisherCount()) job_->DoSync<FinishCompile>();
3276 153 : }
3277 : }
3278 :
3279 : private:
3280 : std::atomic<bool> failed_{false};
3281 : std::atomic<bool> finished_{false};
3282 : };
3283 :
3284 : //==========================================================================
3285 : // Step 5 (sync): Finish heap-allocated data structures.
3286 : //==========================================================================
3287 345 : class AsyncCompileJob::FinishCompile : public CompileStep {
3288 115 : void RunInForeground() override {
3289 115 : TRACE_COMPILE("(5b) Finish compile...\n");
3290 : // At this point, compilation has completed. Update the code table.
3291 1285 : for (int i = FLAG_skip_compiling_wasm_funcs,
3292 115 : e = job_->code_table_->length();
3293 : i < e; ++i) {
3294 1055 : Object* val = job_->code_table_->get(i);
3295 2110 : if (val->IsCode()) RecordStats(Code::cast(val), job_->counters());
3296 : }
3297 :
3298 : // Create heap objects for script and module bytes to be stored in the
3299 : // shared module data. Asm.js is not compiled asynchronously.
3300 230 : Handle<Script> script = CreateWasmScript(job_->isolate_, job_->wire_bytes_);
3301 : Handle<ByteArray> asm_js_offset_table;
3302 : // TODO(wasm): Improve efficiency of storing module wire bytes.
3303 : // 1. Only store relevant sections, not function bodies
3304 : // 2. Don't make a second copy of the bytes here; reuse the copy made
3305 : // for asynchronous compilation and store it as an external one
3306 : // byte string for serialization/deserialization.
3307 : Handle<String> module_bytes =
3308 : job_->isolate_->factory()
3309 : ->NewStringFromOneByte(
3310 : {job_->wire_bytes_.start(), job_->wire_bytes_.length()},
3311 345 : TENURED)
3312 230 : .ToHandleChecked();
3313 : DCHECK(module_bytes->IsSeqOneByteString());
3314 :
3315 : // The {module_wrapper} will take ownership of the {WasmModule} object,
3316 : // and it will be destroyed when the GC reclaims the wrapper object.
3317 : Handle<WasmModuleWrapper> module_wrapper =
3318 230 : WasmModuleWrapper::From(job_->isolate_, job_->module_.release());
3319 :
3320 : // Create the shared module data.
3321 : // TODO(clemensh): For the same module (same bytes / same hash), we should
3322 : // only have one WasmSharedModuleData. Otherwise, we might only set
3323 : // breakpoints on a (potentially empty) subset of the instances.
3324 :
3325 : Handle<WasmSharedModuleData> shared =
3326 : WasmSharedModuleData::New(job_->isolate_, module_wrapper,
3327 : Handle<SeqOneByteString>::cast(module_bytes),
3328 115 : script, asm_js_offset_table);
3329 :
3330 : // Create the compiled module object and populate with compiled functions
3331 : // and information needed at instantiation time. This object needs to be
3332 : // serializable. Instantiation may occur off a deserialized version of
3333 : // this object.
3334 : job_->compiled_module_ =
3335 : NewCompiledModule(job_->isolate_, shared, job_->code_table_,
3336 345 : job_->export_wrappers_, job_->module_env_.get());
3337 : // Finish the wasm script now and make it public to the debugger.
3338 230 : script->set_wasm_compiled_module(*job_->compiled_module_);
3339 230 : job_->isolate_->debug()->OnAfterCompile(script);
3340 :
3341 115 : DeferredHandleScope deferred(job_->isolate_);
3342 230 : job_->compiled_module_ = handle(*job_->compiled_module_, job_->isolate_);
3343 230 : job_->deferred_handles_.push_back(deferred.Detach());
3344 : // TODO(wasm): compiling wrappers should be made async as well.
3345 230 : job_->DoSync<CompileWrappers>();
3346 115 : }
3347 : };
3348 :
3349 : //==========================================================================
3350 : // Step 6 (sync): Compile JS->wasm wrappers.
3351 : //==========================================================================
3352 345 : class AsyncCompileJob::CompileWrappers : public CompileStep {
3353 : // TODO(wasm): Compile all wrappers here, including the start function wrapper
3354 : // and the wrappers for the function table elements.
3355 115 : void RunInForeground() override {
3356 115 : TRACE_COMPILE("(6) Compile wrappers...\n");
3357 : // Compile JS->wasm wrappers for exported functions.
3358 : JSToWasmWrapperCache js_to_wasm_cache;
3359 : int wrapper_index = 0;
3360 230 : WasmModule* module = job_->compiled_module_->module();
3361 1231 : for (auto exp : module->export_table) {
3362 1020 : if (exp.kind != kExternalFunction) continue;
3363 : Handle<Code> wasm_code(Code::cast(job_->code_table_->get(exp.index)),
3364 982 : job_->isolate_);
3365 : Handle<Code> wrapper_code =
3366 : js_to_wasm_cache.CloneOrCompileJSToWasmWrapper(job_->isolate_, module,
3367 982 : wasm_code, exp.index);
3368 1964 : job_->export_wrappers_->set(wrapper_index, *wrapper_code);
3369 1964 : RecordStats(*wrapper_code, job_->counters());
3370 982 : ++wrapper_index;
3371 : }
3372 :
3373 230 : job_->DoSync<FinishModule>();
3374 115 : }
3375 : };
3376 :
3377 : //==========================================================================
3378 : // Step 7 (sync): Finish the module and resolve the promise.
3379 : //==========================================================================
3380 345 : class AsyncCompileJob::FinishModule : public CompileStep {
3381 115 : void RunInForeground() override {
3382 115 : TRACE_COMPILE("(7) Finish module...\n");
3383 : Handle<WasmModuleObject> result =
3384 115 : WasmModuleObject::New(job_->isolate_, job_->compiled_module_);
3385 : // {job_} is deleted in AsyncCompileSucceeded, therefore the {return}.
3386 115 : return job_->AsyncCompileSucceeded(result);
3387 : }
3388 : };
3389 :
3390 0 : class AsyncCompileJob::AbortCompilation : public CompileStep {
3391 0 : void RunInForeground() override {
3392 0 : TRACE_COMPILE("Abort asynchronous compilation ...\n");
3393 0 : job_->isolate_->wasm_compilation_manager()->RemoveJob(job_);
3394 0 : }
3395 : };
3396 :
3397 0 : AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
3398 350 : : job_(job), compilation_unit_builder_(nullptr) {}
3399 :
3400 188 : void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(ResultBase error) {
3401 : // Make sure all background tasks stopped executing before we change the state
3402 : // of the AsyncCompileJob to DecodeFail.
3403 188 : job_->background_task_manager_.CancelAndWait();
3404 :
3405 : // Create a ModuleResult from the result we got as parameter. Since there was
3406 : // no error, we don't have to provide a real wasm module to the ModuleResult.
3407 : ModuleResult result(nullptr);
3408 188 : result.MoveErrorFrom(error);
3409 :
3410 : // Check if there is already a ModuleCompiler, in which case we have to clean
3411 : // it up as well.
3412 376 : if (job_->compiler_) {
3413 : // If {IsFinisherRunning} is true, then there is already a foreground task
3414 : // in the task queue to execute the DecodeFail step. We do not have to start
3415 : // a new task ourselves with DoSync.
3416 56 : if (job_->compiler_->IsFinisherRunning()) {
3417 0 : job_->NextStep<AsyncCompileJob::DecodeFail>(std::move(result));
3418 : } else {
3419 : job_->DoSync<AsyncCompileJob::DecodeFail>(std::move(result));
3420 : }
3421 :
3422 : compilation_unit_builder_->Clear();
3423 : } else {
3424 : job_->DoSync<AsyncCompileJob::DecodeFail>(std::move(result));
3425 188 : }
3426 188 : }
3427 :
3428 : // Process the module header.
3429 344 : bool AsyncStreamingProcessor::ProcessModuleHeader(Vector<const uint8_t> bytes,
3430 : uint32_t offset) {
3431 344 : TRACE_STREAMING("Process module header...\n");
3432 344 : decoder_.StartDecoding(job_->isolate());
3433 344 : decoder_.DecodeModuleHeader(bytes, offset);
3434 344 : if (!decoder_.ok()) {
3435 60 : FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false));
3436 20 : return false;
3437 : }
3438 : return true;
3439 : }
3440 :
3441 : // Process all sections except for the code section.
3442 718 : bool AsyncStreamingProcessor::ProcessSection(SectionCode section_code,
3443 : Vector<const uint8_t> bytes,
3444 : uint32_t offset) {
3445 718 : TRACE_STREAMING("Process section %d ...\n", section_code);
3446 718 : if (section_code == SectionCode::kUnknownSectionCode) {
3447 : // No need to decode unknown sections, even the names section. If decoding
3448 : // of the unknown section fails, compilation should succeed anyways, and
3449 : // even decoding the names section is unnecessary because the result comes
3450 : // too late for streaming compilation.
3451 : return true;
3452 : }
3453 : constexpr bool verify_functions = false;
3454 668 : decoder_.DecodeSection(section_code, bytes, offset, verify_functions);
3455 668 : if (!decoder_.ok()) {
3456 84 : FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false));
3457 28 : return false;
3458 : }
3459 : return true;
3460 : }
3461 :
3462 : // Start the code section.
3463 210 : bool AsyncStreamingProcessor::ProcessCodeSectionHeader(size_t functions_count,
3464 : uint32_t offset) {
3465 210 : TRACE_STREAMING("Start the code section with %zu functions...\n",
3466 : functions_count);
3467 210 : if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(functions_count),
3468 210 : offset)) {
3469 48 : FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false));
3470 16 : return false;
3471 : }
3472 194 : job_->NextStep<AsyncCompileJob::PrepareAndStartCompile>(decoder_.module(),
3473 388 : false);
3474 : // Execute the PrepareAndStartCompile step immediately and not in a separate
3475 : // task. The step expects to be run on a separate foreground thread though, so
3476 : // we to increment {num_pending_foreground_tasks_} to look like one.
3477 194 : ++job_->num_pending_foreground_tasks_;
3478 : DCHECK_EQ(1, job_->num_pending_foreground_tasks_);
3479 : constexpr bool on_foreground = true;
3480 388 : job_->step_->Run(on_foreground);
3481 :
3482 194 : job_->outstanding_units_ = functions_count;
3483 : // Set outstanding_finishers_ to 2, because both the AsyncCompileJob and the
3484 : // AsyncStreamingProcessor have to finish.
3485 194 : job_->outstanding_finishers_.SetValue(2);
3486 194 : next_function_ = decoder_.module()->num_imported_functions +
3487 194 : FLAG_skip_compiling_wasm_funcs;
3488 : compilation_unit_builder_.reset(
3489 388 : new ModuleCompiler::CompilationUnitBuilder(job_->compiler_.get()));
3490 : return true;
3491 : }
3492 :
3493 : // Process a function body.
3494 438 : bool AsyncStreamingProcessor::ProcessFunctionBody(Vector<const uint8_t> bytes,
3495 : uint32_t offset) {
3496 438 : TRACE_STREAMING("Process function body %d ...\n", next_function_);
3497 :
3498 : decoder_.DecodeFunctionBody(
3499 876 : next_function_, static_cast<uint32_t>(bytes.length()), offset, false);
3500 438 : if (next_function_ >= decoder_.module()->num_imported_functions +
3501 : FLAG_skip_compiling_wasm_funcs) {
3502 438 : const WasmFunction* func = &decoder_.module()->functions[next_function_];
3503 : WasmName name = {nullptr, 0};
3504 : compilation_unit_builder_->AddUnit(job_->module_env_.get(), func, offset,
3505 876 : bytes, name);
3506 : }
3507 438 : ++next_function_;
3508 438 : return true;
3509 : }
3510 :
3511 306 : void AsyncStreamingProcessor::OnFinishedChunk() {
3512 : // TRACE_STREAMING("FinishChunk...\n");
3513 306 : if (compilation_unit_builder_) {
3514 252 : compilation_unit_builder_->Commit();
3515 252 : job_->RestartBackgroundTasks();
3516 : }
3517 306 : }
3518 :
3519 : // Finish the processing of the stream.
3520 84 : void AsyncStreamingProcessor::OnFinishedStream(std::unique_ptr<uint8_t[]> bytes,
3521 : size_t length) {
3522 84 : TRACE_STREAMING("Finish stream...\n");
3523 84 : job_->bytes_copy_ = std::move(bytes);
3524 : job_->wire_bytes_ = ModuleWireBytes(job_->bytes_copy_.get(),
3525 252 : job_->bytes_copy_.get() + length);
3526 168 : ModuleResult result = decoder_.FinishDecoding(false);
3527 : DCHECK(result.ok());
3528 84 : job_->module_ = std::move(result.val);
3529 168 : if (job_->DecrementAndCheckFinisherCount())
3530 96 : job_->DoSync<AsyncCompileJob::FinishCompile>();
3531 84 : }
3532 :
3533 : // Report an error detected in the StreamingDecoder.
3534 124 : void AsyncStreamingProcessor::OnError(DecodeResult result) {
3535 124 : TRACE_STREAMING("Stream error...\n");
3536 248 : FinishAsyncCompileJobWithError(std::move(result));
3537 124 : }
3538 :
3539 66 : void AsyncStreamingProcessor::OnAbort() {
3540 66 : TRACE_STREAMING("Abort stream...\n");
3541 66 : job_->Abort();
3542 66 : }
3543 :
3544 : } // namespace wasm
3545 : } // namespace internal
3546 : } // namespace v8
3547 :
3548 : #undef TRACE
3549 : #undef TRACE_COMPILE
3550 : #undef TRACE_STREAMING
3551 : #undef TRACE_CHAIN
3552 : #undef ERROR_THROWER_WITH_MESSAGE
|