[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:
parent
81c080ef8e
commit
f659ae4c89
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
22
test/mjsunit/compiler/osr-array-len.js
Normal file
22
test/mjsunit/compiler/osr-array-len.js
Normal 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");
|
23
test/mjsunit/unbox-double-field-indexed.js
Normal file
23
test/mjsunit/unbox-double-field-indexed.js
Normal 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));
|
22
test/mjsunit/unbox-double-field.js
Normal file
22
test/mjsunit/unbox-double-field.js
Normal 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));
|
23
test/mjsunit/unbox-smi-field-indexed.js
Normal file
23
test/mjsunit/unbox-smi-field-indexed.js
Normal 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));
|
22
test/mjsunit/unbox-smi-field.js
Normal file
22
test/mjsunit/unbox-smi-field.js
Normal 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));
|
Loading…
Reference in New Issue
Block a user