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));
+ }
+ }
}
}
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);
void AstNumberingVisitor::Renumber(FunctionLiteral* node) {
if (node->scope()->HasIllegalRedeclaration()) {
node->scope()->VisitIllegalRedeclaration(this);
+ node->set_ast_properties(&properties_);
return;
}
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_;
};
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
// 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_;
}
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());
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 {
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_;
}
}
// 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_;
}
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) {
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());
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);
}
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());
}
}
-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);
}
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());
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,
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(
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);
}
__ 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);
}
__ IncrementCounter(isolate->counters()->load_miss(), 1, x3, x4);
// 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);
- __ TailCallExternalReference(ref, 2, 1);
+ int arg_count = FLAG_vector_ics ? 4 : 2;
+ __ TailCallExternalReference(ref, arg_count, 1);
}
__ 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.
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);
}
static void LoadIC_PushArgs(MacroAssembler* masm) {
Register receiver = LoadDescriptor::ReceiverRegister();
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);
- __ push(receiver);
- __ push(name);
- __ push(ebx);
+ __ 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);
// 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);
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
}
-// 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)) {}
// 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);
};
Handle<String> name) {
if (!IsNameCompatibleWithPrototypeFailure(name)) return false;
Handle<Map> receiver_map = TypeToMap(*receiver_type(), isolate());
- maybe_handler_ = target()->FindHandlerForMap(*receiver_map);
+ if (UseVector()) {
+ maybe_handler_ = nexus()->FindHandlerForMap(receiver_map);
+ } else {
+ maybe_handler_ = target()->FindHandlerForMap(*receiver_map);
+ }
// The current map wasn't handled yet. There's no reason to stay monomorphic,
// *unless* we're moving from a deprecated map to its replacement, or
if (target()->is_keyed_stub()) {
// Determine whether the failure is due to a name failure.
if (!name->IsName()) return false;
- Name* stub_name = target()->FindFirstName();
+ Name* stub_name =
+ UseVector() ? nexus()->FindFirstName() : target()->FindFirstName();
if (*name != stub_name) return false;
}
void IC::PostPatching(Address address, Code* target, Code* old_target) {
// Type vector based ICs update these statistics at a different time because
// they don't always patch on state change.
- if (target->kind() == Code::CALL_IC) return;
+ if (ICUseVector(target->kind())) return;
Isolate* isolate = target->GetHeap()->isolate();
State old_state = UNINITIALIZED;
switch (target->kind()) {
case Code::LOAD_IC:
+ if (FLAG_vector_ics) return;
return LoadIC::Clear(isolate, address, target, constant_pool);
case Code::KEYED_LOAD_IC:
+ if (FLAG_vector_ics) return;
return KeyedLoadIC::Clear(isolate, address, target, constant_pool);
case Code::STORE_IC:
return StoreIC::Clear(isolate, address, target, constant_pool);
}
-template <class Nexus>
-void IC::Clear(Isolate* isolate, Code::Kind kind, Code* host, Nexus* nexus) {
- switch (kind) {
- case Code::CALL_IC:
- return CallIC::Clear(isolate, host, nexus);
- default:
- UNREACHABLE();
- }
-}
-
-
-// Force instantiation of template instances for vector-based IC clearing.
-template void IC::Clear(Isolate*, Code::Kind, Code*, CallICNexus*);
-
-
void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
ConstantPoolArray* constant_pool) {
+ DCHECK(!FLAG_vector_ics);
if (IsCleared(target)) return;
// Make sure to also clear the map used in inline fast cases. If we
}
+void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
+ if (IsCleared(nexus)) return;
+ // Make sure to also clear the map used in inline fast cases. If we
+ // do not clear these maps, cached code can keep objects alive
+ // through the embedded maps.
+ State state = nexus->StateFromFeedback();
+ nexus->ConfigurePremonomorphic();
+ OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
+}
+
+
void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
// Determine our state.
Object* feedback = nexus->vector()->Get(nexus->slot());
void LoadIC::Clear(Isolate* isolate, Address address, Code* target,
ConstantPoolArray* constant_pool) {
+ DCHECK(!FLAG_vector_ics);
if (IsCleared(target)) return;
Code* code = PropertyICCompiler::FindPreMonomorphic(isolate, Code::LOAD_IC,
target->extra_ic_state());
}
+void LoadIC::Clear(Isolate* isolate, Code* host, LoadICNexus* nexus) {
+ if (IsCleared(nexus)) return;
+ State state = nexus->StateFromFeedback();
+ nexus->ConfigurePremonomorphic();
+ OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
+}
+
+
void StoreIC::Clear(Isolate* isolate, Address address, Code* target,
ConstantPoolArray* constant_pool) {
if (IsCleared(target)) return;
}
+void IC::ConfigureVectorState(IC::State new_state) {
+ DCHECK(UseVector());
+ if (kind() == Code::LOAD_IC) {
+ LoadICNexus* nexus = casted_nexus<LoadICNexus>();
+ if (new_state == PREMONOMORPHIC) {
+ nexus->ConfigurePremonomorphic();
+ } else if (new_state == MEGAMORPHIC) {
+ nexus->ConfigureMegamorphic();
+ } else {
+ UNREACHABLE();
+ }
+ } else if (kind() == Code::KEYED_LOAD_IC) {
+ KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
+ if (new_state == GENERIC) {
+ nexus->ConfigureGeneric();
+ } else if (new_state == PREMONOMORPHIC) {
+ nexus->ConfigurePremonomorphic();
+ } else if (new_state == MEGAMORPHIC) {
+ nexus->ConfigureMegamorphic();
+ } else {
+ UNREACHABLE();
+ }
+ } else {
+ UNREACHABLE();
+ }
+
+ OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
+ new_state);
+}
+
+
+void IC::ConfigureVectorState(Handle<Name> name, Handle<HeapType> type,
+ Handle<Code> handler) {
+ DCHECK(UseVector());
+ if (kind() == Code::LOAD_IC) {
+ LoadICNexus* nexus = casted_nexus<LoadICNexus>();
+ nexus->ConfigureMonomorphic(type, handler);
+ } else {
+ DCHECK(kind() == Code::KEYED_LOAD_IC);
+ KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
+ nexus->ConfigureMonomorphic(name, type, handler);
+ }
+
+ OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
+ MONOMORPHIC);
+}
+
+
+void IC::ConfigureVectorState(Handle<Name> name, TypeHandleList* types,
+ CodeHandleList* handlers) {
+ DCHECK(UseVector());
+ if (kind() == Code::LOAD_IC) {
+ LoadICNexus* nexus = casted_nexus<LoadICNexus>();
+ nexus->ConfigurePolymorphic(types, handlers);
+ } else {
+ DCHECK(kind() == Code::KEYED_LOAD_IC);
+ KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
+ nexus->ConfigurePolymorphic(name, types, handlers);
+ }
+
+ OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
+ POLYMORPHIC);
+}
+
+
MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
// If the object is undefined or null it's illegal to try to get any
// of its properties; throw a TypeError in that case.
if (kind() == Code::KEYED_LOAD_IC && name->AsArrayIndex(&index)) {
// Rewrite to the generic keyed load stub.
if (FLAG_use_ic) {
- set_target(*KeyedLoadIC::generic_stub(isolate()));
+ if (UseVector()) {
+ ConfigureVectorState(GENERIC);
+ } else {
+ set_target(*KeyedLoadIC::generic_stub(isolate()));
+ }
TRACE_IC("LoadIC", name);
TRACE_GENERIC_IC(isolate(), "LoadIC", "name as array index");
}
if (number_of_valid_types >= 4) return false;
if (number_of_types == 0) return false;
- if (!target()->FindHandlers(&handlers, types.length())) return false;
+ if (UseVector()) {
+ if (!nexus()->FindHandlers(&handlers, types.length())) return false;
+ } else {
+ if (!target()->FindHandlers(&handlers, types.length())) return false;
+ }
number_of_valid_types++;
if (number_of_valid_types > 1 && target()->is_keyed_stub()) return false;
Handle<Code> ic;
if (number_of_valid_types == 1) {
- ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, type, code,
- extra_ic_state());
+ if (UseVector()) {
+ ConfigureVectorState(name, receiver_type(), code);
+ } else {
+ ic = PropertyICCompiler::ComputeMonomorphic(kind(), name, type, code,
+ extra_ic_state());
+ }
} else {
if (handler_to_overwrite >= 0) {
handlers.Set(handler_to_overwrite, code);
types.Add(type);
handlers.Add(code);
}
- ic = PropertyICCompiler::ComputePolymorphic(kind(), &types, &handlers,
- number_of_valid_types, name,
- extra_ic_state());
+
+ if (UseVector()) {
+ ConfigureVectorState(name, &types, &handlers);
+ } else {
+ ic = PropertyICCompiler::ComputePolymorphic(kind(), &types, &handlers,
+ number_of_valid_types, name,
+ extra_ic_state());
+ }
}
- set_target(*ic);
+
+ if (!UseVector()) set_target(*ic);
return true;
}
void IC::UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name) {
DCHECK(handler->is_handler());
- Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic(
- kind(), name, receiver_type(), handler, extra_ic_state());
- set_target(*ic);
+ if (UseVector()) {
+ ConfigureVectorState(name, receiver_type(), handler);
+ } else {
+ Handle<Code> ic = PropertyICCompiler::ComputeMonomorphic(
+ kind(), name, receiver_type(), handler, extra_ic_state());
+ set_target(*ic);
+ }
}
// same key.
CopyICToMegamorphicCache(name);
}
- set_target(*megamorphic_stub());
+ if (UseVector()) {
+ ConfigureVectorState(MEGAMORPHIC);
+ } else {
+ set_target(*megamorphic_stub());
+ }
// Fall through.
case MEGAMORPHIC:
UpdateMegamorphicCache(*receiver_type(), *name, *code);
Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
ExtraICState extra_state) {
+ if (FLAG_vector_ics) {
+ return LoadICTrampolineStub(isolate, LoadICState(extra_state)).GetCode();
+ }
+
return PropertyICCompiler::ComputeLoad(isolate, UNINITIALIZED, extra_state);
}
Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate,
ExtraICState extra_state) {
+ DCHECK(!FLAG_vector_ics);
return PropertyICCompiler::ComputeLoad(isolate, PREMONOMORPHIC, extra_state);
}
if (state() == UNINITIALIZED) {
// This is the first time we execute this inline cache. Set the target to
// the pre monomorphic stub to delay setting the monomorphic state.
- set_target(*pre_monomorphic_stub());
+ if (UseVector()) {
+ ConfigureVectorState(PREMONOMORPHIC);
+ } else {
+ set_target(*pre_monomorphic_stub());
+ }
TRACE_IC("LoadIC", lookup->name());
return;
}
Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
+ Handle<Code> null_handle;
Handle<Map> receiver_map(receiver->map(), isolate());
MapHandleList target_receiver_maps;
TargetMaps(&target_receiver_maps);
+
if (target_receiver_maps.length() == 0) {
+ if (FLAG_vector_ics) {
+ Handle<Code> handler =
+ PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
+ ConfigureVectorState(Handle<Name>::null(), receiver_type(), handler);
+ return null_handle;
+ }
return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
}
IsMoreGeneralElementsKindTransition(
target_receiver_maps.at(0)->elements_kind(),
Handle<JSObject>::cast(receiver)->GetElementsKind())) {
+ if (FLAG_vector_ics) {
+ Handle<Code> handler =
+ PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler(receiver_map);
+ ConfigureVectorState(Handle<Name>::null(), receiver_type(), handler);
+ return null_handle;
+ }
return PropertyICCompiler::ComputeKeyedLoadMonomorphic(receiver_map);
}
// If the miss wasn't due to an unseen map, a polymorphic stub
// won't help, use the generic stub.
TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "same map added twice");
+ if (FLAG_vector_ics) {
+ ConfigureVectorState(GENERIC);
+ return null_handle;
+ }
return generic_stub();
}
// version of the IC.
if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "max polymorph exceeded");
+ if (FLAG_vector_ics) {
+ ConfigureVectorState(GENERIC);
+ return null_handle;
+ }
return generic_stub();
}
+ if (FLAG_vector_ics) {
+ CodeHandleList handlers(target_receiver_maps.length());
+ ElementHandlerCompiler compiler(isolate());
+ compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
+ TypeHandleList types(target_receiver_maps.length());
+ for (int i = 0; i < target_receiver_maps.length(); i++) {
+ types.Add(HeapType::Class(target_receiver_maps.at(i), isolate()));
+ }
+ ConfigureVectorState(Handle<Name>::null(), &types, &handlers);
+ return null_handle;
+ }
+
return PropertyICCompiler::ComputeKeyedLoadPolymorphic(&target_receiver_maps);
}
}
if (!is_target_set()) {
- Code* generic = *generic_stub();
- if (*stub == generic) {
- TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
+ if (!FLAG_vector_ics) {
+ Code* generic = *generic_stub();
+ if (*stub == generic) {
+ TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
+ }
+
+ set_target(*stub);
}
- set_target(*stub);
TRACE_IC("LoadIC", key);
}
RUNTIME_FUNCTION(LoadIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
Handle<Object> receiver = args.at<Object>(0);
Handle<Name> key = args.at<Name>(1);
- ic.UpdateState(receiver, key);
Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+
+ if (FLAG_vector_ics) {
+ DCHECK(args.length() == 4);
+ Handle<Smi> slot = args.at<Smi>(2);
+ Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
+ FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+ LoadICNexus nexus(vector, vector_slot);
+ LoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ ic.UpdateState(receiver, key);
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ } else {
+ DCHECK(args.length() == 2);
+ LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
+ ic.UpdateState(receiver, key);
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ }
return *result;
}
RUNTIME_FUNCTION(KeyedLoadIC_Miss) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
Handle<Object> receiver = args.at<Object>(0);
Handle<Object> key = args.at<Object>(1);
- ic.UpdateState(receiver, key);
Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+
+ if (FLAG_vector_ics) {
+ DCHECK(args.length() == 4);
+ Handle<Smi> slot = args.at<Smi>(2);
+ Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
+ FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+ KeyedLoadICNexus nexus(vector, vector_slot);
+ KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate, &nexus);
+ ic.UpdateState(receiver, key);
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ } else {
+ DCHECK(args.length() == 2);
+ KeyedLoadIC ic(IC::NO_EXTRA_FRAME, isolate);
+ ic.UpdateState(receiver, key);
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ }
+
return *result;
}
RUNTIME_FUNCTION(KeyedLoadIC_MissFromStubFailure) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
Handle<Object> receiver = args.at<Object>(0);
Handle<Object> key = args.at<Object>(1);
- ic.UpdateState(receiver, key);
Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+
+ if (FLAG_vector_ics) {
+ DCHECK(args.length() == 4);
+ Handle<Smi> slot = args.at<Smi>(2);
+ Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
+ FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+ KeyedLoadICNexus nexus(vector, vector_slot);
+ KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
+ ic.UpdateState(receiver, key);
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ } else {
+ DCHECK(args.length() == 2);
+ KeyedLoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
+ ic.UpdateState(receiver, key);
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ }
+
return *result;
}
// If the load is non-contextual, just return the undefined result.
// Note that both keyed and non-keyed loads may end up here.
HandleScope scope(isolate);
- LoadIC ic(IC::NO_EXTRA_FRAME, isolate);
+ LoadIC ic(IC::NO_EXTRA_FRAME, isolate, true);
if (ic.contextual_mode() != CONTEXTUAL) {
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(LoadIC_MissFromStubFailure) {
TimerEventScope<TimerEventIcMiss> timer(isolate);
HandleScope scope(isolate);
- DCHECK(args.length() == 2);
- LoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
Handle<Object> receiver = args.at<Object>(0);
Handle<Name> key = args.at<Name>(1);
- ic.UpdateState(receiver, key);
Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+
+ if (FLAG_vector_ics) {
+ DCHECK(args.length() == 4);
+ Handle<Smi> slot = args.at<Smi>(2);
+ Handle<TypeFeedbackVector> vector = args.at<TypeFeedbackVector>(3);
+ FeedbackVectorICSlot vector_slot = vector->ToICSlot(slot->value());
+ LoadICNexus nexus(vector, vector_slot);
+ LoadIC ic(IC::EXTRA_CALL_FRAME, isolate, &nexus);
+ ic.UpdateState(receiver, key);
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ } else {
+ DCHECK(args.length() == 2);
+ LoadIC ic(IC::EXTRA_CALL_FRAME, isolate);
+ ic.UpdateState(receiver, key);
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, ic.Load(receiver, key));
+ }
+
return *result;
}
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();
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,
void FindTargetMaps() {
if (target_maps_set_) return;
target_maps_set_ = true;
- if (state_ == MONOMORPHIC) {
- Map* map = target_->FindFirstMap();
- if (map != NULL) target_maps_.Add(handle(map));
- } else if (state_ != UNINITIALIZED && state_ != PREMONOMORPHIC) {
- target_->FindAllMaps(&target_maps_);
+ if (UseVector()) {
+ nexus()->ExtractMaps(&target_maps_);
+ } else {
+ if (state_ == MONOMORPHIC) {
+ Map* map = target_->FindFirstMap();
+ if (map != NULL) target_maps_.Add(handle(map));
+ } else if (state_ != UNINITIALIZED && state_ != PREMONOMORPHIC) {
+ target_->FindAllMaps(&target_maps_);
+ }
}
}
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());
}
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);
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());
}
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);
}
-// 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) {
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);
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);
// static
-Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(Isolate* isolate,
- int slot_count,
- int ic_slot_count) {
- int index_count =
+Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(
+ Isolate* isolate, const FeedbackVectorSpec& spec) {
+ const int slot_count = spec.slots();
+ const int ic_slot_count = spec.ic_slots();
+ const int index_count =
FLAG_vector_ics ? VectorICComputer::word_count(ic_slot_count) : 0;
- int length = slot_count + ic_slot_count + index_count + kReservedIndexCount;
+ const int length =
+ slot_count + ic_slot_count + index_count + kReservedIndexCount;
if (length == kReservedIndexCount) {
return Handle<TypeFeedbackVector>::cast(
isolate->factory()->empty_fixed_array());
}
array->set(kWithTypesIndex, Smi::FromInt(0));
array->set(kGenericCountIndex, Smi::FromInt(0));
- // Fill the indexes with zeros.
- for (int i = 0; i < index_count; i++) {
- array->set(kReservedIndexCount + i, Smi::FromInt(0));
- }
// Ensure we can skip the write barrier
Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
for (int i = kReservedIndexCount + index_count; i < length; i++) {
array->set(i, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
}
- return Handle<TypeFeedbackVector>::cast(array);
+
+ Handle<TypeFeedbackVector> vector = Handle<TypeFeedbackVector>::cast(array);
+ if (FLAG_vector_ics) {
+ for (int i = 0; i < ic_slot_count; i++) {
+ vector->SetKind(FeedbackVectorICSlot(i), spec.GetKind(i));
+ }
+ }
+ return vector;
}
}
+// This logic is copied from
+// StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget.
+// TODO(mvstanton): with weak handling of all vector ics, this logic should
+// actually be completely eliminated and we no longer need to clear the
+// vector ICs.
+static bool ClearLogic(Heap* heap, int ic_age, Code::Kind kind,
+ InlineCacheState state) {
+ if (FLAG_cleanup_code_caches_at_gc &&
+ (kind == Code::CALL_IC || state == MEGAMORPHIC || state == GENERIC ||
+ state == POLYMORPHIC || heap->flush_monomorphic_ics() ||
+ // TODO(mvstanton): is this ic_age granular enough? it comes from
+ // the SharedFunctionInfo which may change on a different schedule
+ // than ic targets.
+ // ic_age != heap->global_ic_age() ||
+ // is_invalidated_weak_stub ||
+ heap->isolate()->serializer_enabled())) {
+ return true;
+ }
+ return false;
+}
+
+
void TypeFeedbackVector::ClearSlots(SharedFunctionInfo* shared) {
int slots = Slots();
Isolate* isolate = GetIsolate();
slots = ICSlots();
if (slots == 0) return;
- // Now clear vector-based ICs. They are all CallICs.
+ // Now clear vector-based ICs.
// Try and pass the containing code (the "host").
+ Heap* heap = isolate->heap();
Code* host = shared->code();
+ // I'm not sure yet if this ic age is the correct one.
+ int ic_age = shared->ic_age();
for (int i = 0; i < slots; i++) {
FeedbackVectorICSlot slot(i);
Object* obj = Get(slot);
if (obj != uninitialized_sentinel) {
- // TODO(mvstanton): To make this code work with --vector-ics,
- // additional Nexus types must be created.
- DCHECK(!FLAG_vector_ics);
- DCHECK(GetKind(slot) == Code::CALL_IC);
- CallICNexus nexus(this, slot);
- ICUtility::Clear(isolate, Code::CALL_IC, host, &nexus);
+ Code::Kind kind = GetKind(slot);
+ if (kind == Code::CALL_IC) {
+ CallICNexus nexus(this, slot);
+ if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) {
+ nexus.Clear(host);
+ }
+ } else if (kind == Code::LOAD_IC) {
+ LoadICNexus nexus(this, slot);
+ if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) {
+ nexus.Clear(host);
+ }
+ } else if (kind == Code::KEYED_LOAD_IC) {
+ KeyedLoadICNexus nexus(this, slot);
+ if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) {
+ nexus.Clear(host);
+ }
+ }
}
}
}
}
+InlineCacheState LoadICNexus::StateFromFeedback() const {
+ Isolate* isolate = GetIsolate();
+ Object* feedback = GetFeedback();
+ if (feedback == *vector()->UninitializedSentinel(isolate)) {
+ return UNINITIALIZED;
+ } else if (feedback == *vector()->MegamorphicSentinel(isolate)) {
+ return MEGAMORPHIC;
+ } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
+ return PREMONOMORPHIC;
+ } else if (feedback->IsFixedArray()) {
+ FixedArray* array = FixedArray::cast(feedback);
+ int length = array->length();
+ DCHECK(length >= 2);
+ return length == 2 ? MONOMORPHIC : POLYMORPHIC;
+ }
+
+ return UNINITIALIZED;
+}
+
+
+InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
+ Isolate* isolate = GetIsolate();
+ Object* feedback = GetFeedback();
+ if (feedback == *vector()->UninitializedSentinel(isolate)) {
+ return UNINITIALIZED;
+ } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) {
+ return PREMONOMORPHIC;
+ } else if (feedback == *vector()->MegamorphicSentinel(isolate)) {
+ return MEGAMORPHIC;
+ } else if (feedback == *vector()->GenericSentinel(isolate)) {
+ return GENERIC;
+ } else if (feedback->IsFixedArray()) {
+ FixedArray* array = FixedArray::cast(feedback);
+ int length = array->length();
+ DCHECK(length >= 3);
+ return length == 3 ? MONOMORPHIC : POLYMORPHIC;
+ }
+
+ return UNINITIALIZED;
+}
+
+
InlineCacheState CallICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate();
- InlineCacheState state = UNINITIALIZED;
Object* feedback = GetFeedback();
if (feedback == *vector()->MegamorphicSentinel(isolate)) {
- state = GENERIC;
+ return GENERIC;
} else if (feedback->IsAllocationSite() || feedback->IsJSFunction()) {
- state = MONOMORPHIC;
- } else {
- CHECK(feedback == *vector()->UninitializedSentinel(isolate));
+ return MONOMORPHIC;
}
- return state;
+ CHECK(feedback == *vector()->UninitializedSentinel(isolate));
+ return UNINITIALIZED;
}
+void CallICNexus::Clear(Code* host) { CallIC::Clear(GetIsolate(), host, this); }
+
+
void CallICNexus::ConfigureGeneric() {
SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
}
}
+void KeyedLoadICNexus::ConfigureGeneric() {
+ SetFeedback(*vector()->GenericSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+}
+
+
+void KeyedLoadICNexus::ConfigureMegamorphic() {
+ SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+}
+
+
+void LoadICNexus::ConfigureMegamorphic() {
+ SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER);
+}
+
+
+void LoadICNexus::ConfigurePremonomorphic() {
+ SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
+}
+
+
+void KeyedLoadICNexus::ConfigurePremonomorphic() {
+ SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()),
+ SKIP_WRITE_BARRIER);
+}
+
+
+void LoadICNexus::ConfigureMonomorphic(Handle<HeapType> type,
+ Handle<Code> handler) {
+ Handle<FixedArray> array = EnsureArrayOfSize(2);
+ Handle<Map> receiver_map = IC::TypeToMap(*type, GetIsolate());
+ array->set(0, *receiver_map);
+ array->set(1, *handler);
+}
+
+
+void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name,
+ Handle<HeapType> type,
+ Handle<Code> handler) {
+ Handle<FixedArray> array = EnsureArrayOfSize(3);
+ Handle<Map> receiver_map = IC::TypeToMap(*type, GetIsolate());
+ if (name.is_null()) {
+ array->set(0, Smi::FromInt(0));
+ } else {
+ array->set(0, *name);
+ }
+ array->set(1, *receiver_map);
+ array->set(2, *handler);
+}
+
+
+void LoadICNexus::ConfigurePolymorphic(TypeHandleList* types,
+ CodeHandleList* handlers) {
+ int receiver_count = types->length();
+ EnsureArrayOfSize(receiver_count * 2);
+ InstallHandlers(0, types, handlers);
+}
+
+
+void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name,
+ TypeHandleList* types,
+ CodeHandleList* handlers) {
+ int receiver_count = types->length();
+ Handle<FixedArray> array = EnsureArrayOfSize(1 + receiver_count * 2);
+ if (name.is_null()) {
+ array->set(0, Smi::FromInt(0));
+ } else {
+ array->set(0, *name);
+ }
+ InstallHandlers(1, types, handlers);
+}
+
+
int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const {
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
}
return count == length;
}
+
+
+int LoadICNexus::ExtractMaps(MapHandleList* maps) const {
+ return FeedbackNexus::ExtractMaps(0, maps);
+}
+
+
+void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); }
+
+
+void KeyedLoadICNexus::Clear(Code* host) {
+ KeyedLoadIC::Clear(GetIsolate(), host, this);
+}
+
+
+int KeyedLoadICNexus::ExtractMaps(MapHandleList* maps) const {
+ return FeedbackNexus::ExtractMaps(1, maps);
+}
+
+
+MaybeHandle<Code> LoadICNexus::FindHandlerForMap(Handle<Map> map) const {
+ return FeedbackNexus::FindHandlerForMap(0, map);
+}
+
+
+MaybeHandle<Code> KeyedLoadICNexus::FindHandlerForMap(Handle<Map> map) const {
+ return FeedbackNexus::FindHandlerForMap(1, map);
+}
+
+
+bool LoadICNexus::FindHandlers(CodeHandleList* code_list, int length) const {
+ return FeedbackNexus::FindHandlers(0, code_list, length);
+}
+
+
+bool KeyedLoadICNexus::FindHandlers(CodeHandleList* code_list,
+ int length) const {
+ return FeedbackNexus::FindHandlers(1, code_list, length);
+}
+
+
+Name* KeyedLoadICNexus::FindFirstName() const {
+ Object* feedback = GetFeedback();
+ if (feedback->IsFixedArray()) {
+ FixedArray* array = FixedArray::cast(feedback);
+ DCHECK(array->length() >= 3);
+ Object* name = array->get(0);
+ if (name->IsName()) return Name::cast(name);
+ }
+ return NULL;
+}
}
} // namespace v8::internal
#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"
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
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);
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;
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;
DCHECK(vector->GetKind(slot) == Code::CALL_IC);
}
+ void Clear(Code* host);
+
void ConfigureUninitialized();
void ConfigureGeneric();
void ConfigureMonomorphicArray();
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
}
+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;
}
+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);
}
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);
}
}
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;
}
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);
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);
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,
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);
void AstTyper::VisitProperty(Property* expr) {
// Collect type feedback.
- TypeFeedbackId id = expr->PropertyFeedbackId();
- expr->set_is_uninitialized(oracle()->LoadIsUninitialized(id));
+ 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());
- oracle()->PropertyReceiverTypes(id, name, expr->GetReceiverTypes());
+ 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);
}
}
// 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);");
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.
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());
}
int index = vector->GetIndex(FeedbackVectorSlot(0));
+
CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index);
CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index));
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;
} 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) {
// 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));
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);
// 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.
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());
+}
}
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)),
- *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
- }
+ CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot1)),
+ *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
+ CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot2)),
+ *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
}
}
+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();
CcTest::global()->Get(v8_str("f"))));
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());
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
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);
+ }
}
CcTest::global()->Get(v8_str("f"))));
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.
CcTest::isolate()->ContextDisposedNotification();
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
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));
+ }
}
CcTest::global()->Get(v8_str("f"))));
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.
CcTest::isolate()->ContextDisposedNotification();
CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
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));
+ }
}
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());
// 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;"
"}"
TEST(WeakMapInMonomorphicKeyedLoadIC) {
+ // TODO(mvstanton): vector ics need weak support!
+ if (FLAG_vector_ics) return;
CheckWeakness("function keyedLoadIC(obj, field) {"
" return obj[field];"
"}"