[turbofan] Support vector IC feedback in the JSTypeFeedbackTable.

R=mvstanton@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#28465}
This commit is contained in:
titzer 2015-05-19 01:58:43 -07:00 committed by Commit bot
parent 81c080ef8e
commit f659ae4c89
8 changed files with 197 additions and 43 deletions

View 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());
}

View 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) {

View 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 map_;
TypeFeedbackIdMap type_feedback_id_map_;
FeedbackVectorICSlotMap feedback_vector_ic_slot_map_;
TypeFeedbackId find(Node* node) {
TypeFeedbackIdMap::const_iterator it = map_.find(node->id());
return it == map_.end() ? TypeFeedbackId::None() : it->second;
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;
}
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);
};

View File

@ -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");

View File

@ -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));

View File

@ -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));

View File

@ -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));

View File

@ -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));