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/codegen/optimized-compilation-info.h"
6
7 #include "src/api/api.h"
8 #include "src/codegen/source-position.h"
9 #include "src/debug/debug.h"
10 #include "src/execution/isolate.h"
11 #include "src/objects/objects-inl.h"
12 #include "src/objects/shared-function-info.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
OptimizedCompilationInfo(Zone * zone,Isolate * isolate,Handle<SharedFunctionInfo> shared,Handle<JSFunction> closure,CodeKind code_kind)20 OptimizedCompilationInfo::OptimizedCompilationInfo(
21 Zone* zone, Isolate* isolate, Handle<SharedFunctionInfo> shared,
22 Handle<JSFunction> closure, CodeKind code_kind)
23 : code_kind_(code_kind),
24 zone_(zone),
25 optimization_id_(isolate->NextOptimizationId()) {
26 DCHECK_EQ(*shared, closure->shared());
27 DCHECK(shared->is_compiled());
28 bytecode_array_ = handle(shared->GetBytecodeArray(), isolate);
29 shared_info_ = shared;
30 closure_ = closure;
31
32 // Collect source positions for optimized code when profiling or if debugger
33 // is active, to be able to get more precise source positions at the price of
34 // more memory consumption.
35 if (isolate->NeedsDetailedOptimizedCodeLineInfo()) {
36 set_source_positions();
37 }
38
39 SetTracingFlags(shared->PassesFilter(FLAG_trace_turbo_filter));
40 ConfigureFlags();
41 }
42
OptimizedCompilationInfo(Vector<const char> debug_name,Zone * zone,CodeKind code_kind)43 OptimizedCompilationInfo::OptimizedCompilationInfo(
44 Vector<const char> debug_name, Zone* zone, CodeKind code_kind)
45 : code_kind_(code_kind),
46 zone_(zone),
47 optimization_id_(kNoOptimizationId),
48 debug_name_(debug_name) {
49 SetTracingFlags(
50 PassesFilter(debug_name, CStrVector(FLAG_trace_turbo_filter)));
51 ConfigureFlags();
52 }
53
54 #ifdef DEBUG
FlagSetIsValid(Flag flag) const55 bool OptimizedCompilationInfo::FlagSetIsValid(Flag flag) const {
56 switch (flag) {
57 case kPoisonRegisterArguments:
58 return untrusted_code_mitigations();
59 case kFunctionContextSpecializing:
60 return !IsNativeContextIndependent();
61 default:
62 return true;
63 }
64 UNREACHABLE();
65 }
66
FlagGetIsValid(Flag flag) const67 bool OptimizedCompilationInfo::FlagGetIsValid(Flag flag) const {
68 switch (flag) {
69 case kPoisonRegisterArguments:
70 if (!GetFlag(kPoisonRegisterArguments)) return true;
71 return untrusted_code_mitigations() && called_with_code_start_register();
72 default:
73 return true;
74 }
75 UNREACHABLE();
76 }
77 #endif // DEBUG
78
ConfigureFlags()79 void OptimizedCompilationInfo::ConfigureFlags() {
80 if (FLAG_untrusted_code_mitigations) set_untrusted_code_mitigations();
81
82 switch (code_kind_) {
83 case CodeKind::TURBOFAN:
84 if (FLAG_function_context_specialization) {
85 set_function_context_specializing();
86 }
87 V8_FALLTHROUGH;
88 case CodeKind::TURBOPROP:
89 case CodeKind::NATIVE_CONTEXT_INDEPENDENT:
90 set_called_with_code_start_register();
91 set_switch_jump_table();
92 if (FLAG_turbo_splitting) set_splitting();
93 if (FLAG_untrusted_code_mitigations) set_poison_register_arguments();
94 // TODO(yangguo): Disable this in case of debugging for crbug.com/826613
95 if (FLAG_analyze_environment_liveness) set_analyze_environment_liveness();
96 break;
97 case CodeKind::BYTECODE_HANDLER:
98 set_called_with_code_start_register();
99 if (FLAG_turbo_splitting) set_splitting();
100 break;
101 case CodeKind::BUILTIN:
102 case CodeKind::FOR_TESTING:
103 if (FLAG_turbo_splitting) set_splitting();
104 #if ENABLE_GDB_JIT_INTERFACE && DEBUG
105 set_source_positions();
106 #endif // ENABLE_GDB_JIT_INTERFACE && DEBUG
107 break;
108 case CodeKind::WASM_FUNCTION:
109 case CodeKind::WASM_TO_CAPI_FUNCTION:
110 set_switch_jump_table();
111 break;
112 default:
113 break;
114 }
115 }
116
~OptimizedCompilationInfo()117 OptimizedCompilationInfo::~OptimizedCompilationInfo() {
118 if (disable_future_optimization() && has_shared_info()) {
119 shared_info()->DisableOptimization(bailout_reason());
120 }
121 }
122
ReopenHandlesInNewHandleScope(Isolate * isolate)123 void OptimizedCompilationInfo::ReopenHandlesInNewHandleScope(Isolate* isolate) {
124 if (!shared_info_.is_null()) {
125 shared_info_ = Handle<SharedFunctionInfo>(*shared_info_, isolate);
126 }
127 if (!bytecode_array_.is_null()) {
128 bytecode_array_ = Handle<BytecodeArray>(*bytecode_array_, isolate);
129 }
130 if (!closure_.is_null()) {
131 closure_ = Handle<JSFunction>(*closure_, isolate);
132 }
133 DCHECK(code_.is_null());
134 }
135
AbortOptimization(BailoutReason reason)136 void OptimizedCompilationInfo::AbortOptimization(BailoutReason reason) {
137 DCHECK_NE(reason, BailoutReason::kNoReason);
138 if (bailout_reason_ == BailoutReason::kNoReason) {
139 bailout_reason_ = reason;
140 }
141 set_disable_future_optimization();
142 }
143
RetryOptimization(BailoutReason reason)144 void OptimizedCompilationInfo::RetryOptimization(BailoutReason reason) {
145 DCHECK_NE(reason, BailoutReason::kNoReason);
146 if (disable_future_optimization()) return;
147 bailout_reason_ = reason;
148 }
149
GetDebugName() const150 std::unique_ptr<char[]> OptimizedCompilationInfo::GetDebugName() const {
151 if (!shared_info().is_null()) {
152 return shared_info()->DebugName().ToCString();
153 }
154 Vector<const char> name_vec = debug_name_;
155 if (name_vec.empty()) name_vec = ArrayVector("unknown");
156 std::unique_ptr<char[]> name(new char[name_vec.length() + 1]);
157 memcpy(name.get(), name_vec.begin(), name_vec.length());
158 name[name_vec.length()] = '\0';
159 return name;
160 }
161
GetOutputStackFrameType() const162 StackFrame::Type OptimizedCompilationInfo::GetOutputStackFrameType() const {
163 switch (code_kind()) {
164 case CodeKind::FOR_TESTING:
165 case CodeKind::BYTECODE_HANDLER:
166 case CodeKind::BUILTIN:
167 return StackFrame::STUB;
168 case CodeKind::WASM_FUNCTION:
169 return StackFrame::WASM;
170 case CodeKind::WASM_TO_CAPI_FUNCTION:
171 return StackFrame::WASM_EXIT;
172 case CodeKind::JS_TO_WASM_FUNCTION:
173 return StackFrame::JS_TO_WASM;
174 case CodeKind::WASM_TO_JS_FUNCTION:
175 return StackFrame::WASM_TO_JS;
176 case CodeKind::C_WASM_ENTRY:
177 return StackFrame::C_WASM_ENTRY;
178 default:
179 UNIMPLEMENTED();
180 return StackFrame::NONE;
181 }
182 }
183
SetCode(Handle<Code> code)184 void OptimizedCompilationInfo::SetCode(Handle<Code> code) {
185 DCHECK_EQ(code->kind(), code_kind());
186 code_ = code;
187 }
188
SetWasmCompilationResult(std::unique_ptr<wasm::WasmCompilationResult> wasm_compilation_result)189 void OptimizedCompilationInfo::SetWasmCompilationResult(
190 std::unique_ptr<wasm::WasmCompilationResult> wasm_compilation_result) {
191 wasm_compilation_result_ = std::move(wasm_compilation_result);
192 }
193
194 std::unique_ptr<wasm::WasmCompilationResult>
ReleaseWasmCompilationResult()195 OptimizedCompilationInfo::ReleaseWasmCompilationResult() {
196 return std::move(wasm_compilation_result_);
197 }
198
has_context() const199 bool OptimizedCompilationInfo::has_context() const {
200 return !closure().is_null();
201 }
202
context() const203 Context OptimizedCompilationInfo::context() const {
204 DCHECK(has_context());
205 return closure()->context();
206 }
207
has_native_context() const208 bool OptimizedCompilationInfo::has_native_context() const {
209 return !closure().is_null() && !closure()->native_context().is_null();
210 }
211
native_context() const212 NativeContext OptimizedCompilationInfo::native_context() const {
213 DCHECK(has_native_context());
214 return closure()->native_context();
215 }
216
has_global_object() const217 bool OptimizedCompilationInfo::has_global_object() const {
218 return has_native_context();
219 }
220
global_object() const221 JSGlobalObject OptimizedCompilationInfo::global_object() const {
222 DCHECK(has_global_object());
223 return native_context().global_object();
224 }
225
AddInlinedFunction(Handle<SharedFunctionInfo> inlined_function,Handle<BytecodeArray> inlined_bytecode,SourcePosition pos)226 int OptimizedCompilationInfo::AddInlinedFunction(
227 Handle<SharedFunctionInfo> inlined_function,
228 Handle<BytecodeArray> inlined_bytecode, SourcePosition pos) {
229 int id = static_cast<int>(inlined_functions_.size());
230 inlined_functions_.push_back(
231 InlinedFunctionHolder(inlined_function, inlined_bytecode, pos));
232 return id;
233 }
234
SetTracingFlags(bool passes_filter)235 void OptimizedCompilationInfo::SetTracingFlags(bool passes_filter) {
236 if (!passes_filter) return;
237 if (FLAG_trace_turbo) set_trace_turbo_json();
238 if (FLAG_trace_turbo_graph) set_trace_turbo_graph();
239 if (FLAG_trace_turbo_scheduled) set_trace_turbo_scheduled();
240 if (FLAG_trace_turbo_alloc) set_trace_turbo_allocation();
241 if (FLAG_trace_heap_broker) set_trace_heap_broker();
242 }
243
InlinedFunctionHolder(Handle<SharedFunctionInfo> inlined_shared_info,Handle<BytecodeArray> inlined_bytecode,SourcePosition pos)244 OptimizedCompilationInfo::InlinedFunctionHolder::InlinedFunctionHolder(
245 Handle<SharedFunctionInfo> inlined_shared_info,
246 Handle<BytecodeArray> inlined_bytecode, SourcePosition pos)
247 : shared_info(inlined_shared_info), bytecode_array(inlined_bytecode) {
248 position.position = pos;
249 // initialized when generating the deoptimization literals
250 position.inlined_function_id = DeoptimizationData::kNotInlinedIndex;
251 }
252
253 } // namespace internal
254 } // namespace v8
255