vector-based ICs did not update type feedback counts correctly.
authormvstanton@chromium.org <mvstanton@chromium.org>
Mon, 20 Oct 2014 11:42:56 +0000 (11:42 +0000)
committermvstanton@chromium.org <mvstanton@chromium.org>
Mon, 20 Oct 2014 11:42:56 +0000 (11:42 +0000)
BUG=v8:3605
LOG=N
R=jkummerow@chromium.org, ulan@chromium.org

Review URL: https://codereview.chromium.org/650073002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24732 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

50 files changed:
src/arm/code-stubs-arm.cc
src/arm/full-codegen-arm.cc
src/arm/lithium-codegen-arm.cc
src/arm64/code-stubs-arm64.cc
src/arm64/full-codegen-arm64.cc
src/arm64/lithium-codegen-arm64.cc
src/ast.cc
src/ast.h
src/bootstrapper.cc
src/compiler.cc
src/compiler/ast-graph-builder.cc
src/compiler/ast-graph-builder.h
src/compiler/js-operator.h
src/factory.cc
src/factory.h
src/full-codegen.cc
src/full-codegen.h
src/heap/objects-visiting-inl.h
src/hydrogen-instructions.h
src/ia32/code-stubs-ia32.cc
src/ia32/full-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/ic/ic-inl.h
src/ic/ic-state.cc
src/ic/ic-state.h
src/ic/ic.cc
src/ic/ic.h
src/isolate.cc
src/liveedit.cc
src/liveedit.h
src/mips/code-stubs-mips.cc
src/mips/full-codegen-mips.cc
src/mips/lithium-codegen-mips.cc
src/objects.cc
src/objects.h
src/runtime-profiler.cc
src/type-feedback-vector-inl.h
src/type-feedback-vector.cc
src/type-feedback-vector.h
src/type-info.cc
src/type-info.h
src/utils.h
src/x64/code-stubs-x64.cc
src/x64/full-codegen-x64.cc
src/x64/lithium-codegen-x64.cc
test/cctest/cctest.gyp
test/cctest/test-compiler.cc
test/cctest/test-feedback-vector.cc [new file with mode: 0644]
test/cctest/test-heap.cc
test/unittests/compiler/js-typed-lowering-unittest.cc

index 45c0c5f352fcf3a815deb9c3dc97efc6e66c74f7..a5a34a4b9771b643d2d4b46e0faa72cf57356444 100644 (file)
@@ -2740,6 +2740,17 @@ void CallICStub::Generate(MacroAssembler* masm) {
     __ 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);
   }
 
index 45331031ee59bcd32d863fcb08ebf8452e02ee23..a84ef889ea57ab1a086849f5eaa20604e6ec7676 100644 (file)
@@ -1194,7 +1194,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
 
   __ 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
index ce903d39958f5e8d0946a62a2f4b36c914bf9985..e945a13c8788df96de7bf578fab5957ccd6f1d75 100644 (file)
@@ -2994,13 +2994,14 @@ void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
 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)));
 }
 
 
index ed951ae7eb925074a9a9aacaa4bc2e1d49aa7a65..bdcd08aefe3fd26302c35529c0ce650e45b9a33e 100644 (file)
@@ -3078,6 +3078,17 @@ void CallICStub::Generate(MacroAssembler* masm) {
            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);
   }
 
index c0eca3c401b5af80dbfc4c8831e5bc5075b67953..fb698a344fa2626bd56c5c27bb0d8fdb5f423f1c 100644 (file)
@@ -1181,7 +1181,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
 
   __ 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.
index 37c6649249da1680ff7f662f511f1de40fa916f7..a285e7bcc1529419639093e5f204e3ee17abda1e 100644 (file)
@@ -3371,13 +3371,14 @@ void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
 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));
 }
 
 
index 2acb2f5f365a0922c95e0e542439d11195b8fbc4..722742e16ca7e5475a432cd069134b58239cbe0a 100644 (file)
@@ -65,7 +65,7 @@ VariableProxy::VariableProxy(Zone* zone, Variable* var, int position,
       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);
@@ -78,7 +78,7 @@ VariableProxy::VariableProxy(Zone* zone, const AstRawString* name, bool is_this,
       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) {}
 
index 847d9cae2b68bcbb93d8b4711a2b110ccd2b30e0..fe9a7fd11f9c7d49cbf74323eb0c4643363e4c75 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -157,11 +157,25 @@ enum AstPropertiesFlag {
 };
 
 
