[nci] Add Unary/Binary/Compare builtins with feedback
This CL adds the new _WithFeedback variant of unary, binary, and compare operation builtins. Existing logic to do these operations is refactored s.t. it can be used by both ignition bytecode handlers and the new builtins. Note that the new builtins are not yet used. Follow-up CLs will hook them into generic lowering. Bug: v8:8888 Change-Id: Id77dbe74bdf3b3806b2aefdf1abe52c3d165a3a3 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2208862 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Igor Sheludko <ishell@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#67956}
This commit is contained in:
parent
d4bb820827
commit
a0e7456d38
2
BUILD.gn
2
BUILD.gn
@ -1683,6 +1683,8 @@ v8_source_set("v8_initializers") {
|
||||
"src/ic/binary-op-assembler.h",
|
||||
"src/ic/keyed-store-generic.cc",
|
||||
"src/ic/keyed-store-generic.h",
|
||||
"src/ic/unary-op-assembler.cc",
|
||||
"src/ic/unary-op-assembler.h",
|
||||
"src/interpreter/interpreter-assembler.cc",
|
||||
"src/interpreter/interpreter-assembler.h",
|
||||
"src/interpreter/interpreter-generator.cc",
|
||||
|
@ -608,6 +608,34 @@ namespace internal {
|
||||
TFC(SameValue, Compare) \
|
||||
TFC(SameValueNumbersOnly, Compare) \
|
||||
\
|
||||
/* Binary ops with feedback collection */ \
|
||||
TFC(Add_WithFeedback, BinaryOp_WithFeedback) \
|
||||
TFC(Subtract_WithFeedback, BinaryOp_WithFeedback) \
|
||||
TFC(Multiply_WithFeedback, BinaryOp_WithFeedback) \
|
||||
TFC(Divide_WithFeedback, BinaryOp_WithFeedback) \
|
||||
TFC(Modulus_WithFeedback, BinaryOp_WithFeedback) \
|
||||
TFC(Exponentiate_WithFeedback, BinaryOp_WithFeedback) \
|
||||
TFC(BitwiseAnd_WithFeedback, BinaryOp_WithFeedback) \
|
||||
TFC(BitwiseOr_WithFeedback, BinaryOp_WithFeedback) \
|
||||
TFC(BitwiseXor_WithFeedback, BinaryOp_WithFeedback) \
|
||||
TFC(ShiftLeft_WithFeedback, BinaryOp_WithFeedback) \
|
||||
TFC(ShiftRight_WithFeedback, BinaryOp_WithFeedback) \
|
||||
TFC(ShiftRightLogical_WithFeedback, BinaryOp_WithFeedback) \
|
||||
\
|
||||
/* Compare ops with feedback collection */ \
|
||||
TFC(Equal_WithFeedback, Compare_WithFeedback) \
|
||||
TFC(StrictEqual_WithFeedback, Compare_WithFeedback) \
|
||||
TFC(LessThan_WithFeedback, Compare_WithFeedback) \
|
||||
TFC(GreaterThan_WithFeedback, Compare_WithFeedback) \
|
||||
TFC(LessThanOrEqual_WithFeedback, Compare_WithFeedback) \
|
||||
TFC(GreaterThanOrEqual_WithFeedback, Compare_WithFeedback) \
|
||||
\
|
||||
/* Unary ops with feedback collection */ \
|
||||
TFC(BitwiseNot_WithFeedback, UnaryOp_WithFeedback) \
|
||||
TFC(Decrement_WithFeedback, UnaryOp_WithFeedback) \
|
||||
TFC(Increment_WithFeedback, UnaryOp_WithFeedback) \
|
||||
TFC(Negate_WithFeedback, UnaryOp_WithFeedback) \
|
||||
\
|
||||
/* Object */ \
|
||||
/* ES #sec-object-constructor */ \
|
||||
TFJ(ObjectConstructor, kDontAdaptArgumentsSentinel) \
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "src/builtins/builtins.h"
|
||||
#include "src/codegen/code-stub-assembler.h"
|
||||
#include "src/ic/binary-op-assembler.h"
|
||||
#include "src/ic/unary-op-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -245,5 +246,109 @@ TF_BUILTIN(Add, AddStubAssembler) {
|
||||
}
|
||||
}
|
||||
|
||||
#define DEF_BINOP(Name, Generator) \
|
||||
TF_BUILTIN(Name, CodeStubAssembler) { \
|
||||
TNode<Object> lhs = CAST(Parameter(Descriptor::kLeft)); \
|
||||
TNode<Object> rhs = CAST(Parameter(Descriptor::kRight)); \
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext)); \
|
||||
TNode<HeapObject> maybe_feedback_vector = \
|
||||
CAST(Parameter(Descriptor::kMaybeFeedbackVector)); \
|
||||
TNode<UintPtrT> slot = \
|
||||
UncheckedCast<UintPtrT>(Parameter(Descriptor::kSlot)); \
|
||||
\
|
||||
BinaryOpAssembler binop_asm(state()); \
|
||||
TNode<Object> result = binop_asm.Generator(context, lhs, rhs, slot, \
|
||||
maybe_feedback_vector, false); \
|
||||
\
|
||||
Return(result); \
|
||||
}
|
||||
DEF_BINOP(Add_WithFeedback, Generate_AddWithFeedback)
|
||||
DEF_BINOP(Subtract_WithFeedback, Generate_SubtractWithFeedback)
|
||||
DEF_BINOP(Multiply_WithFeedback, Generate_MultiplyWithFeedback)
|
||||
DEF_BINOP(Divide_WithFeedback, Generate_DivideWithFeedback)
|
||||
DEF_BINOP(Modulus_WithFeedback, Generate_ModulusWithFeedback)
|
||||
DEF_BINOP(Exponentiate_WithFeedback, Generate_ExponentiateWithFeedback)
|
||||
DEF_BINOP(BitwiseOr_WithFeedback, Generate_BitwiseOrWithFeedback)
|
||||
DEF_BINOP(BitwiseXor_WithFeedback, Generate_BitwiseXorWithFeedback)
|
||||
DEF_BINOP(BitwiseAnd_WithFeedback, Generate_BitwiseAndWithFeedback)
|
||||
DEF_BINOP(ShiftLeft_WithFeedback, Generate_ShiftLeftWithFeedback)
|
||||
DEF_BINOP(ShiftRight_WithFeedback, Generate_ShiftRightWithFeedback)
|
||||
DEF_BINOP(ShiftRightLogical_WithFeedback,
|
||||
Generate_ShiftRightLogicalWithFeedback)
|
||||
#undef DEF_BINOP
|
||||
|
||||
#define DEF_UNOP(Name, Generator) \
|
||||
TF_BUILTIN(Name, CodeStubAssembler) { \
|
||||
TNode<Object> value = CAST(Parameter(Descriptor::kValue)); \
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext)); \
|
||||
TNode<HeapObject> maybe_feedback_vector = \
|
||||
CAST(Parameter(Descriptor::kMaybeFeedbackVector)); \
|
||||
TNode<UintPtrT> slot = \
|
||||
UncheckedCast<UintPtrT>(Parameter(Descriptor::kSlot)); \
|
||||
\
|
||||
UnaryOpAssembler a(state()); \
|
||||
TNode<Object> result = \
|
||||
a.Generator(context, value, slot, maybe_feedback_vector); \
|
||||
\
|
||||
Return(result); \
|
||||
}
|
||||
DEF_UNOP(BitwiseNot_WithFeedback, Generate_BitwiseNotWithFeedback)
|
||||
DEF_UNOP(Decrement_WithFeedback, Generate_DecrementWithFeedback)
|
||||
DEF_UNOP(Increment_WithFeedback, Generate_IncrementWithFeedback)
|
||||
DEF_UNOP(Negate_WithFeedback, Generate_NegateWithFeedback)
|
||||
#undef DEF_UNOP
|
||||
|
||||
#define DEF_COMPARE(Name) \
|
||||
TF_BUILTIN(Name##_WithFeedback, CodeStubAssembler) { \
|
||||
TNode<Object> lhs = CAST(Parameter(Descriptor::kLeft)); \
|
||||
TNode<Object> rhs = CAST(Parameter(Descriptor::kRight)); \
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext)); \
|
||||
TNode<HeapObject> maybe_feedback_vector = \
|
||||
CAST(Parameter(Descriptor::kMaybeFeedbackVector)); \
|
||||
TNode<UintPtrT> slot = \
|
||||
UncheckedCast<UintPtrT>(Parameter(Descriptor::kSlot)); \
|
||||
\
|
||||
TVARIABLE(Smi, var_type_feedback); \
|
||||
TNode<Oddball> result = RelationalComparison(Operation::k##Name, lhs, rhs, \
|
||||
context, &var_type_feedback); \
|
||||
UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot); \
|
||||
\
|
||||
Return(result); \
|
||||
}
|
||||
DEF_COMPARE(LessThan)
|
||||
DEF_COMPARE(LessThanOrEqual)
|
||||
DEF_COMPARE(GreaterThan)
|
||||
DEF_COMPARE(GreaterThanOrEqual)
|
||||
#undef DEF_COMPARE
|
||||
|
||||
TF_BUILTIN(Equal_WithFeedback, CodeStubAssembler) {
|
||||
TNode<Object> lhs = CAST(Parameter(Descriptor::kLeft));
|
||||
TNode<Object> rhs = CAST(Parameter(Descriptor::kRight));
|
||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
||||
TNode<HeapObject> maybe_feedback_vector =
|
||||
CAST(Parameter(Descriptor::kMaybeFeedbackVector));
|
||||
TNode<UintPtrT> slot = UncheckedCast<UintPtrT>(Parameter(Descriptor::kSlot));
|
||||
|
||||
TVARIABLE(Smi, var_type_feedback);
|
||||
TNode<Oddball> result = Equal(lhs, rhs, context, &var_type_feedback);
|
||||
UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot);
|
||||
|
||||
Return(result);
|
||||
}
|
||||
|
||||
TF_BUILTIN(StrictEqual_WithFeedback, CodeStubAssembler) {
|
||||
TNode<Object> lhs = CAST(Parameter(Descriptor::kLeft));
|
||||
TNode<Object> rhs = CAST(Parameter(Descriptor::kRight));
|
||||
TNode<HeapObject> maybe_feedback_vector =
|
||||
CAST(Parameter(Descriptor::kMaybeFeedbackVector));
|
||||
TNode<UintPtrT> slot = UncheckedCast<UintPtrT>(Parameter(Descriptor::kSlot));
|
||||
|
||||
TVARIABLE(Smi, var_type_feedback);
|
||||
TNode<Oddball> result = StrictEqual(lhs, rhs, &var_type_feedback);
|
||||
UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot);
|
||||
|
||||
Return(result);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -946,6 +946,7 @@ class CallWithSpreadDescriptor : public CallInterfaceDescriptor {
|
||||
DECLARE_DESCRIPTOR(CallWithSpreadDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
// TODO(jgruber): Pass the slot as UintPtr.
|
||||
class CallWithSpread_WithFeedbackDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kTarget, kArgumentsCount, kSpread, kSlot,
|
||||
@ -967,6 +968,7 @@ class CallWithArrayLikeDescriptor : public CallInterfaceDescriptor {
|
||||
DECLARE_DESCRIPTOR(CallWithArrayLikeDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
// TODO(jgruber): Pass the slot as UintPtr.
|
||||
class CallWithArrayLike_WithFeedbackDescriptor
|
||||
: public CallInterfaceDescriptor {
|
||||
public:
|
||||
@ -1002,6 +1004,7 @@ class ConstructWithSpreadDescriptor : public CallInterfaceDescriptor {
|
||||
DECLARE_DESCRIPTOR(ConstructWithSpreadDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
// TODO(jgruber): Pass the slot as UintPtr.
|
||||
class ConstructWithSpread_WithFeedbackDescriptor
|
||||
: public CallInterfaceDescriptor {
|
||||
public:
|
||||
@ -1024,6 +1027,7 @@ class ConstructWithArrayLikeDescriptor : public CallInterfaceDescriptor {
|
||||
DECLARE_DESCRIPTOR(ConstructWithArrayLikeDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
// TODO(jgruber): Pass the slot as UintPtr.
|
||||
class ConstructWithArrayLike_WithFeedbackDescriptor
|
||||
: public CallInterfaceDescriptor {
|
||||
public:
|
||||
@ -1465,11 +1469,12 @@ class BinaryOp_WithFeedbackDescriptor : public CallInterfaceDescriptor {
|
||||
DEFINE_PARAMETERS(kLeft, kRight, kSlot, kMaybeFeedbackVector)
|
||||
DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kLeft
|
||||
MachineType::AnyTagged(), // kRight
|
||||
MachineType::Int32(), // kSlot
|
||||
MachineType::UintPtr(), // kSlot
|
||||
MachineType::AnyTagged()) // kMaybeFeedbackVector
|
||||
DECLARE_DESCRIPTOR(BinaryOp_WithFeedbackDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
// TODO(jgruber): Pass the slot as UintPtr.
|
||||
class CallTrampoline_WithFeedbackDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS_VARARGS(kFunction, kActualArgumentsCount, kSlot,
|
||||
@ -1487,11 +1492,12 @@ class Compare_WithFeedbackDescriptor : public CallInterfaceDescriptor {
|
||||
DEFINE_PARAMETERS(kLeft, kRight, kSlot, kMaybeFeedbackVector)
|
||||
DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kLeft
|
||||
MachineType::AnyTagged(), // kRight
|
||||
MachineType::Int32(), // kSlot
|
||||
MachineType::UintPtr(), // kSlot
|
||||
MachineType::AnyTagged()) // kMaybeFeedbackVector
|
||||
DECLARE_DESCRIPTOR(Compare_WithFeedbackDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
||||
// TODO(jgruber): Pass the slot as UintPtr.
|
||||
class Construct_WithFeedbackDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
// kSlot is passed in a register, kMaybeFeedbackVector on the stack.
|
||||
@ -1506,7 +1512,7 @@ class UnaryOp_WithFeedbackDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DEFINE_PARAMETERS(kValue, kSlot, kMaybeFeedbackVector)
|
||||
DEFINE_PARAMETER_TYPES(MachineType::AnyTagged(), // kValue
|
||||
MachineType::Int32(), // kSlot
|
||||
MachineType::UintPtr(), // kSlot
|
||||
MachineType::AnyTagged()) // kMaybeFeedbackVector
|
||||
DECLARE_DESCRIPTOR(UnaryOp_WithFeedbackDescriptor, CallInterfaceDescriptor)
|
||||
};
|
||||
|
@ -50,6 +50,72 @@ class BinaryOpAssembler : public CodeStubAssembler {
|
||||
TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
|
||||
bool rhs_known_smi);
|
||||
|
||||
TNode<Object> Generate_BitwiseOrWithFeedback(
|
||||
TNode<Context> context, TNode<Object> left, TNode<Object> right,
|
||||
TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
|
||||
bool /* unused */) {
|
||||
TVARIABLE(Smi, feedback);
|
||||
TNode<Object> result = Generate_BitwiseBinaryOpWithFeedback(
|
||||
Operation::kBitwiseOr, left, right, context, &feedback);
|
||||
UpdateFeedback(feedback.value(), maybe_feedback_vector, slot);
|
||||
return result;
|
||||
}
|
||||
|
||||
TNode<Object> Generate_BitwiseXorWithFeedback(
|
||||
TNode<Context> context, TNode<Object> left, TNode<Object> right,
|
||||
TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
|
||||
bool /* unused */) {
|
||||
TVARIABLE(Smi, feedback);
|
||||
TNode<Object> result = Generate_BitwiseBinaryOpWithFeedback(
|
||||
Operation::kBitwiseXor, left, right, context, &feedback);
|
||||
UpdateFeedback(feedback.value(), maybe_feedback_vector, slot);
|
||||
return result;
|
||||
}
|
||||
|
||||
TNode<Object> Generate_BitwiseAndWithFeedback(
|
||||
TNode<Context> context, TNode<Object> left, TNode<Object> right,
|
||||
TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
|
||||
bool /* unused */) {
|
||||
TVARIABLE(Smi, feedback);
|
||||
TNode<Object> result = Generate_BitwiseBinaryOpWithFeedback(
|
||||
Operation::kBitwiseAnd, left, right, context, &feedback);
|
||||
UpdateFeedback(feedback.value(), maybe_feedback_vector, slot);
|
||||
return result;
|
||||
}
|
||||
|
||||
TNode<Object> Generate_ShiftLeftWithFeedback(
|
||||
TNode<Context> context, TNode<Object> left, TNode<Object> right,
|
||||
TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
|
||||
bool /* unused */) {
|
||||
TVARIABLE(Smi, feedback);
|
||||
TNode<Object> result = Generate_BitwiseBinaryOpWithFeedback(
|
||||
Operation::kShiftLeft, left, right, context, &feedback);
|
||||
UpdateFeedback(feedback.value(), maybe_feedback_vector, slot);
|
||||
return result;
|
||||
}
|
||||
|
||||
TNode<Object> Generate_ShiftRightWithFeedback(
|
||||
TNode<Context> context, TNode<Object> left, TNode<Object> right,
|
||||
TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
|
||||
bool /* unused */) {
|
||||
TVARIABLE(Smi, feedback);
|
||||
TNode<Object> result = Generate_BitwiseBinaryOpWithFeedback(
|
||||
Operation::kShiftRight, left, right, context, &feedback);
|
||||
UpdateFeedback(feedback.value(), maybe_feedback_vector, slot);
|
||||
return result;
|
||||
}
|
||||
|
||||
TNode<Object> Generate_ShiftRightLogicalWithFeedback(
|
||||
TNode<Context> context, TNode<Object> left, TNode<Object> right,
|
||||
TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
|
||||
bool /* unused */) {
|
||||
TVARIABLE(Smi, feedback);
|
||||
TNode<Object> result = Generate_BitwiseBinaryOpWithFeedback(
|
||||
Operation::kShiftRightLogical, left, right, context, &feedback);
|
||||
UpdateFeedback(feedback.value(), maybe_feedback_vector, slot);
|
||||
return result;
|
||||
}
|
||||
|
||||
TNode<Object> Generate_BitwiseBinaryOpWithFeedback(Operation bitwise_op,
|
||||
TNode<Object> left,
|
||||
TNode<Object> right,
|
||||
|
276
src/ic/unary-op-assembler.cc
Normal file
276
src/ic/unary-op-assembler.cc
Normal file
@ -0,0 +1,276 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/ic/unary-op-assembler.h"
|
||||
|
||||
#include "src/common/globals.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Unary op helper classes.
|
||||
namespace {
|
||||
|
||||
class UnaryNumericOpAssembler : public CodeStubAssembler {
|
||||
public:
|
||||
explicit UnaryNumericOpAssembler(compiler::CodeAssemblerState* state)
|
||||
: CodeStubAssembler(state) {}
|
||||
|
||||
protected:
|
||||
virtual TNode<Number> SmiOp(TNode<Smi> smi_value,
|
||||
TVariable<Smi>* var_feedback, Label* do_float_op,
|
||||
TVariable<Float64T>* var_float) = 0;
|
||||
virtual TNode<Float64T> FloatOp(TNode<Float64T> float_value) = 0;
|
||||
virtual TNode<HeapObject> BigIntOp(TNode<Context> context,
|
||||
TNode<HeapObject> bigint_value) = 0;
|
||||
|
||||
TNode<Object> UnaryOpWithFeedback(TNode<Context> context, TNode<Object> value,
|
||||
TNode<UintPtrT> slot,
|
||||
TNode<HeapObject> maybe_feedback_vector) {
|
||||
TVARIABLE(Object, var_value, value);
|
||||
TVARIABLE(Object, var_result);
|
||||
TVARIABLE(Float64T, var_float_value);
|
||||
TVARIABLE(Smi, var_feedback, SmiConstant(BinaryOperationFeedback::kNone));
|
||||
Label start(this, {&var_value, &var_feedback}), end(this);
|
||||
Label do_float_op(this, &var_float_value);
|
||||
Goto(&start);
|
||||
// We might have to try again after ToNumeric conversion.
|
||||
BIND(&start);
|
||||
{
|
||||
Label if_smi(this), if_heapnumber(this), if_oddball(this);
|
||||
Label if_bigint(this, Label::kDeferred);
|
||||
Label if_other(this, Label::kDeferred);
|
||||
TNode<Object> value = var_value.value();
|
||||
GotoIf(TaggedIsSmi(value), &if_smi);
|
||||
|
||||
TNode<HeapObject> value_heap_object = CAST(value);
|
||||
TNode<Map> map = LoadMap(value_heap_object);
|
||||
GotoIf(IsHeapNumberMap(map), &if_heapnumber);
|
||||
TNode<Uint16T> instance_type = LoadMapInstanceType(map);
|
||||
GotoIf(IsBigIntInstanceType(instance_type), &if_bigint);
|
||||
Branch(InstanceTypeEqual(instance_type, ODDBALL_TYPE), &if_oddball,
|
||||
&if_other);
|
||||
|
||||
BIND(&if_smi);
|
||||
{
|
||||
var_result =
|
||||
SmiOp(CAST(value), &var_feedback, &do_float_op, &var_float_value);
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&if_heapnumber);
|
||||
{
|
||||
var_float_value = LoadHeapNumberValue(value_heap_object);
|
||||
Goto(&do_float_op);
|
||||
}
|
||||
|
||||
BIND(&if_bigint);
|
||||
{
|
||||
var_result = BigIntOp(context, value_heap_object);
|
||||
CombineFeedback(&var_feedback, BinaryOperationFeedback::kBigInt);
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&if_oddball);
|
||||
{
|
||||
// We do not require an Or with earlier feedback here because once we
|
||||
// convert the value to a number, we cannot reach this path. We can
|
||||
// only reach this path on the first pass when the feedback is kNone.
|
||||
CSA_ASSERT(this, SmiEqual(var_feedback.value(),
|
||||
SmiConstant(BinaryOperationFeedback::kNone)));
|
||||
OverwriteFeedback(&var_feedback,
|
||||
BinaryOperationFeedback::kNumberOrOddball);
|
||||
var_value =
|
||||
LoadObjectField(value_heap_object, Oddball::kToNumberOffset);
|
||||
Goto(&start);
|
||||
}
|
||||
|
||||
BIND(&if_other);
|
||||
{
|
||||
// We do not require an Or with earlier feedback here because once we
|
||||
// convert the value to a number, we cannot reach this path. We can
|
||||
// only reach this path on the first pass when the feedback is kNone.
|
||||
CSA_ASSERT(this, SmiEqual(var_feedback.value(),
|
||||
SmiConstant(BinaryOperationFeedback::kNone)));
|
||||
OverwriteFeedback(&var_feedback, BinaryOperationFeedback::kAny);
|
||||
var_value = CallBuiltin(Builtins::kNonNumberToNumeric, context,
|
||||
value_heap_object);
|
||||
Goto(&start);
|
||||
}
|
||||
}
|
||||
|
||||
BIND(&do_float_op);
|
||||
{
|
||||
CombineFeedback(&var_feedback, BinaryOperationFeedback::kNumber);
|
||||
var_result =
|
||||
AllocateHeapNumberWithValue(FloatOp(var_float_value.value()));
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&end);
|
||||
UpdateFeedback(var_feedback.value(), maybe_feedback_vector, slot);
|
||||
return var_result.value();
|
||||
}
|
||||
};
|
||||
|
||||
class NegateAssembler : public UnaryNumericOpAssembler {
|
||||
public:
|
||||
explicit NegateAssembler(compiler::CodeAssemblerState* state)
|
||||
: UnaryNumericOpAssembler(state) {}
|
||||
|
||||
using UnaryNumericOpAssembler::UnaryOpWithFeedback;
|
||||
|
||||
private:
|
||||
TNode<Number> SmiOp(TNode<Smi> smi_value, TVariable<Smi>* var_feedback,
|
||||
Label* do_float_op,
|
||||
TVariable<Float64T>* var_float) override {
|
||||
TVARIABLE(Number, var_result);
|
||||
Label if_zero(this), if_min_smi(this), end(this);
|
||||
// Return -0 if operand is 0.
|
||||
GotoIf(SmiEqual(smi_value, SmiConstant(0)), &if_zero);
|
||||
|
||||
// Special-case the minimum Smi to avoid overflow.
|
||||
GotoIf(SmiEqual(smi_value, SmiConstant(Smi::kMinValue)), &if_min_smi);
|
||||
|
||||
// Else simply subtract operand from 0.
|
||||
CombineFeedback(var_feedback, BinaryOperationFeedback::kSignedSmall);
|
||||
var_result = SmiSub(SmiConstant(0), smi_value);
|
||||
Goto(&end);
|
||||
|
||||
BIND(&if_zero);
|
||||
CombineFeedback(var_feedback, BinaryOperationFeedback::kNumber);
|
||||
var_result = MinusZeroConstant();
|
||||
Goto(&end);
|
||||
|
||||
BIND(&if_min_smi);
|
||||
*var_float = SmiToFloat64(smi_value);
|
||||
Goto(do_float_op);
|
||||
|
||||
BIND(&end);
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
TNode<Float64T> FloatOp(TNode<Float64T> float_value) override {
|
||||
return Float64Neg(float_value);
|
||||
}
|
||||
|
||||
TNode<HeapObject> BigIntOp(TNode<Context> context,
|
||||
TNode<HeapObject> bigint_value) override {
|
||||
return CAST(CallRuntime(Runtime::kBigIntUnaryOp, context, bigint_value,
|
||||
SmiConstant(Operation::kNegate)));
|
||||
}
|
||||
};
|
||||
|
||||
template <int kAddValue, Operation kOperation>
|
||||
class IncDecAssembler : public UnaryNumericOpAssembler {
|
||||
public:
|
||||
explicit IncDecAssembler(compiler::CodeAssemblerState* state)
|
||||
: UnaryNumericOpAssembler(state) {}
|
||||
|
||||
using UnaryNumericOpAssembler::UnaryOpWithFeedback;
|
||||
|
||||
private:
|
||||
TNode<Number> SmiOp(TNode<Smi> value, TVariable<Smi>* var_feedback,
|
||||
Label* do_float_op,
|
||||
TVariable<Float64T>* var_float) override {
|
||||
Label if_overflow(this), out(this);
|
||||
TNode<Smi> result = TrySmiAdd(value, SmiConstant(kAddValue), &if_overflow);
|
||||
CombineFeedback(var_feedback, BinaryOperationFeedback::kSignedSmall);
|
||||
Goto(&out);
|
||||
|
||||
BIND(&if_overflow);
|
||||
*var_float = SmiToFloat64(value);
|
||||
Goto(do_float_op);
|
||||
|
||||
BIND(&out);
|
||||
return result;
|
||||
}
|
||||
TNode<Float64T> FloatOp(TNode<Float64T> float_value) override {
|
||||
return Float64Add(float_value, Float64Constant(kAddValue));
|
||||
}
|
||||
TNode<HeapObject> BigIntOp(TNode<Context> context,
|
||||
TNode<HeapObject> bigint_value) override {
|
||||
return CAST(CallRuntime(Runtime::kBigIntUnaryOp, context, bigint_value,
|
||||
SmiConstant(kOperation)));
|
||||
}
|
||||
};
|
||||
|
||||
using IncAssembler = IncDecAssembler<1, Operation::kIncrement>;
|
||||
using DecAssembler = IncDecAssembler<-1, Operation::kDecrement>;
|
||||
|
||||
class BitwiseNotAssembler : public CodeStubAssembler {
|
||||
public:
|
||||
explicit BitwiseNotAssembler(compiler::CodeAssemblerState* state)
|
||||
: CodeStubAssembler(state) {}
|
||||
|
||||
TNode<Object> BitwiseNotWithFeedback(
|
||||
TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
|
||||
TNode<HeapObject> maybe_feedback_vector) {
|
||||
TVARIABLE(Word32T, var_word32);
|
||||
TVARIABLE(Smi, var_feedback);
|
||||
TVARIABLE(BigInt, var_bigint);
|
||||
TVARIABLE(Object, var_result);
|
||||
Label if_number(this), if_bigint(this, Label::kDeferred), out(this);
|
||||
TaggedToWord32OrBigIntWithFeedback(context, value, &if_number, &var_word32,
|
||||
&if_bigint, &var_bigint, &var_feedback);
|
||||
|
||||
// Number case.
|
||||
BIND(&if_number);
|
||||
var_result =
|
||||
ChangeInt32ToTagged(Signed(Word32BitwiseNot(var_word32.value())));
|
||||
TNode<Smi> result_type = SelectSmiConstant(
|
||||
TaggedIsSmi(var_result.value()), BinaryOperationFeedback::kSignedSmall,
|
||||
BinaryOperationFeedback::kNumber);
|
||||
UpdateFeedback(SmiOr(result_type, var_feedback.value()),
|
||||
maybe_feedback_vector, slot);
|
||||
Goto(&out);
|
||||
|
||||
// BigInt case.
|
||||
BIND(&if_bigint);
|
||||
UpdateFeedback(SmiConstant(BinaryOperationFeedback::kBigInt),
|
||||
maybe_feedback_vector, slot);
|
||||
var_result =
|
||||
CallRuntime(Runtime::kBigIntUnaryOp, context, var_bigint.value(),
|
||||
SmiConstant(Operation::kBitwiseNot));
|
||||
Goto(&out);
|
||||
|
||||
BIND(&out);
|
||||
return var_result.value();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TNode<Object> UnaryOpAssembler::Generate_BitwiseNotWithFeedback(
|
||||
TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
|
||||
TNode<HeapObject> maybe_feedback_vector) {
|
||||
// TODO(jgruber): Make this implementation more consistent with other unary
|
||||
// ops (i.e. have them all use UnaryOpWithFeedback or some other mechanism).
|
||||
BitwiseNotAssembler a(state_);
|
||||
return a.BitwiseNotWithFeedback(context, value, slot, maybe_feedback_vector);
|
||||
}
|
||||
|
||||
TNode<Object> UnaryOpAssembler::Generate_DecrementWithFeedback(
|
||||
TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
|
||||
TNode<HeapObject> maybe_feedback_vector) {
|
||||
DecAssembler a(state_);
|
||||
return a.UnaryOpWithFeedback(context, value, slot, maybe_feedback_vector);
|
||||
}
|
||||
|
||||
TNode<Object> UnaryOpAssembler::Generate_IncrementWithFeedback(
|
||||
TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
|
||||
TNode<HeapObject> maybe_feedback_vector) {
|
||||
IncAssembler a(state_);
|
||||
return a.UnaryOpWithFeedback(context, value, slot, maybe_feedback_vector);
|
||||
}
|
||||
|
||||
TNode<Object> UnaryOpAssembler::Generate_NegateWithFeedback(
|
||||
TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
|
||||
TNode<HeapObject> maybe_feedback_vector) {
|
||||
NegateAssembler a(state_);
|
||||
return a.UnaryOpWithFeedback(context, value, slot, maybe_feedback_vector);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
45
src/ic/unary-op-assembler.h
Normal file
45
src/ic/unary-op-assembler.h
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_IC_UNARY_OP_ASSEMBLER_H_
|
||||
#define V8_IC_UNARY_OP_ASSEMBLER_H_
|
||||
|
||||
#include "src/codegen/code-stub-assembler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
namespace compiler {
|
||||
class CodeAssemblerState;
|
||||
}
|
||||
|
||||
class UnaryOpAssembler final {
|
||||
public:
|
||||
explicit UnaryOpAssembler(compiler::CodeAssemblerState* state)
|
||||
: state_(state) {}
|
||||
|
||||
TNode<Object> Generate_BitwiseNotWithFeedback(
|
||||
TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
|
||||
TNode<HeapObject> maybe_feedback_vector);
|
||||
|
||||
TNode<Object> Generate_DecrementWithFeedback(
|
||||
TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
|
||||
TNode<HeapObject> maybe_feedback_vector);
|
||||
|
||||
TNode<Object> Generate_IncrementWithFeedback(
|
||||
TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
|
||||
TNode<HeapObject> maybe_feedback_vector);
|
||||
|
||||
TNode<Object> Generate_NegateWithFeedback(
|
||||
TNode<Context> context, TNode<Object> value, TNode<UintPtrT> slot,
|
||||
TNode<HeapObject> maybe_feedback_vector);
|
||||
|
||||
private:
|
||||
compiler::CodeAssemblerState* const state_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_IC_UNARY_OP_ASSEMBLER_H_
|
@ -14,6 +14,7 @@
|
||||
#include "src/ic/accessor-assembler.h"
|
||||
#include "src/ic/binary-op-assembler.h"
|
||||
#include "src/ic/ic.h"
|
||||
#include "src/ic/unary-op-assembler.h"
|
||||
#include "src/interpreter/bytecode-flags.h"
|
||||
#include "src/interpreter/bytecodes.h"
|
||||
#include "src/interpreter/interpreter-assembler.h"
|
||||
@ -1083,38 +1084,17 @@ IGNITION_HANDLER(BitwiseAndSmi, InterpreterBitwiseBinaryOpAssembler) {
|
||||
//
|
||||
// Perform bitwise-not on the accumulator.
|
||||
IGNITION_HANDLER(BitwiseNot, InterpreterAssembler) {
|
||||
TNode<Object> operand = GetAccumulator();
|
||||
TNode<Object> value = GetAccumulator();
|
||||
TNode<Context> context = GetContext();
|
||||
TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
|
||||
TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
|
||||
TNode<Context> context = GetContext();
|
||||
|
||||
TVARIABLE(Word32T, var_word32);
|
||||
TVARIABLE(Smi, var_feedback);
|
||||
TVARIABLE(BigInt, var_bigint);
|
||||
Label if_number(this), if_bigint(this);
|
||||
TaggedToWord32OrBigIntWithFeedback(context, operand, &if_number, &var_word32,
|
||||
&if_bigint, &var_bigint, &var_feedback);
|
||||
UnaryOpAssembler unary_op_asm(state());
|
||||
TNode<Object> result = unary_op_asm.Generate_BitwiseNotWithFeedback(
|
||||
context, value, slot_index, maybe_feedback_vector);
|
||||
|
||||
// Number case.
|
||||
BIND(&if_number);
|
||||
TNode<Number> result =
|
||||
ChangeInt32ToTagged(Signed(Word32BitwiseNot(var_word32.value())));
|
||||
TNode<Smi> result_type = SelectSmiConstant(
|
||||
TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall,
|
||||
BinaryOperationFeedback::kNumber);
|
||||
UpdateFeedback(SmiOr(result_type, var_feedback.value()),
|
||||
maybe_feedback_vector, slot_index);
|
||||
SetAccumulator(result);
|
||||
Dispatch();
|
||||
|
||||
// BigInt case.
|
||||
BIND(&if_bigint);
|
||||
UpdateFeedback(SmiConstant(BinaryOperationFeedback::kBigInt),
|
||||
maybe_feedback_vector, slot_index);
|
||||
SetAccumulator(CallRuntime(Runtime::kBigIntUnaryOp, context,
|
||||
var_bigint.value(),
|
||||
SmiConstant(Operation::kBitwiseNot)));
|
||||
Dispatch();
|
||||
}
|
||||
|
||||
// ShiftLeftSmi <imm>
|
||||
@ -1144,162 +1124,22 @@ IGNITION_HANDLER(ShiftRightLogicalSmi, InterpreterBitwiseBinaryOpAssembler) {
|
||||
BitwiseBinaryOpWithSmi(Operation::kShiftRightLogical);
|
||||
}
|
||||
|
||||
class UnaryNumericOpAssembler : public InterpreterAssembler {
|
||||
public:
|
||||
UnaryNumericOpAssembler(CodeAssemblerState* state, Bytecode bytecode,
|
||||
OperandScale operand_scale)
|
||||
: InterpreterAssembler(state, bytecode, operand_scale) {}
|
||||
|
||||
virtual ~UnaryNumericOpAssembler() = default;
|
||||
|
||||
// Must return a tagged value.
|
||||
virtual TNode<Number> SmiOp(TNode<Smi> smi_value,
|
||||
TVariable<Smi>* var_feedback, Label* do_float_op,
|
||||
TVariable<Float64T>* var_float) = 0;
|
||||
// Must return a Float64 value.
|
||||
virtual TNode<Float64T> FloatOp(TNode<Float64T> float_value) = 0;
|
||||
// Must return a tagged value.
|
||||
virtual TNode<HeapObject> BigIntOp(TNode<HeapObject> bigint_value) = 0;
|
||||
|
||||
void UnaryOpWithFeedback() {
|
||||
TVARIABLE(Object, var_value, GetAccumulator());
|
||||
TVARIABLE(Object, var_result);
|
||||
TVARIABLE(Float64T, var_float_value);
|
||||
TVARIABLE(Smi, var_feedback, SmiConstant(BinaryOperationFeedback::kNone));
|
||||
Label start(this, {&var_value, &var_feedback}), end(this);
|
||||
Label do_float_op(this, &var_float_value);
|
||||
Goto(&start);
|
||||
// We might have to try again after ToNumeric conversion.
|
||||
BIND(&start);
|
||||
{
|
||||
Label if_smi(this), if_heapnumber(this), if_oddball(this);
|
||||
Label if_bigint(this, Label::kDeferred);
|
||||
Label if_other(this, Label::kDeferred);
|
||||
TNode<Object> value = var_value.value();
|
||||
GotoIf(TaggedIsSmi(value), &if_smi);
|
||||
|
||||
TNode<HeapObject> value_heap_object = CAST(value);
|
||||
TNode<Map> map = LoadMap(value_heap_object);
|
||||
GotoIf(IsHeapNumberMap(map), &if_heapnumber);
|
||||
TNode<Uint16T> instance_type = LoadMapInstanceType(map);
|
||||
GotoIf(IsBigIntInstanceType(instance_type), &if_bigint);
|
||||
Branch(InstanceTypeEqual(instance_type, ODDBALL_TYPE), &if_oddball,
|
||||
&if_other);
|
||||
|
||||
BIND(&if_smi);
|
||||
{
|
||||
var_result =
|
||||
SmiOp(CAST(value), &var_feedback, &do_float_op, &var_float_value);
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&if_heapnumber);
|
||||
{
|
||||
var_float_value = LoadHeapNumberValue(value_heap_object);
|
||||
Goto(&do_float_op);
|
||||
}
|
||||
|
||||
BIND(&if_bigint);
|
||||
{
|
||||
var_result = BigIntOp(value_heap_object);
|
||||
CombineFeedback(&var_feedback, BinaryOperationFeedback::kBigInt);
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&if_oddball);
|
||||
{
|
||||
// We do not require an Or with earlier feedback here because once we
|
||||
// convert the value to a number, we cannot reach this path. We can
|
||||
// only reach this path on the first pass when the feedback is kNone.
|
||||
CSA_ASSERT(this, SmiEqual(var_feedback.value(),
|
||||
SmiConstant(BinaryOperationFeedback::kNone)));
|
||||
OverwriteFeedback(&var_feedback,
|
||||
BinaryOperationFeedback::kNumberOrOddball);
|
||||
var_value =
|
||||
LoadObjectField(value_heap_object, Oddball::kToNumberOffset);
|
||||
Goto(&start);
|
||||
}
|
||||
|
||||
BIND(&if_other);
|
||||
{
|
||||
// We do not require an Or with earlier feedback here because once we
|
||||
// convert the value to a number, we cannot reach this path. We can
|
||||
// only reach this path on the first pass when the feedback is kNone.
|
||||
CSA_ASSERT(this, SmiEqual(var_feedback.value(),
|
||||
SmiConstant(BinaryOperationFeedback::kNone)));
|
||||
OverwriteFeedback(&var_feedback, BinaryOperationFeedback::kAny);
|
||||
var_value = CallBuiltin(Builtins::kNonNumberToNumeric, GetContext(),
|
||||
value_heap_object);
|
||||
Goto(&start);
|
||||
}
|
||||
}
|
||||
|
||||
BIND(&do_float_op);
|
||||
{
|
||||
CombineFeedback(&var_feedback, BinaryOperationFeedback::kNumber);
|
||||
var_result =
|
||||
AllocateHeapNumberWithValue(FloatOp(var_float_value.value()));
|
||||
Goto(&end);
|
||||
}
|
||||
|
||||
BIND(&end);
|
||||
TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
|
||||
TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
|
||||
UpdateFeedback(var_feedback.value(), maybe_feedback_vector, slot_index);
|
||||
SetAccumulator(var_result.value());
|
||||
Dispatch();
|
||||
}
|
||||
};
|
||||
|
||||
class NegateAssemblerImpl : public UnaryNumericOpAssembler {
|
||||
public:
|
||||
explicit NegateAssemblerImpl(CodeAssemblerState* state, Bytecode bytecode,
|
||||
OperandScale operand_scale)
|
||||
: UnaryNumericOpAssembler(state, bytecode, operand_scale) {}
|
||||
|
||||
TNode<Number> SmiOp(TNode<Smi> smi_value, TVariable<Smi>* var_feedback,
|
||||
Label* do_float_op,
|
||||
TVariable<Float64T>* var_float) override {
|
||||
TVARIABLE(Number, var_result);
|
||||
Label if_zero(this), if_min_smi(this), end(this);
|
||||
// Return -0 if operand is 0.
|
||||
GotoIf(SmiEqual(smi_value, SmiConstant(0)), &if_zero);
|
||||
|
||||
// Special-case the minimum Smi to avoid overflow.
|
||||
GotoIf(SmiEqual(smi_value, SmiConstant(Smi::kMinValue)), &if_min_smi);
|
||||
|
||||
// Else simply subtract operand from 0.
|
||||
CombineFeedback(var_feedback, BinaryOperationFeedback::kSignedSmall);
|
||||
var_result = SmiSub(SmiConstant(0), smi_value);
|
||||
Goto(&end);
|
||||
|
||||
BIND(&if_zero);
|
||||
CombineFeedback(var_feedback, BinaryOperationFeedback::kNumber);
|
||||
var_result = MinusZeroConstant();
|
||||
Goto(&end);
|
||||
|
||||
BIND(&if_min_smi);
|
||||
*var_float = SmiToFloat64(smi_value);
|
||||
Goto(do_float_op);
|
||||
|
||||
BIND(&end);
|
||||
return var_result.value();
|
||||
}
|
||||
|
||||
TNode<Float64T> FloatOp(TNode<Float64T> float_value) override {
|
||||
return Float64Neg(float_value);
|
||||
}
|
||||
|
||||
TNode<HeapObject> BigIntOp(TNode<HeapObject> bigint_value) override {
|
||||
return CAST(CallRuntime(Runtime::kBigIntUnaryOp, GetContext(), bigint_value,
|
||||
SmiConstant(Operation::kNegate)));
|
||||
}
|
||||
};
|
||||
|
||||
// Negate <feedback_slot>
|
||||
//
|
||||
// Perform arithmetic negation on the accumulator.
|
||||
IGNITION_HANDLER(Negate, NegateAssemblerImpl) { UnaryOpWithFeedback(); }
|
||||
IGNITION_HANDLER(Negate, InterpreterAssembler) {
|
||||
TNode<Object> value = GetAccumulator();
|
||||
TNode<Context> context = GetContext();
|
||||
TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
|
||||
TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
|
||||
|
||||
UnaryOpAssembler unary_op_asm(state());
|
||||
TNode<Object> result = unary_op_asm.Generate_NegateWithFeedback(
|
||||
context, value, slot_index, maybe_feedback_vector);
|
||||
|
||||
SetAccumulator(result);
|
||||
Dispatch();
|
||||
}
|
||||
|
||||
// ToName <dst>
|
||||
//
|
||||
@ -1345,72 +1185,39 @@ IGNITION_HANDLER(ToString, InterpreterAssembler) {
|
||||
Dispatch();
|
||||
}
|
||||
|
||||
class IncDecAssembler : public UnaryNumericOpAssembler {
|
||||
public:
|
||||
explicit IncDecAssembler(CodeAssemblerState* state, Bytecode bytecode,
|
||||
OperandScale operand_scale)
|
||||
: UnaryNumericOpAssembler(state, bytecode, operand_scale) {}
|
||||
|
||||
Operation op() {
|
||||
DCHECK(op_ == Operation::kIncrement || op_ == Operation::kDecrement);
|
||||
return op_;
|
||||
}
|
||||
|
||||
TNode<Number> SmiOp(TNode<Smi> value, TVariable<Smi>* var_feedback,
|
||||
Label* do_float_op,
|
||||
TVariable<Float64T>* var_float) override {
|
||||
TNode<Smi> one = SmiConstant(1);
|
||||
Label if_overflow(this), if_notoverflow(this);
|
||||
TNode<Smi> result = op() == Operation::kIncrement
|
||||
? TrySmiAdd(value, one, &if_overflow)
|
||||
: TrySmiSub(value, one, &if_overflow);
|
||||
Goto(&if_notoverflow);
|
||||
|
||||
BIND(&if_overflow);
|
||||
{
|
||||
*var_float = SmiToFloat64(value);
|
||||
Goto(do_float_op);
|
||||
}
|
||||
|
||||
BIND(&if_notoverflow);
|
||||
CombineFeedback(var_feedback, BinaryOperationFeedback::kSignedSmall);
|
||||
return result;
|
||||
}
|
||||
|
||||
TNode<Float64T> FloatOp(TNode<Float64T> float_value) override {
|
||||
return op() == Operation::kIncrement
|
||||
? Float64Add(float_value, Float64Constant(1.0))
|
||||
: Float64Sub(float_value, Float64Constant(1.0));
|
||||
}
|
||||
|
||||
TNode<HeapObject> BigIntOp(TNode<HeapObject> bigint_value) override {
|
||||
return CAST(CallRuntime(Runtime::kBigIntUnaryOp, GetContext(), bigint_value,
|
||||
SmiConstant(op())));
|
||||
}
|
||||
|
||||
void IncWithFeedback() {
|
||||
op_ = Operation::kIncrement;
|
||||
UnaryOpWithFeedback();
|
||||
}
|
||||
|
||||
void DecWithFeedback() {
|
||||
op_ = Operation::kDecrement;
|
||||
UnaryOpWithFeedback();
|
||||
}
|
||||
|
||||
private:
|
||||
Operation op_ = Operation::kEqual; // Dummy initialization.
|
||||
};
|
||||
|
||||
// Inc
|
||||
//
|
||||
// Increments value in the accumulator by one.
|
||||
IGNITION_HANDLER(Inc, IncDecAssembler) { IncWithFeedback(); }
|
||||
IGNITION_HANDLER(Inc, InterpreterAssembler) {
|
||||
TNode<Object> value = GetAccumulator();
|
||||
TNode<Context> context = GetContext();
|
||||
TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
|
||||
TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
|
||||
|
||||
UnaryOpAssembler unary_op_asm(state());
|
||||
TNode<Object> result = unary_op_asm.Generate_IncrementWithFeedback(
|
||||
context, value, slot_index, maybe_feedback_vector);
|
||||
|
||||
SetAccumulator(result);
|
||||
Dispatch();
|
||||
}
|
||||
|
||||
// Dec
|
||||
//
|
||||
// Decrements value in the accumulator by one.
|
||||
IGNITION_HANDLER(Dec, IncDecAssembler) { DecWithFeedback(); }
|
||||
IGNITION_HANDLER(Dec, InterpreterAssembler) {
|
||||
TNode<Object> value = GetAccumulator();
|
||||
TNode<Context> context = GetContext();
|
||||
TNode<UintPtrT> slot_index = BytecodeOperandIdx(0);
|
||||
TNode<HeapObject> maybe_feedback_vector = LoadFeedbackVector();
|
||||
|
||||
UnaryOpAssembler unary_op_asm(state());
|
||||
TNode<Object> result = unary_op_asm.Generate_DecrementWithFeedback(
|
||||
context, value, slot_index, maybe_feedback_vector);
|
||||
|
||||
SetAccumulator(result);
|
||||
Dispatch();
|
||||
}
|
||||
|
||||
// ToBooleanLogicalNot
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user