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 | |
17 | namespace v8 { |
18 | namespace internal { |
19 | |
20 | OptimizedCompilationInfo::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 | |
40 | OptimizedCompilationInfo::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 | |
49 | OptimizedCompilationInfo::OptimizedCompilationInfo(Code::Kind code_kind, |
50 | Zone* zone) |
51 | : code_kind_(code_kind), zone_(zone) { |
52 | ConfigureFlags(); |
53 | } |
54 | |
55 | void 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 | |
100 | OptimizedCompilationInfo::~OptimizedCompilationInfo() { |
101 | if (GetFlag(kDisableFutureOptimization) && has_shared_info()) { |
102 | shared_info()->DisableOptimization(bailout_reason()); |
103 | } |
104 | } |
105 | |
106 | void OptimizedCompilationInfo::set_deferred_handles( |
107 | std::shared_ptr<DeferredHandles> deferred_handles) { |
108 | DCHECK_NULL(deferred_handles_); |
109 | deferred_handles_.swap(deferred_handles); |
110 | } |
111 | |
112 | void OptimizedCompilationInfo::set_deferred_handles( |
113 | DeferredHandles* deferred_handles) { |
114 | DCHECK_NULL(deferred_handles_); |
115 | deferred_handles_.reset(deferred_handles); |
116 | } |
117 | |
118 | void 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 | |
130 | void 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 | |
142 | void 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 | |
152 | std::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 | |
164 | StackFrame::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 | |
184 | void OptimizedCompilationInfo::SetWasmCompilationResult( |
185 | std::unique_ptr<wasm::WasmCompilationResult> wasm_compilation_result) { |
186 | wasm_compilation_result_ = std::move(wasm_compilation_result); |
187 | } |
188 | |
189 | std::unique_ptr<wasm::WasmCompilationResult> |
190 | OptimizedCompilationInfo::ReleaseWasmCompilationResult() { |
191 | return std::move(wasm_compilation_result_); |
192 | } |
193 | |
194 | bool OptimizedCompilationInfo::has_context() const { |
195 | return !closure().is_null(); |
196 | } |
197 | |
198 | Context OptimizedCompilationInfo::context() const { |
199 | DCHECK(has_context()); |
200 | return closure()->context(); |
201 | } |
202 | |
203 | bool OptimizedCompilationInfo::has_native_context() const { |
204 | return !closure().is_null() && !closure()->native_context().is_null(); |
205 | } |
206 | |
207 | Context OptimizedCompilationInfo::native_context() const { |
208 | DCHECK(has_native_context()); |
209 | return closure()->native_context(); |
210 | } |
211 | |
212 | bool OptimizedCompilationInfo::has_global_object() const { |
213 | return has_native_context(); |
214 | } |
215 | |
216 | JSGlobalObject OptimizedCompilationInfo::global_object() const { |
217 | DCHECK(has_global_object()); |
218 | return native_context()->global_object(); |
219 | } |
220 | |
221 | int 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 | |
230 | void 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 | |
237 | OptimizedCompilationInfo::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 | |
247 | std::unique_ptr<v8::tracing::TracedValue> |
248 | OptimizedCompilationInfo::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 | |