+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_; }
@@ -172,10 +186,14 @@ AstProperties() : node_count_(0), feedback_slots_(0) {}
     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_;
 };
 
 
@@ -237,11 +255,13 @@ class AstNode: public ZoneObject {
   // 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
@@ -945,7 +965,9 @@ class ForInStatement FINAL : public ForEachStatement {
   }
 
   // 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;
   }
@@ -1692,12 +1714,16 @@ class VariableProxy FINAL : public Expression {
   // 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);
@@ -1708,7 +1734,7 @@ class VariableProxy FINAL : public Expression {
   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_
@@ -1759,12 +1785,14 @@ class Property FINAL : public Expression {
     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_;
   }
 
@@ -1774,7 +1802,7 @@ class Property FINAL : public Expression {
         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) {}
 
@@ -1785,7 +1813,7 @@ class Property FINAL : public Expression {
   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_;
@@ -1800,13 +1828,15 @@ class Call FINAL : public Expression {
   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()) {
@@ -1868,7 +1898,7 @@ class Call FINAL : public Expression {
   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()) {
@@ -1880,7 +1910,7 @@ class Call FINAL : public Expression {
   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_;
@@ -1897,8 +1927,8 @@ class CallNew FINAL : public Expression {
   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;
@@ -1958,14 +1988,15 @@ class CallRuntime FINAL : public Expression {
   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_;
   }
 
@@ -1981,7 +2012,7 @@ class CallRuntime FINAL : public Expression {
         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(); }
@@ -1990,7 +2021,7 @@ class CallRuntime FINAL : public Expression {
   const AstRawString* raw_name_;
   const Runtime::Function* function_;
   ZoneList<Expression*>* arguments_;
-  FeedbackVectorSlot callruntime_feedback_slot_;
+  FeedbackVectorICSlot callruntime_feedback_slot_;
 };
 
 
@@ -2316,22 +2347,23 @@ class Yield FINAL : public Expression {
   }
 
   // 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,
@@ -2341,14 +2373,14 @@ class Yield FINAL : public 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_;
 };
 
 
@@ -2498,6 +2530,7 @@ class FunctionLiteral FINAL : public Expression {
   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) {
@@ -2636,12 +2669,14 @@ class SuperReference FINAL : public Expression {
   }
 
   // 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_;
   }
@@ -2650,7 +2685,7 @@ class SuperReference FINAL : public Expression {
   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());
   }
 
@@ -2659,7 +2694,7 @@ class SuperReference FINAL : public Expression {
 
  private:
   VariableProxy* this_var_;
-  FeedbackVectorSlot homeobject_feedback_slot_;
+  FeedbackVectorICSlot homeobject_feedback_slot_;
 };
 
 
@@ -3123,11 +3158,16 @@ class AstConstructionVisitor BASE_EMBEDDED {
   }
 
   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());
     }
   }
 
index 1e453e5e298b4abf1bf4310782b2b7bdc396956e..eafc89b733d0fc7d2a38bb1e61a19474481f0fdf 100644 (file)
@@ -1956,7 +1956,7 @@ bool Genesis::InstallNatives() {
       // 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);
     }
 
index 402011ebb9ef418664caf657cab2c90c8bd68639..0e6c3a3867c95a824698396991b8d7e3d7c9e882 100644 (file)
@@ -291,12 +291,13 @@ void CompilationInfo::PrepareForCompilation(Scope* scope) {
   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());
 }
 
 
index ba10bf57f31f6a0594dfd226ee342e4c9a7bf24c..a85dcd5559288f15b38a5208a2552f9a71a8eba8 100644 (file)
@@ -1717,7 +1717,7 @@ StrictMode AstGraphBuilder::strict_mode() const {
 
 
 VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
-    FeedbackVectorSlot slot) const {
+    FeedbackVectorICSlot slot) const {
   return VectorSlotPair(handle(info()->shared_info()->feedback_vector()), slot);
 }
 
index 59439d80fc6f3e54ccf8cccf44b9c28b24bcd4bd..33c8f1208baa70b284049d437a57aabc75d26918 100644 (file)
@@ -145,7 +145,7 @@ class AstGraphBuilder : public StructuredGraphBuilder, public AstVisitor {
   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.
index 8cd9fc7605f8b9327263a98304d5ae36e9cc2c09..b659292d6680f7e2cd9a3c3a1cc4d8b17c41ddce 100644 (file)
@@ -98,15 +98,15 @@ ContextAccess const& ContextAccessOf(Operator const*);
 
 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_;
 };
 
 
index e284382a9cb362b03cd6102ba501eabf7ec4a6b1..5713f73160c0ad312c8c2e9bbc90dbeaa94da3ec 100644 (file)
@@ -1982,20 +1982,9 @@ void Factory::BecomeJSFunction(Handle<JSProxy> proxy) {
 }
 
 
-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);
 }
 
 
