Type Feedback Vector: Calculate profiler counts on the fly.

It's cumbersome to maintain IC profiler statistics all the time.
Let's just do it as needed.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#32693}
This commit is contained in:
mvstanton 2015-12-09 00:32:56 -08:00 committed by Commit bot
parent 175c90f8f2
commit 2b63d6b079
15 changed files with 247 additions and 421 deletions

View File

@ -2448,10 +2448,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
// r1 - function
// r3 - slot id (Smi)
// r2 - vector
const int with_types_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
ParameterCount actual(argc);
@ -2527,13 +2523,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));
__ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex);
__ str(ip, FieldMemOperand(r4, FixedArray::kHeaderSize));
// We have to update statistics for runtime profiling.
__ ldr(r4, FieldMemOperand(r2, with_types_offset));
__ sub(r4, r4, Operand(Smi::FromInt(1)));
__ str(r4, FieldMemOperand(r2, with_types_offset));
__ ldr(r4, FieldMemOperand(r2, generic_offset));
__ add(r4, r4, Operand(Smi::FromInt(1)));
__ str(r4, FieldMemOperand(r2, generic_offset));
__ bind(&call);
__ mov(r0, Operand(argc));
@ -2562,11 +2551,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ cmp(r4, ip);
__ b(ne, &miss);
// Update stats.
__ ldr(r4, FieldMemOperand(r2, with_types_offset));
__ add(r4, r4, Operand(Smi::FromInt(1)));
__ str(r4, FieldMemOperand(r2, with_types_offset));
// Initialize the call counter.
__ Move(r5, Operand(Smi::FromInt(CallICNexus::kCallCountIncrement)));
__ add(r4, r2, Operand::PointerOffsetFromSmiKey(r3));

View File

