class AstNumberingVisitor final : public AstVisitor {
public:
- explicit AstNumberingVisitor(Isolate* isolate, Zone* zone)
+ AstNumberingVisitor(Isolate* isolate, Zone* zone)
: AstVisitor(),
next_id_(BailoutId::FirstUsable().ToInt()),
properties_(zone),
bool Finish(FunctionLiteral* node);
+ void VisitVariableProxyReference(VariableProxy* node);
+ void VisitPropertyReference(Property* node);
+ void VisitReference(Expression* expr);
+
void VisitStatements(ZoneList<Statement*>* statements) override;
void VisitDeclarations(ZoneList<Declaration*>* declarations) override;
void VisitArguments(ZoneList<Expression*>* arguments);
}
-void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node) {
+void AstNumberingVisitor::VisitVariableProxyReference(VariableProxy* node) {
IncrementNodeCount();
if (node->var()->IsLookupSlot()) {
DisableCrankshaft(kReferenceToAVariableWhichRequiresDynamicLookup);
}
- ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(VariableProxy::num_ids()));
}
+void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node) {
+ VisitVariableProxyReference(node);
+ ReserveFeedbackSlots(node);
+}
+
+
void AstNumberingVisitor::VisitThisFunction(ThisFunction* node) {
IncrementNodeCount();
node->set_base_id(ReserveIdRange(ThisFunction::num_ids()));
}
-void AstNumberingVisitor::VisitProperty(Property* node) {
+void AstNumberingVisitor::VisitPropertyReference(Property* node) {
IncrementNodeCount();
- ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(Property::num_ids()));
Visit(node->key());
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) {
IncrementNodeCount();
node->set_base_id(ReserveIdRange(Assignment::num_ids()));
if (node->is_compound()) VisitBinaryOperation(node->binary_operation());
- Visit(node->target());
+ VisitReference(node->target());
Visit(node->value());
ReserveFeedbackSlots(node);
}
ICSlotCache* cache) override;
Code::Kind FeedbackICSlotKind(int index) override { return Code::LOAD_IC; }
FeedbackVectorICSlot VariableFeedbackSlot() {
- DCHECK(!UsesVariableFeedbackSlot() || !variable_feedback_slot_.IsInvalid());
return variable_feedback_slot_;
}
}
FeedbackVectorICSlot PropertyFeedbackSlot() const {
- DCHECK(!property_feedback_slot_.IsInvalid());
return property_feedback_slot_;
}
InlineCacheState TypeFeedbackOracle::LoadInlineCacheState(
FeedbackVectorICSlot slot) {
- Code::Kind kind = feedback_vector_->GetKind(slot);
- if (kind == Code::LOAD_IC) {
- LoadICNexus nexus(feedback_vector_, slot);
- return nexus.StateFromFeedback();
- } else if (kind == Code::KEYED_LOAD_IC) {
- KeyedLoadICNexus nexus(feedback_vector_, slot);
- return nexus.StateFromFeedback();
+ if (!slot.IsInvalid()) {
+ Code::Kind kind = feedback_vector_->GetKind(slot);
+ if (kind == Code::LOAD_IC) {
+ LoadICNexus nexus(feedback_vector_, slot);
+ return nexus.StateFromFeedback();
+ } else if (kind == Code::KEYED_LOAD_IC) {
+ 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
Handle<Name> name,
SmallMapList* receiver_types) {
receiver_types->Clear();
- LoadICNexus nexus(feedback_vector_, slot);
- Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
- CollectReceiverTypes(&nexus, name, flags, receiver_types);
+ if (!slot.IsInvalid()) {
+ LoadICNexus nexus(feedback_vector_, slot);
+ Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
+ CollectReceiverTypes(&nexus, name, flags, receiver_types);
+ }
}
FeedbackVectorICSlot slot, SmallMapList* receiver_types, bool* is_string,
IcCheckType* key_type) {
receiver_types->Clear();
- KeyedLoadICNexus nexus(feedback_vector_, slot);
- CollectReceiverTypes<FeedbackNexus>(&nexus, receiver_types);
- *is_string = HasOnlyStringMaps(receiver_types);
- *key_type = nexus.FindFirstName() != NULL ? PROPERTY : ELEMENT;
+ if (slot.IsInvalid()) {
+ *is_string = false;
+ *key_type = ELEMENT;
+ } else {
+ KeyedLoadICNexus nexus(feedback_vector_, slot);
+ CollectReceiverTypes<FeedbackNexus>(&nexus, receiver_types);
+ *is_string = HasOnlyStringMaps(receiver_types);
+ *key_type = nexus.FindFirstName() != NULL ? PROPERTY : ELEMENT;
+ }
}
nexus.FindAllMaps(&maps2);
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);
+}
}