blob: bf45a5f38be7e4d4ab3b8aa18f64869067ccb0e8 [file] [log] [blame]
// 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, CodeKind code_kind)
: code_kind_(code_kind),
zone_(zone),
optimization_id_(isolate->NextOptimizationId()) {
DCHECK_EQ(*shared, closure->shared());
DCHECK(shared->is_compiled());
bytecode_array_ = handle(shared->GetBytecodeArray(), isolate);
shared_info_ = shared;
closure_ = closure;
// 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()) {
set_source_positions();
}
SetTracingFlags(shared->PassesFilter(FLAG_trace_turbo_filter));
ConfigureFlags();
}
OptimizedCompilationInfo::OptimizedCompilationInfo(
Vector<const char> debug_name, Zone* zone, CodeKind code_kind)
: code_kind_(code_kind),
zone_(zone),
optimization_id_(kNoOptimizationId),
debug_name_(debug_name) {
SetTracingFlags(
PassesFilter(debug_name, CStrVector(FLAG_trace_turbo_filter)));
ConfigureFlags();
}
#ifdef DEBUG
bool OptimizedCompilationInfo::FlagSetIsValid(Flag flag) const {
switch (flag) {
case kPoisonRegisterArguments:
return untrusted_code_mitigations();
case kFunctionContextSpecializing:
return !IsNativeContextIndependent();
default:
return true;
}
UNREACHABLE();
}
bool OptimizedCompilationInfo::FlagGetIsValid(Flag flag) const {
switch (flag) {
case kPoisonRegisterArguments:
if (!GetFlag(kPoisonRegisterArguments)) return true;
return untrusted_code_mitigations() && called_with_code_start_register();
default:
return true;
}
UNREACHABLE();
}
#endif // DEBUG
void OptimizedCompilationInfo::ConfigureFlags() {
if (FLAG_untrusted_code_mitigations) set_untrusted_code_mitigations();
switch (code_kind_) {
case CodeKind::TURBOFAN:
if (FLAG_function_context_specialization) {
set_function_context_specializing();
}
V8_FALLTHROUGH;
case CodeKind::TURBOPROP:
case CodeKind::NATIVE_CONTEXT_INDEPENDENT:
set_called_with_code_start_register();
set_switch_jump_table();
if (FLAG_turbo_splitting) set_splitting();
if (FLAG_untrusted_code_mitigations) set_poison_register_arguments();
// TODO(yangguo): Disable this in case of debugging for crbug.com/826613
if (FLAG_analyze_environment_liveness) set_analyze_environment_liveness();
break;
case CodeKind::BYTECODE_HANDLER:
set_called_with_code_start_register();
if (FLAG_turbo_splitting) set_splitting();
break;
case CodeKind::BUILTIN:
case CodeKind::FOR_TESTING:
if (FLAG_turbo_splitting) set_splitting();
#if ENABLE_GDB_JIT_INTERFACE && DEBUG
set_source_positions();
#endif // ENABLE_GDB_JIT_INTERFACE && DEBUG
break;
case CodeKind::WASM_FUNCTION:
case CodeKind::WASM_TO_CAPI_FUNCTION:
set_switch_jump_table();
break;
default:
break;
}
}
OptimizedCompilationInfo::~OptimizedCompilationInfo() {
if (disable_future_optimization() && has_shared_info()) {
shared_info()->DisableOptimization(bailout_reason());
}
}
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);
}
DCHECK(code_.is_null());
}
void OptimizedCompilationInfo::AbortOptimization(BailoutReason reason) {
DCHECK_NE(reason, BailoutReason::kNoReason);
if (bailout_reason_ == BailoutReason::kNoReason) {
bailout_reason_ = reason;
}
set_disable_future_optimization();
}
void OptimizedCompilationInfo::RetryOptimization(BailoutReason reason) {
DCHECK_NE(reason, BailoutReason::kNoReason);
if (disable_future_optimization()) return;
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 CodeKind::FOR_TESTING:
case CodeKind::BYTECODE_HANDLER:
case CodeKind::BUILTIN:
return StackFrame::STUB;
case CodeKind::WASM_FUNCTION:
return StackFrame::WASM;
case CodeKind::WASM_TO_CAPI_FUNCTION:
return StackFrame::WASM_EXIT;
case CodeKind::JS_TO_WASM_FUNCTION:
return StackFrame::JS_TO_WASM;
case CodeKind::WASM_TO_JS_FUNCTION:
return StackFrame::WASM_TO_JS;
case CodeKind::C_WASM_ENTRY:
return StackFrame::C_WASM_ENTRY;
default:
UNIMPLEMENTED();
return StackFrame::NONE;
}
}
void OptimizedCompilationInfo::SetCode(Handle<Code> code) {
DCHECK_EQ(code->kind(), code_kind());
code_ = code;
}
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) set_trace_turbo_json();
if (FLAG_trace_turbo_graph) set_trace_turbo_graph();
if (FLAG_trace_turbo_scheduled) set_trace_turbo_scheduled();
if (FLAG_trace_turbo_alloc) set_trace_turbo_allocation();
if (FLAG_trace_heap_broker) set_trace_heap_broker();
}
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;
}
} // namespace internal
} // namespace v8