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;
}
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());
}
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());
}
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());
}
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));
}
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;
}
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;
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)) {
}
-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) {
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;
}
};
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);
};
--- /dev/null
+// 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");
--- /dev/null
+// 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));
--- /dev/null
+// 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));
--- /dev/null
+// 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));
--- /dev/null
+// 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));