@@ -2070,7 +2059,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
   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);
index 1a658d17cbae4ea4082b87f04ede4b012ee6569f..e9972cc13a8a96613a3bc4102745bb43c503045f 100644 (file)
@@ -622,7 +622,8 @@ class Factory FINAL {
                                                    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(
index 61a6eac6349a73896b88b5676b8660552affb151..89ae329823937508b500fba45144c70bd1780b74 100644 (file)
@@ -367,11 +367,22 @@ unsigned FullCodeGenerator::EmitBackEdgeTable() {
 
 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);
   }
 }
 
index 57283bbaae7783d92206c67a76ea37c1101eb07f..078b69be6ad9ab5f04ef4f2815308b7804035e19 100644 (file)
@@ -429,12 +429,20 @@ class FullCodeGenerator: public AstVisitor {
 
   // 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
index dcf8a9b02607508d75169d4740ab2321d27a309a..28dfbc577dd968855ca9ba3463ad619c9a656236 100644 (file)
@@ -262,6 +262,7 @@ void StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget(Heap* heap,
   // 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()) ||
index 3dcdf58a62df4f7e41a7429f4f8a45830d93d947..b08bc7705a71b4bf9991554cc1ea708ffdc5c179 100644 (file)
@@ -5475,12 +5475,15 @@ class HLoadGlobalGeneric FINAL : public HTemplateInstruction<2> {
   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;
@@ -5499,7 +5502,7 @@ class HLoadGlobalGeneric FINAL : public HTemplateInstruction<2> {
                      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());
@@ -5508,8 +5511,8 @@ class HLoadGlobalGeneric FINAL : public HTemplateInstruction<2> {
 
   Handle<String> name_;
   bool for_typeof_;
-  Handle<FixedArray> feedback_vector_;
-  FeedbackVectorSlot slot_;
+  Handle<TypeFeedbackVector> feedback_vector_;
+  FeedbackVectorICSlot slot_;
 };
 
 
@@ -6480,12 +6483,15 @@ class HLoadNamedGeneric FINAL : public HTemplateInstruction<2> {
   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;
@@ -6501,7 +6507,7 @@ class HLoadNamedGeneric FINAL : public HTemplateInstruction<2> {
 
  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());
@@ -6509,8 +6515,8 @@ class HLoadNamedGeneric FINAL : public HTemplateInstruction<2> {
   }
 
   Handle<Object> name_;
-  Handle<FixedArray> feedback_vector_;
-  FeedbackVectorSlot slot_;
+  Handle<TypeFeedbackVector> feedback_vector_;
+  FeedbackVectorICSlot slot_;
 };
 
 
@@ -6756,12 +6762,15 @@ class HLoadKeyedGeneric FINAL : public HTemplateInstruction<3> {
   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;
@@ -6780,7 +6789,7 @@ class HLoadKeyedGeneric FINAL : public HTemplateInstruction<3> {
 
  private:
   HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key)
-      : slot_(FeedbackVectorSlot::Invalid()) {
+      : slot_(FeedbackVectorICSlot::Invalid()) {
     set_representation(Representation::Tagged());
     SetOperandAt(0, obj);
     SetOperandAt(1, key);
@@ -6788,8 +6797,8 @@ class HLoadKeyedGeneric FINAL : public HTemplateInstruction<3> {
     SetAllSideEffects();
   }
 
-  Handle<FixedArray> feedback_vector_;
-  FeedbackVectorSlot slot_;
+  Handle<TypeFeedbackVector> feedback_vector_;
+  FeedbackVectorICSlot slot_;
 };
 
 
index d64289882d0086b9200a56583da27b7c3da87454..643483394e481077960acdc1e54f8c2e25dd49a6 100644 (file)
@@ -2271,6 +2271,13 @@ void CallICStub::Generate(MacroAssembler* masm) {
     __ 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);
   }
 
index cddefa1b85d93d25e5c8e06f41532ffa3d746967..96525029ce584c43d2ec2b2e1bf7905dce5a11a4 100644 (file)
@@ -1117,7 +1117,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
 
   // 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
index 646cb8690dfea0a71e3f1441f84b742266528a2f..c64a4b0892e763007b80ee49434f278ed4c846fd 100644 (file)
@@ -2828,13 +2828,15 @@ void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
 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)));
 }
 
 
