1// Copyright 2016 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/optimized-compilation-info.h"
6
7#include "src/api.h"
8#include "src/debug/debug.h"
9#include "src/isolate.h"
10#include "src/objects-inl.h"
11#include "src/objects/shared-function-info.h"
12#include "src/source-position.h"
13#include "src/tracing/trace-event.h"
14#include "src/tracing/traced-value.h"
15#include "src/wasm/function-compiler.h"
16
17namespace v8 {
18namespace internal {
19
20OptimizedCompilationInfo::OptimizedCompilationInfo(
21 Zone* zone, Isolate* isolate, Handle<SharedFunctionInfo> shared,
22 Handle<JSFunction> closure)
23 : OptimizedCompilationInfo(Code::OPTIMIZED_FUNCTION, zone) {
24 DCHECK(shared->is_compiled());
25 bytecode_array_ = handle(shared->GetBytecodeArray(), isolate);
26 shared_info_ = shared;
27 closure_ = closure;
28 optimization_id_ = isolate->NextOptimizationId();
29
30 // Collect source positions for optimized code when profiling or if debugger
31 // is active, to be able to get more precise source positions at the price of
32 // more memory consumption.
33 if (isolate->NeedsDetailedOptimizedCodeLineInfo()) {
34 MarkAsSourcePositionsEnabled();
35 }
36
37 SetTracingFlags(shared->PassesFilter(FLAG_trace_turbo_filter));
38}
39
40OptimizedCompilationInfo::OptimizedCompilationInfo(
41 Vector<const char> debug_name, Zone* zone, Code::Kind code_kind)
42 : OptimizedCompilationInfo(code_kind, zone) {
43 debug_name_ = debug_name;
44
45 SetTracingFlags(
46 PassesFilter(debug_name, CStrVector(FLAG_trace_turbo_filter)));
47}
48
49OptimizedCompilationInfo::OptimizedCompilationInfo(Code::Kind code_kind,
50 Zone* zone)
51 : code_kind_(code_kind), zone_(zone) {
52 ConfigureFlags();
53}
54
55void OptimizedCompilationInfo::ConfigureFlags() {
56 if (FLAG_untrusted_code_mitigations) SetFlag(kUntrustedCodeMitigations);
57
58 switch (code_kind_) {
59 case Code::OPTIMIZED_FUNCTION:
60 SetFlag(kCalledWithCodeStartRegister);
61 SetFlag(kSwitchJumpTableEnabled);
62 if (FLAG_function_context_specialization) {
63 MarkAsFunctionContextSpecializing();
64 }
65 if (FLAG_turbo_splitting) {
66 MarkAsSplittingEnabled();
67 }
68 if (FLAG_untrusted_code_mitigations) {
69 MarkAsPoisoningRegisterArguments();
70 }
71 if (FLAG_analyze_environment_liveness) {
72 // TODO(yangguo): Disable this in case of debugging for crbug.com/826613
73 MarkAsAnalyzeEnvironmentLiveness();
74 }
75 break;
76 case Code::BYTECODE_HANDLER:
77 SetFlag(kCalledWithCodeStartRegister);
78 break;
79 case Code::BUILTIN:
80 case Code::STUB:
81#if ENABLE_GDB_JIT_INTERFACE && DEBUG
82 MarkAsSourcePositionsEnabled();
83#endif // ENABLE_GDB_JIT_INTERFACE && DEBUG
84 break;
85 case Code::WASM_FUNCTION:
86 SetFlag(kSwitchJumpTableEnabled);
87 break;
88 default:
89 break;
90 }
91
92 if (FLAG_turbo_control_flow_aware_allocation) {
93 MarkAsTurboControlFlowAwareAllocation();
94 }
95 if (FLAG_turbo_preprocess_ranges) {
96 MarkAsTurboPreprocessRanges();
97 }
98}
99
100OptimizedCompilationInfo::~OptimizedCompilationInfo() {
101 if (GetFlag(kDisableFutureOptimization) && has_shared_info()) {
102 shared_info()->DisableOptimization(bailout_reason());
103 }
104}
105
106void OptimizedCompilationInfo::set_deferred_handles(
107 std::shared_ptr<DeferredHandles> deferred_handles) {
108 DCHECK_NULL(deferred_handles_);
109 deferred_handles_.swap(deferred_handles);
110}
111
112void OptimizedCompilationInfo::set_deferred_handles(
113 DeferredHandles* deferred_handles) {
114 DCHECK_NULL(deferred_handles_);
115 deferred_handles_.reset(deferred_handles);
116}
117
118void OptimizedCompilationInfo::ReopenHandlesInNewHandleScope(Isolate* isolate) {
119 if (!shared_info_.is_null()) {
120 shared_info_ = Handle<SharedFunctionInfo>(*shared_info_, isolate);
121 }
122 if (!bytecode_array_.is_null()) {
123 bytecode_array_ = Handle<BytecodeArray>(*bytecode_array_, isolate);
124 }
125 if (!closure_.is_null()) {
126 closure_ = Handle<JSFunction>(*closure_, isolate);
127 }
128}
129
130void OptimizedCompilationInfo::AbortOptimization(BailoutReason reason) {
131 DCHECK_NE(reason, BailoutReason::kNoReason);
132 if (bailout_reason_ == BailoutReason::kNoReason) {
133 TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
134 "V8.AbortOptimization", TRACE_EVENT_SCOPE_THREAD,
135 "reason", GetBailoutReason(reason), "function",
136 shared_info()->TraceIDRef());
137 bailout_reason_ = reason;
138 }
139 SetFlag(kDisableFutureOptimization);
140}
141
142void OptimizedCompilationInfo::RetryOptimization(BailoutReason reason) {
143 DCHECK_NE(reason, BailoutReason::kNoReason);
144 if (GetFlag(kDisableFutureOptimization)) return;
145 TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
146 "V8.RetryOptimization", TRACE_EVENT_SCOPE_THREAD,
147 "reason", GetBailoutReason(reason), "function",
148 shared_info()->TraceIDRef());
149 bailout_reason_ = reason;
150}
151
152std::unique_ptr<char[]> OptimizedCompilationInfo::GetDebugName() const {
153 if (!shared_info().is_null()) {
154 return shared_info()->DebugName()->ToCString();
155 }
156 Vector<const char> name_vec = debug_name_;
157 if (name_vec.empty()) name_vec = ArrayVector("unknown");
158 std::unique_ptr<char[]> name(new char[name_vec.length() + 1]);
159 memcpy(name.get(), name_vec.start(), name_vec.length());
160 name[name_vec.length()] = '\0';
161 return name;
162}
163
164StackFrame::Type OptimizedCompilationInfo::GetOutputStackFrameType() const {
165 switch (code_kind()) {
166 case Code::STUB:
167 case Code::BYTECODE_HANDLER:
168 case Code::BUILTIN:
169 return StackFrame::STUB;
170 case Code::WASM_FUNCTION:
171 return StackFrame::WASM_COMPILED;
172 case Code::JS_TO_WASM_FUNCTION:
173 return StackFrame::JS_TO_WASM;
174 case Code::WASM_TO_JS_FUNCTION:
175 return StackFrame::WASM_TO_JS;
176 case Code::WASM_INTERPRETER_ENTRY:
177 return StackFrame::WASM_INTERPRETER_ENTRY;
178 default:
179 UNIMPLEMENTED();
180 return StackFrame::NONE;
181 }
182}
183
184void OptimizedCompilationInfo::SetWasmCompilationResult(
185 std::unique_ptr<wasm::WasmCompilationResult> wasm_compilation_result) {
186 wasm_compilation_result_ = std::move(wasm_compilation_result);
187}
188
189std::unique_ptr<wasm::WasmCompilationResult>
190OptimizedCompilationInfo::ReleaseWasmCompilationResult() {
191 return std::move(wasm_compilation_result_);
192}
193
194bool OptimizedCompilationInfo::has_context() const {
195 return !closure().is_null();
196}
197
198Context OptimizedCompilationInfo::context() const {
199 DCHECK(has_context());
200 return closure()->context();
201}
202
203bool OptimizedCompilationInfo::has_native_context() const {
204 return !closure().is_null() && !closure()->native_context().is_null();
205}
206
207Context OptimizedCompilationInfo::native_context() const {
208 DCHECK(has_native_context());
209 return closure()->native_context();
210}
211
212bool OptimizedCompilationInfo::has_global_object() const {
213 return has_native_context();
214}
215
216JSGlobalObject OptimizedCompilationInfo::global_object() const {
217 DCHECK(has_global_object());
218 return native_context()->global_object();
219}
220
221int OptimizedCompilationInfo::AddInlinedFunction(
222 Handle<SharedFunctionInfo> inlined_function,
223 Handle<BytecodeArray> inlined_bytecode, SourcePosition pos) {
224 int id = static_cast<int>(inlined_functions_.size());
225 inlined_functions_.push_back(
226 InlinedFunctionHolder(inlined_function, inlined_bytecode, pos));
227 return id;
228}
229
230void OptimizedCompilationInfo::SetTracingFlags(bool passes_filter) {
231 if (!passes_filter) return;
232 if (FLAG_trace_turbo) SetFlag(kTraceTurboJson);
233 if (FLAG_trace_turbo_graph) SetFlag(kTraceTurboGraph);
234 if (FLAG_trace_turbo_scheduled) SetFlag(kTraceTurboScheduled);
235}
236
237OptimizedCompilationInfo::InlinedFunctionHolder::InlinedFunctionHolder(
238 Handle<SharedFunctionInfo> inlined_shared_info,
239 Handle<BytecodeArray> inlined_bytecode, SourcePosition pos)
240 : shared_info(inlined_shared_info), bytecode_array(inlined_bytecode) {
241 DCHECK_EQ(shared_info->GetBytecodeArray(), *bytecode_array);
242 position.position = pos;
243 // initialized when generating the deoptimization literals
244 position.inlined_function_id = DeoptimizationData::kNotInlinedIndex;
245}
246
247std::unique_ptr<v8::tracing::TracedValue>
248OptimizedCompilationInfo::ToTracedValue() {
249 auto value = v8::tracing::TracedValue::Create();
250 value->SetBoolean("osr", is_osr());
251 value->SetBoolean("functionContextSpecialized",
252 is_function_context_specializing());
253 if (has_shared_info()) {
254 value->SetValue("function", shared_info()->TraceIDRef());
255 }
256 if (bailout_reason() != BailoutReason::kNoReason) {
257 value->SetString("bailoutReason", GetBailoutReason(bailout_reason()));
258 value->SetBoolean("disableFutureOptimization",
259 is_disable_future_optimization());
260 } else {
261 value->SetInteger("optimizationId", optimization_id());
262 value->BeginArray("inlinedFunctions");
263 for (auto const& inlined_function : inlined_functions()) {
264 value->BeginDictionary();
265 value->SetValue("function", inlined_function.shared_info->TraceIDRef());
266 // TODO(bmeurer): Also include the source position from the
267 // {inlined_function} here as dedicated "sourcePosition" field.
268 value->EndDictionary();
269 }
270 value->EndArray();
271 }
272 return value;
273}
274
275} // namespace internal
276} // namespace v8
277