Vector-ICs: Implement slot sharing for global loads.

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}
This commit is contained in:
mvstanton 2015-03-12 02:22:47 -07:00 committed by Commit bot
parent b5197ea478
commit 4ededa8694
4 changed files with 108 additions and 23 deletions

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

View 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.

View File

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

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