[turbofan] Support vector IC feedback in the JSTypeFeedbackTable.
authortitzer <titzer@chromium.org>
Tue, 19 May 2015 08:58:43 +0000 (01:58 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 19 May 2015 08:58:29 +0000 (08:58 +0000)
R=mvstanton@chromium.org
BUG=

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

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

src/compiler/ast-graph-builder.cc
src/compiler/js-type-feedback.cc
src/compiler/js-type-feedback.h
test/mjsunit/compiler/osr-array-len.js [new file with mode: 0644]
test/mjsunit/unbox-double-field-indexed.js [new file with mode: 0644]
test/mjsunit/unbox-double-field.js [new file with mode: 0644]
test/mjsunit/unbox-smi-field-indexed.js [new file with mode: 0644]
test/mjsunit/unbox-smi-field.js [new file with mode: 0644]

index e1f9667..2d92ca5 100644 (file)
@@ -3132,8 +3132,11 @@ Node* AstGraphBuilder::BuildVariableAssignment(
 
 
 static inline Node* Record(JSTypeFeedbackTable* js_type_feedback, Node* node,
-                           TypeFeedbackId id) {
-  if (js_type_feedback) js_type_feedback->Record(node, id);
+                           TypeFeedbackId id, FeedbackVectorICSlot slot) {
+  if (js_type_feedback) {
+    js_type_feedback->Record(node, id);
+    js_type_feedback->Record(node, slot);
+  }
   return node;
 }
 
@@ -3142,7 +3145,8 @@ Node* AstGraphBuilder::BuildKeyedLoad(Node* object, Node* key,
                                       const VectorSlotPair& feedback,
                                       TypeFeedbackId id) {
   const Operator* op = javascript()->LoadProperty(feedback);
-  return Record(js_type_feedback_, NewNode(op, object, key), id);
+  return Record(js_type_feedback_, NewNode(op, object, key), id,
+                feedback.slot());
 }
 
 
@@ -3151,14 +3155,15 @@ Node* AstGraphBuilder::BuildNamedLoad(Node* object, Handle<Name> name,
                                       TypeFeedbackId id, ContextualMode mode) {
   const Operator* op =
       javascript()->LoadNamed(MakeUnique(name), feedback, mode);
-  return Record(js_type_feedback_, NewNode(op, object), id);
+  return Record(js_type_feedback_, NewNode(op, object), id, feedback.slot());
 }
 
 
 Node* AstGraphBuilder::BuildKeyedStore(Node* object, Node* key, Node* value,
                                        TypeFeedbackId id) {
   const Operator* op = javascript()->StoreProperty(language_mode());
-  return Record(js_type_feedback_, NewNode(op, object, key, value), id);
+  return Record(js_type_feedback_, NewNode(op, object, key, value), id,
+                FeedbackVectorICSlot::Invalid());
 }
 
 
@@ -3166,7 +3171,8 @@ Node* AstGraphBuilder::BuildNamedStore(Node* object, Handle<Name> name,
                                        Node* value, TypeFeedbackId id) {
   const Operator* op =
       javascript()->StoreNamed(language_mode(), MakeUnique(name));
-  return Record(js_type_feedback_, NewNode(op, object, value), id);
+  return Record(js_type_feedback_, NewNode(op, object, value), id,
+                FeedbackVectorICSlot::Invalid());
 }
 
 
index c82972a..689e4ac 100644 (file)
@@ -25,13 +25,24 @@ namespace compiler {
 
 enum LoadOrStore { LOAD, STORE };
 
+// TODO(turbofan): fix deoptimization problems
+#define ENABLE_FAST_PROPERTY_LOADS false
+#define ENABLE_FAST_PROPERTY_STORES false
+
 JSTypeFeedbackTable::JSTypeFeedbackTable(Zone* zone)
-    : map_(TypeFeedbackIdMap::key_compare(),
-           TypeFeedbackIdMap::allocator_type(zone)) {}
+    : type_feedback_id_map_(TypeFeedbackIdMap::key_compare(),
+                            TypeFeedbackIdMap::allocator_type(zone)),
+      feedback_vector_ic_slot_map_(TypeFeedbackIdMap::key_compare(),
+                                   TypeFeedbackIdMap::allocator_type(zone)) {}
 
 
 void JSTypeFeedbackTable::Record(Node* node, TypeFeedbackId id) {
-  map_.insert(std::make_pair(node->id(), id));
+  type_feedback_id_map_.insert(std::make_pair(node->id(), id));
+}
+
+
+void JSTypeFeedbackTable::Record(Node* node, FeedbackVectorICSlot slot) {
+  feedback_vector_ic_slot_map_.insert(std::make_pair(node->id(), slot));
 }
 
 
@@ -136,6 +147,10 @@ static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map,
   FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double);
 
   if (field_index.is_inobject()) {
+    if (is_double && !map->IsUnboxedDoubleField(field_index)) {
+      // TODO(turbofan): support for out-of-line (MutableHeapNumber) loads.
+      return false;
+    }
     access->offset = field_index.offset();
     return true;
   }
@@ -162,19 +177,29 @@ Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) {
   Node* frame_state_before = GetFrameStateBefore(node);
   if (frame_state_before == nullptr) return NoChange();
 
-  // TODO(turbofan): handle vector-based type feedback.
-  TypeFeedbackId id = js_type_feedback_->find(node);
-  if (id.IsNone() || oracle()->LoadInlineCacheState(id) == UNINITIALIZED) {
+  const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
+  Handle<Name> name = p.name().handle();
+  SmallMapList maps;
+
+  FeedbackVectorICSlot slot = js_type_feedback_->FindFeedbackVectorICSlot(node);
+  if (slot.IsInvalid() ||
+      oracle()->LoadInlineCacheState(slot) == UNINITIALIZED) {
+    // No type feedback ids or the load is uninitialized.
     return NoChange();
   }
+  if (p.load_ic() == NAMED) {
+    oracle()->PropertyReceiverTypes(slot, name, &maps);
+  } else {
+    // The load named was originally a load property.
+    bool is_string;        // Unused.
+    IcCheckType key_type;  // Unused.
+    oracle()->KeyedPropertyReceiverTypes(slot, &maps, &is_string, &key_type);
+  }
 
-  const LoadNamedParameters& p = LoadNamedParametersOf(node->op());
-  SmallMapList maps;
-  Handle<Name> name = p.name().handle();
   Node* effect = NodeProperties::GetEffectInput(node);
-  GatherReceiverTypes(receiver, effect, id, name, &maps);
 
   if (maps.length() != 1) return NoChange();  // TODO(turbofan): polymorphism
+  if (!ENABLE_FAST_PROPERTY_LOADS) return NoChange();
 
   Handle<Map> map = maps.first();
   FieldAccess field_access;
@@ -276,22 +301,35 @@ Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) {
 
 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) {
   DCHECK(node->opcode() == IrOpcode::kJSStoreNamed);
-  if (true) return NoChange();  // TODO(titzer): storenamed is broken
   Node* frame_state_before = GetFrameStateBefore(node);
   if (frame_state_before == nullptr) return NoChange();
 
-  TypeFeedbackId id = js_type_feedback_->find(node);
-  if (id.IsNone() || oracle()->StoreIsUninitialized(id)) return NoChange();
-
   const StoreNamedParameters& p = StoreNamedParametersOf(node->op());
-  SmallMapList maps;
   Handle<Name> name = p.name().handle();
+  SmallMapList maps;
+  TypeFeedbackId id = js_type_feedback_->FindTypeFeedbackId(node);
+  if (id.IsNone() || oracle()->StoreIsUninitialized(id) == UNINITIALIZED) {
+    // No type feedback ids or the store is uninitialized.
+    // TODO(titzer): no feedback from vector ICs from stores.
+    return NoChange();
+  } else {
+    if (p.store_ic() == NAMED) {
+      oracle()->PropertyReceiverTypes(id, name, &maps);
+    } else {
+      // The named store was originally a store property.
+      bool is_string;        // Unused.
+      IcCheckType key_type;  // Unused.
+      oracle()->KeyedPropertyReceiverTypes(id, &maps, &is_string, &key_type);
+    }
+  }
+
   Node* receiver = node->InputAt(0);
   Node* effect = NodeProperties::GetEffectInput(node);
-  GatherReceiverTypes(receiver, effect, id, name, &maps);
 
   if (maps.length() != 1) return NoChange();  // TODO(turbofan): polymorphism
 
+  if (!ENABLE_FAST_PROPERTY_STORES) return NoChange();
+
   Handle<Map> map = maps.first();
   FieldAccess field_access;
   if (!GetInObjectFieldAccess(STORE, map, name, &field_access)) {
@@ -353,18 +391,6 @@ void JSTypeFeedbackSpecializer::BuildMapCheck(Node* receiver, Handle<Map> map,
 }
 
 
-void JSTypeFeedbackSpecializer::GatherReceiverTypes(Node* receiver,
-                                                    Node* effect,
-                                                    TypeFeedbackId id,
-                                                    Handle<Name> name,
-                                                    SmallMapList* maps) {
-  // TODO(turbofan): filter maps by initial receiver map if known
-  // TODO(turbofan): filter maps by native context (if specializing)
-  // TODO(turbofan): filter maps by effect chain
-  oracle()->PropertyReceiverTypes(id, name, maps);
-}
-
-
 // Get the frame state before an operation if it exists and has a valid
 // bailout id.
 Node* JSTypeFeedbackSpecializer::GetFrameStateBefore(Node* node) {
index 4f1f045..17a6b58 100644 (file)
@@ -27,20 +27,33 @@ class JSTypeFeedbackTable : public ZoneObject {
  public:
   explicit JSTypeFeedbackTable(Zone* zone);
 
-  // TODO(titzer): support recording the feedback vector slot.
-
   void Record(Node* node, TypeFeedbackId id);
+  void Record(Node* node, FeedbackVectorICSlot slot);
 
  private:
   friend class JSTypeFeedbackSpecializer;
   typedef std::map<NodeId, TypeFeedbackId, std::less<NodeId>,
                    zone_allocator<TypeFeedbackId> > TypeFeedbackIdMap;
+  typedef std::map<NodeId, FeedbackVectorICSlot, std::less<NodeId>,
+                   zone_allocator<FeedbackVectorICSlot> >
+      FeedbackVectorICSlotMap;
+
+  TypeFeedbackIdMap type_feedback_id_map_;
+  FeedbackVectorICSlotMap feedback_vector_ic_slot_map_;
+
+  TypeFeedbackId FindTypeFeedbackId(Node* node) {
+    TypeFeedbackIdMap::const_iterator it =
+        type_feedback_id_map_.find(node->id());
+    return it == type_feedback_id_map_.end() ? TypeFeedbackId::None()
+                                             : it->second;
+  }
 
-  TypeFeedbackIdMap map_;
-
-  TypeFeedbackId find(Node* node) {
-    TypeFeedbackIdMap::const_iterator it = map_.find(node->id());
-    return it == map_.end() ? TypeFeedbackId::None() : it->second;
+  FeedbackVectorICSlot FindFeedbackVectorICSlot(Node* node) {
+    FeedbackVectorICSlotMap::const_iterator it =
+        feedback_vector_ic_slot_map_.find(node->id());
+    return it == feedback_vector_ic_slot_map_.end()
+               ? FeedbackVectorICSlot::Invalid()
+               : it->second;
   }
 };
 
@@ -90,9 +103,6 @@ class JSTypeFeedbackSpecializer : public AdvancedReducer {
   void BuildMapCheck(Node* receiver, Handle<Map> map, bool smi_check,
                      Node* effect, Node* control, Node** success, Node** fail);
 
-  void GatherReceiverTypes(Node* receiver, Node* effect, TypeFeedbackId id,
-                           Handle<Name> property, SmallMapList* maps);
-
   Node* GetFrameStateBefore(Node* node);
 };
 
diff --git a/test/mjsunit/compiler/osr-array-len.js b/test/mjsunit/compiler/osr-array-len.js
new file mode 100644 (file)
index 0000000..aaee860
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2015 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.
+
+// Flags: --allow-natives-syntax
+
+
+function fastaRandom(n, table) {
+  var line = new Array(5);
+  while (n > 0) {
+    if (n < line.length) line = new Array(n);
+    %OptimizeOsr();
+    line[0] = n;
+    n--;
+  }
+}
+
+print("---BEGIN 1");
+assertEquals(undefined, fastaRandom(6, null));
+print("---BEGIN 2");
+assertEquals(undefined, fastaRandom(6, null));
+print("---END");
diff --git a/test/mjsunit/unbox-double-field-indexed.js b/test/mjsunit/unbox-double-field-indexed.js
new file mode 100644 (file)
index 0000000..29dfc79
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+// Flags: --allow-natives-syntax
+
+function Foo(x) {
+  this.x = x;
+}
+
+var f = new Foo(1.25);
+var g = new Foo(2.25);
+
+function add(a, b) {
+  var name = "x";
+  return a[name] + b[name];
+}
+
+assertEquals(3.5, add(f, g));
+assertEquals(3.5, add(g, f));
+%OptimizeFunctionOnNextCall(add);
+assertEquals(3.5, add(f, g));
+assertEquals(3.5, add(g, f));
diff --git a/test/mjsunit/unbox-double-field.js b/test/mjsunit/unbox-double-field.js
new file mode 100644 (file)
index 0000000..9fb5479
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2015 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.
+
+// Flags: --allow-natives-syntax
+
+function Foo(x) {
+  this.x = x;
+}
+
+var f = new Foo(1.25);
+var g = new Foo(2.25);
+
+function add(a, b) {
+  return a.x + b.x;
+}
+
+assertEquals(3.5, add(f, g));
+assertEquals(3.5, add(g, f));
+%OptimizeFunctionOnNextCall(add);
+assertEquals(3.5, add(f, g));
+assertEquals(3.5, add(g, f));
diff --git a/test/mjsunit/unbox-smi-field-indexed.js b/test/mjsunit/unbox-smi-field-indexed.js
new file mode 100644 (file)
index 0000000..9e77da0
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+// Flags: --allow-natives-syntax
+
+function Foo(x) {
+  this.x = x;
+}
+
+var f = new Foo(1);
+var g = new Foo(2);
+
+function add(a, b) {
+  var name = "x";
+  return a[name] + b[name];
+}
+
+assertEquals(3, add(f, g));
+assertEquals(3, add(g, f));
+%OptimizeFunctionOnNextCall(add);
+assertEquals(3, add(f, g));
+assertEquals(3, add(g, f));
diff --git a/test/mjsunit/unbox-smi-field.js b/test/mjsunit/unbox-smi-field.js
new file mode 100644 (file)
index 0000000..3619118
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2015 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.
+
+// Flags: --allow-natives-syntax
+
+function Foo(x) {
+  this.x = x;
+}
+
+var f = new Foo(1);
+var g = new Foo(2);
+
+function add(a, b) {
+  return a.x + b.x;
+}
+
+assertEquals(3, add(f, g));
+assertEquals(3, add(g, f));
+%OptimizeFunctionOnNextCall(add);
+assertEquals(3, add(f, g));
+assertEquals(3, add(g, f));