index e10fb456ce5cc6a8bdc75216a99a59749537b884..91b8955fd47ca08b7eb2cd6d63aa788cf67efb23 100644 (file)
@@ -208,17 +208,26 @@ Handle<Map> IC::GetICCacheHolder(HeapType* type, Isolate* isolate,
 }
 
 
-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;
index 6dcf13d19f1255e395ca9efc9b016eaaed8755d3..5a17bc8688c77514d1ed2865675524d31f75ba06 100644 (file)
 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)) {}
index 72fc865c68d1ebe221f37829f5e457bf7c12cd84..a8cfefd10453466405cd8d72940d337f18bc7aa2 100644 (file)
@@ -19,6 +19,9 @@ class ICUtility : public AllStatic {
   // 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);
 };
 
 
index 8730a3fa038550da51728b71fdb4ff83e08d6e0c..98d86b5e39f41e97b45bc301e92e5768ba4a2616 100644 (file)
@@ -491,12 +491,11 @@ void IC::Clear(Isolate* isolate, Address address,
       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
@@ -508,6 +507,17 @@ void IC::Clear(Isolate* isolate, Address address,
 }
 
 
+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;
@@ -519,9 +529,19 @@ void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
 }
 
 
-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);
+  }
 }
 
 
@@ -1920,9 +1940,34 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
 }
 
 
+// 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?
@@ -1930,12 +1975,12 @@ bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> 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);
@@ -1946,8 +1991,8 @@ bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function,
                             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;
   }
@@ -1957,13 +2002,12 @@ bool CallIC::DoCustomHandler(Handle<Object> receiver, Handle<Object> function,
 
 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);
@@ -1976,26 +2020,26 @@ void CallIC::PatchMegamorphic(Handle<Object> function,
     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.
@@ -2013,7 +2057,7 @@ void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function,
       return;
     }
 
-    vector->set(slot->value(), *function);
+    vector->Set(slot, *function);
   }
 
   if (function->IsJSFunction()) {
@@ -2021,8 +2065,8 @@ void CallIC::HandleMiss(Handle<Object> receiver, Handle<Object> function,
     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);
 }
 
@@ -2044,7 +2088,8 @@ RUNTIME_FUNCTION(CallIC_Miss) {
   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;
 }
 
@@ -2058,7 +2103,8 @@ RUNTIME_FUNCTION(CallIC_Customization_Miss) {
   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;
 }
 
index 44df480f5500f7b8d10c9bdede035cd36d44d407..5177ff8e22881aa53bd119419142a96a5894a830 100644 (file)
@@ -86,6 +86,10 @@ class IC {
   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();
@@ -294,26 +298,35 @@ class CallIC : public IC {
   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);
 };
 
 
index ef980dc2b9ea26ee2482ba40c078d2e594b0acc0..162b9043acbf15fe64867f67ade5110afa390d7d 100644 (file)
@@ -1931,6 +1931,10 @@ bool Isolate::Init(Deserializer* des) {
     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);
@@ -1949,8 +1953,6 @@ bool Isolate::Init(Deserializer* des) {
   // 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];
@@ -1960,7 +1962,6 @@ bool Isolate::Init(Deserializer* des) {
                                    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 &&
index a87c31bac17f544093162e0f93136aaa363eb864..b1476a0b6ec32c09a8b04f7fb86e729234db32f7 100644 (file)
@@ -605,13 +605,9 @@ static int GetArrayLength(Handle<JSArray> array) {
 }
 
 
-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);
@@ -619,6 +615,7 @@ void FunctionInfoWrapper::SetInitialProperties(Handle<String> name,
   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);
 }
 
@@ -658,12 +655,15 @@ Handle<TypeFeedbackVector> FunctionInfoWrapper::GetFeedbackVector() {
     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;
 }
