[fullcodegen] Deprecate usage of patching BinaryOpICStub.

This switches all uses of the patching {BinaryOpICStub} over to the
respective existing and non-patching CSA-builtins, and removes some
supporting code. It also removes the inlined SMI handling.

R=verwaest@chromium.org
BUG=v8:6408

Change-Id: If547c0127bfcafbd01ccb33b702b1868006ebcb1
Reviewed-on: https://chromium-review.googlesource.com/541398
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46122}
This commit is contained in:
Michael Starzinger 2017-06-22 10:30:40 +02:00 committed by Commit Bot
parent baa4d4faea
commit e6c2df47e1
50 changed files with 161 additions and 2719 deletions

View File

@ -785,8 +785,6 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
CreateWeakCellStub::GenerateAheadOfTime(isolate);
BinaryOpICStub::GenerateAheadOfTime(isolate);
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
StoreFastElementStub::GenerateAheadOfTime(isolate);
}
@ -1487,37 +1485,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r1 : left
// -- r0 : right
// -- lr : return address
// -----------------------------------
// Load r2 with the allocation site. We stick an undefined dummy value here
// and replace it with the real allocation site later when we instantiate this
// stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
__ Move(r2, isolate()->factory()->undefined_value());
// Make sure that we actually patched the allocation site.
if (FLAG_debug_code) {
__ tst(r2, Operand(kSmiTagMask));
__ Assert(ne, kExpectedAllocationSite);
__ push(r2);
__ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kAllocationSiteMapRootIndex);
__ cmp(r2, ip);
__ pop(r2);
__ Assert(eq, kExpectedAllocationSite);
}
// Tail call into the stub that handles binary operations with allocation
// sites.
BinaryOpWithAllocationSiteStub stub(isolate(), state());
__ TailCallStub(&stub);
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;

View File

@ -804,10 +804,8 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
CreateWeakCellStub::GenerateAheadOfTime(isolate);
BinaryOpICStub::GenerateAheadOfTime(isolate);
StoreRegistersStateStub::GenerateAheadOfTime(isolate);
RestoreRegistersStateStub::GenerateAheadOfTime(isolate);
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
StoreFastElementStub::GenerateAheadOfTime(isolate);
}
@ -2006,32 +2004,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x1 : left
// -- x0 : right
// -- lr : return address
// -----------------------------------
// Load x2 with the allocation site. We stick an undefined dummy value here
// and replace it with the real allocation site later when we instantiate this
// stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
__ LoadObject(x2, handle(isolate()->heap()->undefined_value()));
// Make sure that we actually patched the allocation site.
if (FLAG_debug_code) {
__ AssertNotSmi(x2, kExpectedAllocationSite);
__ Ldr(x10, FieldMemOperand(x2, HeapObject::kMapOffset));
__ AssertRegisterIsRoot(x10, Heap::kAllocationSiteMapRootIndex,
kExpectedAllocationSite);
}
// Tail call into the stub that handles binary operations with allocation
// sites.
BinaryOpWithAllocationSiteStub stub(isolate(), state());
__ TailCallStub(&stub);
}
RecordWriteStub::RegisterAllocation::RegisterAllocation(Register object,
Register address,
Register scratch)

View File

@ -170,9 +170,34 @@ Callable CodeFactory::CompareIC(Isolate* isolate, Token::Value op) {
}
// static
Callable CodeFactory::BinaryOpIC(Isolate* isolate, Token::Value op) {
BinaryOpICStub stub(isolate, op);
return make_callable(stub);
Callable CodeFactory::BinaryOperation(Isolate* isolate, Token::Value op) {
switch (op) {
case Token::SAR:
return Builtins::CallableFor(isolate, Builtins::kShiftRight);
case Token::SHL:
return Builtins::CallableFor(isolate, Builtins::kShiftLeft);
case Token::SHR:
return Builtins::CallableFor(isolate, Builtins::kShiftRightLogical);
case Token::ADD:
return Builtins::CallableFor(isolate, Builtins::kAdd);
case Token::SUB:
return Builtins::CallableFor(isolate, Builtins::kSubtract);
case Token::MUL:
return Builtins::CallableFor(isolate, Builtins::kMultiply);
case Token::DIV:
return Builtins::CallableFor(isolate, Builtins::kDivide);
case Token::MOD:
return Builtins::CallableFor(isolate, Builtins::kModulus);
case Token::BIT_OR:
return Builtins::CallableFor(isolate, Builtins::kBitwiseOr);
case Token::BIT_AND:
return Builtins::CallableFor(isolate, Builtins::kBitwiseAnd);
case Token::BIT_XOR:
return Builtins::CallableFor(isolate, Builtins::kBitwiseXor);
default:
break;
}
UNREACHABLE();
}
// static

View File

@ -55,7 +55,7 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Callable CompareIC(Isolate* isolate, Token::Value op);
static Callable CompareNilIC(Isolate* isolate, NilValue nil_value);
static Callable BinaryOpIC(Isolate* isolate, Token::Value op);
static Callable BinaryOperation(Isolate* isolate, Token::Value op);
static Callable ApiGetter(Isolate* isolate);

View File

@ -384,105 +384,6 @@ Handle<Code> TransitionElementsKindStub::GenerateCode() {
return DoGenerateCode(this);
}
template <>
HValue* CodeStubGraphBuilder<BinaryOpICStub>::BuildCodeInitializedStub() {
BinaryOpICState state = casted_stub()->state();
HValue* left = GetParameter(Descriptor::kLeft);
HValue* right = GetParameter(Descriptor::kRight);
AstType* left_type = state.GetLeftType();
AstType* right_type = state.GetRightType();
AstType* result_type = state.GetResultType();
DCHECK(!left_type->Is(AstType::None()) && !right_type->Is(AstType::None()) &&
(state.HasSideEffects() || !result_type->Is(AstType::None())));
HValue* result = NULL;
HAllocationMode allocation_mode(NOT_TENURED);
if (state.op() == Token::ADD && (left_type->Maybe(AstType::String()) ||
right_type->Maybe(AstType::String())) &&
!left_type->Is(AstType::String()) && !right_type->Is(AstType::String())) {
// For the generic add stub a fast case for string addition is performance
// critical.
if (left_type->Maybe(AstType::String())) {
IfBuilder if_leftisstring(this);
if_leftisstring.If<HIsStringAndBranch>(left);
if_leftisstring.Then();
{
Push(BuildBinaryOperation(state.op(), left, right, AstType::String(),
right_type, result_type,
state.fixed_right_arg(), allocation_mode));
}
if_leftisstring.Else();
{
Push(BuildBinaryOperation(state.op(), left, right, left_type,
right_type, result_type,
state.fixed_right_arg(), allocation_mode));
}
if_leftisstring.End();
result = Pop();
} else {
IfBuilder if_rightisstring(this);
if_rightisstring.If<HIsStringAndBranch>(right);
if_rightisstring.Then();
{
Push(BuildBinaryOperation(state.op(), left, right, left_type,
AstType::String(), result_type,
state.fixed_right_arg(), allocation_mode));
}
if_rightisstring.Else();
{
Push(BuildBinaryOperation(state.op(), left, right, left_type,
right_type, result_type,
state.fixed_right_arg(), allocation_mode));
}
if_rightisstring.End();
result = Pop();
}
} else {
result = BuildBinaryOperation(state.op(), left, right, left_type,
right_type, result_type,
state.fixed_right_arg(), allocation_mode);
}
// If we encounter a generic argument, the number conversion is
// observable, thus we cannot afford to bail out after the fact.
if (!state.HasSideEffects()) {
result = EnforceNumberType(result, result_type);
}
return result;
}
Handle<Code> BinaryOpICStub::GenerateCode() {
return DoGenerateCode(this);
}
template <>
HValue* CodeStubGraphBuilder<BinaryOpWithAllocationSiteStub>::BuildCodeStub() {
BinaryOpICState state = casted_stub()->state();
HValue* allocation_site = GetParameter(Descriptor::kAllocationSite);
HValue* left = GetParameter(Descriptor::kLeft);
HValue* right = GetParameter(Descriptor::kRight);
AstType* left_type = state.GetLeftType();
AstType* right_type = state.GetRightType();
AstType* result_type = state.GetResultType();
HAllocationMode allocation_mode(allocation_site);
return BuildBinaryOperation(state.op(), left, right, left_type, right_type,
result_type, state.fixed_right_arg(),
allocation_mode);
}
Handle<Code> BinaryOpWithAllocationSiteStub::GenerateCode() {
return DoGenerateCode(this);
}
} // namespace internal
} // namespace v8

View File

@ -281,56 +281,6 @@ MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
}
// static
void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
if (FLAG_minimal) return;
// Generate the uninitialized versions of the stub.
for (int op = Token::BIT_OR; op <= Token::MOD; ++op) {
BinaryOpICStub stub(isolate, static_cast<Token::Value>(op));
stub.GetCode();
}
// Generate special versions of the stub.
BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
}
void BinaryOpICStub::PrintState(std::ostream& os) const { // NOLINT
os << state();
}
// static
void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate,
const BinaryOpICState& state) {
if (FLAG_minimal) return;
BinaryOpICStub stub(isolate, state);
stub.GetCode();
}
// static
void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
// Generate special versions of the stub.
BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
}
void BinaryOpICWithAllocationSiteStub::PrintState(
std::ostream& os) const { // NOLINT
os << state();
}
// static
void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(
Isolate* isolate, const BinaryOpICState& state) {
if (state.CouldCreateAllocationMementos()) {
BinaryOpICWithAllocationSiteStub stub(isolate, state);
stub.GetCode();
}
}
void StringAddStub::PrintBaseName(std::ostream& os) const { // NOLINT
os << "StringAddStub_" << flags() << "_" << pretenure_flag();
}
@ -803,18 +753,6 @@ void AllocateHeapNumberStub::InitializeDescriptor(
}
void BinaryOpICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
descriptor->Initialize(FUNCTION_ADDR(Runtime_BinaryOpIC_Miss));
descriptor->SetMissHandler(Runtime::kBinaryOpIC_Miss);
}
void BinaryOpWithAllocationSiteStub::InitializeDescriptor(
CodeStubDescriptor* descriptor) {
descriptor->Initialize(
FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite));
}
// TODO(ishell): move to builtins.
TF_STUB(GetPropertyStub, CodeStubAssembler) {
Label call_runtime(this, Label::kDeferred), return_undefined(this), end(this);

View File

@ -32,7 +32,6 @@ class Node;
#define CODE_STUB_LIST_ALL_PLATFORMS(V) \
/* --- PlatformCodeStubs --- */ \
V(ArrayConstructor) \
V(BinaryOpICWithAllocationSite) \
V(CallApiCallback) \
V(CallApiGetter) \
V(CallConstruct) \
@ -61,8 +60,6 @@ class Node;
/* These should never be ported to TF */ \
/* because they are either used only by */ \
/* FCG/Crankshaft or are deprecated */ \
V(BinaryOpIC) \
V(BinaryOpWithAllocationSite) \
V(TransitionElementsKind) \
/* --- TurboFanCodeStubs --- */ \
V(AllocateHeapNumber) \
@ -864,95 +861,6 @@ class CallApiGetterStub : public PlatformCodeStub {
};
class BinaryOpICStub : public HydrogenCodeStub {
public:
BinaryOpICStub(Isolate* isolate, Token::Value op)
: HydrogenCodeStub(isolate, UNINITIALIZED) {
BinaryOpICState state(isolate, op);
set_sub_minor_key(state.GetExtraICState());
}
BinaryOpICStub(Isolate* isolate, const BinaryOpICState& state)
: HydrogenCodeStub(isolate) {
set_sub_minor_key(state.GetExtraICState());
}
static void GenerateAheadOfTime(Isolate* isolate);
Code::Kind GetCodeKind() const override { return Code::BINARY_OP_IC; }
ExtraICState GetExtraICState() const final {
return static_cast<ExtraICState>(sub_minor_key());
}
BinaryOpICState state() const {
return BinaryOpICState(isolate(), GetExtraICState());
}
void PrintState(std::ostream& os) const final; // NOLINT
private:
static void GenerateAheadOfTime(Isolate* isolate,
const BinaryOpICState& state);
DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOp);
DEFINE_HYDROGEN_CODE_STUB(BinaryOpIC, HydrogenCodeStub);
};
// TODO(bmeurer): Merge this into the BinaryOpICStub once we have proper tail
// call support for stubs in Hydrogen.
class BinaryOpICWithAllocationSiteStub final : public PlatformCodeStub {
public:
BinaryOpICWithAllocationSiteStub(Isolate* isolate,
const BinaryOpICState& state)
: PlatformCodeStub(isolate) {
minor_key_ = state.GetExtraICState();
}
static void GenerateAheadOfTime(Isolate* isolate);
Handle<Code> GetCodeCopyFromTemplate(Handle<AllocationSite> allocation_site) {
FindAndReplacePattern pattern;
pattern.Add(isolate()->factory()->undefined_map(), allocation_site);
return CodeStub::GetCodeCopy(pattern);
}
Code::Kind GetCodeKind() const override { return Code::BINARY_OP_IC; }
ExtraICState GetExtraICState() const override {
return static_cast<ExtraICState>(minor_key_);
}
void PrintState(std::ostream& os) const override; // NOLINT
private:
BinaryOpICState state() const {
return BinaryOpICState(isolate(), GetExtraICState());
}
static void GenerateAheadOfTime(Isolate* isolate,
const BinaryOpICState& state);
DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOpWithAllocationSite);
DEFINE_PLATFORM_CODE_STUB(BinaryOpICWithAllocationSite, PlatformCodeStub);
};
class BinaryOpWithAllocationSiteStub final : public BinaryOpICStub {
public:
BinaryOpWithAllocationSiteStub(Isolate* isolate, Token::Value op)
: BinaryOpICStub(isolate, op) {}
BinaryOpWithAllocationSiteStub(Isolate* isolate, const BinaryOpICState& state)
: BinaryOpICStub(isolate, state) {}
Code::Kind GetCodeKind() const final { return Code::STUB; }
DEFINE_CALL_INTERFACE_DESCRIPTOR(BinaryOpWithAllocationSite);
DEFINE_HYDROGEN_CODE_STUB(BinaryOpWithAllocationSite, BinaryOpICStub);
};
class StringAddStub final : public TurboFanCodeStub {
public:
StringAddStub(Isolate* isolate, StringAddFlags flags,

View File

@ -646,8 +646,7 @@ void LCodeGen::AddToTranslation(LEnvironment* environment,
int LCodeGen::CallCodeSize(Handle<Code> code, RelocInfo::Mode mode) {
int size = masm()->CallSize(code, mode);
if (code->kind() == Code::BINARY_OP_IC ||
code->kind() == Code::COMPARE_IC) {
if (code->kind() == Code::COMPARE_IC) {
size += Assembler::kInstrSize; // extra nop() added in CallCodeGeneric.
}
return size;
@ -676,8 +675,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
// Signal that we don't inline smi code before these stubs in the
// optimizing code generator.
if (code->kind() == Code::BINARY_OP_IC ||
code->kind() == Code::COMPARE_IC) {
if (code->kind() == Code::COMPARE_IC) {
__ nop();
}
}
@ -1954,11 +1952,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
DCHECK(ToRegister(instr->right()).is(r0));
DCHECK(ToRegister(instr->result()).is(r0));
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), instr->op()).code();
// Block literal pool emission to ensure nop indicating no inlined smi code
// is in the correct position.
Assembler::BlockConstPoolScope block_const_pool(masm());
CallCode(code, RelocInfo::CODE_TARGET, instr);
UNREACHABLE();
}

View File

@ -374,8 +374,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
__ Call(code, mode);
RecordSafepointWithLazyDeopt(instr, safepoint_mode);
if ((code->kind() == Code::BINARY_OP_IC) ||
(code->kind() == Code::COMPARE_IC)) {
if ((code->kind() == Code::COMPARE_IC)) {
// Signal that we don't inline smi code before these stubs in the
// optimizing code generator.
InlineSmiCheckInfo::EmitNotInlined(masm());
@ -1670,8 +1669,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
DCHECK(ToRegister(instr->right()).is(x0));
DCHECK(ToRegister(instr->result()).is(x0));
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
UNREACHABLE();
}

View File

@ -576,8 +576,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
// Signal that we don't inline smi code before these stubs in the
// optimizing code generator.
if (code->kind() == Code::BINARY_OP_IC ||
code->kind() == Code::COMPARE_IC) {
if (code->kind() == Code::COMPARE_IC) {
__ nop();
}
}
@ -1755,8 +1754,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
DCHECK(ToRegister(instr->right()).is(eax));
DCHECK(ToRegister(instr->result()).is(eax));
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
UNREACHABLE();
}

View File

@ -1812,11 +1812,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
DCHECK(ToRegister(instr->right()).is(a0));
DCHECK(ToRegister(instr->result()).is(v0));
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
// Other arch use a nop here, to signal that there is no inlined
// patchable code. Mips does not need the nop, since our marker
// instruction (andi zero_reg) will never be used in normal code.
UNREACHABLE();
}

View File

@ -1935,11 +1935,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
DCHECK(ToRegister(instr->right()).is(a0));
DCHECK(ToRegister(instr->result()).is(v0));
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
// Other arch use a nop here, to signal that there is no inlined
// patchable code. Mips does not need the nop, since our marker
// instruction (andi zero_reg) will never be used in normal code.
UNREACHABLE();
}

