}
-void CallICStub::Generate_MonomorphicArray(MacroAssembler* masm, Label* miss) {
+void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
// r1 - function
- // r2 - feedback vector
// r3 - slot id
+ Label miss;
+ int argc = state_.arg_count();
+ ParameterCount actual(argc);
+
+ EmitLoadTypeFeedbackVector(masm, r2);
+
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, r4);
__ cmp(r1, r4);
- __ b(ne, miss);
+ __ b(ne, &miss);
__ mov(r0, Operand(arg_count()));
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
__ AssertUndefinedOrAllocationSite(r2, r4);
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
-}
-
-
-void CallICStub::Generate_CustomFeedbackCall(MacroAssembler* masm) {
- // r1 - function
- // r2 - feedback vector
- // r3 - slot id
- Label miss;
-
- if (state_.stub_type() == CallIC::MONOMORPHIC_ARRAY) {
- Generate_MonomorphicArray(masm, &miss);
- } else {
- // So far there is only one customer for our custom feedback scheme.
- UNREACHABLE();
- }
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, IC::kCallIC_Customization_Miss);
// The slow case, we need this no matter what to complete a call after a miss.
CallFunctionNoFeedback(masm,
EmitLoadTypeFeedbackVector(masm, r2);
- if (state_.stub_type() != CallIC::DEFAULT) {
- Generate_CustomFeedbackCall(masm);
- return;
- }
-
// The checks. First, does r1 match the recorded monomorphic target?
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
__ ldr(r4, FieldMemOperand(r4, FixedArray::kHeaderSize));
// We are here because tracing is on or we are going monomorphic.
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, IC::kCallIC_Miss);
// the slow case
__ bind(&slow_start);
}
-void CallICStub::GenerateMiss(MacroAssembler* masm) {
+void CallICStub::GenerateMiss(MacroAssembler* masm, IC::UtilityId id) {
// Get the receiver of the function from the stack; 1 ~ return address.
__ ldr(r4, MemOperand(sp, (state_.arg_count() + 1) * kPointerSize));
__ Push(r4, r1, r2, r3);
// Call the entry.
- ExternalReference miss = ExternalReference(IC_Utility(IC::kCallIC_Miss),
+ ExternalReference miss = ExternalReference(IC_Utility(id),
masm->isolate());
__ CallExternalReference(miss, 4);
}
-void CallICStub::Generate_MonomorphicArray(MacroAssembler* masm, Label* miss) {
+void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
// x1 - function
- // x2 - feedback vector
// x3 - slot id
+ Label miss;
Register function = x1;
Register feedback_vector = x2;
Register index = x3;
Register scratch = x4;
+ EmitLoadTypeFeedbackVector(masm, feedback_vector);
+
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, scratch);
__ Cmp(function, scratch);
- __ B(ne, miss);
+ __ B(ne, &miss);
Register allocation_site = feedback_vector;
__ Mov(x0, Operand(arg_count()));
__ AssertUndefinedOrAllocationSite(allocation_site, scratch);
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
-}
-
-
-void CallICStub::Generate_CustomFeedbackCall(MacroAssembler* masm) {
- // x1 - function
- // x2 - feedback vector
- // x3 - slot id
- Label miss;
-
- if (state_.stub_type() == CallIC::MONOMORPHIC_ARRAY) {
- Generate_MonomorphicArray(masm, &miss);
- } else {
- // So far there is only one customer for our custom feedback scheme.
- UNREACHABLE();
- }
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, IC::kCallIC_Customization_Miss);
// The slow case, we need this no matter what to complete a call after a miss.
CallFunctionNoFeedback(masm,
EmitLoadTypeFeedbackVector(masm, feedback_vector);
- if (state_.stub_type() != CallIC::DEFAULT) {
- Generate_CustomFeedbackCall(masm);
- return;
- }
-
// The checks. First, does x1 match the recorded monomorphic target?
__ Add(x4, feedback_vector,
Operand::UntagSmiAndScale(index, kPointerSizeLog2));
// We are here because tracing is on or we are going monomorphic.
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, IC::kCallIC_Miss);
// the slow case
__ bind(&slow_start);
}
-void CallICStub::GenerateMiss(MacroAssembler* masm) {
+void CallICStub::GenerateMiss(MacroAssembler* masm, IC::UtilityId id) {
ASM_LOCATION("CallICStub[Miss]");
// Get the receiver of the function from the stack; 1 ~ return address.
__ Push(x4, x1, x2, x3);
// Call the entry.
- ExternalReference miss = ExternalReference(IC_Utility(IC::kCallIC_Miss),
+ ExternalReference miss = ExternalReference(IC_Utility(id),
masm->isolate());
__ CallExternalReference(miss, 4);
}
+void CallIC_ArrayStub::PrintState(StringStream* stream) {
+ state_.Print(stream);
+ stream->Add(" (Array)");
+}
+
+
void CallICStub::PrintState(StringStream* stream) {
state_.Print(stream);
}
V(CompareNilIC) \
V(MathPow) \
V(CallIC) \
+ V(CallIC_Array) \
V(FunctionPrototype) \
V(RecordWrite) \
V(StoreBufferOverflow) \
virtual int MinorKey() { return GetExtraICState(); }
virtual void PrintState(StringStream* stream) V8_FINAL V8_OVERRIDE;
- private:
virtual CodeStub::Major MajorKey() { return CallIC; }
// Code generation helpers.
- void GenerateMiss(MacroAssembler* masm);
- void Generate_CustomFeedbackCall(MacroAssembler* masm);
- void Generate_MonomorphicArray(MacroAssembler* masm, Label* miss);
+ void GenerateMiss(MacroAssembler* masm, IC::UtilityId id);
+
+ const CallIC::State state_;
+};
+
+
+class CallIC_ArrayStub: public CallICStub {
+ public:
+ CallIC_ArrayStub(Isolate* isolate, const CallIC::State& state_in)
+ : CallICStub(isolate, state_in) {}
+
+ virtual void Generate(MacroAssembler* masm);
+
+ protected:
+ virtual void PrintState(StringStream* stream) V8_FINAL V8_OVERRIDE;
- CallIC::State state_;
+ virtual CodeStub::Major MajorKey() { return CallIC_Array; }
};
}
-void CallICStub::Generate_MonomorphicArray(MacroAssembler* masm, Label* miss) {
+void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
// edi - function
- // ebx - feedback vector
// edx - slot id
+ Label miss;
+ int argc = state_.arg_count();
+ ParameterCount actual(argc);
+
+ EmitLoadTypeFeedbackVector(masm, ebx);
+
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, ecx);
__ cmp(edi, ecx);
- __ j(not_equal, miss);
+ __ j(not_equal, &miss);
__ mov(eax, arg_count());
__ mov(ebx, FieldOperand(ebx, edx, times_half_pointer_size,
__ AssertUndefinedOrAllocationSite(ebx);
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
-}
-
-
-void CallICStub::Generate_CustomFeedbackCall(MacroAssembler* masm) {
- // edi - function
- // ebx - feedback vector
- // edx - slot id
- Label miss;
-
- if (state_.stub_type() == CallIC::MONOMORPHIC_ARRAY) {
- Generate_MonomorphicArray(masm, &miss);
- } else {
- // So far there is only one customer for our custom feedback scheme.
- UNREACHABLE();
- }
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, IC::kCallIC_Customization_Miss);
// The slow case, we need this no matter what to complete a call after a miss.
CallFunctionNoFeedback(masm,
EmitLoadTypeFeedbackVector(masm, ebx);
- if (state_.stub_type() != CallIC::DEFAULT) {
- Generate_CustomFeedbackCall(masm);
- return;
- }
-
// The checks. First, does edi match the recorded monomorphic target?
__ cmp(edi, FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize));
// We are here because tracing is on or we are going monomorphic.
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, IC::kCallIC_Miss);
// the slow case
__ bind(&slow_start);
}
-void CallICStub::GenerateMiss(MacroAssembler* masm) {
+void CallICStub::GenerateMiss(MacroAssembler* masm, IC::UtilityId id) {
// Get the receiver of the function from the stack; 1 ~ return address.
__ mov(ecx, Operand(esp, (state_.arg_count() + 1) * kPointerSize));
__ push(edx);
// Call the entry.
- ExternalReference miss = ExternalReference(IC_Utility(IC::kCallIC_Miss),
+ ExternalReference miss = ExternalReference(IC_Utility(id),
masm->isolate());
__ CallExternalReference(miss, 4);
Code* target,
ConstantPoolArray* constant_pool) {
// Currently, CallIC doesn't have state changes.
- if (target->ic_state() != v8::internal::MONOMORPHIC) return;
- CallIC::State existing_state(target->extra_ic_state());
-
- // Monomorphic array stubs don't need to be cleared because
- // 1) the stub doesn't store information that should be cleared, and
- // 2) the AllocationSite stored in the type feedback vector is immune
- // from gc type feedback clearing.
- ASSERT(existing_state.stub_type() == MONOMORPHIC_ARRAY);
}
Handle<Code> CallIC::initialize_stub(Isolate* isolate,
int argc,
CallType call_type) {
- CallICStub stub(isolate, State::DefaultCallState(argc, call_type));
+ CallICStub stub(isolate, State(argc, call_type));
Handle<Code> code = stub.GetCode();
return code;
}
CallIC::State::State(ExtraICState extra_ic_state)
: argc_(ArgcBits::decode(extra_ic_state)),
- call_type_(CallTypeBits::decode(extra_ic_state)),
- stub_type_(StubTypeBits::decode(extra_ic_state)) {
+ call_type_(CallTypeBits::decode(extra_ic_state)) {
}
ExtraICState CallIC::State::GetExtraICState() const {
ExtraICState extra_ic_state =
ArgcBits::encode(argc_) |
- CallTypeBits::encode(call_type_) |
- StubTypeBits::encode(stub_type_);
+ CallTypeBits::encode(call_type_);
return extra_ic_state;
}
// Alter the slot.
Handle<AllocationSite> new_site = isolate()->factory()->NewAllocationSite();
vector->set(slot->value(), *new_site);
- State new_state = state.ToMonomorphicArrayCallState();
- CallICStub stub(isolate(), new_state);
+ CallIC_ArrayStub stub(isolate(), state);
set_target(*stub.GetCode());
Handle<String> name;
if (array_function->shared()->name()->IsString()) {
}
+void CallIC::PatchMegamorphic(Handle<FixedArray> vector,
+ Handle<Smi> slot) {
+ State state(target()->extra_ic_state());
+
+ // We are going generic.
+ vector->set(slot->value(),
+ *TypeFeedbackInfo::MegamorphicSentinel(isolate()),
+ SKIP_WRITE_BARRIER);
+
+ CallICStub stub(isolate(), state);
+ Handle<Code> code = stub.GetCode();
+ set_target(*code);
+
+ TRACE_GENERIC_IC(isolate(), "CallIC", "megamorphic");
+}
+
+
void CallIC::HandleMiss(Handle<Object> receiver,
Handle<Object> function,
Handle<FixedArray> vector,
State state(target()->extra_ic_state());
Object* feedback = vector->get(slot->value());
- if (feedback->IsJSFunction() || !function->IsJSFunction() ||
- state.stub_type() != DEFAULT) {
+ if (feedback->IsJSFunction() || !function->IsJSFunction()) {
// We are going generic.
vector->set(slot->value(),
*TypeFeedbackInfo::MegamorphicSentinel(isolate()),
SKIP_WRITE_BARRIER);
- State new_state = state.ToGenericState();
- if (new_state != state) {
- // Only happens when the array ic goes generic.
- ASSERT(state.stub_type() == MONOMORPHIC_ARRAY &&
- FLAG_use_ic);
- CallICStub stub(isolate(), new_state);
- Handle<Code> code = stub.GetCode();
- set_target(*code);
- }
-
TRACE_GENERIC_IC(isolate(), "CallIC", "megamorphic");
} else {
// If we came here feedback must be the uninitialized sentinel,
}
+RUNTIME_FUNCTION(CallIC_Customization_Miss) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 4);
+ // A miss on a custom call ic always results in going megamorphic.
+ CallIC ic(isolate);
+ Handle<Object> function = args.at<Object>(1);
+ Handle<FixedArray> vector = args.at<FixedArray>(2);
+ Handle<Smi> slot = args.at<Smi>(3);
+ ic.PatchMegamorphic(vector, slot);
+ return *function;
+}
+
+
// Used from ic-<arch>.cc.
RUNTIME_FUNCTION(LoadIC_Miss) {
HandleScope scope(isolate);
ICU(LoadIC_Miss) \
ICU(KeyedLoadIC_Miss) \
ICU(CallIC_Miss) \
+ ICU(CallIC_Customization_Miss) \
ICU(StoreIC_Miss) \
ICU(StoreIC_ArrayLength) \
ICU(StoreIC_Slow) \
class CallIC: public IC {
public:
enum CallType { METHOD, FUNCTION };
- enum StubType { DEFAULT, MONOMORPHIC_ARRAY };
class State V8_FINAL BASE_EMBEDDED {
public:
explicit State(ExtraICState extra_ic_state);
- static State MonomorphicArrayCallState(int argc, CallType call_type) {
- return State(argc, call_type, MONOMORPHIC_ARRAY);
+ State(int argc, CallType call_type)
+ : argc_(argc), call_type_(call_type) {
}
- static State DefaultCallState(int argc, CallType call_type) {
- return State(argc, call_type, DEFAULT);
- }
-
- // Transition from the current state to another.
- State ToGenericState() const {
- return DefaultCallState(arg_count(), call_type());
- }
-
- State ToMonomorphicArrayCallState() const {
- return MonomorphicArrayCallState(arg_count(), call_type());
- }
-
- InlineCacheState GetICState() const {
- return stub_type_ == CallIC::DEFAULT
- ? ::v8::internal::GENERIC
- : ::v8::internal::MONOMORPHIC;
- }
+ InlineCacheState GetICState() const { return ::v8::internal::GENERIC; }
ExtraICState GetExtraICState() const;
int arg_count() const { return argc_; }
CallType call_type() const { return call_type_; }
- StubType stub_type() const { return stub_type_; }
bool CallAsMethod() const { return call_type_ == METHOD; }
void Print(StringStream* stream) const;
- bool operator==(const State& other_state) const {
- return (argc_ == other_state.argc_ &&
- call_type_ == other_state.call_type_ &&
- stub_type_ == other_state.stub_type_);
- }
-
- bool operator!=(const State& other_state) const {
- return !(*this == other_state);
- }
-
private:
- State(int argc, CallType call_type, StubType stub_type)
- : argc_(argc),
- call_type_(call_type),
- stub_type_(stub_type) {
- }
-
class ArgcBits: public BitField<int, 0, Code::kArgumentsBits> {};
class CallTypeBits: public BitField<CallType, Code::kArgumentsBits, 1> {};
- class StubTypeBits:
- public BitField<StubType, Code::kArgumentsBits + 1, 1> {}; // NOLINT
const int argc_;
const CallType call_type_;
- const StubType stub_type_;
};
explicit CallIC(Isolate* isolate)
: IC(EXTRA_CALL_FRAME, isolate) {
}
+ void PatchMegamorphic(Handle<FixedArray> vector, Handle<Smi> slot);
+
void HandleMiss(Handle<Object> receiver,
Handle<Object> function,
Handle<FixedArray> vector,
Handle<Object> function,
Handle<FixedArray> vector,
Handle<Smi> slot,
- const State& new_state);
+ const State& state);
// Code generator routines.
static Handle<Code> initialize_stub(Isolate* isolate,
}
-void CallICStub::Generate_MonomorphicArray(MacroAssembler* masm, Label* miss) {
+void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
// a1 - function
- // a2 - feedback vector
// a3 - slot id
+ Label miss;
+
+ EmitLoadTypeFeedbackVector(masm, a2);
+
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, at);
- __ Branch(miss, ne, a1, Operand(at));
+ __ Branch(&miss, ne, a1, Operand(at));
__ li(a0, Operand(arg_count()));
__ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
__ AssertUndefinedOrAllocationSite(a2, at);
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
-}
-
-
-void CallICStub::Generate_CustomFeedbackCall(MacroAssembler* masm) {
- // a1 - function
- // a2 - feedback vector
- // a3 - slot id
- Label miss;
-
- if (state_.stub_type() == CallIC::MONOMORPHIC_ARRAY) {
- Generate_MonomorphicArray(masm, &miss);
- } else {
- // So far there is only one customer for our custom feedback scheme.
- UNREACHABLE();
- }
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, IC::kCallIC_Customization_Miss);
// The slow case, we need this no matter what to complete a call after a miss.
CallFunctionNoFeedback(masm,
EmitLoadTypeFeedbackVector(masm, a2);
- if (state_.stub_type() != CallIC::DEFAULT) {
- Generate_CustomFeedbackCall(masm);
- return;
- }
-
// The checks. First, does r1 match the recorded monomorphic target?
__ sll(t0, a3, kPointerSizeLog2 - kSmiTagSize);
__ Addu(t0, a2, Operand(t0));
// We are here because tracing is on or we are going monomorphic.
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, IC::kCallIC_Miss);
// the slow case
__ bind(&slow_start);
}
-void CallICStub::GenerateMiss(MacroAssembler* masm) {
+void CallICStub::GenerateMiss(MacroAssembler* masm, IC::UtilityId id) {
// Get the receiver of the function from the stack; 1 ~ return address.
__ lw(t0, MemOperand(sp, (state_.arg_count() + 1) * kPointerSize));
__ Push(t0, a1, a2, a3);
// Call the entry.
- ExternalReference miss = ExternalReference(IC_Utility(IC::kCallIC_Miss),
+ ExternalReference miss = ExternalReference(IC_Utility(id),
masm->isolate());
__ CallExternalReference(miss, 4);
}
-void CallICStub::Generate_MonomorphicArray(MacroAssembler* masm, Label* miss) {
+void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
// rdi - function
- // rbx - feedback vector
// rdx - slot id (as integer)
+ Label miss;
+ int argc = state_.arg_count();
+ ParameterCount actual(argc);
+
+ EmitLoadTypeFeedbackVector(masm, rbx);
+ __ SmiToInteger32(rdx, rdx);
+
__ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, rcx);
__ cmpq(rdi, rcx);
- __ j(not_equal, miss);
+ __ j(not_equal, &miss);
__ movq(rax, Immediate(arg_count()));
__ movp(rbx, FieldOperand(rbx, rdx, times_pointer_size,
__ AssertUndefinedOrAllocationSite(rbx);
ArrayConstructorStub stub(masm->isolate(), arg_count());
__ TailCallStub(&stub);
-}
-
-
-void CallICStub::Generate_CustomFeedbackCall(MacroAssembler* masm) {
- // rdi - function
- // rbx - feedback vector
- // rdx - slot id
- Label miss;
-
- __ SmiToInteger32(rdx, rdx);
-
- if (state_.stub_type() == CallIC::MONOMORPHIC_ARRAY) {
- Generate_MonomorphicArray(masm, &miss);
- } else {
- // So far there is only one customer for our custom feedback scheme.
- UNREACHABLE();
- }
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, IC::kCallIC_Customization_Miss);
// The slow case, we need this no matter what to complete a call after a miss.
CallFunctionNoFeedback(masm,
EmitLoadTypeFeedbackVector(masm, rbx);
- if (state_.stub_type() != CallIC::DEFAULT) {
- Generate_CustomFeedbackCall(masm);
- return;
- }
-
// The checks. First, does rdi match the recorded monomorphic target?
__ SmiToInteger32(rdx, rdx);
__ cmpq(rdi, FieldOperand(rbx, rdx, times_pointer_size,
// We are here because tracing is on or we are going monomorphic.
__ bind(&miss);
- GenerateMiss(masm);
+ GenerateMiss(masm, IC::kCallIC_Miss);
// the slow case
__ bind(&slow_start);
}
-void CallICStub::GenerateMiss(MacroAssembler* masm) {
+void CallICStub::GenerateMiss(MacroAssembler* masm, IC::UtilityId id) {
// Get the receiver of the function from the stack; 1 ~ return address.
__ movp(rcx, Operand(rsp, (state_.arg_count() + 1) * kPointerSize));
__ Push(rdx);
// Call the entry.
- ExternalReference miss = ExternalReference(IC_Utility(IC::kCallIC_Miss),
+ ExternalReference miss = ExternalReference(IC_Utility(id),
masm->isolate());
__ CallExternalReference(miss, 4);