@@ -706,11 +706,10 @@ class FunctionInfoListener {
   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_++;
index 53418b0918964cf9e548f6d3e1f0d8595053d2e2..6534b7e378f153593eca4273ece50201caa81459 100644 (file)
@@ -280,12 +280,9 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
       : 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,
@@ -321,6 +318,8 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
     return this->GetSmiValueField(kSlotNumOffset_);
   }
 
+  int GetICSlotCount() { return this->GetSmiValueField(kICSlotNumOffset_); }
+
  private:
   static const int kFunctionNameOffset_ = 0;
   static const int kStartPositionOffset_ = 1;
@@ -333,7 +332,8 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
   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>;
 };
index 0ebc0a48f539a468303a896c3556d46783d8304d..e827d777e5288987d96de0770aeab65ee7b4e18e 100644 (file)
@@ -2886,6 +2886,17 @@ void CallICStub::Generate(MacroAssembler* masm) {
     __ 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);
   }
 
index 9f26d4cfe129381ff359bc75e907c4cff5d05390..479e3f87f72b74d168a955b561a1469ded855f2f 100644 (file)
@@ -1181,7 +1181,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
 
   __ 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
index 50325bd672536b9fd0fd793ea8577690ed09f739..c9e3686c9e1bf5e76a208522aaf0a5faeb3a37be 100644 (file)
@@ -2887,13 +2887,14 @@ void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
 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)));
 }
 
 
index 1dff71eca2e57b89c792365842c4dea87b3b3a76..b95787fe16df3f97202c6d716c5e32c33cf6bd45 100644 (file)
@@ -10497,27 +10497,7 @@ void Code::ClearInlineCaches(Code::Kind* kind) {
 
 
 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);
 }
 
 
index d944bee72a1082a2695b8263f2e11a6d46691047..603f7b3e3f8a78a2c4be4178cb9d34f33321ccf9 100644 (file)
@@ -8131,7 +8131,6 @@ class TypeFeedbackInfo: public Struct {
   inline void set_inlined_type_change_checksum(int checksum);
   inline bool matches_inlined_type_change_checksum(int checksum);
 
-
   DECLARE_CAST(TypeFeedbackInfo)
 
   // Dispatched behavior.
index d6099d43be86001892e3f97e74bd08cca981da1c..f786846b365ba1cc43ac04a4803dbeef8c803a92 100644 (file)
@@ -57,9 +57,11 @@ RuntimeProfiler::RuntimeProfiler(Isolate* isolate)
 }
 
 