@ -2827,10 +2827,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
// x1 - function
// x3 - slot id (Smi)
// x2 - vector
const int with_types_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
ParameterCount actual(argc);
@ -2908,13 +2904,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
Operand::UntagSmiAndScale(index, kPointerSizeLog2));
__ LoadRoot(x5, Heap::kmegamorphic_symbolRootIndex);
__ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize));
// We have to update statistics for runtime profiling.
__ Ldr(x4, FieldMemOperand(feedback_vector, with_types_offset));
__ Subs(x4, x4, Operand(Smi::FromInt(1)));
__ Str(x4, FieldMemOperand(feedback_vector, with_types_offset));
__ Ldr(x4, FieldMemOperand(feedback_vector, generic_offset));
__ Adds(x4, x4, Operand(Smi::FromInt(1)));
__ Str(x4, FieldMemOperand(feedback_vector, generic_offset));
__ Bind(&call);
__ Mov(x0, argc);
@ -2942,11 +2931,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ Cmp(x4, x5);
__ B(ne, &miss);
// Update stats.
__ Ldr(x4, FieldMemOperand(feedback_vector, with_types_offset));
__ Adds(x4, x4, Operand(Smi::FromInt(1)));
__ Str(x4, FieldMemOperand(feedback_vector, with_types_offset));
// Initialize the call counter.
__ Mov(x5, Smi::FromInt(CallICNexus::kCallCountIncrement));
__ Adds(x4, feedback_vector,

View File

@ -2085,10 +2085,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
// edx - slot id
// ebx - vector
Isolate* isolate = masm->isolate();
const int with_types_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
ParameterCount actual(argc);
@ -2161,9 +2157,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ mov(
FieldOperand(ebx, edx, times_half_pointer_size, FixedArray::kHeaderSize),
Immediate(TypeFeedbackVector::MegamorphicSentinel(isolate)));
// We have to update statistics for runtime profiling.
__ sub(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
__ add(FieldOperand(ebx, generic_offset), Immediate(Smi::FromInt(1)));
__ bind(&call);
__ Set(eax, argc);
@ -2191,9 +2184,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ cmp(ecx, NativeContextOperand());
__ j(not_equal, &miss);
// Update stats.
__ add(FieldOperand(ebx, with_types_offset), Immediate(Smi::FromInt(1)));
// Initialize the call counter.
__ mov(FieldOperand(ebx, edx, times_half_pointer_size,
FixedArray::kHeaderSize + kPointerSize),

View File

@ -415,19 +415,9 @@ void IC::OnTypeFeedbackChanged(Isolate* isolate, Address address,
// static
void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host,
TypeFeedbackVector* vector, State old_state,
State new_state) {
void IC::OnTypeFeedbackChanged(Isolate* isolate, Code* host) {
if (host->kind() != Code::FUNCTION) return;
if (FLAG_type_info_threshold > 0) {
int polymorphic_delta = 0; // "Polymorphic" here includes monomorphic.
int generic_delta = 0; // "Generic" here includes megamorphic.
ComputeTypeInfoCountDelta(old_state, new_state, &polymorphic_delta,
&generic_delta);
vector->change_ic_with_type_info_count(polymorphic_delta);
vector->change_ic_generic_count(generic_delta);
}
TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
info->change_own_type_change_checksum();
host->set_profiler_ticks(0);
@ -491,9 +481,8 @@ void KeyedLoadIC::Clear(Isolate* isolate, Code* host, KeyedLoadICNexus* nexus) {
// 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);
OnTypeFeedbackChanged(isolate, host);
}
@ -505,16 +494,15 @@ void CallIC::Clear(Isolate* isolate, Code* host, CallICNexus* nexus) {
if (state != UNINITIALIZED && !feedback->IsAllocationSite()) {
nexus->ConfigureUninitialized();
// The change in state must be processed.
OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, UNINITIALIZED);
OnTypeFeedbackChanged(isolate, host);
}
}
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);
OnTypeFeedbackChanged(isolate, host);
}
@ -529,9 +517,8 @@ void StoreIC::Clear(Isolate* isolate, Address address, Code* target,
void StoreIC::Clear(Isolate* isolate, Code* host, StoreICNexus* nexus) {
if (IsCleared(nexus)) return;
State state = nexus->StateFromFeedback();
nexus->ConfigurePremonomorphic();
OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
OnTypeFeedbackChanged(isolate, host);
}
@ -547,9 +534,8 @@ void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target,
void KeyedStoreIC::Clear(Isolate* isolate, Code* host,
KeyedStoreICNexus* nexus) {
if (IsCleared(nexus)) return;
State state = nexus->StateFromFeedback();
nexus->ConfigurePremonomorphic();
OnTypeFeedbackChanged(isolate, host, nexus->vector(), state, PREMONOMORPHIC);
OnTypeFeedbackChanged(isolate, host);
}
@ -599,8 +585,7 @@ void IC::ConfigureVectorState(IC::State new_state) {
}
vector_set_ = true;
OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
new_state);
OnTypeFeedbackChanged(isolate(), get_host());
}
@ -623,8 +608,7 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
}
vector_set_ = true;
OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
MONOMORPHIC);
OnTypeFeedbackChanged(isolate(), get_host());
}
@ -647,8 +631,7 @@ void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
}
vector_set_ = true;
OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
POLYMORPHIC);
OnTypeFeedbackChanged(isolate(), get_host());
}
@ -661,8 +644,7 @@ void IC::ConfigureVectorState(MapHandleList* maps,
nexus->ConfigurePolymorphic(maps, transitioned_maps, handlers);
vector_set_ = true;
OnTypeFeedbackChanged(isolate(), get_host(), *vector(), saved_state(),
POLYMORPHIC);
OnTypeFeedbackChanged(isolate(), get_host());
}
@ -2205,8 +2187,7 @@ void CallIC::HandleMiss(Handle<Object> function) {
name = handle(js_function->shared()->name(), isolate());
}
IC::State new_state = nexus->StateFromFeedback();
OnTypeFeedbackChanged(isolate(), get_host(), *vector(), state(), new_state);
OnTypeFeedbackChanged(isolate(), get_host());
TRACE_IC("CallIC", name);
}

View File

@ -143,9 +143,7 @@ class IC {
State old_state, State new_state,
bool target_remains_ic_stub);
// As a vector-based IC, type feedback must be updated differently.
static void OnTypeFeedbackChanged(Isolate* isolate, Code* host,
TypeFeedbackVector* vector, State old_state,
State new_state);
static void OnTypeFeedbackChanged(Isolate* isolate, Code* host);
static void PostPatching(Address address, Code* target, Code* old_target);
// Compute the handler either by compiling or by retrieving a cached version.

View File

