Commit c142994f authored by Michael Stanton's avatar Michael Stanton

Flesh out vector ic state query and set mechanisms.

The IC system now fully integrates the vector concept and can
handle loads and keyed loads vector-based.

BUG=
R=jkummerow@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#25552}
parent 76178f1d
...@@ -69,14 +69,18 @@ class AstNumberingVisitor FINAL : public AstVisitor { ...@@ -69,14 +69,18 @@ class AstNumberingVisitor FINAL : public AstVisitor {
FeedbackVectorRequirements reqs = FeedbackVectorRequirements reqs =
node->ComputeFeedbackRequirements(isolate()); node->ComputeFeedbackRequirements(isolate());
if (reqs.slots() > 0) { if (reqs.slots() > 0) {
node->SetFirstFeedbackSlot( node->SetFirstFeedbackSlot(FeedbackVectorSlot(properties_.slots()));
FeedbackVectorSlot(properties_.feedback_slots())); properties_.increase_slots(reqs.slots());
properties_.increase_feedback_slots(reqs.slots());
} }
if (reqs.ic_slots() > 0) { if (reqs.ic_slots() > 0) {
node->SetFirstFeedbackICSlot( int ic_slots = properties_.ic_slots();
FeedbackVectorICSlot(properties_.ic_feedback_slots())); node->SetFirstFeedbackICSlot(FeedbackVectorICSlot(ic_slots));
properties_.increase_ic_feedback_slots(reqs.ic_slots()); properties_.increase_ic_slots(reqs.ic_slots());
if (FLAG_vector_ics) {
for (int i = 0; i < reqs.ic_slots(); i++) {
properties_.SetKind(ic_slots + i, node->FeedbackICSlotKind(i));
}
}
} }
} }
...@@ -285,6 +289,7 @@ void AstNumberingVisitor::VisitModuleLiteral(ModuleLiteral* node) { ...@@ -285,6 +289,7 @@ void AstNumberingVisitor::VisitModuleLiteral(ModuleLiteral* node) {
void AstNumberingVisitor::VisitCallRuntime(CallRuntime* node) { void AstNumberingVisitor::VisitCallRuntime(CallRuntime* node) {
IncrementNodeCount(); IncrementNodeCount();
ReserveFeedbackSlots(node);
if (node->is_jsruntime()) { if (node->is_jsruntime()) {
// Don't try to optimize JS runtime calls because we bailout on them. // Don't try to optimize JS runtime calls because we bailout on them.
DisableCrankshaft(kCallToAJavaScriptRuntimeFunction); DisableCrankshaft(kCallToAJavaScriptRuntimeFunction);
...@@ -535,6 +540,7 @@ void AstNumberingVisitor::VisitFunctionLiteral(FunctionLiteral* node) { ...@@ -535,6 +540,7 @@ void AstNumberingVisitor::VisitFunctionLiteral(FunctionLiteral* node) {
void AstNumberingVisitor::Renumber(FunctionLiteral* node) { void AstNumberingVisitor::Renumber(FunctionLiteral* node) {
if (node->scope()->HasIllegalRedeclaration()) { if (node->scope()->HasIllegalRedeclaration()) {
node->scope()->VisitIllegalRedeclaration(this); node->scope()->VisitIllegalRedeclaration(this);
node->set_ast_properties(&properties_);
return; return;
} }
......
...@@ -174,25 +174,24 @@ class AstProperties FINAL BASE_EMBEDDED { ...@@ -174,25 +174,24 @@ class AstProperties FINAL BASE_EMBEDDED {
public: public:
class Flags : public EnumSet<AstPropertiesFlag, int> {}; class Flags : public EnumSet<AstPropertiesFlag, int> {};
AstProperties() : node_count_(0), feedback_slots_(0), ic_feedback_slots_(0) {} AstProperties() : node_count_(0) {}
Flags* flags() { return &flags_; } Flags* flags() { return &flags_; }
int node_count() { return node_count_; } int node_count() { return node_count_; }
void add_node_count(int count) { node_count_ += count; } void add_node_count(int count) { node_count_ += count; }
int feedback_slots() const { return feedback_slots_; } int slots() const { return spec_.slots(); }
void increase_feedback_slots(int count) { void increase_slots(int count) { spec_.increase_slots(count); }
feedback_slots_ += count;
}
int ic_feedback_slots() const { return ic_feedback_slots_; } int ic_slots() const { return spec_.ic_slots(); }
void increase_ic_feedback_slots(int count) { ic_feedback_slots_ += count; } void increase_ic_slots(int count) { spec_.increase_ic_slots(count); }
void SetKind(int ic_slot, Code::Kind kind) { spec_.SetKind(ic_slot, kind); }
const FeedbackVectorSpec& get_spec() const { return spec_; }
private: private:
Flags flags_; Flags flags_;
int node_count_; int node_count_;
int feedback_slots_; FeedbackVectorSpec spec_;
int ic_feedback_slots_;
}; };
...@@ -245,6 +244,11 @@ class AstNode: public ZoneObject { ...@@ -245,6 +244,11 @@ class AstNode: public ZoneObject {
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) { virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) {
UNREACHABLE(); UNREACHABLE();
} }
// Each ICSlot stores a kind of IC which the participating node should know.
virtual Code::Kind FeedbackICSlotKind(int index) {
UNREACHABLE();
return Code::NUMBER_OF_KINDS;
}
private: private:
// Hidden to prevent accidental usage. It would have to load the // Hidden to prevent accidental usage. It would have to load the
...@@ -1698,16 +1702,23 @@ class VariableProxy FINAL : public Expression { ...@@ -1698,16 +1702,23 @@ class VariableProxy FINAL : public Expression {
// Bind this proxy to the variable var. Interfaces must match. // Bind this proxy to the variable var. Interfaces must match.
void BindTo(Variable* var); void BindTo(Variable* var);
bool UsesVariableFeedbackSlot() const {
return FLAG_vector_ics && (var()->IsUnallocated() || var()->IsLookupSlot());
}
virtual FeedbackVectorRequirements ComputeFeedbackRequirements( virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
Isolate* isolate) OVERRIDE { Isolate* isolate) OVERRIDE {
return FeedbackVectorRequirements(0, FLAG_vector_ics ? 1 : 0); return FeedbackVectorRequirements(0, UsesVariableFeedbackSlot() ? 1 : 0);
} }
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE { virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
variable_feedback_slot_ = slot; variable_feedback_slot_ = slot;
} }
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return Code::LOAD_IC;
}
FeedbackVectorICSlot VariableFeedbackSlot() { FeedbackVectorICSlot VariableFeedbackSlot() {
DCHECK(!FLAG_vector_ics || !variable_feedback_slot_.IsInvalid()); DCHECK(!UsesVariableFeedbackSlot() || !variable_feedback_slot_.IsInvalid());
return variable_feedback_slot_; return variable_feedback_slot_;
} }
...@@ -1792,6 +1803,9 @@ class Property FINAL : public Expression { ...@@ -1792,6 +1803,9 @@ class Property FINAL : public Expression {
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE { virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
property_feedback_slot_ = slot; property_feedback_slot_ = slot;
} }
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return key()->IsPropertyName() ? Code::LOAD_IC : Code::KEYED_LOAD_IC;
}
FeedbackVectorICSlot PropertyFeedbackSlot() const { FeedbackVectorICSlot PropertyFeedbackSlot() const {
DCHECK(!FLAG_vector_ics || !property_feedback_slot_.IsInvalid()); DCHECK(!FLAG_vector_ics || !property_feedback_slot_.IsInvalid());
...@@ -1836,6 +1850,9 @@ class Call FINAL : public Expression { ...@@ -1836,6 +1850,9 @@ class Call FINAL : public Expression {
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE { virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
call_feedback_slot_ = slot; call_feedback_slot_ = slot;
} }
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return Code::CALL_IC;
}
bool HasCallFeedbackSlot() const { return !call_feedback_slot_.IsInvalid(); } bool HasCallFeedbackSlot() const { return !call_feedback_slot_.IsInvalid(); }
FeedbackVectorICSlot CallFeedbackSlot() const { FeedbackVectorICSlot CallFeedbackSlot() const {
...@@ -2009,17 +2026,22 @@ class CallRuntime FINAL : public Expression { ...@@ -2009,17 +2026,22 @@ class CallRuntime FINAL : public Expression {
bool is_jsruntime() const { return function_ == NULL; } bool is_jsruntime() const { return function_ == NULL; }
// Type feedback information. // Type feedback information.
bool HasCallRuntimeFeedbackSlot() const {
return FLAG_vector_ics && is_jsruntime();
}
virtual FeedbackVectorRequirements ComputeFeedbackRequirements( virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
Isolate* isolate) OVERRIDE { Isolate* isolate) OVERRIDE {
return FeedbackVectorRequirements( return FeedbackVectorRequirements(0, HasCallRuntimeFeedbackSlot() ? 1 : 0);
0, (FLAG_vector_ics && is_jsruntime()) ? 1 : 0);
} }
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE { virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
callruntime_feedback_slot_ = slot; callruntime_feedback_slot_ = slot;
} }
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return Code::LOAD_IC;
}
FeedbackVectorICSlot CallRuntimeFeedbackSlot() { FeedbackVectorICSlot CallRuntimeFeedbackSlot() {
DCHECK(!(FLAG_vector_ics && is_jsruntime()) || DCHECK(!HasCallRuntimeFeedbackSlot() ||
!callruntime_feedback_slot_.IsInvalid()); !callruntime_feedback_slot_.IsInvalid());
return callruntime_feedback_slot_; return callruntime_feedback_slot_;
} }
...@@ -2389,17 +2411,22 @@ class Yield FINAL : public Expression { ...@@ -2389,17 +2411,22 @@ class Yield FINAL : public Expression {
} }
// Type feedback information. // Type feedback information.
bool HasFeedbackSlots() const {
return FLAG_vector_ics && (yield_kind() == kDelegating);
}
virtual FeedbackVectorRequirements ComputeFeedbackRequirements( virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
Isolate* isolate) OVERRIDE { Isolate* isolate) OVERRIDE {
return FeedbackVectorRequirements( return FeedbackVectorRequirements(0, HasFeedbackSlots() ? 3 : 0);
0, (FLAG_vector_ics && yield_kind() == kDelegating) ? 3 : 0);
} }
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE { virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
yield_first_feedback_slot_ = slot; yield_first_feedback_slot_ = slot;
} }
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return index == 0 ? Code::KEYED_LOAD_IC : Code::LOAD_IC;
}
FeedbackVectorICSlot KeyedLoadFeedbackSlot() { FeedbackVectorICSlot KeyedLoadFeedbackSlot() {
DCHECK(!FLAG_vector_ics || !yield_first_feedback_slot_.IsInvalid()); DCHECK(!HasFeedbackSlots() || !yield_first_feedback_slot_.IsInvalid());
return yield_first_feedback_slot_; return yield_first_feedback_slot_;
} }
...@@ -2580,10 +2607,9 @@ class FunctionLiteral FINAL : public Expression { ...@@ -2580,10 +2607,9 @@ class FunctionLiteral FINAL : public Expression {
void set_ast_properties(AstProperties* ast_properties) { void set_ast_properties(AstProperties* ast_properties) {
ast_properties_ = *ast_properties; ast_properties_ = *ast_properties;
} }
int slot_count() { const FeedbackVectorSpec& feedback_vector_spec() const {
return ast_properties_.feedback_slots(); return ast_properties_.get_spec();
} }
int ic_slot_count() { return ast_properties_.ic_feedback_slots(); }
bool dont_optimize() { return dont_optimize_reason_ != kNoReason; } bool dont_optimize() { return dont_optimize_reason_ != kNoReason; }
BailoutReason dont_optimize_reason() { return dont_optimize_reason_; } BailoutReason dont_optimize_reason() { return dont_optimize_reason_; }
void set_dont_optimize_reason(BailoutReason reason) { void set_dont_optimize_reason(BailoutReason reason) {
...@@ -2734,6 +2760,9 @@ class SuperReference FINAL : public Expression { ...@@ -2734,6 +2760,9 @@ class SuperReference FINAL : public Expression {
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE { virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
homeobject_feedback_slot_ = slot; homeobject_feedback_slot_ = slot;
} }
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return Code::LOAD_IC;
}
FeedbackVectorICSlot HomeObjectFeedbackSlot() { FeedbackVectorICSlot HomeObjectFeedbackSlot() {
DCHECK(!FLAG_vector_ics || !homeobject_feedback_slot_.IsInvalid()); DCHECK(!FLAG_vector_ics || !homeobject_feedback_slot_.IsInvalid());
......
...@@ -2038,8 +2038,10 @@ bool Genesis::InstallNatives() { ...@@ -2038,8 +2038,10 @@ bool Genesis::InstallNatives() {
if (FLAG_vector_ics) { if (FLAG_vector_ics) {
// Apply embeds an IC, so we need a type vector of size 1 in the shared // Apply embeds an IC, so we need a type vector of size 1 in the shared
// function info. // function info.
FeedbackVectorSpec spec(0, 1);
spec.SetKind(0, Code::CALL_IC);
Handle<TypeFeedbackVector> feedback_vector = Handle<TypeFeedbackVector> feedback_vector =
factory()->NewTypeFeedbackVector(0, 1); factory()->NewTypeFeedbackVector(spec);
apply->shared()->set_feedback_vector(*feedback_vector); apply->shared()->set_feedback_vector(*feedback_vector);
} }
......
...@@ -297,10 +297,8 @@ void CompilationInfo::PrepareForCompilation(Scope* scope) { ...@@ -297,10 +297,8 @@ void CompilationInfo::PrepareForCompilation(Scope* scope) {
void CompilationInfo::EnsureFeedbackVector() { void CompilationInfo::EnsureFeedbackVector() {
if (feedback_vector_.is_null()) { if (feedback_vector_.is_null()) {
feedback_vector_ = isolate()->factory()->NewTypeFeedbackVector( feedback_vector_ = isolate()->factory()->NewTypeFeedbackVector(
function()->slot_count(), function()->ic_slot_count()); function()->feedback_vector_spec());
} }
DCHECK(feedback_vector_->Slots() == function()->slot_count() &&
feedback_vector_->ICSlots() == function()->ic_slot_count());
} }
......
...@@ -2014,9 +2014,9 @@ void Factory::BecomeJSFunction(Handle<JSProxy> proxy) { ...@@ -2014,9 +2014,9 @@ void Factory::BecomeJSFunction(Handle<JSProxy> proxy) {
} }
Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(int slot_count, Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(
int ic_slot_count) { const FeedbackVectorSpec& spec) {
return TypeFeedbackVector::Allocate(isolate(), slot_count, ic_slot_count); return TypeFeedbackVector::Allocate(isolate(), spec);
} }
...@@ -2091,7 +2091,9 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo( ...@@ -2091,7 +2091,9 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
share->set_script(*undefined_value(), SKIP_WRITE_BARRIER); share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_debug_info(*undefined_value(), SKIP_WRITE_BARRIER); share->set_debug_info(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_inferred_name(*empty_string(), SKIP_WRITE_BARRIER); share->set_inferred_name(*empty_string(), SKIP_WRITE_BARRIER);
Handle<TypeFeedbackVector> feedback_vector = NewTypeFeedbackVector(0, 0); FeedbackVectorSpec empty_spec;
Handle<TypeFeedbackVector> feedback_vector =
NewTypeFeedbackVector(empty_spec);
share->set_feedback_vector(*feedback_vector, SKIP_WRITE_BARRIER); share->set_feedback_vector(*feedback_vector, SKIP_WRITE_BARRIER);
#if TRACE_MAPS #if TRACE_MAPS
share->set_unique_id(isolate()->GetNextUniqueSharedFunctionInfoId()); share->set_unique_id(isolate()->GetNextUniqueSharedFunctionInfoId());
......
...@@ -10,8 +10,9 @@ ...@@ -10,8 +10,9 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// Interface for handle based allocation. class FeedbackVectorSpec;
// Interface for handle based allocation.
class Factory FINAL { class Factory FINAL {
public: public:
Handle<Oddball> NewOddball(Handle<Map> map, Handle<Oddball> NewOddball(Handle<Map> map,
...@@ -636,8 +637,8 @@ class Factory FINAL { ...@@ -636,8 +637,8 @@ class Factory FINAL {
MaybeHandle<Code> code); MaybeHandle<Code> code);
// Allocate a new type feedback vector // Allocate a new type feedback vector
Handle<TypeFeedbackVector> NewTypeFeedbackVector(int slot_count, Handle<TypeFeedbackVector> NewTypeFeedbackVector(
int ic_slot_count); const FeedbackVectorSpec& spec);
// Allocates a new JSMessageObject object. // Allocates a new JSMessageObject object.
Handle<JSMessageObject> NewJSMessageObject( Handle<JSMessageObject> NewJSMessageObject(
......
...@@ -265,18 +265,32 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { ...@@ -265,18 +265,32 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
static const Register LoadIC_TempRegister() { return r3; } static const Register LoadIC_TempRegister() { return r3; }
static void LoadIC_PushArgs(MacroAssembler* masm) {
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
if (FLAG_vector_ics) {
Register slot = VectorLoadICDescriptor::SlotRegister();
Register vector = VectorLoadICDescriptor::VectorRegister();
__ Push(receiver, name, slot, vector);
} else {
__ Push(receiver, name);
}
}
void LoadIC::GenerateMiss(MacroAssembler* masm) { void LoadIC::GenerateMiss(MacroAssembler* masm) {
// The return address is in lr. // The return address is in lr.
Isolate* isolate = masm->isolate(); Isolate* isolate = masm->isolate();
__ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4); __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4);
__ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister()); LoadIC_PushArgs(masm);
__ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
// Perform tail call to the entry. // Perform tail call to the entry.
ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate); ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
__ TailCallExternalReference(ref, 2, 1); int arg_count = FLAG_vector_ics ? 4 : 2;
__ TailCallExternalReference(ref, arg_count, 1);
} }
...@@ -405,13 +419,13 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { ...@@ -405,13 +419,13 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
__ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4); __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4);
__ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); LoadIC_PushArgs(masm);
// Perform tail call to the entry. // Perform tail call to the entry.
ExternalReference ref = ExternalReference ref =
ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate); ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
int arg_count = FLAG_vector_ics ? 4 : 2;
__ TailCallExternalReference(ref, 2, 1); __ TailCallExternalReference(ref, arg_count, 1);
} }
......
...@@ -357,9 +357,17 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { ...@@ -357,9 +357,17 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
__ IncrementCounter(isolate->counters()->load_miss(), 1, x3, x4); __ IncrementCounter(isolate->counters()->load_miss(), 1, x3, x4);
// Perform tail call to the entry. // Perform tail call to the entry.
__ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); if (FLAG_vector_ics) {
__ Push(VectorLoadICDescriptor::ReceiverRegister(),
VectorLoadICDescriptor::NameRegister(),
VectorLoadICDescriptor::SlotRegister(),
VectorLoadICDescriptor::VectorRegister());
} else {
__ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
}
ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate); ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
__ TailCallExternalReference(ref, 2, 1); int arg_count = FLAG_vector_ics ? 4 : 2;
__ TailCallExternalReference(ref, arg_count, 1);
} }
...@@ -422,13 +430,20 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { ...@@ -422,13 +430,20 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
__ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, x10, x11); __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, x10, x11);
__ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); if (FLAG_vector_ics) {
__ Push(VectorLoadICDescriptor::ReceiverRegister(),
VectorLoadICDescriptor::NameRegister(),
VectorLoadICDescriptor::SlotRegister(),
VectorLoadICDescriptor::VectorRegister());
} else {
__ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
}
// Perform tail call to the entry. // Perform tail call to the entry.
ExternalReference ref = ExternalReference ref =
ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate); ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
int arg_count = FLAG_vector_ics ? 4 : 2;
__ TailCallExternalReference(ref, 2, 1); __ TailCallExternalReference(ref, arg_count, 1);
} }
......
...@@ -767,31 +767,52 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { ...@@ -767,31 +767,52 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
static void LoadIC_PushArgs(MacroAssembler* masm) { static void LoadIC_PushArgs(MacroAssembler* masm) {
Register receiver = LoadDescriptor::ReceiverRegister(); Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister(); Register name = LoadDescriptor::NameRegister();
DCHECK(!ebx.is(receiver) && !ebx.is(name)); if (FLAG_vector_ics) {
Register slot = VectorLoadICDescriptor::SlotRegister();
Register vector = VectorLoadICDescriptor::VectorRegister();
DCHECK(!edi.is(receiver) && !edi.is(name) && !edi.is(slot) &&
!edi.is(vector));
__ pop(edi);
__ push(receiver);
__ push(name);
__ push(slot);
__ push(vector);
__ push(edi);
} else {
DCHECK(!ebx.is(receiver) && !ebx.is(name));
__ pop(ebx); __ pop(ebx);
__ push(receiver); __ push(receiver);
__ push(name); __ push(name);
__ push(ebx); __ push(ebx);
}
} }
void LoadIC::GenerateMiss(MacroAssembler* masm) { void LoadIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack. // Return address is on the stack.
__ IncrementCounter(masm->isolate()->counters()->load_miss(), 1); __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
LoadIC_PushArgs(masm); LoadIC_PushArgs(masm);
// Perform tail call to the entry. // Perform tail call to the entry.
ExternalReference ref = ExternalReference ref =
ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate()); ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1); int arg_count = FLAG_vector_ics ? 4 : 2;
__ TailCallExternalReference(ref, arg_count, 1);
} }
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// Return address is on the stack. // Return address is on the stack.
LoadIC_PushArgs(masm); Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(!ebx.is(receiver) && !ebx.is(name));
__ pop(ebx);
__ push(receiver);
__ push(name);
__ push(ebx);
// Perform tail call to the entry. // Perform tail call to the entry.
__ TailCallRuntime(Runtime::kGetProperty, 2, 1); __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
...@@ -807,13 +828,21 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { ...@@ -807,13 +828,21 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
// Perform tail call to the entry. // Perform tail call to the entry.
ExternalReference ref = ExternalReference ref =
ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1); int arg_count = FLAG_vector_ics ? 4 : 2;
__ TailCallExternalReference(ref, arg_count, 1);
} }
void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// Return address is on the stack. // Return address is on the stack.
LoadIC_PushArgs(masm); Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(!ebx.is(receiver) && !ebx.is(name));
__ pop(ebx);
__ push(receiver);
__ push(name);
__ push(ebx);
// Perform tail call to the entry. // Perform tail call to the entry.
__ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
......
...@@ -96,6 +96,12 @@ Code* IC::GetTargetAtAddress(Address address, ...@@ -96,6 +96,12 @@ Code* IC::GetTargetAtAddress(Address address,
void IC::SetTargetAtAddress(Address address, Code* target, void IC::SetTargetAtAddress(Address address, Code* target,
ConstantPoolArray* constant_pool) { ConstantPoolArray* constant_pool) {
DCHECK(target->is_inline_cache_stub() || target->is_compare_ic_stub()); DCHECK(target->is_inline_cache_stub() || target->is_compare_ic_stub());
// Don't use this for load_ics when --vector-ics is turned on.
DCHECK(!(FLAG_vector_ics && target->is_inline_cache_stub()) ||
(target->kind() != Code::LOAD_IC &&
target->kind() != Code::KEYED_LOAD_IC));
Heap* heap = target->GetHeap(); Heap* heap = target->GetHeap();
Code* old_target = GetTargetAtAddress(address, constant_pool); Code* old_target = GetTargetAtAddress(address, constant_pool);
#ifdef DEBUG #ifdef DEBUG
......
...@@ -17,19 +17,6 @@ void ICUtility::Clear(Isolate* isolate, Address address, ...@@ -17,19 +17,6 @@ void ICUtility::Clear(Isolate* isolate, Address address,
} }
// static
template <class Nexus>
void ICUtility::Clear(Isolate* isolate, Code::Kind kind, Code* host,
Nexus* nexus) {
IC::Clear<Nexus>(isolate, kind, host, nexus);
}
// Force instantiation of template instances for vector-based IC clearing.
template void ICUtility::Clear<CallICNexus>(Isolate*, Code::Kind, Code*,
CallICNexus*);
CallICState::CallICState(ExtraICState extra_ic_state) CallICState::CallICState(ExtraICState extra_ic_state)
: argc_(ArgcBits::decode(extra_ic_state)), : argc_(ArgcBits::decode(extra_ic_state)),
call_type_(CallTypeBits::decode(extra_ic_state)) {} call_type_(CallTypeBits::decode(extra_ic_state)) {}
......
...@@ -19,10 +19,6 @@ class ICUtility : public AllStatic { ...@@ -19,10 +19,6 @@ class ICUtility : public AllStatic {
// Clear the inline cache to initial state. // Clear the inline cache to initial state.
static void Clear(Isolate* isolate, Address address, static void Clear(Isolate* isolate, Address address,
ConstantPoolArray* constant_pool); ConstantPoolArray* constant_pool);
// Clear a vector-based inline cache to initial state.
template <class Nexus>
static void Clear(Isolate* isolate, Code::Kind kind, Code* host,
Nexus* nexus);
}; };
......
This diff is collapsed.
...@@ -88,11 +88,6 @@ class IC { ...@@ -88,11 +88,6 @@ class IC {
static void Clear(Isolate* isolate, Address address, static void Clear(Isolate* isolate, Address address,
ConstantPoolArray* constant_pool); ConstantPoolArray* constant_pool);
// Clear the vector-based inline cache to initial state.
template <class Nexus>
static void Clear(Isolate* isolate, Code::Kind kind, Code* host,
Nexus* nexus);
#ifdef DEBUG #ifdef DEBUG
bool IsLoadStub() const { bool IsLoadStub() const {
return target()->is_load_stub() || target()->is_keyed_load_stub(); return target()->is_load_stub() || target()->is_keyed_load_stub();
...@@ -157,15 +152,28 @@ class IC { ...@@ -157,15 +152,28 @@ class IC {
inline void set_target(Code* code); inline void set_target(Code* code);
bool is_target_set() { return target_set_; } bool is_target_set() { return target_set_; }
static bool ICUseVector(Code::Kind kind) {
return (FLAG_vector_ics &&
(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC)) ||
kind == Code::CALL_IC;
}
bool UseVector() const { bool UseVector() const {
bool use = (FLAG_vector_ics && bool use = ICUseVector(kind());
(kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC)) ||
kind() == Code::CALL_IC;
// If we are supposed to use the nexus, verify the nexus is non-null. // If we are supposed to use the nexus, verify the nexus is non-null.
DCHECK(!use || nexus_ != NULL); DCHECK(!use || nexus_ != NULL);
return use; return use;
} }
// Configure for most states.
void ConfigureVectorState(IC::State new_state);
// Configure the vector for MONOMORPHIC.
void ConfigureVectorState(Handle<Name> name, Handle<HeapType> type,
Handle<Code> handler);
// Configure the vector for POLYMORPHIC.
void ConfigureVectorState(Handle<Name> name, TypeHandleList* types,
CodeHandleList* handlers);
char TransitionMarkFromState(IC::State state); char TransitionMarkFromState(IC::State state);
void TraceIC(const char* type, Handle<Object> name); void TraceIC(const char* type, Handle<Object> name);
void TraceIC(const char* type, Handle<Object> name, State old_state, void TraceIC(const char* type, Handle<Object> name, State old_state,
...@@ -272,11 +280,15 @@ class IC { ...@@ -272,11 +280,15 @@ class IC {
void FindTargetMaps() { void FindTargetMaps() {
if (target_maps_set_) return; if (target_maps_set_) return;
target_maps_set_ = true; target_maps_set_ = true;
if (state_ == MONOMORPHIC) { if (UseVector()) {
Map* map = target_->FindFirstMap(); nexus()->ExtractMaps(&target_maps_);
if (map != NULL) target_maps_.Add(handle(map)); } else {
} else if (state_ != UNINITIALIZED && state_ != PREMONOMORPHIC) { if (state_ == MONOMORPHIC) {
target_->FindAllMaps(&target_maps_); Map* map = target_->FindFirstMap();
if (map != NULL) target_maps_.Add(handle(map));
} else if (state_ != UNINITIALIZED && state_ != PREMONOMORPHIC) {
target_->FindAllMaps(&target_maps_);
}
} }
} }
...@@ -364,7 +376,18 @@ class LoadIC : public IC { ...@@ -364,7 +376,18 @@ class LoadIC : public IC {
return LoadICState::GetContextualMode(extra_ic_state()); return LoadICState::GetContextualMode(extra_ic_state());
} }
explicit LoadIC(FrameDepth depth, Isolate* isolate) : IC(depth, isolate) { LoadIC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL)
: IC(depth, isolate, nexus) {
DCHECK(!FLAG_vector_ics || nexus != NULL);
DCHECK(IsLoadStub());
}
// TODO(mvstanton): The for_queries_only is because we have a case where we
// construct an IC only to gather the contextual mode, and we don't have
// vector/slot information. for_queries_only is a temporary hack to enable the
// strong DCHECK protection around vector/slot.
LoadIC(FrameDepth depth, Isolate* isolate, bool for_queries_only)
: IC(depth, isolate, NULL, for_queries_only) {
DCHECK(IsLoadStub()); DCHECK(IsLoadStub());
} }
...@@ -396,6 +419,8 @@ class LoadIC : public IC { ...@@ -396,6 +419,8 @@ class LoadIC : public IC {
MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object, MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
Handle<Name> name); Handle<Name> name);
static void Clear(Isolate* isolate, Code* host, LoadICNexus* nexus);
protected: protected:
inline void set_target(Code* code); inline void set_target(Code* code);
...@@ -434,8 +459,10 @@ class LoadIC : public IC { ...@@ -434,8 +459,10 @@ class LoadIC : public IC {
class KeyedLoadIC : public LoadIC { class KeyedLoadIC : public LoadIC {
public: public:
explicit KeyedLoadIC(FrameDepth depth, Isolate* isolate) KeyedLoadIC(FrameDepth depth, Isolate* isolate,
: LoadIC(depth, isolate) { KeyedLoadICNexus* nexus = NULL)
: LoadIC(depth, isolate, nexus) {
DCHECK(!FLAG_vector_ics || nexus != NULL);
DCHECK(target()->is_keyed_load_stub()); DCHECK(target()->is_keyed_load_stub());
} }
...@@ -463,6 +490,8 @@ class KeyedLoadIC : public LoadIC { ...@@ -463,6 +490,8 @@ class KeyedLoadIC : public LoadIC {
static Handle<Code> generic_stub(Isolate* isolate); static Handle<Code> generic_stub(Isolate* isolate);
static Handle<Code> pre_monomorphic_stub(Isolate* isolate); static Handle<Code> pre_monomorphic_stub(Isolate* isolate);
static void Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus);
protected: protected:
// receiver is HeapObject because it could be a String or a JSObject // receiver is HeapObject because it could be a String or a JSObject
Handle<Code> LoadElementStub(Handle<HeapObject> receiver); Handle<Code> LoadElementStub(Handle<HeapObject> receiver);
......
...@@ -762,11 +762,30 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) { ...@@ -762,11 +762,30 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
} }
// A register that isn't one of the parameters to the load ic. static void LoadIC_PushArgs(MacroAssembler* masm) {
static const Register LoadIC_TempRegister() { return rbx; } Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
if (FLAG_vector_ics) {
Register slot = VectorLoadICDescriptor::SlotRegister();
Register vector = VectorLoadICDescriptor::VectorRegister();
DCHECK(!rdi.is(receiver) && !rdi.is(name) && !rdi.is(slot) &&
!rdi.is(vector));
__ PopReturnAddressTo(rdi);
__ Push(receiver);
__ Push(name);
__ Push(slot);
__ Push(vector);
__ PushReturnAddressFrom(rdi);
} else {
DCHECK(!rbx.is(receiver) && !rbx.is(name));
static const Register KeyedLoadIC_TempRegister() { return rbx; } __ PopReturnAddressTo(rbx);
__ Push(receiver);
__ Push(name);
__ PushReturnAddressFrom(rbx);
}
}
void LoadIC::GenerateMiss(MacroAssembler* masm) { void LoadIC::GenerateMiss(MacroAssembler* masm) {
...@@ -775,25 +794,26 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) { ...@@ -775,25 +794,26 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
Counters* counters = masm->isolate()->counters(); Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->load_miss(), 1); __ IncrementCounter(counters->load_miss(), 1);
__ PopReturnAddressTo(LoadIC_TempRegister()); LoadIC_PushArgs(masm);
__ Push(LoadDescriptor::ReceiverRegister()); // receiver
__ Push(LoadDescriptor::NameRegister()); // name
__ PushReturnAddressFrom(LoadIC_TempRegister());
// Perform tail call to the entry. // Perform tail call to the entry.
ExternalReference ref = ExternalReference ref =
ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate()); ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1); int arg_count = FLAG_vector_ics ? 4 : 2;
__ TailCallExternalReference(ref, arg_count, 1);
} }
void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is on the stack. // The return address is on the stack.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(!rbx.is(receiver) && !rbx.is(name));
__ PopReturnAddressTo(LoadIC_TempRegister()); __ PopReturnAddressTo(rbx);
__ Push(LoadDescriptor::ReceiverRegister()); // receiver __ Push(receiver);
__ Push(LoadDescriptor::NameRegister()); // name __ Push(name);
__ PushReturnAddressFrom(LoadIC_TempRegister()); __ PushReturnAddressFrom(rbx);
// Perform tail call to the entry. // Perform tail call to the entry.
__ TailCallRuntime(Runtime::kGetProperty, 2, 1); __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
...@@ -805,25 +825,26 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { ...@@ -805,25 +825,26 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
Counters* counters = masm->isolate()->counters(); Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->keyed_load_miss(), 1); __ IncrementCounter(counters->keyed_load_miss(), 1);
__ PopReturnAddressTo(KeyedLoadIC_TempRegister()); LoadIC_PushArgs(masm);
__ Push(LoadDescriptor::ReceiverRegister()); // receiver
__ Push(LoadDescriptor::NameRegister()); // name
__ PushReturnAddressFrom(KeyedLoadIC_TempRegister());
// Perform tail call to the entry. // Perform tail call to the entry.
ExternalReference ref = ExternalReference ref =
ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate()); ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
__ TailCallExternalReference(ref, 2, 1); int arg_count = FLAG_vector_ics ? 4 : 2;
__ TailCallExternalReference(ref, arg_count, 1);
} }
void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
// The return address is on the stack. // The return address is on the stack.
Register receiver = LoadDescriptor::ReceiverRegister();
Register name = LoadDescriptor::NameRegister();
DCHECK(!rbx.is(receiver) && !rbx.is(name));
__ PopReturnAddressTo(KeyedLoadIC_TempRegister()); __ PopReturnAddressTo(rbx);
__ Push(LoadDescriptor::ReceiverRegister()); // receiver __ Push(receiver);
__ Push(LoadDescriptor::NameRegister()); // name __ Push(name);
__ PushReturnAddressFrom(KeyedLoadIC_TempRegister()); __ PushReturnAddressFrom(rbx);
// Perform tail call to the entry. // Perform tail call to the entry.
__ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
......
This diff is collapsed.
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef V8_TYPE_FEEDBACK_VECTOR_H_ #ifndef V8_TYPE_FEEDBACK_VECTOR_H_
#define V8_TYPE_FEEDBACK_VECTOR_H_ #define V8_TYPE_FEEDBACK_VECTOR_H_
#include <vector>
#include "src/checks.h" #include "src/checks.h"
#include "src/elements-kind.h" #include "src/elements-kind.h"
#include "src/heap/heap.h" #include "src/heap/heap.h"
...@@ -14,6 +16,40 @@ ...@@ -14,6 +16,40 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class FeedbackVectorSpec {
public:
FeedbackVectorSpec() : slots_(0), ic_slots_(0) {}
FeedbackVectorSpec(int slots, int ic_slots)
: slots_(slots), ic_slots_(ic_slots) {
if (FLAG_vector_ics) ic_slot_kinds_.resize(ic_slots);
}
int slots() const { return slots_; }
void increase_slots(int count) { slots_ += count; }
int ic_slots() const { return ic_slots_; }
void increase_ic_slots(int count) {
ic_slots_ += count;
if (FLAG_vector_ics) ic_slot_kinds_.resize(ic_slots_);
}
void SetKind(int ic_slot, Code::Kind kind) {
DCHECK(FLAG_vector_ics);
ic_slot_kinds_[ic_slot] = kind;
}
Code::Kind GetKind(int ic_slot) const {
DCHECK(FLAG_vector_ics);
return static_cast<Code::Kind>(ic_slot_kinds_.at(ic_slot));
}
private:
int slots_;
int ic_slots_;
std::vector<unsigned char> ic_slot_kinds_;
};
// The shape of the TypeFeedbackVector is an array with: // The shape of the TypeFeedbackVector is an array with:
// 0: first_ic_slot_index (== length() if no ic slots are present) // 0: first_ic_slot_index (== length() if no ic slots are present)
// 1: ics_with_types // 1: ics_with_types
...@@ -118,17 +154,11 @@ class TypeFeedbackVector : public FixedArray { ...@@ -118,17 +154,11 @@ class TypeFeedbackVector : public FixedArray {
set(GetIndex(slot), value, mode); set(GetIndex(slot), value, mode);
} }
// IC slots need metadata to recognize the type of IC. Set a Kind for every // IC slots need metadata to recognize the type of IC.
// slot. If GetKind() returns Code::NUMBER_OF_KINDS, then there is
// no kind associated with this slot. This may happen in the current design
// if a decision is made at compile time not to emit an IC that was planned
// for at parse time. This can be eliminated if we encode kind at parse
// time.
Code::Kind GetKind(FeedbackVectorICSlot slot) const; Code::Kind GetKind(FeedbackVectorICSlot slot) const;
void SetKind(FeedbackVectorICSlot slot, Code::Kind kind);
static Handle<TypeFeedbackVector> Allocate(Isolate* isolate, int slot_count, static Handle<TypeFeedbackVector> Allocate(Isolate* isolate,
int ic_slot_count); const FeedbackVectorSpec& spec);
static Handle<TypeFeedbackVector> Copy(Isolate* isolate, static Handle<TypeFeedbackVector> Copy(Isolate* isolate,
Handle<TypeFeedbackVector> vector); Handle<TypeFeedbackVector> vector);
...@@ -168,6 +198,8 @@ class TypeFeedbackVector : public FixedArray { ...@@ -168,6 +198,8 @@ class TypeFeedbackVector : public FixedArray {
static const int kVectorICKindBits = 2; static const int kVectorICKindBits = 2;
static VectorICKind FromCodeKind(Code::Kind kind); static VectorICKind FromCodeKind(Code::Kind kind);
static Code::Kind FromVectorICKind(VectorICKind kind); static Code::Kind FromVectorICKind(VectorICKind kind);
void SetKind(FeedbackVectorICSlot slot, Code::Kind kind);
typedef BitSetComputer<VectorICKind, kVectorICKindBits, kSmiValueSize, typedef BitSetComputer<VectorICKind, kVectorICKindBits, kSmiValueSize,
uint32_t> VectorICComputer; uint32_t> VectorICComputer;
...@@ -202,6 +234,9 @@ class FeedbackNexus { ...@@ -202,6 +234,9 @@ class FeedbackNexus {
return NULL; return NULL;
} }
// TODO(mvstanton): remove FindAllMaps, it didn't survive a code review.
void FindAllMaps(MapHandleList* maps) const { ExtractMaps(maps); }
virtual InlineCacheState StateFromFeedback() const = 0; virtual InlineCacheState StateFromFeedback() const = 0;
virtual int ExtractMaps(MapHandleList* maps) const = 0; virtual int ExtractMaps(MapHandleList* maps) const = 0;
virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const = 0; virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const = 0;
...@@ -250,6 +285,8 @@ class CallICNexus : public FeedbackNexus { ...@@ -250,6 +285,8 @@ class CallICNexus : public FeedbackNexus {
DCHECK(vector->GetKind(slot) == Code::CALL_IC); DCHECK(vector->GetKind(slot) == Code::CALL_IC);
} }
void Clear(Code* host);
void ConfigureUninitialized(); void ConfigureUninitialized();
void ConfigureGeneric(); void ConfigureGeneric();
void ConfigureMonomorphicArray(); void ConfigureMonomorphicArray();
...@@ -269,6 +306,65 @@ class CallICNexus : public FeedbackNexus { ...@@ -269,6 +306,65 @@ class CallICNexus : public FeedbackNexus {
return length == 0; return length == 0;
} }
}; };
class LoadICNexus : public FeedbackNexus {
public:
LoadICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
: FeedbackNexus(vector, slot) {
DCHECK(vector->GetKind(slot) == Code::LOAD_IC);
}
LoadICNexus(TypeFeedbackVector* vector, FeedbackVectorICSlot slot)
: FeedbackNexus(vector, slot) {
DCHECK(vector->GetKind(slot) == Code::LOAD_IC);
}
void Clear(Code* host);
void ConfigureMegamorphic();
void ConfigurePremonomorphic();
void ConfigureMonomorphic(Handle<HeapType> type, Handle<Code> handler);
void ConfigurePolymorphic(TypeHandleList* types, CodeHandleList* handlers);
virtual InlineCacheState StateFromFeedback() const OVERRIDE;
virtual int ExtractMaps(MapHandleList* maps) const OVERRIDE;
virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const OVERRIDE;
virtual bool FindHandlers(CodeHandleList* code_list,
int length = -1) const OVERRIDE;
};
class KeyedLoadICNexus : public FeedbackNexus {
public:
KeyedLoadICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot)
: FeedbackNexus(vector, slot) {
DCHECK(vector->GetKind(slot) == Code::KEYED_LOAD_IC);
}
KeyedLoadICNexus(TypeFeedbackVector* vector, FeedbackVectorICSlot slot)
: FeedbackNexus(vector, slot) {
DCHECK(vector->GetKind(slot) == Code::KEYED_LOAD_IC);
}
void Clear(Code* host);
void ConfigureMegamorphic();
void ConfigureGeneric();
void ConfigurePremonomorphic();
// name can be a null handle for element loads.
void ConfigureMonomorphic(Handle<Name> name, Handle<HeapType> type,
Handle<Code> handler);
// name can be null.
void ConfigurePolymorphic(Handle<Name> name, TypeHandleList* types,
CodeHandleList* handlers);
virtual InlineCacheState StateFromFeedback() const OVERRIDE;
virtual int ExtractMaps(MapHandleList* maps) const OVERRIDE;
virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const OVERRIDE;
virtual bool FindHandlers(CodeHandleList* code_list,
int length = -1) const OVERRIDE;
virtual Name* FindFirstName() const OVERRIDE;
};
} }
} // namespace v8::internal } // namespace v8::internal
......
...@@ -81,6 +81,24 @@ bool TypeFeedbackOracle::LoadIsUninitialized(TypeFeedbackId id) { ...@@ -81,6 +81,24 @@ bool TypeFeedbackOracle::LoadIsUninitialized(TypeFeedbackId id) {
} }
bool TypeFeedbackOracle::LoadIsUninitialized(FeedbackVectorICSlot slot) {
Code::Kind kind = feedback_vector_->GetKind(slot);
if (kind == Code::LOAD_IC) {
LoadICNexus nexus(feedback_vector_, slot);
return nexus.StateFromFeedback() == UNINITIALIZED;
} else if (kind == Code::KEYED_LOAD_IC) {
KeyedLoadICNexus nexus(feedback_vector_, slot);
return nexus.StateFromFeedback() == UNINITIALIZED;
} else if (kind == Code::NUMBER_OF_KINDS) {
// Code::NUMBER_OF_KINDS indicates a slot that was never even compiled
// in full code.
return true;
}
return false;
}
bool TypeFeedbackOracle::StoreIsUninitialized(TypeFeedbackId ast_id) { bool TypeFeedbackOracle::StoreIsUninitialized(TypeFeedbackId ast_id) {
Handle<Object> maybe_code = GetInfo(ast_id); Handle<Object> maybe_code = GetInfo(ast_id);
if (!maybe_code->IsCode()) return false; if (!maybe_code->IsCode()) return false;
...@@ -277,17 +295,39 @@ void TypeFeedbackOracle::PropertyReceiverTypes(TypeFeedbackId id, ...@@ -277,17 +295,39 @@ void TypeFeedbackOracle::PropertyReceiverTypes(TypeFeedbackId id,
} }
bool TypeFeedbackOracle::HasOnlyStringMaps(SmallMapList* receiver_types) {
bool all_strings = receiver_types->length() > 0;
for (int i = 0; i < receiver_types->length(); i++) {
all_strings &= receiver_types->at(i)->IsStringMap();
}
return all_strings;
}
void TypeFeedbackOracle::KeyedPropertyReceiverTypes( void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
TypeFeedbackId id, SmallMapList* receiver_types, bool* is_string) { TypeFeedbackId id, SmallMapList* receiver_types, bool* is_string) {
receiver_types->Clear(); receiver_types->Clear();
CollectReceiverTypes(id, receiver_types); CollectReceiverTypes(id, receiver_types);
*is_string = HasOnlyStringMaps(receiver_types);
}
// Are all the receiver maps string maps?
bool all_strings = receiver_types->length() > 0; void TypeFeedbackOracle::PropertyReceiverTypes(FeedbackVectorICSlot slot,
for (int i = 0; i < receiver_types->length(); i++) { Handle<String> name,
all_strings &= receiver_types->at(i)->IsStringMap(); SmallMapList* receiver_types) {
} receiver_types->Clear();
*is_string = all_strings; LoadICNexus nexus(feedback_vector_, slot);
Code::Flags flags = Code::ComputeHandlerFlags(Code::LOAD_IC);
CollectReceiverTypes(&nexus, name, flags, receiver_types);
}
void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
FeedbackVectorICSlot slot, SmallMapList* receiver_types, bool* is_string) {
receiver_types->Clear();
KeyedLoadICNexus nexus(feedback_vector_, slot);
CollectReceiverTypes<FeedbackNexus>(&nexus, receiver_types);
*is_string = HasOnlyStringMaps(receiver_types);
} }
...@@ -324,14 +364,21 @@ void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id, ...@@ -324,14 +364,21 @@ void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
DCHECK(object->IsCode()); DCHECK(object->IsCode());
Handle<Code> code(Handle<Code>::cast(object)); Handle<Code> code(Handle<Code>::cast(object));
CollectReceiverTypes<Code>(*code, name, flags, types);
}
template <class T>
void TypeFeedbackOracle::CollectReceiverTypes(T* obj, Handle<String> name,
Code::Flags flags,
SmallMapList* types) {
if (FLAG_collect_megamorphic_maps_from_stub_cache && if (FLAG_collect_megamorphic_maps_from_stub_cache &&
code->ic_state() == MEGAMORPHIC) { obj->ic_state() == MEGAMORPHIC) {
types->Reserve(4, zone()); types->Reserve(4, zone());
isolate()->stub_cache()->CollectMatchingMaps( isolate()->stub_cache()->CollectMatchingMaps(
types, name, flags, native_context_, zone()); types, name, flags, native_context_, zone());
} else { } else {
CollectReceiverTypes(ast_id, types); CollectReceiverTypes<T>(obj, types);
} }
} }
...@@ -375,12 +422,18 @@ void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id, ...@@ -375,12 +422,18 @@ void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
Handle<Object> object = GetInfo(ast_id); Handle<Object> object = GetInfo(ast_id);
if (!object->IsCode()) return; if (!object->IsCode()) return;
Handle<Code> code = Handle<Code>::cast(object); Handle<Code> code = Handle<Code>::cast(object);
CollectReceiverTypes<Code>(*code, types);
}
template <class T>
void TypeFeedbackOracle::CollectReceiverTypes(T* obj, SmallMapList* types) {
MapHandleList maps; MapHandleList maps;
if (code->ic_state() == MONOMORPHIC) { if (obj->ic_state() == MONOMORPHIC) {
Map* map = code->FindFirstMap(); Map* map = obj->FindFirstMap();
if (map != NULL) maps.Add(handle(map)); if (map != NULL) maps.Add(handle(map));
} else if (code->ic_state() == POLYMORPHIC) { } else if (obj->ic_state() == POLYMORPHIC) {
code->FindAllMaps(&maps); obj->FindAllMaps(&maps);
} else { } else {
return; return;
} }
......
...@@ -24,6 +24,7 @@ class TypeFeedbackOracle: public ZoneObject { ...@@ -24,6 +24,7 @@ class TypeFeedbackOracle: public ZoneObject {
Handle<Context> native_context, Zone* zone); Handle<Context> native_context, Zone* zone);
bool LoadIsUninitialized(TypeFeedbackId id); bool LoadIsUninitialized(TypeFeedbackId id);
bool LoadIsUninitialized(FeedbackVectorICSlot slot);
bool StoreIsUninitialized(TypeFeedbackId id); bool StoreIsUninitialized(TypeFeedbackId id);
bool CallIsUninitialized(FeedbackVectorICSlot slot); bool CallIsUninitialized(FeedbackVectorICSlot slot);
bool CallIsMonomorphic(FeedbackVectorICSlot slot); bool CallIsMonomorphic(FeedbackVectorICSlot slot);
...@@ -42,9 +43,14 @@ class TypeFeedbackOracle: public ZoneObject { ...@@ -42,9 +43,14 @@ class TypeFeedbackOracle: public ZoneObject {
void PropertyReceiverTypes(TypeFeedbackId id, Handle<String> name, void PropertyReceiverTypes(TypeFeedbackId id, Handle<String> name,
SmallMapList* receiver_types); SmallMapList* receiver_types);
void PropertyReceiverTypes(FeedbackVectorICSlot slot, Handle<String> name,
SmallMapList* receiver_types);
void KeyedPropertyReceiverTypes(TypeFeedbackId id, void KeyedPropertyReceiverTypes(TypeFeedbackId id,
SmallMapList* receiver_types, SmallMapList* receiver_types,
bool* is_string); bool* is_string);
void KeyedPropertyReceiverTypes(FeedbackVectorICSlot slot,
SmallMapList* receiver_types,
bool* is_string);
void AssignmentReceiverTypes(TypeFeedbackId id, void AssignmentReceiverTypes(TypeFeedbackId id,
Handle<String> name, Handle<String> name,
SmallMapList* receiver_types); SmallMapList* receiver_types);
...@@ -57,6 +63,8 @@ class TypeFeedbackOracle: public ZoneObject { ...@@ -57,6 +63,8 @@ class TypeFeedbackOracle: public ZoneObject {
void CollectReceiverTypes(TypeFeedbackId id, void CollectReceiverTypes(TypeFeedbackId id,
SmallMapList* types); SmallMapList* types);
template <class T>
void CollectReceiverTypes(T* obj, SmallMapList* types);
static bool CanRetainOtherContext(Map* map, Context* native_context); static bool CanRetainOtherContext(Map* map, Context* native_context);
static bool CanRetainOtherContext(JSFunction* function, static bool CanRetainOtherContext(JSFunction* function,
...@@ -98,6 +106,13 @@ class TypeFeedbackOracle: public ZoneObject { ...@@ -98,6 +106,13 @@ class TypeFeedbackOracle: public ZoneObject {
Handle<String> name, Handle<String> name,
Code::Flags flags, Code::Flags flags,
SmallMapList* types); SmallMapList* types);
template <class T>
void CollectReceiverTypes(T* obj, Handle<String> name, Code::Flags flags,
SmallMapList* types);
// Returns true if there is at least one string map and if
// all maps are string maps.
bool HasOnlyStringMaps(SmallMapList* receiver_types);
void SetInfo(TypeFeedbackId id, Object* target); void SetInfo(TypeFeedbackId id, Object* target);
......
...@@ -484,18 +484,35 @@ void AstTyper::VisitThrow(Throw* expr) { ...@@ -484,18 +484,35 @@ void AstTyper::VisitThrow(Throw* expr) {
void AstTyper::VisitProperty(Property* expr) { void AstTyper::VisitProperty(Property* expr) {
// Collect type feedback. // Collect type feedback.
TypeFeedbackId id = expr->PropertyFeedbackId(); FeedbackVectorICSlot slot(FeedbackVectorICSlot::Invalid());
expr->set_is_uninitialized(oracle()->LoadIsUninitialized(id)); TypeFeedbackId id(TypeFeedbackId::None());
if (FLAG_vector_ics) {
slot = expr->PropertyFeedbackSlot();
expr->set_is_uninitialized(oracle()->LoadIsUninitialized(slot));
} else {
id = expr->PropertyFeedbackId();
expr->set_is_uninitialized(oracle()->LoadIsUninitialized(id));
}
if (!expr->IsUninitialized()) { if (!expr->IsUninitialized()) {
if (expr->key()->IsPropertyName()) { if (expr->key()->IsPropertyName()) {
Literal* lit_key = expr->key()->AsLiteral(); Literal* lit_key = expr->key()->AsLiteral();
DCHECK(lit_key != NULL && lit_key->value()->IsString()); DCHECK(lit_key != NULL && lit_key->value()->IsString());
Handle<String> name = Handle<String>::cast(lit_key->value()); Handle<String> name = Handle<String>::cast(lit_key->value());
oracle()->PropertyReceiverTypes(id, name, expr->GetReceiverTypes()); if (FLAG_vector_ics) {
oracle()->PropertyReceiverTypes(slot, name, expr->GetReceiverTypes());
} else {
oracle()->PropertyReceiverTypes(id, name, expr->GetReceiverTypes());
}
} else { } else {
bool is_string; bool is_string;
oracle()->KeyedPropertyReceiverTypes( if (FLAG_vector_ics) {
id, expr->GetReceiverTypes(), &is_string); oracle()->KeyedPropertyReceiverTypes(slot, expr->GetReceiverTypes(),
&is_string);
} else {
oracle()->KeyedPropertyReceiverTypes(id, expr->GetReceiverTypes(),
&is_string);
}
expr->set_is_string_access(is_string); expr->set_is_string_access(is_string);
} }
} }
......
...@@ -310,10 +310,10 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) { ...@@ -310,10 +310,10 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) {
// Verify that we gathered feedback. // Verify that we gathered feedback.
int expected_slots = 0; int expected_slots = 0;
int expected_ic_slots = FLAG_vector_ics ? 2 : 1; int expected_ic_slots = 1;
CHECK_EQ(expected_slots, feedback_vector->Slots()); CHECK_EQ(expected_slots, feedback_vector->Slots());
CHECK_EQ(expected_ic_slots, feedback_vector->ICSlots()); CHECK_EQ(expected_ic_slots, feedback_vector->ICSlots());
FeedbackVectorICSlot slot_for_a(FLAG_vector_ics ? 1 : 0); FeedbackVectorICSlot slot_for_a(0);
CHECK(feedback_vector->Get(slot_for_a)->IsJSFunction()); CHECK(feedback_vector->Get(slot_for_a)->IsJSFunction());
CompileRun("%OptimizeFunctionOnNextCall(f); f(fun1);"); CompileRun("%OptimizeFunctionOnNextCall(f); f(fun1);");
......
...@@ -24,7 +24,8 @@ TEST(VectorStructure) { ...@@ -24,7 +24,8 @@ TEST(VectorStructure) {
Factory* factory = isolate->factory(); Factory* factory = isolate->factory();
// Empty vectors are the empty fixed array. // Empty vectors are the empty fixed array.
Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(0, 0); FeedbackVectorSpec empty;
Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(empty);
CHECK(Handle<FixedArray>::cast(vector) CHECK(Handle<FixedArray>::cast(vector)
.is_identical_to(factory->empty_fixed_array())); .is_identical_to(factory->empty_fixed_array()));
// Which can nonetheless be queried. // Which can nonetheless be queried.
...@@ -33,15 +34,18 @@ TEST(VectorStructure) { ...@@ -33,15 +34,18 @@ TEST(VectorStructure) {
CHECK_EQ(0, vector->Slots()); CHECK_EQ(0, vector->Slots());
CHECK_EQ(0, vector->ICSlots()); CHECK_EQ(0, vector->ICSlots());
vector = factory->NewTypeFeedbackVector(1, 0); FeedbackVectorSpec one_slot(1, 0);
vector = factory->NewTypeFeedbackVector(one_slot);
CHECK_EQ(1, vector->Slots()); CHECK_EQ(1, vector->Slots());
CHECK_EQ(0, vector->ICSlots()); CHECK_EQ(0, vector->ICSlots());
vector = factory->NewTypeFeedbackVector(0, 1); FeedbackVectorSpec one_icslot(0, 1);
vector = factory->NewTypeFeedbackVector(one_icslot);
CHECK_EQ(0, vector->Slots()); CHECK_EQ(0, vector->Slots());
CHECK_EQ(1, vector->ICSlots()); CHECK_EQ(1, vector->ICSlots());
vector = factory->NewTypeFeedbackVector(3, 5); FeedbackVectorSpec spec(3, 5);
vector = factory->NewTypeFeedbackVector(spec);
CHECK_EQ(3, vector->Slots()); CHECK_EQ(3, vector->Slots());
CHECK_EQ(5, vector->ICSlots()); CHECK_EQ(5, vector->ICSlots());
...@@ -53,6 +57,7 @@ TEST(VectorStructure) { ...@@ -53,6 +57,7 @@ TEST(VectorStructure) {
} }
int index = vector->GetIndex(FeedbackVectorSlot(0)); int index = vector->GetIndex(FeedbackVectorSlot(0));
CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index); CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index);
CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index)); CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index));
...@@ -78,11 +83,7 @@ TEST(VectorICMetadata) { ...@@ -78,11 +83,7 @@ TEST(VectorICMetadata) {
Isolate* isolate = CcTest::i_isolate(); Isolate* isolate = CcTest::i_isolate();
Factory* factory = isolate->factory(); Factory* factory = isolate->factory();
Handle<TypeFeedbackVector> vector = FeedbackVectorSpec spec(10, 3 * 10);
factory->NewTypeFeedbackVector(10, 3 * 10);
CHECK_EQ(10, vector->Slots());
CHECK_EQ(3 * 10, vector->ICSlots());
// Set metadata. // Set metadata.
for (int i = 0; i < 30; i++) { for (int i = 0; i < 30; i++) {
Code::Kind kind; Code::Kind kind;
...@@ -93,16 +94,20 @@ TEST(VectorICMetadata) { ...@@ -93,16 +94,20 @@ TEST(VectorICMetadata) {
} else { } else {
kind = Code::KEYED_LOAD_IC; kind = Code::KEYED_LOAD_IC;
} }
vector->SetKind(FeedbackVectorICSlot(i), kind); spec.SetKind(i, kind);
} }
Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec);
CHECK_EQ(10, vector->Slots());
CHECK_EQ(3 * 10, vector->ICSlots());
// Meanwhile set some feedback values and type feedback values to // Meanwhile set some feedback values and type feedback values to
// verify the data structure remains intact. // verify the data structure remains intact.
vector->change_ic_with_type_info_count(100); vector->change_ic_with_type_info_count(100);
vector->change_ic_generic_count(3333); vector->change_ic_generic_count(3333);
vector->Set(FeedbackVectorSlot(0), *vector); vector->Set(FeedbackVectorSlot(0), *vector);
// Verify the metadata remains the same. // Verify the metadata is correctly set up from the spec.
for (int i = 0; i < 30; i++) { for (int i = 0; i < 30; i++) {
Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i)); Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i));
if (i % 3 == 0) { if (i % 3 == 0) {
...@@ -125,7 +130,8 @@ TEST(VectorSlotClearing) { ...@@ -125,7 +130,8 @@ TEST(VectorSlotClearing) {
// We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots. // We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots.
// The reason is that FeedbackVectorICSlots need a full code environment // The reason is that FeedbackVectorICSlots need a full code environment
// to fully test (See VectorICProfilerStatistics test below). // to fully test (See VectorICProfilerStatistics test below).
Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(5, 0); FeedbackVectorSpec spec(5, 0);
Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec);
// Fill with information // Fill with information
vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1)); vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1));
...@@ -188,7 +194,7 @@ TEST(VectorICProfilerStatistics) { ...@@ -188,7 +194,7 @@ TEST(VectorICProfilerStatistics) {
CHECK_EQ(1, feedback_vector->ic_with_type_info_count()); CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
CHECK_EQ(0, feedback_vector->ic_generic_count()); CHECK_EQ(0, feedback_vector->ic_generic_count());
int ic_slot = FLAG_vector_ics ? 1 : 0; int ic_slot = 0;
CHECK( CHECK(
feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite()); feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
heap->CollectAllGarbage(i::Heap::kNoGCFlags); heap->CollectAllGarbage(i::Heap::kNoGCFlags);
...@@ -217,7 +223,7 @@ TEST(VectorCallICStates) { ...@@ -217,7 +223,7 @@ TEST(VectorCallICStates) {
// There should be one IC. // There should be one IC.
Handle<TypeFeedbackVector> feedback_vector = Handle<TypeFeedbackVector> feedback_vector =
Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate); Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
FeedbackVectorICSlot slot(FLAG_vector_ics ? 1 : 0); FeedbackVectorICSlot slot(0);
CallICNexus nexus(feedback_vector, slot); CallICNexus nexus(feedback_vector, slot);
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
// CallIC doesn't return map feedback. // CallIC doesn't return map feedback.
...@@ -239,4 +245,58 @@ TEST(VectorCallICStates) { ...@@ -239,4 +245,58 @@ TEST(VectorCallICStates) {
heap->CollectAllGarbage(i::Heap::kNoGCFlags); heap->CollectAllGarbage(i::Heap::kNoGCFlags);
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
} }
TEST(VectorLoadICStates) {
if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
CcTest::InitializeVM();
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
Isolate* isolate = CcTest::i_isolate();
Heap* heap = isolate->heap();
// Make sure function f has a call that uses a type feedback slot.
CompileRun(
"var o = { foo: 3 };"
"function f(a) { return a.foo; } f(o);");
Handle<JSFunction> f = v8::Utils::OpenHandle(
*v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
// There should be one IC.
Handle<TypeFeedbackVector> feedback_vector =
Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
FeedbackVectorICSlot slot(0);
LoadICNexus nexus(feedback_vector, slot);
CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
CompileRun("f(o)");
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
// Verify that the monomorphic map is the one we expect.
Handle<JSObject> o = v8::Utils::OpenHandle(
*v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str("o"))));
CHECK_EQ(o->map(), nexus.FindFirstMap());
// Now go polymorphic.
CompileRun("f({ blarg: 3, foo: 2 })");
CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
CompileRun(
"delete o.foo;"
"f(o)");
CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
MapHandleList maps;
nexus.FindAllMaps(&maps);
CHECK_EQ(4, maps.length());
// Finally driven megamorphic.
CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
CHECK_EQ(NULL, nexus.FindFirstMap());
// After a collection, state should be reset to PREMONOMORPHIC.
heap->CollectAllGarbage(i::Heap::kNoGCFlags);
CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
}
} }
...@@ -3295,18 +3295,18 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) { ...@@ -3295,18 +3295,18 @@ TEST(IncrementalMarkingClearsTypeFeedbackInfo) {
int expected_slots = 2; int expected_slots = 2;
CHECK_EQ(expected_slots, feedback_vector->ICSlots()); CHECK_EQ(expected_slots, feedback_vector->ICSlots());
for (int i = 0; i < expected_slots; i++) { int slot1 = 0;
CHECK(feedback_vector->Get(FeedbackVectorICSlot(i))->IsJSFunction()); int slot2 = 1;
} CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot1))->IsJSFunction());
CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot2))->IsJSFunction());
SimulateIncrementalMarking(CcTest::heap()); SimulateIncrementalMarking(CcTest::heap());
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
CHECK_EQ(expected_slots, feedback_vector->ICSlots()); CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot1)),
for (int i = 0; i < expected_slots; i++) { *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(i)), CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot2)),
*TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate())); *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
}
} }
...@@ -3325,6 +3325,25 @@ static Code* FindFirstIC(Code* code, Code::Kind kind) { ...@@ -3325,6 +3325,25 @@ static Code* FindFirstIC(Code* code, Code::Kind kind) {
} }
static void CheckVectorIC(Handle<JSFunction> f, int ic_slot_index,
InlineCacheState desired_state) {
Handle<TypeFeedbackVector> vector =
Handle<TypeFeedbackVector>(f->shared()->feedback_vector());
FeedbackVectorICSlot slot(ic_slot_index);
LoadICNexus nexus(vector, slot);
CHECK(nexus.StateFromFeedback() == desired_state);
}
static void CheckVectorICCleared(Handle<JSFunction> f, int ic_slot_index) {
Handle<TypeFeedbackVector> vector =
Handle<TypeFeedbackVector>(f->shared()->feedback_vector());
FeedbackVectorICSlot slot(ic_slot_index);
LoadICNexus nexus(vector, slot);
CHECK(IC::IsCleared(&nexus));
}
TEST(IncrementalMarkingPreservesMonomorphicIC) { TEST(IncrementalMarkingPreservesMonomorphicIC) {
if (i::FLAG_always_opt) return; if (i::FLAG_always_opt) return;
CcTest::InitializeVM(); CcTest::InitializeVM();
...@@ -3340,13 +3359,23 @@ TEST(IncrementalMarkingPreservesMonomorphicIC) { ...@@ -3340,13 +3359,23 @@ TEST(IncrementalMarkingPreservesMonomorphicIC) {
CcTest::global()->Get(v8_str("f")))); CcTest::global()->Get(v8_str("f"))));
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(ic_before->ic_state() == MONOMORPHIC); if (FLAG_vector_ics) {
CheckVectorIC(f, 0, MONOMORPHIC);
CHECK(ic_before->ic_state() == DEFAULT);
} else {
CHECK(ic_before->ic_state() == MONOMORPHIC);
}
SimulateIncrementalMarking(CcTest::heap()); SimulateIncrementalMarking(CcTest::heap());
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(ic_after->ic_state() == MONOMORPHIC); if (FLAG_vector_ics) {
CheckVectorIC(f, 0, MONOMORPHIC);
CHECK(ic_after->ic_state() == DEFAULT);
} else {
CHECK(ic_after->ic_state() == MONOMORPHIC);
}
} }
...@@ -3372,7 +3401,12 @@ TEST(IncrementalMarkingClearsMonomorphicIC) { ...@@ -3372,7 +3401,12 @@ TEST(IncrementalMarkingClearsMonomorphicIC) {
CcTest::global()->Get(v8_str("f")))); CcTest::global()->Get(v8_str("f"))));
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(ic_before->ic_state() == MONOMORPHIC); if (FLAG_vector_ics) {
CheckVectorIC(f, 0, MONOMORPHIC);
CHECK(ic_before->ic_state() == DEFAULT);
} else {
CHECK(ic_before->ic_state() == MONOMORPHIC);
}
// Fire context dispose notification. // Fire context dispose notification.
CcTest::isolate()->ContextDisposedNotification(); CcTest::isolate()->ContextDisposedNotification();
...@@ -3380,7 +3414,12 @@ TEST(IncrementalMarkingClearsMonomorphicIC) { ...@@ -3380,7 +3414,12 @@ TEST(IncrementalMarkingClearsMonomorphicIC) {
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(IC::IsCleared(ic_after)); if (FLAG_vector_ics) {
CheckVectorICCleared(f, 0);
CHECK(ic_after->ic_state() == DEFAULT);
} else {
CHECK(IC::IsCleared(ic_after));
}
} }
...@@ -3413,7 +3452,12 @@ TEST(IncrementalMarkingClearsPolymorphicIC) { ...@@ -3413,7 +3452,12 @@ TEST(IncrementalMarkingClearsPolymorphicIC) {
CcTest::global()->Get(v8_str("f")))); CcTest::global()->Get(v8_str("f"))));
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC); Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(ic_before->ic_state() == POLYMORPHIC); if (FLAG_vector_ics) {
CheckVectorIC(f, 0, POLYMORPHIC);
CHECK(ic_before->ic_state() == DEFAULT);
} else {
CHECK(ic_before->ic_state() == POLYMORPHIC);
}
// Fire context dispose notification. // Fire context dispose notification.
CcTest::isolate()->ContextDisposedNotification(); CcTest::isolate()->ContextDisposedNotification();
...@@ -3421,7 +3465,12 @@ TEST(IncrementalMarkingClearsPolymorphicIC) { ...@@ -3421,7 +3465,12 @@ TEST(IncrementalMarkingClearsPolymorphicIC) {
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags); CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC); Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
CHECK(IC::IsCleared(ic_after)); if (FLAG_vector_ics) {
CheckVectorICCleared(f, 0);
CHECK(ic_before->ic_state() == DEFAULT);
} else {
CHECK(IC::IsCleared(ic_after));
}
} }
...@@ -4047,6 +4096,10 @@ TEST(EnsureAllocationSiteDependentCodesProcessed) { ...@@ -4047,6 +4096,10 @@ TEST(EnsureAllocationSiteDependentCodesProcessed) {
heap->CollectAllGarbage(Heap::kNoGCFlags); heap->CollectAllGarbage(Heap::kNoGCFlags);
} }
// TODO(mvstanton): this test fails when FLAG_vector_ics is true because
// monomorphic load ics are preserved, but also strongly walked. They
// end up keeping function bar alive.
// The site still exists because of our global handle, but the code is no // The site still exists because of our global handle, but the code is no
// longer referred to by dependent_code(). // longer referred to by dependent_code().
DependentCode::GroupStartIndexes starts(site->dependent_code()); DependentCode::GroupStartIndexes starts(site->dependent_code());
...@@ -4311,6 +4364,8 @@ void CheckWeakness(const char* source) { ...@@ -4311,6 +4364,8 @@ void CheckWeakness(const char* source) {
// Each of the following "weak IC" tests creates an IC that embeds a map with // Each of the following "weak IC" tests creates an IC that embeds a map with
// the prototype pointing to _proto_ and checks that the _proto_ dies on GC. // the prototype pointing to _proto_ and checks that the _proto_ dies on GC.
TEST(WeakMapInMonomorphicLoadIC) { TEST(WeakMapInMonomorphicLoadIC) {
// TODO(mvstanton): vector ics need weak support!
if (FLAG_vector_ics) return;
CheckWeakness("function loadIC(obj) {" CheckWeakness("function loadIC(obj) {"
" return obj.name;" " return obj.name;"
"}" "}"
...@@ -4326,6 +4381,8 @@ TEST(WeakMapInMonomorphicLoadIC) { ...@@ -4326,6 +4381,8 @@ TEST(WeakMapInMonomorphicLoadIC) {
TEST(WeakMapInMonomorphicKeyedLoadIC) { TEST(WeakMapInMonomorphicKeyedLoadIC) {
// TODO(mvstanton): vector ics need weak support!
if (FLAG_vector_ics) return;
CheckWeakness("function keyedLoadIC(obj, field) {" CheckWeakness("function keyedLoadIC(obj, field) {"
" return obj[field];" " return obj[field];"
"}" "}"
......
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