Vector-ICs: Implement slot sharing for global loads.
authormvstanton <mvstanton@chromium.org>
Thu, 12 Mar 2015 09:22:47 +0000 (02:22 -0700)
committerCommit bot <commit-bot@chromium.org>
Thu, 12 Mar 2015 09:23:01 +0000 (09:23 +0000)
We can reduce the number of type feedback vector slots required, and
also reduce IC misses.

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

Cr-Commit-Position: refs/heads/master@{#27149}

src/ast-numbering.cc
src/ast.cc
src/ast.h
test/cctest/test-feedback-vector.cc

index 152363e8fd0e58de555742d90b479234b6bd0f53..eaaaf29596f6f17d5fc4e39164b4c2d33b1a44a7 100644 (file)
@@ -17,6 +17,7 @@ class AstNumberingVisitor FINAL : public AstVisitor {
   explicit AstNumberingVisitor(Isolate* isolate, Zone* zone)
       : AstVisitor(),
         next_id_(BailoutId::FirstUsable().ToInt()),
+        ic_slot_cache_(FLAG_vector_ics ? 4 : 0),
         dont_optimize_reason_(kNoReason) {
     InitializeAstVisitor(isolate, zone);
   }
@@ -59,14 +60,15 @@ class AstNumberingVisitor FINAL : public AstVisitor {
   template <typename Node>
   void ReserveFeedbackSlots(Node* node) {
     FeedbackVectorRequirements reqs =
-        node->ComputeFeedbackRequirements(isolate());
+        node->ComputeFeedbackRequirements(isolate(), &ic_slot_cache_);
     if (reqs.slots() > 0) {
       node->SetFirstFeedbackSlot(FeedbackVectorSlot(properties_.slots()));
       properties_.increase_slots(reqs.slots());
     }
     if (reqs.ic_slots() > 0) {
       int ic_slots = properties_.ic_slots();
-      node->SetFirstFeedbackICSlot(FeedbackVectorICSlot(ic_slots));
+      node->SetFirstFeedbackICSlot(FeedbackVectorICSlot(ic_slots),
+                                   &ic_slot_cache_);
       properties_.increase_ic_slots(reqs.ic_slots());
       if (FLAG_vector_ics) {
         for (int i = 0; i < reqs.ic_slots(); i++) {
@@ -80,6 +82,9 @@ class AstNumberingVisitor FINAL : public AstVisitor {
 
   int next_id_;
   AstProperties properties_;
+  // The slot cache allows us to reuse certain vector IC slots. It's only used
+  // if FLAG_vector_ics is true.
+  ICSlotCache ic_slot_cache_;
   BailoutReason dont_optimize_reason_;
 
   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
index 01c4131d3a9e895647acac9a4fac6b4255e1b7ca..482c2e6cb74ec776a37a91bf2ac551ca49c82502 100644 (file)
@@ -90,6 +90,35 @@ void VariableProxy::BindTo(Variable* var) {
 }
 
 
+void VariableProxy::SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                                           ICSlotCache* cache) {
+  variable_feedback_slot_ = slot;
+  if (var()->IsUnallocated()) {
+    cache->Add(VariableICSlotPair(var(), slot));
+  }
+}
+
+
+FeedbackVectorRequirements VariableProxy::ComputeFeedbackRequirements(
+    Isolate* isolate, const ICSlotCache* cache) {
+  if (UsesVariableFeedbackSlot()) {
+    // VariableProxies that point to the same Variable within a function can
+    // make their loads from the same IC slot.
+    if (var()->IsUnallocated()) {
+      for (int i = 0; i < cache->length(); i++) {
+        VariableICSlotPair& pair = cache->at(i);
+        if (pair.variable() == var()) {
+          variable_feedback_slot_ = pair.slot();
+          return FeedbackVectorRequirements(0, 0);
+        }
+      }
+    }
+    return FeedbackVectorRequirements(0, 1);
+  }
+  return FeedbackVectorRequirements(0, 0);
+}
+
+
 Assignment::Assignment(Zone* zone, Token::Value op, Expression* target,
                        Expression* value, int pos)
     : Expression(zone, pos),
@@ -564,7 +593,8 @@ bool Call::IsUsingCallFeedbackSlot(Isolate* isolate) const {
 }
 
 
-FeedbackVectorRequirements Call::ComputeFeedbackRequirements(Isolate* isolate) {
+FeedbackVectorRequirements Call::ComputeFeedbackRequirements(
+    Isolate* isolate, const ICSlotCache* cache) {
   int ic_slots = IsUsingCallFeedbackICSlot(isolate) ? 1 : 0;
   int slots = IsUsingCallFeedbackSlot(isolate) ? 1 : 0;
   // A Call uses either a slot or an IC slot.
index 8a13e21b1ef9929954f6a5301681bd5eaa21cbbc..3c07471a3055d305d942fc4ef900293ead012870 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -165,6 +165,25 @@ class FeedbackVectorRequirements {
 };
 
 
+class VariableICSlotPair FINAL {
+ public:
+  VariableICSlotPair(Variable* variable, FeedbackVectorICSlot slot)
+      : variable_(variable), slot_(slot) {}
+  VariableICSlotPair()
+      : variable_(NULL), slot_(FeedbackVectorICSlot::Invalid()) {}
+
+  Variable* variable() const { return variable_; }
+  FeedbackVectorICSlot slot() const { return slot_; }
+
+ private:
+  Variable* variable_;
+  FeedbackVectorICSlot slot_;
+};
+
+
+typedef List<VariableICSlotPair> ICSlotCache;
+
+
 class AstProperties FINAL BASE_EMBEDDED {
  public:
   class Flags : public EnumSet<AstPropertiesFlag, int> {};
@@ -229,11 +248,12 @@ class AstNode: public ZoneObject {
   // not really nice, but multiple inheritance would introduce yet another
   // vtable entry per node, something we don't want for space reasons.
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) {
+      Isolate* isolate, const ICSlotCache* cache) {
     return FeedbackVectorRequirements(0, 0);
   }
   virtual void SetFirstFeedbackSlot(FeedbackVectorSlot slot) { UNREACHABLE(); }
-  virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) {
+  virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                                      ICSlotCache* cache) {
     UNREACHABLE();
   }
   // Each ICSlot stores a kind of IC which the participating node should know.
@@ -884,7 +904,7 @@ class ForInStatement FINAL : public ForEachStatement {
 
   // Type feedback information.
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(1, 0);
   }
   void SetFirstFeedbackSlot(FeedbackVectorSlot slot) OVERRIDE {
@@ -1646,13 +1666,10 @@ class VariableProxy FINAL : public Expression {
   }
 
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
-    return FeedbackVectorRequirements(0, UsesVariableFeedbackSlot() ? 1 : 0);
-  }
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE;
 
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
-    variable_feedback_slot_ = slot;
-  }
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE;
   Code::Kind FeedbackICSlotKind(int index) OVERRIDE { return Code::LOAD_IC; }
   FeedbackVectorICSlot VariableFeedbackSlot() {
     DCHECK(!UsesVariableFeedbackSlot() || !variable_feedback_slot_.IsInvalid());
@@ -1734,10 +1751,11 @@ class Property FINAL : public Expression {
   }
 
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(0, FLAG_vector_ics ? 1 : 0);
   }
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE {
     property_feedback_slot_ = slot;
   }
   Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
@@ -1784,8 +1802,9 @@ class Call FINAL : public Expression {
 
   // Type feedback information.
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE;
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE;
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE {
     ic_slot_or_slot_ = slot.ToInt();
   }
   void SetFirstFeedbackSlot(FeedbackVectorSlot slot) OVERRIDE {
@@ -1907,7 +1926,7 @@ class CallNew FINAL : public Expression {
 
   // Type feedback information.
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(FLAG_pretenuring_call_new ? 2 : 1, 0);
   }
   void SetFirstFeedbackSlot(FeedbackVectorSlot slot) OVERRIDE {
@@ -1981,10 +2000,11 @@ class CallRuntime FINAL : public Expression {
     return FLAG_vector_ics && is_jsruntime();
   }
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(0, HasCallRuntimeFeedbackSlot() ? 1 : 0);
   }
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE {
     callruntime_feedback_slot_ = slot;
   }
   Code::Kind FeedbackICSlotKind(int index) OVERRIDE { return Code::LOAD_IC; }
@@ -2354,10 +2374,11 @@ class Yield FINAL : public Expression {
     return FLAG_vector_ics && (yield_kind() == kDelegating);
   }
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(0, HasFeedbackSlots() ? 3 : 0);
   }
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE {
     yield_first_feedback_slot_ = slot;
   }
   Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
@@ -2695,10 +2716,11 @@ class SuperReference FINAL : public Expression {
 
   // Type feedback information.
   virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
-      Isolate* isolate) OVERRIDE {
+      Isolate* isolate, const ICSlotCache* cache) OVERRIDE {
     return FeedbackVectorRequirements(0, FLAG_vector_ics ? 1 : 0);
   }
-  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
+  void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
+                              ICSlotCache* cache) OVERRIDE {
     homeobject_feedback_slot_ = slot;
   }
   Code::Kind FeedbackICSlotKind(int index) OVERRIDE { return Code::LOAD_IC; }
index 89c475eab5b3d78c463d1a39f0a5b9e1418220b7..fe7198cded852d63a4bb3e3001dc4abe3483a023 100644 (file)
@@ -307,6 +307,34 @@ TEST(VectorLoadICStates) {
 }
 
 
+TEST(VectorLoadICSlotSharing) {
+  if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
+  CcTest::InitializeVM();
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+
+  // Function f has 3 LoadICs, one for each o, but the ICs share the same
+  // feedback vector IC slot.
+  CompileRun(
+      "var o = 10;"
+      "function f() {"
+      "  var x = o + 10;"
+      "  return o + x + o;"
+      "}"
+      "f();");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+  // There should be one IC slot.
+  Handle<TypeFeedbackVector> feedback_vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
+  CHECK_EQ(1, feedback_vector->ICSlots());
+  FeedbackVectorICSlot slot(0);
+  LoadICNexus nexus(feedback_vector, slot);
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+}
+
+
 TEST(VectorLoadICOnSmi) {
   if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
   CcTest::InitializeVM();