Commit 980e224a authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[nci] Update interrupt budget from NCI code

This is the first step towards implementing a tier-up mechanism from
NCI code to TF. We will follow the existing Ignition-to-Turbofan
mechanics, which are, roughly:

1. Track a bytecode interrupt budget.
2. When exhausted, call the runtime profiler, which increments
   profiler ticks for the top frame's function.
3. When a function should tier up, it is marked as such using the
   FeedbackVector::optimized_code_weak_or_smi slot / the
   OptimizationMarker mechanism.
4. The InterpreterEntryTrampoline checks this slot and calls into
   runtime to compile if needed.
5. The finished code is also placed into this slot, as well as
   installed on the JSFunction.
6. Again, the IET checks the slot and tail-calls the code object if it
   exists.

This CL implements step 1 for NCI code by inserting the new simplified
UpdateInterruptBudget operator at the same spots (and using the same
offsets) as Ignition. When the budget is exhausted, we call a runtime
function that currently does nothing and will be implemented in the
next CL.

Bug: v8:8888
Change-Id: I98c0f8d96f32d515218dc2a76f961d44fe281c86
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2312778
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69124}
parent 4f0b79ee
...@@ -7,6 +7,8 @@ namespace internal { ...@@ -7,6 +7,8 @@ namespace internal {
namespace runtime { namespace runtime {
extern runtime GetTemplateObject(implicit context: Context)( extern runtime GetTemplateObject(implicit context: Context)(
TemplateObjectDescription, SharedFunctionInfo, Smi): JSAny; TemplateObjectDescription, SharedFunctionInfo, Smi): JSAny;
extern runtime BytecodeBudgetInterruptFromCode(implicit context: Context)(
FeedbackCell): JSAny;
} }
builtin GetTemplateObject( builtin GetTemplateObject(
...@@ -32,4 +34,11 @@ builtin GetTemplateObject( ...@@ -32,4 +34,11 @@ builtin GetTemplateObject(
} }
} }
builtin BytecodeBudgetInterruptFromCode(implicit context: Context)(
feedbackCell: FeedbackCell): Object {
// The runtime call is wrapped by a builtin since the calling sequence in
// generated code is shorter for builtins than for runtime calls.
tail runtime::BytecodeBudgetInterruptFromCode(feedbackCell);
}
} // namespace internal } // namespace internal
...@@ -1217,6 +1217,18 @@ FieldAccess AccessBuilder::ForFeedbackCellValue() { ...@@ -1217,6 +1217,18 @@ FieldAccess AccessBuilder::ForFeedbackCellValue() {
return access; return access;
} }
// static
FieldAccess AccessBuilder::ForFeedbackCellInterruptBudget() {
FieldAccess access = {kTaggedBase,
FeedbackCell::kInterruptBudgetOffset,
Handle<Name>(),
MaybeHandle<Map>(),
TypeCache::Get()->kInt32,
MachineType::Int32(),
kNoWriteBarrier};
return access;
}
// static // static
FieldAccess AccessBuilder::ForFeedbackVectorClosureFeedbackCellArray() { FieldAccess AccessBuilder::ForFeedbackVectorClosureFeedbackCellArray() {
FieldAccess access = { FieldAccess access = {
......
...@@ -338,8 +338,9 @@ class V8_EXPORT_PRIVATE AccessBuilder final ...@@ -338,8 +338,9 @@ class V8_EXPORT_PRIVATE AccessBuilder final
static FieldAccess ForDictionaryNextEnumerationIndex(); static FieldAccess ForDictionaryNextEnumerationIndex();
static FieldAccess ForDictionaryObjectHashIndex(); static FieldAccess ForDictionaryObjectHashIndex();
// Provides access to a FeedbackCell's value. // Provides access to FeedbackCell fields.
static FieldAccess ForFeedbackCellValue(); static FieldAccess ForFeedbackCellValue();
static FieldAccess ForFeedbackCellInterruptBudget();
// Provides access to a FeedbackVector fields. // Provides access to a FeedbackVector fields.
static FieldAccess ForFeedbackVectorClosureFeedbackCellArray(); static FieldAccess ForFeedbackVectorClosureFeedbackCellArray();
......
...@@ -80,6 +80,13 @@ class BytecodeGraphBuilder { ...@@ -80,6 +80,13 @@ class BytecodeGraphBuilder {
return feedback_vector_node_; return feedback_vector_node_;
} }
void CreateFeedbackCellNode();
Node* BuildLoadFeedbackCell();
Node* feedback_cell_node() const {
DCHECK_NOT_NULL(feedback_cell_node_);
return feedback_cell_node_;
}
// Same as above for the feedback vector node. // Same as above for the feedback vector node.
void CreateNativeContextNode(); void CreateNativeContextNode();
Node* BuildLoadNativeContext(); Node* BuildLoadNativeContext();
...@@ -275,6 +282,8 @@ class BytecodeGraphBuilder { ...@@ -275,6 +282,8 @@ class BytecodeGraphBuilder {
void BuildJumpIfNotHole(); void BuildJumpIfNotHole();
void BuildJumpIfJSReceiver(); void BuildJumpIfJSReceiver();
void BuildUpdateInterruptBudget(int delta);
void BuildSwitchOnSmi(Node* condition); void BuildSwitchOnSmi(Node* condition);
void BuildSwitchOnGeneratorState( void BuildSwitchOnGeneratorState(
const ZoneVector<ResumeJumpTarget>& resume_jump_targets, const ZoneVector<ResumeJumpTarget>& resume_jump_targets,
...@@ -418,6 +427,7 @@ class BytecodeGraphBuilder { ...@@ -418,6 +427,7 @@ class BytecodeGraphBuilder {
Node** input_buffer_; Node** input_buffer_;
const bool native_context_independent_; const bool native_context_independent_;
Node* feedback_cell_node_;
Node* feedback_vector_node_; Node* feedback_vector_node_;
Node* native_context_node_; Node* native_context_node_;
...@@ -989,6 +999,7 @@ BytecodeGraphBuilder::BytecodeGraphBuilder( ...@@ -989,6 +999,7 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(
input_buffer_(nullptr), input_buffer_(nullptr),
native_context_independent_( native_context_independent_(
flags & BytecodeGraphBuilderFlag::kNativeContextIndependent), flags & BytecodeGraphBuilderFlag::kNativeContextIndependent),
feedback_cell_node_(nullptr),
feedback_vector_node_(nullptr), feedback_vector_node_(nullptr),
native_context_node_(nullptr), native_context_node_(nullptr),
needs_eager_checkpoint_(true), needs_eager_checkpoint_(true),
...@@ -1008,6 +1019,29 @@ Node* BytecodeGraphBuilder::GetFunctionClosure() { ...@@ -1008,6 +1019,29 @@ Node* BytecodeGraphBuilder::GetFunctionClosure() {
return function_closure_.get(); return function_closure_.get();
} }
void BytecodeGraphBuilder::CreateFeedbackCellNode() {
DCHECK_NULL(feedback_cell_node_);
if (native_context_independent()) {
feedback_cell_node_ = BuildLoadFeedbackCell();
}
}
Node* BytecodeGraphBuilder::BuildLoadFeedbackCell() {
DCHECK(native_context_independent());
DCHECK_NULL(feedback_cell_node_);
Environment* env = environment();
Node* control = env->GetControlDependency();
Node* effect = env->GetEffectDependency();
Node* feedback_cell = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSFunctionFeedbackCell()),
GetFunctionClosure(), effect, control);
env->UpdateEffectDependency(effect);
return feedback_cell;
}
void BytecodeGraphBuilder::CreateFeedbackVectorNode() { void BytecodeGraphBuilder::CreateFeedbackVectorNode() {
DCHECK_NULL(feedback_vector_node_); DCHECK_NULL(feedback_vector_node_);
feedback_vector_node_ = native_context_independent() feedback_vector_node_ = native_context_independent()
...@@ -1027,12 +1061,9 @@ Node* BytecodeGraphBuilder::BuildLoadFeedbackVector() { ...@@ -1027,12 +1061,9 @@ Node* BytecodeGraphBuilder::BuildLoadFeedbackVector() {
Node* control = env->GetControlDependency(); Node* control = env->GetControlDependency();
Node* effect = env->GetEffectDependency(); Node* effect = env->GetEffectDependency();
Node* feedback_cell = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSFunctionFeedbackCell()),
GetFunctionClosure(), effect, control);
Node* vector = effect = graph()->NewNode( Node* vector = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForFeedbackCellValue()), simplified()->LoadField(AccessBuilder::ForFeedbackCellValue()),
feedback_cell, effect, control); feedback_cell_node(), effect, control);
env->UpdateEffectDependency(effect); env->UpdateEffectDependency(effect);
return vector; return vector;
...@@ -1119,6 +1150,7 @@ void BytecodeGraphBuilder::CreateGraph() { ...@@ -1119,6 +1150,7 @@ void BytecodeGraphBuilder::CreateGraph() {
graph()->start()); graph()->start());
set_environment(&env); set_environment(&env);
CreateFeedbackCellNode();
CreateFeedbackVectorNode(); CreateFeedbackVectorNode();
CreateNativeContextNode(); CreateNativeContextNode();
VisitBytecodes(); VisitBytecodes();
...@@ -3448,6 +3480,9 @@ void BytecodeGraphBuilder::VisitSetPendingMessage() { ...@@ -3448,6 +3480,9 @@ void BytecodeGraphBuilder::VisitSetPendingMessage() {
void BytecodeGraphBuilder::BuildReturn(const BytecodeLivenessState* liveness) { void BytecodeGraphBuilder::BuildReturn(const BytecodeLivenessState* liveness) {
BuildLoopExitsForFunctionExit(liveness); BuildLoopExitsForFunctionExit(liveness);
// Note: Negated offset since a return acts like a backwards jump, and should
// decrement the budget.
BuildUpdateInterruptBudget(-bytecode_iterator().current_offset());
Node* pop_node = jsgraph()->ZeroConstant(); Node* pop_node = jsgraph()->ZeroConstant();
Node* control = Node* control =
NewNode(common()->Return(), pop_node, environment()->LookupAccumulator()); NewNode(common()->Return(), pop_node, environment()->LookupAccumulator());
...@@ -3861,6 +3896,7 @@ void BytecodeGraphBuilder::BuildLoopExitsForFunctionExit( ...@@ -3861,6 +3896,7 @@ void BytecodeGraphBuilder::BuildLoopExitsForFunctionExit(
} }
void BytecodeGraphBuilder::BuildJump() { void BytecodeGraphBuilder::BuildJump() {
BuildUpdateInterruptBudget(bytecode_iterator().GetRelativeJumpTargetOffset());
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
} }
...@@ -3869,6 +3905,8 @@ void BytecodeGraphBuilder::BuildJumpIf(Node* condition) { ...@@ -3869,6 +3905,8 @@ void BytecodeGraphBuilder::BuildJumpIf(Node* condition) {
{ {
SubEnvironment sub_environment(this); SubEnvironment sub_environment(this);
NewIfTrue(); NewIfTrue();
BuildUpdateInterruptBudget(
bytecode_iterator().GetRelativeJumpTargetOffset());
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
} }
NewIfFalse(); NewIfFalse();
...@@ -3879,6 +3917,8 @@ void BytecodeGraphBuilder::BuildJumpIfNot(Node* condition) { ...@@ -3879,6 +3917,8 @@ void BytecodeGraphBuilder::BuildJumpIfNot(Node* condition) {
{ {
SubEnvironment sub_environment(this); SubEnvironment sub_environment(this);
NewIfFalse(); NewIfFalse();
BuildUpdateInterruptBudget(
bytecode_iterator().GetRelativeJumpTargetOffset());
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
} }
NewIfTrue(); NewIfTrue();
...@@ -3904,6 +3944,8 @@ void BytecodeGraphBuilder::BuildJumpIfFalse() { ...@@ -3904,6 +3944,8 @@ void BytecodeGraphBuilder::BuildJumpIfFalse() {
{ {
SubEnvironment sub_environment(this); SubEnvironment sub_environment(this);
NewIfFalse(); NewIfFalse();
BuildUpdateInterruptBudget(
bytecode_iterator().GetRelativeJumpTargetOffset());
environment()->BindAccumulator(jsgraph()->FalseConstant()); environment()->BindAccumulator(jsgraph()->FalseConstant());
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
} }
...@@ -3918,6 +3960,8 @@ void BytecodeGraphBuilder::BuildJumpIfTrue() { ...@@ -3918,6 +3960,8 @@ void BytecodeGraphBuilder::BuildJumpIfTrue() {
SubEnvironment sub_environment(this); SubEnvironment sub_environment(this);
NewIfTrue(); NewIfTrue();
environment()->BindAccumulator(jsgraph()->TrueConstant()); environment()->BindAccumulator(jsgraph()->TrueConstant());
BuildUpdateInterruptBudget(
bytecode_iterator().GetRelativeJumpTargetOffset());
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset()); MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
} }
NewIfFalse(); NewIfFalse();
...@@ -3949,6 +3993,16 @@ void BytecodeGraphBuilder::BuildJumpIfJSReceiver() { ...@@ -3949,6 +3993,16 @@ void BytecodeGraphBuilder::BuildJumpIfJSReceiver() {
BuildJumpIf(condition); BuildJumpIf(condition);
} }
void BytecodeGraphBuilder::BuildUpdateInterruptBudget(int delta) {
if (native_context_independent()) {
// Keep uses of this in sync with Ignition's UpdateInterruptBudget.
int delta_with_current_bytecode =
delta - bytecode_iterator().current_bytecode_size();
NewNode(simplified()->UpdateInterruptBudget(delta_with_current_bytecode),
feedback_cell_node());
}
}
JSTypeHintLowering::LoweringResult JSTypeHintLowering::LoweringResult
BytecodeGraphBuilder::TryBuildSimplifiedUnaryOp(const Operator* op, BytecodeGraphBuilder::TryBuildSimplifiedUnaryOp(const Operator* op,
Node* operand, Node* operand,
......
...@@ -179,6 +179,7 @@ class EffectControlLinearizer { ...@@ -179,6 +179,7 @@ class EffectControlLinearizer {
void LowerCheckEqualsInternalizedString(Node* node, Node* frame_state); void LowerCheckEqualsInternalizedString(Node* node, Node* frame_state);
void LowerCheckEqualsSymbol(Node* node, Node* frame_state); void LowerCheckEqualsSymbol(Node* node, Node* frame_state);
Node* LowerTypeOf(Node* node); Node* LowerTypeOf(Node* node);
Node* LowerUpdateInterruptBudget(Node* node);
Node* LowerToBoolean(Node* node); Node* LowerToBoolean(Node* node);
Node* LowerPlainPrimitiveToNumber(Node* node); Node* LowerPlainPrimitiveToNumber(Node* node);
Node* LowerPlainPrimitiveToWord32(Node* node); Node* LowerPlainPrimitiveToWord32(Node* node);
...@@ -1117,6 +1118,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node, ...@@ -1117,6 +1118,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kTypeOf: case IrOpcode::kTypeOf:
result = LowerTypeOf(node); result = LowerTypeOf(node);
break; break;
case IrOpcode::kUpdateInterruptBudget:
result = LowerUpdateInterruptBudget(node);
break;
case IrOpcode::kNewDoubleElements: case IrOpcode::kNewDoubleElements:
result = LowerNewDoubleElements(node); result = LowerNewDoubleElements(node);
break; break;
...@@ -3580,6 +3584,30 @@ Node* EffectControlLinearizer::LowerTypeOf(Node* node) { ...@@ -3580,6 +3584,30 @@ Node* EffectControlLinearizer::LowerTypeOf(Node* node) {
__ NoContextConstant()); __ NoContextConstant());
} }
Node* EffectControlLinearizer::LowerUpdateInterruptBudget(Node* node) {
UpdateInterruptBudgetNode n(node);
TNode<FeedbackCell> feedback_cell = n.feedback_cell();
TNode<Int32T> budget = __ LoadField<Int32T>(
AccessBuilder::ForFeedbackCellInterruptBudget(), feedback_cell);
Node* new_budget = __ Int32Add(budget, __ Int32Constant(n.delta()));
if (n.delta() < 0) {
auto next = __ MakeLabel();
auto if_budget_exhausted = __ MakeDeferredLabel();
__ Branch(__ Int32LessThan(new_budget, __ Int32Constant(0)),
&if_budget_exhausted, &next);
__ Bind(&if_budget_exhausted);
CallBuiltin(Builtins::kBytecodeBudgetInterruptFromCode,
node->op()->properties(), feedback_cell);
__ Goto(&next);
__ Bind(&next);
}
__ StoreField(AccessBuilder::ForFeedbackCellInterruptBudget(), feedback_cell,
new_budget);
return nullptr;
}
Node* EffectControlLinearizer::LowerToBoolean(Node* node) { Node* EffectControlLinearizer::LowerToBoolean(Node* node) {
Node* obj = node->InputAt(0); Node* obj = node->InputAt(0);
Callable const callable = Callable const callable =
......
...@@ -389,105 +389,106 @@ ...@@ -389,105 +389,106 @@
#define SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(V) V(SpeculativeToNumber) #define SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(V) V(SpeculativeToNumber)
#define SIMPLIFIED_OTHER_OP_LIST(V) \ #define SIMPLIFIED_OTHER_OP_LIST(V) \
V(PlainPrimitiveToNumber) \ V(Allocate) \
V(PlainPrimitiveToWord32) \ V(AllocateRaw) \
V(PlainPrimitiveToFloat64) \ V(ArgumentsFrame) \
V(ArgumentsLength) \
V(AssertType) \
V(BooleanNot) \ V(BooleanNot) \
V(StringConcat) \
V(StringToNumber) \
V(StringCharCodeAt) \
V(StringCodePointAt) \
V(StringFromSingleCharCode) \
V(StringFromSingleCodePoint) \
V(StringFromCodePointAt) \
V(StringIndexOf) \
V(StringLength) \
V(StringToLowerCaseIntl) \
V(StringToUpperCaseIntl) \
V(StringSubstring) \
V(CheckBounds) \ V(CheckBounds) \
V(CheckClosure) \
V(CheckEqualsInternalizedString) \
V(CheckEqualsSymbol) \
V(CheckFloat64Hole) \
V(CheckHeapObject) \
V(CheckIf) \ V(CheckIf) \
V(CheckInternalizedString) \
V(CheckMaps) \ V(CheckMaps) \
V(DynamicCheckMaps) \ V(CheckNotTaggedHole) \
V(CheckNumber) \ V(CheckNumber) \
V(CheckInternalizedString) \
V(CheckReceiver) \ V(CheckReceiver) \
V(CheckReceiverOrNullOrUndefined) \ V(CheckReceiverOrNullOrUndefined) \
V(CheckSmi) \
V(CheckString) \ V(CheckString) \
V(CheckSymbol) \ V(CheckSymbol) \
V(CheckSmi) \
V(CheckHeapObject) \
V(CheckFloat64Hole) \
V(CheckClosure) \
V(CheckNotTaggedHole) \
V(CheckEqualsInternalizedString) \
V(CheckEqualsSymbol) \
V(CompareMaps) \ V(CompareMaps) \
V(ConvertReceiver) \ V(ConvertReceiver) \
V(ConvertTaggedHoleToUndefined) \ V(ConvertTaggedHoleToUndefined) \
V(TypeOf) \ V(DateNow) \
V(Allocate) \ V(DelayedStringConstant) \
V(AllocateRaw) \ V(DynamicCheckMaps) \
V(LoadFieldByIndex) \ V(EnsureWritableFastElements) \
V(LoadField) \ V(FastApiCall) \
V(FindOrderedHashMapEntry) \
V(FindOrderedHashMapEntryForInt32Key) \
V(LoadDataViewElement) \
V(LoadElement) \ V(LoadElement) \
V(LoadMessage) \ V(LoadField) \
V(LoadTypedElement) \ V(LoadFieldByIndex) \
V(LoadFromObject) \ V(LoadFromObject) \
V(LoadDataViewElement) \ V(LoadMessage) \
V(LoadStackArgument) \ V(LoadStackArgument) \
V(StoreField) \ V(LoadTypedElement) \
V(StoreElement) \ V(MaybeGrowFastElements) \
V(StoreMessage) \ V(NewArgumentsElements) \
V(StoreTypedElement) \ V(NewConsString) \
V(StoreToObject) \ V(NewDoubleElements) \
V(StoreDataViewElement) \ V(NewSmiOrObjectElements) \
V(StoreSignedSmallElement) \
V(TransitionAndStoreElement) \
V(TransitionAndStoreNumberElement) \
V(TransitionAndStoreNonNumberElement) \
V(ToBoolean) \
V(NumberIsFloat64Hole) \
V(NumberIsFinite) \ V(NumberIsFinite) \
V(ObjectIsFiniteNumber) \ V(NumberIsFloat64Hole) \
V(NumberIsInteger) \ V(NumberIsInteger) \
V(ObjectIsSafeInteger) \ V(NumberIsMinusZero) \
V(NumberIsNaN) \
V(NumberIsSafeInteger) \ V(NumberIsSafeInteger) \
V(ObjectIsInteger) \
V(ObjectIsArrayBufferView) \ V(ObjectIsArrayBufferView) \
V(ObjectIsBigInt) \ V(ObjectIsBigInt) \
V(ObjectIsCallable) \ V(ObjectIsCallable) \
V(ObjectIsConstructor) \ V(ObjectIsConstructor) \
V(ObjectIsDetectableCallable) \ V(ObjectIsDetectableCallable) \
V(ObjectIsFiniteNumber) \
V(ObjectIsInteger) \
V(ObjectIsMinusZero) \ V(ObjectIsMinusZero) \
V(NumberIsMinusZero) \
V(ObjectIsNaN) \ V(ObjectIsNaN) \
V(NumberIsNaN) \
V(ObjectIsNonCallable) \ V(ObjectIsNonCallable) \
V(ObjectIsNumber) \ V(ObjectIsNumber) \
V(ObjectIsReceiver) \ V(ObjectIsReceiver) \
V(ObjectIsSafeInteger) \
V(ObjectIsSmi) \ V(ObjectIsSmi) \
V(ObjectIsString) \ V(ObjectIsString) \
V(ObjectIsSymbol) \ V(ObjectIsSymbol) \
V(ObjectIsUndetectable) \ V(ObjectIsUndetectable) \
V(ArgumentsFrame) \ V(PlainPrimitiveToFloat64) \
V(ArgumentsLength) \ V(PlainPrimitiveToNumber) \
V(RestLength) \ V(PlainPrimitiveToWord32) \
V(NewDoubleElements) \
V(NewSmiOrObjectElements) \
V(NewArgumentsElements) \
V(NewConsString) \
V(DelayedStringConstant) \
V(EnsureWritableFastElements) \
V(MaybeGrowFastElements) \
V(TransitionElementsKind) \
V(FindOrderedHashMapEntry) \
V(FindOrderedHashMapEntryForInt32Key) \
V(PoisonIndex) \ V(PoisonIndex) \
V(RestLength) \
V(RuntimeAbort) \ V(RuntimeAbort) \
V(AssertType) \ V(StoreDataViewElement) \
V(DateNow) \ V(StoreElement) \
V(FastApiCall) V(StoreField) \
V(StoreMessage) \
V(StoreSignedSmallElement) \
V(StoreToObject) \
V(StoreTypedElement) \
V(StringCharCodeAt) \
V(StringCodePointAt) \
V(StringConcat) \
V(StringFromCodePointAt) \
V(StringFromSingleCharCode) \
V(StringFromSingleCodePoint) \
V(StringIndexOf) \
V(StringLength) \
V(StringSubstring) \
V(StringToLowerCaseIntl) \
V(StringToNumber) \
V(StringToUpperCaseIntl) \
V(ToBoolean) \
V(TransitionAndStoreElement) \
V(TransitionAndStoreNonNumberElement) \
V(TransitionAndStoreNumberElement) \
V(TransitionElementsKind) \
V(TypeOf) \
V(UpdateInterruptBudget)
#define SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(V) \ #define SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(V) \
V(SpeculativeBigIntAdd) \ V(SpeculativeBigIntAdd) \
......
...@@ -2825,6 +2825,12 @@ class RepresentationSelector { ...@@ -2825,6 +2825,12 @@ class RepresentationSelector {
return VisitUnop<T>(node, UseInfo::AnyTagged(), return VisitUnop<T>(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedPointer); MachineRepresentation::kTaggedPointer);
} }
case IrOpcode::kUpdateInterruptBudget: {
ProcessInput<T>(node, 0, UseInfo::AnyTagged());
ProcessRemainingInputs<T>(node, 1);
SetOutput<T>(node, MachineRepresentation::kNone);
return;
}
case IrOpcode::kNewConsString: { case IrOpcode::kNewConsString: {
ProcessInput<T>(node, 0, UseInfo::TruncatingWord32()); // length ProcessInput<T>(node, 0, UseInfo::TruncatingWord32()); // length
ProcessInput<T>(node, 1, UseInfo::AnyTagged()); // first ProcessInput<T>(node, 1, UseInfo::AnyTagged()); // first
......
...@@ -1309,6 +1309,12 @@ const Operator* SimplifiedOperatorBuilder::BigIntAsUintN(int bits) { ...@@ -1309,6 +1309,12 @@ const Operator* SimplifiedOperatorBuilder::BigIntAsUintN(int bits) {
"BigIntAsUintN", 1, 0, 0, 1, 0, 0, bits); "BigIntAsUintN", 1, 0, 0, 1, 0, 0, bits);
} }
const Operator* SimplifiedOperatorBuilder::UpdateInterruptBudget(int delta) {
return zone()->New<Operator1<int>>(
IrOpcode::kUpdateInterruptBudget, Operator::kNoThrow | Operator::kNoDeopt,
"UpdateInterruptBudget", 1, 1, 1, 0, 1, 0, delta);
}
const Operator* SimplifiedOperatorBuilder::AssertType(Type type) { const Operator* SimplifiedOperatorBuilder::AssertType(Type type) {
DCHECK(type.IsRange()); DCHECK(type.IsRange());
return zone()->New<Operator1<Type>>(IrOpcode::kAssertType, return zone()->New<Operator1<Type>>(IrOpcode::kAssertType,
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/compiler/feedback-source.h" #include "src/compiler/feedback-source.h"
#include "src/compiler/node-properties.h" #include "src/compiler/node-properties.h"
#include "src/compiler/node.h"
#include "src/compiler/operator.h" #include "src/compiler/operator.h"
#include "src/compiler/types.h" #include "src/compiler/types.h"
#include "src/compiler/write-barrier-kind.h" #include "src/compiler/write-barrier-kind.h"
...@@ -793,6 +792,15 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final ...@@ -793,6 +792,15 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
const Operator* TypeOf(); const Operator* TypeOf();
// Adds the given delta to the current feedback vector's interrupt budget,
// and calls the runtime profiler in case the budget is exhausted. A note on
// the delta parameter: the interrupt budget mechanism originates in the
// interpreter and thus still refers to 'bytecodes' even though we are
// generating native code. The interrupt budget essentially corresponds to
// the number of bytecodes we can execute before calling the profiler. The
// delta parameter represents the executed bytecodes since the last update.
const Operator* UpdateInterruptBudget(int delta);
const Operator* ToBoolean(); const Operator* ToBoolean();
const Operator* StringConcat(); const Operator* StringConcat();
...@@ -1036,6 +1044,39 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final ...@@ -1036,6 +1044,39 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
DISALLOW_COPY_AND_ASSIGN(SimplifiedOperatorBuilder); DISALLOW_COPY_AND_ASSIGN(SimplifiedOperatorBuilder);
}; };
// Node wrappers.
// TODO(jgruber): Consider merging with JSNodeWrapperBase.
class SimplifiedNodeWrapperBase : public NodeWrapper {
public:
explicit constexpr SimplifiedNodeWrapperBase(Node* node)
: NodeWrapper(node) {}
// Valid iff this node has a context input.
TNode<Object> context() const {
// Could be a Context or NoContextConstant.
return TNode<Object>::UncheckedCast(
NodeProperties::GetContextInput(node()));
}
// Valid iff this node has exactly one effect input.
Effect effect() const {
DCHECK_EQ(node()->op()->EffectInputCount(), 1);
return Effect{NodeProperties::GetEffectInput(node())};
}
// Valid iff this node has exactly one control input.
Control control() const {
DCHECK_EQ(node()->op()->ControlInputCount(), 1);
return Control{NodeProperties::GetControlInput(node())};
}
// Valid iff this node has a frame state input.
FrameState frame_state() const {
return FrameState{NodeProperties::GetFrameStateInput(node())};
}
};
#define DEFINE_INPUT_ACCESSORS(Name, name, TheIndex, Type) \ #define DEFINE_INPUT_ACCESSORS(Name, name, TheIndex, Type) \
static constexpr int Name##Index() { return TheIndex; } \ static constexpr int Name##Index() { return TheIndex; } \
TNode<Type> name() const { \ TNode<Type> name() const { \
...@@ -1043,9 +1084,10 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final ...@@ -1043,9 +1084,10 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
NodeProperties::GetValueInput(node(), TheIndex)); \ NodeProperties::GetValueInput(node(), TheIndex)); \
} }
class FastApiCallNode final : public NodeWrapper { class FastApiCallNode final : public SimplifiedNodeWrapperBase {
public: public:
explicit constexpr FastApiCallNode(Node* node) : NodeWrapper(node) { explicit constexpr FastApiCallNode(Node* node)
: SimplifiedNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kFastApiCall); CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kFastApiCall);
} }
...@@ -1114,6 +1156,20 @@ class FastApiCallNode final : public NodeWrapper { ...@@ -1114,6 +1156,20 @@ class FastApiCallNode final : public NodeWrapper {
} }
}; };
class UpdateInterruptBudgetNode final : public SimplifiedNodeWrapperBase {
public:
explicit constexpr UpdateInterruptBudgetNode(Node* node)
: SimplifiedNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kUpdateInterruptBudget);
}
int delta() const { return OpParameter<int>(node()->op()); }
#define INPUTS(V) V(FeedbackCell, feedback_cell, 0, FeedbackCell)
INPUTS(DEFINE_INPUT_ACCESSORS)
#undef INPUTS
};
#undef DEFINE_INPUT_ACCESSORS #undef DEFINE_INPUT_ACCESSORS
} // namespace compiler } // namespace compiler
......
...@@ -1196,6 +1196,8 @@ Type Typer::Visitor::TypeTypeOf(Node* node) { ...@@ -1196,6 +1196,8 @@ Type Typer::Visitor::TypeTypeOf(Node* node) {
return Type::InternalizedString(); return Type::InternalizedString();
} }
Type Typer::Visitor::TypeUpdateInterruptBudget(Node* node) { UNREACHABLE(); }
// JS conversion operators. // JS conversion operators.
Type Typer::Visitor::TypeToBoolean(Node* node) { Type Typer::Visitor::TypeToBoolean(Node* node) {
......
...@@ -760,6 +760,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) { ...@@ -760,6 +760,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kTypeOf: case IrOpcode::kTypeOf:
CheckTypeIs(node, Type::InternalizedString()); CheckTypeIs(node, Type::InternalizedString());
break; break;
case IrOpcode::kUpdateInterruptBudget:
CheckValueInputIs(node, 0, Type::Any());
CheckNotTyped(node);
break;
case IrOpcode::kJSGetSuperConstructor: case IrOpcode::kJSGetSuperConstructor:
// We don't check the input for Type::Function because this_function can // We don't check the input for Type::Function because this_function can
// be context-allocated. // be context-allocated.
......
...@@ -203,7 +203,7 @@ OptimizationReason RuntimeProfiler::ShouldOptimize(JSFunction function, ...@@ -203,7 +203,7 @@ OptimizationReason RuntimeProfiler::ShouldOptimize(JSFunction function,
return OptimizationReason::kDoNotOptimize; return OptimizationReason::kDoNotOptimize;
} }
void RuntimeProfiler::MarkCandidatesForOptimization() { void RuntimeProfiler::MarkCandidatesForOptimizationFromBytecode() {
HandleScope scope(isolate_); HandleScope scope(isolate_);
if (!isolate_->use_optimizer()) return; if (!isolate_->use_optimizer()) return;
...@@ -240,5 +240,13 @@ void RuntimeProfiler::MarkCandidatesForOptimization() { ...@@ -240,5 +240,13 @@ void RuntimeProfiler::MarkCandidatesForOptimization() {
any_ic_changed_ = false; any_ic_changed_ = false;
} }
void RuntimeProfiler::MarkCandidatesForOptimizationFromCode() {
if (FLAG_trace_turbo_nci) {
StdoutStream os;
os << "NCI tier-up: Marking candidates for optimization" << std::endl;
}
// TODO(jgruber,v8:8888): Implement.
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -20,7 +20,10 @@ class RuntimeProfiler { ...@@ -20,7 +20,10 @@ class RuntimeProfiler {
public: public:
explicit RuntimeProfiler(Isolate* isolate); explicit RuntimeProfiler(Isolate* isolate);
void MarkCandidatesForOptimization(); // Called from the interpreter when the bytecode interrupt has been exhausted.
void MarkCandidatesForOptimizationFromBytecode();
// Likewise, from generated code.
void MarkCandidatesForOptimizationFromCode();
void NotifyICChanged() { any_ic_changed_ = true; } void NotifyICChanged() { any_ic_changed_ = true; }
......
...@@ -273,22 +273,26 @@ Handle<Object> BytecodeArrayAccessor::GetConstantForIndexOperand( ...@@ -273,22 +273,26 @@ Handle<Object> BytecodeArrayAccessor::GetConstantForIndexOperand(
return GetConstantAtIndex(GetIndexOperand(operand_index), isolate); return GetConstantAtIndex(GetIndexOperand(operand_index), isolate);
} }
int BytecodeArrayAccessor::GetJumpTargetOffset() const { int BytecodeArrayAccessor::GetRelativeJumpTargetOffset() const {
Bytecode bytecode = current_bytecode(); Bytecode bytecode = current_bytecode();
if (interpreter::Bytecodes::IsJumpImmediate(bytecode)) { if (interpreter::Bytecodes::IsJumpImmediate(bytecode)) {
int relative_offset = GetUnsignedImmediateOperand(0); int relative_offset = GetUnsignedImmediateOperand(0);
if (bytecode == Bytecode::kJumpLoop) { if (bytecode == Bytecode::kJumpLoop) {
relative_offset = -relative_offset; relative_offset = -relative_offset;
} }
return GetAbsoluteOffset(relative_offset); return relative_offset;
} else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) { } else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) {
Smi smi = GetConstantAtIndexAsSmi(GetIndexOperand(0)); Smi smi = GetConstantAtIndexAsSmi(GetIndexOperand(0));
return GetAbsoluteOffset(smi.value()); return smi.value();
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }
} }
int BytecodeArrayAccessor::GetJumpTargetOffset() const {
return GetAbsoluteOffset(GetRelativeJumpTargetOffset());
}
JumpTableTargetOffsets BytecodeArrayAccessor::GetJumpTableTargetOffsets() JumpTableTargetOffsets BytecodeArrayAccessor::GetJumpTableTargetOffsets()
const { const {
uint32_t table_start, table_size; uint32_t table_start, table_size;
......
...@@ -123,6 +123,10 @@ class V8_EXPORT_PRIVATE BytecodeArrayAccessor { ...@@ -123,6 +123,10 @@ class V8_EXPORT_PRIVATE BytecodeArrayAccessor {
Handle<Object> GetConstantForIndexOperand(int operand_index, Handle<Object> GetConstantForIndexOperand(int operand_index,
Isolate* isolate) const; Isolate* isolate) const;
// Returns the relative offset of the branch target at the current bytecode.
// It is an error to call this method if the bytecode is not for a jump or
// conditional jump. Returns a negative offset for backward jumps.
int GetRelativeJumpTargetOffset() const;
// Returns the absolute offset of the branch target at the current bytecode. // Returns the absolute offset of the branch target at the current bytecode.
// It is an error to call this method if the bytecode is not for a jump or // It is an error to call this method if the bytecode is not for a jump or
// conditional jump. // conditional jump.
......
...@@ -1048,7 +1048,8 @@ void InterpreterAssembler::UpdateInterruptBudget(TNode<Int32T> weight, ...@@ -1048,7 +1048,8 @@ void InterpreterAssembler::UpdateInterruptBudget(TNode<Int32T> weight,
Branch(condition, &ok, &interrupt_check); Branch(condition, &ok, &interrupt_check);
BIND(&interrupt_check); BIND(&interrupt_check);
CallRuntime(Runtime::kBytecodeBudgetInterrupt, GetContext(), function); CallRuntime(Runtime::kBytecodeBudgetInterruptFromBytecode, GetContext(),
function);
Goto(&done); Goto(&done);
BIND(&ok); BIND(&ok);
......
...@@ -326,7 +326,7 @@ RUNTIME_FUNCTION(Runtime_StackGuardWithGap) { ...@@ -326,7 +326,7 @@ RUNTIME_FUNCTION(Runtime_StackGuardWithGap) {
return isolate->stack_guard()->HandleInterrupts(); return isolate->stack_guard()->HandleInterrupts();
} }
RUNTIME_FUNCTION(Runtime_BytecodeBudgetInterrupt) { RUNTIME_FUNCTION(Runtime_BytecodeBudgetInterruptFromBytecode) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(1, args.length()); DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0); CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
...@@ -344,11 +344,26 @@ RUNTIME_FUNCTION(Runtime_BytecodeBudgetInterrupt) { ...@@ -344,11 +344,26 @@ RUNTIME_FUNCTION(Runtime_BytecodeBudgetInterrupt) {
{ {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
isolate->counters()->runtime_profiler_ticks()->Increment(); isolate->counters()->runtime_profiler_ticks()->Increment();
isolate->runtime_profiler()->MarkCandidatesForOptimization(); isolate->runtime_profiler()->MarkCandidatesForOptimizationFromBytecode();
return ReadOnlyRoots(isolate).undefined_value(); return ReadOnlyRoots(isolate).undefined_value();
} }
} }
RUNTIME_FUNCTION(Runtime_BytecodeBudgetInterruptFromCode) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(FeedbackCell, feedback_cell, 0);
DCHECK(feedback_cell->value().IsFeedbackVector());
feedback_cell->set_interrupt_budget(FLAG_interrupt_budget);
SealHandleScope shs(isolate);
isolate->counters()->runtime_profiler_ticks()->Increment();
isolate->runtime_profiler()->MarkCandidatesForOptimizationFromCode();
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_AllocateInYoungGeneration) { RUNTIME_FUNCTION(Runtime_AllocateInYoungGeneration) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(2, args.length());
......
...@@ -220,7 +220,8 @@ namespace internal { ...@@ -220,7 +220,8 @@ namespace internal {
F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \ F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \
F(GetTemplateObject, 3, 1) \ F(GetTemplateObject, 3, 1) \
F(IncrementUseCounter, 1, 1) \ F(IncrementUseCounter, 1, 1) \
F(BytecodeBudgetInterrupt, 1, 1) \ F(BytecodeBudgetInterruptFromBytecode, 1, 1) \
F(BytecodeBudgetInterruptFromCode, 1, 1) \
F(NewError, 2, 1) \ F(NewError, 2, 1) \
F(NewReferenceError, 2, 1) \ F(NewReferenceError, 2, 1) \
F(NewSyntaxError, 2, 1) \ F(NewSyntaxError, 2, 1) \
......
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