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 {
namespace runtime {
extern runtime GetTemplateObject(implicit context: Context)(
TemplateObjectDescription, SharedFunctionInfo, Smi): JSAny;
extern runtime BytecodeBudgetInterruptFromCode(implicit context: Context)(
FeedbackCell): JSAny;
}
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
......@@ -1217,6 +1217,18 @@ FieldAccess AccessBuilder::ForFeedbackCellValue() {
return access;
}
// static
FieldAccess AccessBuilder::ForFeedbackCellInterruptBudget() {
FieldAccess access = {kTaggedBase,
FeedbackCell::kInterruptBudgetOffset,
Handle<Name>(),
MaybeHandle<Map>(),
TypeCache::Get()->kInt32,
MachineType::Int32(),
kNoWriteBarrier};
return access;
}
// static
FieldAccess AccessBuilder::ForFeedbackVectorClosureFeedbackCellArray() {
FieldAccess access = {
......
......@@ -338,8 +338,9 @@ class V8_EXPORT_PRIVATE AccessBuilder final
static FieldAccess ForDictionaryNextEnumerationIndex();
static FieldAccess ForDictionaryObjectHashIndex();
// Provides access to a FeedbackCell's value.
// Provides access to FeedbackCell fields.
static FieldAccess ForFeedbackCellValue();
static FieldAccess ForFeedbackCellInterruptBudget();
// Provides access to a FeedbackVector fields.
static FieldAccess ForFeedbackVectorClosureFeedbackCellArray();
......
......@@ -80,6 +80,13 @@ class BytecodeGraphBuilder {
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.
void CreateNativeContextNode();
Node* BuildLoadNativeContext();
......@@ -275,6 +282,8 @@ class BytecodeGraphBuilder {
void BuildJumpIfNotHole();
void BuildJumpIfJSReceiver();
void BuildUpdateInterruptBudget(int delta);
void BuildSwitchOnSmi(Node* condition);
void BuildSwitchOnGeneratorState(
const ZoneVector<ResumeJumpTarget>& resume_jump_targets,
......@@ -418,6 +427,7 @@ class BytecodeGraphBuilder {
Node** input_buffer_;
const bool native_context_independent_;
Node* feedback_cell_node_;
Node* feedback_vector_node_;
Node* native_context_node_;
......@@ -989,6 +999,7 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(
input_buffer_(nullptr),
native_context_independent_(
flags & BytecodeGraphBuilderFlag::kNativeContextIndependent),
feedback_cell_node_(nullptr),
feedback_vector_node_(nullptr),
native_context_node_(nullptr),
needs_eager_checkpoint_(true),
......@@ -1008,6 +1019,29 @@ Node* BytecodeGraphBuilder::GetFunctionClosure() {
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() {
DCHECK_NULL(feedback_vector_node_);
feedback_vector_node_ = native_context_independent()
......@@ -1027,12 +1061,9 @@ Node* BytecodeGraphBuilder::BuildLoadFeedbackVector() {
Node* control = env->GetControlDependency();
Node* effect = env->GetEffectDependency();
Node* feedback_cell = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSFunctionFeedbackCell()),
GetFunctionClosure(), effect, control);
Node* vector = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForFeedbackCellValue()),
feedback_cell, effect, control);
feedback_cell_node(), effect, control);
env->UpdateEffectDependency(effect);
return vector;
......@@ -1119,6 +1150,7 @@ void BytecodeGraphBuilder::CreateGraph() {
graph()->start());
set_environment(&env);
CreateFeedbackCellNode();
CreateFeedbackVectorNode();
CreateNativeContextNode();
VisitBytecodes();
......@@ -3448,6 +3480,9 @@ void BytecodeGraphBuilder::VisitSetPendingMessage() {
void BytecodeGraphBuilder::BuildReturn(const BytecodeLivenessState* 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* control =
NewNode(common()->Return(), pop_node, environment()->LookupAccumulator());
......@@ -3861,6 +3896,7 @@ void BytecodeGraphBuilder::BuildLoopExitsForFunctionExit(
}
void BytecodeGraphBuilder::BuildJump() {
BuildUpdateInterruptBudget(bytecode_iterator().GetRelativeJumpTargetOffset());
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
}
......@@ -3869,6 +3905,8 @@ void BytecodeGraphBuilder::BuildJumpIf(Node* condition) {
{
SubEnvironment sub_environment(this);
NewIfTrue();
BuildUpdateInterruptBudget(
bytecode_iterator().GetRelativeJumpTargetOffset());
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
}
NewIfFalse();
......@@ -3879,6 +3917,8 @@ void BytecodeGraphBuilder::BuildJumpIfNot(Node* condition) {
{
SubEnvironment sub_environment(this);
NewIfFalse();
BuildUpdateInterruptBudget(
bytecode_iterator().GetRelativeJumpTargetOffset());
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
}
NewIfTrue();
......@@ -3904,6 +3944,8 @@ void BytecodeGraphBuilder::BuildJumpIfFalse() {
{
SubEnvironment sub_environment(this);
NewIfFalse();
BuildUpdateInterruptBudget(
bytecode_iterator().GetRelativeJumpTargetOffset());
environment()->BindAccumulator(jsgraph()->FalseConstant());
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
}
......@@ -3918,6 +3960,8 @@ void BytecodeGraphBuilder::BuildJumpIfTrue() {
SubEnvironment sub_environment(this);
NewIfTrue();
environment()->BindAccumulator(jsgraph()->TrueConstant());
BuildUpdateInterruptBudget(
bytecode_iterator().GetRelativeJumpTargetOffset());
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
}
NewIfFalse();
......@@ -3949,6 +3993,16 @@ void BytecodeGraphBuilder::BuildJumpIfJSReceiver() {
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
BytecodeGraphBuilder::TryBuildSimplifiedUnaryOp(const Operator* op,
Node* operand,
......
......@@ -179,6 +179,7 @@ class EffectControlLinearizer {
void LowerCheckEqualsInternalizedString(Node* node, Node* frame_state);
void LowerCheckEqualsSymbol(Node* node, Node* frame_state);
Node* LowerTypeOf(Node* node);
Node* LowerUpdateInterruptBudget(Node* node);
Node* LowerToBoolean(Node* node);
Node* LowerPlainPrimitiveToNumber(Node* node);
Node* LowerPlainPrimitiveToWord32(Node* node);
......@@ -1117,6 +1118,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kTypeOf:
result = LowerTypeOf(node);
break;
case IrOpcode::kUpdateInterruptBudget:
result = LowerUpdateInterruptBudget(node);
break;
case IrOpcode::kNewDoubleElements:
result = LowerNewDoubleElements(node);
break;
......@@ -3580,6 +3584,30 @@ Node* EffectControlLinearizer::LowerTypeOf(Node* node) {
__ 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* obj = node->InputAt(0);
Callable const callable =
......
......@@ -389,105 +389,106 @@
#define SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(V) V(SpeculativeToNumber)
#define SIMPLIFIED_OTHER_OP_LIST(V) \
V(PlainPrimitiveToNumber) \
V(PlainPrimitiveToWord32) \
V(PlainPrimitiveToFloat64) \
V(Allocate) \
V(AllocateRaw) \
V(ArgumentsFrame) \
V(ArgumentsLength) \
V(AssertType) \
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(CheckClosure) \
V(CheckEqualsInternalizedString) \
V(CheckEqualsSymbol) \
V(CheckFloat64Hole) \
V(CheckHeapObject) \
V(CheckIf) \
V(CheckInternalizedString) \
V(CheckMaps) \
V(DynamicCheckMaps) \
V(CheckNotTaggedHole) \
V(CheckNumber) \
V(CheckInternalizedString) \
V(CheckReceiver) \
V(CheckReceiverOrNullOrUndefined) \
V(CheckSmi) \
V(CheckString) \
V(CheckSymbol) \
V(CheckSmi) \
V(CheckHeapObject) \
V(CheckFloat64Hole) \
V(CheckClosure) \
V(CheckNotTaggedHole) \
V(CheckEqualsInternalizedString) \
V(CheckEqualsSymbol) \
V(CompareMaps) \
V(ConvertReceiver) \
V(ConvertTaggedHoleToUndefined) \
V(TypeOf) \
V(Allocate) \
V(AllocateRaw) \
V(LoadFieldByIndex) \
V(LoadField) \
V(DateNow) \
V(DelayedStringConstant) \
V(DynamicCheckMaps) \
V(EnsureWritableFastElements) \
V(FastApiCall) \
V(FindOrderedHashMapEntry) \
V(FindOrderedHashMapEntryForInt32Key) \
V(LoadDataViewElement) \
V(LoadElement) \
V(LoadMessage) \
V(LoadTypedElement) \
V(LoadField) \
V(LoadFieldByIndex) \
V(LoadFromObject) \
V(LoadDataViewElement) \
V(LoadMessage) \
V(LoadStackArgument) \
V(StoreField) \
V(StoreElement) \
V(StoreMessage) \
V(StoreTypedElement) \
V(StoreToObject) \
V(StoreDataViewElement) \
V(StoreSignedSmallElement) \
V(TransitionAndStoreElement) \
V(TransitionAndStoreNumberElement) \
V(TransitionAndStoreNonNumberElement) \
V(ToBoolean) \
V(NumberIsFloat64Hole) \
V(LoadTypedElement) \
V(MaybeGrowFastElements) \
V(NewArgumentsElements) \
V(NewConsString) \
V(NewDoubleElements) \
V(NewSmiOrObjectElements) \
V(NumberIsFinite) \
V(ObjectIsFiniteNumber) \
V(NumberIsFloat64Hole) \
V(NumberIsInteger) \
V(ObjectIsSafeInteger) \
V(NumberIsMinusZero) \
V(NumberIsNaN) \
V(NumberIsSafeInteger) \
V(ObjectIsInteger) \
V(ObjectIsArrayBufferView) \
V(ObjectIsBigInt) \
V(ObjectIsCallable) \
V(ObjectIsConstructor) \
V(ObjectIsDetectableCallable) \
V(ObjectIsFiniteNumber) \
V(ObjectIsInteger) \
V(ObjectIsMinusZero) \
V(NumberIsMinusZero) \
V(ObjectIsNaN) \
V(NumberIsNaN) \
V(ObjectIsNonCallable) \
V(ObjectIsNumber) \
V(ObjectIsReceiver) \
V(ObjectIsSafeInteger) \
V(ObjectIsSmi) \
V(ObjectIsString) \
V(ObjectIsSymbol) \
V(ObjectIsUndetectable) \
V(ArgumentsFrame) \
V(ArgumentsLength) \
V(RestLength) \
V(NewDoubleElements) \
V(NewSmiOrObjectElements) \
V(NewArgumentsElements) \
V(NewConsString) \
V(DelayedStringConstant) \
V(EnsureWritableFastElements) \
V(MaybeGrowFastElements) \
V(TransitionElementsKind) \
V(FindOrderedHashMapEntry) \
V(FindOrderedHashMapEntryForInt32Key) \
V(PlainPrimitiveToFloat64) \
V(PlainPrimitiveToNumber) \
V(PlainPrimitiveToWord32) \
V(PoisonIndex) \
V(RestLength) \
V(RuntimeAbort) \
V(AssertType) \
V(DateNow) \
V(FastApiCall)
V(StoreDataViewElement) \
V(StoreElement) \
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) \
V(SpeculativeBigIntAdd) \
......
......@@ -2825,6 +2825,12 @@ class RepresentationSelector {
return VisitUnop<T>(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedPointer);
}
case IrOpcode::kUpdateInterruptBudget: {
ProcessInput<T>(node, 0, UseInfo::AnyTagged());
ProcessRemainingInputs<T>(node, 1);
SetOutput<T>(node, MachineRepresentation::kNone);
return;
}
case IrOpcode::kNewConsString: {
ProcessInput<T>(node, 0, UseInfo::TruncatingWord32()); // length
ProcessInput<T>(node, 1, UseInfo::AnyTagged()); // first
......
......@@ -1309,6 +1309,12 @@ const Operator* SimplifiedOperatorBuilder::BigIntAsUintN(int 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) {
DCHECK(type.IsRange());
return zone()->New<Operator1<Type>>(IrOpcode::kAssertType,
......
......@@ -13,7 +13,6 @@
#include "src/common/globals.h"
#include "src/compiler/feedback-source.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/node.h"
#include "src/compiler/operator.h"
#include "src/compiler/types.h"
#include "src/compiler/write-barrier-kind.h"
......@@ -793,6 +792,15 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
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* StringConcat();
......@@ -1036,6 +1044,39 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
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) \
static constexpr int Name##Index() { return TheIndex; } \
TNode<Type> name() const { \
......@@ -1043,9 +1084,10 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
NodeProperties::GetValueInput(node(), TheIndex)); \
}
class FastApiCallNode final : public NodeWrapper {
class FastApiCallNode final : public SimplifiedNodeWrapperBase {
public:
explicit constexpr FastApiCallNode(Node* node) : NodeWrapper(node) {
explicit constexpr FastApiCallNode(Node* node)
: SimplifiedNodeWrapperBase(node) {
CONSTEXPR_DCHECK(node->opcode() == IrOpcode::kFastApiCall);
}
......@@ -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
} // namespace compiler
......
......@@ -1196,6 +1196,8 @@ Type Typer::Visitor::TypeTypeOf(Node* node) {
return Type::InternalizedString();
}
Type Typer::Visitor::TypeUpdateInterruptBudget(Node* node) { UNREACHABLE(); }
// JS conversion operators.
Type Typer::Visitor::TypeToBoolean(Node* node) {
......
......@@ -760,6 +760,10 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
case IrOpcode::kTypeOf:
CheckTypeIs(node, Type::InternalizedString());
break;
case IrOpcode::kUpdateInterruptBudget:
CheckValueInputIs(node, 0, Type::Any());
CheckNotTyped(node);
break;
case IrOpcode::kJSGetSuperConstructor:
// We don't check the input for Type::Function because this_function can
// be context-allocated.
......
......@@ -203,7 +203,7 @@ OptimizationReason RuntimeProfiler::ShouldOptimize(JSFunction function,
return OptimizationReason::kDoNotOptimize;
}
void RuntimeProfiler::MarkCandidatesForOptimization() {
void RuntimeProfiler::MarkCandidatesForOptimizationFromBytecode() {
HandleScope scope(isolate_);
if (!isolate_->use_optimizer()) return;
......@@ -240,5 +240,13 @@ void RuntimeProfiler::MarkCandidatesForOptimization() {
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 v8
......@@ -20,7 +20,10 @@ class RuntimeProfiler {
public:
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; }
......
......@@ -273,22 +273,26 @@ Handle<Object> BytecodeArrayAccessor::GetConstantForIndexOperand(
return GetConstantAtIndex(GetIndexOperand(operand_index), isolate);
}
int BytecodeArrayAccessor::GetJumpTargetOffset() const {
int BytecodeArrayAccessor::GetRelativeJumpTargetOffset() const {
Bytecode bytecode = current_bytecode();
if (interpreter::Bytecodes::IsJumpImmediate(bytecode)) {
int relative_offset = GetUnsignedImmediateOperand(0);
if (bytecode == Bytecode::kJumpLoop) {
relative_offset = -relative_offset;
}
return GetAbsoluteOffset(relative_offset);
return relative_offset;
} else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) {
Smi smi = GetConstantAtIndexAsSmi(GetIndexOperand(0));
return GetAbsoluteOffset(smi.value());
return smi.value();
} else {
UNREACHABLE();
}
}
int BytecodeArrayAccessor::GetJumpTargetOffset() const {
return GetAbsoluteOffset(GetRelativeJumpTargetOffset());
}
JumpTableTargetOffsets BytecodeArrayAccessor::GetJumpTableTargetOffsets()
const {
uint32_t table_start, table_size;
......
......@@ -123,6 +123,10 @@ class V8_EXPORT_PRIVATE BytecodeArrayAccessor {
Handle<Object> GetConstantForIndexOperand(int operand_index,
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.
// It is an error to call this method if the bytecode is not for a jump or
// conditional jump.
......
......@@ -1048,7 +1048,8 @@ void InterpreterAssembler::UpdateInterruptBudget(TNode<Int32T> weight,
Branch(condition, &ok, &interrupt_check);
BIND(&interrupt_check);
CallRuntime(Runtime::kBytecodeBudgetInterrupt, GetContext(), function);
CallRuntime(Runtime::kBytecodeBudgetInterruptFromBytecode, GetContext(),
function);
Goto(&done);
BIND(&ok);
......
......@@ -326,7 +326,7 @@ RUNTIME_FUNCTION(Runtime_StackGuardWithGap) {
return isolate->stack_guard()->HandleInterrupts();
}
RUNTIME_FUNCTION(Runtime_BytecodeBudgetInterrupt) {
RUNTIME_FUNCTION(Runtime_BytecodeBudgetInterruptFromBytecode) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
......@@ -344,11 +344,26 @@ RUNTIME_FUNCTION(Runtime_BytecodeBudgetInterrupt) {
{
SealHandleScope shs(isolate);
isolate->counters()->runtime_profiler_ticks()->Increment();
isolate->runtime_profiler()->MarkCandidatesForOptimization();
isolate->runtime_profiler()->MarkCandidatesForOptimizationFromBytecode();
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) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
......
......@@ -220,7 +220,8 @@ namespace internal {
F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \
F(GetTemplateObject, 3, 1) \
F(IncrementUseCounter, 1, 1) \
F(BytecodeBudgetInterrupt, 1, 1) \
F(BytecodeBudgetInterruptFromBytecode, 1, 1) \
F(BytecodeBudgetInterruptFromCode, 1, 1) \
F(NewError, 2, 1) \
F(NewReferenceError, 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