__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
__ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex);
__ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
+ // We have to update statistics for runtime profiling.
+ const int with_types_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+ __ ldr(r4, FieldMemOperand(r2, with_types_offset));
+ __ sub(r4, r4, Operand(Smi::FromInt(1)));
+ __ str(r4, FieldMemOperand(r2, with_types_offset));
+ const int generic_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
+ __ ldr(r4, FieldMemOperand(r2, generic_offset));
+ __ add(r4, r4, Operand(Smi::FromInt(1)));
+ __ str(r4, FieldMemOperand(r2, generic_offset));
__ jmp(&slow_start);
}
__ Move(r1, FeedbackVector());
__ mov(r2, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate())));
- __ str(r2, FieldMemOperand(r1, FixedArray::OffsetOfElementAt(slot.ToInt())));
+ int vector_index = FeedbackVector()->GetIndex(slot);
+ __ str(r2, FieldMemOperand(r1, FixedArray::OffsetOfElementAt(vector_index)));
__ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check
__ ldr(r2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object
template <class T>
void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
DCHECK(FLAG_vector_ics);
- Register vector = ToRegister(instr->temp_vector());
- DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
- __ Move(vector, instr->hydrogen()->feedback_vector());
+ Register vector_register = ToRegister(instr->temp_vector());
+ DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+ Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+ __ Move(vector_register, vector);
// No need to allocate this register.
DCHECK(VectorLoadICDescriptor::SlotRegister().is(r0));
- __ mov(VectorLoadICDescriptor::SlotRegister(),
- Operand(Smi::FromInt(instr->hydrogen()->slot().ToInt())));
+ int index = vector->GetIndex(instr->hydrogen()->slot());
+ __ mov(VectorLoadICDescriptor::SlotRegister(), Operand(Smi::FromInt(index)));
}
Operand::UntagSmiAndScale(index, kPointerSizeLog2));
__ LoadRoot(x5, Heap::kmegamorphic_symbolRootIndex);
__ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize));
+ // We have to update statistics for runtime profiling.
+ const int with_types_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+ __ Ldr(x4, FieldMemOperand(feedback_vector, with_types_offset));
+ __ Subs(x4, x4, Operand(Smi::FromInt(1)));
+ __ Str(x4, FieldMemOperand(feedback_vector, with_types_offset));
+ const int generic_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
+ __ Ldr(x4, FieldMemOperand(feedback_vector, generic_offset));
+ __ Adds(x4, x4, Operand(Smi::FromInt(1)));
+ __ Str(x4, FieldMemOperand(feedback_vector, generic_offset));
__ B(&slow_start);
}
__ LoadObject(x1, FeedbackVector());
__ Mov(x10, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate())));
- __ Str(x10, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(slot.ToInt())));
+ int vector_index = FeedbackVector()->GetIndex(slot);
+ __ Str(x10, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(vector_index)));
__ Mov(x1, Smi::FromInt(1)); // Smi indicates slow check.
__ Peek(x10, 0); // Get enumerated object.
template <class T>
void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
DCHECK(FLAG_vector_ics);
- Register vector = ToRegister(instr->temp_vector());
- DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
- __ Mov(vector, instr->hydrogen()->feedback_vector());
+ Register vector_register = ToRegister(instr->temp_vector());
+ DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+ Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+ __ Mov(vector_register, vector);
// No need to allocate this register.
DCHECK(VectorLoadICDescriptor::SlotRegister().is(x0));
- __ Mov(VectorLoadICDescriptor::SlotRegister(),
- Smi::FromInt(instr->hydrogen()->slot().ToInt()));
+ int index = vector->GetIndex(instr->hydrogen()->slot());
+ __ Mov(VectorLoadICDescriptor::SlotRegister(), Smi::FromInt(index));
}
is_this_(var->is_this()),
is_assigned_(false),
is_resolved_(false),
- variable_feedback_slot_(FeedbackVectorSlot::Invalid()),
+ variable_feedback_slot_(FeedbackVectorICSlot::Invalid()),
raw_name_(var->raw_name()),
interface_(var->interface()) {
BindTo(var);
is_this_(is_this),
is_assigned_(false),
is_resolved_(false),
- variable_feedback_slot_(FeedbackVectorSlot::Invalid()),
+ variable_feedback_slot_(FeedbackVectorICSlot::Invalid()),
raw_name_(name),
interface_(interface) {}
};
+class FeedbackVectorRequirements {
+ public:
+ FeedbackVectorRequirements(int slots, int ic_slots)
+ : slots_(slots), ic_slots_(ic_slots) {}
+
+ int slots() const { return slots_; }
+ int ic_slots() const { return ic_slots_; }
+
+ private:
+ int slots_;
+ int ic_slots_;
+};
+
+
class AstProperties FINAL BASE_EMBEDDED {
public:
class Flags : public EnumSet<AstPropertiesFlag, int> {};
-AstProperties() : node_count_(0), feedback_slots_(0) {}
+ AstProperties() : node_count_(0), feedback_slots_(0), ic_feedback_slots_(0) {}
Flags* flags() { return &flags_; }
int node_count() { return node_count_; }
feedback_slots_ += count;
}
+ int ic_feedback_slots() const { return ic_feedback_slots_; }
+ void increase_ic_feedback_slots(int count) { ic_feedback_slots_ += count; }
+
private:
Flags flags_;
int node_count_;
int feedback_slots_;
+ int ic_feedback_slots_;
};
// node types which don't actually have this. Note that this is conceptually
// not really nice, but multiple inheritance would introduce yet another
// vtable entry per node, something we don't want for space reasons.
- virtual int ComputeFeedbackSlotCount() {
- UNREACHABLE();
- return 0;
+ virtual FeedbackVectorRequirements ComputeFeedbackRequirements() {
+ return FeedbackVectorRequirements(0, 0);
}
virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) { UNREACHABLE(); }
+ virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) {
+ UNREACHABLE();
+ }
private:
// Hidden to prevent accidental usage. It would have to load the
}
// Type feedback information.
- virtual int ComputeFeedbackSlotCount() { return 1; }
+ virtual FeedbackVectorRequirements ComputeFeedbackRequirements() {
+ return FeedbackVectorRequirements(1, 0);
+ }
virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) {
for_in_feedback_slot_ = slot;
}
// Bind this proxy to the variable var. Interfaces must match.
void BindTo(Variable* var);
- virtual int ComputeFeedbackSlotCount() { return FLAG_vector_ics ? 1 : 0; }
- virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) {
+ virtual FeedbackVectorRequirements ComputeFeedbackRequirements() {
+ return FeedbackVectorRequirements(0, FLAG_vector_ics ? 1 : 0);
+ }
+ virtual void SetFirstICFeedbackSlot(FeedbackVectorICSlot slot) {
variable_feedback_slot_ = slot;
}
- FeedbackVectorSlot VariableFeedbackSlot() { return variable_feedback_slot_; }
+ FeedbackVectorICSlot VariableFeedbackSlot() {
+ return variable_feedback_slot_;
+ }
protected:
VariableProxy(Zone* zone, Variable* var, int position, IdGen* id_gen);
bool is_this_ : 1;
bool is_assigned_ : 1;
bool is_resolved_ : 1;
- FeedbackVectorSlot variable_feedback_slot_;
+ FeedbackVectorICSlot variable_feedback_slot_;
union {
const AstRawString* raw_name_; // if !is_resolved_
Variable* var_; // if is_resolved_
return obj()->IsSuperReference();
}
- virtual int ComputeFeedbackSlotCount() { return FLAG_vector_ics ? 1 : 0; }
- virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) {
+ virtual FeedbackVectorRequirements ComputeFeedbackRequirements() {
+ return FeedbackVectorRequirements(0, FLAG_vector_ics ? 1 : 0);
+ }
+ virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) {
property_feedback_slot_ = slot;
}
- FeedbackVectorSlot PropertyFeedbackSlot() const {
+ FeedbackVectorICSlot PropertyFeedbackSlot() const {
return property_feedback_slot_;
}
is_for_call_(false),
is_uninitialized_(false),
is_string_access_(false),
- property_feedback_slot_(FeedbackVectorSlot::Invalid()),
+ property_feedback_slot_(FeedbackVectorICSlot::Invalid()),
obj_(obj),
key_(key) {}
bool is_for_call_ : 1;
bool is_uninitialized_ : 1;
bool is_string_access_ : 1;
- FeedbackVectorSlot property_feedback_slot_;
+ FeedbackVectorICSlot property_feedback_slot_;
Expression* obj_;
Expression* key_;
SmallMapList receiver_types_;
ZoneList<Expression*>* arguments() const { return arguments_; }
// Type feedback information.
- virtual int ComputeFeedbackSlotCount() { return 1; }
- virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) {
+ virtual FeedbackVectorRequirements ComputeFeedbackRequirements() {
+ return FeedbackVectorRequirements(0, 1);
+ }
+ virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) {
call_feedback_slot_ = slot;
}
bool HasCallFeedbackSlot() const { return !call_feedback_slot_.IsInvalid(); }
- FeedbackVectorSlot CallFeedbackSlot() const { return call_feedback_slot_; }
+ FeedbackVectorICSlot CallFeedbackSlot() const { return call_feedback_slot_; }
virtual SmallMapList* GetReceiverTypes() OVERRIDE {
if (expression()->IsProperty()) {
Call(Zone* zone, Expression* expression, ZoneList<Expression*>* arguments,
int pos, IdGen* id_gen)
: Expression(zone, pos, num_ids(), id_gen),
- call_feedback_slot_(FeedbackVectorSlot::Invalid()),
+ call_feedback_slot_(FeedbackVectorICSlot::Invalid()),
expression_(expression),
arguments_(arguments) {
if (expression->IsProperty()) {
int base_id() const { return Expression::base_id() + Expression::num_ids(); }
private:
- FeedbackVectorSlot call_feedback_slot_;
+ FeedbackVectorICSlot call_feedback_slot_;
Expression* expression_;
ZoneList<Expression*>* arguments_;
Handle<JSFunction> target_;
ZoneList<Expression*>* arguments() const { return arguments_; }
// Type feedback information.
- virtual int ComputeFeedbackSlotCount() {
- return FLAG_pretenuring_call_new ? 2 : 1;
+ virtual FeedbackVectorRequirements ComputeFeedbackRequirements() {
+ return FeedbackVectorRequirements(FLAG_pretenuring_call_new ? 2 : 1, 0);
}
virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) {
callnew_feedback_slot_ = slot;
bool is_jsruntime() const { return function_ == NULL; }
// Type feedback information.
- virtual int ComputeFeedbackSlotCount() {
- return (FLAG_vector_ics && is_jsruntime()) ? 1 : 0;
+ virtual FeedbackVectorRequirements ComputeFeedbackRequirements() {
+ return FeedbackVectorRequirements(
+ 0, (FLAG_vector_ics && is_jsruntime()) ? 1 : 0);
}
- virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) {
+ virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) {
callruntime_feedback_slot_ = slot;
}
- FeedbackVectorSlot CallRuntimeFeedbackSlot() {
+ FeedbackVectorICSlot CallRuntimeFeedbackSlot() {
return callruntime_feedback_slot_;
}
raw_name_(name),
function_(function),
arguments_(arguments),
- callruntime_feedback_slot_(FeedbackVectorSlot::Invalid()) {}
+ callruntime_feedback_slot_(FeedbackVectorICSlot::Invalid()) {}
static int num_ids() { return 1; }
int base_id() const { return Expression::base_id() + Expression::num_ids(); }
const AstRawString* raw_name_;
const Runtime::Function* function_;
ZoneList<Expression*>* arguments_;
- FeedbackVectorSlot callruntime_feedback_slot_;
+ FeedbackVectorICSlot callruntime_feedback_slot_;
};
}
// Type feedback information.
- virtual int ComputeFeedbackSlotCount() {
- return (FLAG_vector_ics && yield_kind() == kDelegating) ? 3 : 0;
+ virtual FeedbackVectorRequirements ComputeFeedbackRequirements() {
+ return FeedbackVectorRequirements(
+ 0, (FLAG_vector_ics && yield_kind() == kDelegating) ? 3 : 0);
}
- virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) {
+ virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) {
yield_first_feedback_slot_ = slot;
}
- FeedbackVectorSlot KeyedLoadFeedbackSlot() {
+ FeedbackVectorICSlot KeyedLoadFeedbackSlot() {
return yield_first_feedback_slot_;
}
- FeedbackVectorSlot DoneFeedbackSlot() {
+ FeedbackVectorICSlot DoneFeedbackSlot() {
return KeyedLoadFeedbackSlot().next();
}
- FeedbackVectorSlot ValueFeedbackSlot() { return DoneFeedbackSlot().next(); }
+ FeedbackVectorICSlot ValueFeedbackSlot() { return DoneFeedbackSlot().next(); }
protected:
Yield(Zone* zone, Expression* generator_object, Expression* expression,
expression_(expression),
yield_kind_(yield_kind),
index_(-1),
- yield_first_feedback_slot_(FeedbackVectorSlot::Invalid()) {}
+ yield_first_feedback_slot_(FeedbackVectorICSlot::Invalid()) {}
private:
Expression* generator_object_;
Expression* expression_;
Kind yield_kind_;
int index_;
- FeedbackVectorSlot yield_first_feedback_slot_;
+ FeedbackVectorICSlot yield_first_feedback_slot_;
};
int slot_count() {
return ast_properties_.feedback_slots();
}
+ int ic_slot_count() { return ast_properties_.ic_feedback_slots(); }
bool dont_optimize() { return dont_optimize_reason_ != kNoReason; }
BailoutReason dont_optimize_reason() { return dont_optimize_reason_; }
void set_dont_optimize_reason(BailoutReason reason) {
}
// Type feedback information.
- virtual int ComputeFeedbackSlotCount() { return FLAG_vector_ics ? 1 : 0; }
- virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) {
+ virtual FeedbackVectorRequirements ComputeFeedbackRequirements() {
+ return FeedbackVectorRequirements(0, FLAG_vector_ics ? 1 : 0);
+ }
+ virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) {
homeobject_feedback_slot_ = slot;
}
- FeedbackVectorSlot HomeObjectFeedbackSlot() {
+ FeedbackVectorICSlot HomeObjectFeedbackSlot() {
DCHECK(!FLAG_vector_ics || !homeobject_feedback_slot_.IsInvalid());
return homeobject_feedback_slot_;
}
SuperReference(Zone* zone, VariableProxy* this_var, int pos, IdGen* id_gen)
: Expression(zone, pos, num_ids(), id_gen),
this_var_(this_var),
- homeobject_feedback_slot_(FeedbackVectorSlot::Invalid()) {
+ homeobject_feedback_slot_(FeedbackVectorICSlot::Invalid()) {
DCHECK(this_var->is_this());
}
private:
VariableProxy* this_var_;
- FeedbackVectorSlot homeobject_feedback_slot_;
+ FeedbackVectorICSlot homeobject_feedback_slot_;
};
}
void add_slot_node(AstNode* slot_node) {
- int count = slot_node->ComputeFeedbackSlotCount();
- if (count > 0) {
+ FeedbackVectorRequirements reqs = slot_node->ComputeFeedbackRequirements();
+ if (reqs.slots() > 0) {
slot_node->SetFirstFeedbackSlot(
FeedbackVectorSlot(properties_.feedback_slots()));
- properties_.increase_feedback_slots(count);
+ properties_.increase_feedback_slots(reqs.slots());
+ }
+ if (reqs.ic_slots() > 0) {
+ slot_node->SetFirstFeedbackICSlot(
+ FeedbackVectorICSlot(properties_.ic_feedback_slots()));
+ properties_.increase_ic_feedback_slots(reqs.ic_slots());
}
}
// Apply embeds an IC, so we need a type vector of size 1 in the shared
// function info.
Handle<TypeFeedbackVector> feedback_vector =
- factory()->NewTypeFeedbackVector(1);
+ factory()->NewTypeFeedbackVector(0, 1);
apply->shared()->set_feedback_vector(*feedback_vector);
}
DCHECK(scope_ == NULL);
scope_ = scope;
- int length = function()->slot_count();
if (feedback_vector_.is_null()) {
// Allocate the feedback vector too.
- feedback_vector_ = isolate()->factory()->NewTypeFeedbackVector(length);
+ feedback_vector_ = isolate()->factory()->NewTypeFeedbackVector(
+ function()->slot_count(), function()->ic_slot_count());
}
- DCHECK(feedback_vector_->length() == length);
+ DCHECK(feedback_vector_->Slots() == function()->slot_count() &&
+ feedback_vector_->ICSlots() == function()->ic_slot_count());
}
VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
- FeedbackVectorSlot slot) const {
+ FeedbackVectorICSlot slot) const {
return VectorSlotPair(handle(info()->shared_info()->feedback_vector()), slot);
}
inline Scope* current_scope() const;
// Named and keyed loads require a VectorSlotPair for successful lowering.
- VectorSlotPair CreateVectorSlotPair(FeedbackVectorSlot slot) const;
+ VectorSlotPair CreateVectorSlotPair(FeedbackVectorICSlot slot) const;
// Process arguments to a call by popping {arity} elements off the operand
// stack and build a call node using the given call operator.
class VectorSlotPair {
public:
- VectorSlotPair(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
+ VectorSlotPair(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
: vector_(vector), slot_(slot) {}
Handle<TypeFeedbackVector> vector() const { return vector_; }
- FeedbackVectorSlot slot() const { return slot_; }
+ FeedbackVectorICSlot slot() const { return slot_; }
private:
const Handle<TypeFeedbackVector> vector_;
- const FeedbackVectorSlot slot_;
+ const FeedbackVectorICSlot slot_;
};
}
-Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(int slot_count) {
- // Ensure we can skip the write barrier
- DCHECK_EQ(isolate()->heap()->uninitialized_symbol(),
- *TypeFeedbackVector::UninitializedSentinel(isolate()));
-
- if (slot_count == 0) {
- return Handle<TypeFeedbackVector>::cast(empty_fixed_array());
- }
-
- CALL_HEAP_FUNCTION(isolate(),
- isolate()->heap()->AllocateFixedArrayWithFiller(
- slot_count, TENURED,
- *TypeFeedbackVector::UninitializedSentinel(isolate())),
- TypeFeedbackVector);
+Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(int slot_count,
+ int ic_slot_count) {
+ return TypeFeedbackVector::Allocate(isolate(), slot_count, ic_slot_count);
}
share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_debug_info(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_inferred_name(*empty_string(), SKIP_WRITE_BARRIER);
- Handle<TypeFeedbackVector> feedback_vector = NewTypeFeedbackVector(0);
+ Handle<TypeFeedbackVector> feedback_vector = NewTypeFeedbackVector(0, 0);
share->set_feedback_vector(*feedback_vector, SKIP_WRITE_BARRIER);
share->set_profiler_ticks(0);
share->set_ast_node_count(0);
MaybeHandle<Code> code);
// Allocate a new type feedback vector
- Handle<TypeFeedbackVector> NewTypeFeedbackVector(int slot_count);
+ Handle<TypeFeedbackVector> NewTypeFeedbackVector(int slot_count,
+ int ic_slot_count);
// Allocates a new JSMessageObject object.
Handle<JSMessageObject> NewJSMessageObject(
void FullCodeGenerator::EnsureSlotContainsAllocationSite(
FeedbackVectorSlot slot) {
- Handle<FixedArray> vector = FeedbackVector();
- if (!vector->get(slot.ToInt())->IsAllocationSite()) {
+ Handle<TypeFeedbackVector> vector = FeedbackVector();
+ if (!vector->Get(slot)->IsAllocationSite()) {
Handle<AllocationSite> allocation_site =
isolate()->factory()->NewAllocationSite();
- vector->set(slot.ToInt(), *allocation_site);
+ vector->Set(slot, *allocation_site);
+ }
+}
+
+
+void FullCodeGenerator::EnsureSlotContainsAllocationSite(
+ FeedbackVectorICSlot slot) {
+ Handle<TypeFeedbackVector> vector = FeedbackVector();
+ if (!vector->Get(slot)->IsAllocationSite()) {
+ Handle<AllocationSite> allocation_site =
+ isolate()->factory()->NewAllocationSite();
+ vector->Set(slot, *allocation_site);
}
}
// Feedback slot support. The feedback vector will be cleared during gc and
// collected by the type-feedback oracle.
- Handle<FixedArray> FeedbackVector() {
+ Handle<TypeFeedbackVector> FeedbackVector() const {
return info_->feedback_vector();
}
void EnsureSlotContainsAllocationSite(FeedbackVectorSlot slot);
+ void EnsureSlotContainsAllocationSite(FeedbackVectorICSlot slot);
+
+ // Returns a smi for the index into the FixedArray that backs the feedback
+ // vector
Smi* SmiFromSlot(FeedbackVectorSlot slot) const {
- return Smi::FromInt(slot.ToInt());
+ return Smi::FromInt(FeedbackVector()->GetIndex(slot));
+ }
+
+ Smi* SmiFromSlot(FeedbackVectorICSlot slot) const {
+ return Smi::FromInt(FeedbackVector()->GetIndex(slot));
}
// Record a call's return site offset, used to rebuild the frame if the
// when they might be keeping a Context alive, or when the heap is about
// to be serialized.
if (FLAG_cleanup_code_caches_at_gc && target->is_inline_cache_stub() &&
+ !target->is_call_stub() &&
(target->ic_state() == MEGAMORPHIC || target->ic_state() == GENERIC ||
target->ic_state() == POLYMORPHIC ||
(heap->flush_monomorphic_ics() && !target->is_weak_stub()) ||
HValue* global_object() { return OperandAt(1); }
Handle<String> name() const { return name_; }
bool for_typeof() const { return for_typeof_; }
- FeedbackVectorSlot slot() const {
+ FeedbackVectorICSlot slot() const {
DCHECK(FLAG_vector_ics && !slot_.IsInvalid());
return slot_;
}
- Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
- void SetVectorAndSlot(Handle<FixedArray> vector, FeedbackVectorSlot slot) {
+ Handle<TypeFeedbackVector> feedback_vector() const {
+ return feedback_vector_;
+ }
+ void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
+ FeedbackVectorICSlot slot) {
DCHECK(FLAG_vector_ics);
feedback_vector_ = vector;
slot_ = slot;
Handle<String> name, bool for_typeof)
: name_(name),
for_typeof_(for_typeof),
- slot_(FeedbackVectorSlot::Invalid()) {
+ slot_(FeedbackVectorICSlot::Invalid()) {
SetOperandAt(0, context);
SetOperandAt(1, global_object);
set_representation(Representation::Tagged());
Handle<String> name_;
bool for_typeof_;
- Handle<FixedArray> feedback_vector_;
- FeedbackVectorSlot slot_;
+ Handle<TypeFeedbackVector> feedback_vector_;
+ FeedbackVectorICSlot slot_;
};
HValue* object() const { return OperandAt(1); }
Handle<Object> name() const { return name_; }
- FeedbackVectorSlot slot() const {
+ FeedbackVectorICSlot slot() const {
DCHECK(FLAG_vector_ics && !slot_.IsInvalid());
return slot_;
}
- Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
- void SetVectorAndSlot(Handle<FixedArray> vector, FeedbackVectorSlot slot) {
+ Handle<TypeFeedbackVector> feedback_vector() const {
+ return feedback_vector_;
+ }
+ void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
+ FeedbackVectorICSlot slot) {
DCHECK(FLAG_vector_ics);
feedback_vector_ = vector;
slot_ = slot;
private:
HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name)
- : name_(name), slot_(FeedbackVectorSlot::Invalid()) {
+ : name_(name), slot_(FeedbackVectorICSlot::Invalid()) {
SetOperandAt(0, context);
SetOperandAt(1, object);
set_representation(Representation::Tagged());
}
Handle<Object> name_;
- Handle<FixedArray> feedback_vector_;
- FeedbackVectorSlot slot_;
+ Handle<TypeFeedbackVector> feedback_vector_;
+ FeedbackVectorICSlot slot_;
};
HValue* object() const { return OperandAt(0); }
HValue* key() const { return OperandAt(1); }
HValue* context() const { return OperandAt(2); }
- FeedbackVectorSlot slot() const {
+ FeedbackVectorICSlot slot() const {
DCHECK(FLAG_vector_ics && !slot_.IsInvalid());
return slot_;
}
- Handle<FixedArray> feedback_vector() const { return feedback_vector_; }
- void SetVectorAndSlot(Handle<FixedArray> vector, FeedbackVectorSlot slot) {
+ Handle<TypeFeedbackVector> feedback_vector() const {
+ return feedback_vector_;
+ }
+ void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
+ FeedbackVectorICSlot slot) {
DCHECK(FLAG_vector_ics);
feedback_vector_ = vector;
slot_ = slot;
private:
HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key)
- : slot_(FeedbackVectorSlot::Invalid()) {
+ : slot_(FeedbackVectorICSlot::Invalid()) {
set_representation(Representation::Tagged());
SetOperandAt(0, obj);
SetOperandAt(1, key);
SetAllSideEffects();
}
- Handle<FixedArray> feedback_vector_;
- FeedbackVectorSlot slot_;
+ Handle<TypeFeedbackVector> feedback_vector_;
+ FeedbackVectorICSlot slot_;
};
__ mov(FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize),
Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
+ // We have to update statistics for runtime profiling.
+ const int with_types_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+ __ sub(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
+ const int generic_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
+ __ add(FieldOperand(ebx, generic_offset), Immediate(Smi::FromInt(1)));
__ jmp(&slow_start);
}
// No need for a write barrier, we are storing a Smi in the feedback vector.
__ LoadHeapObject(ebx, FeedbackVector());
- __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(slot.ToInt())),
+ int vector_index = FeedbackVector()->GetIndex(slot);
+ __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(vector_index)),
Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate())));
__ mov(ebx, Immediate(Smi::FromInt(1))); // Smi indicates slow check
template <class T>
void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
DCHECK(FLAG_vector_ics);
- Register vector = ToRegister(instr->temp_vector());
- DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
- __ mov(vector, instr->hydrogen()->feedback_vector());
+ Register vector_register = ToRegister(instr->temp_vector());
+ DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+ Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+ __ mov(vector_register, vector);
// No need to allocate this register.
DCHECK(VectorLoadICDescriptor::SlotRegister().is(eax));
+ int index = vector->GetIndex(instr->hydrogen()->slot());
__ mov(VectorLoadICDescriptor::SlotRegister(),
- Immediate(Smi::FromInt(instr->hydrogen()->slot().ToInt())));
+ Immediate(Smi::FromInt(index)));
}
}
-IC::State CallIC::FeedbackToState(Handle<TypeFeedbackVector> vector,
- Handle<Smi> slot) const {
+inline Code* CallIC::get_host() {
+ return isolate()
+ ->inner_pointer_to_code_cache()
+ ->GetCacheEntry(address())
+ ->code;
+}
+
+
+// static
+IC::State CallIC::FeedbackToState(Isolate* isolate, TypeFeedbackVector* vector,
+ FeedbackVectorICSlot slot) {
IC::State state = UNINITIALIZED;
- Object* feedback = vector->get(slot->value());
+ Object* feedback = vector->Get(slot);
- if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate())) {
+ if (feedback == *TypeFeedbackVector::MegamorphicSentinel(isolate)) {
state = GENERIC;
} else if (feedback->IsAllocationSite() || feedback->IsJSFunction()) {
state = MONOMORPHIC;
} else {
- CHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate()));
+ CHECK(feedback == *TypeFeedbackVector::UninitializedSentinel(isolate));
}
return state;
namespace v8 {
namespace internal {
+// static
void ICUtility::Clear(Isolate* isolate, Address address,
ConstantPoolArray* constant_pool) {
IC::Clear(isolate, address, constant_pool);
}
+// static
+void ICUtility::Clear(Isolate* isolate, Code::Kind kind, Code* host,
+ TypeFeedbackVector* vector, FeedbackVectorICSlot slot) {
+ IC::Clear(isolate, kind, host, vector, slot);
+}
+
+
CallICState::CallICState(ExtraICState extra_ic_state)
: argc_(ArgcBits::decode(extra_ic_state)),
call_type_(CallTypeBits::decode(extra_ic_state)) {}
// Clear the inline cache to initial state.
static void Clear(Isolate* isolate, Address address,
ConstantPoolArray* constant_pool);
+ // Clear a vector-based inline cache to initial state.
+ static void Clear(Isolate* isolate, Code::Kind kind, Code* host,
+ TypeFeedbackVector* vector, FeedbackVectorICSlot slot);
};
return StoreIC::Clear(isolate, address, target, constant_pool);
case Code::KEYED_STORE_IC:
return KeyedStoreIC::Clear(isolate, address, target, constant_pool);
- case Code::CALL_IC:
- return CallIC::Clear(isolate, address, target, constant_pool);
case Code::COMPARE_IC:
return CompareIC::Clear(isolate, address, target, constant_pool);
case Code::COMPARE_NIL_IC:
return CompareNilIC::Clear(address, target, constant_pool);
+ case Code::CALL_IC: // CallICs are vector-based and cleared differently.
case Code::BINARY_OP_IC:
case Code::TO_BOOLEAN_IC:
// Clearing these is tricky and does not
}
+void IC::Clear(Isolate* isolate, Code::Kind kind, Code* host,
+ TypeFeedbackVector* vector, FeedbackVectorICSlot slot) {
+ switch (kind) {
+ case Code::CALL_IC:
+ return CallIC::Clear(isolate, host, vector, slot);
+ default:
+ UNREACHABLE();
+ }
+}
+
+
void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
ConstantPoolArray* constant_pool) {
if (IsCleared(target)) return;
}
-void CallIC::Clear(Isolate* isolate, Address address, Code* target,
- ConstantPoolArray* constant_pool) {
- // Currently, CallIC doesn't have state changes.
+void CallIC::Clear(Isolate* isolate, Code* host, TypeFeedbackVector* vector,
+ FeedbackVectorICSlot slot) {
+ DCHECK(vector != NULL && !slot.IsInvalid());
+ Object* feedback = vector->Get(slot);
+ // Determine our state.
+ State state = FeedbackToState(isolate, vector, slot);
+
+ if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
+ vector->Set(slot, isolate->heap()->uninitialized_symbol(),
+ SKIP_WRITE_BARRIER);
+ // The change in state must be processed.
+ OnTypeFeedbackChanged(isolate, host, vector, state, UNINITIALIZED);
+ }
}
}
+// static
+void CallIC::OnTypeFeedbackChanged(Isolate* isolate, Code* host,
+ TypeFeedbackVector* vector, State old_state,
+ State new_state) {
+ if (host->kind() != Code::FUNCTION) return;
+
+ if (FLAG_type_info_threshold > 0) {
+ int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
+ int generic_delta = 0; // "Generic" here includes megamorphic.
+ ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
+ &generic_delta);
+ vector->change_ic_with_type_info_count(polymorphic_delta);
+ vector->change_ic_generic_count(generic_delta);
+ }
+ TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
+ info->change_own_type_change_checksum();
+ host->set_profiler_ticks(0);
+ isolate->runtime_profiler()->NotifyICChanged();
+ // TODO(2029): When an optimized function is patched, it would
+ // be nice to propagate the corresponding type information to its
+ // unoptimized version for the benefit of later inlining.
+}
+
+
bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function,
Handle<TypeFeedbackVector> vector,
- Handle<Smi> slot, const CallICState& state) {
+ FeedbackVectorICSlot slot,
+ const CallICState& state) {
DCHECK(FLAG_use_ic && function->IsJSFunction());
// Are we the array function?
Handle<JSFunction>(isolate()->native_context()->array_function());
if (array_function.is_identical_to(Handle<JSFunction>::cast(function))) {
// Alter the slot.
- IC::State old_state = FeedbackToState(vector, slot);
- Object* feedback = vector->get(slot->value());
+ IC::State old_state = FeedbackToState(isolate(), *vector, slot);
+ Object* feedback = vector->Get(slot);
if (!feedback->IsAllocationSite()) {
Handle<AllocationSite> new_site =
isolate()->factory()->NewAllocationSite();
- vector->set(slot->value(), *new_site);
+ vector->Set(slot, *new_site);
}
CallIC_ArrayStub stub(isolate(), state);
isolate());
}
- IC::State new_state = FeedbackToState(vector, slot);
- OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true);
+ IC::State new_state = FeedbackToState(isolate(), *vector, slot);
+ OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state);
TRACE_VECTOR_IC("CallIC (custom handler)", name, old_state, new_state);
return true;
}
void CallIC::PatchMegamorphic(Handle<Object> function,
Handle<TypeFeedbackVector> vector,
- Handle<Smi> slot) {
+ FeedbackVectorICSlot slot) {
CallICState state(target()->extra_ic_state());
- IC::State old_state = FeedbackToState(vector, slot);
+ IC::State old_state = FeedbackToState(isolate(), *vector, slot);
// We are going generic.
- vector->set(slot->value(),
- *TypeFeedbackVector::MegamorphicSentinel(isolate()),
+ vector->Set(slot, *TypeFeedbackVector::MegamorphicSentinel(isolate()),
SKIP_WRITE_BARRIER);
CallICStub stub(isolate(), state);
name = handle(js_function->shared()->name(), isolate());
}
- IC::State new_state = FeedbackToState(vector, slot);
- OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true);
+ IC::State new_state = FeedbackToState(isolate(), *vector, slot);
+ OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state);
TRACE_VECTOR_IC("CallIC", name, old_state, new_state);
}
void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function,
- Handle<TypeFeedbackVector> vector, Handle<Smi> slot) {
+ Handle<TypeFeedbackVector> vector,
+ FeedbackVectorICSlot slot) {
CallICState state(target()->extra_ic_state());
- IC::State old_state = FeedbackToState(vector, slot);
+ IC::State old_state = FeedbackToState(isolate(), *vector, slot);
Handle<Object> name = isolate()->factory()->empty_string();
- Object* feedback = vector->get(slot->value());
+ Object* feedback = vector->Get(slot);
// Hand-coded MISS handling is easier if CallIC slots don't contain smis.
DCHECK(!feedback->IsSmi());
if (feedback->IsJSFunction() || !function->IsJSFunction()) {
// We are going generic.
- vector->set(slot->value(),
- *TypeFeedbackVector::MegamorphicSentinel(isolate()),
+ vector->Set(slot, *TypeFeedbackVector::MegamorphicSentinel(isolate()),
SKIP_WRITE_BARRIER);
} else {
// The feedback is either uninitialized or an allocation site.
return;
}
- vector->set(slot->value(), *function);
+ vector->Set(slot, *function);
}
if (function->IsJSFunction()) {
name = handle(js_function->shared()->name(), isolate());
}
- IC::State new_state = FeedbackToState(vector, slot);
- OnTypeFeedbackChanged(isolate(), address(), old_state, new_state, true);
+ IC::State new_state = FeedbackToState(isolate(), *vector, slot);
+ OnTypeFeedbackChanged(isolate(), get_host(), *vector, old_state, new_state);
TRACE_VECTOR_IC("CallIC", name, old_state, new_state);
}
Handle<Object> function = args.at<Object>(1);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
Handle<Smi> slot = args.at<Smi>(3);
- ic.HandleMiss(receiver, function, vector, slot);
+ FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+ ic.HandleMiss(receiver, function, vector, vector_slot);
return *function;
}
Handle<Object> function = args.at<Object>(1);
Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(2);
Handle<Smi> slot = args.at<Smi>(3);
- ic.PatchMegamorphic(function, vector, slot);
+ FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+ ic.PatchMegamorphic(function, vector, vector_slot);
return *function;
}
static void Clear(Isolate* isolate, Address address,
ConstantPoolArray* constant_pool);
+ // Clear the vector-based inline cache to initial state.
+ static void Clear(Isolate* isolate, Code::Kind kind, Code* host,
+ TypeFeedbackVector* vector, FeedbackVectorICSlot slot);
+
#ifdef DEBUG
bool IsLoadStub() const {
return target()->is_load_stub() || target()->is_keyed_load_stub();
explicit CallIC(Isolate* isolate) : IC(EXTRA_CALL_FRAME, isolate) {}
void PatchMegamorphic(Handle<Object> function,
- Handle<TypeFeedbackVector> vector, Handle<Smi> slot);
+ Handle<TypeFeedbackVector> vector,
+ FeedbackVectorICSlot slot);
void HandleMiss(Handle<Object> receiver, Handle<Object> function,
- Handle<TypeFeedbackVector> vector, Handle<Smi> slot);
+ Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot);
// Returns true if a custom handler was installed.
bool DoCustomHandler(Handle<Object> receiver, Handle<Object> function,
- Handle<TypeFeedbackVector> vector, Handle<Smi> slot,
- const CallICState& state);
+ Handle<TypeFeedbackVector> vector,
+ FeedbackVectorICSlot slot, const CallICState& state);
// Code generator routines.
static Handle<Code> initialize_stub(Isolate* isolate, int argc,
CallICState::CallType call_type);
- static void Clear(Isolate* isolate, Address address, Code* target,
- ConstantPoolArray* constant_pool);
+ static void Clear(Isolate* isolate, Code* host, TypeFeedbackVector* vector,
+ FeedbackVectorICSlot slot);
private:
- inline IC::State FeedbackToState(Handle<TypeFeedbackVector> vector,
- Handle<Smi> slot) const;
+ static inline IC::State FeedbackToState(Isolate* isolate,
+ TypeFeedbackVector* vector,
+ FeedbackVectorICSlot slot);
+
+ inline Code* get_host();
+
+ // As a vector-based IC, type feedback must be updated differently.
+ static void OnTypeFeedbackChanged(Isolate* isolate, Code* host,
+ TypeFeedbackVector* vector, State old_state,
+ State new_state);
};
optimizing_compiler_thread_->Start();
}
+ // Initialize runtime profiler before deserialization, because collections may
+ // occur, clearing/updating ICs.
+ runtime_profiler_ = new RuntimeProfiler(this);
+
// If we are deserializing, read the state into the now-empty heap.
if (!create_heap_objects) {
des->Deserialize(this);
// Quiet the heap NaN if needed on target platform.
if (!create_heap_objects) Assembler::QuietNaN(heap_.nan_value());
- runtime_profiler_ = new RuntimeProfiler(this);
-
if (FLAG_trace_turbo) {
// Erase the file.
char buffer[512];
std::fstream::out | std::fstream::trunc);
}
-
// If we are deserializing, log non-function code objects and compiled
// functions found in the snapshot.
if (!create_heap_objects &&
}
-void FunctionInfoWrapper::SetInitialProperties(Handle<String> name,
- int start_position,
- int end_position,
- int param_num,
- int literal_count,
- int slot_count,
- int parent_index) {
+void FunctionInfoWrapper::SetInitialProperties(
+ Handle<String> name, int start_position, int end_position, int param_num,
+ int literal_count, int slot_count, int ic_slot_count, int parent_index) {
HandleScope scope(isolate());
this->SetField(kFunctionNameOffset_, name);
this->SetSmiValueField(kStartPositionOffset_, start_position);
this->SetSmiValueField(kParamNumOffset_, param_num);
this->SetSmiValueField(kLiteralNumOffset_, literal_count);
this->SetSmiValueField(kSlotNumOffset_, slot_count);
+ this->SetSmiValueField(kICSlotNumOffset_, ic_slot_count);
this->SetSmiValueField(kParentIndexOffset_, parent_index);
}
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>::cast(raw_result);
result = Handle<TypeFeedbackVector>(shared->feedback_vector(), isolate());
- CHECK_EQ(result->length(), GetSlotCount());
+ CHECK_EQ(result->Slots(), GetSlotCount());
+ CHECK_EQ(result->ICSlots(), GetICSlotCount());
} else {
// Scripts may never have a SharedFunctionInfo created, so
// create a type feedback vector here.
int slot_count = GetSlotCount();
- result = isolate()->factory()->NewTypeFeedbackVector(slot_count);
+ int ic_slot_count = GetICSlotCount();
+ result =
+ isolate()->factory()->NewTypeFeedbackVector(slot_count, ic_slot_count);
}
return result;
}
void FunctionStarted(FunctionLiteral* fun) {
HandleScope scope(isolate());
FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate());
- info.SetInitialProperties(fun->name(), fun->start_position(),
- fun->end_position(), fun->parameter_count(),
- fun->materialized_literal_count(),
- fun->slot_count(),
- current_parent_index_);
+ info.SetInitialProperties(
+ fun->name(), fun->start_position(), fun->end_position(),
+ fun->parameter_count(), fun->materialized_literal_count(),
+ fun->slot_count(), fun->ic_slot_count(), current_parent_index_);
current_parent_index_ = len_;
SetElementSloppy(result_, len_, info.GetJSArray());
len_++;
: JSArrayBasedStruct<FunctionInfoWrapper>(array) {
}
- void SetInitialProperties(Handle<String> name,
- int start_position,
- int end_position,
- int param_num,
- int literal_count,
- int slot_count,
+ void SetInitialProperties(Handle<String> name, int start_position,
+ int end_position, int param_num, int literal_count,
+ int slot_count, int ic_slot_count,
int parent_index);
void SetFunctionCode(Handle<Code> function_code,
return this->GetSmiValueField(kSlotNumOffset_);
}
+ int GetICSlotCount() { return this->GetSmiValueField(kICSlotNumOffset_); }
+
private:
static const int kFunctionNameOffset_ = 0;
static const int kStartPositionOffset_ = 1;
static const int kSharedFunctionInfoOffset_ = 8;
static const int kLiteralNumOffset_ = 9;
static const int kSlotNumOffset_ = 10;
- static const int kSize_ = 11;
+ static const int kICSlotNumOffset_ = 11;
+ static const int kSize_ = 12;
friend class JSArrayBasedStruct<FunctionInfoWrapper>;
};
__ Addu(t0, a2, Operand(t0));
__ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
__ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize));
+ // We have to update statistics for runtime profiling.
+ const int with_types_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+ __ lw(t0, FieldMemOperand(a2, with_types_offset));
+ __ Subu(t0, t0, Operand(Smi::FromInt(1)));
+ __ sw(t0, FieldMemOperand(a2, with_types_offset));
+ const int generic_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
+ __ lw(t0, FieldMemOperand(a2, generic_offset));
+ __ Addu(t0, t0, Operand(Smi::FromInt(1)));
+ __ sw(t0, FieldMemOperand(a2, generic_offset));
__ Branch(&slow_start);
}
__ li(a1, FeedbackVector());
__ li(a2, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate())));
- __ sw(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(slot.ToInt())));
+ int vector_index = FeedbackVector()->GetIndex(slot);
+ __ sw(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(vector_index)));
__ li(a1, Operand(Smi::FromInt(1))); // Smi indicates slow check
__ lw(a2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object
template <class T>
void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
DCHECK(FLAG_vector_ics);
- Register vector = ToRegister(instr->temp_vector());
- DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
- __ li(vector, instr->hydrogen()->feedback_vector());
+ Register vector_register = ToRegister(instr->temp_vector());
+ DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+ Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+ __ li(vector_register, vector);
// No need to allocate this register.
DCHECK(VectorLoadICDescriptor::SlotRegister().is(a0));
- __ li(VectorLoadICDescriptor::SlotRegister(),
- Operand(Smi::FromInt(instr->hydrogen()->slot().ToInt())));
+ int index = vector->GetIndex(instr->hydrogen()->slot());
+ __ li(VectorLoadICDescriptor::SlotRegister(), Operand(Smi::FromInt(index)));
}
void SharedFunctionInfo::ClearTypeFeedbackInfo() {
- TypeFeedbackVector* vector = feedback_vector();
- Heap* heap = GetHeap();
- int length = vector->length();
-
- for (int i = 0; i < length; i++) {
- Object* obj = vector->get(i);
- if (obj->IsHeapObject()) {
- InstanceType instance_type =
- HeapObject::cast(obj)->map()->instance_type();
- switch (instance_type) {
- case ALLOCATION_SITE_TYPE:
- // AllocationSites are not cleared because they do not store
- // information that leaks.
- break;
- // Fall through...
- default:
- vector->set(i, TypeFeedbackVector::RawUninitializedSentinel(heap),
- SKIP_WRITE_BARRIER);
- }
- }
- }
+ feedback_vector()->ClearSlots(this);
}
inline void set_inlined_type_change_checksum(int checksum);
inline bool matches_inlined_type_change_checksum(int checksum);
-
DECLARE_CAST(TypeFeedbackInfo)
// Dispatched behavior.
}
-static void GetICCounts(Code* shared_code, int* ic_with_type_info_count,
- int* ic_generic_count, int* ic_total_count,
- int* type_info_percentage, int* generic_percentage) {
+static void GetICCounts(SharedFunctionInfo* shared,
+ int* ic_with_type_info_count, int* ic_generic_count,
+ int* ic_total_count, int* type_info_percentage,
+ int* generic_percentage) {
+ Code* shared_code = shared->code();
*ic_total_count = 0;
*ic_generic_count = 0;
*ic_with_type_info_count = 0;
*ic_generic_count = info->ic_generic_count();
*ic_total_count = info->ic_total_count();
}
+
+ // Harvest vector-ics as well
+ TypeFeedbackVector* vector = shared->feedback_vector();
+ *ic_with_type_info_count += vector->ic_with_type_info_count();
+ *ic_generic_count += vector->ic_generic_count();
+
if (*ic_total_count > 0) {
*type_info_percentage = 100 * *ic_with_type_info_count / *ic_total_count;
*generic_percentage = 100 * *ic_generic_count / *ic_total_count;
PrintF(" for recompilation, reason: %s", reason);
if (FLAG_type_info_threshold > 0) {
int typeinfo, generic, total, type_percentage, generic_percentage;
- GetICCounts(function->shared()->code(), &typeinfo, &generic, &total,
+ GetICCounts(function->shared(), &typeinfo, &generic, &total,
&type_percentage, &generic_percentage);
PrintF(", ICs with typeinfo: %d/%d (%d%%)", typeinfo, total,
type_percentage);
if (ticks >= kProfilerTicksBeforeOptimization) {
int typeinfo, generic, total, type_percentage, generic_percentage;
- GetICCounts(shared_code, &typeinfo, &generic, &total, &type_percentage,
+ GetICCounts(shared, &typeinfo, &generic, &total, &type_percentage,
&generic_percentage);
if (type_percentage >= FLAG_type_info_threshold &&
generic_percentage <= FLAG_generic_ic_threshold) {
// If no IC was patched since the last tick and this function is very
// small, optimistically optimize it now.
int typeinfo, generic, total, type_percentage, generic_percentage;
- GetICCounts(shared_code, &typeinfo, &generic, &total, &type_percentage,
+ GetICCounts(shared, &typeinfo, &generic, &total, &type_percentage,
&generic_percentage);
if (type_percentage >= FLAG_type_info_threshold &&
generic_percentage <= FLAG_generic_ic_threshold) {
Handle<Object> TypeFeedbackVector::PremonomorphicSentinel(Isolate* isolate) {
- return isolate->factory()->megamorphic_symbol();
+ return isolate->factory()->premonomorphic_symbol();
}
#include "src/v8.h"
+#include "src/ic/ic-state.h"
#include "src/objects.h"
#include "src/type-feedback-vector-inl.h"
namespace v8 {
namespace internal {
+// static
+Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(Isolate* isolate,
+ int slot_count,
+ int ic_slot_count) {
+ int length = slot_count + ic_slot_count + kReservedIndexCount;
+ if (length == kReservedIndexCount) {
+ return Handle<TypeFeedbackVector>::cast(
+ isolate->factory()->empty_fixed_array());
+ }
+
+ Handle<FixedArray> array = isolate->factory()->NewFixedArray(length, TENURED);
+ if (ic_slot_count > 0) {
+ array->set(kFirstICSlotIndex,
+ Smi::FromInt(slot_count + kReservedIndexCount));
+ } else {
+ array->set(kFirstICSlotIndex, Smi::FromInt(length));
+ }
+ array->set(kWithTypesIndex, Smi::FromInt(0));
+ array->set(kGenericCountIndex, Smi::FromInt(0));
+
+ // Ensure we can skip the write barrier
+ Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
+ DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel);
+ for (int i = kReservedIndexCount; i < length; i++) {
+ array->set(i, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
+ }
+ return Handle<TypeFeedbackVector>::cast(array);
+}
+
+
// static
Handle<TypeFeedbackVector> TypeFeedbackVector::Copy(
Isolate* isolate, Handle<TypeFeedbackVector> vector) {
isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
return result;
}
+
+
+void TypeFeedbackVector::ClearSlots(SharedFunctionInfo* shared) {
+ int slots = Slots();
+ Isolate* isolate = GetIsolate();
+ Object* uninitialized_sentinel =
+ TypeFeedbackVector::RawUninitializedSentinel(isolate->heap());
+
+ for (int i = 0; i < slots; i++) {
+ FeedbackVectorSlot slot(i);
+ Object* obj = Get(slot);
+ if (obj->IsHeapObject()) {
+ InstanceType instance_type =
+ HeapObject::cast(obj)->map()->instance_type();
+ // AllocationSites are exempt from clearing. They don't store Maps
+ // or Code pointers which can cause memory leaks if not cleared
+ // regularly.
+ if (instance_type != ALLOCATION_SITE_TYPE) {
+ Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
+ }
+ }
+ }
+
+ slots = ICSlots();
+ if (slots == 0) return;
+
+ // Now clear vector-based ICs. They are all CallICs.
+ // Try and pass the containing code (the "host").
+ Code* host = shared->code();
+ for (int i = 0; i < slots; i++) {
+ FeedbackVectorICSlot slot(i);
+ Object* obj = Get(slot);
+ if (obj != uninitialized_sentinel) {
+ ICUtility::Clear(isolate, Code::CALL_IC, host, this, slot);
+ }
+ }
+}
}
} // namespace v8::internal
namespace v8 {
namespace internal {
+// The shape of the TypeFeedbackVector is an array with:
+// 0: first_ic_slot_index (== length() if no ic slots are present)
+// 1: ics_with_types
+// 2: ics_with_generic_info
+// 3: first feedback slot
+// ...
+// [<first_ic_slot_index>: feedback slot]
+// ...to length() - 1
+//
class TypeFeedbackVector : public FixedArray {
public:
// Casting.
return reinterpret_cast<TypeFeedbackVector*>(obj);
}
+ static const int kReservedIndexCount = 3;
+ static const int kFirstICSlotIndex = 0;
+ static const int kWithTypesIndex = 1;
+ static const int kGenericCountIndex = 2;
+
+ int first_ic_slot_index() {
+ DCHECK(length() >= kReservedIndexCount);
+ return Smi::cast(get(kFirstICSlotIndex))->value();
+ }
+
+ int ic_with_type_info_count() {
+ return length() > 0 ? Smi::cast(get(kWithTypesIndex))->value() : 0;
+ }
+
+ void change_ic_with_type_info_count(int delta) {
+ if (delta == 0) return;
+ int value = ic_with_type_info_count() + delta;
+ // Could go negative because of the debugger.
+ if (value >= 0) {
+ set(kWithTypesIndex, Smi::FromInt(value));
+ }
+ }
+
+ int ic_generic_count() {
+ return length() > 0 ? Smi::cast(get(kGenericCountIndex))->value() : 0;
+ }
+
+ void change_ic_generic_count(int delta) {
+ if (delta == 0) return;
+ int value = ic_generic_count() + delta;
+ if (value >= 0) {
+ set(kGenericCountIndex, Smi::FromInt(value));
+ }
+ }
+
+ int Slots() {
+ if (length() == 0) return 0;
+ return Max(0, first_ic_slot_index() - kReservedIndexCount);
+ }
+
+ int ICSlots() {
+ if (length() == 0) return 0;
+ return length() - first_ic_slot_index();
+ }
+
+ // Conversion from a slot or ic slot to an integer index to the underlying
+ // array.
+ int GetIndex(FeedbackVectorSlot slot) {
+ return kReservedIndexCount + slot.ToInt();
+ }
+
+ int GetIndex(FeedbackVectorICSlot slot) {
+ int first_ic_slot = first_ic_slot_index();
+ DCHECK(slot.ToInt() < ICSlots());
+ return first_ic_slot + slot.ToInt();
+ }
+
+
+ // Conversion from an integer index to either a slot or an ic slot. The caller
+ // should know what kind she expects.
+ FeedbackVectorSlot ToSlot(int index) {
+ DCHECK(index >= kReservedIndexCount && index < first_ic_slot_index());
+ return FeedbackVectorSlot(index - kReservedIndexCount);
+ }
+
+ FeedbackVectorICSlot ToICSlot(int index) {
+ DCHECK(index >= first_ic_slot_index() && index < length());
+ return FeedbackVectorICSlot(index - first_ic_slot_index());
+ }
+
+ Object* Get(FeedbackVectorSlot slot) { return get(GetIndex(slot)); }
+ void Set(FeedbackVectorSlot slot, Object* value,
+ WriteBarrierMode mode = UPDATE_WRITE_BARRIER) {
+ set(GetIndex(slot), value, mode);
+ }
+
+ Object* Get(FeedbackVectorICSlot slot) { return get(GetIndex(slot)); }
+ void Set(FeedbackVectorICSlot slot, Object* value,
+ WriteBarrierMode mode = UPDATE_WRITE_BARRIER) {
+ set(GetIndex(slot), value, mode);
+ }
+
+
+ static Handle<TypeFeedbackVector> Allocate(Isolate* isolate, int slot_count,
+ int ic_slot_count);
+
static Handle<TypeFeedbackVector> Copy(Isolate* isolate,
Handle<TypeFeedbackVector> vector);
+ // Clears the vector slots and the vector ic slots.
+ void ClearSlots(SharedFunctionInfo* shared);
+
// The object that indicates an uninitialized cache.
static inline Handle<Object> UninitializedSentinel(Isolate* isolate);
Handle<Object> TypeFeedbackOracle::GetInfo(FeedbackVectorSlot slot) {
DCHECK(slot.ToInt() >= 0 && slot.ToInt() < feedback_vector_->length());
- Object* obj = feedback_vector_->get(slot.ToInt());
+ Object* obj = feedback_vector_->Get(slot);
+ if (!obj->IsJSFunction() ||
+ !CanRetainOtherContext(JSFunction::cast(obj), *native_context_)) {
+ return Handle<Object>(obj, isolate());
+ }
+ return Handle<Object>::cast(isolate()->factory()->undefined_value());
+}
+
+
+Handle<Object> TypeFeedbackOracle::GetInfo(FeedbackVectorICSlot slot) {
+ DCHECK(slot.ToInt() >= 0 && slot.ToInt() < feedback_vector_->length());
+ Object* obj = feedback_vector_->Get(slot);
if (!obj->IsJSFunction() ||
!CanRetainOtherContext(JSFunction::cast(obj), *native_context_)) {
return Handle<Object>(obj, isolate());
}
-bool TypeFeedbackOracle::CallIsMonomorphic(FeedbackVectorSlot slot) {
+bool TypeFeedbackOracle::CallIsMonomorphic(FeedbackVectorICSlot slot) {
Handle<Object> value = GetInfo(slot);
return value->IsAllocationSite() || value->IsJSFunction();
}
}
-Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(FeedbackVectorSlot slot) {
+Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(
+ FeedbackVectorICSlot slot) {
Handle<Object> info = GetInfo(slot);
if (info->IsAllocationSite()) {
return Handle<JSFunction>(isolate()->native_context()->array_function());
Handle<AllocationSite> TypeFeedbackOracle::GetCallAllocationSite(
- FeedbackVectorSlot slot) {
+ FeedbackVectorICSlot slot) {
Handle<Object> info = GetInfo(slot);
if (info->IsAllocationSite()) {
return Handle<AllocationSite>::cast(info);
bool LoadIsUninitialized(TypeFeedbackId id);
bool StoreIsUninitialized(TypeFeedbackId id);
- bool CallIsMonomorphic(FeedbackVectorSlot slot);
- bool CallIsMonomorphic(TypeFeedbackId aid);
+ bool CallIsMonomorphic(FeedbackVectorICSlot slot);
bool KeyedArrayCallIsHoley(TypeFeedbackId id);
bool CallNewIsMonomorphic(FeedbackVectorSlot slot);
static bool CanRetainOtherContext(JSFunction* function,
Context* native_context);
- Handle<JSFunction> GetCallTarget(FeedbackVectorSlot slot);
- Handle<AllocationSite> GetCallAllocationSite(FeedbackVectorSlot slot);
+ Handle<JSFunction> GetCallTarget(FeedbackVectorICSlot slot);
+ Handle<AllocationSite> GetCallAllocationSite(FeedbackVectorICSlot slot);
Handle<JSFunction> GetCallNewTarget(FeedbackVectorSlot slot);
Handle<AllocationSite> GetCallNewAllocationSite(FeedbackVectorSlot slot);
// Returns an element from the type feedback vector. Returns undefined
// if there is no information.
Handle<Object> GetInfo(FeedbackVectorSlot slot);
+ Handle<Object> GetInfo(FeedbackVectorICSlot slot);
private:
Handle<Context> native_context_;
};
-class FeedbackVectorSlot {
+template <int dummy_parameter>
+class VectorSlot {
public:
- explicit FeedbackVectorSlot(int id) : id_(id) {}
+ explicit VectorSlot(int id) : id_(id) {}
int ToInt() const { return id_; }
- static FeedbackVectorSlot Invalid() {
- return FeedbackVectorSlot(kInvalidSlot);
- }
+ static VectorSlot Invalid() { return VectorSlot(kInvalidSlot); }
bool IsInvalid() const { return id_ == kInvalidSlot; }
- FeedbackVectorSlot next() const {
+ VectorSlot next() const {
DCHECK(id_ != kInvalidSlot);
- return FeedbackVectorSlot(id_ + 1);
+ return VectorSlot(id_ + 1);
}
+ bool operator==(const VectorSlot& other) const { return id_ == other.id_; }
+
private:
static const int kInvalidSlot = -1;
};
+typedef VectorSlot<0> FeedbackVectorSlot;
+typedef VectorSlot<1> FeedbackVectorICSlot;
+
+
class BailoutId {
public:
explicit BailoutId(int id) : id_(id) { }
__ j(not_equal, &miss);
__ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
TypeFeedbackVector::MegamorphicSentinel(isolate));
+ // We have to update statistics for runtime profiling.
+ const int with_types_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
+ __ SmiAddConstant(FieldOperand(rbx, with_types_offset), Smi::FromInt(-1));
+ const int generic_offset =
+ FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
+ __ SmiAddConstant(FieldOperand(rbx, generic_offset), Smi::FromInt(1));
__ jmp(&slow_start);
}
// No need for a write barrier, we are storing a Smi in the feedback vector.
__ Move(rbx, FeedbackVector());
- __ Move(FieldOperand(rbx, FixedArray::OffsetOfElementAt(slot.ToInt())),
+ int vector_index = FeedbackVector()->GetIndex(slot);
+ __ Move(FieldOperand(rbx, FixedArray::OffsetOfElementAt(vector_index)),
TypeFeedbackVector::MegamorphicSentinel(isolate()));
__ Move(rbx, Smi::FromInt(1)); // Smi indicates slow check
__ movp(rcx, Operand(rsp, 0 * kPointerSize)); // Get enumerated object
template <class T>
void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
DCHECK(FLAG_vector_ics);
- Register vector = ToRegister(instr->temp_vector());
- DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
- __ Move(vector, instr->hydrogen()->feedback_vector());
+ Register vector_register = ToRegister(instr->temp_vector());
+ DCHECK(vector_register.is(VectorLoadICDescriptor::VectorRegister()));
+ Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector();
+ __ Move(vector_register, vector);
// No need to allocate this register.
DCHECK(VectorLoadICDescriptor::SlotRegister().is(rax));
- __ Move(VectorLoadICDescriptor::SlotRegister(),
- Smi::FromInt(instr->hydrogen()->slot().ToInt()));
+ int index = vector->GetIndex(instr->hydrogen()->slot());
+ __ Move(VectorLoadICDescriptor::SlotRegister(), Smi::FromInt(index));
}
'test-double.cc',
'test-dtoa.cc',
'test-fast-dtoa.cc',
+ 'test-feedback-vector.cc',
'test-fixed-dtoa.cc',
'test-flags.cc',
'test-func-name-inference.cc',
// We shouldn't have deoptimization support. We want to recompile and
// verify that our feedback vector preserves information.
CHECK(!f->shared()->has_deoptimization_support());
- Handle<FixedArray> feedback_vector(f->shared()->feedback_vector());
+ Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
// Verify that we gathered feedback.
- int expected_count = FLAG_vector_ics ? 2 : 1;
- CHECK_EQ(expected_count, feedback_vector->length());
- CHECK(feedback_vector->get(expected_count - 1)->IsJSFunction());
+ int expected_slots = 0;
+ int expected_ic_slots = FLAG_vector_ics ? 2 : 1;
+ CHECK_EQ(expected_slots, feedback_vector->Slots());
+ CHECK_EQ(expected_ic_slots, feedback_vector->ICSlots());
+ FeedbackVectorICSlot slot_for_a(FLAG_vector_ics ? 1 : 0);
+ CHECK(feedback_vector->Get(slot_for_a)->IsJSFunction());
CompileRun("%OptimizeFunctionOnNextCall(f); f(fun1);");
// of the full code.
CHECK(f->IsOptimized());
CHECK(f->shared()->has_deoptimization_support());
- CHECK(f->shared()->feedback_vector()->
- get(expected_count - 1)->IsJSFunction());
+ CHECK(f->shared()->feedback_vector()->Get(slot_for_a)->IsJSFunction());
}
*v8::Handle<v8::Function>::Cast(
CcTest::global()->Get(v8_str("morphing_call"))));
- int expected_count = FLAG_vector_ics ? 2 : 1;
- CHECK_EQ(expected_count, f->shared()->feedback_vector()->length());
+ int expected_slots = 0;
+ int expected_ic_slots = FLAG_vector_ics ? 2 : 1;
+ CHECK_EQ(expected_slots, f->shared()->feedback_vector()->Slots());
+ CHECK_EQ(expected_ic_slots, f->shared()->feedback_vector()->ICSlots());
+
// And yet it's not compiled.
CHECK(!f->shared()->is_compiled());
CompileRun("morphing_call();");
// The vector should have the same size despite the new scoping.
- CHECK_EQ(expected_count, f->shared()->feedback_vector()->length());
+ CHECK_EQ(expected_slots, f->shared()->feedback_vector()->Slots());
+ CHECK_EQ(expected_ic_slots, f->shared()->feedback_vector()->ICSlots());
CHECK(f->shared()->is_compiled());
}
--- /dev/null
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/api.h"
+#include "src/debug.h"
+#include "src/execution.h"
+#include "src/factory.h"
+#include "src/global-handles.h"
+#include "src/macro-assembler.h"
+#include "src/objects.h"
+
+using namespace v8::internal;
+
+namespace {
+
+TEST(VectorStructure) {
+ LocalContext context;
+ v8::HandleScope scope(context->GetIsolate());
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+
+ // Empty vectors are the empty fixed array.
+ Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(0, 0);
+ CHECK(Handle<FixedArray>::cast(vector)
+ .is_identical_to(factory->empty_fixed_array()));
+ // Which can nonetheless be queried.
+ CHECK_EQ(0, vector->ic_with_type_info_count());
+ CHECK_EQ(0, vector->ic_generic_count());
+ CHECK_EQ(0, vector->Slots());
+ CHECK_EQ(0, vector->ICSlots());
+
+ vector = factory->NewTypeFeedbackVector(1, 0);
+ CHECK_EQ(1, vector->Slots());
+ CHECK_EQ(0, vector->ICSlots());
+
+ vector = factory->NewTypeFeedbackVector(0, 1);
+ CHECK_EQ(0, vector->Slots());
+ CHECK_EQ(1, vector->ICSlots());
+
+ vector = factory->NewTypeFeedbackVector(3, 5);
+ CHECK_EQ(3, vector->Slots());
+ CHECK_EQ(5, vector->ICSlots());
+
+ int index = vector->GetIndex(FeedbackVectorSlot(0));
+ CHECK_EQ(TypeFeedbackVector::kReservedIndexCount, index);
+ CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index));
+
+ index = vector->GetIndex(FeedbackVectorICSlot(0));
+ CHECK_EQ(index, TypeFeedbackVector::kReservedIndexCount + 3);
+ CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index));
+
+ CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + 3 + 5, vector->length());
+}
+
+
+TEST(VectorSlotClearing) {
+ LocalContext context;
+ v8::HandleScope scope(context->GetIsolate());
+ Isolate* isolate = CcTest::i_isolate();
+ Factory* factory = isolate->factory();
+
+ // We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots.
+ // The reason is that FeedbackVectorICSlots need a full code environment
+ // to fully test (See VectorICProfilerStatistics test below).
+ Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(5, 0);
+
+ // Fill with information
+ vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1));
+ vector->Set(FeedbackVectorSlot(1), *factory->fixed_array_map());
+ vector->Set(FeedbackVectorSlot(2), *factory->NewAllocationSite());
+
+ vector->ClearSlots(NULL);
+
+ // The feedback vector slots are cleared. AllocationSites are granted
+ // an exemption from clearing, as are smis.
+ CHECK_EQ(Smi::FromInt(1), vector->Get(FeedbackVectorSlot(0)));
+ CHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(isolate),
+ vector->Get(FeedbackVectorSlot(1)));
+ CHECK(vector->Get(FeedbackVectorSlot(2))->IsAllocationSite());
+}
+
+
+TEST(VectorICProfilerStatistics) {
+ if (i::FLAG_always_opt) return;
+ CcTest::InitializeVM();
+ LocalContext context;
+ v8::HandleScope scope(context->GetIsolate());
+ Isolate* isolate = CcTest::i_isolate();
+ Heap* heap = isolate->heap();
+
+ // Make sure function f has a call that uses a type feedback slot.
+ CompileRun(
+ "function fun() {};"
+ "function f(a) { a(); } f(fun);");
+ Handle<JSFunction> f = v8::Utils::OpenHandle(
+ *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+ // There should be one IC.
+ Code* code = f->shared()->code();
+ TypeFeedbackInfo* feedback_info =
+ TypeFeedbackInfo::cast(code->type_feedback_info());
+ CHECK_EQ(1, feedback_info->ic_total_count());
+ CHECK_EQ(0, feedback_info->ic_with_type_info_count());
+ CHECK_EQ(0, feedback_info->ic_generic_count());
+ TypeFeedbackVector* feedback_vector = f->shared()->feedback_vector();
+ CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+ CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+ // Now send the information generic.
+ CompileRun("f(Object);");
+ feedback_vector = f->shared()->feedback_vector();
+ CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
+ CHECK_EQ(1, feedback_vector->ic_generic_count());
+
+ // A collection will make the site uninitialized again.
+ heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+ feedback_vector = f->shared()->feedback_vector();
+ CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
+ CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+ // The Array function is special. A call to array remains monomorphic
+ // and isn't cleared by gc because an AllocationSite is being held.
+ CompileRun("f(Array);");
+ feedback_vector = f->shared()->feedback_vector();
+ CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+ CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+ CHECK(feedback_vector->Get(FeedbackVectorICSlot(0))->IsAllocationSite());
+ heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+ feedback_vector = f->shared()->feedback_vector();
+ CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+ CHECK_EQ(0, feedback_vector->ic_generic_count());
+ CHECK(feedback_vector->Get(FeedbackVectorICSlot(0))->IsAllocationSite());
+}
+}
Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
- int expected_length = FLAG_vector_ics ? 4 : 2;
- CHECK_EQ(expected_length, feedback_vector->length());
- for (int i = 0; i < expected_length; i++) {
- if ((i % 2) == 1) {
- CHECK(feedback_vector->get(i)->IsJSFunction());
- }
+ int expected_slots = 2;
+ CHECK_EQ(expected_slots, feedback_vector->ICSlots());
+ for (int i = 0; i < expected_slots; i++) {
+ CHECK(feedback_vector->Get(FeedbackVectorICSlot(i))->IsJSFunction());
}
SimulateIncrementalMarking(CcTest::heap());
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
- CHECK_EQ(expected_length, feedback_vector->length());
- for (int i = 0; i < expected_length; i++) {
- CHECK_EQ(feedback_vector->get(i),
+ CHECK_EQ(expected_slots, feedback_vector->ICSlots());
+ for (int i = 0; i < expected_slots; i++) {
+ CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(i)),
*TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
}
}
Handle<JSArrayBuffer> buffer =
NewArrayBuffer(backing_store, arraysize(backing_store));
VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
- FeedbackVectorSlot::Invalid());
+ FeedbackVectorICSlot::Invalid());
TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
Handle<JSTypedArray> array =
factory()->NewJSTypedArray(type, buffer, 0, kLength);