Commit a6cb4903 authored by Mythri's avatar Mythri Committed by Commit Bot

Update bytecode handlers to work without feedback vectors

This is the first in a series of patches for adding support to execute
without feedback vectors. This cl updates some of the bytecode handlers
to check for feedback before using them. All these bytecodes only collect
type feedback, so their funcitonality would not change. This cl changes the
implementation for following bytecode:
  BinaryOperation
  CompareOperation
  UnaryOperation
  Call

Bug: v8:8394
Change-Id: I284bf9c010718c65f3fe76b6f3f4461b5bfa6742
Reviewed-on: https://chromium-review.googlesource.com/c/1333667
Commit-Queue: Mythri Alle <mythria@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57580}
parent 83fd98ab
......@@ -9845,32 +9845,42 @@ TNode<BoolT> CodeStubAssembler::IsOffsetInBounds(SloppyTNode<IntPtrT> offset,
TNode<FeedbackVector> CodeStubAssembler::LoadFeedbackVector(
SloppyTNode<JSFunction> closure, Label* if_undefined) {
TNode<FeedbackCell> feedback_cell =
CAST(LoadObjectField(closure, JSFunction::kFeedbackCellOffset));
TNode<Object> maybe_vector =
LoadObjectField(feedback_cell, FeedbackCell::kValueOffset);
TNode<Object> maybe_vector = LoadFeedbackVectorUnchecked(closure);
if (if_undefined) {
GotoIf(IsUndefined(maybe_vector), if_undefined);
}
return CAST(maybe_vector);
}
TNode<Object> CodeStubAssembler::LoadFeedbackVectorUnchecked(
SloppyTNode<JSFunction> closure) {
TNode<FeedbackCell> feedback_cell =
CAST(LoadObjectField(closure, JSFunction::kFeedbackCellOffset));
TNode<Object> maybe_vector =
LoadObjectField(feedback_cell, FeedbackCell::kValueOffset);
return maybe_vector;
}
TNode<FeedbackVector> CodeStubAssembler::LoadFeedbackVectorForStub() {
TNode<JSFunction> function =
CAST(LoadFromParentFrame(JavaScriptFrameConstants::kFunctionOffset));
return LoadFeedbackVector(function);
}
void CodeStubAssembler::UpdateFeedback(Node* feedback, Node* feedback_vector,
void CodeStubAssembler::UpdateFeedback(Node* feedback, Node* maybe_vector,
Node* slot_id) {
Label end(this);
// If feedback_vector is not valid, then nothing to do.
GotoIf(IsUndefined(maybe_vector), &end);
// This method is used for binary op and compare feedback. These
// vector nodes are initialized with a smi 0, so we can simply OR
// our new feedback in place.
TNode<FeedbackVector> feedback_vector = CAST(maybe_vector);
TNode<MaybeObject> feedback_element =
LoadFeedbackVectorSlot(feedback_vector, slot_id);
TNode<Smi> previous_feedback = CAST(feedback_element);
TNode<Smi> combined_feedback = SmiOr(previous_feedback, CAST(feedback));
Label end(this);
GotoIf(SmiEqual(previous_feedback, combined_feedback), &end);
{
......
......@@ -2789,6 +2789,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
TNode<FeedbackVector> LoadFeedbackVector(SloppyTNode<JSFunction> closure,
Label* if_undefined = nullptr);
// Load the object from feedback vector cell for the given closure.
// The returned object could be undefined if the closure does not have
// a feedback vector associated with it.
TNode<Object> LoadFeedbackVectorUnchecked(SloppyTNode<JSFunction> closure);
// Update the type feedback vector.
void UpdateFeedback(Node* feedback, Node* feedback_vector, Node* slot_id);
......
......@@ -674,6 +674,11 @@ TNode<FeedbackVector> InterpreterAssembler::LoadFeedbackVector() {
return CodeStubAssembler::LoadFeedbackVector(function);
}
Node* InterpreterAssembler::LoadFeedbackVectorUnchecked() {
TNode<JSFunction> function = CAST(LoadRegister(Register::function_closure()));
return CodeStubAssembler::LoadFeedbackVectorUnchecked(function);
}
void InterpreterAssembler::CallPrologue() {
if (!Bytecodes::MakesCallAlongCriticalPath(bytecode_)) {
// Bytecodes that make a call along the critical path save the bytecode
......@@ -818,13 +823,22 @@ void InterpreterAssembler::CollectCallableFeedback(Node* target, Node* context,
}
void InterpreterAssembler::CollectCallFeedback(Node* target, Node* context,
Node* feedback_vector,
Node* maybe_feedback_vector,
Node* slot_id) {
Label feedback_done(this);
// If feedback_vector is not valid, then nothing to do.
GotoIf(IsUndefined(maybe_feedback_vector), &feedback_done);
CSA_SLOW_ASSERT(this, IsFeedbackVector(maybe_feedback_vector));
// Increment the call count.
IncrementCallCount(feedback_vector, slot_id);
IncrementCallCount(maybe_feedback_vector, slot_id);
// Collect the callable {target} feedback.
CollectCallableFeedback(target, context, feedback_vector, slot_id);
CollectCallableFeedback(target, context, maybe_feedback_vector, slot_id);
Goto(&feedback_done);
BIND(&feedback_done);
}
void InterpreterAssembler::CallJSAndDispatch(
......@@ -898,10 +912,10 @@ template V8_EXPORT_PRIVATE void InterpreterAssembler::CallJSAndDispatch(
void InterpreterAssembler::CallJSWithSpreadAndDispatch(
Node* function, Node* context, const RegListNodePair& args, Node* slot_id,
Node* feedback_vector) {
Node* maybe_feedback_vector) {
DCHECK(Bytecodes::MakesCallAlongCriticalPath(bytecode_));
DCHECK_EQ(Bytecodes::GetReceiverMode(bytecode_), ConvertReceiverMode::kAny);
CollectCallFeedback(function, context, feedback_vector, slot_id);
CollectCallFeedback(function, context, maybe_feedback_vector, slot_id);
Comment("call using CallWithSpread builtin");
Callable callable = CodeFactory::InterpreterPushArgsThenCall(
isolate(), ConvertReceiverMode::kAny,
......@@ -1771,8 +1785,9 @@ void InterpreterAssembler::ToNumberOrNumeric(Object::Conversion mode) {
// Record the type feedback collected for {object}.
Node* slot_index = BytecodeOperandIdx(0);
Node* feedback_vector = LoadFeedbackVector();
UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_index);
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot_index);
SetAccumulator(var_result.value());
Dispatch();
......
......@@ -147,6 +147,10 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
// Load the FeedbackVector for the current function.
compiler::TNode<FeedbackVector> LoadFeedbackVector();
// Load the FeedbackVector for the current function. The returned node
// could be undefined.
compiler::Node* LoadFeedbackVectorUnchecked();
// Increment the call count for a CALL_IC or construct call.
// The call count is located at feedback_vector[slot_id + 1].
void IncrementCallCount(compiler::Node* feedback_vector,
......@@ -162,7 +166,7 @@ class V8_EXPORT_PRIVATE InterpreterAssembler : public CodeStubAssembler {
// |feedback_vector| at |slot_id|, and the call counts in
// the |feedback_vector| at |slot_id+1|.
void CollectCallFeedback(compiler::Node* target, compiler::Node* context,
compiler::Node* feedback_vector,
compiler::Node* maybe_feedback_vector,
compiler::Node* slot_id);
// Call JSFunction or Callable |function| with |args| arguments, possibly
......
......@@ -812,11 +812,11 @@ class InterpreterBinaryOpAssembler : public InterpreterAssembler {
Node* rhs = GetAccumulator();
Node* context = GetContext();
Node* slot_index = BytecodeOperandIdx(1);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
BinaryOpAssembler binop_asm(state());
Node* result = (binop_asm.*generator)(context, lhs, rhs, slot_index,
feedback_vector, false);
maybe_feedback_vector, false);
SetAccumulator(result);
Dispatch();
}
......@@ -826,11 +826,11 @@ class InterpreterBinaryOpAssembler : public InterpreterAssembler {
Node* rhs = BytecodeOperandImmSmi(0);
Node* context = GetContext();
Node* slot_index = BytecodeOperandIdx(1);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
BinaryOpAssembler binop_asm(state());
Node* result = (binop_asm.*generator)(context, lhs, rhs, slot_index,
feedback_vector, true);
maybe_feedback_vector, true);
SetAccumulator(result);
Dispatch();
}
......@@ -933,7 +933,7 @@ class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
Node* right = GetAccumulator();
Node* context = GetContext();
Node* slot_index = BytecodeOperandIdx(1);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
TVARIABLE(Smi, var_left_feedback);
TVARIABLE(Smi, var_right_feedback);
......@@ -959,7 +959,7 @@ class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
BinaryOperationFeedback::kNumber);
TNode<Smi> input_feedback =
SmiOr(var_left_feedback.value(), var_right_feedback.value());
UpdateFeedback(SmiOr(result_type, input_feedback), feedback_vector,
UpdateFeedback(SmiOr(result_type, input_feedback), maybe_feedback_vector,
slot_index);
SetAccumulator(result);
Dispatch();
......@@ -974,7 +974,7 @@ class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
CallRuntime(Runtime::kBigIntBinaryOp, context, var_left_bigint.value(),
var_right_bigint.value(), SmiConstant(bitwise_op)));
UpdateFeedback(SmiOr(var_left_feedback.value(), var_right_feedback.value()),
feedback_vector, slot_index);
maybe_feedback_vector, slot_index);
Dispatch();
}
......@@ -982,7 +982,7 @@ class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
Node* left = GetAccumulator();
Node* right = BytecodeOperandImmSmi(0);
Node* slot_index = BytecodeOperandIdx(1);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
Node* context = GetContext();
TVARIABLE(Smi, var_left_feedback);
......@@ -1000,12 +1000,13 @@ class InterpreterBitwiseBinaryOpAssembler : public InterpreterAssembler {
TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall,
BinaryOperationFeedback::kNumber);
UpdateFeedback(SmiOr(result_type, var_left_feedback.value()),
feedback_vector, slot_index);
maybe_feedback_vector, slot_index);
SetAccumulator(result);
Dispatch();
BIND(&if_bigint_mix);
UpdateFeedback(var_left_feedback.value(), feedback_vector, slot_index);
UpdateFeedback(var_left_feedback.value(), maybe_feedback_vector,
slot_index);
ThrowTypeError(context, MessageTemplate::kBigIntMixedTypes);
}
};
......@@ -1088,7 +1089,7 @@ IGNITION_HANDLER(BitwiseAndSmi, InterpreterBitwiseBinaryOpAssembler) {
IGNITION_HANDLER(BitwiseNot, InterpreterAssembler) {
Node* operand = GetAccumulator();
Node* slot_index = BytecodeOperandIdx(0);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
Node* context = GetContext();
VARIABLE(var_word32, MachineRepresentation::kWord32);
......@@ -1105,15 +1106,15 @@ IGNITION_HANDLER(BitwiseNot, InterpreterAssembler) {
TNode<Smi> result_type = SelectSmiConstant(
TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall,
BinaryOperationFeedback::kNumber);
UpdateFeedback(SmiOr(result_type, var_feedback.value()), feedback_vector,
slot_index);
UpdateFeedback(SmiOr(result_type, var_feedback.value()),
maybe_feedback_vector, slot_index);
SetAccumulator(result);
Dispatch();
// BigInt case.
BIND(&if_bigint);
UpdateFeedback(SmiConstant(BinaryOperationFeedback::kBigInt), feedback_vector,
slot_index);
UpdateFeedback(SmiConstant(BinaryOperationFeedback::kBigInt),
maybe_feedback_vector, slot_index);
SetAccumulator(CallRuntime(Runtime::kBigIntUnaryOp, context,
var_bigint.value(),
SmiConstant(Operation::kBitwiseNot)));
......@@ -1166,7 +1167,7 @@ class UnaryNumericOpAssembler : public InterpreterAssembler {
void UnaryOpWithFeedback() {
VARIABLE(var_value, MachineRepresentation::kTagged, GetAccumulator());
Node* slot_index = BytecodeOperandIdx(0);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
VARIABLE(var_result, MachineRepresentation::kTagged);
VARIABLE(var_float_value, MachineRepresentation::kFloat64);
......@@ -1245,7 +1246,7 @@ class UnaryNumericOpAssembler : public InterpreterAssembler {
}
BIND(&end);
UpdateFeedback(var_feedback.value(), feedback_vector, slot_index);
UpdateFeedback(var_feedback.value(), maybe_feedback_vector, slot_index);
SetAccumulator(var_result.value());
Dispatch();
}
......@@ -1522,11 +1523,11 @@ class InterpreterJSCallAssembler : public InterpreterAssembler {
Node* function = LoadRegisterAtOperandIndex(0);
RegListNodePair args = GetRegisterListAtOperandIndex(1);
Node* slot_id = BytecodeOperandIdx(3);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
Node* context = GetContext();
// Collect the {function} feedback.
CollectCallFeedback(function, context, feedback_vector, slot_id);
CollectCallFeedback(function, context, maybe_feedback_vector, slot_id);
// Call the function and dispatch to the next handler.
CallJSAndDispatch(function, context, args, receiver_mode);
......@@ -1555,11 +1556,11 @@ class InterpreterJSCallAssembler : public InterpreterAssembler {
Node* function = LoadRegisterAtOperandIndex(0);
Node* slot_id = BytecodeOperandIdx(kSlotOperandIndex);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
Node* context = GetContext();
// Collect the {function} feedback.
CollectCallFeedback(function, context, feedback_vector, slot_id);
CollectCallFeedback(function, context, maybe_feedback_vector, slot_id);
switch (kRecieverAndArgOperandCount) {
case 0:
......@@ -1710,12 +1711,12 @@ IGNITION_HANDLER(CallWithSpread, InterpreterAssembler) {
Node* callable = LoadRegisterAtOperandIndex(0);
RegListNodePair args = GetRegisterListAtOperandIndex(1);
Node* slot_id = BytecodeOperandIdx(3);
Node* feedback_vector = LoadFeedbackVector();
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
Node* context = GetContext();
// Call into Runtime function CallWithSpread which does everything.
CallJSWithSpreadAndDispatch(callable, context, args, slot_id,
feedback_vector);
maybe_feedback_vector);
}
// ConstructWithSpread <first_arg> <arg_count>
......@@ -1788,8 +1789,9 @@ class InterpreterCompareOpAssembler : public InterpreterAssembler {
}
Node* slot_index = BytecodeOperandIdx(1);
Node* feedback_vector = LoadFeedbackVector();
UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_index);
Node* maybe_feedback_vector = LoadFeedbackVectorUnchecked();
UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector,
slot_index);
SetAccumulator(result);
Dispatch();
}
......@@ -1872,12 +1874,17 @@ IGNITION_HANDLER(TestInstanceOf, InterpreterAssembler) {
Node* object = LoadRegisterAtOperandIndex(0);
Node* callable = GetAccumulator();
Node* slot_id = BytecodeOperandIdx(1);
Node* feedback_vector = LoadFeedbackVector();
Node* feedback_vector = LoadFeedbackVectorUnchecked();
Node* context = GetContext();
Label feedback_done(this);
GotoIf(IsUndefined(feedback_vector), &feedback_done);
// Record feedback for the {callable} in the {feedback_vector}.
CollectCallableFeedback(callable, context, feedback_vector, slot_id);
Goto(&feedback_done);
BIND(&feedback_done);
// Perform the actual instanceof operation.
SetAccumulator(InstanceOf(object, callable, context));
Dispatch();
......
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