| // Copyright 2016 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/codegen/optimized-compilation-info.h" |
| |
| #include "src/api/api.h" |
| #include "src/codegen/source-position.h" |
| #include "src/debug/debug.h" |
| #include "src/execution/isolate.h" |
| #include "src/objects/objects-inl.h" |
| #include "src/objects/shared-function-info.h" |
| #include "src/tracing/trace-event.h" |
| #include "src/tracing/traced-value.h" |
| #include "src/wasm/function-compiler.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| OptimizedCompilationInfo::OptimizedCompilationInfo( |
| Zone* zone, Isolate* isolate, Handle<SharedFunctionInfo> shared, |
| Handle<JSFunction> closure) |
| : OptimizedCompilationInfo(Code::OPTIMIZED_FUNCTION, zone) { |
| DCHECK(shared->is_compiled()); |
| bytecode_array_ = handle(shared->GetBytecodeArray(), isolate); |
| shared_info_ = shared; |
| closure_ = closure; |
| optimization_id_ = isolate->NextOptimizationId(); |
| |
| // Collect source positions for optimized code when profiling or if debugger |
| // is active, to be able to get more precise source positions at the price of |
| // more memory consumption. |
| if (isolate->NeedsDetailedOptimizedCodeLineInfo()) { |
| MarkAsSourcePositionsEnabled(); |
| } |
| |
| SetTracingFlags(shared->PassesFilter(FLAG_trace_turbo_filter)); |
| } |
| |
| OptimizedCompilationInfo::OptimizedCompilationInfo( |
| Vector<const char> debug_name, Zone* zone, Code::Kind code_kind) |
| : OptimizedCompilationInfo(code_kind, zone) { |
| debug_name_ = debug_name; |
| |
| SetTracingFlags( |
| PassesFilter(debug_name, CStrVector(FLAG_trace_turbo_filter))); |
| } |
| |
| OptimizedCompilationInfo::OptimizedCompilationInfo(Code::Kind code_kind, |
| Zone* zone) |
| : code_kind_(code_kind), zone_(zone) { |
| ConfigureFlags(); |
| } |
| |
| void OptimizedCompilationInfo::ConfigureFlags() { |
| if (FLAG_untrusted_code_mitigations) SetFlag(kUntrustedCodeMitigations); |
| |
| switch (code_kind_) { |
| case Code::OPTIMIZED_FUNCTION: |
| SetFlag(kCalledWithCodeStartRegister); |
| SetFlag(kSwitchJumpTableEnabled); |
| if (FLAG_function_context_specialization) { |
| MarkAsFunctionContextSpecializing(); |
| } |
| if (FLAG_turbo_splitting) { |
| MarkAsSplittingEnabled(); |
| } |
| if (FLAG_untrusted_code_mitigations) { |
| MarkAsPoisoningRegisterArguments(); |
| } |
| if (FLAG_analyze_environment_liveness) { |
| // TODO(yangguo): Disable this in case of debugging for crbug.com/826613 |
| MarkAsAnalyzeEnvironmentLiveness(); |
| } |
| break; |
| case Code::BYTECODE_HANDLER: |
| SetFlag(kCalledWithCodeStartRegister); |
| if (FLAG_turbo_splitting) { |
| MarkAsSplittingEnabled(); |
| } |
| break; |
| case Code::BUILTIN: |
| case Code::STUB: |
| if (FLAG_turbo_splitting) { |
| MarkAsSplittingEnabled(); |
| } |
| #if ENABLE_GDB_JIT_INTERFACE && DEBUG |
| MarkAsSourcePositionsEnabled(); |
| #endif // ENABLE_GDB_JIT_INTERFACE && DEBUG |
| break; |
| case Code::WASM_FUNCTION: |
| case Code::WASM_TO_CAPI_FUNCTION: |
| SetFlag(kSwitchJumpTableEnabled); |
| break; |
| default: |
| break; |
| } |
| |
| if (FLAG_turbo_control_flow_aware_allocation) { |
| MarkAsTurboControlFlowAwareAllocation(); |
| } else { |
| MarkAsTurboPreprocessRanges(); |
| } |
| } |
| |
| OptimizedCompilationInfo::~OptimizedCompilationInfo() { |
| if (GetFlag(kDisableFutureOptimization) && has_shared_info()) { |
| shared_info()->DisableOptimization(bailout_reason()); |
| } |
| } |
| |
| void OptimizedCompilationInfo::set_deferred_handles( |
| std::shared_ptr<DeferredHandles> deferred_handles) { |
| DCHECK_NULL(deferred_handles_); |
| deferred_handles_.swap(deferred_handles); |
| } |
| |
| void OptimizedCompilationInfo::set_deferred_handles( |
| DeferredHandles* deferred_handles) { |
| DCHECK_NULL(deferred_handles_); |
| deferred_handles_.reset(deferred_handles); |
| } |
| |
| void OptimizedCompilationInfo::ReopenHandlesInNewHandleScope(Isolate* isolate) { |
| if (!shared_info_.is_null()) { |
| shared_info_ = Handle<SharedFunctionInfo>(*shared_info_, isolate); |
| } |
| if (!bytecode_array_.is_null()) { |
| bytecode_array_ = Handle<BytecodeArray>(*bytecode_array_, isolate); |
| } |
| if (!closure_.is_null()) { |
| closure_ = Handle<JSFunction>(*closure_, isolate); |
| } |
| } |
| |
| void OptimizedCompilationInfo::AbortOptimization(BailoutReason reason) { |
| DCHECK_NE(reason, BailoutReason::kNoReason); |
| if (bailout_reason_ == BailoutReason::kNoReason) { |
| TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("v8.compile"), |
| "V8.AbortOptimization", TRACE_EVENT_SCOPE_THREAD, |
| "reason", GetBailoutReason(reason), "function", |
| shared_info()->TraceIDRef()); |
| bailout_reason_ = reason; |
| } |
| SetFlag(kDisableFutureOptimization); |
| } |
| |
| void OptimizedCompilationInfo::RetryOptimization(BailoutReason reason) { |
| DCHECK_NE(reason, BailoutReason::kNoReason); |
| if (GetFlag(kDisableFutureOptimization)) return; |
| TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("v8.compile"), |
| "V8.RetryOptimization", TRACE_EVENT_SCOPE_THREAD, |
| "reason", GetBailoutReason(reason), "function", |
| shared_info()->TraceIDRef()); |
| bailout_reason_ = reason; |
| } |
| |
| std::unique_ptr<char[]> OptimizedCompilationInfo::GetDebugName() const { |
| if (!shared_info().is_null()) { |
| return shared_info()->DebugName().ToCString(); |
| } |
| Vector<const char> name_vec = debug_name_; |
| if (name_vec.empty()) name_vec = ArrayVector("unknown"); |
| std::unique_ptr<char[]> name(new char[name_vec.length() + 1]); |
| memcpy(name.get(), name_vec.begin(), name_vec.length()); |
| name[name_vec.length()] = '\0'; |
| return name; |
| } |
| |
| StackFrame::Type OptimizedCompilationInfo::GetOutputStackFrameType() const { |
| switch (code_kind()) { |
| case Code::STUB: |
| case Code::BYTECODE_HANDLER: |
| case Code::BUILTIN: |
| return StackFrame::STUB; |
| case Code::WASM_FUNCTION: |
| return StackFrame::WASM_COMPILED; |
| case Code::WASM_TO_CAPI_FUNCTION: |
| return StackFrame::WASM_EXIT; |
| case Code::JS_TO_WASM_FUNCTION: |
| return StackFrame::JS_TO_WASM; |
| case Code::WASM_TO_JS_FUNCTION: |
| return StackFrame::WASM_TO_JS; |
| case Code::WASM_INTERPRETER_ENTRY: |
| return StackFrame::WASM_INTERPRETER_ENTRY; |
| case Code::C_WASM_ENTRY: |
| return StackFrame::C_WASM_ENTRY; |
| default: |
| UNIMPLEMENTED(); |
| return StackFrame::NONE; |
| } |
| } |
| |
| void OptimizedCompilationInfo::SetWasmCompilationResult( |
| std::unique_ptr<wasm::WasmCompilationResult> wasm_compilation_result) { |
| wasm_compilation_result_ = std::move(wasm_compilation_result); |
| } |
| |
| std::unique_ptr<wasm::WasmCompilationResult> |
| OptimizedCompilationInfo::ReleaseWasmCompilationResult() { |
| return std::move(wasm_compilation_result_); |
| } |
| |
| bool OptimizedCompilationInfo::has_context() const { |
| return !closure().is_null(); |
| } |
| |
| Context OptimizedCompilationInfo::context() const { |
| DCHECK(has_context()); |
| return closure()->context(); |
| } |
| |
| bool OptimizedCompilationInfo::has_native_context() const { |
| return !closure().is_null() && !closure()->native_context().is_null(); |
| } |
| |
| NativeContext OptimizedCompilationInfo::native_context() const { |
| DCHECK(has_native_context()); |
| return closure()->native_context(); |
| } |
| |
| bool OptimizedCompilationInfo::has_global_object() const { |
| return has_native_context(); |
| } |
| |
| JSGlobalObject OptimizedCompilationInfo::global_object() const { |
| DCHECK(has_global_object()); |
| return native_context().global_object(); |
| } |
| |
| int OptimizedCompilationInfo::AddInlinedFunction( |
| Handle<SharedFunctionInfo> inlined_function, |
| Handle<BytecodeArray> inlined_bytecode, SourcePosition pos) { |
| int id = static_cast<int>(inlined_functions_.size()); |
| inlined_functions_.push_back( |
| InlinedFunctionHolder(inlined_function, inlined_bytecode, pos)); |
| return id; |
| } |
| |
| void OptimizedCompilationInfo::SetTracingFlags(bool passes_filter) { |
| if (!passes_filter) return; |
| if (FLAG_trace_turbo) SetFlag(kTraceTurboJson); |
| if (FLAG_trace_turbo_graph) SetFlag(kTraceTurboGraph); |
| if (FLAG_trace_turbo_scheduled) SetFlag(kTraceTurboScheduled); |
| if (FLAG_trace_turbo_alloc) SetFlag(kTraceTurboAllocation); |
| if (FLAG_trace_heap_broker) SetFlag(kTraceHeapBroker); |
| } |
| |
| OptimizedCompilationInfo::InlinedFunctionHolder::InlinedFunctionHolder( |
| Handle<SharedFunctionInfo> inlined_shared_info, |
| Handle<BytecodeArray> inlined_bytecode, SourcePosition pos) |
| : shared_info(inlined_shared_info), bytecode_array(inlined_bytecode) { |
| position.position = pos; |
| // initialized when generating the deoptimization literals |
| position.inlined_function_id = DeoptimizationData::kNotInlinedIndex; |
| } |
| |
| std::unique_ptr<v8::tracing::TracedValue> |
| OptimizedCompilationInfo::ToTracedValue() { |
| auto value = v8::tracing::TracedValue::Create(); |
| value->SetBoolean("osr", is_osr()); |
| value->SetBoolean("functionContextSpecialized", |
| is_function_context_specializing()); |
| if (has_shared_info()) { |
| value->SetValue("function", shared_info()->TraceIDRef()); |
| } |
| if (bailout_reason() != BailoutReason::kNoReason) { |
| value->SetString("bailoutReason", GetBailoutReason(bailout_reason())); |
| value->SetBoolean("disableFutureOptimization", |
| is_disable_future_optimization()); |
| } else { |
| value->SetInteger("optimizationId", optimization_id()); |
| value->BeginArray("inlinedFunctions"); |
| for (auto const& inlined_function : inlined_functions()) { |
| value->BeginDictionary(); |
| value->SetValue("function", inlined_function.shared_info->TraceIDRef()); |
| // TODO(bmeurer): Also include the source position from the |
| // {inlined_function} here as dedicated "sourcePosition" field. |
| value->EndDictionary(); |
| } |
| value->EndArray(); |
| } |
| return value; |
| } |
| |
| } // namespace internal |
| } // namespace v8 |