[turboprop] Add TURBOPROP code kind
Turboprop-generated Code objects will now have the dedicated TURBOPROP code kind instead of OPTIMIZED_FUNCTION. When possible, the code kind is used as the source of truth instead of FLAG_turboprop. This is the initial step towards implementing tier-up from Turboprop to Turbofan. Future work: Rename OPTIMIZED_FUNCTION to TURBOFAN, rename STUB to DEOPT_ENTRIES_OR_FOR_TESTING, implement TP tier-up. No-Try: true Bug: v8:9684 Cq-Include-Trybots: luci.v8.try:v8_linux64_fyi_rel_ng Change-Id: I3c9308718d7e9a2b7e6796e7ea94f17e5ff84c0a Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2424140 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Mythri Alle <mythria@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#70213}
This commit is contained in:
parent
83133d95f2
commit
75b8c238dc
@ -857,8 +857,7 @@ V8_WARN_UNUSED_RESULT MaybeHandle<Code> GetCodeFromOptimizedCodeCache(
|
||||
DCHECK(!code.marked_for_deoptimization());
|
||||
DCHECK(function->shared().is_compiled());
|
||||
DCHECK(CodeKindIsStoredInOptimizedCodeCache(code.kind()));
|
||||
DCHECK_IMPLIES(!osr_offset.IsNone(),
|
||||
code.kind() == CodeKind::OPTIMIZED_FUNCTION);
|
||||
DCHECK_IMPLIES(!osr_offset.IsNone(), CodeKindCanOSR(code.kind()));
|
||||
return Handle<Code>(code, isolate);
|
||||
}
|
||||
return MaybeHandle<Code>();
|
||||
@ -902,7 +901,7 @@ void InsertCodeIntoOptimizedCodeCache(
|
||||
handle(function->feedback_vector(), function->GetIsolate());
|
||||
FeedbackVector::SetOptimizedCode(vector, code);
|
||||
} else {
|
||||
DCHECK_EQ(kind, CodeKind::OPTIMIZED_FUNCTION);
|
||||
DCHECK(CodeKindCanOSR(kind));
|
||||
OSROptimizedCodeCache::AddOptimizedCode(native_context, shared, code,
|
||||
compilation_info->osr_offset());
|
||||
}
|
||||
|
@ -85,6 +85,7 @@ void OptimizedCompilationInfo::ConfigureFlags() {
|
||||
set_function_context_specializing();
|
||||
}
|
||||
V8_FALLTHROUGH;
|
||||
case CodeKind::TURBOPROP:
|
||||
case CodeKind::NATIVE_CONTEXT_INDEPENDENT:
|
||||
set_called_with_code_start_register();
|
||||
set_switch_jump_table();
|
||||
|
@ -429,7 +429,7 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo(
|
||||
PropertyConstness constness;
|
||||
if (details.IsReadOnly() && !details.IsConfigurable()) {
|
||||
constness = PropertyConstness::kConst;
|
||||
} else if (FLAG_turboprop && !map->is_prototype_map()) {
|
||||
} else if (broker()->is_turboprop() && !map->is_prototype_map()) {
|
||||
// The constness feedback is too unstable for the aggresive compilation
|
||||
// of turboprop.
|
||||
constness = PropertyConstness::kMutable;
|
||||
|
@ -4104,7 +4104,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
|
||||
if (feedback_target.has_value() && feedback_target->map().is_callable()) {
|
||||
Node* target_function = jsgraph()->Constant(*feedback_target);
|
||||
|
||||
if (FLAG_turboprop) {
|
||||
if (broker()->is_turboprop()) {
|
||||
if (!feedback_target->IsJSFunction()) return NoChange();
|
||||
if (!IsBuiltinOrApiFunction(feedback_target->AsJSFunction())) {
|
||||
return NoChange();
|
||||
@ -4138,7 +4138,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
if (FLAG_turboprop &&
|
||||
if (broker()->is_turboprop() &&
|
||||
!feedback_vector.shared_function_info().HasBuiltinId()) {
|
||||
return NoChange();
|
||||
}
|
||||
@ -4965,7 +4965,7 @@ Reduction JSCallReducer::ReduceForInsufficientFeedback(
|
||||
// TODO(mythria): May be add additional flags to specify if we need to deopt
|
||||
// on calls / construct rather than checking for TurboProp here. We may need
|
||||
// it for NativeContextIndependent code too.
|
||||
if (FLAG_turboprop) return NoChange();
|
||||
if (broker()->is_turboprop()) return NoChange();
|
||||
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
|
@ -2390,7 +2390,7 @@ SourceTextModuleRef ContextRef::GetModule(SerializationPolicy policy) const {
|
||||
|
||||
JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone,
|
||||
bool tracing_enabled, bool is_concurrent_inlining,
|
||||
bool is_native_context_independent)
|
||||
CodeKind code_kind)
|
||||
: isolate_(isolate),
|
||||
zone_(broker_zone),
|
||||
refs_(zone()->New<RefsMap>(kMinimalRefsBucketCount, AddressMatcher(),
|
||||
@ -2399,7 +2399,7 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone,
|
||||
array_and_object_prototypes_(zone()),
|
||||
tracing_enabled_(tracing_enabled),
|
||||
is_concurrent_inlining_(is_concurrent_inlining),
|
||||
is_native_context_independent_(is_native_context_independent),
|
||||
code_kind_(code_kind),
|
||||
local_heap_(base::nullopt),
|
||||
feedback_(zone()),
|
||||
bytecode_analyses_(zone()),
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "src/handles/persistent-handles.h"
|
||||
#include "src/heap/local-heap.h"
|
||||
#include "src/interpreter/bytecode-array-accessor.h"
|
||||
#include "src/objects/code-kind.h"
|
||||
#include "src/objects/feedback-vector.h"
|
||||
#include "src/objects/function-kind.h"
|
||||
#include "src/objects/objects.h"
|
||||
@ -78,13 +79,13 @@ struct PropertyAccessTarget {
|
||||
class V8_EXPORT_PRIVATE JSHeapBroker {
|
||||
public:
|
||||
JSHeapBroker(Isolate* isolate, Zone* broker_zone, bool tracing_enabled,
|
||||
bool is_concurrent_inlining, bool is_native_context_independent);
|
||||
bool is_concurrent_inlining, CodeKind code_kind);
|
||||
|
||||
// For use only in tests, sets default values for some arguments. Avoids
|
||||
// churn when new flags are added.
|
||||
JSHeapBroker(Isolate* isolate, Zone* broker_zone)
|
||||
: JSHeapBroker(isolate, broker_zone, FLAG_trace_heap_broker, false,
|
||||
false) {}
|
||||
CodeKind::OPTIMIZED_FUNCTION) {}
|
||||
|
||||
~JSHeapBroker();
|
||||
|
||||
@ -102,7 +103,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
|
||||
bool tracing_enabled() const { return tracing_enabled_; }
|
||||
bool is_concurrent_inlining() const { return is_concurrent_inlining_; }
|
||||
bool is_native_context_independent() const {
|
||||
return is_native_context_independent_;
|
||||
return code_kind_ == CodeKind::NATIVE_CONTEXT_INDEPENDENT;
|
||||
}
|
||||
bool generate_full_feedback_collection() const {
|
||||
// NCI code currently collects full feedback.
|
||||
@ -110,6 +111,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
|
||||
CollectFeedbackInGenericLowering());
|
||||
return is_native_context_independent();
|
||||
}
|
||||
bool is_turboprop() const { return code_kind_ == CodeKind::TURBOPROP; }
|
||||
|
||||
enum BrokerMode { kDisabled, kSerializing, kSerialized, kRetired };
|
||||
BrokerMode mode() const { return mode_; }
|
||||
@ -357,7 +359,7 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
|
||||
BrokerMode mode_ = kDisabled;
|
||||
bool const tracing_enabled_;
|
||||
bool const is_concurrent_inlining_;
|
||||
bool const is_native_context_independent_;
|
||||
CodeKind const code_kind_;
|
||||
std::unique_ptr<PersistentHandles> ph_;
|
||||
base::Optional<LocalHeap> local_heap_;
|
||||
std::unique_ptr<CanonicalHandlesMap> canonical_handles_;
|
||||
|
@ -574,8 +574,8 @@ Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackSlot slot, Node* effect,
|
||||
|
||||
FeedbackSource source(feedback_vector(), slot);
|
||||
// TODO(mythria): Think of adding flags to specify if we need a soft deopt for
|
||||
// calls instead of using FLAG_turboprop here.
|
||||
if (FLAG_turboprop &&
|
||||
// calls instead of using broker()->is_turboprop() here.
|
||||
if (broker()->is_turboprop() &&
|
||||
broker()->GetFeedbackSlotKind(source) == FeedbackSlotKind::kCall) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -151,9 +151,9 @@ class PipelineData {
|
||||
instruction_zone_(instruction_zone_scope_.zone()),
|
||||
codegen_zone_scope_(zone_stats_, kCodegenZoneName),
|
||||
codegen_zone_(codegen_zone_scope_.zone()),
|
||||
broker_(new JSHeapBroker(
|
||||
isolate_, info_->zone(), info_->trace_heap_broker(),
|
||||
is_concurrent_inlining, info->IsNativeContextIndependent())),
|
||||
broker_(new JSHeapBroker(isolate_, info_->zone(),
|
||||
info_->trace_heap_broker(),
|
||||
is_concurrent_inlining, info->code_kind())),
|
||||
register_allocation_zone_scope_(zone_stats_,
|
||||
kRegisterAllocationZoneName),
|
||||
register_allocation_zone_(register_allocation_zone_scope_.zone()),
|
||||
@ -1191,7 +1191,7 @@ PipelineCompilationJob::Status PipelineCompilationJob::ExecuteJobImpl(
|
||||
ParkedScope parked_scope(data_.broker()->local_heap());
|
||||
|
||||
bool success;
|
||||
if (FLAG_turboprop) {
|
||||
if (compilation_info_.code_kind() == CodeKind::TURBOPROP) {
|
||||
success = pipeline_.OptimizeGraphForMidTier(linkage_);
|
||||
} else {
|
||||
success = pipeline_.OptimizeGraph(linkage_);
|
||||
|
@ -1109,7 +1109,8 @@ bool SerializerForBackgroundCompilation::BailoutOnUninitialized(
|
||||
// OSR entry point. TODO(neis): Support OSR?
|
||||
return false;
|
||||
}
|
||||
if (FLAG_turboprop && feedback.slot_kind() == FeedbackSlotKind::kCall) {
|
||||
if (broker()->is_turboprop() &&
|
||||
feedback.slot_kind() == FeedbackSlotKind::kCall) {
|
||||
return false;
|
||||
}
|
||||
if (feedback.IsInsufficient()) {
|
||||
|
@ -205,7 +205,9 @@ void PerfJitLogger::LogRecordedBuffer(
|
||||
int length) {
|
||||
if (FLAG_perf_basic_prof_only_functions &&
|
||||
(abstract_code->kind() != CodeKind::INTERPRETED_FUNCTION &&
|
||||
abstract_code->kind() != CodeKind::OPTIMIZED_FUNCTION)) {
|
||||
abstract_code->kind() != CodeKind::OPTIMIZED_FUNCTION &&
|
||||
abstract_code->kind() != CodeKind::NATIVE_CONTEXT_INDEPENDENT &&
|
||||
abstract_code->kind() != CodeKind::TURBOPROP)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -591,6 +591,7 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
|
||||
return BUILTIN;
|
||||
case CodeKind::OPTIMIZED_FUNCTION:
|
||||
case CodeKind::NATIVE_CONTEXT_INDEPENDENT:
|
||||
case CodeKind::TURBOPROP:
|
||||
return OPTIMIZED;
|
||||
case CodeKind::JS_TO_WASM_FUNCTION:
|
||||
return JS_TO_WASM;
|
||||
|
@ -240,6 +240,10 @@ OptimizationReason RuntimeProfiler::ShouldOptimize(JSFunction function,
|
||||
if (function.ActiveTierIsTurbofan()) {
|
||||
return OptimizationReason::kDoNotOptimize;
|
||||
}
|
||||
if (V8_UNLIKELY(FLAG_turboprop) && function.ActiveTierIsTurboprop()) {
|
||||
// TODO(turboprop): Implement tier up from Turboprop.
|
||||
return OptimizationReason::kDoNotOptimize;
|
||||
}
|
||||
int ticks = function.feedback_vector().profiler_ticks();
|
||||
int ticks_for_optimization =
|
||||
kProfilerTicksBeforeOptimization +
|
||||
|
@ -78,11 +78,13 @@ static v8::CodeEventType GetCodeEventTypeForTag(
|
||||
}
|
||||
|
||||
static const char* ComputeMarker(SharedFunctionInfo shared, AbstractCode code) {
|
||||
// TODO(mythria,jgruber): Use different markers for Turboprop/NCI.
|
||||
switch (code.kind()) {
|
||||
case CodeKind::INTERPRETED_FUNCTION:
|
||||
return shared.optimization_disabled() ? "" : "~";
|
||||
case CodeKind::OPTIMIZED_FUNCTION:
|
||||
case CodeKind::NATIVE_CONTEXT_INDEPENDENT:
|
||||
case CodeKind::TURBOPROP:
|
||||
return "*";
|
||||
default:
|
||||
return "";
|
||||
@ -2164,6 +2166,7 @@ void ExistingCodeLogger::LogCodeObject(Object object) {
|
||||
case CodeKind::INTERPRETED_FUNCTION:
|
||||
case CodeKind::OPTIMIZED_FUNCTION:
|
||||
case CodeKind::NATIVE_CONTEXT_INDEPENDENT:
|
||||
case CodeKind::TURBOPROP:
|
||||
return; // We log this later using LogCompiledFunctions.
|
||||
case CodeKind::BYTECODE_HANDLER:
|
||||
return; // We log it later by walking the dispatch table.
|
||||
|
@ -15,20 +15,21 @@ namespace internal {
|
||||
// disambiguated Turboprop, Turbofan, and NCI code kinds.
|
||||
// TODO(jgruber): Rename STUB to DEOPT_ENTRIES_OR_FOR_TESTING, or split it into
|
||||
// DEOPT_ENTRIES and FOR_TESTING, or convert DEOPT_ENTRIES into a builtin.
|
||||
#define CODE_KIND_LIST(V) \
|
||||
V(OPTIMIZED_FUNCTION) \
|
||||
V(BYTECODE_HANDLER) \
|
||||
V(STUB) \
|
||||
V(BUILTIN) \
|
||||
V(REGEXP) \
|
||||
V(WASM_FUNCTION) \
|
||||
V(WASM_TO_CAPI_FUNCTION) \
|
||||
V(WASM_TO_JS_FUNCTION) \
|
||||
V(JS_TO_WASM_FUNCTION) \
|
||||
V(JS_TO_JS_FUNCTION) \
|
||||
V(C_WASM_ENTRY) \
|
||||
V(INTERPRETED_FUNCTION) \
|
||||
V(NATIVE_CONTEXT_INDEPENDENT)
|
||||
#define CODE_KIND_LIST(V) \
|
||||
V(OPTIMIZED_FUNCTION) \
|
||||
V(BYTECODE_HANDLER) \
|
||||
V(STUB) \
|
||||
V(BUILTIN) \
|
||||
V(REGEXP) \
|
||||
V(WASM_FUNCTION) \
|
||||
V(WASM_TO_CAPI_FUNCTION) \
|
||||
V(WASM_TO_JS_FUNCTION) \
|
||||
V(JS_TO_WASM_FUNCTION) \
|
||||
V(JS_TO_JS_FUNCTION) \
|
||||
V(C_WASM_ENTRY) \
|
||||
V(INTERPRETED_FUNCTION) \
|
||||
V(NATIVE_CONTEXT_INDEPENDENT) \
|
||||
V(TURBOPROP)
|
||||
|
||||
enum class CodeKind {
|
||||
#define DEFINE_CODE_KIND_ENUM(name) name,
|
||||
@ -53,7 +54,8 @@ inline constexpr bool CodeKindIsNativeContextIndependentJSFunction(
|
||||
|
||||
inline constexpr bool CodeKindIsOptimizedJSFunction(CodeKind kind) {
|
||||
return kind == CodeKind::OPTIMIZED_FUNCTION ||
|
||||
kind == CodeKind::NATIVE_CONTEXT_INDEPENDENT;
|
||||
kind == CodeKind::NATIVE_CONTEXT_INDEPENDENT ||
|
||||
kind == CodeKind::TURBOPROP;
|
||||
}
|
||||
|
||||
inline constexpr bool CodeKindIsJSFunction(CodeKind kind) {
|
||||
@ -72,6 +74,10 @@ inline constexpr bool CodeKindCanDeoptimize(CodeKind kind) {
|
||||
return CodeKindIsOptimizedJSFunction(kind);
|
||||
}
|
||||
|
||||
inline constexpr bool CodeKindCanOSR(CodeKind kind) {
|
||||
return kind == CodeKind::OPTIMIZED_FUNCTION || kind == CodeKind::TURBOPROP;
|
||||
}
|
||||
|
||||
inline constexpr bool CodeKindChecksOptimizationMarker(CodeKind kind) {
|
||||
return kind == CodeKind::INTERPRETED_FUNCTION ||
|
||||
kind == CodeKind::NATIVE_CONTEXT_INDEPENDENT;
|
||||
@ -82,10 +88,13 @@ inline constexpr bool CodeKindChecksOptimizationMarker(CodeKind kind) {
|
||||
// access from multiple closures. The marker is not used for all code kinds
|
||||
// though, in particular it is not used when generating NCI code.
|
||||
inline constexpr bool CodeKindIsStoredInOptimizedCodeCache(CodeKind kind) {
|
||||
return kind == CodeKind::OPTIMIZED_FUNCTION;
|
||||
return kind == CodeKind::OPTIMIZED_FUNCTION || kind == CodeKind::TURBOPROP;
|
||||
}
|
||||
|
||||
inline CodeKind CodeKindForTopTier() { return CodeKind::OPTIMIZED_FUNCTION; }
|
||||
inline CodeKind CodeKindForTopTier() {
|
||||
return V8_UNLIKELY(FLAG_turboprop) ? CodeKind::TURBOPROP
|
||||
: CodeKind::OPTIMIZED_FUNCTION;
|
||||
}
|
||||
|
||||
// The dedicated CodeKindFlag enum represents all code kinds in a format
|
||||
// suitable for bit sets.
|
||||
@ -108,10 +117,10 @@ DEFINE_OPERATORS_FOR_FLAGS(CodeKinds)
|
||||
|
||||
static constexpr CodeKinds kJSFunctionCodeKindsMask{
|
||||
CodeKindFlag::INTERPRETED_FUNCTION | CodeKindFlag::OPTIMIZED_FUNCTION |
|
||||
CodeKindFlag::NATIVE_CONTEXT_INDEPENDENT};
|
||||
CodeKindFlag::NATIVE_CONTEXT_INDEPENDENT | CodeKindFlag::TURBOPROP};
|
||||
static constexpr CodeKinds kOptimizedJSFunctionCodeKindsMask{
|
||||
CodeKindFlag::OPTIMIZED_FUNCTION |
|
||||
CodeKindFlag::NATIVE_CONTEXT_INDEPENDENT};
|
||||
CodeKindFlag::NATIVE_CONTEXT_INDEPENDENT | CodeKindFlag::TURBOPROP};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -90,6 +90,9 @@ bool HighestTierOf(CodeKinds kinds, CodeKind* highest_tier) {
|
||||
if ((kinds & CodeKindFlag::OPTIMIZED_FUNCTION) != 0) {
|
||||
*highest_tier = CodeKind::OPTIMIZED_FUNCTION;
|
||||
return true;
|
||||
} else if ((kinds & CodeKindFlag::TURBOPROP) != 0) {
|
||||
*highest_tier = CodeKind::TURBOPROP;
|
||||
return true;
|
||||
} else if ((kinds & CodeKindFlag::NATIVE_CONTEXT_INDEPENDENT) != 0) {
|
||||
*highest_tier = CodeKind::NATIVE_CONTEXT_INDEPENDENT;
|
||||
return true;
|
||||
@ -128,10 +131,19 @@ bool JSFunction::ActiveTierIsNCI() const {
|
||||
return highest_tier == CodeKind::NATIVE_CONTEXT_INDEPENDENT;
|
||||
}
|
||||
|
||||
bool JSFunction::ActiveTierIsTurboprop() const {
|
||||
CodeKind highest_tier;
|
||||
if (!HighestTierOf(GetAvailableCodeKinds(), &highest_tier)) return false;
|
||||
return highest_tier == CodeKind::TURBOPROP;
|
||||
}
|
||||
|
||||
CodeKind JSFunction::NextTier() const {
|
||||
return (FLAG_turbo_nci_as_midtier && ActiveTierIsIgnition())
|
||||
? CodeKind::NATIVE_CONTEXT_INDEPENDENT
|
||||
: CodeKind::OPTIMIZED_FUNCTION;
|
||||
if (V8_UNLIKELY(FLAG_turbo_nci_as_midtier && ActiveTierIsIgnition())) {
|
||||
return CodeKind::NATIVE_CONTEXT_INDEPENDENT;
|
||||
} else if (V8_UNLIKELY(FLAG_turboprop)) {
|
||||
return CodeKind::TURBOPROP;
|
||||
}
|
||||
return CodeKind::OPTIMIZED_FUNCTION;
|
||||
}
|
||||
|
||||
bool JSFunction::CanDiscardCompiled() const {
|
||||
@ -144,7 +156,7 @@ bool JSFunction::CanDiscardCompiled() const {
|
||||
//
|
||||
// Note that when the function has not yet been compiled we also return
|
||||
// false; that's fine, since nothing must be discarded in that case.
|
||||
if (code().kind() == CodeKind::OPTIMIZED_FUNCTION) return true;
|
||||
if (CodeKindIsOptimizedJSFunction(code().kind())) return true;
|
||||
CodeKinds result = GetAvailableCodeKinds();
|
||||
return (result & kJSFunctionCodeKindsMask) != 0;
|
||||
}
|
||||
|
@ -115,6 +115,7 @@ class JSFunction : public JSFunctionOrBoundFunction {
|
||||
V8_EXPORT_PRIVATE bool ActiveTierIsIgnition() const;
|
||||
bool ActiveTierIsTurbofan() const;
|
||||
bool ActiveTierIsNCI() const;
|
||||
bool ActiveTierIsTurboprop() const;
|
||||
|
||||
CodeKind NextTier() const;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user