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}
This commit is contained in:
parent
76178f1ddb
commit
c142994f74
@ -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;
|
||||
}
|
||||
|
||||
|
71
src/ast.h
71
src/ast.h
@ -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.
|
||||
__ 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);
|
||||
}
|
||||
|
||||
|
||||
@ -422,13 +430,20 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
|
||||
|
||||
__ 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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -767,31 +767,52 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||
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(ebx);
|
||||
__ push(receiver);
|
||||
__ push(name);
|
||||
__ push(ebx);
|
||||
__ 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);
|
||||
};
|
||||
|
||||
|
||||
|
305
src/ic/ic.cc
305
src/ic/ic.cc
@ -258,7 +258,11 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
|
||||
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
|
||||
@ -310,7 +314,8 @@ bool IC::IsNameCompatibleWithPrototypeFailure(Handle<Object> name) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -452,7 +457,7 @@ void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host,
|
||||
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;
|
||||
@ -514,8 +519,10 @@ void IC::Clear(Isolate* isolate, Address address,
|
||||
|
||||
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);
|
||||
@ -537,23 +544,9 @@ void IC::Clear(Isolate* isolate, Address address,
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
@ -563,6 +556,17 @@ void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target,
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
@ -578,6 +582,7 @@ void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
|
||||
|
||||
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());
|
||||
@ -585,6 +590,14 @@ void LoadIC::Clear(Isolate* isolate, Address address, Code* target,
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@ -635,6 +648,71 @@ static bool MigrateDeprecated(Handle<Object> object) {
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
@ -648,7 +726,11 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
|
||||
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");
|
||||
}
|
||||
@ -753,14 +835,22 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code) {
|
||||
|
||||
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);
|
||||
@ -771,11 +861,17 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Code> 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;
|
||||
}
|
||||
|
||||
@ -823,9 +919,13 @@ template Handle<HeapType> IC::MapToType<HeapType>(Handle<Map> map,
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -870,7 +970,11 @@ void IC::PatchCache(Handle<Name> name, Handle<Code> code) {
|
||||
// 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);
|
||||
@ -893,6 +997,10 @@ void IC::PatchCache(Handle<Name> name, Handle<Code> 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);
|
||||
}
|
||||
|
||||
@ -936,6 +1044,7 @@ Handle<Code> LoadIC::megamorphic_stub() {
|
||||
|
||||
Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate,
|
||||
ExtraICState extra_state) {
|
||||
DCHECK(!FLAG_vector_ics);
|
||||
return PropertyICCompiler::ComputeLoad(isolate, PREMONOMORPHIC, extra_state);
|
||||
}
|
||||
|
||||
@ -965,7 +1074,11 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
|
||||
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;
|
||||
}
|
||||
@ -1228,11 +1341,19 @@ static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1247,6 +1368,12 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1258,6 +1385,10 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
|
||||
// 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();
|
||||
}
|
||||
|
||||
@ -1265,9 +1396,25 @@ Handle<Code> KeyedLoadIC::LoadElementStub(Handle<HeapObject> receiver) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -1303,11 +1450,14 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2158,13 +2308,25 @@ RUNTIME_FUNCTION(CallIC_Customization_Miss) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2173,13 +2335,26 @@ RUNTIME_FUNCTION(LoadIC_Miss) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2187,13 +2362,26 @@ RUNTIME_FUNCTION(KeyedLoadIC_Miss) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2683,7 +2871,7 @@ static Object* ThrowReferenceError(Isolate* isolate, Name* name) {
|
||||
// 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();
|
||||
}
|
||||
@ -2765,13 +2953,26 @@ RUNTIME_FUNCTION(LoadElementWithInterceptor) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
61
src/ic/ic.h
61
src/ic/ic.h
@ -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,11 +280,15 @@ class IC {
|
||||
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_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
@ -76,12 +76,14 @@ void TypeFeedbackVector::SetKind(FeedbackVectorICSlot slot, Code::Kind kind) {
|
||||
|
||||
|
||||
// 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());
|
||||
@ -96,10 +98,6 @@ Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(Isolate* isolate,
|
||||
}
|
||||
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);
|
||||
@ -107,7 +105,14 @@ Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate(Isolate* 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;
|
||||
}
|
||||
|
||||
|
||||
@ -121,6 +126,28 @@ Handle<TypeFeedbackVector> TypeFeedbackVector::Copy(
|
||||
}
|
||||
|
||||
|
||||
// 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();
|
||||
@ -145,19 +172,33 @@ void TypeFeedbackVector::ClearSlots(SharedFunctionInfo* shared) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,23 +231,66 @@ void FeedbackNexus::InstallHandlers(int start_index, TypeHandleList* types,
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
@ -233,6 +317,79 @@ void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) {
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
@ -289,5 +446,56 @@ bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list,
|
||||
}
|
||||
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
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
||||
void TypeFeedbackOracle::KeyedPropertyReceiverTypes(
|
||||
TypeFeedbackId id, SmallMapList* receiver_types, bool* is_string) {
|
||||
receiver_types->Clear();
|
||||
CollectReceiverTypes(id, receiver_types);
|
||||
|
||||
// Are all the receiver maps string maps?
|
||||
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();
|
||||
}
|
||||
*is_string = all_strings;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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)),
|
||||
*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()));
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3372,7 +3401,12 @@ TEST(IncrementalMarkingClearsMonomorphicIC) {
|
||||
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();
|
||||
@ -3380,7 +3414,12 @@ TEST(IncrementalMarkingClearsMonomorphicIC) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3413,7 +3452,12 @@ TEST(IncrementalMarkingClearsPolymorphicIC) {
|
||||
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();
|
||||
@ -3421,7 +3465,12 @@ TEST(IncrementalMarkingClearsPolymorphicIC) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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];"
|
||||
"}"
|
||||
|
Loading…
Reference in New Issue
Block a user