5 #include "src/wasm/module-compiler.h" 8 #include "src/asmjs/asm-js.h" 9 #include "src/base/template-utils.h" 10 #include "src/base/utils/random-number-generator.h" 11 #include "src/compiler/wasm-compiler.h" 12 #include "src/counters.h" 13 #include "src/identity-map.h" 14 #include "src/property-descriptor.h" 15 #include "src/task-utils.h" 16 #include "src/tracing/trace-event.h" 17 #include "src/trap-handler/trap-handler.h" 18 #include "src/wasm/module-decoder.h" 19 #include "src/wasm/streaming-decoder.h" 20 #include "src/wasm/wasm-code-manager.h" 21 #include "src/wasm/wasm-engine.h" 22 #include "src/wasm/wasm-import-wrapper-cache-inl.h" 23 #include "src/wasm/wasm-js.h" 24 #include "src/wasm/wasm-limits.h" 25 #include "src/wasm/wasm-memory.h" 26 #include "src/wasm/wasm-objects-inl.h" 27 #include "src/wasm/wasm-result.h" 28 #include "src/wasm/wasm-serialization.h" 32 if (FLAG_trace_wasm_instances) PrintF(__VA_ARGS__); \ 35 #define TRACE_COMPILE(...) \ 37 if (FLAG_trace_wasm_compiler) PrintF(__VA_ARGS__); \ 40 #define TRACE_STREAMING(...) \ 42 if (FLAG_trace_wasm_streaming) PrintF(__VA_ARGS__); \ 45 #define TRACE_LAZY(...) \ 47 if (FLAG_trace_wasm_lazy_compilation) PrintF(__VA_ARGS__); \ 59 enum class CompilationEvent : uint8_t {
60 kFinishedBaselineCompilation,
61 kFinishedTopTierCompilation,
65 enum class CompileMode : uint8_t { kRegular, kTiering };
72 class CompilationStateImpl {
74 using callback_t = std::function<void(CompilationEvent, const VoidResult*)>;
76 CompilationStateImpl(internal::Isolate*, NativeModule*);
77 ~CompilationStateImpl();
86 void SetNumberOfFunctionsToCompile(
size_t num_functions);
90 void SetCallback(callback_t callback);
93 void AddCompilationUnits(
94 std::vector<std::unique_ptr<WasmCompilationUnit>>& baseline_units,
95 std::vector<std::unique_ptr<WasmCompilationUnit>>& tiering_units);
96 std::unique_ptr<WasmCompilationUnit> GetNextCompilationUnit();
97 std::unique_ptr<WasmCompilationUnit> GetNextExecutedUnit();
99 bool HasCompilationUnitToFinish();
101 void OnFinishedUnit();
102 void ScheduleUnitForFinishing(std::unique_ptr<WasmCompilationUnit> unit,
104 void ScheduleCodeLogging(WasmCode*);
106 void OnBackgroundTaskStopped(
const WasmFeatures& detected);
107 void PublishDetectedFeatures(Isolate* isolate,
const WasmFeatures& detected);
108 void RestartBackgroundTasks(
size_t max = std::numeric_limits<size_t>::max());
111 bool SetFinisherIsRunning(
bool value);
112 void ScheduleFinisherTask();
116 void SetError(
uint32_t func_index,
const ResultBase& error_result);
118 Isolate* isolate()
const {
return isolate_; }
120 bool failed()
const {
121 base::MutexGuard guard(&mutex_);
122 return compile_error_ !=
nullptr;
125 bool baseline_compilation_finished()
const {
126 return outstanding_baseline_units_ == 0 ||
127 (compile_mode_ == CompileMode::kTiering &&
128 outstanding_tiering_units_ == 0);
131 bool has_outstanding_units()
const {
132 return outstanding_tiering_units_ > 0 || outstanding_baseline_units_ > 0;
135 CompileMode compile_mode()
const {
return compile_mode_; }
136 WasmFeatures* detected_features() {
return &detected_features_; }
141 VoidResult GetCompileError() {
142 DCHECK_NOT_NULL(compile_error_);
143 std::ostringstream error;
144 error <<
"Compiling wasm function \"";
145 wasm::ModuleWireBytes wire_bytes(native_module_->wire_bytes());
146 wasm::WireBytesRef name_ref = native_module_->module()->LookupFunctionName(
147 wire_bytes, compile_error_->func_index);
148 if (name_ref.is_set()) {
149 wasm::WasmName name = wire_bytes.GetNameOrNull(name_ref);
150 error.write(name.start(), name.length());
152 error <<
"wasm-function[" << compile_error_->func_index <<
"]";
154 error <<
"\" failed: " << compile_error_->result.error_msg();
155 return VoidResult::Error(compile_error_->result.error_offset(),
159 std::shared_ptr<WireBytesStorage> GetSharedWireBytesStorage()
const {
160 base::MutexGuard guard(&mutex_);
161 DCHECK_NOT_NULL(wire_bytes_storage_);
162 return wire_bytes_storage_;
165 void SetWireBytesStorage(
166 std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
167 base::MutexGuard guard(&mutex_);
168 wire_bytes_storage_ = wire_bytes_storage;
171 std::shared_ptr<WireBytesStorage> GetWireBytesStorage() {
172 base::MutexGuard guard(&mutex_);
173 return wire_bytes_storage_;
177 struct CompilationError {
179 VoidResult
const result;
180 CompilationError(
uint32_t func_index,
const ResultBase& compile_result)
181 : func_index(func_index),
182 result(VoidResult::ErrorFrom(compile_result)) {}
185 class LogCodesTask :
public CancelableTask {
187 LogCodesTask(CancelableTaskManager* manager,
188 CompilationStateImpl* compilation_state, Isolate* isolate)
189 : CancelableTask(manager),
190 compilation_state_(compilation_state),
193 DCHECK(WasmCode::ShouldBeLogged(isolate));
197 void AddCode(WasmCode* code) { code_to_log_.push_back(code); }
199 void RunInternal()
override {
203 base::MutexGuard guard(&compilation_state_->mutex_);
204 DCHECK_EQ(
this, compilation_state_->log_codes_task_);
205 compilation_state_->log_codes_task_ =
nullptr;
208 if (!WasmCode::ShouldBeLogged(isolate_))
return;
209 for (WasmCode* code : code_to_log_) {
210 code->LogCode(isolate_);
215 CompilationStateImpl*
const compilation_state_;
216 Isolate*
const isolate_;
217 std::vector<WasmCode*> code_to_log_;
220 void NotifyOnEvent(CompilationEvent event,
const VoidResult* error_result);
222 std::vector<std::unique_ptr<WasmCompilationUnit>>& finish_units() {
223 return baseline_compilation_finished() ? tiering_finish_units_
224 : baseline_finish_units_;
229 Isolate*
const isolate_;
230 NativeModule*
const native_module_;
231 const CompileMode compile_mode_;
236 bool const should_log_code_;
240 mutable base::Mutex mutex_;
245 std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_compilation_units_;
246 std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_compilation_units_;
248 bool finisher_is_running_ =
false;
249 size_t num_background_tasks_ = 0;
250 std::unique_ptr<CompilationError> compile_error_;
252 std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_finish_units_;
253 std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_finish_units_;
257 WasmFeatures detected_features_ = kNoWasmFeatures;
261 LogCodesTask* log_codes_task_ =
nullptr;
266 std::shared_ptr<WireBytesStorage> wire_bytes_storage_;
272 callback_t callback_;
274 CancelableTaskManager background_task_manager_;
275 CancelableTaskManager foreground_task_manager_;
276 std::shared_ptr<v8::TaskRunner> foreground_task_runner_;
278 const size_t max_background_tasks_ = 0;
280 size_t outstanding_baseline_units_ = 0;
281 size_t outstanding_tiering_units_ = 0;
284 void UpdateFeatureUseCounts(Isolate* isolate,
const WasmFeatures& detected) {
285 if (detected.threads) {
286 isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmThreadOpcodes);
290 class JSToWasmWrapperCache {
292 Handle<Code> GetOrCompileJSToWasmWrapper(Isolate* isolate, FunctionSig* sig,
294 std::pair<bool, FunctionSig> key(is_import, *sig);
295 Handle<Code>& cached = cache_[key];
296 if (cached.is_null()) {
297 cached = compiler::CompileJSToWasmWrapper(isolate, sig, is_import)
306 using CacheKey = std::pair<bool, FunctionSig>;
307 std::unordered_map<CacheKey, Handle<Code>, base::hash<CacheKey>> cache_;
312 class InstanceBuilder {
314 InstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
315 Handle<WasmModuleObject> module_object,
316 MaybeHandle<JSReceiver> ffi,
317 MaybeHandle<JSArrayBuffer> memory);
320 MaybeHandle<WasmInstanceObject> Build();
322 bool ExecuteStartFunction();
326 struct TableInstance {
327 Handle<WasmTableObject> table_object;
328 Handle<FixedArray> js_wrappers;
333 struct SanitizedImport {
334 Handle<String> module_name;
335 Handle<String> import_name;
336 Handle<Object> value;
340 const WasmFeatures enabled_;
341 const WasmModule*
const module_;
342 ErrorThrower* thrower_;
343 Handle<WasmModuleObject> module_object_;
344 MaybeHandle<JSReceiver> ffi_;
345 MaybeHandle<JSArrayBuffer> memory_;
346 Handle<JSArrayBuffer> globals_;
347 std::vector<TableInstance> table_instances_;
348 std::vector<Handle<JSFunction>> js_wrappers_;
349 std::vector<Handle<WasmExceptionObject>> exception_wrappers_;
350 Handle<WasmExportedFunction> start_function_;
351 JSToWasmWrapperCache js_to_wasm_cache_;
352 std::vector<SanitizedImport> sanitized_imports_;
354 UseTrapHandler use_trap_handler()
const {
355 return module_object_->native_module()->use_trap_handler() ? kUseTrapHandler
360 #define ERROR_THROWER_WITH_MESSAGE(TYPE) \ 361 void Report##TYPE(const char* error, uint32_t index, \ 362 Handle<String> module_name, Handle<String> import_name) { \ 363 thrower_->TYPE("Import #%d module=\"%s\" function=\"%s\" error: %s", \ 364 index, module_name->ToCString().get(), \ 365 import_name->ToCString().get(), error); \ 368 MaybeHandle<Object> Report##TYPE(const char* error, uint32_t index, \ 369 Handle<String> module_name) { \ 370 thrower_->TYPE("Import #%d module=\"%s\" error: %s", index, \ 371 module_name->ToCString().get(), error); \ 372 return MaybeHandle<Object>(); \ 375 ERROR_THROWER_WITH_MESSAGE(LinkError)
376 ERROR_THROWER_WITH_MESSAGE(TypeError)
378 #undef ERROR_THROWER_WITH_MESSAGE 381 MaybeHandle<Object> LookupImport(
uint32_t index, Handle<String> module_name,
382 Handle<String> import_name);
388 MaybeHandle<Object> LookupImportAsm(
uint32_t index,
389 Handle<String> import_name);
391 uint32_t EvalUint32InitExpr(
const WasmInitExpr& expr);
394 void LoadDataSegments(Handle<WasmInstanceObject> instance);
396 void WriteGlobalValue(
const WasmGlobal& global,
double value);
397 void WriteGlobalValue(
const WasmGlobal& global,
398 Handle<WasmGlobalObject> value);
400 void SanitizeImports();
404 MaybeHandle<JSArrayBuffer> FindImportedMemoryBuffer()
const;
409 int ProcessImports(Handle<WasmInstanceObject> instance);
411 template <
typename T>
412 T* GetRawGlobalPtr(
const WasmGlobal& global);
418 Handle<JSArrayBuffer> AllocateMemory(
uint32_t num_pages);
420 bool NeedsWrappers()
const;
424 void ProcessExports(Handle<WasmInstanceObject> instance);
426 void InitializeTables(Handle<WasmInstanceObject> instance);
428 void LoadTableSegments(Handle<WasmInstanceObject> instance);
432 void InitializeExceptions(Handle<WasmInstanceObject> instance);
435 CompilationStateImpl* Impl(CompilationState* compilation_state) {
436 return reinterpret_cast<CompilationStateImpl*
>(compilation_state);
444 void CompilationState::CancelAndWait() { Impl(
this)->CancelAndWait(); }
446 void CompilationState::SetError(
uint32_t func_index,
447 const ResultBase& error_result) {
448 Impl(
this)->SetError(func_index, error_result);
451 void CompilationState::SetWireBytesStorage(
452 std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
453 Impl(
this)->SetWireBytesStorage(std::move(wire_bytes_storage));
456 std::shared_ptr<WireBytesStorage> CompilationState::GetWireBytesStorage() {
457 return Impl(
this)->GetWireBytesStorage();
460 CompilationState::~CompilationState() { Impl(
this)->~CompilationStateImpl(); }
463 std::unique_ptr<CompilationState> CompilationState::New(
464 Isolate* isolate, NativeModule* native_module) {
465 return std::unique_ptr<CompilationState>(
reinterpret_cast<CompilationState*
>(
466 new CompilationStateImpl(isolate, native_module)));
472 MaybeHandle<WasmInstanceObject> InstantiateToInstanceObject(
473 Isolate* isolate, ErrorThrower* thrower,
474 Handle<WasmModuleObject> module_object, MaybeHandle<JSReceiver> imports,
475 MaybeHandle<JSArrayBuffer> memory) {
476 InstanceBuilder builder(isolate, thrower, module_object, imports, memory);
477 auto instance = builder.Build();
478 if (!instance.is_null() && builder.ExecuteStartFunction()) {
481 DCHECK(isolate->has_pending_exception() || thrower->error());
485 WasmCode* LazyCompileFunction(Isolate* isolate, NativeModule* native_module,
487 base::ElapsedTimer compilation_timer;
488 DCHECK(!native_module->has_code(static_cast<uint32_t>(func_index)));
490 compilation_timer.Start();
492 TRACE_LAZY(
"Compiling wasm-function#%d.\n", func_index);
494 const uint8_t* module_start = native_module->wire_bytes().start();
496 const WasmFunction* func = &native_module->module()->functions[func_index];
497 FunctionBody func_body{func->sig, func->code.offset(),
498 module_start + func->code.offset(),
499 module_start + func->code.end_offset()};
501 WasmCompilationUnit unit(isolate->wasm_engine(), native_module, func_index);
502 CompilationEnv env = native_module->CreateCompilationEnv();
503 unit.ExecuteCompilation(
504 &env, native_module->compilation_state()->GetWireBytesStorage(),
506 Impl(native_module->compilation_state())->detected_features());
513 CHECK(!unit.failed());
515 WasmCode* code = unit.result();
517 if (WasmCode::ShouldBeLogged(isolate)) code->LogCode(isolate);
520 static_cast<int64_t>(func->code.end_offset() - func->code.offset());
521 int64_t compilation_time = compilation_timer.Elapsed().InMicroseconds();
523 auto counters = isolate->counters();
524 counters->wasm_lazily_compiled_functions()->Increment();
526 counters->wasm_lazy_compilation_throughput()->AddSample(
527 compilation_time != 0 ? static_cast<int>(func_size / compilation_time)
533 Address CompileLazy(Isolate* isolate, NativeModule* native_module,
535 HistogramTimerScope lazy_time_scope(
536 isolate->counters()->wasm_lazy_compilation_time());
538 DCHECK(!native_module->lazy_compile_frozen());
540 NativeModuleModificationScope native_module_modification_scope(native_module);
542 WasmCode* result = LazyCompileFunction(isolate, native_module, func_index);
543 DCHECK_NOT_NULL(result);
544 DCHECK_EQ(func_index, result->index());
546 return result->instruction_start();
554 class CompilationUnitBuilder {
556 explicit CompilationUnitBuilder(NativeModule* native_module,
557 WasmEngine* wasm_engine)
558 : native_module_(native_module), wasm_engine_(wasm_engine) {}
561 switch (compilation_state()->compile_mode()) {
562 case CompileMode::kTiering:
563 tiering_units_.emplace_back(
564 CreateUnit(func_index, ExecutionTier::kOptimized));
565 baseline_units_.emplace_back(
566 CreateUnit(func_index, ExecutionTier::kBaseline));
568 case CompileMode::kRegular:
569 baseline_units_.emplace_back(CreateUnit(
570 func_index, WasmCompilationUnit::GetDefaultExecutionTier()));
577 if (baseline_units_.empty() && tiering_units_.empty())
return false;
578 compilation_state()->AddCompilationUnits(baseline_units_, tiering_units_);
584 baseline_units_.clear();
585 tiering_units_.clear();
589 std::unique_ptr<WasmCompilationUnit> CreateUnit(
uint32_t func_index,
590 ExecutionTier tier) {
591 return base::make_unique<WasmCompilationUnit>(wasm_engine_, native_module_,
595 CompilationStateImpl* compilation_state()
const {
596 return Impl(native_module_->compilation_state());
599 NativeModule*
const native_module_;
600 WasmEngine*
const wasm_engine_;
601 std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_units_;
602 std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_units_;
605 bool compile_lazy(
const WasmModule* module) {
606 return FLAG_wasm_lazy_compilation ||
607 (FLAG_asm_wasm_lazy_compilation && module->origin == kAsmJsOrigin);
610 byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer,
int offset) {
611 return static_cast<byte*
>(buffer.ToHandleChecked()->backing_store()) + offset;
614 void RecordStats(
const Code code, Counters* counters) {
615 counters->wasm_generated_code_size()->Increment(code->body_size());
616 counters->wasm_reloc_size()->Increment(code->relocation_info()->length());
619 bool in_bounds(
uint32_t offset,
size_t size,
size_t upper) {
620 return offset + size <= upper && offset + size >= offset;
623 using WasmInstanceMap =
624 IdentityMap<Handle<WasmInstanceObject>, FreeStoreAllocationPolicy>;
626 double MonotonicallyIncreasingTimeInMs() {
627 return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
628 base::Time::kMillisecondsPerSecond;
635 bool FetchAndExecuteCompilationUnit(CompilationEnv* env,
636 CompilationStateImpl* compilation_state,
637 WasmFeatures* detected,
638 Counters* counters) {
639 DisallowHeapAccess no_heap_access;
641 std::unique_ptr<WasmCompilationUnit> unit =
642 compilation_state->GetNextCompilationUnit();
643 if (unit ==
nullptr)
return false;
647 ExecutionTier tier = unit->tier();
648 unit->ExecuteCompilation(env, compilation_state->GetSharedWireBytesStorage(),
650 if (!unit->failed()) compilation_state->ScheduleCodeLogging(unit->result());
651 compilation_state->ScheduleUnitForFinishing(std::move(unit), tier);
656 void InitializeCompilationUnits(NativeModule* native_module,
657 WasmEngine* wasm_engine) {
658 ModuleWireBytes wire_bytes(native_module->wire_bytes());
659 const WasmModule* module = native_module->module();
660 CompilationUnitBuilder builder(native_module, wasm_engine);
661 uint32_t start = module->num_imported_functions;
662 uint32_t end = start + module->num_declared_functions;
669 void FinishCompilationUnits(CompilationStateImpl* compilation_state) {
670 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT(
"v8.wasm"),
"FinishCompilationUnits");
671 while (!compilation_state->failed()) {
672 std::unique_ptr<WasmCompilationUnit> unit =
673 compilation_state->GetNextExecutedUnit();
674 if (unit ==
nullptr)
break;
676 if (unit->failed()) {
677 compilation_state->Abort();
682 compilation_state->OnFinishedUnit();
686 void CompileInParallel(Isolate* isolate, NativeModule* native_module) {
711 CanonicalHandleScope canonical(isolate);
713 CompilationStateImpl* compilation_state =
714 Impl(native_module->compilation_state());
718 compilation_state->SetFinisherIsRunning(
true);
720 native_module->num_functions() - native_module->num_imported_functions();
721 compilation_state->SetNumberOfFunctionsToCompile(num_wasm_functions);
728 InitializeCompilationUnits(native_module, isolate->wasm_engine());
736 WasmFeatures detected_features;
737 CompilationEnv env = native_module->CreateCompilationEnv();
738 while (FetchAndExecuteCompilationUnit(&env, compilation_state,
740 isolate->counters()) &&
741 !compilation_state->baseline_compilation_finished()) {
746 FinishCompilationUnits(compilation_state);
748 if (compilation_state->failed())
break;
751 while (!compilation_state->failed()) {
757 FinishCompilationUnits(compilation_state);
759 if (compilation_state->baseline_compilation_finished())
break;
763 compilation_state->PublishDetectedFeatures(isolate, detected_features);
768 if (!compilation_state->failed() &&
769 compilation_state->compile_mode() == CompileMode::kTiering) {
770 compilation_state->SetFinisherIsRunning(
false);
774 void CompileSequentially(Isolate* isolate, NativeModule* native_module,
775 ErrorThrower* thrower) {
776 DCHECK(!thrower->error());
778 ModuleWireBytes wire_bytes(native_module->wire_bytes());
779 const WasmModule* module = native_module->module();
780 WasmFeatures detected = kNoWasmFeatures;
781 for (
uint32_t i = 0;
i < module->functions.size(); ++
i) {
782 const WasmFunction& func = module->functions[
i];
783 if (func.imported)
continue;
786 bool success = WasmCompilationUnit::CompileWasmFunction(
787 isolate, native_module, &detected, &func);
789 thrower->CompileFailed(
790 Impl(native_module->compilation_state())->GetCompileError());
794 UpdateFeatureUseCounts(isolate, detected);
797 void ValidateSequentially(Isolate* isolate, NativeModule* native_module,
798 ErrorThrower* thrower) {
799 DCHECK(!thrower->error());
801 ModuleWireBytes wire_bytes(native_module->wire_bytes());
802 const WasmModule* module = native_module->module();
803 uint32_t start = module->num_imported_functions;
804 uint32_t end = start + module->num_declared_functions;
806 const WasmFunction& func = module->functions[
i];
808 const byte* base = wire_bytes.start();
809 FunctionBody body{func.sig, func.code.offset(), base + func.code.offset(),
810 base + func.code.end_offset()};
813 auto time_counter = SELECT_WASM_COUNTER(
814 isolate->counters(), module->origin, wasm_decode, function_time);
816 TimedHistogramScope wasm_decode_function_time_scope(time_counter);
817 WasmFeatures detected;
818 result = VerifyWasmCode(isolate->allocator(),
819 native_module->enabled_features(), module,
822 if (result.failed()) {
823 TruncatedUserString<> name(wire_bytes.GetNameOrNull(&func, module));
824 thrower->CompileError(
"Compiling function #%d:%.*s failed: %s @+%u",
i,
825 name.length(), name.start(),
826 result.error_msg().c_str(), result.error_offset());
832 void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
833 const WasmModule* wasm_module,
834 NativeModule* native_module) {
835 ModuleWireBytes wire_bytes(native_module->wire_bytes());
837 if (compile_lazy(wasm_module)) {
838 if (wasm_module->origin == kWasmOrigin) {
845 ValidateSequentially(isolate, native_module, thrower);
846 if (thrower->error())
return;
849 native_module->SetLazyBuiltin(BUILTIN_CODE(isolate, WasmCompileLazy));
851 size_t funcs_to_compile =
852 wasm_module->functions.size() - wasm_module->num_imported_functions;
853 bool compile_parallel =
854 !FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks > 0 &&
855 funcs_to_compile > 1 &&
856 V8::GetCurrentPlatform()->NumberOfWorkerThreads() > 0;
858 if (compile_parallel) {
859 CompileInParallel(isolate, native_module);
861 CompileSequentially(isolate, native_module, thrower);
863 auto* compilation_state = Impl(native_module->compilation_state());
864 if (compilation_state->failed()) {
865 thrower->CompileFailed(compilation_state->GetCompileError());
872 class FinishCompileTask :
public CancelableTask {
874 explicit FinishCompileTask(CompilationStateImpl* compilation_state,
875 CancelableTaskManager* task_manager)
876 : CancelableTask(task_manager), compilation_state_(compilation_state) {}
878 void RunInternal()
override {
879 Isolate* isolate = compilation_state_->isolate();
880 HandleScope scope(isolate);
881 SaveContext saved_context(isolate);
882 isolate->set_context(Context());
884 TRACE_COMPILE(
"(4a) Finishing compilation units...\n");
885 if (compilation_state_->failed()) {
886 compilation_state_->SetFinisherIsRunning(
false);
891 double deadline = MonotonicallyIncreasingTimeInMs() + 1.0;
893 compilation_state_->RestartBackgroundTasks();
895 std::unique_ptr<WasmCompilationUnit> unit =
896 compilation_state_->GetNextExecutedUnit();
898 if (unit ==
nullptr) {
902 compilation_state_->SetFinisherIsRunning(
false);
903 if (compilation_state_->HasCompilationUnitToFinish() &&
904 compilation_state_->SetFinisherIsRunning(
true)) {
910 DCHECK_IMPLIES(unit->failed(), compilation_state_->failed());
911 if (unit->failed())
break;
915 compilation_state_->OnFinishedUnit();
917 if (deadline < MonotonicallyIncreasingTimeInMs()) {
921 compilation_state_->ScheduleFinisherTask();
928 CompilationStateImpl* compilation_state_;
932 class BackgroundCompileTask :
public CancelableTask {
934 explicit BackgroundCompileTask(CancelableTaskManager* task_manager,
935 NativeModule* native_module,
937 : CancelableTask(task_manager),
938 native_module_(native_module),
939 counters_(counters) {}
941 void RunInternal()
override {
942 TRACE_COMPILE(
"(3b) Compiling...\n");
943 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT(
"v8.wasm"),
944 "BackgroundCompileTask::RunInternal");
947 CompilationEnv env = native_module_->CreateCompilationEnv();
948 auto* compilation_state = Impl(native_module_->compilation_state());
949 WasmFeatures detected_features = kNoWasmFeatures;
950 while (!compilation_state->failed()) {
951 if (!FetchAndExecuteCompilationUnit(&env, compilation_state,
952 &detected_features, counters_)) {
956 compilation_state->OnBackgroundTaskStopped(detected_features);
960 NativeModule*
const native_module_;
961 Counters*
const counters_;
966 std::unique_ptr<NativeModule> CompileToNativeModule(
967 Isolate* isolate,
const WasmFeatures& enabled, ErrorThrower* thrower,
968 std::shared_ptr<const WasmModule> module,
const ModuleWireBytes& wire_bytes,
969 Handle<FixedArray>* export_wrappers_out) {
970 const WasmModule* wasm_module = module.get();
971 TimedHistogramScope wasm_compile_module_time_scope(SELECT_WASM_COUNTER(
972 isolate->counters(), wasm_module->origin, wasm_compile, module_time));
975 if (wasm_module->has_shared_memory) {
976 isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
978 int export_wrapper_size =
static_cast<int>(module->num_exported_functions);
982 OwnedVector<uint8_t> wire_bytes_copy =
983 OwnedVector<uint8_t>::Of(wire_bytes.module_bytes());
986 size_t code_size_estimate =
987 wasm::WasmCodeManager::EstimateNativeModuleCodeSize(module.get());
990 auto native_module = isolate->wasm_engine()->code_manager()->NewNativeModule(
991 isolate, enabled, code_size_estimate,
992 wasm::NativeModule::kCanAllocateMoreMemory, std::move(module));
993 native_module->SetWireBytes(std::move(wire_bytes_copy));
994 native_module->SetRuntimeStubs(isolate);
996 CompileNativeModule(isolate, thrower, wasm_module, native_module.get());
997 if (thrower->error())
return {};
1000 *export_wrappers_out =
1001 isolate->factory()->NewFixedArray(export_wrapper_size, TENURED);
1002 CompileJsToWasmWrappers(isolate, native_module.get(), *export_wrappers_out);
1005 native_module->LogWasmCodes(isolate);
1007 return native_module;
1010 InstanceBuilder::InstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
1011 Handle<WasmModuleObject> module_object,
1012 MaybeHandle<JSReceiver> ffi,
1013 MaybeHandle<JSArrayBuffer> memory)
1014 : isolate_(isolate),
1015 enabled_(module_object->native_module()->enabled_features()),
1016 module_(module_object->module()),
1018 module_object_(module_object),
1021 sanitized_imports_.reserve(module_->import_table.size());
1025 MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
1026 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT(
"v8.wasm"),
"InstanceBuilder::Build");
1029 if (!module_->import_table.empty() && ffi_.is_null()) {
1030 thrower_->TypeError(
1031 "Imports argument must be present and must be an object");
1036 if (thrower_->error())
return {};
1039 CodeSpaceMemoryModificationScope modification_scope(isolate_->heap());
1041 DisallowJavascriptExecution no_js(isolate_);
1043 TimedHistogramScope wasm_instantiate_module_time_scope(SELECT_WASM_COUNTER(
1044 isolate_->counters(), module_->origin, wasm_instantiate, module_time));
1051 uint32_t initial_pages = module_->initial_pages;
1052 auto initial_pages_counter = SELECT_WASM_COUNTER(
1053 isolate_->counters(), module_->origin, wasm, min_mem_pages_count);
1054 initial_pages_counter->AddSample(initial_pages);
1057 if (memory_.is_null()) {
1058 memory_ = FindImportedMemoryBuffer();
1060 if (!memory_.is_null()) {
1062 Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
1063 memory->set_is_neuterable(
false);
1065 DCHECK_IMPLIES(use_trap_handler(), module_->origin == kAsmJsOrigin ||
1066 memory->is_wasm_memory() ||
1067 memory->backing_store() ==
nullptr);
1068 }
else if (initial_pages > 0 || use_trap_handler()) {
1073 memory_ = AllocateMemory(initial_pages);
1074 if (memory_.is_null()) {
1076 DCHECK(isolate_->has_pending_exception() || thrower_->error());
1084 if (module_->origin == kWasmOrigin && use_trap_handler()) {
1086 WasmMemoryTracker*
const memory_tracker =
1087 isolate_->wasm_engine()->memory_tracker();
1089 if (!memory_tracker->HasFullGuardRegions(
1090 memory_.ToHandleChecked()->backing_store())) {
1091 if (!FLAG_wasm_trap_handler_fallback) {
1092 thrower_->LinkError(
1093 "Provided memory is lacking guard regions but fallback was " 1098 TRACE(
"Recompiling module without bounds checks\n");
1099 constexpr
bool allow_trap_handler =
false;
1101 USE(allow_trap_handler);
1103 NativeModule* native_module = module_object_->native_module();
1104 native_module->DisableTrapHandler();
1107 ErrorThrower thrower(isolate_,
"recompile");
1108 CompileNativeModule(isolate_, &thrower, module_, native_module);
1109 if (thrower.error()) {
1112 DCHECK(!native_module->use_trap_handler());
1119 NativeModule* native_module = module_object_->native_module();
1120 TRACE(
"New module instantiation for %p\n", native_module);
1121 Handle<WasmInstanceObject> instance =
1122 WasmInstanceObject::New(isolate_, module_object_);
1123 NativeModuleModificationScope native_modification_scope(native_module);
1128 uint32_t globals_buffer_size = module_->globals_buffer_size;
1129 if (globals_buffer_size > 0) {
1130 void* backing_store =
1131 isolate_->array_buffer_allocator()->Allocate(globals_buffer_size);
1132 if (backing_store ==
nullptr) {
1133 thrower_->RangeError(
"Out of memory: wasm globals");
1137 isolate_->factory()->NewJSArrayBuffer(SharedFlag::kNotShared, TENURED);
1138 constexpr
bool is_external =
false;
1139 constexpr
bool is_wasm_memory =
false;
1140 JSArrayBuffer::Setup(globals_, isolate_, is_external, backing_store,
1141 globals_buffer_size, SharedFlag::kNotShared,
1143 if (globals_.is_null()) {
1144 thrower_->RangeError(
"Out of memory: wasm globals");
1147 instance->set_globals_start(
1148 reinterpret_cast<byte*>(globals_->backing_store()));
1149 instance->set_globals_buffer(*globals_);
1155 if (module_->num_imported_mutable_globals > 0) {
1159 Handle<FixedArray> buffers_array = isolate_->factory()->NewFixedArray(
1160 module_->num_imported_mutable_globals, TENURED);
1161 instance->set_imported_mutable_globals_buffers(*buffers_array);
1167 int exceptions_count =
static_cast<int>(module_->exceptions.size());
1168 if (exceptions_count > 0) {
1169 Handle<FixedArray> exception_table =
1170 isolate_->factory()->NewFixedArray(exceptions_count, TENURED);
1171 instance->set_exceptions_table(*exception_table);
1172 exception_wrappers_.resize(exceptions_count);
1178 int table_count =
static_cast<int>(module_->tables.size());
1179 table_instances_.resize(table_count);
1184 int num_imported_functions = ProcessImports(instance);
1185 if (num_imported_functions < 0)
return {};
1195 if (table_count > 0) {
1196 InitializeTables(instance);
1202 if (exceptions_count > 0) {
1203 InitializeExceptions(instance);
1209 if (module_->has_memory) {
1210 if (!instance->has_memory_object()) {
1212 Handle<WasmMemoryObject> memory_object = WasmMemoryObject::New(
1214 module_->maximum_pages != 0 ? module_->maximum_pages : -1);
1215 instance->set_memory_object(*memory_object);
1219 Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate_);
1220 WasmMemoryObject::AddInstance(isolate_, memory_object, instance);
1222 if (!memory_.is_null()) {
1224 Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
1225 CHECK_EQ(instance->memory_size(), memory->byte_length());
1226 CHECK_EQ(instance->memory_start(), memory->backing_store());
1233 for (
const WasmTableInit& table_init : module_->table_inits) {
1234 if (!table_init.active)
continue;
1235 DCHECK(table_init.table_index < table_instances_.size());
1236 uint32_t base = EvalUint32InitExpr(table_init.offset);
1237 size_t table_size = table_instances_[table_init.table_index].table_size;
1238 if (!in_bounds(base, table_init.entries.size(), table_size)) {
1239 thrower_->LinkError(
"table initializer is out of bounds");
1247 for (
const WasmDataSegment& seg : module_->data_segments) {
1248 if (!seg.active)
continue;
1249 uint32_t base = EvalUint32InitExpr(seg.dest_addr);
1250 if (!in_bounds(base, seg.source.length(), instance->memory_size())) {
1251 thrower_->LinkError(
"data segment is out of bounds");
1259 ProcessExports(instance);
1260 if (thrower_->error())
return {};
1265 if (table_count > 0) {
1266 LoadTableSegments(instance);
1272 if (module_->data_segments.size() > 0) {
1273 LoadDataSegments(instance);
1280 WasmModuleObject::SetBreakpointsOnNewInstance(module_object_, instance);
1282 if (FLAG_wasm_interpret_all && module_->origin == kWasmOrigin) {
1283 Handle<WasmDebugInfo> debug_info =
1284 WasmInstanceObject::GetOrCreateDebugInfo(instance);
1285 std::vector<int> func_indexes;
1286 for (
int func_index = num_imported_functions,
1287 num_wasm_functions = static_cast<int>(module_->functions.size());
1288 func_index < num_wasm_functions; ++func_index) {
1289 func_indexes.push_back(func_index);
1291 WasmDebugInfo::RedirectToInterpreter(debug_info, VectorOf(func_indexes));
1297 if (module_->start_function_index >= 0) {
1298 int start_index = module_->start_function_index;
1299 auto&
function = module_->functions[start_index];
1300 Handle<Code> wrapper_code = js_to_wasm_cache_.GetOrCompileJSToWasmWrapper(
1301 isolate_,
function.sig,
function.imported);
1304 start_function_ = WasmExportedFunction::New(
1305 isolate_, instance, MaybeHandle<String>(), start_index,
1306 static_cast<int>(
function.sig->parameter_count()), wrapper_code);
1309 DCHECK(!isolate_->has_pending_exception());
1310 TRACE(
"Successfully built instance for module %p\n",
1311 module_object_->native_module());
1315 bool InstanceBuilder::ExecuteStartFunction() {
1316 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT(
"v8.wasm"),
1317 "InstanceBuilder::ExecuteStartFunction");
1318 if (start_function_.is_null())
return true;
1320 HandleScope scope(isolate_);
1322 Handle<Object> undefined = isolate_->factory()->undefined_value();
1323 MaybeHandle<Object> retval =
1324 Execution::Call(isolate_, start_function_, undefined, 0,
nullptr);
1326 if (retval.is_null()) {
1327 DCHECK(isolate_->has_pending_exception());
1334 MaybeHandle<Object> InstanceBuilder::LookupImport(
uint32_t index,
1335 Handle<String> module_name,
1337 Handle<String> import_name) {
1340 DCHECK(!ffi_.is_null());
1343 MaybeHandle<Object> result = Object::GetPropertyOrElement(
1344 isolate_, ffi_.ToHandleChecked(), module_name);
1345 if (result.is_null()) {
1346 return ReportTypeError(
"module not found", index, module_name);
1349 Handle<Object> module = result.ToHandleChecked();
1352 if (!module->IsJSReceiver()) {
1353 return ReportTypeError(
"module is not an object or function", index,
1357 result = Object::GetPropertyOrElement(isolate_, module, import_name);
1358 if (result.is_null()) {
1359 ReportLinkError(
"import not found", index, module_name, import_name);
1360 return MaybeHandle<JSFunction>();
1370 MaybeHandle<Object> InstanceBuilder::LookupImportAsm(
1371 uint32_t index, Handle<String> import_name) {
1373 if (ffi_.is_null()) {
1374 return ReportLinkError(
"missing imports object", index, import_name);
1380 Handle<Object> result;
1381 LookupIterator it = LookupIterator::PropertyOrElement(
1382 isolate_, ffi_.ToHandleChecked(), import_name);
1383 switch (it.state()) {
1384 case LookupIterator::ACCESS_CHECK:
1385 case LookupIterator::INTEGER_INDEXED_EXOTIC:
1386 case LookupIterator::INTERCEPTOR:
1387 case LookupIterator::JSPROXY:
1388 case LookupIterator::ACCESSOR:
1389 case LookupIterator::TRANSITION:
1390 return ReportLinkError(
"not a data property", index, import_name);
1391 case LookupIterator::NOT_FOUND:
1394 result = isolate_->factory()->undefined_value();
1396 case LookupIterator::DATA:
1397 result = it.GetDataValue();
1404 uint32_t InstanceBuilder::EvalUint32InitExpr(
const WasmInitExpr& expr) {
1405 switch (expr.kind) {
1406 case WasmInitExpr::kI32Const:
1407 return expr.val.i32_const;
1408 case WasmInitExpr::kGlobalIndex: {
1409 uint32_t offset = module_->globals[expr.val.global_index].offset;
1410 return ReadLittleEndianValue<uint32_t>(
1411 reinterpret_cast<Address
>(raw_buffer_ptr(globals_, offset)));
1419 void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
1420 Vector<const uint8_t> wire_bytes =
1421 module_object_->native_module()->wire_bytes();
1422 for (
const WasmDataSegment& segment : module_->data_segments) {
1423 uint32_t source_size = segment.source.length();
1425 if (source_size == 0)
continue;
1427 if (!segment.active)
continue;
1428 uint32_t dest_offset = EvalUint32InitExpr(segment.dest_addr);
1429 DCHECK(in_bounds(dest_offset, source_size, instance->memory_size()));
1430 byte* dest = instance->memory_start() + dest_offset;
1431 const byte* src = wire_bytes.start() + segment.source.offset();
1432 memcpy(dest, src, source_size);
1436 void InstanceBuilder::WriteGlobalValue(
const WasmGlobal& global,
double num) {
1437 TRACE(
"init [globals_start=%p + %u] = %lf, type = %s\n",
1438 reinterpret_cast<void*>(raw_buffer_ptr(globals_, 0)), global.offset,
1439 num, ValueTypes::TypeName(global.type));
1440 switch (global.type) {
1442 WriteLittleEndianValue<int32_t>(GetRawGlobalPtr<int32_t>(global),
1443 static_cast<int32_t>(num));
1450 WriteLittleEndianValue<float>(GetRawGlobalPtr<float>(global),
1451 static_cast<float>(num));
1454 WriteLittleEndianValue<double>(GetRawGlobalPtr<double>(global),
1455 static_cast<double>(num));
1462 void InstanceBuilder::WriteGlobalValue(
const WasmGlobal& global,
1463 Handle<WasmGlobalObject> value) {
1464 TRACE(
"init [globals_start=%p + %u] = ",
1465 reinterpret_cast<void*>(raw_buffer_ptr(globals_, 0)), global.offset);
1466 switch (global.type) {
1468 int32_t num = value->GetI32();
1469 WriteLittleEndianValue<int32_t>(GetRawGlobalPtr<int32_t>(global), num);
1474 int64_t num = value->GetI64();
1475 WriteLittleEndianValue<int64_t>(GetRawGlobalPtr<int64_t>(global), num);
1476 TRACE(
"%" PRId64, num);
1480 float num = value->GetF32();
1481 WriteLittleEndianValue<float>(GetRawGlobalPtr<float>(global), num);
1486 double num = value->GetF64();
1487 WriteLittleEndianValue<double>(GetRawGlobalPtr<double>(global), num);
1494 TRACE(
", type = %s (from WebAssembly.Global)\n",
1495 ValueTypes::TypeName(global.type));
1498 void InstanceBuilder::SanitizeImports() {
1499 Vector<const uint8_t> wire_bytes =
1500 module_object_->native_module()->wire_bytes();
1501 for (
size_t index = 0; index < module_->import_table.size(); ++index) {
1502 const WasmImport&
import = module_->import_table[index];
1504 Handle<String> module_name;
1505 MaybeHandle<String> maybe_module_name =
1506 WasmModuleObject::ExtractUtf8StringFromModuleBytes(isolate_, wire_bytes,
1507 import.module_name);
1508 if (!maybe_module_name.ToHandle(&module_name)) {
1509 thrower_->LinkError(
"Could not resolve module name for import %zu",
1514 Handle<String> import_name;
1515 MaybeHandle<String> maybe_import_name =
1516 WasmModuleObject::ExtractUtf8StringFromModuleBytes(isolate_, wire_bytes,
1518 if (!maybe_import_name.ToHandle(&import_name)) {
1519 thrower_->LinkError(
"Could not resolve import name for import %zu",
1524 int int_index =
static_cast<int>(index);
1525 MaybeHandle<Object> result =
1526 module_->origin == kAsmJsOrigin
1527 ? LookupImportAsm(int_index, import_name)
1528 : LookupImport(int_index, module_name, import_name);
1529 if (thrower_->error()) {
1530 thrower_->LinkError(
"Could not find value for import %zu", index);
1533 Handle<Object> value = result.ToHandleChecked();
1534 sanitized_imports_.push_back({module_name, import_name, value});
1538 MaybeHandle<JSArrayBuffer> InstanceBuilder::FindImportedMemoryBuffer()
const {
1539 DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
1540 for (
size_t index = 0; index < module_->import_table.size(); index++) {
1541 const WasmImport&
import = module_->import_table[index];
1543 if (
import.kind == kExternalMemory) {
1544 const auto& value = sanitized_imports_[index].value;
1545 if (!value->IsWasmMemoryObject()) {
1548 auto memory = Handle<WasmMemoryObject>::cast(value);
1549 Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate_);
1559 int InstanceBuilder::ProcessImports(Handle<WasmInstanceObject> instance) {
1560 int num_imported_functions = 0;
1561 int num_imported_tables = 0;
1562 int num_imported_mutable_globals = 0;
1564 DCHECK_EQ(module_->import_table.size(), sanitized_imports_.size());
1565 int num_imports =
static_cast<int>(module_->import_table.size());
1566 NativeModule* native_module = instance->module_object()->native_module();
1567 for (
int index = 0; index < num_imports; ++index) {
1568 const WasmImport&
import = module_->import_table[index];
1570 Handle<String> module_name = sanitized_imports_[index].module_name;
1571 Handle<String> import_name = sanitized_imports_[index].import_name;
1572 Handle<Object> value = sanitized_imports_[index].value;
1574 switch (
import.kind) {
1575 case kExternalFunction: {
1577 if (!value->IsCallable()) {
1578 ReportLinkError(
"function import requires a callable", index,
1579 module_name, import_name);
1582 uint32_t func_index =
import.index;
1583 DCHECK_EQ(num_imported_functions, func_index);
1584 auto js_receiver = Handle<JSReceiver>::cast(value);
1585 FunctionSig* expected_sig = module_->functions[func_index].sig;
1586 auto kind = compiler::GetWasmImportCallKind(js_receiver, expected_sig);
1588 case compiler::WasmImportCallKind::kLinkError:
1590 "imported function does not match the expected type", index,
1591 module_name, import_name);
1593 case compiler::WasmImportCallKind::kWasmToWasm: {
1595 auto imported_function = Handle<WasmExportedFunction>::cast(value);
1596 Handle<WasmInstanceObject> imported_instance(
1597 imported_function->instance(), isolate_);
1599 Address imported_target = imported_function->GetWasmCallTarget();
1600 ImportedFunctionEntry entry(instance, func_index);
1601 entry.SetWasmToWasm(*imported_instance, imported_target);
1606 WasmCode* wasm_code =
1607 native_module->import_wrapper_cache()->GetOrCompile(
1608 isolate_, kind, expected_sig);
1609 ImportedFunctionEntry entry(instance, func_index);
1610 if (wasm_code->kind() == WasmCode::kWasmToJsWrapper) {
1612 entry.SetWasmToJs(isolate_, js_receiver, wasm_code);
1616 compiler::WasmImportCallKind::kFirstMathIntrinsic &&
1617 kind <= compiler::WasmImportCallKind::kLastMathIntrinsic);
1618 entry.SetWasmToWasm(*instance, wasm_code->instruction_start());
1623 num_imported_functions++;
1626 case kExternalTable: {
1627 if (!value->IsWasmTableObject()) {
1628 ReportLinkError(
"table import requires a WebAssembly.Table", index,
1629 module_name, import_name);
1633 DCHECK_EQ(table_num, num_imported_tables);
1634 const WasmTable& table = module_->tables[table_num];
1635 TableInstance& table_instance = table_instances_[table_num];
1636 table_instance.table_object = Handle<WasmTableObject>::cast(value);
1637 instance->set_table_object(*table_instance.table_object);
1638 table_instance.js_wrappers = Handle<FixedArray>(
1639 table_instance.table_object->functions(), isolate_);
1641 int imported_table_size = table_instance.js_wrappers->length();
1642 if (imported_table_size < static_cast<int>(table.initial_size)) {
1643 thrower_->LinkError(
1644 "table import %d is smaller than initial %d, got %u", index,
1645 table.initial_size, imported_table_size);
1649 if (table.has_maximum_size) {
1650 int64_t imported_maximum_size =
1651 table_instance.table_object->maximum_length()->Number();
1652 if (imported_maximum_size < 0) {
1653 thrower_->LinkError(
1654 "table import %d has no maximum length, expected %d", index,
1655 table.maximum_size);
1658 if (imported_maximum_size > table.maximum_size) {
1659 thrower_->LinkError(
1660 " table import %d has a larger maximum size %" PRIx64
1661 " than the module's declared maximum %u",
1662 index, imported_maximum_size, table.maximum_size);
1668 if (!instance->has_indirect_function_table()) {
1669 WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
1670 instance, imported_table_size);
1671 table_instances_[table_num].table_size = imported_table_size;
1675 for (
int i = 0;
i < imported_table_size; ++
i) {
1676 Handle<Object> val(table_instance.js_wrappers->get(
i), isolate_);
1680 if (!val->IsJSFunction())
continue;
1681 if (!WasmExportedFunction::IsWasmExportedFunction(*val)) {
1682 thrower_->LinkError(
"table import %d[%d] is not a wasm function",
1686 auto target_func = Handle<WasmExportedFunction>::cast(val);
1687 Handle<WasmInstanceObject> target_instance =
1688 handle(target_func->instance(), isolate_);
1692 FunctionSig* sig = target_func->sig();
1693 IndirectFunctionTableEntry(instance,
i)
1694 .Set(module_->signature_map.Find(*sig), target_instance,
1695 target_func->function_index());
1697 num_imported_tables++;
1700 case kExternalMemory: {
1703 DCHECK(!instance->has_memory_object());
1704 if (!value->IsWasmMemoryObject()) {
1705 ReportLinkError(
"memory import must be a WebAssembly.Memory object",
1706 index, module_name, import_name);
1709 auto memory = Handle<WasmMemoryObject>::cast(value);
1710 instance->set_memory_object(*memory);
1711 Handle<JSArrayBuffer> buffer(memory->array_buffer(), isolate_);
1713 DCHECK_EQ(*memory_.ToHandleChecked(), *buffer);
1715 static_cast<uint32_t>(buffer->byte_length() / kWasmPageSize);
1716 if (imported_cur_pages < module_->initial_pages) {
1717 thrower_->LinkError(
1718 "memory import %d is smaller than initial %u, got %u", index,
1719 module_->initial_pages, imported_cur_pages);
1721 int32_t imported_maximum_pages = memory->maximum_pages();
1722 if (module_->has_maximum_pages) {
1723 if (imported_maximum_pages < 0) {
1724 thrower_->LinkError(
1725 "memory import %d has no maximum limit, expected at most %u",
1726 index, imported_maximum_pages);
1729 if (static_cast<uint32_t>(imported_maximum_pages) >
1730 module_->maximum_pages) {
1731 thrower_->LinkError(
1732 "memory import %d has a larger maximum size %u than the " 1733 "module's declared maximum %u",
1734 index, imported_maximum_pages, module_->maximum_pages);
1738 if (module_->has_shared_memory != buffer->is_shared()) {
1739 thrower_->LinkError(
1740 "mismatch in shared state of memory, declared = %d, imported = " 1742 module_->has_shared_memory, buffer->is_shared());
1748 case kExternalGlobal: {
1755 const WasmGlobal& global = module_->globals[
import.index];
1759 if (global.type == kWasmI64 &&
1760 !(enabled_.mut_global && value->IsWasmGlobalObject())) {
1761 ReportLinkError(
"global import cannot have type i64", index,
1762 module_name, import_name);
1765 if (module_->origin == kAsmJsOrigin) {
1772 if (value->IsJSFunction()) value = isolate_->factory()->nan_value();
1773 if (value->IsPrimitive() && !value->IsSymbol()) {
1774 if (global.type == kWasmI32) {
1775 value = Object::ToInt32(isolate_, value).ToHandleChecked();
1777 value = Object::ToNumber(isolate_, value).ToHandleChecked();
1781 if (enabled_.mut_global) {
1782 if (value->IsWasmGlobalObject()) {
1783 auto global_object = Handle<WasmGlobalObject>::cast(value);
1784 if (global_object->type() != global.type) {
1786 "imported global does not match the expected type", index,
1787 module_name, import_name);
1790 if (global_object->is_mutable() != global.mutability) {
1792 "imported global does not match the expected mutability",
1793 index, module_name, import_name);
1796 if (global.mutability) {
1797 Handle<JSArrayBuffer> buffer(global_object->array_buffer(),
1799 int index = num_imported_mutable_globals++;
1800 instance->imported_mutable_globals_buffers()->set(index, *buffer);
1804 instance->imported_mutable_globals()[index] =
1805 reinterpret_cast<Address
>(
1806 raw_buffer_ptr(buffer, global_object->offset()));
1808 WriteGlobalValue(global, global_object);
1810 }
else if (value->IsNumber()) {
1811 if (global.mutability) {
1813 "imported mutable global must be a WebAssembly.Global object",
1814 index, module_name, import_name);
1817 WriteGlobalValue(global, value->Number());
1820 "global import must be a number or WebAssembly.Global object",
1821 index, module_name, import_name);
1825 if (value->IsNumber()) {
1826 WriteGlobalValue(global, value->Number());
1828 ReportLinkError(
"global import must be a number", index,
1829 module_name, import_name);
1835 case kExternalException: {
1836 if (!value->IsWasmExceptionObject()) {
1837 ReportLinkError(
"exception import requires a WebAssembly.Exception",
1838 index, module_name, import_name);
1841 Handle<WasmExceptionObject> imported_exception =
1842 Handle<WasmExceptionObject>::cast(value);
1843 if (!imported_exception->IsSignatureEqual(
1844 module_->exceptions[
import.index].sig)) {
1845 ReportLinkError(
"imported exception does not match the expected type",
1846 index, module_name, import_name);
1849 Object* exception_tag = imported_exception->exception_tag();
1850 DCHECK(instance->exceptions_table()->get(
import.index)->IsUndefined());
1851 instance->exceptions_table()->set(
import.index, exception_tag);
1852 exception_wrappers_[
import.index] = imported_exception;
1861 DCHECK_EQ(module_->num_imported_mutable_globals,
1862 num_imported_mutable_globals);
1864 return num_imported_functions;
1867 template <
typename T>
1868 T* InstanceBuilder::GetRawGlobalPtr(
const WasmGlobal& global) {
1869 return reinterpret_cast<T*
>(raw_buffer_ptr(globals_, global.offset));
1873 void InstanceBuilder::InitGlobals() {
1874 for (
auto global : module_->globals) {
1875 if (global.mutability && global.imported) {
1879 switch (global.init.kind) {
1880 case WasmInitExpr::kI32Const:
1881 WriteLittleEndianValue<int32_t>(GetRawGlobalPtr<int32_t>(global),
1882 global.init.val.i32_const);
1884 case WasmInitExpr::kI64Const:
1885 WriteLittleEndianValue<int64_t>(GetRawGlobalPtr<int64_t>(global),
1886 global.init.val.i64_const);
1888 case WasmInitExpr::kF32Const:
1889 WriteLittleEndianValue<float>(GetRawGlobalPtr<float>(global),
1890 global.init.val.f32_const);
1892 case WasmInitExpr::kF64Const:
1893 WriteLittleEndianValue<double>(GetRawGlobalPtr<double>(global),
1894 global.init.val.f64_const);
1896 case WasmInitExpr::kGlobalIndex: {
1898 uint32_t new_offset = global.offset;
1900 module_->globals[global.init.val.global_index].offset;
1901 TRACE(
"init [globals+%u] = [globals+%d]\n", global.offset, old_offset);
1902 size_t size = (global.type == kWasmI64 || global.type == kWasmF64)
1905 memcpy(raw_buffer_ptr(globals_, new_offset),
1906 raw_buffer_ptr(globals_, old_offset), size);
1909 case WasmInitExpr::kNone:
1920 Handle<JSArrayBuffer> InstanceBuilder::AllocateMemory(
uint32_t num_pages) {
1921 if (num_pages > max_mem_pages()) {
1922 thrower_->RangeError(
"Out of memory: wasm memory too large");
1923 return Handle<JSArrayBuffer>::null();
1925 const bool is_shared_memory = module_->has_shared_memory && enabled_.threads;
1926 SharedFlag shared_flag =
1927 is_shared_memory ? SharedFlag::kShared : SharedFlag::kNotShared;
1928 Handle<JSArrayBuffer> mem_buffer;
1929 if (!NewArrayBuffer(isolate_, num_pages * kWasmPageSize, shared_flag)
1930 .ToHandle(&mem_buffer)) {
1931 thrower_->RangeError(
"Out of memory: wasm memory");
1936 bool InstanceBuilder::NeedsWrappers()
const {
1937 if (module_->num_exported_functions > 0)
return true;
1938 for (
auto& table_instance : table_instances_) {
1939 if (!table_instance.js_wrappers.is_null())
return true;
1941 for (
auto& table : module_->tables) {
1942 if (table.exported)
return true;
1949 void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
1950 Handle<FixedArray> export_wrappers(module_object_->export_wrappers(),
1952 if (NeedsWrappers()) {
1954 js_wrappers_.insert(js_wrappers_.begin(), module_->functions.size(),
1955 Handle<JSFunction>::null());
1960 for (
int index = 0, end = static_cast<int>(module_->import_table.size());
1961 index < end; ++index) {
1962 const WasmImport&
import = module_->import_table[index];
1963 if (
import.kind == kExternalFunction) {
1964 Handle<Object> value = sanitized_imports_[index].value;
1965 if (WasmExportedFunction::IsWasmExportedFunction(*value)) {
1966 js_wrappers_[
import.index] = Handle<JSFunction>::cast(value);
1972 Handle<JSObject> exports_object;
1973 bool is_asm_js =
false;
1974 switch (module_->origin) {
1977 exports_object = isolate_->factory()->NewJSObjectWithNullProto();
1980 case kAsmJsOrigin: {
1981 Handle<JSFunction> object_function = Handle<JSFunction>(
1982 isolate_->native_context()->object_function(), isolate_);
1983 exports_object = isolate_->factory()->NewJSObject(object_function);
1990 instance->set_exports_object(*exports_object);
1992 Handle<String> single_function_name =
1993 isolate_->factory()->InternalizeUtf8String(AsmJs::kSingleFunctionName);
1995 PropertyDescriptor desc;
1996 desc.set_writable(is_asm_js);
1997 desc.set_enumerable(
true);
1998 desc.set_configurable(is_asm_js);
2001 int export_index = 0;
2002 for (
const WasmExport& exp : module_->export_table) {
2003 Handle<String> name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
2004 isolate_, module_object_, exp.name)
2006 Handle<JSObject> export_to;
2007 if (is_asm_js && exp.kind == kExternalFunction &&
2008 String::Equals(isolate_, name, single_function_name)) {
2009 export_to = instance;
2011 export_to = exports_object;
2015 case kExternalFunction: {
2017 const WasmFunction&
function = module_->functions[exp.index];
2018 Handle<JSFunction> js_function = js_wrappers_[exp.index];
2019 if (js_function.is_null()) {
2021 Handle<Code> export_code =
2022 export_wrappers->GetValueChecked<Code>(isolate_, export_index);
2023 MaybeHandle<String> func_name;
2026 WireBytesRef func_name_ref = module_->LookupFunctionName(
2027 module_object_->native_module()->wire_bytes(),
2028 function.func_index);
2029 func_name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
2030 isolate_, module_object_, func_name_ref)
2033 js_function = WasmExportedFunction::New(
2034 isolate_, instance, func_name,
function.func_index,
2035 static_cast<int>(
function.sig->parameter_count()), export_code);
2036 js_wrappers_[exp.index] = js_function;
2038 desc.set_value(js_function);
2042 case kExternalTable: {
2044 TableInstance& table_instance = table_instances_[exp.index];
2045 const WasmTable& table = module_->tables[exp.index];
2046 if (table_instance.table_object.is_null()) {
2047 uint32_t maximum = table.has_maximum_size ? table.maximum_size
2048 : FLAG_wasm_max_table_size;
2049 table_instance.table_object =
2050 WasmTableObject::New(isolate_, table.initial_size, maximum,
2051 &table_instance.js_wrappers);
2053 desc.set_value(table_instance.table_object);
2056 case kExternalMemory: {
2060 DCHECK(instance->has_memory_object());
2062 Handle<WasmMemoryObject>(instance->memory_object(), isolate_));
2065 case kExternalGlobal: {
2066 const WasmGlobal& global = module_->globals[exp.index];
2067 if (enabled_.mut_global) {
2068 Handle<JSArrayBuffer> buffer;
2071 if (global.mutability && global.imported) {
2072 Handle<FixedArray> buffers_array(
2073 instance->imported_mutable_globals_buffers(), isolate_);
2074 buffer = buffers_array->GetValueChecked<JSArrayBuffer>(
2075 isolate_, global.index);
2076 Address global_addr =
2077 instance->imported_mutable_globals()[global.index];
2079 size_t buffer_size = buffer->byte_length();
2080 Address backing_store =
2081 reinterpret_cast<Address
>(buffer->backing_store());
2082 CHECK(global_addr >= backing_store &&
2083 global_addr < backing_store + buffer_size);
2084 offset =
static_cast<uint32_t>(global_addr - backing_store);
2086 buffer = handle(instance->globals_buffer(), isolate_);
2087 offset = global.offset;
2092 Handle<WasmGlobalObject> global_obj =
2093 WasmGlobalObject::New(isolate_, buffer, global.type, offset,
2096 desc.set_value(global_obj);
2100 switch (global.type) {
2102 num = ReadLittleEndianValue<int32_t>(
2103 GetRawGlobalPtr<int32_t>(global));
2107 ReadLittleEndianValue<float>(GetRawGlobalPtr<float>(global));
2110 num = ReadLittleEndianValue<double>(
2111 GetRawGlobalPtr<double>(global));
2114 thrower_->LinkError(
2115 "export of globals of type I64 is not allowed.");
2120 desc.set_value(isolate_->factory()->NewNumber(num));
2124 case kExternalException: {
2125 const WasmException& exception = module_->exceptions[exp.index];
2126 Handle<WasmExceptionObject> wrapper = exception_wrappers_[exp.index];
2127 if (wrapper.is_null()) {
2128 Handle<HeapObject> exception_tag(
2129 HeapObject::cast(instance->exceptions_table()->get(exp.index)),
2132 WasmExceptionObject::New(isolate_, exception.sig, exception_tag);
2133 exception_wrappers_[exp.index] = wrapper;
2135 desc.set_value(wrapper);
2144 isolate_, export_to, name, &desc, kThrowOnError);
2145 if (!status.IsJust()) {
2146 TruncatedUserString<> trunc_name(name->GetCharVector<uint8_t>());
2147 thrower_->LinkError(
"export of %.*s failed.", trunc_name.length(),
2148 trunc_name.start());
2152 DCHECK_EQ(export_index, export_wrappers->length());
2154 if (module_->origin == kWasmOrigin) {
2156 JSReceiver::SetIntegrityLevel(exports_object, FROZEN, kDontThrow);
2162 void InstanceBuilder::InitializeTables(Handle<WasmInstanceObject> instance) {
2163 size_t table_count = module_->tables.size();
2164 for (
size_t index = 0; index < table_count; ++index) {
2165 const WasmTable& table = module_->tables[index];
2166 TableInstance& table_instance = table_instances_[index];
2168 if (!instance->has_indirect_function_table() &&
2169 table.type == kWasmAnyFunc) {
2170 WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
2171 instance, table.initial_size);
2172 table_instance.table_size = table.initial_size;
2177 void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
2178 NativeModule* native_module = module_object_->native_module();
2179 for (
auto& table_init : module_->table_inits) {
2181 if (!table_init.active)
continue;
2183 uint32_t base = EvalUint32InitExpr(table_init.offset);
2185 uint32_t index = table_init.table_index;
2186 TableInstance& table_instance = table_instances_[index];
2187 DCHECK(in_bounds(base, num_entries, table_instance.table_size));
2189 uint32_t func_index = table_init.entries[
i];
2190 const WasmFunction*
function = &module_->functions[func_index];
2191 int table_index =
static_cast<int>(
i + base);
2194 uint32_t sig_id = module_->signature_ids[
function->sig_index];
2195 IndirectFunctionTableEntry(instance, table_index)
2196 .Set(sig_id, instance, func_index);
2198 if (!table_instance.table_object.is_null()) {
2200 if (js_wrappers_[func_index].is_null()) {
2206 Handle<Code> wrapper_code =
2207 js_to_wasm_cache_.GetOrCompileJSToWasmWrapper(
2208 isolate_, function->sig, function->imported);
2209 MaybeHandle<String> func_name;
2210 if (module_->origin == kAsmJsOrigin) {
2212 WireBytesRef func_name_ref = module_->LookupFunctionName(
2213 native_module->wire_bytes(), func_index);
2214 func_name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
2215 isolate_, module_object_, func_name_ref)
2218 Handle<WasmExportedFunction> js_function = WasmExportedFunction::New(
2219 isolate_, instance, func_name, func_index,
2220 static_cast<int>(function->sig->parameter_count()), wrapper_code);
2221 js_wrappers_[func_index] = js_function;
2223 table_instance.js_wrappers->set(table_index, *js_wrappers_[func_index]);
2226 WasmTableObject::UpdateDispatchTables(
2227 isolate_, table_instance.table_object, table_index, function->sig,
2228 instance, func_index);
2233 int table_count =
static_cast<int>(module_->tables.size());
2234 for (
int index = 0; index < table_count; ++index) {
2235 TableInstance& table_instance = table_instances_[index];
2238 if (!table_instance.table_object.is_null()) {
2239 WasmTableObject::AddDispatchTable(isolate_, table_instance.table_object,
2245 void InstanceBuilder::InitializeExceptions(
2246 Handle<WasmInstanceObject> instance) {
2247 Handle<FixedArray> exceptions_table(instance->exceptions_table(), isolate_);
2248 for (
int index = 0; index < exceptions_table->length(); ++index) {
2249 if (!exceptions_table->get(index)->IsUndefined(isolate_))
continue;
2253 Handle<HeapObject> exception_tag =
2254 isolate_->factory()->NewJSObjectWithNullProto();
2255 exceptions_table->set(index, *exception_tag);
2259 AsyncCompileJob::AsyncCompileJob(
2260 Isolate* isolate,
const WasmFeatures& enabled,
2261 std::unique_ptr<byte[]> bytes_copy,
size_t length, Handle<Context> context,
2262 std::shared_ptr<CompilationResultResolver> resolver)
2263 : isolate_(isolate),
2264 enabled_features_(enabled),
2265 bytes_copy_(
std::move(bytes_copy)),
2266 wire_bytes_(bytes_copy_.get(), bytes_copy_.get() + length),
2267 resolver_(
std::move(resolver)) {
2268 v8::Isolate* v8_isolate =
reinterpret_cast<v8::Isolate*
>(isolate);
2272 DeferredHandleScope deferred(isolate);
2273 native_context_ = Handle<Context>(context->native_context(), isolate);
2274 DCHECK(native_context_->IsNativeContext());
2275 deferred_handles_.push_back(deferred.Detach());
2278 void AsyncCompileJob::Start() {
2279 DoAsync<DecodeModule>(isolate_->counters());
2282 void AsyncCompileJob::Abort() {
2285 isolate_->wasm_engine()->RemoveCompileJob(
this);
2298 bool ProcessCodeSectionHeader(
size_t functions_count,
uint32_t offset,
2299 std::shared_ptr<WireBytesStorage>)
override;
2304 void OnFinishedChunk()
override;
2310 void OnAbort()
override;
2317 void FinishAsyncCompileJobWithError(
ResultBase result);
2319 void CommitCompilationUnits();
2323 std::unique_ptr<CompilationUnitBuilder> compilation_unit_builder_;
2327 std::shared_ptr<StreamingDecoder> AsyncCompileJob::CreateStreamingDecoder() {
2328 DCHECK_NULL(stream_);
2334 AsyncCompileJob::~AsyncCompileJob() {
2335 background_task_manager_.CancelAndWait();
2336 if (native_module_) Impl(native_module_->compilation_state())->Abort();
2341 if (stream_) stream_->NotifyCompilationEnded();
2342 CancelPendingForegroundTask();
2343 for (
auto d : deferred_handles_)
delete d;
2346 void AsyncCompileJob::PrepareRuntimeObjects(
2347 std::shared_ptr<const WasmModule> module) {
2349 if (module->has_shared_memory) {
2350 isolate_->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
2355 Handle<Script> script =
2356 CreateWasmScript(isolate_, wire_bytes_, module->source_map_url);
2357 Handle<ByteArray> asm_js_offset_table;
2369 WasmModuleObject::New(isolate_, enabled_features_, std::move(module),
2370 {std::move(bytes_copy_), wire_bytes_.length()},
2371 script, asm_js_offset_table);
2372 native_module_ = module_object_->native_module();
2375 DeferredHandleScope deferred(isolate_);
2376 module_object_ = handle(*module_object_, isolate_);
2377 deferred_handles_.push_back(deferred.Detach());
2383 void AsyncCompileJob::FinishCompile(
bool compile_wrappers) {
2384 DCHECK(!isolate_->context().is_null());
2386 Handle<Script> script(module_object_->script(), isolate_);
2387 if (script->type() == Script::TYPE_WASM &&
2388 module_object_->module()->source_map_url.size() != 0) {
2389 MaybeHandle<String> src_map_str = isolate_->factory()->NewStringFromUtf8(
2390 CStrVector(module_object_->module()->source_map_url.c_str()), TENURED);
2391 script->set_source_mapping_url(*src_map_str.ToHandleChecked());
2393 isolate_->debug()->OnAfterCompile(script);
2396 auto compilation_state = Impl(native_module_->compilation_state());
2397 compilation_state->PublishDetectedFeatures(
2398 isolate_, *compilation_state->detected_features());
2402 if (compile_wrappers) {
2403 DoSync<CompileWrappers>();
2406 DoSync<AsyncCompileJob::FinishModule>();
2410 void AsyncCompileJob::AsyncCompileFailed(Handle<Object> error_reason) {
2412 std::shared_ptr<AsyncCompileJob> job =
2413 isolate_->wasm_engine()->RemoveCompileJob(
this);
2414 resolver_->OnCompilationFailed(error_reason);
2417 void AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) {
2418 resolver_->OnCompilationSucceeded(result);
2425 void operator()(CompilationEvent event,
const VoidResult* error_result) {
2428 case CompilationEvent::kFinishedBaselineCompilation:
2429 DCHECK(!last_event_.has_value());
2430 if (job_->DecrementAndCheckFinisherCount()) {
2432 job_->isolate()->set_context(*job_->native_context_);
2433 job_->FinishCompile(
true);
2436 case CompilationEvent::kFinishedTopTierCompilation:
2437 DCHECK_EQ(CompilationEvent::kFinishedBaselineCompilation, last_event_);
2439 if (job_->stream_ && job_->stream_->module_compiled_callback()) {
2440 job_->stream_->module_compiled_callback()(job_->module_object_);
2444 if (!job_->pending_foreground_task_ &&
2445 job_->outstanding_finishers_.load() == 0) {
2446 job_->isolate_->wasm_engine()->RemoveCompileJob(job_);
2449 case CompilationEvent::kFailedCompilation:
2450 DCHECK(!last_event_.has_value());
2451 DCHECK_NOT_NULL(error_result);
2454 DCHECK(!Impl(job_->native_module_->compilation_state())
2455 ->baseline_compilation_finished());
2459 job_->isolate()->set_context(*job_->native_context_);
2460 ErrorThrower thrower(job_->isolate(),
"AsyncCompilation");
2461 thrower.CompileFailed(*error_result);
2465 error = handle(*error, job_->isolate());
2466 job_->deferred_handles_.push_back(deferred.Detach());
2468 job_->DoSync<
CompileFailed, kUseExistingForegroundTask>(error);
2476 last_event_ = event;
2494 if (on_foreground) {
2497 job->isolate_->set_context(*job->native_context_);
2498 RunInForeground(job);
2500 RunInBackground(job);
2515 :
CancelableTask(on_foreground ? job->isolate_->cancelable_task_manager()
2516 : &job->background_task_manager_),
2518 on_foreground_(on_foreground) {}
2521 if (job_ !=
nullptr && on_foreground_) ResetPendingForegroundTask();
2524 void RunInternal()
final {
2526 if (on_foreground_) ResetPendingForegroundTask();
2527 job_->step_->Run(job_, on_foreground_);
2534 DCHECK_NOT_NULL(job_);
2541 bool on_foreground_;
2543 void ResetPendingForegroundTask()
const {
2544 DCHECK_EQ(
this, job_->pending_foreground_task_);
2545 job_->pending_foreground_task_ =
nullptr;
2549 void AsyncCompileJob::StartForegroundTask() {
2550 DCHECK_NULL(pending_foreground_task_);
2552 auto new_task = base::make_unique<CompileTask>(
this,
true);
2553 pending_foreground_task_ = new_task.get();
2554 foreground_task_runner_->PostTask(std::move(new_task));
2557 void AsyncCompileJob::ExecuteForegroundTaskImmediately() {
2558 DCHECK_NULL(pending_foreground_task_);
2560 auto new_task = base::make_unique<CompileTask>(
this,
true);
2561 pending_foreground_task_ = new_task.get();
2565 void AsyncCompileJob::CancelPendingForegroundTask() {
2566 if (!pending_foreground_task_)
return;
2567 pending_foreground_task_->Cancel();
2568 pending_foreground_task_ =
nullptr;
2571 void AsyncCompileJob::StartBackgroundTask() {
2572 auto task = base::make_unique<CompileTask>(
this,
false);
2576 if (FLAG_wasm_num_compilation_tasks > 0) {
2577 V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
2579 foreground_task_runner_->PostTask(std::move(task));
2583 template <
typename Step,
2584 AsyncCompileJob::UseExistingForegroundTask use_existing_fg_task,
2586 void AsyncCompileJob::DoSync(Args&&... args) {
2587 NextStep<Step>(std::forward<Args>(args)...);
2588 if (use_existing_fg_task && pending_foreground_task_ !=
nullptr)
return;
2589 StartForegroundTask();
2592 template <
typename Step,
typename... Args>
2593 void AsyncCompileJob::DoImmediately(Args&&... args) {
2594 NextStep<Step>(std::forward<Args>(args)...);
2595 ExecuteForegroundTaskImmediately();
2598 template <
typename Step,
typename... Args>
2599 void AsyncCompileJob::DoAsync(Args&&... args) {
2600 NextStep<Step>(std::forward<Args>(args)...);
2601 StartBackgroundTask();
2604 template <
typename Step,
typename... Args>
2605 void AsyncCompileJob::NextStep(Args&&... args) {
2606 step_.reset(
new Step(std::forward<Args>(args)...));
2622 TRACE_COMPILE(
"(1) Decoding module...\n");
2623 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT(
"v8.wasm"),
2624 "AsyncCompileJob::DecodeModule");
2625 result = DecodeWasmModule(
2626 job->enabled_features_, job->wire_bytes_.start(),
2627 job->wire_bytes_.end(),
false, kWasmOrigin, counters_,
2628 job->isolate()->wasm_engine()->allocator());
2630 if (result.failed()) {
2653 TRACE_COMPILE(
"(1b) Decoding failed.\n");
2655 thrower.CompileFailed(
"Wasm decoding failed", result_);
2657 return job->AsyncCompileFailed(thrower.Reify());
2667 bool start_compilation)
2668 : module_(std::move(module)), start_compilation_(start_compilation) {}
2671 std::shared_ptr<const WasmModule> module_;
2672 bool start_compilation_;
2675 TRACE_COMPILE(
"(2) Prepare and start compile...\n");
2679 job->background_task_manager_.CancelAndWait();
2681 job->PrepareRuntimeObjects(module_);
2683 size_t num_functions =
2684 module_->functions.size() - module_->num_imported_functions;
2686 if (num_functions == 0) {
2688 job->FinishCompile(
true);
2692 CompilationStateImpl* compilation_state =
2693 Impl(job->native_module_->compilation_state());
2695 if (start_compilation_) {
2701 compilation_state->SetNumberOfFunctionsToCompile(
2702 module_->num_declared_functions);
2704 InitializeCompilationUnits(job->native_module_,
2705 job->isolate()->wasm_engine());
2716 : error_reason_(error_reason) {}
2719 TRACE_COMPILE(
"(4b) Compilation Failed...\n");
2720 return job->AsyncCompileFailed(error_reason_);
2734 TRACE_COMPILE(
"(5) Compile wrappers...\n");
2736 CompileJsToWasmWrappers(
2737 job->isolate_, job->module_object_->native_module(),
2738 handle(job->module_object_->export_wrappers(), job->isolate_));
2748 TRACE_COMPILE(
"(6) Finish module...\n");
2749 job->AsyncCompileSucceeded(job->module_object_);
2751 size_t num_functions = job->native_module_->num_functions() -
2752 job->native_module_->num_imported_functions();
2753 auto* compilation_state = Impl(job->native_module_->compilation_state());
2754 if (compilation_state->compile_mode() == CompileMode::kRegular ||
2755 num_functions == 0) {
2758 job->isolate_->wasm_engine()->RemoveCompileJob(job);
2761 DCHECK_EQ(CompileMode::kTiering, compilation_state->compile_mode());
2762 if (!compilation_state->has_outstanding_units()) {
2763 job->isolate_->wasm_engine()->RemoveCompileJob(job);
2768 AsyncStreamingProcessor::AsyncStreamingProcessor(
AsyncCompileJob* job)
2769 : decoder_(job->enabled_features_),
2771 compilation_unit_builder_(nullptr) {}
2773 void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(
ResultBase error) {
2774 DCHECK(error.failed());
2777 job_->background_task_manager_.CancelAndWait();
2781 ModuleResult result = ModuleResult::ErrorFrom(std::move(error));
2785 if (job_->native_module_) {
2786 Impl(job_->native_module_->compilation_state())->Abort();
2789 AsyncCompileJob::kUseExistingForegroundTask>(
2795 if (compilation_unit_builder_) compilation_unit_builder_->Clear();
2797 job_->DoSync<AsyncCompileJob::DecodeFail>(std::move(result));
2802 bool AsyncStreamingProcessor::ProcessModuleHeader(Vector<const uint8_t> bytes,
2804 TRACE_STREAMING(
"Process module header...\n");
2805 decoder_.StartDecoding(job_->isolate()->counters(),
2806 job_->isolate()->wasm_engine()->allocator());
2807 decoder_.DecodeModuleHeader(bytes, offset);
2808 if (!decoder_.ok()) {
2809 FinishAsyncCompileJobWithError(decoder_.FinishDecoding(
false));
2816 bool AsyncStreamingProcessor::ProcessSection(SectionCode section_code,
2817 Vector<const uint8_t> bytes,
2819 TRACE_STREAMING(
"Process section %d ...\n", section_code);
2820 if (compilation_unit_builder_) {
2823 CommitCompilationUnits();
2824 compilation_unit_builder_.reset();
2826 if (section_code == SectionCode::kUnknownSectionCode) {
2827 Decoder decoder(bytes, offset);
2828 section_code = ModuleDecoder::IdentifyUnknownSection(
2829 decoder, bytes.start() + bytes.length());
2830 if (section_code == SectionCode::kUnknownSectionCode) {
2835 offset += decoder.position();
2836 bytes = bytes.SubVector(decoder.position(), bytes.size());
2838 constexpr
bool verify_functions =
false;
2839 decoder_.DecodeSection(section_code, bytes, offset, verify_functions);
2840 if (!decoder_.ok()) {
2841 FinishAsyncCompileJobWithError(decoder_.FinishDecoding(
false));
2848 bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
2849 size_t functions_count,
uint32_t offset,
2850 std::shared_ptr<WireBytesStorage> wire_bytes_storage) {
2851 TRACE_STREAMING(
"Start the code section with %zu functions...\n",
2853 if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(functions_count),
2855 FinishAsyncCompileJobWithError(decoder_.FinishDecoding(
false));
2860 job_->DoImmediately<AsyncCompileJob::PrepareAndStartCompile>(
2861 decoder_.shared_module(),
false);
2862 job_->native_module_->compilation_state()->SetWireBytesStorage(
2863 std::move(wire_bytes_storage));
2865 auto* compilation_state = Impl(job_->native_module_->compilation_state());
2866 compilation_state->SetNumberOfFunctionsToCompile(functions_count);
2870 job_->outstanding_finishers_.store(2);
2871 compilation_unit_builder_.reset(
new CompilationUnitBuilder(
2872 job_->native_module_, job_->isolate()->wasm_engine()));
2877 bool AsyncStreamingProcessor::ProcessFunctionBody(Vector<const uint8_t> bytes,
2879 TRACE_STREAMING(
"Process function body %d ...\n", next_function_);
2881 decoder_.DecodeFunctionBody(
2882 next_function_, static_cast<uint32_t>(bytes.length()), offset,
false);
2884 uint32_t index = next_function_ + decoder_.module()->num_imported_functions;
2885 compilation_unit_builder_->AddUnit(index);
2892 void AsyncStreamingProcessor::CommitCompilationUnits() {
2893 DCHECK(compilation_unit_builder_);
2894 compilation_unit_builder_->Commit();
2897 void AsyncStreamingProcessor::OnFinishedChunk() {
2898 TRACE_STREAMING(
"FinishChunk...\n");
2899 if (compilation_unit_builder_) CommitCompilationUnits();
2903 void AsyncStreamingProcessor::OnFinishedStream(OwnedVector<uint8_t> bytes) {
2904 TRACE_STREAMING(
"Finish stream...\n");
2905 ModuleResult result = decoder_.FinishDecoding(
false);
2906 DCHECK(result.ok());
2907 bool needs_finish = job_->DecrementAndCheckFinisherCount();
2908 if (job_->native_module_ ==
nullptr) {
2911 job_->PrepareRuntimeObjects(std::move(result).value());
2912 DCHECK(needs_finish);
2914 job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector());
2915 job_->native_module_->SetWireBytes(std::move(bytes));
2917 HandleScope scope(job_->isolate_);
2918 SaveContext saved_context(job_->isolate_);
2919 job_->isolate_->set_context(*job_->native_context_);
2920 job_->FinishCompile(
true);
2925 void AsyncStreamingProcessor::OnError(DecodeResult result) {
2926 TRACE_STREAMING(
"Stream error...\n");
2927 FinishAsyncCompileJobWithError(std::move(result));
2930 void AsyncStreamingProcessor::OnAbort() {
2931 TRACE_STREAMING(
"Abort stream...\n");
2935 bool AsyncStreamingProcessor::Deserialize(Vector<const uint8_t> module_bytes,
2936 Vector<const uint8_t> wire_bytes) {
2939 HandleScope scope(job_->isolate_);
2940 SaveContext saved_context(job_->isolate_);
2941 job_->isolate_->set_context(*job_->native_context_);
2943 MaybeHandle<WasmModuleObject> result =
2944 DeserializeNativeModule(job_->isolate_, module_bytes, wire_bytes);
2945 if (result.is_null())
return false;
2947 job_->module_object_ = result.ToHandleChecked();
2949 DeferredHandleScope deferred(job_->isolate_);
2950 job_->module_object_ = handle(*job_->module_object_, job_->isolate_);
2951 job_->deferred_handles_.push_back(deferred.Detach());
2953 job_->native_module_ = job_->module_object_->native_module();
2954 auto owned_wire_bytes = OwnedVector<uint8_t>::Of(wire_bytes);
2955 job_->wire_bytes_ = ModuleWireBytes(owned_wire_bytes.as_vector());
2956 job_->native_module_->SetWireBytes(std::move(owned_wire_bytes));
2957 job_->FinishCompile(
false);
2961 CompilationStateImpl::CompilationStateImpl(internal::Isolate* isolate,
2962 NativeModule* native_module)
2963 : isolate_(isolate),
2964 native_module_(native_module),
2965 compile_mode_(FLAG_wasm_tier_up &&
2966 native_module->module()->origin == kWasmOrigin
2967 ? CompileMode::kTiering
2968 : CompileMode::kRegular),
2969 should_log_code_(WasmCode::ShouldBeLogged(isolate)),
2970 max_background_tasks_(
std::max(
2971 1,
std::min(FLAG_wasm_num_compilation_tasks,
2972 V8::GetCurrentPlatform()->NumberOfWorkerThreads()))) {
2973 v8::Isolate* v8_isolate =
reinterpret_cast<v8::Isolate*
>(isolate_);
2978 CompilationStateImpl::~CompilationStateImpl() {
2979 DCHECK(background_task_manager_.canceled());
2980 DCHECK(foreground_task_manager_.canceled());
2983 void CompilationStateImpl::CancelAndWait() {
2984 background_task_manager_.CancelAndWait();
2985 foreground_task_manager_.CancelAndWait();
2988 void CompilationStateImpl::SetNumberOfFunctionsToCompile(
size_t num_functions) {
2990 outstanding_baseline_units_ = num_functions;
2992 if (compile_mode_ == CompileMode::kTiering) {
2993 outstanding_tiering_units_ = num_functions;
2997 void CompilationStateImpl::SetCallback(callback_t callback) {
2998 DCHECK_NULL(callback_);
2999 callback_ = std::move(callback);
3002 void CompilationStateImpl::AddCompilationUnits(
3003 std::vector<std::unique_ptr<WasmCompilationUnit>>& baseline_units,
3004 std::vector<std::unique_ptr<WasmCompilationUnit>>& tiering_units) {
3006 base::MutexGuard guard(&mutex_);
3008 if (compile_mode_ == CompileMode::kTiering) {
3009 DCHECK_EQ(baseline_units.size(), tiering_units.size());
3010 DCHECK_EQ(tiering_units.back()->tier(), ExecutionTier::kOptimized);
3011 tiering_compilation_units_.insert(
3012 tiering_compilation_units_.end(),
3013 std::make_move_iterator(tiering_units.begin()),
3014 std::make_move_iterator(tiering_units.end()));
3016 DCHECK(tiering_compilation_units_.empty());
3019 baseline_compilation_units_.insert(
3020 baseline_compilation_units_.end(),
3021 std::make_move_iterator(baseline_units.begin()),
3022 std::make_move_iterator(baseline_units.end()));
3025 RestartBackgroundTasks();
3028 std::unique_ptr<WasmCompilationUnit>
3029 CompilationStateImpl::GetNextCompilationUnit() {
3030 base::MutexGuard guard(&mutex_);
3032 std::vector<std::unique_ptr<WasmCompilationUnit>>& units =
3033 baseline_compilation_units_.empty() ? tiering_compilation_units_
3034 : baseline_compilation_units_;
3036 if (!units.empty()) {
3037 std::unique_ptr<WasmCompilationUnit> unit = std::move(units.back());
3042 return std::unique_ptr<WasmCompilationUnit>();
3045 std::unique_ptr<WasmCompilationUnit>
3046 CompilationStateImpl::GetNextExecutedUnit() {
3047 base::MutexGuard guard(&mutex_);
3048 std::vector<std::unique_ptr<WasmCompilationUnit>>& units = finish_units();
3049 if (units.empty())
return {};
3050 std::unique_ptr<WasmCompilationUnit> ret = std::move(units.back());
3055 bool CompilationStateImpl::HasCompilationUnitToFinish() {
3056 base::MutexGuard guard(&mutex_);
3057 return !finish_units().empty();
3060 void CompilationStateImpl::OnFinishedUnit() {
3063 bool is_tiering_mode = compile_mode_ == CompileMode::kTiering;
3064 bool is_tiering_unit = is_tiering_mode && outstanding_baseline_units_ == 0;
3068 DCHECK_IMPLIES(!is_tiering_mode, outstanding_tiering_units_ == 0);
3070 if (is_tiering_unit) {
3071 DCHECK_LT(0, outstanding_tiering_units_);
3072 --outstanding_tiering_units_;
3073 if (outstanding_tiering_units_ == 0) {
3075 DCHECK_EQ(0, outstanding_baseline_units_);
3076 NotifyOnEvent(CompilationEvent::kFinishedTopTierCompilation,
nullptr);
3079 DCHECK_LT(0, outstanding_baseline_units_);
3080 --outstanding_baseline_units_;
3081 if (outstanding_baseline_units_ == 0) {
3082 NotifyOnEvent(CompilationEvent::kFinishedBaselineCompilation,
nullptr);
3085 if (!is_tiering_mode) {
3086 NotifyOnEvent(CompilationEvent::kFinishedTopTierCompilation,
nullptr);
3092 void CompilationStateImpl::ScheduleUnitForFinishing(
3093 std::unique_ptr<WasmCompilationUnit> unit, ExecutionTier tier) {
3094 base::MutexGuard guard(&mutex_);
3095 if (compile_mode_ == CompileMode::kTiering &&
3096 tier == ExecutionTier::kOptimized) {
3097 tiering_finish_units_.push_back(std::move(unit));
3099 baseline_finish_units_.push_back(std::move(unit));
3102 if (!finisher_is_running_ && !compile_error_) {
3103 ScheduleFinisherTask();
3105 finisher_is_running_ =
true;
3109 void CompilationStateImpl::ScheduleCodeLogging(WasmCode* code) {
3110 if (!should_log_code_)
return;
3111 base::MutexGuard guard(&mutex_);
3112 if (log_codes_task_ ==
nullptr) {
3113 auto new_task = base::make_unique<LogCodesTask>(&foreground_task_manager_,
3115 log_codes_task_ = new_task.get();
3116 foreground_task_runner_->PostTask(std::move(new_task));
3118 log_codes_task_->AddCode(code);
3121 void CompilationStateImpl::OnBackgroundTaskStopped(
3122 const WasmFeatures& detected) {
3123 base::MutexGuard guard(&mutex_);
3124 DCHECK_LE(1, num_background_tasks_);
3125 --num_background_tasks_;
3126 UnionFeaturesInto(&detected_features_, detected);
3129 void CompilationStateImpl::PublishDetectedFeatures(
3130 Isolate* isolate,
const WasmFeatures& detected) {
3134 base::MutexGuard guard(&mutex_);
3135 UnionFeaturesInto(&detected_features_, detected);
3136 UpdateFeatureUseCounts(isolate, detected_features_);
3139 void CompilationStateImpl::RestartBackgroundTasks(
size_t max) {
3142 base::MutexGuard guard(&mutex_);
3144 if (compile_error_)
return;
3146 DCHECK_LE(num_background_tasks_, max_background_tasks_);
3147 if (num_background_tasks_ == max_background_tasks_)
return;
3148 size_t num_compilation_units =
3149 baseline_compilation_units_.size() + tiering_compilation_units_.size();
3150 size_t stopped_tasks = max_background_tasks_ - num_background_tasks_;
3151 num_restart = std::min(max, std::min(num_compilation_units, stopped_tasks));
3152 num_background_tasks_ += num_restart;
3155 for (; num_restart > 0; --num_restart) {
3156 auto task = base::make_unique<BackgroundCompileTask>(
3157 &background_task_manager_, native_module_, isolate_->counters());
3161 if (FLAG_wasm_num_compilation_tasks > 0) {
3162 V8::GetCurrentPlatform()->CallOnWorkerThread(std::move(task));
3164 foreground_task_runner_->PostTask(std::move(task));
3169 bool CompilationStateImpl::SetFinisherIsRunning(
bool value) {
3170 base::MutexGuard guard(&mutex_);
3171 if (finisher_is_running_ == value)
return false;
3172 finisher_is_running_ = value;
3176 void CompilationStateImpl::ScheduleFinisherTask() {
3177 foreground_task_runner_->PostTask(
3178 base::make_unique<FinishCompileTask>(
this, &foreground_task_manager_));
3181 void CompilationStateImpl::Abort() {
3183 base::MutexGuard guard(&mutex_);
3184 if (!compile_error_) {
3185 compile_error_ = base::make_unique<CompilationError>(
3186 0, VoidResult::Error(0,
"Compilation aborted"));
3189 background_task_manager_.CancelAndWait();
3192 void CompilationStateImpl::SetError(
uint32_t func_index,
3193 const ResultBase& error_result) {
3194 DCHECK(error_result.failed());
3195 base::MutexGuard guard(&mutex_);
3197 if (compile_error_)
return;
3199 base::make_unique<CompilationError>(func_index, error_result);
3202 foreground_task_runner_->PostTask(
3203 MakeCancelableTask(&foreground_task_manager_, [
this] {
3204 VoidResult error_result = GetCompileError();
3205 NotifyOnEvent(CompilationEvent::kFailedCompilation, &error_result);
3209 void CompilationStateImpl::NotifyOnEvent(CompilationEvent event,
3210 const VoidResult* error_result) {
3211 HandleScope scope(isolate_);
3212 if (callback_) callback_(event, error_result);
3215 void CompileJsToWasmWrappers(Isolate* isolate, NativeModule* native_module,
3216 Handle<FixedArray> export_wrappers) {
3217 JSToWasmWrapperCache js_to_wasm_cache;
3218 int wrapper_index = 0;
3219 const WasmModule* module = native_module->module();
3224 CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
3225 for (
auto exp : module->export_table) {
3226 if (exp.kind != kExternalFunction)
continue;
3227 auto&
function = module->functions[exp.index];
3228 Handle<Code> wrapper_code = js_to_wasm_cache.GetOrCompileJSToWasmWrapper(
3229 isolate,
function.sig,
function.imported);
3230 export_wrappers->set(wrapper_index, *wrapper_code);
3231 RecordStats(*wrapper_code, isolate->counters());
3236 Handle<Script> CreateWasmScript(Isolate* isolate,
3237 const ModuleWireBytes& wire_bytes,
3238 const std::string& source_map_url) {
3239 Handle<Script> script =
3240 isolate->factory()->NewScript(isolate->factory()->empty_string());
3241 script->set_context_data(isolate->native_context()->debug_context_id());
3242 script->set_type(Script::TYPE_WASM);
3244 int hash = StringHasher::HashSequentialString(
3245 reinterpret_cast<const char*>(wire_bytes.start()),
3246 static_cast<int>(wire_bytes.length()), kZeroHashSeed);
3248 const int kBufferSize = 32;
3249 char buffer[kBufferSize];
3251 int name_chars = SNPrintF(ArrayVector(buffer),
"wasm-%08x", hash);
3252 DCHECK(name_chars >= 0 && name_chars < kBufferSize);
3253 MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
3254 Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), name_chars),
3256 script->set_name(*name_str.ToHandleChecked());
3258 if (source_map_url.size() != 0) {
3259 MaybeHandle<String> src_map_str = isolate->factory()->NewStringFromUtf8(
3260 CStrVector(source_map_url.c_str()), TENURED);
3261 script->set_source_mapping_url(*src_map_str.ToHandleChecked());
3271 #undef TRACE_COMPILE 3272 #undef TRACE_STREAMING
V8_INLINE T FromMaybe(const T &default_value) const