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:
parent
b5197ea478
commit
4ededa8694
@ -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();
|
||||
|
32
src/ast.cc
32
src/ast.cc
@ -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.
|
||||
|
62
src/ast.h
62
src/ast.h
@ -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; }
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user