View File

@ -641,7 +641,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code, RelocInfo::Mode mode,
// Signal that we don't inline smi code before these stubs in the
// optimizing code generator.
if (code->kind() == Code::BINARY_OP_IC || code->kind() == Code::COMPARE_IC) {
if (code->kind() == Code::COMPARE_IC) {
__ nop();
}
}
@ -2024,8 +2024,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
DCHECK(ToRegister(instr->right()).is(r3));
DCHECK(ToRegister(instr->result()).is(r3));
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
UNREACHABLE();
}

View File

@ -610,7 +610,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code, RelocInfo::Mode mode,
// Signal that we don't inline smi code before these stubs in the
// optimizing code generator.
if (code->kind() == Code::BINARY_OP_IC || code->kind() == Code::COMPARE_IC) {
if (code->kind() == Code::COMPARE_IC) {
__ nop();
}
}
@ -2034,8 +2034,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
DCHECK(ToRegister(instr->right()).is(r2));
DCHECK(ToRegister(instr->result()).is(r2));
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
UNREACHABLE();
}
template <class InstrType>

View File

@ -599,8 +599,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
// Signal that we don't inline smi code before these stubs in the
// optimizing code generator.
if (code->kind() == Code::BINARY_OP_IC ||
code->kind() == Code::COMPARE_IC) {
if (code->kind() == Code::COMPARE_IC) {
__ nop();
}
}
@ -1891,8 +1890,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
DCHECK(ToRegister(instr->right()).is(rax));
DCHECK(ToRegister(instr->result()).is(rax));
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
UNREACHABLE();
}

View File

@ -840,8 +840,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
// Signal that we don't inline smi code before these stubs in the
// optimizing code generator.
if (code->kind() == Code::BINARY_OP_IC ||
code->kind() == Code::COMPARE_IC) {
if (code->kind() == Code::COMPARE_IC) {
__ nop();
}
}
@ -2023,8 +2022,7 @@ void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
DCHECK(ToRegister(instr->right()).is(eax));
DCHECK(ToRegister(instr->result()).is(eax));
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), instr->op()).code();
CallCode(code, RelocInfo::CODE_TARGET, instr);
UNREACHABLE();
}

View File