@ -2577,10 +2577,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
// a1 - function
// a3 - slot id (Smi)
// a2 - vector
const int with_types_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
ParameterCount actual(argc);
@ -2657,13 +2653,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ Addu(t0, a2, Operand(t0));
__ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
__ sw(at, FieldMemOperand(t0, FixedArray::kHeaderSize));
// We have to update statistics for runtime profiling.
__ lw(t0, FieldMemOperand(a2, with_types_offset));
__ Subu(t0, t0, Operand(Smi::FromInt(1)));
__ sw(t0, FieldMemOperand(a2, with_types_offset));
__ lw(t0, FieldMemOperand(a2, generic_offset));
__ Addu(t0, t0, Operand(Smi::FromInt(1)));
__ sw(t0, FieldMemOperand(a2, generic_offset));
__ bind(&call);
__ Jump(masm->isolate()->builtins()->Call(convert_mode()),
@ -2691,11 +2680,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ lw(t1, NativeContextMemOperand());
__ Branch(&miss, ne, t0, Operand(t1));
// Update stats.
__ lw(t0, FieldMemOperand(a2, with_types_offset));
__ Addu(t0, t0, Operand(Smi::FromInt(1)));
__ sw(t0, FieldMemOperand(a2, with_types_offset));
// Initialize the call counter.
__ sll(at, a3, kPointerSizeLog2 - kSmiTagSize);
__ Addu(at, a2, Operand(at));

View File

@ -2653,10 +2653,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
// a1 - function
// a3 - slot id (Smi)
// a2 - vector
const int with_types_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
ParameterCount actual(argc);
@ -2733,13 +2729,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ Daddu(a4, a2, Operand(a4));
__ LoadRoot(at, Heap::kmegamorphic_symbolRootIndex);
__ sd(at, FieldMemOperand(a4, FixedArray::kHeaderSize));
// We have to update statistics for runtime profiling.
__ ld(a4, FieldMemOperand(a2, with_types_offset));
__ Dsubu(a4, a4, Operand(Smi::FromInt(1)));
__ sd(a4, FieldMemOperand(a2, with_types_offset));
__ ld(a4, FieldMemOperand(a2, generic_offset));
__ Daddu(a4, a4, Operand(Smi::FromInt(1)));
__ sd(a4, FieldMemOperand(a2, generic_offset));
__ bind(&call);
__ Jump(masm->isolate()->builtins()->Call(convert_mode()),
@ -2767,11 +2756,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ ld(t1, NativeContextMemOperand());
__ Branch(&miss, ne, t0, Operand(t1));
// Update stats.
__ ld(a4, FieldMemOperand(a2, with_types_offset));
__ Daddu(a4, a4, Operand(Smi::FromInt(1)));
__ sd(a4, FieldMemOperand(a2, with_types_offset));
// Initialize the call counter.
__ dsrl(at, a3, 32 - kPointerSizeLog2);
__ Daddu(at, a2, Operand(at));

View File

@ -597,9 +597,6 @@ void TypeFeedbackVector::TypeFeedbackVectorPrint(std::ostream& os) { // NOLINT
return;
}
os << "\n - ics with type info: " << ic_with_type_info_count();
os << "\n - generic ics: " << ic_generic_count();
TypeFeedbackMetadataIterator iter(metadata());
while (iter.HasNext()) {
FeedbackVectorSlot slot = iter.Next();

View File

@ -72,8 +72,10 @@ static void GetICCounts(SharedFunctionInfo* shared,
// Harvest vector-ics as well
TypeFeedbackVector* vector = shared->feedback_vector();
*ic_with_type_info_count += vector->ic_with_type_info_count();
*ic_generic_count += vector->ic_generic_count();
int with = 0, gen = 0;
vector->ComputeCounts(&with, &gen);
*ic_with_type_info_count += with;
*ic_generic_count += gen;
if (*ic_total_count > 0) {
*type_info_percentage = 100 * *ic_with_type_info_count / *ic_total_count;

View File

@ -81,35 +81,6 @@ FeedbackVectorSlotKind TypeFeedbackVector::GetKind(
}
int TypeFeedbackVector::ic_with_type_info_count() {
return length() > 0 ? Smi::cast(get(kWithTypesIndex))->value() : 0;
}
void TypeFeedbackVector::change_ic_with_type_info_count(int delta) {
if (delta == 0) return;
int value = ic_with_type_info_count() + delta;
// Could go negative because of the debugger.
if (value >= 0) {
set(kWithTypesIndex, Smi::FromInt(value));
}
}
int TypeFeedbackVector::ic_generic_count() {
return length() > 0 ? Smi::cast(get(kGenericCountIndex))->value() : 0;
}
void TypeFeedbackVector::change_ic_generic_count(int delta) {
if (delta == 0) return;
int value = ic_generic_count() + delta;
if (value >= 0) {
set(kGenericCountIndex, Smi::FromInt(value));
}
}
int TypeFeedbackVector::GetIndex(FeedbackVectorSlot slot) const {
DCHECK(slot.ToInt() < slot_count());
return kReservedIndexCount + slot.ToInt();
@ -135,6 +106,34 @@ void TypeFeedbackVector::Set(FeedbackVectorSlot slot, Object* value,
}
void TypeFeedbackVector::ComputeCounts(int* with_type_info, int* generic) {
Object* uninitialized_sentinel =
TypeFeedbackVector::RawUninitializedSentinel(GetIsolate());
Object* megamorphic_sentinel =
*TypeFeedbackVector::MegamorphicSentinel(GetIsolate());
int with = 0;
int gen = 0;
TypeFeedbackMetadataIterator iter(metadata());
while (iter.HasNext()) {
FeedbackVectorSlot slot = iter.Next();
FeedbackVectorSlotKind kind = iter.kind();
Object* obj = Get(slot);
if (obj != uninitialized_sentinel &&
kind != FeedbackVectorSlotKind::GENERAL) {
if (obj->IsWeakCell() || obj->IsFixedArray() || obj->IsString()) {
with++;
} else if (obj == megamorphic_sentinel) {
gen++;
}
}
}
*with_type_info = with;
*generic = gen;
}
Handle<Object> TypeFeedbackVector::UninitializedSentinel(Isolate* isolate) {
return isolate->factory()->uninitialized_symbol();
}

View File

@ -140,8 +140,6 @@ Handle<TypeFeedbackVector> TypeFeedbackVector::New(
Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
array->set(kMetadataIndex, *metadata);
array->set(kWithTypesIndex, Smi::FromInt(0));
array->set(kGenericCountIndex, Smi::FromInt(0));
// Ensure we can skip the write barrier
Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);

View File

@ -182,14 +182,9 @@ class TypeFeedbackVector : public FixedArray {
static inline TypeFeedbackVector* cast(Object* obj);
static const int kMetadataIndex = 0;
static const int kWithTypesIndex = 1;
static const int kGenericCountIndex = 2;
static const int kReservedIndexCount = 3;
static const int kReservedIndexCount = 1;
inline int ic_with_type_info_count();
inline void change_ic_with_type_info_count(int delta);
inline int ic_generic_count();
inline void change_ic_generic_count(int delta);
inline void ComputeCounts(int* with_type_info, int* generic);
inline bool is_empty() const;

View File

@ -1936,10 +1936,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
// -- rbx - vector
// -----------------------------------
Isolate* isolate = masm->isolate();
const int with_types_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kWithTypesIndex);
const int generic_offset =
FixedArray::OffsetOfElementAt(TypeFeedbackVector::kGenericCountIndex);
Label extra_checks_or_miss, call, call_function;
int argc = arg_count();
StackArgumentsAccessor args(rsp, argc);
@ -2013,9 +2009,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ j(not_equal, &miss);
__ Move(FieldOperand(rbx, rdx, times_pointer_size, FixedArray::kHeaderSize),
TypeFeedbackVector::MegamorphicSentinel(isolate));
// We have to update statistics for runtime profiling.
__ SmiAddConstant(FieldOperand(rbx, with_types_offset), Smi::FromInt(-1));
__ SmiAddConstant(FieldOperand(rbx, generic_offset), Smi::FromInt(1));
__ bind(&call);
__ Set(rax, argc);
@ -2043,9 +2036,6 @@ void CallICStub::Generate(MacroAssembler* masm) {
__ cmpp(rcx, NativeContextOperand());
__ j(not_equal, &miss);
// Update stats.
__ SmiAddConstant(FieldOperand(rbx, with_types_offset), Smi::FromInt(1));
// Initialize the call counter.
__ Move(FieldOperand(rbx, rdx, times_pointer_size,
FixedArray::kHeaderSize + kPointerSize),

View File

@ -912,91 +912,87 @@ TEST(PropertyLoads) {
},
1,
{"name"}},
{
"function f(a, b) { \"use strict\"; return a[b]; }\n"
"f({arg : \"test\"}, \"arg\")",
0,
3,
6,
{
B(Ldar), A(2, 3), //
B(KeyedLoadICStrict), A(1, 3), U8(vector->GetIndex(slot1)), //
B(Return), //
},
0},
{
"function f(a) {\n"
" var b;\n"
REPEAT_127(SPACE, " b = a.name; ")
" return a.name; }\n"
"f({name : \"test\"})\n",
1 * kPointerSize,
2,
769,
{
REPEAT_127(COMMA, //
B(LoadICSloppy), A(1, 2), U8(0), U8((wide_idx_1 += 2)), //
B(Star), R(0)), //
B(LoadICSloppyWide), A(1, 2), U16(0), U16(wide_idx_1 + 2), //
B(Return), //
},
1,
{"name"}},
{
"function f(a) {\n"
" 'use strict'; var b;\n"
REPEAT_127(SPACE, " b = a.name; ")
" return a.name; }\n"
"f({name : \"test\"})\n",
1 * kPointerSize,
2,
769,
{
REPEAT_127(COMMA, //
B(LoadICStrict), A(1, 2), U8(0), U8((wide_idx_2 += 2)), //
B(Star), R(0)), //
B(LoadICStrictWide), A(1, 2), U16(0), U16(wide_idx_2 + 2), //
B(Return), //
},
1,
{"name"}},
{
"function f(a, b) {\n"
" var c;\n"
REPEAT_127(SPACE, " c = a[b]; ")
" return a[b]; }\n"
"f({name : \"test\"}, \"name\")\n",
1 * kPointerSize,
3,
896,
{
REPEAT_127(COMMA, //
B(Ldar), A(2, 3), //
B(KeyedLoadICSloppy), A(1, 3), U8((wide_idx_3 += 2)), //
B(Star), R(0)), //
B(Ldar), A(2, 3), //
B(KeyedLoadICSloppyWide), A(1, 3), U16(wide_idx_3 + 2), //
B(Return), //
}},
{
"function f(a, b) {\n"
" 'use strict'; var c;\n"
REPEAT_127(SPACE, " c = a[b]; ")
" return a[b]; }\n"
"f({name : \"test\"}, \"name\")\n",
1 * kPointerSize,
3,
896,
{
REPEAT_127(COMMA, //
B(Ldar), A(2, 3), //
B(KeyedLoadICStrict), A(1, 3), U8((wide_idx_4 += 2)), //
B(Star), R(0)), //
B(Ldar), A(2, 3), //
B(KeyedLoadICStrictWide), A(1, 3), U16(wide_idx_4 + 2), //
B(Return), //
}},
};
{"function f(a, b) { \"use strict\"; return a[b]; }\n"
"f({arg : \"test\"}, \"arg\")",
0,
3,
6,
{
B(Ldar), A(2, 3), //
B(KeyedLoadICStrict), A(1, 3), U8(vector->GetIndex(slot1)), //
B(Return), //
},
0},
{"function f(a) {\n"
" var b;\n" REPEAT_127(SPACE, " b = a.name; ") " return a.name; }\n"
"f({name : \"test\"})\n",
1 * kPointerSize,
2,
767,
{
REPEAT_127(COMMA, //
B(LoadICSloppy), A(1, 2), U8(0),
U8((wide_idx_1 += 2)), //
B(Star), R(0)), //
B(LoadICSloppy),
A(1, 2), U8(0), U8(wide_idx_1 + 2), //
B(Return), //
},
1,
{"name"}},
{"function f(a) {\n"
" 'use strict'; var b;\n" REPEAT_127(
SPACE, " b = a.name; ") " return a.name; }\n"
"f({name : \"test\"})\n",
1 * kPointerSize,
2,
767,
{
REPEAT_127(COMMA, //
B(LoadICStrict), A(1, 2), U8(0),
U8((wide_idx_2 += 2)), //
B(Star), R(0)), //
B(LoadICStrict),
A(1, 2), U8(0), U8(wide_idx_2 + 2), //
B(Return), //
},
1,
{"name"}},
{"function f(a, b) {\n"
" var c;\n" REPEAT_127(SPACE,
" c = a[b]; ") " return a[b]; }\n"
"f({name : \"test\"}, \"name\")\n",
1 * kPointerSize,
3,
895,
{
REPEAT_127(COMMA, //
B(Ldar), A(2, 3), //
B(KeyedLoadICSloppy), A(1, 3), U8((wide_idx_3 += 2)), //
B(Star), R(0)), //
B(Ldar),
A(2, 3), //
B(KeyedLoadICSloppy), A(1, 3), U8(wide_idx_3 + 2), //
B(Return), //
}},
{"function f(a, b) {\n"
" 'use strict'; var c;\n" REPEAT_127(
SPACE, " c = a[b]; ") " return a[b]; }\n"
"f({name : \"test\"}, \"name\")\n",
1 * kPointerSize,
3,
895,
{
REPEAT_127(COMMA, //
B(Ldar), A(2, 3), //
B(KeyedLoadICStrict), A(1, 3), U8((wide_idx_4 += 2)), //
B(Star), R(0)), //
B(Ldar),
A(2, 3), //
B(KeyedLoadICStrict), A(1, 3), U8(wide_idx_4 + 2), //
B(Return), //
}},
};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName);
@ -1053,13 +1049,13 @@ TEST(PropertyStores) {
2,
12,
{
B(LdaSmi8), U8(100), //
B(Star), R(0), //
B(LdaConstant), U8(0), //
B(KeyedStoreICSloppy), A(1, 2), R(0), //
U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
B(LdaSmi8), U8(100), //
B(Star), R(0), //
B(LdaConstant), U8(0), //
B(KeyedStoreICSloppy), A(1, 2), R(0), //
U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
},
1,
{"val"}},
@ -1068,11 +1064,11 @@ TEST(PropertyStores) {
3,
8,
{
B(LdaConstant), U8(0), //
B(KeyedStoreICSloppy), A(1, 3), A(2, 3), //
U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
B(LdaConstant), U8(0), //
B(KeyedStoreICSloppy), A(1, 3), A(2, 3), //
U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
},
1,
{"val"}},
@ -1109,87 +1105,89 @@ TEST(PropertyStores) {
3,
8,
{
B(LdaConstant), U8(0), //
B(KeyedStoreICStrict), A(1, 3), A(2, 3), //
U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
B(LdaConstant), U8(0), //
B(KeyedStoreICStrict), A(1, 3), A(2, 3), //
U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
},
1,
{"val"}},
{"function f(a) {\n"
REPEAT_127(SPACE, " a.name = 1; ")
" a.name = 2; }\n"
"f({name : \"test\"})\n",
{"function f(a) {\n" REPEAT_127(SPACE,
" a.name = 1; ") " a.name = 2; }\n"
"f({name : \"test\"})\n",
0,
2,
772,
770,
{
REPEAT_127(COMMA, //
B(LdaSmi8), U8(1), //
B(StoreICSloppy), A(1, 2), U8(0), U8((wide_idx_1 += 2))), //
B(LdaSmi8), U8(2), //
B(StoreICSloppyWide), A(1, 2), U16(0), U16(wide_idx_1 + 2), //
B(LdaUndefined), //
B(Return), //
REPEAT_127(COMMA, //
B(LdaSmi8), U8(1), //
B(StoreICSloppy), A(1, 2), U8(0),
U8((wide_idx_1 += 2))), //
B(LdaSmi8),
U8(2), //
B(StoreICSloppy), A(1, 2), U8(0), U8(wide_idx_1 + 2), //
B(LdaUndefined), //
B(Return), //
},
1,
{"name"}},
{"function f(a) {\n"
"'use strict';\n"
REPEAT_127(SPACE, " a.name = 1; ")
" a.name = 2; }\n"
"f({name : \"test\"})\n",
"'use strict';\n" REPEAT_127(SPACE,
" a.name = 1; ") " a.name = 2; }\n"
"f({name : \"test\"})\n",
0,
2,
772,
770,
{
REPEAT_127(COMMA, //
B(LdaSmi8), U8(1), //
B(StoreICStrict), A(1, 2), U8(0), U8((wide_idx_2 += 2))), //
B(LdaSmi8), U8(2), //
B(StoreICStrictWide), A(1, 2), U16(0), U16(wide_idx_2 + 2), //
B(LdaUndefined), //
B(Return), //
REPEAT_127(COMMA, //
B(LdaSmi8), U8(1), //
B(StoreICStrict), A(1, 2), U8(0),
U8((wide_idx_2 += 2))), //
B(LdaSmi8),
U8(2), //
B(StoreICStrict), A(1, 2), U8(0), U8(wide_idx_2 + 2), //
B(LdaUndefined), //
B(Return), //
},
1,
{"name"}},
{"function f(a, b) {\n"
REPEAT_127(SPACE, " a[b] = 1; ")
" a[b] = 2; }\n"
"f({name : \"test\"})\n",
{"function f(a, b) {\n" REPEAT_127(
SPACE, " a[b] = 1; ") " a[b] = 2; }\n"
"f({name : \"test\"})\n",
0,
3,
771,
770,
{
REPEAT_127(COMMA, //
B(LdaSmi8), U8(1), //
B(KeyedStoreICSloppy), A(1, 3), A(2, 3), //
U8((wide_idx_3 += 2))), //
B(LdaSmi8), U8(2), //
B(KeyedStoreICSloppyWide), A(1, 3), A(2, 3), //
U16(wide_idx_3 + 2), //
B(LdaUndefined), //
B(Return), //
REPEAT_127(COMMA, //
B(LdaSmi8), U8(1), //
B(KeyedStoreICSloppy), A(1, 3), A(2, 3), //
U8((wide_idx_3 += 2))), //
B(LdaSmi8),
U8(2), //
B(KeyedStoreICSloppy), A(1, 3), A(2, 3), //
U8(wide_idx_3 + 2), //
B(LdaUndefined), //
B(Return), //
}},
{"function f(a, b) {\n"
"'use strict';\n"
REPEAT_127(SPACE, " a[b] = 1; ")
" a[b] = 2; }\n"
"f({name : \"test\"})\n",
"'use strict';\n" REPEAT_127(SPACE,
" a[b] = 1; ") " a[b] = 2; }\n"
"f({name : \"test\"})\n",
0,
3,
771,
770,
{
REPEAT_127(COMMA, //
B(LdaSmi8), U8(1), //
B(KeyedStoreICStrict), A(1, 3), A(2, 3), //
U8((wide_idx_4 += 2))), //
B(LdaSmi8), U8(2), //
B(KeyedStoreICStrictWide), A(1, 3), A(2, 3), //
U16(wide_idx_4 + 2), //
B(LdaUndefined), //
B(Return), //
REPEAT_127(COMMA, //
B(LdaSmi8), U8(1), //
B(KeyedStoreICStrict), A(1, 3), A(2, 3), //
U8((wide_idx_4 += 2))), //
B(LdaSmi8),
U8(2), //
B(KeyedStoreICStrict), A(1, 3), A(2, 3), //
U8(wide_idx_4 + 2), //
B(LdaUndefined), //
B(Return), //
}}};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
@ -1270,21 +1268,21 @@ TEST(PropertyCall) {
},
1,
{"func"}},
{"function f(a) {\n"
REPEAT_127(SPACE, " a.func;\n")
" return a.func(); }\nf(" FUNC_ARG ")",
{"function f(a) {\n" REPEAT_127(
SPACE, " a.func;\n") " return a.func(); }\nf(" FUNC_ARG ")",
2 * kPointerSize,
2,
528,
526,
{
REPEAT_127(COMMA, //
B(LoadICSloppy), A(1, 2), U8(0), U8((wide_idx += 2))), //
B(Ldar), A(1, 2), //
B(Star), R(1), //
B(LoadICSloppyWide), R(1), U16(0), U16(wide_idx + 4), //
B(Star), R(0), //
B(CallWide), R(0), R(1), U16(0), U16(wide_idx + 2), //
B(Return), //
REPEAT_127(COMMA, //
B(LoadICSloppy), A(1, 2), U8(0), U8((wide_idx += 2))), //
B(Ldar),
A(1, 2), //
B(Star), R(1), //
B(LoadICSloppyWide), R(1), U16(0), U16(wide_idx + 4), //
B(Star), R(0), //
B(Call), R(0), R(1), U8(0), U8(wide_idx + 2), //
B(Return), //
},
1,
{"func"}},
@ -1353,32 +1351,32 @@ TEST(LoadGlobal) {
},
1,
{"a"}},
{"a = 1; function f(b) {\n"
REPEAT_127(SPACE, "b.name; ")
" return a; }\nf({name: 1});",
{"a = 1; function f(b) {\n" REPEAT_127(
SPACE, "b.name; ") " return a; }\nf({name: 1});",
0,
2,
514,
512,
{
REPEAT_127(COMMA, //
B(LoadICSloppy), A(1, 2), U8(0), U8(wide_idx_1 += 2)), //
B(LdaGlobalSloppyWide), U16(1), U16(wide_idx_1 + 2), //
B(Return), //
REPEAT_127(COMMA, //
B(LoadICSloppy), A(1, 2), U8(0), U8(wide_idx_1 += 2)), //
B(LdaGlobalSloppy),
U8(1), U8(wide_idx_1 + 2), //
B(Return), //
},
2,
{"name", "a"}},
{"a = 1; function f(b) {\n"
" 'use strict';\n"
REPEAT_127(SPACE, "b.name; ")
" return a; }\nf({name: 1});",
" 'use strict';\n" REPEAT_127(SPACE,
"b.name; ") " return a; }\nf({name: 1});",
0,
2,
514,
512,
{
REPEAT_127(COMMA, //
B(LoadICStrict), A(1, 2), U8(0), U8(wide_idx_2 += 2)), //
B(LdaGlobalStrictWide), U16(1), U16(wide_idx_2 + 2), //
B(Return), //
REPEAT_127(COMMA, //
B(LoadICStrict), A(1, 2), U8(0), U8(wide_idx_2 += 2)), //
B(LdaGlobalStrict),
U8(1), U8(wide_idx_2 + 2), //
B(Return), //
},
2,
{"name", "a"}},
@ -1456,36 +1454,36 @@ TEST(StoreGlobal) {
},
1,
{"a"}},
{"a = 1; function f(b) {\n"
REPEAT_127(SPACE, "b.name; ")
" a = 2; }\nf({name: 1});",
{"a = 1; function f(b) {\n" REPEAT_127(
SPACE, "b.name; ") " a = 2; }\nf({name: 1});",
0,
2,
517,
515,
{
REPEAT_127(COMMA, //
B(LoadICSloppy), A(1, 2), U8(0), U8(wide_idx_1 += 2)), //
B(LdaSmi8), U8(2), //
B(StaGlobalSloppyWide), U16(1), U16(wide_idx_1 + 2), //
B(LdaUndefined), //
B(Return), //
REPEAT_127(COMMA, //
B(LoadICSloppy), A(1, 2), U8(0), U8(wide_idx_1 += 2)), //
B(LdaSmi8),
U8(2), //
B(StaGlobalSloppy), U8(1), U8(wide_idx_1 + 2), //
B(LdaUndefined), //
B(Return), //
},
2,
{"name", "a"}},
{"a = 1; function f(b) {\n"
" 'use strict';\n"
REPEAT_127(SPACE, "b.name; ")
" a = 2; }\nf({name: 1});",
" 'use strict';\n" REPEAT_127(SPACE,
"b.name; ") " a = 2; }\nf({name: 1});",
0,
2,
517,
515,
{
REPEAT_127(COMMA, //
B(LoadICStrict), A(1, 2), U8(0), U8(wide_idx_2 += 2)), //
B(LdaSmi8), U8(2), //
B(StaGlobalStrictWide), U16(1), U16(wide_idx_2 + 2), //
B(LdaUndefined), //
B(Return), //
REPEAT_127(COMMA, //
B(LoadICStrict), A(1, 2), U8(0), U8(wide_idx_2 += 2)), //
B(LdaSmi8),
U8(2), //
B(StaGlobalStrict), U8(1), U8(wide_idx_2 + 2), //
B(LdaUndefined), //
B(Return), //
},
2,
{"name", "a"}},
@ -3399,7 +3397,7 @@ TEST(TopLevelObjectLiterals) {
B(CreateObjectLiteral), U8(0), U8(has_function_flags), //
B(Star), R(4), //
B(CreateClosure), U8(4), U8(1), //
B(StoreICSloppy), R(4), U8(3), U8(5), //
B(StoreICSloppy), R(4), U8(3), U8(3), //
B(CallRuntime), U16(Runtime::kToFastProperties), R(4), U8(1), //
B(Ldar), R(4), //
B(Star), R(3), //

View File

@ -47,8 +47,6 @@ TEST(VectorStructure) {
CHECK(Handle<FixedArray>::cast(vector)
.is_identical_to(factory->empty_fixed_array()));
// Which can nonetheless be queried.
CHECK_EQ(0, vector->ic_with_type_info_count());
CHECK_EQ(0, vector->ic_generic_count());
CHECK(vector->is_empty());
{
@ -135,8 +133,6 @@ TEST(VectorICMetadata) {
// 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 is correctly set up from the spec.
@ -200,60 +196,6 @@ TEST(VectorSlotClearing) {
}
TEST(VectorICProfilerStatistics) {
if (i::FLAG_always_opt) 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(
"function fun() {};"
"function f(a) { a(); } f(fun);");
Handle<JSFunction> f = GetFunction("f");
// There should be one IC.
Handle<Code> code = handle(f->shared()->code(), isolate);
TypeFeedbackInfo* feedback_info =
TypeFeedbackInfo::cast(code->type_feedback_info());
CHECK_EQ(1, feedback_info->ic_total_count());
CHECK_EQ(0, feedback_info->ic_with_type_info_count());
CHECK_EQ(0, feedback_info->ic_generic_count());
Handle<TypeFeedbackVector> feedback_vector =
handle(f->shared()->feedback_vector(), isolate);
FeedbackVectorHelper helper(feedback_vector);
CallICNexus nexus(feedback_vector, helper.slot(0));
CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
CHECK_EQ(0, feedback_vector->ic_generic_count());
// Now send the information generic.
CompileRun("f(Object);");
CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
CHECK_EQ(1, feedback_vector->ic_generic_count());
// A collection will not affect the site.
heap->CollectAllGarbage();
CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
CHECK_EQ(1, feedback_vector->ic_generic_count());
// The Array function is special. A call to array remains monomorphic
// and isn't cleared by gc because an AllocationSite is being held.
// Clear the IC manually in order to test this case.
nexus.Clear(*code);
CompileRun("f(Array);");
CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
CHECK_EQ(0, feedback_vector->ic_generic_count());
CHECK(nexus.GetFeedback()->IsAllocationSite());
heap->CollectAllGarbage();
CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
CHECK_EQ(0, feedback_vector->ic_generic_count());
CHECK(nexus.GetFeedback()->IsAllocationSite());
}
TEST(VectorCallICStates) {
if (i::FLAG_always_opt) return;
CcTest::InitializeVM();