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 {
FeedbackVectorRequirements reqs =
node->ComputeFeedbackRequirements(isolate());
if (reqs.slots() > 0) {
node->SetFirstFeedbackSlot(
FeedbackVectorSlot(properties_.feedback_slots()));
properties_.increase_feedback_slots(reqs.slots());
node->SetFirstFeedbackSlot(FeedbackVectorSlot(properties_.slots()));
properties_.increase_slots(reqs.slots());
}
if (reqs.ic_slots() > 0) {
node->SetFirstFeedbackICSlot(
FeedbackVectorICSlot(properties_.ic_feedback_slots()));
properties_.increase_ic_feedback_slots(reqs.ic_slots());
int ic_slots = properties_.ic_slots();
node->SetFirstFeedbackICSlot(FeedbackVectorICSlot(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) {
void AstNumberingVisitor::VisitCallRuntime(CallRuntime* node) {
IncrementNodeCount();
ReserveFeedbackSlots(node);
if (node->is_jsruntime()) {
// Don't try to optimize JS runtime calls because we bailout on them.
DisableCrankshaft(kCallToAJavaScriptRuntimeFunction);
......@@ -535,6 +540,7 @@ void AstNumberingVisitor::VisitFunctionLiteral(FunctionLiteral* node) {
void AstNumberingVisitor::Renumber(FunctionLiteral* node) {
if (node->scope()->HasIllegalRedeclaration()) {
node->scope()->VisitIllegalRedeclaration(this);
node->set_ast_properties(&properties_);
return;
}
......
......@@ -174,25 +174,24 @@ class AstProperties FINAL BASE_EMBEDDED {
public:
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_; }
int node_count() { return node_count_; }
void add_node_count(int count) { node_count_ += count; }
int feedback_slots() const { return feedback_slots_; }
void increase_feedback_slots(int count) {
feedback_slots_ += count;
}
int slots() const { return spec_.slots(); }
void increase_slots(int count) { spec_.increase_slots(count); }
int ic_feedback_slots() const { return ic_feedback_slots_; }
void increase_ic_feedback_slots(int count) { ic_feedback_slots_ += count; }
int ic_slots() const { return spec_.ic_slots(); }
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:
Flags flags_;
int node_count_;
int feedback_slots_;
int ic_feedback_slots_;
FeedbackVectorSpec spec_;
};
......@@ -245,6 +244,11 @@ class AstNode: public ZoneObject {
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) {
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:
// Hidden to prevent accidental usage. It would have to load the
......@@ -1698,16 +1702,23 @@ class VariableProxy FINAL : public Expression {
// Bind this proxy to the variable var. Interfaces must match.
void BindTo(Variable* var);
bool UsesVariableFeedbackSlot() const {
return FLAG_vector_ics && (var()->IsUnallocated() || var()->IsLookupSlot());
}
virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
Isolate* isolate) OVERRIDE {
return FeedbackVectorRequirements(0, FLAG_vector_ics ? 1 : 0);
return FeedbackVectorRequirements(0, UsesVariableFeedbackSlot() ? 1 : 0);
}
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
variable_feedback_slot_ = slot;
}
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return Code::LOAD_IC;
}
FeedbackVectorICSlot VariableFeedbackSlot() {
DCHECK(!FLAG_vector_ics || !variable_feedback_slot_.IsInvalid());
DCHECK(!UsesVariableFeedbackSlot() || !variable_feedback_slot_.IsInvalid());
return variable_feedback_slot_;
}
......@@ -1792,6 +1803,9 @@ class Property FINAL : public Expression {
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
property_feedback_slot_ = slot;
}
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return key()->IsPropertyName() ? Code::LOAD_IC : Code::KEYED_LOAD_IC;
}
FeedbackVectorICSlot PropertyFeedbackSlot() const {
DCHECK(!FLAG_vector_ics || !property_feedback_slot_.IsInvalid());
......@@ -1836,6 +1850,9 @@ class Call FINAL : public Expression {
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
call_feedback_slot_ = slot;
}
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return Code::CALL_IC;
}
bool HasCallFeedbackSlot() const { return !call_feedback_slot_.IsInvalid(); }
FeedbackVectorICSlot CallFeedbackSlot() const {
......@@ -2009,17 +2026,22 @@ class CallRuntime FINAL : public Expression {
bool is_jsruntime() const { return function_ == NULL; }
// Type feedback information.
bool HasCallRuntimeFeedbackSlot() const {
return FLAG_vector_ics && is_jsruntime();
}
virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
Isolate* isolate) OVERRIDE {
return FeedbackVectorRequirements(
0, (FLAG_vector_ics && is_jsruntime()) ? 1 : 0);
return FeedbackVectorRequirements(0, HasCallRuntimeFeedbackSlot() ? 1 : 0);
}
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
callruntime_feedback_slot_ = slot;
}
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return Code::LOAD_IC;
}
FeedbackVectorICSlot CallRuntimeFeedbackSlot() {
DCHECK(!(FLAG_vector_ics && is_jsruntime()) ||
DCHECK(!HasCallRuntimeFeedbackSlot() ||
!callruntime_feedback_slot_.IsInvalid());
return callruntime_feedback_slot_;
}
......@@ -2389,17 +2411,22 @@ class Yield FINAL : public Expression {
}
// Type feedback information.
bool HasFeedbackSlots() const {
return FLAG_vector_ics && (yield_kind() == kDelegating);
}
virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
Isolate* isolate) OVERRIDE {
return FeedbackVectorRequirements(
0, (FLAG_vector_ics && yield_kind() == kDelegating) ? 3 : 0);
return FeedbackVectorRequirements(0, HasFeedbackSlots() ? 3 : 0);
}
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
yield_first_feedback_slot_ = slot;
}
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return index == 0 ? Code::KEYED_LOAD_IC : Code::LOAD_IC;
}
FeedbackVectorICSlot KeyedLoadFeedbackSlot() {
DCHECK(!FLAG_vector_ics || !yield_first_feedback_slot_.IsInvalid());
DCHECK(!HasFeedbackSlots() || !yield_first_feedback_slot_.IsInvalid());
return yield_first_feedback_slot_;
}
......@@ -2580,10 +2607,9 @@ class FunctionLiteral FINAL : public Expression {
void set_ast_properties(AstProperties* ast_properties) {
ast_properties_ = *ast_properties;
}
int slot_count() {
return ast_properties_.feedback_slots();
const FeedbackVectorSpec& feedback_vector_spec() const {
return ast_properties_.get_spec();
}
int ic_slot_count() { return ast_properties_.ic_feedback_slots(); }
bool dont_optimize() { return dont_optimize_reason_ != kNoReason; }
BailoutReason dont_optimize_reason() { return dont_optimize_reason_; }
void set_dont_optimize_reason(BailoutReason reason) {
......@@ -2734,6 +2760,9 @@ class SuperReference FINAL : public Expression {
virtual void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot) OVERRIDE {
homeobject_feedback_slot_ = slot;
}
virtual Code::Kind FeedbackICSlotKind(int index) OVERRIDE {
return Code::LOAD_IC;
}
FeedbackVectorICSlot HomeObjectFeedbackSlot() {
DCHECK(!FLAG_vector_ics || !homeobject_feedback_slot_.IsInvalid());
......
......@@ -2038,8 +2038,10 @@ bool Genesis::InstallNatives() {
if (FLAG_vector_ics) {
// Apply embeds an IC, so we need a type vector of size 1 in the shared
// function info.
FeedbackVectorSpec spec(0, 1);
spec.SetKind(0, Code::CALL_IC);
Handle<TypeFeedbackVector> feedback_vector =
factory()->NewTypeFeedbackVector(0, 1);
factory()->NewTypeFeedbackVector(spec);
apply->shared()->set_feedback_vector(*feedback_vector);
}
......
......@@ -297,10 +297,8 @@ void CompilationInfo::PrepareForCompilation(Scope* scope) {
void CompilationInfo::EnsureFeedbackVector() {
if (feedback_vector_.is_null()) {
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) {
}
Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(int slot_count,
int ic_slot_count) {
return TypeFeedbackVector::Allocate(isolate(), slot_count, ic_slot_count);
Handle<TypeFeedbackVector> Factory::NewTypeFeedbackVector(
const FeedbackVectorSpec& spec) {
return TypeFeedbackVector::Allocate(isolate(), spec);
}
......@@ -2091,7 +2091,9 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
share->set_script(*undefined_value(), SKIP_WRITE_BARRIER);
share->set_debug_info(*undefined_value(), 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);
#if TRACE_MAPS
share->set_unique_id(isolate()->GetNextUniqueSharedFunctionInfoId());
......
......@@ -10,8 +10,9 @@
namespace v8 {
namespace internal {
// Interface for handle based allocation.
class FeedbackVectorSpec;
// Interface for handle based allocation.
class Factory FINAL {
public:
Handle<Oddball> NewOddball(Handle<Map> map,
......@@ -636,8 +637,8 @@ class Factory FINAL {
MaybeHandle<Code> code);
// Allocate a new type feedback vector
Handle<TypeFeedbackVector> NewTypeFeedbackVector(int slot_count,
int ic_slot_count);
Handle<TypeFeedbackVector> NewTypeFeedbackVector(
const FeedbackVectorSpec& spec);
// Allocates a new JSMessageObject object.
Handle<JSMessageObject> NewJSMessageObject(
......
......@@ -265,18 +265,32 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
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) {
// The return address is in lr.
Isolate* isolate = masm->isolate();
__ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4);
__ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
__ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
LoadIC_PushArgs(masm);
// Perform tail call to the entry.
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) {
__ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4);
__ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
LoadIC_PushArgs(masm);
// Perform tail call to the entry.
ExternalReference ref =
ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
__ TailCallExternalReference(ref, 2, 1);
int arg_count = FLAG_vector_ics ? 4 : 2;
__ TailCallExternalReference(ref, arg_count, 1);
}
......
......@@ -357,9 +357,17 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
__ IncrementCounter(isolate->counters()->load_miss(), 1, x3, x4);
// Perform tail call to the entry.
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);
__ 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) {
__ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, x10, x11);
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.
ExternalReference ref =
ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
__ TailCallExternalReference(ref, 2, 1);
int arg_count = FLAG_vector_ics ? 4 : 2;
__ TailCallExternalReference(ref, arg_count, 1);
}
......
......@@ -767,31 +767,52 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
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();
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);
__ push(receiver);
__ push(name);
__ push(ebx);
}
}
void LoadIC::GenerateMiss(MacroAssembler* masm) {
// Return address is on the stack.
__ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
LoadIC_PushArgs(masm);
// Perform tail call to the entry.
ExternalReference ref =
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) {
// 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.
__ TailCallRuntime(Runtime::kGetProperty, 2, 1);
......@@ -807,13 +828,21 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
// Perform tail call to the entry.
ExternalReference ref =
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) {
// 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.
__ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
......
......@@ -96,6 +96,12 @@ Code* IC::GetTargetAtAddress(Address address,
void IC::SetTargetAtAddress(Address address, Code* target,
ConstantPoolArray* constant_pool) {
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();
Code* old_target = GetTargetAtAddress(address, constant_pool);
#ifdef DEBUG
......
......@@ -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)
: argc_(ArgcBits::decode(extra_ic_state)),
call_type_(CallTypeBits::decode(extra_ic_state)) {}
......
......@@ -19,10 +19,6 @@ class ICUtility : public AllStatic {
// Clear the inline cache to initial state.
static void Clear(Isolate* isolate, Address address,
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 {
static void Clear(Isolate* isolate, Address address,
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
bool IsLoadStub() const {
return target()->is_load_stub() || target()->is_keyed_load_stub();
......@@ -157,15 +152,28 @@ class IC {
inline void set_target(Code* code);
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 use = (FLAG_vector_ics &&
(kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC)) ||
kind() == Code::CALL_IC;
bool use = ICUseVector(kind());
// If we are supposed to use the nexus, verify the nexus is non-null.
DCHECK(!use || nexus_ != NULL);
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);
void TraceIC(const char* type, Handle<Object> name);
void TraceIC(const char* type, Handle<Object> name, State old_state,
......@@ -272,6 +280,9 @@ class IC {
void FindTargetMaps() {
if (target_maps_set_) return;
target_maps_set_ = true;
if (UseVector()) {
nexus()->ExtractMaps(&target_maps_);
} else {
if (state_ == MONOMORPHIC) {
Map* map = target_->FindFirstMap();
if (map != NULL) target_maps_.Add(handle(map));
......@@ -279,6 +290,7 @@ class IC {
target_->FindAllMaps(&target_maps_);
}
}
}
// Frame pointer for the frame that uses (calls) the IC.
Address fp_;
......@@ -364,7 +376,18 @@ class LoadIC : public IC {
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());
}
......@@ -396,6 +419,8 @@ class LoadIC : public IC {
MUST_USE_RESULT MaybeHandle<Object> Load(Handle<Object> object,
Handle<Name> name);
static void Clear(Isolate* isolate, Code* host, LoadICNexus* nexus);
protected:
inline void set_target(Code* code);
......@@ -434,8 +459,10 @@ class LoadIC : public IC {
class KeyedLoadIC : public LoadIC {
public:
explicit KeyedLoadIC(FrameDepth depth, Isolate* isolate)
: LoadIC(depth, isolate) {
KeyedLoadIC(FrameDepth depth, Isolate* isolate,
KeyedLoadICNexus* nexus = NULL)
: LoadIC(depth, isolate, nexus) {
DCHECK(!FLAG_vector_ics || nexus != NULL);
DCHECK(target()->is_keyed_load_stub());
}
......@@ -463,6 +490,8 @@ class KeyedLoadIC : public LoadIC {
static Handle<Code> generic_stub(Isolate* isolate);
static Handle<Code> pre_monomorphic_stub(Isolate* isolate);
static void Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus);
protected:
// receiver is HeapObject because it could be a String or a JSObject
Handle<Code> LoadElementStub(Handle<HeapObject> receiver);
......
......@@ -762,11 +762,30 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
}
// A register that isn't one of the parameters to the load ic.
static const Register LoadIC_TempRegister() { return rbx; }
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();
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) {
......@@ -775,25 +794,26 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->load_miss(), 1);
__ PopReturnAddressTo(LoadIC_TempRegister());
__ Push(LoadDescriptor::ReceiverRegister()); // receiver
__ Push(LoadDescriptor::NameRegister()); // name
__ PushReturnAddressFrom(LoadIC_TempRegister());
LoadIC_PushArgs(masm);
// Perform tail call to the entry.
ExternalReference ref =
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) {
// 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());
__ Push(LoadDescriptor::ReceiverRegister()); // receiver
__ Push(LoadDescriptor::NameRegister()); // name
__ PushReturnAddressFrom(LoadIC_TempRegister());
__ PopReturnAddressTo(rbx);
__ Push(receiver);
__ Push(name);
__ PushReturnAddressFrom(rbx);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kGetProperty, 2, 1);
......@@ -805,25 +825,26 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->keyed_load_miss(), 1);
__ PopReturnAddressTo(KeyedLoadIC_TempRegister());
__ Push(LoadDescriptor::ReceiverRegister()); // receiver
__ Push(LoadDescriptor::NameRegister()); // name
__ PushReturnAddressFrom(KeyedLoadIC_TempRegister());
LoadIC_PushArgs(masm);
// Perform tail call to the entry.
ExternalReference ref =
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) {
// 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());
__ Push(LoadDescriptor::ReceiverRegister()); // receiver
__ Push(LoadDescriptor::NameRegister()); // name
__ PushReturnAddressFrom(KeyedLoadIC_TempRegister());
__ PopReturnAddressTo(rbx);
__ Push(receiver);
__ Push(name);
__ PushReturnAddressFrom(rbx);
// Perform tail call to the entry.
__ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
......
This diff is collapsed.
......@@ -5,6 +5,8 @@
#ifndef V8_TYPE_FEEDBACK_VECTOR_H_
#define V8_TYPE_FEEDBACK_VECTOR_H_
#include <vector>
#include "src/checks.h"
#include "src/elements-kind.h"
#include "src/heap/heap.h"
......@@ -14,6 +16,40 @@
namespace v8 {
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:
// 0: first_ic_slot_index (== length() if no ic slots are present)
// 1: ics_with_types
......@@ -118,17 +154,11 @@ class TypeFeedbackVector : public FixedArray {
set(GetIndex(slot), value, mode);
}
// IC slots need metadata to recognize the type of IC. Set a Kind for every
// 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.
// IC slots need metadata to recognize the type of IC.
Code::Kind GetKind(FeedbackVectorICSlot slot) const;
void SetKind(FeedbackVectorICSlot slot, Code::Kind kind);
static Handle<TypeFeedbackVector> Allocate(Isolate* isolate, int slot_count,
int ic_slot_count);
static Handle<TypeFeedbackVector> Allocate(Isolate* isolate,
const FeedbackVectorSpec& spec);
static Handle<TypeFeedbackVector> Copy(Isolate* isolate,
Handle<TypeFeedbackVector> vector);
......@@ -168,6 +198,8 @@ class TypeFeedbackVector : public FixedArray {
static const int kVectorICKindBits = 2;
static VectorICKind FromCodeKind(Code::Kind kind);
static Code::Kind FromVectorICKind(VectorICKind kind);
void SetKind(FeedbackVectorICSlot slot, Code::Kind kind);
typedef BitSetComputer<VectorICKind, kVectorICKindBits, kSmiValueSize,
uint32_t> VectorICComputer;
......@@ -202,6 +234,9 @@ class FeedbackNexus {
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 int ExtractMaps(MapHandleList* maps) const = 0;
virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const = 0;
......@@ -250,6 +285,8 @@ class CallICNexus : public FeedbackNexus {
DCHECK(vector->GetKind(slot) == Code::CALL_IC);
}
void Clear(Code* host);
void ConfigureUninitialized();
void ConfigureGeneric();
void ConfigureMonomorphicArray();
......@@ -269,6 +306,65 @@ class CallICNexus : public FeedbackNexus {
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
......
......@@ -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) {
Handle<Object> maybe_code = GetInfo(ast_id);
if (!maybe_code->IsCode()) return false;
......@@ -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(
TypeFeedbackId id, SmallMapList* receiver_types, bool* is_string) {
receiver_types->Clear();
CollectReceiverTypes(id, receiver_types);
*is_string = HasOnlyStringMaps(receiver_types);
}
// Are all the receiver maps string maps?
bool all_strings = receiver_types->length() > 0;
for (int i = 0; i < receiver_types->length(); i++) {
all_strings &= receiver_types->at(i)->IsStringMap();
}
*is_string = all_strings;
void TypeFeedbackOracle::PropertyReceiverTypes(FeedbackVectorICSlot slot,
Handle<String> 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);
}
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,
DCHECK(object->IsCode());
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 &&
code->ic_state() == MEGAMORPHIC) {
obj->ic_state() == MEGAMORPHIC) {
types->Reserve(4, zone());
isolate()->stub_cache()->CollectMatchingMaps(
types, name, flags, native_context_, zone());
} else {
CollectReceiverTypes(ast_id, types);
CollectReceiverTypes<T>(obj, types);
}
}
......@@ -375,12 +422,18 @@ void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
Handle<Object> object = GetInfo(ast_id);
if (!object->IsCode()) return;
Handle<Code> code = Handle<Code>::cast(object);
CollectReceiverTypes<Code>(*code, types);
}
template <class T>
void TypeFeedbackOracle::CollectReceiverTypes(T* obj, SmallMapList* types) {
MapHandleList maps;
if (code->ic_state() == MONOMORPHIC) {
Map* map = code->FindFirstMap();
if (obj->ic_state() == MONOMORPHIC) {
Map* map = obj->FindFirstMap();
if (map != NULL) maps.Add(handle(map));
} else if (code->ic_state() == POLYMORPHIC) {
code->FindAllMaps(&maps);
} else if (obj->ic_state() == POLYMORPHIC) {
obj->FindAllMaps(&maps);
} else {
return;
}
......
......@@ -24,6 +24,7 @@ class TypeFeedbackOracle: public ZoneObject {
Handle<Context> native_context, Zone* zone);
bool LoadIsUninitialized(TypeFeedbackId id);
bool LoadIsUninitialized(FeedbackVectorICSlot slot);
bool StoreIsUninitialized(TypeFeedbackId id);
bool CallIsUninitialized(FeedbackVectorICSlot slot);
bool CallIsMonomorphic(FeedbackVectorICSlot slot);
......@@ -42,9 +43,14 @@ class TypeFeedbackOracle: public ZoneObject {
void PropertyReceiverTypes(TypeFeedbackId id, Handle<String> name,
SmallMapList* receiver_types);
void PropertyReceiverTypes(FeedbackVectorICSlot slot, Handle<String> name,
SmallMapList* receiver_types);
void KeyedPropertyReceiverTypes(TypeFeedbackId id,
SmallMapList* receiver_types,
bool* is_string);
void KeyedPropertyReceiverTypes(FeedbackVectorICSlot slot,
SmallMapList* receiver_types,
bool* is_string);
void AssignmentReceiverTypes(TypeFeedbackId id,
Handle<String> name,
SmallMapList* receiver_types);
......@@ -57,6 +63,8 @@ class TypeFeedbackOracle: public ZoneObject {
void CollectReceiverTypes(TypeFeedbackId id,
SmallMapList* types);
template <class T>
void CollectReceiverTypes(T* obj, SmallMapList* types);
static bool CanRetainOtherContext(Map* map, Context* native_context);
static bool CanRetainOtherContext(JSFunction* function,
......@@ -98,6 +106,13 @@ class TypeFeedbackOracle: public ZoneObject {
Handle<String> name,
Code::Flags flags,
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);
......
......@@ -484,18 +484,35 @@ void AstTyper::VisitThrow(Throw* expr) {
void AstTyper::VisitProperty(Property* expr) {
// Collect type feedback.
TypeFeedbackId id = expr->PropertyFeedbackId();
FeedbackVectorICSlot slot(FeedbackVectorICSlot::Invalid());
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->key()->IsPropertyName()) {
Literal* lit_key = expr->key()->AsLiteral();
DCHECK(lit_key != NULL && lit_key->value()->IsString());
Handle<String> name = Handle<String>::cast(lit_key->value());
if (FLAG_vector_ics) {
oracle()->PropertyReceiverTypes(slot, name, expr->GetReceiverTypes());
} else {
oracle()->PropertyReceiverTypes(id, name, expr->GetReceiverTypes());
}
} else {
bool is_string;
oracle()->KeyedPropertyReceiverTypes(
id, expr->GetReceiverTypes(), &is_string);
if (FLAG_vector_ics) {
oracle()->KeyedPropertyReceiverTypes(slot, expr->GetReceiverTypes(),
&is_string);
} else {
oracle()->KeyedPropertyReceiverTypes(id, expr->GetReceiverTypes(),
&is_string);
}
expr->set_is_string_access(is_string);
}
}
......
......@@ -310,10 +310,10 @@ TEST(FeedbackVectorPreservedAcrossRecompiles) {
// Verify that we gathered feedback.
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_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());
CompileRun("%OptimizeFunctionOnNextCall(f); f(fun1);");
......
......@@ -24,7 +24,8 @@ TEST(VectorStructure) {
Factory* factory = isolate->factory();
// 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)
.is_identical_to(factory->empty_fixed_array()));
// Which can nonetheless be queried.
......@@ -33,15 +34,18 @@ TEST(VectorStructure) {
CHECK_EQ(0, vector->Slots());
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(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(1, vector->ICSlots());
vector = factory->NewTypeFeedbackVector(3, 5);
FeedbackVectorSpec spec(3, 5);
vector = factory->NewTypeFeedbackVector(spec);
CHECK_EQ(3, vector->Slots());
CHECK_EQ(5, vector->ICSlots());
......@@ -53,6 +57,7 @@ TEST(VectorStructure) {
}
int index = vector->GetIndex(FeedbackVectorSlot(0));
CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index);
CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index));
......@@ -78,11 +83,7 @@ TEST(VectorICMetadata) {
Isolate* isolate = CcTest::i_isolate();
Factory* factory = isolate->factory();
Handle<TypeFeedbackVector> vector =
factory->NewTypeFeedbackVector(10, 3 * 10);
CHECK_EQ(10, vector->Slots());
CHECK_EQ(3 * 10, vector->ICSlots());
FeedbackVectorSpec spec(10, 3 * 10);
// Set metadata.
for (int i = 0; i < 30; i++) {
Code::Kind kind;
......@@ -93,16 +94,20 @@ TEST(VectorICMetadata) {
} else {
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
// verify the data structure remains intact.
vector->change_ic_with_type_info_count(100);
vector->change_ic_generic_count(3333);
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++) {
Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i));
if (i % 3 == 0) {
......@@ -125,7 +130,8 @@ TEST(VectorSlotClearing) {
// We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots.
// The reason is that FeedbackVectorICSlots need a full code environment
// 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
vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1));
......@@ -188,7 +194,7 @@ TEST(VectorICProfilerStatistics) {
CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
CHECK_EQ(0, feedback_vector->ic_generic_count());
int ic_slot = FLAG_vector_ics ? 1 : 0;
int ic_slot = 0;
CHECK(
feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
heap->CollectAllGarbage(i::Heap::kNoGCFlags);
......@@ -217,7 +223,7 @@ TEST(VectorCallICStates) {
// There should be one IC.
Handle<TypeFeedbackVector> feedback_vector =
Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
FeedbackVectorICSlot slot(FLAG_vector_ics ? 1 : 0);
FeedbackVectorICSlot slot(0);
CallICNexus nexus(feedback_vector, slot);
CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
// CallIC doesn't return map feedback.
......@@ -239,4 +245,58 @@ TEST(VectorCallICStates) {
heap->CollectAllGarbage(i::Heap::kNoGCFlags);
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) {
int expected_slots = 2;
CHECK_EQ(expected_slots, feedback_vector->ICSlots());
for (int i = 0; i < expected_slots; i++) {
CHECK(feedback_vector->Get(FeedbackVectorICSlot(i))->IsJSFunction());
}
int slot1 = 0;
int slot2 = 1;
CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot1))->IsJSFunction());
CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot2))->IsJSFunction());
SimulateIncrementalMarking(CcTest::heap());
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
CHECK_EQ(expected_slots, feedback_vector->ICSlots());
for (int i = 0; i < expected_slots; i++) {
CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(i)),
CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot1)),
*TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot2)),
*TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
}
}
......@@ -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) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();
......@@ -3340,13 +3359,23 @@ TEST(IncrementalMarkingPreservesMonomorphicIC) {
CcTest::global()->Get(v8_str("f"))));
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
if (FLAG_vector_ics) {
CheckVectorIC(f, 0, MONOMORPHIC);
CHECK(ic_before->ic_state() == DEFAULT);
} else {
CHECK(ic_before->ic_state() == MONOMORPHIC);
}
SimulateIncrementalMarking(CcTest::heap());
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
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) {
CcTest::global()->Get(v8_str("f"))));
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
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.
CcTest::isolate()->ContextDisposedNotification();
......@@ -3380,7 +3414,12 @@ TEST(IncrementalMarkingClearsMonomorphicIC) {
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
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) {
CcTest::global()->Get(v8_str("f"))));
Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
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.
CcTest::isolate()->ContextDisposedNotification();
......@@ -3421,7 +3465,12 @@ TEST(IncrementalMarkingClearsPolymorphicIC) {
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
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) {
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
// longer referred to by dependent_code().
DependentCode::GroupStartIndexes starts(site->dependent_code());
......@@ -4311,6 +4364,8 @@ void CheckWeakness(const char* source) {
// 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.
TEST(WeakMapInMonomorphicLoadIC) {
// TODO(mvstanton): vector ics need weak support!
if (FLAG_vector_ics) return;
CheckWeakness("function loadIC(obj) {"
" return obj.name;"
"}"
......@@ -4326,6 +4381,8 @@ TEST(WeakMapInMonomorphicLoadIC) {
TEST(WeakMapInMonomorphicKeyedLoadIC) {
// TODO(mvstanton): vector ics need weak support!
if (FLAG_vector_ics) return;
CheckWeakness("function keyedLoadIC(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