@ -118,7 +118,7 @@ static void PrintRelocInfo(StringBuilder* out, Isolate* isolate,
Code::Kind kind = code->kind();
if (code->is_inline_cache_stub()) {
out->AddFormatted(" %s", Code::Kind2String(kind));
if (kind == Code::BINARY_OP_IC || kind == Code::COMPARE_IC) {
if (kind == Code::COMPARE_IC) {
InlineCacheState ic_state = IC::StateFromCode(code);
out->AddFormatted(" %s", Code::ICState2String(ic_state));
}

View File

@ -725,7 +725,7 @@ class CompareICNexus final : public FeedbackNexus {
CompareOperationHint GetCompareOperationFeedback() const;
int ExtractMaps(MapHandles* maps) const final {
// BinaryOpICs don't record map feedback.
// CompareICs don't record map feedback.
return 0;
}
MaybeHandle<Object> FindHandlerForMap(Handle<Map> map) const final {

View File

@ -1399,14 +1399,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
VisitForAccumulatorValue(expr->value());
AccumulatorValueContext context(this);
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr->binary_operation(),
op,
expr->target(),
expr->value());
} else {
EmitBinaryOp(expr->binary_operation(), op);
}
EmitBinaryOp(expr->binary_operation(), op);
} else {
VisitForAccumulatorValue(expr->value());
}
@ -1460,104 +1453,11 @@ void FullCodeGenerator::EmitOperandStackDepthCheck() {
}
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op,
Expression* left_expr,
Expression* right_expr) {
Label done, smi_case, stub_call;
Register scratch1 = r2;
Register scratch2 = r3;
// Get the arguments.
Register left = r1;
Register right = r0;
PopOperand(left);
// Perform combined smi check on both operands.
__ orr(scratch1, left, Operand(right));
STATIC_ASSERT(kSmiTag == 0);
JumpPatchSite patch_site(masm_);
patch_site.EmitJumpIfSmi(scratch1, &smi_case);
__ bind(&stub_call);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ jmp(&done);
__ bind(&smi_case);
// Smi case. This code works the same way as the smi-smi case in the type
// recording binary operation stub, see
switch (op) {
case Token::SAR:
__ GetLeastBitsFromSmi(scratch1, right, 5);
__ mov(right, Operand(left, ASR, scratch1));
__ bic(right, right, Operand(kSmiTagMask));
break;
case Token::SHL: {
__ SmiUntag(scratch1, left);
__ GetLeastBitsFromSmi(scratch2, right, 5);
__ mov(scratch1, Operand(scratch1, LSL, scratch2));
__ TrySmiTag(right, scratch1, &stub_call);
break;
}
case Token::SHR: {
__ SmiUntag(scratch1, left);
__ GetLeastBitsFromSmi(scratch2, right, 5);
__ mov(scratch1, Operand(scratch1, LSR, scratch2));
__ tst(scratch1, Operand(0xc0000000));
__ b(ne, &stub_call);
__ SmiTag(right, scratch1);
break;
}
case Token::ADD:
__ add(scratch1, left, Operand(right), SetCC);
__ b(vs, &stub_call);
__ mov(right, scratch1);
break;
case Token::SUB:
__ sub(scratch1, left, Operand(right), SetCC);
__ b(vs, &stub_call);
__ mov(right, scratch1);
break;
case Token::MUL: {
__ SmiUntag(ip, right);
__ smull(scratch1, scratch2, left, ip);
__ mov(ip, Operand(scratch1, ASR, 31));
__ cmp(ip, Operand(scratch2));
__ b(ne, &stub_call);
__ cmp(scratch1, Operand::Zero());
__ mov(right, Operand(scratch1), LeaveCC, ne);
__ b(ne, &done);
__ add(scratch2, right, Operand(left), SetCC);
__ mov(right, Operand(Smi::kZero), LeaveCC, pl);
__ b(mi, &stub_call);
break;
}
case Token::BIT_OR:
__ orr(right, left, Operand(right));
break;
case Token::BIT_AND:
__ and_(right, left, Operand(right));
break;
case Token::BIT_XOR:
__ eor(right, left, Operand(right));
break;
default:
UNREACHABLE();
}
__ bind(&done);
context()->Plug(r0);
}
void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
PopOperand(r1);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
CallIC(code);
patch_site.EmitPatchInfo();
Handle<Code> code = CodeFactory::BinaryOperation(isolate(), op).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
context()->Plug(r0);
}
@ -2225,47 +2125,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
// Inline smi case if we are in a loop.
Label stub_call, done;
JumpPatchSite patch_site(masm_);
int count_value = expr->op() == Token::INC ? 1 : -1;
if (ShouldInlineSmiCase(expr->op())) {
Label slow;
patch_site.EmitJumpIfNotSmi(r0, &slow);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(r0);
break;
case NAMED_PROPERTY:
__ str(r0, MemOperand(sp, kPointerSize));
break;
case KEYED_PROPERTY:
__ str(r0, MemOperand(sp, 2 * kPointerSize));
break;
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNREACHABLE();
break;
}
}
}
__ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
__ b(vc, &done);
// Call stub. Undo operation first.
__ sub(r0, r0, Operand(Smi::FromInt(count_value)));
__ jmp(&stub_call);
__ bind(&slow);
}
// Convert old value into a number.
__ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
RestoreContext();
@ -2294,17 +2153,16 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
__ bind(&stub_call);
int count_value = expr->op() == Token::INC ? 1 : -1;
__ mov(r1, r0);
__ mov(r0, Operand(Smi::FromInt(count_value)));
SetExpressionPosition(expr);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ bind(&done);
Handle<Code> code =
CodeFactory::BinaryOperation(isolate(), Token::ADD).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
// Store the value returned in r0.
switch (assign_type) {

View File

@ -1379,14 +1379,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
VisitForAccumulatorValue(expr->value());
AccumulatorValueContext context(this);
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr->binary_operation(),
op,
expr->target(),
expr->value());
} else {
EmitBinaryOp(expr->binary_operation(), op);
}
EmitBinaryOp(expr->binary_operation(), op);
} else {
VisitForAccumulatorValue(expr->value());
}
@ -1416,115 +1409,11 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op,
Expression* left_expr,
Expression* right_expr) {
Label done, both_smis, stub_call;
// Get the arguments.
Register left = x1;
Register right = x0;
Register result = x0;
PopOperand(left);
// Perform combined smi check on both operands.
{
Assembler::BlockPoolsScope scope(masm_);
__ Orr(x10, left, right);
JumpPatchSite patch_site(masm_);
patch_site.EmitJumpIfSmi(x10, &both_smis);
__ Bind(&stub_call);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ B(&done);
__ Bind(&both_smis);
}
// Smi case. This code works in the same way as the smi-smi case in the type
// recording binary operation stub, see
// BinaryOpStub::GenerateSmiSmiOperation for comments.
// TODO(all): That doesn't exist any more. Where are the comments?
//
// The set of operations that needs to be supported here is controlled by
// FullCodeGenerator::ShouldInlineSmiCase().
switch (op) {
case Token::SAR:
__ Ubfx(right, right, kSmiShift, 5);
__ Asr(result, left, right);
__ Bic(result, result, kSmiShiftMask);
break;
case Token::SHL:
__ Ubfx(right, right, kSmiShift, 5);
__ Lsl(result, left, right);
break;
case Token::SHR:
// If `left >>> right` >= 0x80000000, the result is not representable in a
// signed 32-bit smi.
__ Ubfx(right, right, kSmiShift, 5);
__ Lsr(x10, left, right);
__ Tbnz(x10, kXSignBit, &stub_call);
__ Bic(result, x10, kSmiShiftMask);
break;
case Token::ADD:
__ Adds(x10, left, right);
__ B(vs, &stub_call);
__ Mov(result, x10);
break;
case Token::SUB:
__ Subs(x10, left, right);
__ B(vs, &stub_call);
__ Mov(result, x10);
break;
case Token::MUL: {
Label not_minus_zero, done;
STATIC_ASSERT(static_cast<unsigned>(kSmiShift) == (kXRegSizeInBits / 2));
STATIC_ASSERT(kSmiTag == 0);
__ Smulh(x10, left, right);
__ Cbnz(x10, &not_minus_zero);
__ Eor(x11, left, right);
__ Tbnz(x11, kXSignBit, &stub_call);
__ Mov(result, x10);
__ B(&done);
__ Bind(&not_minus_zero);
__ Cls(x11, x10);
__ Cmp(x11, kXRegSizeInBits - kSmiShift);
__ B(lt, &stub_call);
__ SmiTag(result, x10);
__ Bind(&done);
break;
}
case Token::BIT_OR:
__ Orr(result, left, right);
break;
case Token::BIT_AND:
__ And(result, left, right);
break;
case Token::BIT_XOR:
__ Eor(result, left, right);
break;
default:
UNREACHABLE();
}
__ Bind(&done);
context()->Plug(x0);
}
void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
PopOperand(x1);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
JumpPatchSite patch_site(masm_); // Unbound, signals no inlined smi code.
{
Assembler::BlockPoolsScope scope(masm_);
CallIC(code);
patch_site.EmitPatchInfo();
}
Handle<Code> code = CodeFactory::BinaryOperation(isolate(), op).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
context()->Plug(x0);
}
@ -2203,90 +2092,45 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
// Inline smi case if we are in a loop.
{
Assembler::BlockPoolsScope scope(masm_);
Label stub_call, done;
JumpPatchSite patch_site(masm_);
// Convert old value into a number.
__ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
RestoreContext();
int count_value = expr->op() == Token::INC ? 1 : -1;
if (ShouldInlineSmiCase(expr->op())) {
Label slow;
patch_site.EmitJumpIfNotSmi(x0, &slow);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top of
// the stack.
switch (assign_type) {
case VARIABLE:
__ Push(x0);
break;
case NAMED_PROPERTY:
__ Poke(x0, kPointerSize);
break;
case KEYED_PROPERTY:
__ Poke(x0, kPointerSize * 2);
break;
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNREACHABLE();
break;
}
}
}
__ Adds(x0, x0, Smi::FromInt(count_value));
__ B(vc, &done);
// Call stub. Undo operation first.
__ Sub(x0, x0, Smi::FromInt(count_value));
__ B(&stub_call);
__ Bind(&slow);
}
// Convert old value into a number.
__ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
RestoreContext();
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
PushOperand(x0);
break;
case NAMED_PROPERTY:
__ Poke(x0, kXRegSize);
break;
case KEYED_PROPERTY:
__ Poke(x0, 2 * kXRegSize);
break;
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNREACHABLE();
break;
}
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
PushOperand(x0);
break;
case NAMED_PROPERTY:
__ Poke(x0, kXRegSize);
break;
case KEYED_PROPERTY:
__ Poke(x0, 2 * kXRegSize);
break;
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNREACHABLE();
break;
}
}
__ Bind(&stub_call);
__ Mov(x1, x0);
__ Mov(x0, Smi::FromInt(count_value));
SetExpressionPosition(expr);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ Bind(&done);
}
int count_value = expr->op() == Token::INC ? 1 : -1;
__ Mov(x1, x0);
__ Mov(x0, Smi::FromInt(count_value));
SetExpressionPosition(expr);
Handle<Code> code =
CodeFactory::BinaryOperation(isolate(), Token::ADD).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
// Store the value returned in x0.
switch (assign_type) {
case VARIABLE: {

View File

@ -781,11 +781,7 @@ void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
VisitForAccumulatorValue(right);
SetExpressionPosition(expr);
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr, op, left, right);
} else {
EmitBinaryOp(expr, op);
}
EmitBinaryOp(expr, op);
}
void FullCodeGenerator::VisitProperty(Property* expr) {

View File

@ -429,13 +429,6 @@ class FullCodeGenerator final : public AstVisitor<FullCodeGenerator> {
// of the stack and the right one in the accumulator.
void EmitBinaryOp(BinaryOperation* expr, Token::Value op);
// Helper functions for generating inlined smi code for certain
// binary operations.
void EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op,
Expression* left,
Expression* right);
// Assign to the given expression as if via '='. The right-hand-side value
// is expected in the accumulator. slot is only used if FLAG_vector_stores
// is true.

View File

@ -1320,14 +1320,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
PushOperand(eax); // Left operand goes on the stack.
VisitForAccumulatorValue(expr->value());
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr->binary_operation(),
op,
expr->target(),
expr->value());
} else {
EmitBinaryOp(expr->binary_operation(), op);
}
EmitBinaryOp(expr->binary_operation(), op);
} else {
VisitForAccumulatorValue(expr->value());
}
@ -1377,105 +1370,11 @@ void FullCodeGenerator::EmitOperandStackDepthCheck() {
}
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op,
Expression* left,
Expression* right) {
// Do combined smi check of the operands. Left operand is on the
// stack. Right operand is in eax.
Label smi_case, done, stub_call;
PopOperand(edx);
__ mov(ecx, eax);
__ or_(eax, edx);
JumpPatchSite patch_site(masm_);
patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
__ bind(&stub_call);
__ mov(eax, ecx);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ jmp(&done, Label::kNear);
// Smi case.
__ bind(&smi_case);
__ mov(eax, edx); // Copy left operand in case of a stub call.
switch (op) {
case Token::SAR:
__ SmiUntag(ecx);
__ sar_cl(eax); // No checks of result necessary
__ and_(eax, Immediate(~kSmiTagMask));
break;
case Token::SHL: {
Label result_ok;
__ SmiUntag(eax);
__ SmiUntag(ecx);
__ shl_cl(eax);
// Check that the *signed* result fits in a smi.
__ cmp(eax, 0xc0000000);
__ j(positive, &result_ok);
__ SmiTag(ecx);
__ jmp(&stub_call);
__ bind(&result_ok);
__ SmiTag(eax);
break;
}
case Token::SHR: {
Label result_ok;
__ SmiUntag(eax);
__ SmiUntag(ecx);
__ shr_cl(eax);
__ test(eax, Immediate(0xc0000000));
__ j(zero, &result_ok);
__ SmiTag(ecx);
__ jmp(&stub_call);
__ bind(&result_ok);
__ SmiTag(eax);
break;
}
case Token::ADD:
__ add(eax, ecx);
__ j(overflow, &stub_call);
break;
case Token::SUB:
__ sub(eax, ecx);
__ j(overflow, &stub_call);
break;
case Token::MUL: {
__ SmiUntag(eax);
__ imul(eax, ecx);
__ j(overflow, &stub_call);
__ test(eax, eax);
__ j(not_zero, &done, Label::kNear);
__ mov(ebx, edx);
__ or_(ebx, ecx);
__ j(negative, &stub_call);
break;
}
case Token::BIT_OR:
__ or_(eax, ecx);
break;
case Token::BIT_AND:
__ and_(eax, ecx);
break;
case Token::BIT_XOR:
__ xor_(eax, ecx);
break;
default:
UNREACHABLE();
}
__ bind(&done);
context()->Plug(eax);
}
void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
PopOperand(edx);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
CallIC(code);
patch_site.EmitPatchInfo();
Handle<Code> code = CodeFactory::BinaryOperation(isolate(), op).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
context()->Plug(eax);
}
@ -2145,53 +2044,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
// Inline smi case if we are in a loop.
Label done, stub_call;
JumpPatchSite patch_site(masm_);
if (ShouldInlineSmiCase(expr->op())) {
Label slow;
patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(eax);
break;
case NAMED_PROPERTY:
__ mov(Operand(esp, kPointerSize), eax);
break;
case KEYED_PROPERTY:
__ mov(Operand(esp, 2 * kPointerSize), eax);
break;
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNREACHABLE();
break;
}
}
}
if (expr->op() == Token::INC) {
__ add(eax, Immediate(Smi::FromInt(1)));
} else {
__ sub(eax, Immediate(Smi::FromInt(1)));
}
__ j(no_overflow, &done, Label::kNear);
// Call stub. Undo operation first.
if (expr->op() == Token::INC) {
__ sub(eax, Immediate(Smi::FromInt(1)));
} else {
__ add(eax, Immediate(Smi::FromInt(1)));
}
__ jmp(&stub_call, Label::kNear);
__ bind(&slow);
}
// Convert old value into a number.
__ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
RestoreContext();
@ -2223,14 +2075,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
SetExpressionPosition(expr);
// Call stub for +1/-1.
__ bind(&stub_call);
__ mov(edx, eax);
__ mov(eax, Immediate(Smi::FromInt(1)));
Handle<Code> code =
CodeFactory::BinaryOpIC(isolate(), expr->binary_op()).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ bind(&done);
CodeFactory::BinaryOperation(isolate(), expr->binary_op()).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
// Store the value returned in eax.
switch (assign_type) {

View File

@ -1394,14 +1394,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
VisitForAccumulatorValue(expr->value());
AccumulatorValueContext context(this);
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr->binary_operation(),
op,
expr->target(),
expr->value());
} else {
EmitBinaryOp(expr->binary_operation(), op);
}
EmitBinaryOp(expr->binary_operation(), op);
} else {
VisitForAccumulatorValue(expr->value());
}
@ -1466,102 +1459,12 @@ void FullCodeGenerator::EmitOperandStackDepthCheck() {
}
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op,
Expression* left_expr,
Expression* right_expr) {
Label done, smi_case, stub_call;
Register scratch1 = a2;
Register scratch2 = a3;
// Get the arguments.
Register left = a1;
Register right = a0;
PopOperand(left);
__ mov(a0, result_register());
// Perform combined smi check on both operands.
__ Or(scratch1, left, Operand(right));
STATIC_ASSERT(kSmiTag == 0);
JumpPatchSite patch_site(masm_);
patch_site.EmitJumpIfSmi(scratch1, &smi_case);
__ bind(&stub_call);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ jmp(&done);
__ bind(&smi_case);
// Smi case. This code works the same way as the smi-smi case in the type
// recording binary operation stub, see
switch (op) {
case Token::SAR:
__ GetLeastBitsFromSmi(scratch1, right, 5);
__ srav(right, left, scratch1);
__ And(v0, right, Operand(~kSmiTagMask));
break;
case Token::SHL: {
__ SmiUntag(scratch1, left);
__ GetLeastBitsFromSmi(scratch2, right, 5);
__ sllv(scratch1, scratch1, scratch2);
__ Addu(scratch2, scratch1, Operand(0x40000000));
__ Branch(&stub_call, lt, scratch2, Operand(zero_reg));
__ SmiTag(v0, scratch1);
break;
}
case Token::SHR: {
__ SmiUntag(scratch1, left);
__ GetLeastBitsFromSmi(scratch2, right, 5);
__ srlv(scratch1, scratch1, scratch2);
__ And(scratch2, scratch1, 0xc0000000);
__ Branch(&stub_call, ne, scratch2, Operand(zero_reg));
__ SmiTag(v0, scratch1);
break;
}
case Token::ADD:
__ AddBranchOvf(v0, left, Operand(right), &stub_call);
break;
case Token::SUB:
__ SubBranchOvf(v0, left, Operand(right), &stub_call);
break;
case Token::MUL: {
__ SmiUntag(scratch1, right);
__ Mul(scratch2, v0, left, scratch1);
__ sra(scratch1, v0, 31);
__ Branch(&stub_call, ne, scratch1, Operand(scratch2));
__ Branch(&done, ne, v0, Operand(zero_reg));
__ Addu(scratch2, right, left);
__ Branch(&stub_call, lt, scratch2, Operand(zero_reg));
DCHECK(Smi::kZero == 0);
__ mov(v0, zero_reg);
break;
}
case Token::BIT_OR:
__ Or(v0, left, Operand(right));
break;
case Token::BIT_AND:
__ And(v0, left, Operand(right));
break;
case Token::BIT_XOR:
__ Xor(v0, left, Operand(right));
break;
default:
UNREACHABLE();
}
__ bind(&done);
context()->Plug(v0);
}
void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
__ mov(a0, result_register());
PopOperand(a1);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
CallIC(code);
patch_site.EmitPatchInfo();
Handle<Code> code = CodeFactory::BinaryOperation(isolate(), op).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
context()->Plug(v0);
}
@ -2240,48 +2143,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
// Inline smi case if we are in a loop.
Label stub_call, done;
JumpPatchSite patch_site(masm_);
int count_value = expr->op() == Token::INC ? 1 : -1;
__ mov(a0, v0);
if (ShouldInlineSmiCase(expr->op())) {
Label slow;
patch_site.EmitJumpIfNotSmi(v0, &slow);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(v0);
break;
case NAMED_PROPERTY:
__ sw(v0, MemOperand(sp, kPointerSize));
break;
case KEYED_PROPERTY:
__ sw(v0, MemOperand(sp, 2 * kPointerSize));
break;
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNREACHABLE();
break;
}
}
}
Register scratch1 = a1;
__ li(scratch1, Operand(Smi::FromInt(count_value)));
__ AddBranchNoOvf(v0, v0, Operand(scratch1), &done);
// Call stub. Undo operation first.
__ Move(v0, a0);
__ jmp(&stub_call);
__ bind(&slow);
}
// Convert old value into a number.
__ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
@ -2311,16 +2173,16 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
__ bind(&stub_call);
int count_value = expr->op() == Token::INC ? 1 : -1;
__ mov(a1, v0);
__ li(a0, Operand(Smi::FromInt(count_value)));
SetExpressionPosition(expr);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ bind(&done);
Handle<Code> code =
CodeFactory::BinaryOperation(isolate(), Token::ADD).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
// Store the value returned in v0.
switch (assign_type) {

View File

@ -1396,14 +1396,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
VisitForAccumulatorValue(expr->value());
AccumulatorValueContext context(this);
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr->binary_operation(),
op,
expr->target(),
expr->value());
} else {
EmitBinaryOp(expr->binary_operation(), op);
}
EmitBinaryOp(expr->binary_operation(), op);
} else {
VisitForAccumulatorValue(expr->value());
}
@ -1468,101 +1461,12 @@ void FullCodeGenerator::EmitOperandStackDepthCheck() {
}
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op,
Expression* left_expr,
Expression* right_expr) {
Label done, smi_case, stub_call;
Register scratch1 = a2;
Register scratch2 = a3;
// Get the arguments.
Register left = a1;
Register right = a0;
PopOperand(left);
__ mov(a0, result_register());
// Perform combined smi check on both operands.
__ Or(scratch1, left, Operand(right));
STATIC_ASSERT(kSmiTag == 0);
JumpPatchSite patch_site(masm_);
patch_site.EmitJumpIfSmi(scratch1, &smi_case);
__ bind(&stub_call);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ jmp(&done);
__ bind(&smi_case);
// Smi case. This code works the same way as the smi-smi case in the type
// recording binary operation stub, see
switch (op) {
case Token::SAR:
__ GetLeastBitsFromSmi(scratch1, right, 5);
__ dsrav(right, left, scratch1);
__ And(v0, right, Operand(0xffffffff00000000L));
break;
case Token::SHL: {
__ SmiUntag(scratch1, left);
__ GetLeastBitsFromSmi(scratch2, right, 5);
__ dsllv(scratch1, scratch1, scratch2);
__ SmiTag(v0, scratch1);
break;
}
case Token::SHR: {
__ SmiUntag(scratch1, left);
__ GetLeastBitsFromSmi(scratch2, right, 5);
__ dsrlv(scratch1, scratch1, scratch2);
__ And(scratch2, scratch1, 0x80000000);
__ Branch(&stub_call, ne, scratch2, Operand(zero_reg));
__ SmiTag(v0, scratch1);
break;
}
case Token::ADD:
__ DaddBranchOvf(v0, left, Operand(right), &stub_call);
break;
case Token::SUB:
__ DsubBranchOvf(v0, left, Operand(right), &stub_call);
break;
case Token::MUL: {
__ Dmulh(v0, left, right);
__ dsra32(scratch2, v0, 0);
__ sra(scratch1, v0, 31);
__ Branch(USE_DELAY_SLOT, &stub_call, ne, scratch2, Operand(scratch1));
__ SmiTag(v0);
__ Branch(USE_DELAY_SLOT, &done, ne, v0, Operand(zero_reg));
__ Daddu(scratch2, right, left);
__ Branch(&stub_call, lt, scratch2, Operand(zero_reg));
DCHECK(Smi::kZero == 0);
__ mov(v0, zero_reg);
break;
}
case Token::BIT_OR:
__ Or(v0, left, Operand(right));
break;
case Token::BIT_AND:
__ And(v0, left, Operand(right));
break;
case Token::BIT_XOR:
__ Xor(v0, left, Operand(right));
break;
default:
UNREACHABLE();
}
__ bind(&done);
context()->Plug(v0);
}
void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
__ mov(a0, result_register());
PopOperand(a1);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
CallIC(code);
patch_site.EmitPatchInfo();
Handle<Code> code = CodeFactory::BinaryOperation(isolate(), op).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
context()->Plug(v0);
}
@ -2241,48 +2145,7 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
// Inline smi case if we are in a loop.
Label stub_call, done;
JumpPatchSite patch_site(masm_);
int count_value = expr->op() == Token::INC ? 1 : -1;
__ mov(a0, v0);
if (ShouldInlineSmiCase(expr->op())) {
Label slow;
patch_site.EmitJumpIfNotSmi(v0, &slow);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(v0);
break;
case NAMED_PROPERTY:
__ Sd(v0, MemOperand(sp, kPointerSize));
break;
case KEYED_PROPERTY:
__ Sd(v0, MemOperand(sp, 2 * kPointerSize));
break;
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNREACHABLE();
break;
}
}
}
Register scratch1 = a1;
__ li(scratch1, Operand(Smi::FromInt(count_value)));
__ DaddBranchNoOvf(v0, v0, Operand(scratch1), &done);
// Call stub. Undo operation first.
__ Move(v0, a0);
__ jmp(&stub_call);
__ bind(&slow);
}
// Convert old value into a number.
__ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
@ -2312,16 +2175,16 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
__ bind(&stub_call);
int count_value = expr->op() == Token::INC ? 1 : -1;
__ mov(a1, v0);
__ li(a0, Operand(Smi::FromInt(count_value)));
SetExpressionPosition(expr);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ bind(&done);
Handle<Code> code =
CodeFactory::BinaryOperation(isolate(), Token::ADD).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
// Store the value returned in v0.
switch (assign_type) {

View File

@ -1365,12 +1365,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
VisitForAccumulatorValue(expr->value());
AccumulatorValueContext context(this);
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr->binary_operation(), op, expr->target(),
expr->value());
} else {
EmitBinaryOp(expr->binary_operation(), op);
}
EmitBinaryOp(expr->binary_operation(), op);
} else {
VisitForAccumulatorValue(expr->value());
}
@ -1437,136 +1432,11 @@ void FullCodeGenerator::EmitOperandStackDepthCheck() {
}
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op,
Expression* left_expr,
Expression* right_expr) {
Label done, smi_case, stub_call;
Register scratch1 = r5;
Register scratch2 = r6;
// Get the arguments.
Register left = r4;
Register right = r3;
PopOperand(left);
// Perform combined smi check on both operands.
__ orx(scratch1, left, right);
STATIC_ASSERT(kSmiTag == 0);
JumpPatchSite patch_site(masm_);
patch_site.EmitJumpIfSmi(scratch1, &smi_case);
__ bind(&stub_call);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ b(&done);
__ bind(&smi_case);
// Smi case. This code works the same way as the smi-smi case in the type
// recording binary operation stub.
switch (op) {
case Token::SAR:
__ GetLeastBitsFromSmi(scratch1, right, 5);
__ ShiftRightArith(right, left, scratch1);
__ ClearRightImm(right, right, Operand(kSmiTagSize + kSmiShiftSize));
break;
case Token::SHL: {
__ GetLeastBitsFromSmi(scratch2, right, 5);
#if V8_TARGET_ARCH_PPC64
__ ShiftLeft_(right, left, scratch2);
#else
__ SmiUntag(scratch1, left);
__ ShiftLeft_(scratch1, scratch1, scratch2);
// Check that the *signed* result fits in a smi
__ JumpIfNotSmiCandidate(scratch1, scratch2, &stub_call);
__ SmiTag(right, scratch1);
#endif
break;
}
case Token::SHR: {
__ SmiUntag(scratch1, left);
__ GetLeastBitsFromSmi(scratch2, right, 5);
__ srw(scratch1, scratch1, scratch2);
// Unsigned shift is not allowed to produce a negative number.
__ JumpIfNotUnsignedSmiCandidate(scratch1, r0, &stub_call);
__ SmiTag(right, scratch1);
break;
}
case Token::ADD: {
__ AddAndCheckForOverflow(scratch1, left, right, scratch2, r0);
__ BranchOnOverflow(&stub_call);
__ mr(right, scratch1);
break;
}
case Token::SUB: {
__ SubAndCheckForOverflow(scratch1, left, right, scratch2, r0);
__ BranchOnOverflow(&stub_call);
__ mr(right, scratch1);
break;
}
case Token::MUL: {
Label mul_zero;
#if V8_TARGET_ARCH_PPC64
// Remove tag from both operands.
__ SmiUntag(ip, right);
__ SmiUntag(r0, left);
__ Mul(scratch1, r0, ip);
// Check for overflowing the smi range - no overflow if higher 33 bits of
// the result are identical.
__ TestIfInt32(scratch1, r0);
__ bne(&stub_call);
#else
__ SmiUntag(ip, right);
__ mullw(scratch1, left, ip);
__ mulhw(scratch2, left, ip);
// Check for overflowing the smi range - no overflow if higher 33 bits of
// the result are identical.
__ TestIfInt32(scratch2, scratch1, ip);
__ bne(&stub_call);
#endif
// Go slow on zero result to handle -0.
__ cmpi(scratch1, Operand::Zero());
__ beq(&mul_zero);
#if V8_TARGET_ARCH_PPC64
__ SmiTag(right, scratch1);
#else
__ mr(right, scratch1);
#endif
__ b(&done);
// We need -0 if we were multiplying a negative number with 0 to get 0.
// We know one of them was zero.
__ bind(&mul_zero);
__ add(scratch2, right, left);
__ cmpi(scratch2, Operand::Zero());
__ blt(&stub_call);
__ LoadSmiLiteral(right, Smi::kZero);
break;
}
case Token::BIT_OR:
__ orx(right, left, right);
break;
case Token::BIT_AND:
__ and_(right, left, right);
break;
case Token::BIT_XOR:
__ xor_(right, left, right);
break;
default:
UNREACHABLE();
}
__ bind(&done);
context()->Plug(r3);
}
void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
PopOperand(r4);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
CallIC(code);
patch_site.EmitPatchInfo();
Handle<Code> code = CodeFactory::BinaryOperation(isolate(), op).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
context()->Plug(r3);
}
@ -2231,50 +2101,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
// Inline smi case if we are in a loop.
Label stub_call, done;
JumpPatchSite patch_site(masm_);
int count_value = expr->op() == Token::INC ? 1 : -1;
if (ShouldInlineSmiCase(expr->op())) {
Label slow;
patch_site.EmitJumpIfNotSmi(r3, &slow);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(r3);
break;
case NAMED_PROPERTY:
__ StoreP(r3, MemOperand(sp, kPointerSize));
break;
case KEYED_PROPERTY:
__ StoreP(r3, MemOperand(sp, 2 * kPointerSize));
break;
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNREACHABLE();
break;
}
}
}
Register scratch1 = r4;
Register scratch2 = r5;
__ LoadSmiLiteral(scratch1, Smi::FromInt(count_value));
__ AddAndCheckForOverflow(r3, r3, scratch1, scratch2, r0);
__ BranchOnNoOverflow(&done);
// Call stub. Undo operation first.
__ sub(r3, r3, scratch1);
__ b(&stub_call);
__ bind(&slow);
}
// Convert old value into a number.
__ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
RestoreContext();
@ -2303,16 +2129,16 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
__ bind(&stub_call);
int count_value = expr->op() == Token::INC ? 1 : -1;
__ mr(r4, r3);
__ LoadSmiLiteral(r3, Smi::FromInt(count_value));
SetExpressionPosition(expr);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ bind(&done);
Handle<Code> code =
CodeFactory::BinaryOperation(isolate(), Token::ADD).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
// Store the value returned in r3.
switch (assign_type) {

View File

@ -1330,12 +1330,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
VisitForAccumulatorValue(expr->value());
AccumulatorValueContext context(this);
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr->binary_operation(), op, expr->target(),
expr->value());
} else {
EmitBinaryOp(expr->binary_operation(), op);
}
EmitBinaryOp(expr->binary_operation(), op);
} else {
VisitForAccumulatorValue(expr->value());
}
@ -1401,149 +1396,11 @@ void FullCodeGenerator::EmitOperandStackDepthCheck() {
}
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op,
Expression* left_expr,
Expression* right_expr) {
Label done, smi_case, stub_call;
Register scratch1 = r4;
Register scratch2 = r5;
// Get the arguments.
Register left = r3;
Register right = r2;
PopOperand(left);
// Perform combined smi check on both operands.
__ LoadRR(scratch1, right);
__ OrP(scratch1, left);
STATIC_ASSERT(kSmiTag == 0);
JumpPatchSite patch_site(masm_);
patch_site.EmitJumpIfSmi(scratch1, &smi_case);
__ bind(&stub_call);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ b(&done);
__ bind(&smi_case);
// Smi case. This code works the same way as the smi-smi case in the type
// recording binary operation stub.
switch (op) {
case Token::SAR:
__ GetLeastBitsFromSmi(scratch1, right, 5);
__ ShiftRightArithP(right, left, scratch1);
__ ClearRightImm(right, right, Operand(kSmiTagSize + kSmiShiftSize));
break;
case Token::SHL: {
__ GetLeastBitsFromSmi(scratch2, right, 5);
#if V8_TARGET_ARCH_S390X
__ ShiftLeftP(right, left, scratch2);
#else
__ SmiUntag(scratch1, left);
__ ShiftLeftP(scratch1, scratch1, scratch2);
// Check that the *signed* result fits in a smi
__ JumpIfNotSmiCandidate(scratch1, scratch2, &stub_call);
__ SmiTag(right, scratch1);
#endif
break;
}
case Token::SHR: {
__ SmiUntag(scratch1, left);
__ GetLeastBitsFromSmi(scratch2, right, 5);
__ srl(scratch1, scratch2);
// Unsigned shift is not allowed to produce a negative number.
__ JumpIfNotUnsignedSmiCandidate(scratch1, r0, &stub_call);
__ SmiTag(right, scratch1);
break;
}
case Token::ADD: {
__ AddP(scratch1, left, right);
__ b(overflow, &stub_call);
__ LoadRR(right, scratch1);
break;
}
case Token::SUB: {
__ SubP(scratch1, left, right);
__ b(overflow, &stub_call);
__ LoadRR(right, scratch1);
break;
}
case Token::MUL: {
Label mul_zero;
if (CpuFeatures::IsSupported(MISC_INSTR_EXT2)) {
__ SmiUntag(ip, right);
__ MulPWithCondition(scratch2, ip, left);
__ b(overflow, &stub_call);
__ beq(&mul_zero, Label::kNear);
__ LoadRR(right, scratch2);
} else {
#if V8_TARGET_ARCH_S390X
// Remove tag from both operands.
__ SmiUntag(ip, right);
__ SmiUntag(scratch2, left);
__ mr_z(scratch1, ip);
// Check for overflowing the smi range - no overflow if higher 33 bits
// of the result are identical.
__ lr(ip, scratch2); // 32 bit load
__ sra(ip, Operand(31));
__ cr_z(ip, scratch1); // 32 bit compare
__ bne(&stub_call);
#else
__ SmiUntag(ip, right);
__ LoadRR(scratch2, left); // load into low order of reg pair
__ mr_z(scratch1, ip); // R4:R5 = R5 * ip
// Check for overflowing the smi range - no overflow if higher 33 bits
// of the result are identical.
__ lr(ip, scratch2); // 32 bit load
__ sra(ip, Operand(31));
__ cr_z(ip, scratch1); // 32 bit compare
__ bne(&stub_call);
#endif
// Go slow on zero result to handle -0.
__ chi(scratch2, Operand::Zero());
__ beq(&mul_zero, Label::kNear);
#if V8_TARGET_ARCH_S390X
__ SmiTag(right, scratch2);
#else
__ LoadRR(right, scratch2);
#endif
}
__ b(&done);
// We need -0 if we were multiplying a negative number with 0 to get 0.
// We know one of them was zero.
__ bind(&mul_zero);
__ AddP(scratch2, right, left);
__ CmpP(scratch2, Operand::Zero());
__ blt(&stub_call);
__ LoadSmiLiteral(right, Smi::kZero);
break;
}
case Token::BIT_OR:
__ OrP(right, left);
break;
case Token::BIT_AND:
__ AndP(right, left);
break;
case Token::BIT_XOR:
__ XorP(right, left);
break;
default:
UNREACHABLE();
}
__ bind(&done);
context()->Plug(r2);
}
void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
PopOperand(r3);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
CallIC(code);
patch_site.EmitPatchInfo();
Handle<Code> code = CodeFactory::BinaryOperation(isolate(), op).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
context()->Plug(r2);
}
@ -2193,50 +2050,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
// Inline smi case if we are in a loop.
Label stub_call, done;
JumpPatchSite patch_site(masm_);
int count_value = expr->op() == Token::INC ? 1 : -1;
if (ShouldInlineSmiCase(expr->op())) {
Label slow;
patch_site.EmitJumpIfNotSmi(r2, &slow);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(r2);
break;
case NAMED_PROPERTY:
__ StoreP(r2, MemOperand(sp, kPointerSize));
break;
case KEYED_PROPERTY:
__ StoreP(r2, MemOperand(sp, 2 * kPointerSize));
break;
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNREACHABLE();
break;
}
}
}
Register scratch1 = r3;
Register scratch2 = r4;
__ LoadSmiLiteral(scratch1, Smi::FromInt(count_value));
__ AddP(scratch2, r2, scratch1);
__ LoadOnConditionP(nooverflow, r2, scratch2);
__ b(nooverflow, &done);
// Call stub. Undo operation first.
__ b(&stub_call);
__ bind(&slow);
}
// Convert old value into a number.
__ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
RestoreContext();
@ -2265,16 +2078,16 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
__ bind(&stub_call);
int count_value = expr->op() == Token::INC ? 1 : -1;
__ LoadRR(r3, r2);
__ LoadSmiLiteral(r2, Smi::FromInt(count_value));
SetExpressionPosition(expr);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ bind(&done);
Handle<Code> code =
CodeFactory::BinaryOperation(isolate(), Token::ADD).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
// Store the value returned in r2.
switch (assign_type) {

View File

@ -1344,14 +1344,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
VisitForAccumulatorValue(expr->value());
AccumulatorValueContext context(this);
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr->binary_operation(),
op,
expr->target(),
expr->value());
} else {
EmitBinaryOp(expr->binary_operation(), op);
}
EmitBinaryOp(expr->binary_operation(), op);
} else {
VisitForAccumulatorValue(expr->value());
}
@ -1401,72 +1394,12 @@ void FullCodeGenerator::EmitOperandStackDepthCheck() {
}
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op,
Expression* left,
Expression* right) {
// Do combined smi check of the operands. Left operand is on the
// stack (popped into rdx). Right operand is in rax but moved into
// rcx to make the shifts easier.
Label done, stub_call, smi_case;
PopOperand(rdx);
__ movp(rcx, rax);
__ orp(rax, rdx);
JumpPatchSite patch_site(masm_);
patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear);
__ bind(&stub_call);
__ movp(rax, rcx);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ jmp(&done, Label::kNear);
__ bind(&smi_case);
switch (op) {
case Token::SAR:
__ SmiShiftArithmeticRight(rax, rdx, rcx);
break;
case Token::SHL:
__ SmiShiftLeft(rax, rdx, rcx, &stub_call);
break;
case Token::SHR:
__ SmiShiftLogicalRight(rax, rdx, rcx, &stub_call);
break;
case Token::ADD:
__ SmiAdd(rax, rdx, rcx, &stub_call);
break;
case Token::SUB:
__ SmiSub(rax, rdx, rcx, &stub_call);
break;
case Token::MUL:
__ SmiMul(rax, rdx, rcx, &stub_call);
break;
case Token::BIT_OR:
__ SmiOr(rax, rdx, rcx);
break;
case Token::BIT_AND:
__ SmiAnd(rax, rdx, rcx);
break;
case Token::BIT_XOR:
__ SmiXor(rax, rdx, rcx);
break;
default:
UNREACHABLE();
break;
}
__ bind(&done);
context()->Plug(rax);
}
void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
PopOperand(rdx);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
CallIC(code);
patch_site.EmitPatchInfo();
Handle<Code> code = CodeFactory::BinaryOperation(isolate(), op).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
context()->Plug(rax);
}
@ -2133,51 +2066,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
// Inline smi case if we are in a loop.
Label done, stub_call;
JumpPatchSite patch_site(masm_);
if (ShouldInlineSmiCase(expr->op())) {
Label slow;
patch_site.EmitJumpIfNotSmi(rax, &slow, Label::kNear);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ Push(rax);
break;
case NAMED_PROPERTY:
__ movp(Operand(rsp, kPointerSize), rax);
break;
case KEYED_PROPERTY:
__ movp(Operand(rsp, 2 * kPointerSize), rax);
break;
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNREACHABLE();
break;
}
}
}
SmiOperationConstraints constraints =
SmiOperationConstraint::kPreserveSourceRegister |
SmiOperationConstraint::kBailoutOnNoOverflow;
if (expr->op() == Token::INC) {
__ SmiAddConstant(rax, rax, Smi::FromInt(1), constraints, &done,
Label::kNear);
} else {
__ SmiSubConstant(rax, rax, Smi::FromInt(1), constraints, &done,
Label::kNear);
}
__ jmp(&stub_call, Label::kNear);
__ bind(&slow);
}
// Convert old value into a number.
__ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
RestoreContext();
@ -2209,14 +2097,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
SetExpressionPosition(expr);
// Call stub for +1/-1.
__ bind(&stub_call);
__ movp(rdx, rax);
__ Move(rax, Smi::FromInt(1));
Handle<Code> code =
CodeFactory::BinaryOpIC(isolate(), expr->binary_op()).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ bind(&done);
CodeFactory::BinaryOperation(isolate(), expr->binary_op()).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
// Store the value returned in rax.
switch (assign_type) {

View File

@ -1310,14 +1310,7 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
PushOperand(eax); // Left operand goes on the stack.
VisitForAccumulatorValue(expr->value());
if (ShouldInlineSmiCase(op)) {
EmitInlineSmiBinaryOp(expr->binary_operation(),
op,
expr->target(),
expr->value());
} else {
EmitBinaryOp(expr->binary_operation(), op);
}
EmitBinaryOp(expr->binary_operation(), op);
} else {
VisitForAccumulatorValue(expr->value());
}
@ -1367,105 +1360,12 @@ void FullCodeGenerator::EmitOperandStackDepthCheck() {
}
}
void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
Token::Value op,
Expression* left,
Expression* right) {
// Do combined smi check of the operands. Left operand is on the
// stack. Right operand is in eax.
Label smi_case, done, stub_call;
PopOperand(edx);
__ mov(ecx, eax);
__ or_(eax, edx);
JumpPatchSite patch_site(masm_);
patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
__ bind(&stub_call);
__ mov(eax, ecx);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ jmp(&done, Label::kNear);
// Smi case.
__ bind(&smi_case);
__ mov(eax, edx); // Copy left operand in case of a stub call.
switch (op) {
case Token::SAR:
__ SmiUntag(ecx);
__ sar_cl(eax); // No checks of result necessary
__ and_(eax, Immediate(~kSmiTagMask));
break;
case Token::SHL: {
Label result_ok;
__ SmiUntag(eax);
__ SmiUntag(ecx);
__ shl_cl(eax);
// Check that the *signed* result fits in a smi.
__ cmp(eax, 0xc0000000);
__ j(positive, &result_ok);
__ SmiTag(ecx);
__ jmp(&stub_call);
__ bind(&result_ok);
__ SmiTag(eax);
break;
}
case Token::SHR: {
Label result_ok;
__ SmiUntag(eax);
__ SmiUntag(ecx);
__ shr_cl(eax);
__ test(eax, Immediate(0xc0000000));
__ j(zero, &result_ok);
__ SmiTag(ecx);
__ jmp(&stub_call);
__ bind(&result_ok);
__ SmiTag(eax);
break;
}
case Token::ADD:
__ add(eax, ecx);
__ j(overflow, &stub_call);
break;
case Token::SUB:
__ sub(eax, ecx);
__ j(overflow, &stub_call);
break;
case Token::MUL: {
__ SmiUntag(eax);
__ imul(eax, ecx);
__ j(overflow, &stub_call);
__ test(eax, eax);
__ j(not_zero, &done, Label::kNear);
__ mov(ebx, edx);
__ or_(ebx, ecx);
__ j(negative, &stub_call);
break;
}
case Token::BIT_OR:
__ or_(eax, ecx);
break;
case Token::BIT_AND:
__ and_(eax, ecx);
break;
case Token::BIT_XOR:
__ xor_(eax, ecx);
break;
default:
UNREACHABLE();
}
__ bind(&done);
context()->Plug(eax);
}
void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
PopOperand(edx);
Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
CallIC(code);
patch_site.EmitPatchInfo();
Handle<Code> code = CodeFactory::BinaryOperation(isolate(), op).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
context()->Plug(eax);
}
@ -2135,53 +2035,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
// Inline smi case if we are in a loop.
Label done, stub_call;
JumpPatchSite patch_site(masm_);
if (ShouldInlineSmiCase(expr->op())) {
Label slow;
patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
// Save result for postfix expressions.
if (expr->is_postfix()) {
if (!context()->IsEffect()) {
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
switch (assign_type) {
case VARIABLE:
__ push(eax);
break;
case NAMED_PROPERTY:
__ mov(Operand(esp, kPointerSize), eax);
break;
case KEYED_PROPERTY:
__ mov(Operand(esp, 2 * kPointerSize), eax);
break;
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNREACHABLE();
break;
}
}
}
if (expr->op() == Token::INC) {
__ add(eax, Immediate(Smi::FromInt(1)));
} else {
__ sub(eax, Immediate(Smi::FromInt(1)));
}
__ j(no_overflow, &done, Label::kNear);
// Call stub. Undo operation first.
if (expr->op() == Token::INC) {
__ sub(eax, Immediate(Smi::FromInt(1)));
} else {
__ add(eax, Immediate(Smi::FromInt(1)));
}
__ jmp(&stub_call, Label::kNear);
__ bind(&slow);
}
// Convert old value into a number.
__ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
RestoreContext();
@ -2213,14 +2066,12 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
SetExpressionPosition(expr);
// Call stub for +1/-1.
__ bind(&stub_call);
__ mov(edx, eax);
__ mov(eax, Immediate(Smi::FromInt(1)));
Handle<Code> code =
CodeFactory::BinaryOpIC(isolate(), expr->binary_op()).code();
CallIC(code);
patch_site.EmitPatchInfo();
__ bind(&done);
CodeFactory::BinaryOperation(isolate(), expr->binary_op()).code();
__ Call(code, RelocInfo::CODE_TARGET);
RestoreContext();
// Store the value returned in eax.
switch (assign_type) {

View File

@ -951,8 +951,6 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
CreateWeakCellStub::GenerateAheadOfTime(isolate);
BinaryOpICStub::GenerateAheadOfTime(isolate);
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
StoreFastElementStub::GenerateAheadOfTime(isolate);
}
@ -1437,34 +1435,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- edx : left
// -- eax : right
// -- esp[0] : return address
// -----------------------------------
// Load ecx with the allocation site. We stick an undefined dummy value here
// and replace it with the real allocation site later when we instantiate this
// stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
__ mov(ecx, isolate()->factory()->undefined_value());
// Make sure that we actually patched the allocation site.
if (FLAG_debug_code) {
__ test(ecx, Immediate(kSmiTagMask));
__ Assert(not_equal, kExpectedAllocationSite);
__ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
isolate()->factory()->allocation_site_map());
__ Assert(equal, kExpectedAllocationSite);
}
// Tail call into the stub that handles binary operations with allocation
// sites.
BinaryOpWithAllocationSiteStub stub(isolate(), state());
__ TailCallStub(&stub);
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;