-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;
@@ -70,6 +72,12 @@ static void GetICCounts(Code* shared_code, int* ic_with_type_info_count,
     *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;
@@ -89,7 +97,7 @@ void RuntimeProfiler::Optimize(JSFunction* function, const char* reason) {
     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);
@@ -236,7 +244,7 @@ void RuntimeProfiler::OptimizeNow() {
 
     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) {
@@ -259,7 +267,7 @@ void RuntimeProfiler::OptimizeNow() {
       // 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) {
index 43e768ee5df86601fe070ff05e102b4798b78bb1..477a5281d092880efc5e06b0af5fa9639403dbaa 100644 (file)
@@ -21,7 +21,7 @@ Handle<Object> TypeFeedbackVector::MegamorphicSentinel(Isolate* isolate) {
 
 
 Handle<Object> TypeFeedbackVector::PremonomorphicSentinel(Isolate* isolate) {
-  return isolate->factory()->megamorphic_symbol();
+  return isolate->factory()->premonomorphic_symbol();
 }
 
 
index a3fe0707c7d578fbbbcf204dc51a68694308b271..dcae7c72e657bacba67c4ee206fb28c57365098f 100644 (file)
@@ -4,12 +4,43 @@
 
 #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) {
@@ -18,5 +49,42 @@ Handle<TypeFeedbackVector> TypeFeedbackVector::Copy(
       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
index b6fadba73ea0623ea62ee852f15eda9af3394207..ddfa8dd85a915bcbefd18508db4f3b47aaf08ccc 100644 (file)
 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.
@@ -22,9 +31,98 @@ class TypeFeedbackVector : public FixedArray {
     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);
 
index 6cb8e9576da7e56f7576c4999f87eb9ba4779907..2c033b020061bb8479d638d59aea41674075dc9f 100644 (file)
@@ -51,7 +51,18 @@ Handle<Object> TypeFeedbackOracle::GetInfo(TypeFeedbackId ast_id) {
 
 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());
@@ -78,7 +89,7 @@ bool TypeFeedbackOracle::StoreIsUninitialized(TypeFeedbackId ast_id) {
 }
 
 
-bool TypeFeedbackOracle::CallIsMonomorphic(FeedbackVectorSlot slot) {
+bool TypeFeedbackOracle::CallIsMonomorphic(FeedbackVectorICSlot slot) {
   Handle<Object> value = GetInfo(slot);
   return value->IsAllocationSite() || value->IsJSFunction();
 }
@@ -119,7 +130,8 @@ void TypeFeedbackOracle::GetStoreModeAndKeyType(
 }
 
 
-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());
@@ -142,7 +154,7 @@ Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(
 
 
 Handle<AllocationSite> TypeFeedbackOracle::GetCallAllocationSite(
-    FeedbackVectorSlot slot) {
+    FeedbackVectorICSlot slot) {
   Handle<Object> info = GetInfo(slot);
   if (info->IsAllocationSite()) {
     return Handle<AllocationSite>::cast(info);
index 5b13810d95317e9b032babeafebdf1b1eade2fb0..8fe581813b35cc94e3e3d7dd02d06db4ef4ee4a9 100644 (file)
@@ -25,8 +25,7 @@ class TypeFeedbackOracle: public ZoneObject {
 
   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);
 
@@ -62,8 +61,8 @@ class TypeFeedbackOracle: public ZoneObject {
   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);
 
@@ -116,6 +115,7 @@ class TypeFeedbackOracle: public ZoneObject {
   // 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_;
index 5c58ff8e608d03df56ea9b1b082dffc726d95ec8..58bcb3ae746c4955e8b7957ccdc07527a1a57c26 100644 (file)
@@ -951,21 +951,22 @@ class TypeFeedbackId {
 };
 
 
-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;
 
@@ -973,6 +974,10 @@ class FeedbackVectorSlot {
 };
 
 
+typedef VectorSlot<0> FeedbackVectorSlot;
+typedef VectorSlot<1> FeedbackVectorICSlot;
+
+
 class BailoutId {
  public:
   explicit BailoutId(int id) : id_(id) { }
index 0f26d3ba5a7c1b63d497f55e722e4546ee56071d..01bddaf970fc5ea384a5b444d60f05188eac06ae 100644 (file)
@@ -2145,6 +2145,13 @@ void CallICStub::Generate(MacroAssembler* masm) {
     __ 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);
   }
 
index 9b63de9c9baf8214f42ed5cd549a886a0d96e21b..c078f979998946925dd166f50f4aeec3ce1562ef 100644 (file)
@@ -1149,7 +1149,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
 
   // 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
index 1587f75218f704fa0f653c4413205bf60a480d6c..7e482ee3fa363f42a69dd0f66f236bff274342da 100644 (file)
@@ -2850,13 +2850,14 @@ void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
 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));
 }
 
 
index da805f6adbb16b819de9ec415ce25a15ac2b4c15..26ba0e259b8d314ad2e9c8576353a1eaad444bae 100644 (file)
         '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',
index 4d6e005a8b8cf3fe1b35f39e79310614310952b5..d3c06baa45e08198540d007c69db049c21781108 100644 (file)
@@ -306,12 +306,15 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) {
   // 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);");
 
@@ -319,8 +322,7 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) {
   // 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());
 }
 
 
@@ -346,15 +348,19 @@ TEST(FeedbackVectorUnaffectedByScopeChanges) {
           *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());
 }
 
diff --git a/test/cctest/test-feedback-vector.cc b/test/cctest/test-feedback-vector.cc
new file mode 100644 (file)
index 0000000..7e4fec8
--- /dev/null
@@ -0,0 +1,138 @@
+// 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());
+}
+}
index 2e285916079f61528887345627c52b2d656e0168..f3dfeca9fbb5be46b8a315f3e4b2d7f97083cdec 100644 (file)
@@ -3189,20 +3189,18 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) {
 
   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()));
   }
 }
index 5715819b7c6cf7778d2341e6477fb4235c9f7d86..3da4bc71683a75e82c19ee7dedeadfd066c5d3c5 100644 (file)
@@ -78,7 +78,7 @@ TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
   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);