[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:
parent
baa4d4faea
commit
e6c2df47e1
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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, ¬_minus_zero);
|
||||
__ Eor(x11, left, right);
|
||||
__ Tbnz(x11, kXSignBit, &stub_call);
|
||||
__ Mov(result, x10);
|
||||
__ B(&done);
|
||||
__ Bind(¬_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: {
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
163
src/ic/ic.cc
163
src/ic/ic.cc
@ -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,
|
||||
|
14
src/ic/ic.h
14
src/ic/ic.h
@ -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);
|
||||
|
17
src/log.cc
17
src/log.cc
@ -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:
|
||||
|
@ -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. ====
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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) {
|
||||
|
||||
}
|
||||
|
@ -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++;
|
||||
|
Loading…
Reference in New Issue
Block a user