View File

@ -58,8 +58,8 @@ void IC::SetTargetAtAddress(Address address, Code* target,
Address constant_pool) {
if (AddressIsDeoptimizedCode(target->GetIsolate(), address)) return;
// Only these two old-style ICs still do code patching.
DCHECK(target->is_binary_op_stub() || target->is_compare_ic_stub());
// Only one old-style ICs still does code patching.
DCHECK(target->is_compare_ic_stub());
Heap* heap = target->GetHeap();
Code* old_target = GetTargetAtAddress(address, constant_pool);

View File

@ -19,337 +19,6 @@ void ICUtility::Clear(Isolate* isolate, Address address,
}
// static
STATIC_CONST_MEMBER_DEFINITION const int BinaryOpICState::FIRST_TOKEN;
// static
STATIC_CONST_MEMBER_DEFINITION const int BinaryOpICState::LAST_TOKEN;
BinaryOpICState::BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state)
: fixed_right_arg_(
HasFixedRightArgField::decode(extra_ic_state)
? Just(1 << FixedRightArgValueField::decode(extra_ic_state))
: Nothing<int>()),
isolate_(isolate) {
op_ =
static_cast<Token::Value>(FIRST_TOKEN + OpField::decode(extra_ic_state));
left_kind_ = LeftKindField::decode(extra_ic_state);
right_kind_ = fixed_right_arg_.IsJust()
? (Smi::IsValid(fixed_right_arg_.FromJust()) ? SMI : INT32)
: RightKindField::decode(extra_ic_state);
result_kind_ = ResultKindField::decode(extra_ic_state);
DCHECK_LE(FIRST_TOKEN, op_);
DCHECK_LE(op_, LAST_TOKEN);
}
ExtraICState BinaryOpICState::GetExtraICState() const {
ExtraICState extra_ic_state =
OpField::encode(op_ - FIRST_TOKEN) | LeftKindField::encode(left_kind_) |
ResultKindField::encode(result_kind_) |
HasFixedRightArgField::encode(fixed_right_arg_.IsJust());
if (fixed_right_arg_.IsJust()) {
extra_ic_state = FixedRightArgValueField::update(
extra_ic_state, WhichPowerOf2(fixed_right_arg_.FromJust()));
} else {
extra_ic_state = RightKindField::update(extra_ic_state, right_kind_);
}
return extra_ic_state;
}
std::string BinaryOpICState::ToString() const {
std::string ret = "(";
ret += Token::Name(op_);
if (CouldCreateAllocationMementos()) ret += "_CreateAllocationMementos";
ret += ":";
ret += BinaryOpICState::KindToString(left_kind_);
ret += "*";
if (fixed_right_arg_.IsJust()) {
ret += fixed_right_arg_.FromJust();
} else {
ret += BinaryOpICState::KindToString(right_kind_);
}
ret += "->";
ret += BinaryOpICState::KindToString(result_kind_);
ret += ")";
return ret;
}
// static
void BinaryOpICState::GenerateAheadOfTime(
Isolate* isolate, void (*Generate)(Isolate*, const BinaryOpICState&)) {
// TODO(olivf) We should investigate why adding stubs to the snapshot is so
// expensive at runtime. When solved we should be able to add most binops to
// the snapshot instead of hand-picking them.
// Generated list of commonly used stubs
#define GENERATE(op, left_kind, right_kind, result_kind) \
do { \
BinaryOpICState state(isolate, op); \
state.left_kind_ = left_kind; \
state.fixed_right_arg_ = Nothing<int>(); \
state.right_kind_ = right_kind; \
state.result_kind_ = result_kind; \
Generate(isolate, state); \
} while (false)
GENERATE(Token::ADD, INT32, INT32, INT32);
GENERATE(Token::ADD, INT32, INT32, NUMBER);
GENERATE(Token::ADD, INT32, NUMBER, NUMBER);
GENERATE(Token::ADD, INT32, SMI, INT32);
GENERATE(Token::ADD, NUMBER, INT32, NUMBER);
GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER);
GENERATE(Token::ADD, NUMBER, SMI, NUMBER);
GENERATE(Token::ADD, SMI, INT32, INT32);
GENERATE(Token::ADD, SMI, INT32, NUMBER);
GENERATE(Token::ADD, SMI, NUMBER, NUMBER);
GENERATE(Token::ADD, SMI, SMI, INT32);
GENERATE(Token::ADD, SMI, SMI, SMI);
GENERATE(Token::BIT_AND, INT32, INT32, INT32);
GENERATE(Token::BIT_AND, INT32, INT32, SMI);
GENERATE(Token::BIT_AND, INT32, SMI, INT32);
GENERATE(Token::BIT_AND, INT32, SMI, SMI);
GENERATE(Token::BIT_AND, NUMBER, INT32, INT32);
GENERATE(Token::BIT_AND, NUMBER, SMI, SMI);
GENERATE(Token::BIT_AND, SMI, INT32, INT32);
GENERATE(Token::BIT_AND, SMI, INT32, SMI);
GENERATE(Token::BIT_AND, SMI, NUMBER, SMI);
GENERATE(Token::BIT_AND, SMI, SMI, SMI);
GENERATE(Token::BIT_OR, INT32, INT32, INT32);
GENERATE(Token::BIT_OR, INT32, INT32, SMI);
GENERATE(Token::BIT_OR, INT32, SMI, INT32);
GENERATE(Token::BIT_OR, INT32, SMI, SMI);
GENERATE(Token::BIT_OR, NUMBER, SMI, INT32);
GENERATE(Token::BIT_OR, NUMBER, SMI, SMI);
GENERATE(Token::BIT_OR, SMI, INT32, INT32);
GENERATE(Token::BIT_OR, SMI, INT32, SMI);
GENERATE(Token::BIT_OR, SMI, SMI, SMI);
GENERATE(Token::BIT_XOR, INT32, INT32, INT32);
GENERATE(Token::BIT_XOR, INT32, INT32, SMI);
GENERATE(Token::BIT_XOR, INT32, NUMBER, SMI);
GENERATE(Token::BIT_XOR, INT32, SMI, INT32);
GENERATE(Token::BIT_XOR, NUMBER, INT32, INT32);
GENERATE(Token::BIT_XOR, NUMBER, SMI, INT32);
GENERATE(Token::BIT_XOR, NUMBER, SMI, SMI);
GENERATE(Token::BIT_XOR, SMI, INT32, INT32);
GENERATE(Token::BIT_XOR, SMI, INT32, SMI);
GENERATE(Token::BIT_XOR, SMI, SMI, SMI);
GENERATE(Token::DIV, INT32, INT32, INT32);
GENERATE(Token::DIV, INT32, INT32, NUMBER);
GENERATE(Token::DIV, INT32, NUMBER, NUMBER);
GENERATE(Token::DIV, INT32, SMI, INT32);
GENERATE(Token::DIV, INT32, SMI, NUMBER);
GENERATE(Token::DIV, NUMBER, INT32, NUMBER);
GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER);
GENERATE(Token::DIV, NUMBER, SMI, NUMBER);
GENERATE(Token::DIV, SMI, INT32, INT32);
GENERATE(Token::DIV, SMI, INT32, NUMBER);
GENERATE(Token::DIV, SMI, NUMBER, NUMBER);
GENERATE(Token::DIV, SMI, SMI, NUMBER);
GENERATE(Token::DIV, SMI, SMI, SMI);
GENERATE(Token::MOD, NUMBER, SMI, NUMBER);
GENERATE(Token::MOD, SMI, SMI, SMI);
GENERATE(Token::MUL, INT32, INT32, INT32);
GENERATE(Token::MUL, INT32, INT32, NUMBER);
GENERATE(Token::MUL, INT32, NUMBER, NUMBER);
GENERATE(Token::MUL, INT32, SMI, INT32);
GENERATE(Token::MUL, INT32, SMI, NUMBER);
GENERATE(Token::MUL, NUMBER, INT32, NUMBER);
GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER);
GENERATE(Token::MUL, NUMBER, SMI, NUMBER);
GENERATE(Token::MUL, SMI, INT32, INT32);
GENERATE(Token::MUL, SMI, INT32, NUMBER);
GENERATE(Token::MUL, SMI, NUMBER, NUMBER);
GENERATE(Token::MUL, SMI, SMI, INT32);
GENERATE(Token::MUL, SMI, SMI, NUMBER);
GENERATE(Token::MUL, SMI, SMI, SMI);
GENERATE(Token::SAR, INT32, SMI, INT32);
GENERATE(Token::SAR, INT32, SMI, SMI);
GENERATE(Token::SAR, NUMBER, SMI, SMI);
GENERATE(Token::SAR, SMI, SMI, SMI);
GENERATE(Token::SHL, INT32, SMI, INT32);
GENERATE(Token::SHL, INT32, SMI, SMI);
GENERATE(Token::SHL, NUMBER, SMI, SMI);
GENERATE(Token::SHL, SMI, SMI, INT32);
GENERATE(Token::SHL, SMI, SMI, SMI);
GENERATE(Token::SHR, INT32, SMI, SMI);
GENERATE(Token::SHR, NUMBER, SMI, INT32);
GENERATE(Token::SHR, NUMBER, SMI, SMI);
GENERATE(Token::SHR, SMI, SMI, SMI);
GENERATE(Token::SUB, INT32, INT32, INT32);
GENERATE(Token::SUB, INT32, NUMBER, NUMBER);
GENERATE(Token::SUB, INT32, SMI, INT32);
GENERATE(Token::SUB, NUMBER, INT32, NUMBER);
GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER);
GENERATE(Token::SUB, NUMBER, SMI, NUMBER);
GENERATE(Token::SUB, SMI, INT32, INT32);
GENERATE(Token::SUB, SMI, NUMBER, NUMBER);
GENERATE(Token::SUB, SMI, SMI, SMI);
#undef GENERATE
#define GENERATE(op, left_kind, fixed_right_arg_value, result_kind) \
do { \
BinaryOpICState state(isolate, op); \
state.left_kind_ = left_kind; \
state.fixed_right_arg_ = Just(fixed_right_arg_value); \
state.right_kind_ = SMI; \
state.result_kind_ = result_kind; \
Generate(isolate, state); \
} while (false)
GENERATE(Token::MOD, SMI, 2, SMI);
GENERATE(Token::MOD, SMI, 4, SMI);
GENERATE(Token::MOD, SMI, 8, SMI);
GENERATE(Token::MOD, SMI, 16, SMI);
GENERATE(Token::MOD, SMI, 32, SMI);
GENERATE(Token::MOD, SMI, 2048, SMI);
#undef GENERATE
}
AstType* BinaryOpICState::GetResultType() const {
Kind result_kind = result_kind_;
if (HasSideEffects()) {
result_kind = NONE;
} else if (result_kind == GENERIC && op_ == Token::ADD) {
return AstType::NumberOrString();
} else if (result_kind == NUMBER && op_ == Token::SHR) {
return AstType::Unsigned32();
}
DCHECK_NE(GENERIC, result_kind);
return KindToType(result_kind);
}
std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s) {
os << "(" << Token::Name(s.op_);
if (s.CouldCreateAllocationMementos()) os << "_CreateAllocationMementos";
os << ":" << BinaryOpICState::KindToString(s.left_kind_) << "*";
if (s.fixed_right_arg_.IsJust()) {
os << s.fixed_right_arg_.FromJust();
} else {
os << BinaryOpICState::KindToString(s.right_kind_);
}
return os << "->" << BinaryOpICState::KindToString(s.result_kind_) << ")";
}
void BinaryOpICState::Update(Handle<Object> left, Handle<Object> right,
Handle<Object> result) {
ExtraICState old_extra_ic_state = GetExtraICState();
left_kind_ = UpdateKind(left, left_kind_);
right_kind_ = UpdateKind(right, right_kind_);
int32_t fixed_right_arg_value = 0;
bool has_fixed_right_arg =
op_ == Token::MOD && right->ToInt32(&fixed_right_arg_value) &&
fixed_right_arg_value > 0 &&
base::bits::IsPowerOfTwo32(fixed_right_arg_value) &&
FixedRightArgValueField::is_valid(WhichPowerOf2(fixed_right_arg_value)) &&
(left_kind_ == SMI || left_kind_ == INT32) &&
(result_kind_ == NONE || !fixed_right_arg_.IsJust());
fixed_right_arg_ =
has_fixed_right_arg ? Just(fixed_right_arg_value) : Nothing<int32_t>();
result_kind_ = UpdateKind(result, result_kind_);
if (!Token::IsTruncatingBinaryOp(op_)) {
Kind input_kind = Max(left_kind_, right_kind_);
if (result_kind_ < input_kind && input_kind <= NUMBER) {
result_kind_ = input_kind;
}
}
// We don't want to distinguish INT32 and NUMBER for string add (because
// NumberToString can't make use of this anyway).
if (left_kind_ == STRING && right_kind_ == INT32) {
DCHECK_EQ(STRING, result_kind_);
DCHECK_EQ(Token::ADD, op_);
right_kind_ = NUMBER;
} else if (right_kind_ == STRING && left_kind_ == INT32) {
DCHECK_EQ(STRING, result_kind_);
DCHECK_EQ(Token::ADD, op_);
left_kind_ = NUMBER;
}
if (old_extra_ic_state == GetExtraICState()) {
// Tagged operations can lead to non-truncating HChanges
if (left->IsOddball()) {
left_kind_ = GENERIC;
} else {
DCHECK(right->IsOddball());
right_kind_ = GENERIC;
}
}
}
BinaryOpICState::Kind BinaryOpICState::UpdateKind(Handle<Object> object,
Kind kind) const {
Kind new_kind = GENERIC;
bool is_truncating = Token::IsTruncatingBinaryOp(op());
if (object->IsOddball() && is_truncating) {
// Oddballs will be automatically truncated by HChange.
new_kind = INT32;
} else if (object->IsUndefined(isolate_)) {
// Undefined will be automatically truncated by HChange.
new_kind = is_truncating ? INT32 : NUMBER;
} else if (object->IsSmi()) {
new_kind = SMI;
} else if (object->IsHeapNumber()) {
double value = Handle<HeapNumber>::cast(object)->value();
new_kind = IsInt32Double(value) ? INT32 : NUMBER;
} else if (object->IsString() && op() == Token::ADD) {
new_kind = STRING;
}
if (new_kind == INT32 && SmiValuesAre32Bits()) {
new_kind = NUMBER;
}
if (kind != NONE && ((new_kind <= NUMBER && kind > NUMBER) ||
(new_kind > NUMBER && kind <= NUMBER))) {
new_kind = GENERIC;
}
return Max(kind, new_kind);
}
// static
const char* BinaryOpICState::KindToString(Kind kind) {
switch (kind) {
case NONE:
return "None";
case SMI:
return "Smi";
case INT32:
return "Int32";
case NUMBER:
return "Number";
case STRING:
return "String";
case GENERIC:
return "Generic";
}
UNREACHABLE();
}
// static
AstType* BinaryOpICState::KindToType(Kind kind) {
switch (kind) {
case NONE:
return AstType::None();
case SMI:
return AstType::SignedSmall();
case INT32:
return AstType::Signed32();
case NUMBER:
return AstType::Number();
case STRING:
return AstType::String();
case GENERIC:
return AstType::Any();
}
UNREACHABLE();
}
const char* CompareICState::GetStateName(State state) {
switch (state) {
case UNINITIALIZED:

View File

@ -23,130 +23,6 @@ class ICUtility : public AllStatic {
};
class BinaryOpICState final BASE_EMBEDDED {
public:
BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state);
BinaryOpICState(Isolate* isolate, Token::Value op)
: op_(op),
left_kind_(NONE),
right_kind_(NONE),
result_kind_(NONE),
fixed_right_arg_(Nothing<int>()),
isolate_(isolate) {
DCHECK_LE(FIRST_TOKEN, op);
DCHECK_LE(op, LAST_TOKEN);
}
InlineCacheState GetICState() const {
if (Max(left_kind_, right_kind_) == NONE) {
return ::v8::internal::UNINITIALIZED;
}
if (Max(left_kind_, right_kind_) == GENERIC) {
return ::v8::internal::MEGAMORPHIC;
}
if (Min(left_kind_, right_kind_) == GENERIC) {
return ::v8::internal::GENERIC;
}
return ::v8::internal::MONOMORPHIC;
}
ExtraICState GetExtraICState() const;
std::string ToString() const;
static void GenerateAheadOfTime(Isolate*,
void (*Generate)(Isolate*,
const BinaryOpICState&));
// Returns true if the IC _could_ create allocation mementos.
bool CouldCreateAllocationMementos() const {
if (left_kind_ == STRING || right_kind_ == STRING) {
DCHECK_EQ(Token::ADD, op_);
return true;
}
return false;
}
// Returns true if the IC _should_ create allocation mementos.
bool ShouldCreateAllocationMementos() const {
return FLAG_allocation_site_pretenuring && CouldCreateAllocationMementos();
}
bool HasSideEffects() const {
return Max(left_kind_, right_kind_) == GENERIC;
}
// Returns true if the IC should enable the inline smi code (i.e. if either
// parameter may be a smi).
bool UseInlinedSmiCode() const {
return KindMaybeSmi(left_kind_) || KindMaybeSmi(right_kind_);
}
static const int FIRST_TOKEN = Token::BIT_OR;
static const int LAST_TOKEN = Token::MOD;
Token::Value op() const { return op_; }
Maybe<int> fixed_right_arg() const { return fixed_right_arg_; }
AstType* GetLeftType() const { return KindToType(left_kind_); }
AstType* GetRightType() const { return KindToType(right_kind_); }
AstType* GetResultType() const;
void Update(Handle<Object> left, Handle<Object> right, Handle<Object> result);
Isolate* isolate() const { return isolate_; }
enum Kind { NONE, SMI, INT32, NUMBER, STRING, GENERIC };
Kind kind() const {
return KindGeneralize(KindGeneralize(left_kind_, right_kind_),
result_kind_);
}
private:
friend std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s);
Kind UpdateKind(Handle<Object> object, Kind kind) const;
static const char* KindToString(Kind kind);
static AstType* KindToType(Kind kind);
static bool KindMaybeSmi(Kind kind) {
return (kind >= SMI && kind <= NUMBER) || kind == GENERIC;
}
static bool KindLessGeneralThan(Kind kind1, Kind kind2) {
if (kind1 == NONE) return true;
if (kind1 == kind2) return true;
if (kind2 == GENERIC) return true;
if (kind2 == STRING) return false;
return kind1 <= kind2;
}
static Kind KindGeneralize(Kind kind1, Kind kind2) {
if (KindLessGeneralThan(kind1, kind2)) return kind2;
if (KindLessGeneralThan(kind2, kind1)) return kind1;
return GENERIC;
}
// We truncate the last bit of the token.
STATIC_ASSERT(LAST_TOKEN - FIRST_TOKEN < (1 << 4));
class OpField : public BitField<int, 0, 4> {};
class ResultKindField : public BitField<Kind, 4, 3> {};
class LeftKindField : public BitField<Kind, 7, 3> {};
// When fixed right arg is set, we don't need to store the right kind.
// Thus the two fields can overlap.
class HasFixedRightArgField : public BitField<bool, 10, 1> {};
class FixedRightArgValueField : public BitField<int, 11, 4> {};
class RightKindField : public BitField<Kind, 11, 3> {};
Token::Value op_;
Kind left_kind_;
Kind right_kind_;
Kind result_kind_;
Maybe<int> fixed_right_arg_;
Isolate* isolate_;
};
std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s);
class CompareICState {
public:
// The type/state lattice is defined by the following inequations:

View File

@ -229,9 +229,7 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
} else {
Code* target = this->target();
Code::Kind kind = target->kind();
if (kind == Code::BINARY_OP_IC) {
kind_ = FeedbackSlotKind::kBinaryOp;
} else if (kind == Code::COMPARE_IC) {
if (kind == Code::COMPARE_IC) {
kind_ = FeedbackSlotKind::kCompareOp;
} else {
UNREACHABLE();
@ -259,10 +257,6 @@ bool IC::ShouldPushPopSlotAndVector(Code::Kind kind) {
InlineCacheState IC::StateFromCode(Code* code) {
Isolate* isolate = code->GetIsolate();
switch (code->kind()) {
case Code::BINARY_OP_IC: {
BinaryOpICState state(isolate, code->extra_ic_state());
return state.GetICState();
}
case Code::COMPARE_IC: {
CompareICStub stub(isolate, code->extra_ic_state());
return stub.GetICState();
@ -438,8 +432,7 @@ void IC::OnFeedbackChanged(Isolate* isolate, JSFunction* host_function) {
void IC::PostPatching(Address address, Code* target, Code* old_target) {
// Type vector based ICs update these statistics at a different time because
// they don't always patch on state change.
DCHECK(target->kind() == Code::BINARY_OP_IC ||
target->kind() == Code::COMPARE_IC);
DCHECK(target->kind() == Code::COMPARE_IC);
DCHECK(old_target->is_inline_cache_stub());
DCHECK(target->is_inline_cache_stub());
@ -2540,158 +2533,6 @@ RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
}
MaybeHandle<Object> BinaryOpIC::Transition(
Handle<AllocationSite> allocation_site, Handle<Object> left,
Handle<Object> right) {
BinaryOpICState state(isolate(), extra_ic_state());
// Compute the actual result using the builtin for the binary operation.
Handle<Object> result;
switch (state.op()) {
default:
UNREACHABLE();
case Token::ADD:
ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
Object::Add(isolate(), left, right), Object);
break;
case Token::SUB:
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result, Object::Subtract(isolate(), left, right), Object);
break;
case Token::MUL:
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result, Object::Multiply(isolate(), left, right), Object);
break;
case Token::DIV:
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result, Object::Divide(isolate(), left, right), Object);
break;
case Token::MOD:
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result, Object::Modulus(isolate(), left, right), Object);
break;
case Token::BIT_OR:
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result, Object::BitwiseOr(isolate(), left, right), Object);
break;
case Token::BIT_AND:
ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
Object::BitwiseAnd(isolate(), left, right),
Object);
break;
case Token::BIT_XOR:
ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
Object::BitwiseXor(isolate(), left, right),
Object);
break;
case Token::SAR:
ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
Object::ShiftRight(isolate(), left, right),
Object);
break;
case Token::SHR:
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result, Object::ShiftRightLogical(isolate(), left, right),
Object);
break;
case Token::SHL:
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result, Object::ShiftLeft(isolate(), left, right), Object);
break;
}
// Do not try to update the target if the code was marked for lazy
// deoptimization. (Since we do not relocate addresses in these
// code objects, an attempt to access the target could fail.)
if (AddressIsDeoptimizedCode()) {
return result;
}
// Compute the new state.
BinaryOpICState old_state(isolate(), target()->extra_ic_state());
state.Update(left, right, result);
// Check if we have a string operation here.
Handle<Code> new_target;
if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
// Setup the allocation site on-demand.
if (allocation_site.is_null()) {
allocation_site = isolate()->factory()->NewAllocationSite();
}
// Install the stub with an allocation site.
BinaryOpICWithAllocationSiteStub stub(isolate(), state);
new_target = stub.GetCodeCopyFromTemplate(allocation_site);
// Sanity check the trampoline stub.
DCHECK_EQ(*allocation_site, new_target->FindFirstAllocationSite());
} else {
// Install the generic stub.
BinaryOpICStub stub(isolate(), state);
new_target = stub.GetCode();
// Sanity check the generic stub.
DCHECK_NULL(new_target->FindFirstAllocationSite());
}
set_target(*new_target);
if (FLAG_ic_stats &
v8::tracing::TracingCategoryObserver::ENABLED_BY_TRACING) {
auto ic_stats = ICStats::instance();
ic_stats->Begin();
ICInfo& ic_info = ic_stats->Current();
ic_info.type = "BinaryOpIC";
ic_info.state = old_state.ToString();
ic_info.state += " => ";
ic_info.state += state.ToString();
JavaScriptFrame::CollectTopFrameForICStats(isolate());
ic_stats->End();
} else if (FLAG_ic_stats) {
int line;
int column;
Address pc = GetAbstractPC(&line, &column);
LOG(isolate(),
BinaryOpIC(pc, line, column, *new_target, old_state.ToString().c_str(),
state.ToString().c_str(),
allocation_site.is_null() ? nullptr : *allocation_site));
}
// Patch the inlined smi code as necessary.
if (!old_state.UseInlinedSmiCode() && state.UseInlinedSmiCode()) {
PatchInlinedSmiCode(isolate(), address(), ENABLE_INLINED_SMI_CHECK);
} else if (old_state.UseInlinedSmiCode() && !state.UseInlinedSmiCode()) {
PatchInlinedSmiCode(isolate(), address(), DISABLE_INLINED_SMI_CHECK);
}
return result;
}
RUNTIME_FUNCTION(Runtime_BinaryOpIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
typedef BinaryOpDescriptor Descriptor;
Handle<Object> left = args.at(Descriptor::kLeft);
Handle<Object> right = args.at(Descriptor::kRight);
BinaryOpIC ic(isolate);
RETURN_RESULT_OR_FAILURE(
isolate, ic.Transition(Handle<AllocationSite>::null(), left, right));
}
RUNTIME_FUNCTION(Runtime_BinaryOpIC_MissWithAllocationSite) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
typedef BinaryOpWithAllocationSiteDescriptor Descriptor;
Handle<AllocationSite> allocation_site =
args.at<AllocationSite>(Descriptor::kAllocationSite);
Handle<Object> left = args.at(Descriptor::kLeft);
Handle<Object> right = args.at(Descriptor::kRight);
BinaryOpIC ic(isolate);
RETURN_RESULT_OR_FAILURE(isolate,
ic.Transition(allocation_site, left, right));
}
Code* CompareIC::GetRawUninitialized(Isolate* isolate, Token::Value op) {
CompareICStub stub(isolate, op, CompareICState::UNINITIALIZED,
CompareICState::UNINITIALIZED,

View File

@ -421,17 +421,6 @@ class KeyedStoreIC : public StoreIC {
};
// Type Recording BinaryOpIC, that records the types of the inputs and outputs.
class BinaryOpIC : public IC {
public:
explicit BinaryOpIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
MaybeHandle<Object> Transition(Handle<AllocationSite> allocation_site,
Handle<Object> left,
Handle<Object> right) WARN_UNUSED_RESULT;
};
class CompareIC : public IC {
public:
CompareIC(Isolate* isolate, Token::Value op)
@ -459,8 +448,7 @@ class CompareIC : public IC {
friend class IC;
};
// Helper for BinaryOpIC and CompareIC.
// Helper for CompareIC.
enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
void PatchInlinedSmiCode(Isolate* isolate, Address address,
InlinedSmiCheck check);

View File

@ -1380,22 +1380,6 @@ void Logger::CompareIC(const Address pc, int line, int column, Code* stub,
msg.WriteToLogFile();
}
void Logger::BinaryOpIC(const Address pc, int line, int column, Code* stub,
const char* old_state, const char* new_state,
AllocationSite* allocation_site) {
if (!log_->IsEnabled() || !FLAG_trace_ic) return;
Log::MessageBuilder msg(log_);
msg.Append("BinaryOpIC,");
msg.AppendAddress(pc);
msg.Append(",%d,%d,", line, column);
msg.AppendAddress(reinterpret_cast<Address>(stub));
msg.Append(",%s,%s,", old_state, new_state);
if (allocation_site != nullptr) {
msg.AppendAddress(reinterpret_cast<Address>(allocation_site));
}
msg.WriteToLogFile();
}
void Logger::PatchIC(const Address pc, const Address test, int delta) {
if (!log_->IsEnabled() || !FLAG_trace_ic) return;
Log::MessageBuilder msg(log_);
@ -1514,7 +1498,6 @@ void Logger::LogCodeObject(Object* object) {
return; // We log this later using LogCompiledFunctions.
case AbstractCode::BYTECODE_HANDLER:
return; // We log it later by walking the dispatch table.
case AbstractCode::BINARY_OP_IC: // fall through
case AbstractCode::COMPARE_IC: // fall through
case AbstractCode::STUB:

View File

@ -196,9 +196,6 @@ class Logger : public CodeEventListener {
const char* op, const char* old_left, const char* old_right,
const char* old_state, const char* new_left,
const char* new_right, const char* new_state);
void BinaryOpIC(const Address pc, int line, int column, Code* stub,
const char* old_state, const char* new_state,
AllocationSite* allocation_site);
void PatchIC(const Address pc, const Address test, int delta);
// ==== Events logged by --log-gc. ====

View File

@ -879,10 +879,8 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
CreateWeakCellStub::GenerateAheadOfTime(isolate);
BinaryOpICStub::GenerateAheadOfTime(isolate);
StoreRegistersStateStub::GenerateAheadOfTime(isolate);
RestoreRegistersStateStub::GenerateAheadOfTime(isolate);
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
StoreFastElementStub::GenerateAheadOfTime(isolate);
}
@ -1628,34 +1626,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a1 : left
// -- a0 : right
// -- ra : return address
// -----------------------------------
// Load a2 with the allocation site. We stick an undefined dummy value here
// and replace it with the real allocation site later when we instantiate this
// stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
__ li(a2, isolate()->factory()->undefined_value());
// Make sure that we actually patched the allocation site.
if (FLAG_debug_code) {
__ And(at, a2, Operand(kSmiTagMask));
__ Assert(ne, kExpectedAllocationSite, at, Operand(zero_reg));
__ lw(t0, FieldMemOperand(a2, HeapObject::kMapOffset));
__ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
__ Assert(eq, kExpectedAllocationSite, t0, Operand(at));
}
// Tail call into the stub that handles binary operations with allocation
// sites.
BinaryOpWithAllocationSiteStub stub(isolate(), state());
__ TailCallStub(&stub);
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;

View File

@ -876,10 +876,8 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
CreateWeakCellStub::GenerateAheadOfTime(isolate);
BinaryOpICStub::GenerateAheadOfTime(isolate);
StoreRegistersStateStub::GenerateAheadOfTime(isolate);
RestoreRegistersStateStub::GenerateAheadOfTime(isolate);
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
StoreFastElementStub::GenerateAheadOfTime(isolate);
}
@ -1633,34 +1631,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- a1 : left
// -- a0 : right
// -- ra : return address
// -----------------------------------
// Load a2 with the allocation site. We stick an undefined dummy value here
// and replace it with the real allocation site later when we instantiate this
// stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
__ li(a2, isolate()->factory()->undefined_value());
// Make sure that we actually patched the allocation site.
if (FLAG_debug_code) {
__ And(at, a2, Operand(kSmiTagMask));
__ Assert(ne, kExpectedAllocationSite, at, Operand(zero_reg));
__ Ld(a4, FieldMemOperand(a2, HeapObject::kMapOffset));
__ LoadRoot(at, Heap::kAllocationSiteMapRootIndex);
__ Assert(eq, kExpectedAllocationSite, a4, Operand(at));
}
// Tail call into the stub that handles binary operations with allocation
// sites.
BinaryOpWithAllocationSiteStub stub(isolate(), state());
__ TailCallStub(&stub);
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;

View File

@ -3839,7 +3839,7 @@ bool Code::IsCodeStubOrIC() {
}
ExtraICState Code::extra_ic_state() {
DCHECK(is_binary_op_stub() || is_compare_ic_stub() || is_debug_stub());
DCHECK(is_compare_ic_stub() || is_debug_stub());
return ExtractExtraICStateFromFlags(flags());
}
@ -4158,7 +4158,6 @@ bool Code::is_debug_stub() {
}
bool Code::is_handler() { return kind() == HANDLER; }
bool Code::is_stub() { return kind() == STUB; }
bool Code::is_binary_op_stub() { return kind() == BINARY_OP_IC; }
bool Code::is_compare_ic_stub() { return kind() == COMPARE_IC; }
bool Code::is_optimized_code() { return kind() == OPTIMIZED_FUNCTION; }
bool Code::is_wasm_code() { return kind() == WASM_FUNCTION; }

View File

@ -14216,7 +14216,7 @@ void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
os << "major_key = " << (n == NULL ? "null" : n) << "\n";
}
if (is_inline_cache_stub()) {
if (is_compare_ic_stub() || is_binary_op_stub()) {
if (is_compare_ic_stub()) {
InlineCacheState ic_state = IC::StateFromCode(this);
os << "ic_state = " << ICState2String(ic_state) << "\n";
PrintExtraICState(os, kind(), extra_ic_state());

View File

@ -3572,7 +3572,6 @@ class Code: public HeapObject {
V(STORE_IC) \
V(STORE_GLOBAL_IC) \
V(KEYED_STORE_IC) \
V(BINARY_OP_IC) \
V(COMPARE_IC)
#define CODE_KIND_LIST(V) \
@ -3674,7 +3673,6 @@ class Code: public HeapObject {
inline bool is_debug_stub();
inline bool is_handler();
inline bool is_stub();
inline bool is_binary_op_stub();
inline bool is_compare_ic_stub();
inline bool is_optimized_code();
inline bool is_wasm_code();

View File

@ -840,10 +840,8 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
CreateWeakCellStub::GenerateAheadOfTime(isolate);
BinaryOpICStub::GenerateAheadOfTime(isolate);
StoreRegistersStateStub::GenerateAheadOfTime(isolate);
RestoreRegistersStateStub::GenerateAheadOfTime(isolate);
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
StoreFastElementStub::GenerateAheadOfTime(isolate);
}
@ -1591,37 +1589,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r4 : left
// -- r3 : right
// -- lr : return address
// -----------------------------------
// Load r5 with the allocation site. We stick an undefined dummy value here
// and replace it with the real allocation site later when we instantiate this
// stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
__ Move(r5, isolate()->factory()->undefined_value());
// Make sure that we actually patched the allocation site.
if (FLAG_debug_code) {
__ TestIfSmi(r5, r0);
__ Assert(ne, kExpectedAllocationSite, cr0);
__ push(r5);
__ LoadP(r5, FieldMemOperand(r5, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kAllocationSiteMapRootIndex);
__ cmp(r5, ip);
__ pop(r5);
__ Assert(eq, kExpectedAllocationSite);
}
// Tail call into the stub that handles binary operations with allocation
// sites.
BinaryOpWithAllocationSiteStub stub(isolate(), state());
__ TailCallStub(&stub);
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;

View File

@ -676,8 +676,6 @@ namespace internal {
// Most intrinsics are implemented in the runtime/ directory, but ICs are
// implemented in ic.cc for now.
#define FOR_EACH_INTRINSIC_IC(F) \
F(BinaryOpIC_Miss, 2, 1) \
F(BinaryOpIC_MissWithAllocationSite, 3, 1) \
F(CompareIC_Miss, 3, 1) \
F(ElementsTransitionAndStoreIC_Miss, 6, 1) \
F(KeyedLoadIC_Miss, 4, 1) \

View File

@ -804,10 +804,8 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
CreateWeakCellStub::GenerateAheadOfTime(isolate);
BinaryOpICStub::GenerateAheadOfTime(isolate);
StoreRegistersStateStub::GenerateAheadOfTime(isolate);
RestoreRegistersStateStub::GenerateAheadOfTime(isolate);
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
StoreFastElementStub::GenerateAheadOfTime(isolate);
}
@ -1559,35 +1557,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
__ bne(&loop);
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r3 : left
// -- r2 : right
// r3: second string
// -----------------------------------
// Load r4 with the allocation site. We stick an undefined dummy value here
// and replace it with the real allocation site later when we instantiate this
// stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
__ Move(r4, isolate()->factory()->undefined_value());
// Make sure that we actually patched the allocation site.
if (FLAG_debug_code) {
__ TestIfSmi(r4);
__ Assert(ne, kExpectedAllocationSite, cr0);
__ push(r4);
__ LoadP(r4, FieldMemOperand(r4, HeapObject::kMapOffset));
__ CompareRoot(r4, Heap::kAllocationSiteMapRootIndex);
__ pop(r4);
__ Assert(eq, kExpectedAllocationSite);
}
// Tail call into the stub that handles binary operations with allocation
// sites.
BinaryOpWithAllocationSiteStub stub(isolate(), state());
__ TailCallStub(&stub);
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;

View File

@ -836,8 +836,6 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
CreateWeakCellStub::GenerateAheadOfTime(isolate);
BinaryOpICStub::GenerateAheadOfTime(isolate);
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
StoreFastElementStub::GenerateAheadOfTime(isolate);
}
@ -1404,34 +1402,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rdx : left
// -- rax : right
// -- rsp[0] : return address
// -----------------------------------
// Load rcx with the allocation site. We stick an undefined dummy value here
// and replace it with the real allocation site later when we instantiate this
// stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
__ Move(rcx, isolate()->factory()->undefined_value());
// Make sure that we actually patched the allocation site.
if (FLAG_debug_code) {
__ testb(rcx, Immediate(kSmiTagMask));
__ Assert(not_equal, kExpectedAllocationSite);
__ Cmp(FieldOperand(rcx, HeapObject::kMapOffset),
isolate()->factory()->allocation_site_map());
__ Assert(equal, kExpectedAllocationSite);
}
// Tail call into the stub that handles binary operations with allocation
// sites.
BinaryOpWithAllocationSiteStub stub(isolate(), state());
__ TailCallStub(&stub);
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;

View File

@ -984,8 +984,6 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
CreateWeakCellStub::GenerateAheadOfTime(isolate);
BinaryOpICStub::GenerateAheadOfTime(isolate);
BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
StoreFastElementStub::GenerateAheadOfTime(isolate);
}
@ -1483,34 +1481,6 @@ void StringHelper::GenerateOneByteCharsCompareLoop(
}
void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- edx : left
// -- eax : right
// -- esp[0] : return address
// -----------------------------------
// Load ecx with the allocation site. We stick an undefined dummy value here
// and replace it with the real allocation site later when we instantiate this
// stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
__ mov(ecx, isolate()->factory()->undefined_value());
// Make sure that we actually patched the allocation site.
if (FLAG_debug_code) {
__ test(ecx, Immediate(kSmiTagMask));
__ Assert(not_equal, kExpectedAllocationSite);
__ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
isolate()->factory()->allocation_site_map());
__ Assert(equal, kExpectedAllocationSite);
}
// Tail call into the stub that handles binary operations with allocation
// sites.
BinaryOpWithAllocationSiteStub stub(isolate(), state());
__ TailCallStub(&stub);
}
void CompareICStub::GenerateBooleans(MacroAssembler* masm) {
DCHECK_EQ(CompareICState::BOOLEAN, state());
Label miss;

View File

@ -1150,7 +1150,7 @@ TEST(CodeSerializerLargeCodeObjectWithIncrementalMarking) {
Vector<const uint8_t> source = ConstructSource(
STATIC_CHAR_VECTOR("var j=1; if (j == 0) {"),
STATIC_CHAR_VECTOR("for (var i = 0; i < Object.prototype; i++);"),
STATIC_CHAR_VECTOR("} j=7; var s = 'happy_hippo'; j"), 2100);
STATIC_CHAR_VECTOR("} j=7; var s = 'happy_hippo'; j"), 2200);
Handle<String> source_str =
isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();

View File

@ -93,14 +93,6 @@ code is governed by a BSD-style license that can be found in the LICENSE file.
old_state, new_state));
}
processBinaryOpIC(pc, line, column, stub, old_state, new_state,
allocation_site) {
let fnName = this.functionName(pc);
this.entries.push(new Entry("BinaryOpIc", fnName, line, column, name,
old_state, new_state));
}
processPatchIC(pc, test, delta) {
}

View File

@ -60,10 +60,6 @@ function IcProcessor() {
parsers : [parseInt, parseInt, parseInt, parseInt, null, null, null,
null, null, null, null],
processor: this.processCompareIC },
'BinaryOpIC': {
parsers : [parseInt, parseInt, parseInt, parseInt, null, null,
parseInt],
processor: this.processBinaryOpIC },
'PatchIC': {
parsers : [parseInt, parseInt, parseInt],
processor: this.processPatchIC },
@ -76,7 +72,6 @@ function IcProcessor() {
this.KeyedLoadIC = 0;
this.KeyedStoreIC = 0;
this.CompareIC = 0;
this.BinaryOpIC = 0;
this.PatchIC = 0;
}
inherits(IcProcessor, LogReader);
@ -119,7 +114,6 @@ IcProcessor.prototype.processLogFile = function(fileName) {
print("KeyedLoad: " + this.KeyedLoadIC);
print("KeyedStore: " + this.KeyedStoreIC);
print("CompareIC: " + this.CompareIC);
print("BinaryOpIC: " + this.BinaryOpIC);
print("PatchIC: " + this.PatchIC);
};
@ -187,14 +181,6 @@ IcProcessor.prototype.processCompareIC = function (
this.formatName(entry) + ":" + line + ":" + column);
}
IcProcessor.prototype.processBinaryOpIC = function (
pc, line, column, stub, old_state, new_state, allocation_site) {
var entry = this.profile_.findEntry(pc);
this.BinaryOpIC++;
print("BinaryOpIC (" + old_state + "->" + new_state + ") at " +
this.formatName(entry) + ":" + line + ":" + column);
}
IcProcessor.prototype.processPatchIC = function (pc, test, delta) {
var entry = this.profile_.findEntry(pc);
this.PatchIC++;