Commit 75b8c238 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[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: 's avatarMythri Alle <mythria@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70213}
parent 83133d95
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment