Commit f469b211 authored by mvstanton's avatar mvstanton Committed by Commit bot

Stop overallocating feedback vector slots.

When a Property or a VariableProxy is used as the left hand side of an
assignment statement, there is no need to allocate a LOAD_IC feedback
vector slot for it. Alter the numbering phase to support this.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#29924}
parent 5edd18fc
...@@ -11,7 +11,7 @@ namespace internal { ...@@ -11,7 +11,7 @@ namespace internal {
class AstNumberingVisitor final : public AstVisitor { class AstNumberingVisitor final : public AstVisitor {
public: public:
explicit AstNumberingVisitor(Isolate* isolate, Zone* zone) AstNumberingVisitor(Isolate* isolate, Zone* zone)
: AstVisitor(), : AstVisitor(),
next_id_(BailoutId::FirstUsable().ToInt()), next_id_(BailoutId::FirstUsable().ToInt()),
properties_(zone), properties_(zone),
...@@ -30,6 +30,10 @@ class AstNumberingVisitor final : public AstVisitor { ...@@ -30,6 +30,10 @@ class AstNumberingVisitor final : public AstVisitor {
bool Finish(FunctionLiteral* node); bool Finish(FunctionLiteral* node);
void VisitVariableProxyReference(VariableProxy* node);
void VisitPropertyReference(Property* node);
void VisitReference(Expression* expr);
void VisitStatements(ZoneList<Statement*>* statements) override; void VisitStatements(ZoneList<Statement*>* statements) override;
void VisitDeclarations(ZoneList<Declaration*>* declarations) override; void VisitDeclarations(ZoneList<Declaration*>* declarations) override;
void VisitArguments(ZoneList<Expression*>* arguments); void VisitArguments(ZoneList<Expression*>* arguments);
...@@ -145,16 +149,21 @@ void AstNumberingVisitor::VisitRegExpLiteral(RegExpLiteral* node) { ...@@ -145,16 +149,21 @@ void AstNumberingVisitor::VisitRegExpLiteral(RegExpLiteral* node) {
} }
void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node) { void AstNumberingVisitor::VisitVariableProxyReference(VariableProxy* node) {
IncrementNodeCount(); IncrementNodeCount();
if (node->var()->IsLookupSlot()) { if (node->var()->IsLookupSlot()) {
DisableCrankshaft(kReferenceToAVariableWhichRequiresDynamicLookup); DisableCrankshaft(kReferenceToAVariableWhichRequiresDynamicLookup);
} }
ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(VariableProxy::num_ids())); node->set_base_id(ReserveIdRange(VariableProxy::num_ids()));
} }
void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node) {
VisitVariableProxyReference(node);
ReserveFeedbackSlots(node);
}
void AstNumberingVisitor::VisitThisFunction(ThisFunction* node) { void AstNumberingVisitor::VisitThisFunction(ThisFunction* node) {
IncrementNodeCount(); IncrementNodeCount();
node->set_base_id(ReserveIdRange(ThisFunction::num_ids())); node->set_base_id(ReserveIdRange(ThisFunction::num_ids()));
...@@ -304,20 +313,35 @@ void AstNumberingVisitor::VisitTryFinallyStatement(TryFinallyStatement* node) { ...@@ -304,20 +313,35 @@ void AstNumberingVisitor::VisitTryFinallyStatement(TryFinallyStatement* node) {
} }
void AstNumberingVisitor::VisitProperty(Property* node) { void AstNumberingVisitor::VisitPropertyReference(Property* node) {
IncrementNodeCount(); IncrementNodeCount();
ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(Property::num_ids())); node->set_base_id(ReserveIdRange(Property::num_ids()));
Visit(node->key()); Visit(node->key());
Visit(node->obj()); Visit(node->obj());
} }
void AstNumberingVisitor::VisitReference(Expression* expr) {
DCHECK(expr->IsProperty() || expr->IsVariableProxy());
if (expr->IsProperty()) {
VisitPropertyReference(expr->AsProperty());
} else {
VisitVariableProxyReference(expr->AsVariableProxy());
}
}
void AstNumberingVisitor::VisitProperty(Property* node) {
VisitPropertyReference(node);
ReserveFeedbackSlots(node);
}
void AstNumberingVisitor::VisitAssignment(Assignment* node) { void AstNumberingVisitor::VisitAssignment(Assignment* node) {
IncrementNodeCount(); IncrementNodeCount();
node->set_base_id(ReserveIdRange(Assignment::num_ids())); node->set_base_id(ReserveIdRange(Assignment::num_ids()));
if (node->is_compound()) VisitBinaryOperation(node->binary_operation()); if (node->is_compound()) VisitBinaryOperation(node->binary_operation());
Visit(node->target()); VisitReference(node->target());
Visit(node->value()); Visit(node->value());
ReserveFeedbackSlots(node); ReserveFeedbackSlots(node);
} }
......
...@@ -1684,7 +1684,6 @@ class VariableProxy final : public Expression { ...@@ -1684,7 +1684,6 @@ class VariableProxy final : public Expression {
ICSlotCache* cache) override; ICSlotCache* cache) override;
Code::Kind FeedbackICSlotKind(int index) override { return Code::LOAD_IC; } Code::Kind FeedbackICSlotKind(int index) override { return Code::LOAD_IC; }
FeedbackVectorICSlot VariableFeedbackSlot() { FeedbackVectorICSlot VariableFeedbackSlot() {
DCHECK(!UsesVariableFeedbackSlot() || !variable_feedback_slot_.IsInvalid());
return variable_feedback_slot_; return variable_feedback_slot_;
} }
...@@ -1792,7 +1791,6 @@ class Property final : public Expression { ...@@ -1792,7 +1791,6 @@ class Property final : public Expression {
} }
FeedbackVectorICSlot PropertyFeedbackSlot() const { FeedbackVectorICSlot PropertyFeedbackSlot() const {
DCHECK(!property_feedback_slot_.IsInvalid());
return property_feedback_slot_; return property_feedback_slot_;
} }
......
...@@ -106,13 +106,15 @@ InlineCacheState TypeFeedbackOracle::LoadInlineCacheState(TypeFeedbackId id) { ...@@ -106,13 +106,15 @@ InlineCacheState TypeFeedbackOracle::LoadInlineCacheState(TypeFeedbackId id) {
InlineCacheState TypeFeedbackOracle::LoadInlineCacheState( InlineCacheState TypeFeedbackOracle::LoadInlineCacheState(
FeedbackVectorICSlot slot) { FeedbackVectorICSlot slot) {
Code::Kind kind = feedback_vector_->GetKind(slot); if (!slot.IsInvalid()) {
if (kind == Code::LOAD_IC) { Code::Kind kind = feedback_vector_->GetKind(slot);
LoadICNexus nexus(feedback_vector_, slot); if (kind == Code::LOAD_IC) {
return nexus.StateFromFeedback(); LoadICNexus nexus(feedback_vector_, slot);
} else if (kind == Code::KEYED_LOAD_IC) { return nexus.StateFromFeedback();
KeyedLoadICNexus nexus(feedback_vector_, slot); } else if (kind == Code::KEYED_LOAD_IC) {
return nexus.StateFromFeedback(); KeyedLoadICNexus nexus(feedback_vector_, slot);
return nexus.StateFromFeedback();
}
} }
// If we can't find an IC, assume we've seen *something*, but we don't know // If we can't find an IC, assume we've seen *something*, but we don't know
...@@ -331,9 +333,11 @@ void TypeFeedbackOracle::PropertyReceiverTypes(FeedbackVectorICSlot slot, ...@@ -331,9 +333,11 @@ void TypeFeedbackOracle::PropertyReceiverTypes(FeedbackVectorICSlot slot,
Handle<Name> name, Handle<Name> name,
SmallMapList* receiver_types) { SmallMapList* receiver_types) {
receiver_types->Clear(); receiver_types->Clear();
LoadICNexus nexus(feedback_vector_, slot); if (!slot.IsInvalid()) {
Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC); LoadICNexus nexus(feedback_vector_, slot);
CollectReceiverTypes(&nexus, name, flags, receiver_types); Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
CollectReceiverTypes(&nexus, name, flags, receiver_types);
}
} }
...@@ -341,10 +345,15 @@ void TypeFeedbackOracle::KeyedPropertyReceiverTypes( ...@@ -341,10 +345,15 @@ void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
FeedbackVectorICSlot slot, SmallMapList* receiver_types, bool* is_string, FeedbackVectorICSlot slot, SmallMapList* receiver_types, bool* is_string,
IcCheckType* key_type) { IcCheckType* key_type) {
receiver_types->Clear(); receiver_types->Clear();
KeyedLoadICNexus nexus(feedback_vector_, slot); if (slot.IsInvalid()) {
CollectReceiverTypes<FeedbackNexus>(&nexus, receiver_types); *is_string = false;
*is_string = HasOnlyStringMaps(receiver_types); *key_type = ELEMENT;
*key_type = nexus.FindFirstName() != NULL ? PROPERTY : ELEMENT; } else {
KeyedLoadICNexus nexus(feedback_vector_, slot);
CollectReceiverTypes<FeedbackNexus>(&nexus, receiver_types);
*is_string = HasOnlyStringMaps(receiver_types);
*key_type = nexus.FindFirstName() != NULL ? PROPERTY : ELEMENT;
}
} }
......
...@@ -385,4 +385,101 @@ TEST(VectorLoadICOnSmi) { ...@@ -385,4 +385,101 @@ TEST(VectorLoadICOnSmi) {
nexus.FindAllMaps(&maps2); nexus.FindAllMaps(&maps2);
CHECK_EQ(2, maps2.length()); CHECK_EQ(2, maps2.length());
} }
static Handle<JSFunction> GetFunction(const char* name) {
Handle<JSFunction> f = v8::Utils::OpenHandle(
*v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str(name))));
return f;
}
TEST(ReferenceContextAllocatesNoSlots) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
Isolate* isolate = CcTest::i_isolate();
CompileRun(
"function testvar(x) {"
" y = x;"
" y = a;"
" return y;"
"}"
"a = 3;"
"testvar({});");
Handle<JSFunction> f = GetFunction("testvar");
// There should be two LOAD_ICs, one for a and one for y at the end.
Handle<TypeFeedbackVector> feedback_vector =
handle(f->shared()->feedback_vector(), isolate);
CHECK_EQ(2, feedback_vector->ICSlots());
CHECK(feedback_vector->GetKind(FeedbackVectorICSlot(0)) == Code::LOAD_IC);
CHECK(feedback_vector->GetKind(FeedbackVectorICSlot(1)) == Code::LOAD_IC);
CompileRun(
"function testprop(x) {"
" x.blue = a;"
"}"
"testprop({ blue: 3 });");
f = GetFunction("testprop");
// There should be one LOAD_IC, for the load of a.
feedback_vector = handle(f->shared()->feedback_vector(), isolate);
CHECK_EQ(1, feedback_vector->ICSlots());
CompileRun(
"function testpropfunc(x) {"
" x().blue = a;"
" return x().blue;"
"}"
"function makeresult() { return { blue: 3 }; }"
"testpropfunc(makeresult);");
f = GetFunction("testpropfunc");
// There should be 2 LOAD_ICs and 2 CALL_ICs.
feedback_vector = handle(f->shared()->feedback_vector(), isolate);
CHECK_EQ(4, feedback_vector->ICSlots());
CHECK(feedback_vector->GetKind(FeedbackVectorICSlot(0)) == Code::CALL_IC);
CHECK(feedback_vector->GetKind(FeedbackVectorICSlot(1)) == Code::LOAD_IC);
CHECK(feedback_vector->GetKind(FeedbackVectorICSlot(2)) == Code::CALL_IC);
CHECK(feedback_vector->GetKind(FeedbackVectorICSlot(3)) == Code::LOAD_IC);
CompileRun(
"function testkeyedprop(x) {"
" x[0] = a;"
" return x[0];"
"}"
"testkeyedprop([0, 1, 2]);");
f = GetFunction("testkeyedprop");
// There should be 1 LOAD_ICs for the load of a, and one KEYED_LOAD_IC for the
// load of x[0] in the return statement.
feedback_vector = handle(f->shared()->feedback_vector(), isolate);
CHECK_EQ(2, feedback_vector->ICSlots());
CHECK(feedback_vector->GetKind(FeedbackVectorICSlot(0)) == Code::LOAD_IC);
CHECK(feedback_vector->GetKind(FeedbackVectorICSlot(1)) ==
Code::KEYED_LOAD_IC);
CompileRun(
"function testcompound(x) {"
" x.old = x.young = x.in_between = a;"
" return x.old + x.young;"
"}"
"testcompound({ old: 3, young: 3, in_between: 3 });");
f = GetFunction("testcompound");
// There should be 3 LOAD_ICs, for load of a and load of x.old and x.young.
feedback_vector = handle(f->shared()->feedback_vector(), isolate);
CHECK_EQ(3, feedback_vector->ICSlots());
CHECK(feedback_vector->GetKind(FeedbackVectorICSlot(0)) == Code::LOAD_IC);
CHECK(feedback_vector->GetKind(FeedbackVectorICSlot(1)) == Code::LOAD_IC);
CHECK(feedback_vector->GetKind(FeedbackVectorICSlot(2)) == Code::LOAD_IC);
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment