Drop unnecessary receiver validity checks from {Load,Store}IC_Normal.

Since these builtins are used as handlers after a map check/dispatch, they don't need to check the receiver again.

R=verwaest@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22391 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
jkummerow@chromium.org 2014-07-15 08:07:25 +00:00
parent cd0980059d
commit 23cf62232f
4 changed files with 42 additions and 245 deletions

View File

@ -39,48 +39,6 @@ static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
}
// Generated code falls through if the receiver is a regular non-global
// JS object with slow properties and no interceptors.
static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
Register receiver,
Register elements,
Register t0,
Register t1,
Label* miss) {
// Register usage:
// receiver: holds the receiver on entry and is unchanged.
// elements: holds the property dictionary on fall through.
// Scratch registers:
// t0: used to holds the receiver map.
// t1: used to holds the receiver instance type, receiver bit mask and
// elements map.
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, miss);
// Check that the receiver is a valid JS object.
__ CompareObjectType(receiver, t0, t1, FIRST_SPEC_OBJECT_TYPE);
__ b(lt, miss);
// If this assert fails, we have to check upper bound too.
STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
GenerateGlobalInstanceTypeCheck(masm, t1, miss);
// Check that the global object does not require access checks.
__ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
__ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
(1 << Map::kHasNamedInterceptor)));
__ b(ne, miss);
__ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
__ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
__ LoadRoot(ip, Heap::kHashTableMapRootIndex);
__ cmp(t1, ip);
__ b(ne, miss);
}
// Helper function used from LoadIC GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
@ -328,29 +286,20 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
void LoadIC::GenerateNormal(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -- r1 : receiver
// -----------------------------------
ASSERT(r1.is(ReceiverRegister()));
ASSERT(r2.is(NameRegister()));
Register dictionary = r0;
ASSERT(!dictionary.is(ReceiverRegister()));
ASSERT(!dictionary.is(NameRegister()));
Label miss, slow;
Label slow;
GenerateNameDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
// r0: elements
GenerateDictionaryLoad(masm, &slow, r0, r2, r0, r3, r4);
__ ldr(dictionary,
FieldMemOperand(ReceiverRegister(), JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary, NameRegister(), r0, r3, r4);
__ Ret();
// Dictionary load failed, go slow (but don't miss).
__ bind(&slow);
GenerateRuntimeGetProperty(masm);
// Cache miss: Jump to runtime.
__ bind(&miss);
GenerateMiss(masm);
}
@ -1162,13 +1111,14 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
Register receiver = ReceiverRegister();
Register name = NameRegister();
Register value = ValueRegister();
Register dictionary = r3;
ASSERT(receiver.is(r1));
ASSERT(name.is(r2));
ASSERT(value.is(r0));
GenerateNameDictionaryReceiverCheck(masm, receiver, r3, r4, r5, &miss);
__ ldr(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &miss, r3, name, value, r4, r5);
GenerateDictionaryStore(masm, &miss, dictionary, name, value, r4, r5);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->store_normal_hit(),
1, r4, r5);

View File

@ -34,51 +34,6 @@ static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
}
// Generated code falls through if the receiver is a regular non-global
// JS object with slow properties and no interceptors.
//
// "receiver" holds the receiver on entry and is unchanged.
// "elements" holds the property dictionary on fall through.
static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
Register receiver,
Register elements,
Register scratch0,
Register scratch1,
Label* miss) {
ASSERT(!AreAliased(receiver, elements, scratch0, scratch1));
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, miss);
// Check that the receiver is a valid JS object.
// Let t be the object instance type, we want:
// FIRST_SPEC_OBJECT_TYPE <= t <= LAST_SPEC_OBJECT_TYPE.
// Since LAST_SPEC_OBJECT_TYPE is the last possible instance type we only
// check the lower bound.
STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
__ JumpIfObjectType(receiver, scratch0, scratch1, FIRST_SPEC_OBJECT_TYPE,
miss, lt);
// scratch0 now contains the map of the receiver and scratch1 the object type.
Register map = scratch0;
Register type = scratch1;
// Check if the receiver is a global JS object.
GenerateGlobalInstanceTypeCheck(masm, type, miss);
// Check that the object does not require access checks.
__ Ldrb(scratch1, FieldMemOperand(map, Map::kBitFieldOffset));
__ Tbnz(scratch1, Map::kIsAccessCheckNeeded, miss);
__ Tbnz(scratch1, Map::kHasNamedInterceptor, miss);
// Check that the properties dictionary is valid.
__ Ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
__ Ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
__ JumpIfNotRoot(scratch1, Heap::kHashTableMapRootIndex, miss);
}
// Helper function used from LoadIC GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
@ -424,28 +379,19 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
void LoadIC::GenerateNormal(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- x2 : name
// -- lr : return address
// -- x1 : receiver
// -----------------------------------
ASSERT(x1.is(ReceiverRegister()));
ASSERT(x2.is(NameRegister()));
Label miss, slow;
Register dictionary = x0;
ASSERT(!dictionary.is(ReceiverRegister()));
ASSERT(!dictionary.is(NameRegister()));
Label slow;
GenerateNameDictionaryReceiverCheck(masm, x1, x0, x3, x4, &miss);
// x0 now holds the property dictionary.
GenerateDictionaryLoad(masm, &slow, x0, x2, x0, x3, x4);
__ Ldr(dictionary,
FieldMemOperand(ReceiverRegister(), JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary, NameRegister(), x0, x3, x4);
__ Ret();
// Dictionary load failed, go slow (but don't miss).
__ Bind(&slow);
GenerateRuntimeGetProperty(masm);
// Cache miss: Jump to runtime.
__ Bind(&miss);
GenerateMiss(masm);
}
@ -1203,8 +1149,7 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
Register dictionary = x3;
ASSERT(!AreAliased(value, receiver, name, x3, x4, x5));
GenerateNameDictionaryReceiverCheck(
masm, receiver, dictionary, x4, x5, &miss);
__ Ldr(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &miss, dictionary, name, value, x4, x5);
Counters* counters = masm->isolate()->counters();

View File

@ -35,45 +35,6 @@ static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
}
// Generated code falls through if the receiver is a regular non-global
// JS object with slow properties and no interceptors.
static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
Register receiver,
Register r0,
Register r1,
Label* miss) {
// Register usage:
// receiver: holds the receiver on entry and is unchanged.
// r0: used to hold receiver instance type.
// Holds the property dictionary on fall through.
// r1: used to hold receivers map.
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, miss);
// Check that the receiver is a valid JS object.
__ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset));
__ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
__ cmp(r0, FIRST_SPEC_OBJECT_TYPE);
__ j(below, miss);
// If this assert fails, we have to check upper bound too.
STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
GenerateGlobalInstanceTypeCheck(masm, r0, miss);
// Check for non-global object that requires access check.
__ test_b(FieldOperand(r1, Map::kBitFieldOffset),
(1 << Map::kIsAccessCheckNeeded) |
(1 << Map::kHasNamedInterceptor));
__ j(not_zero, miss);
__ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
__ CheckMap(r0, masm->isolate()->factory()->hash_table_map(), miss,
DONT_DO_SMI_CHECK);
}
// Helper function used to load a property from a dictionary backing
// storage. This function may fail to load a property even though it is
// in the dictionary, so code at miss_label must always call a backup
@ -942,30 +903,21 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
void LoadIC::GenerateNormal(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- ecx : name
// -- edx : receiver
// -- esp[0] : return address
// -----------------------------------
ASSERT(edx.is(ReceiverRegister()));
ASSERT(ecx.is(NameRegister()));
Register dictionary = eax;
ASSERT(!dictionary.is(ReceiverRegister()));
ASSERT(!dictionary.is(NameRegister()));
Label miss, slow;
Label slow;
GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
// eax: elements
// Search the dictionary placing the result in eax.
GenerateDictionaryLoad(masm, &slow, eax, ecx, edi, ebx, eax);
__ mov(dictionary,
FieldOperand(ReceiverRegister(), JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary, NameRegister(), edi, ebx,
eax);
__ ret(0);
// Dictionary load failed, go slow (but don't miss).
__ bind(&slow);
GenerateRuntimeGetProperty(masm);
// Cache miss: Jump to runtime.
__ bind(&miss);
GenerateMiss(masm);
}
@ -1094,19 +1046,20 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
void StoreIC::GenerateNormal(MacroAssembler* masm) {
// Return address is on the stack.
Label miss, restore_miss;
Label restore_miss;
Register receiver = ReceiverRegister();
Register name = NameRegister();
Register value = ValueRegister();
Register dictionary = ebx;
GenerateNameDictionaryReceiverCheck(masm, receiver, ebx, edi, &miss);
__ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
// A lot of registers are needed for storing to slow case
// objects. Push and restore receiver but rely on
// GenerateDictionaryStore preserving the value and name.
__ push(receiver);
GenerateDictionaryStore(masm, &restore_miss, ebx, name, value, receiver, edi);
GenerateDictionaryStore(masm, &restore_miss, dictionary, name, value,
receiver, edi);
__ Drop(1);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->store_normal_hit(), 1);
@ -1114,8 +1067,6 @@ void StoreIC::GenerateNormal(MacroAssembler* masm) {
__ bind(&restore_miss);
__ pop(receiver);
__ bind(&miss);
__ IncrementCounter(counters->store_normal_miss(), 1);
GenerateMiss(masm);
}

View File

@ -35,46 +35,6 @@ static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
}
// Generated code falls through if the receiver is a regular non-global
// JS object with slow properties and no interceptors.
static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
Register receiver,
Register r0,
Register r1,
Label* miss) {
// Register usage:
// receiver: holds the receiver on entry and is unchanged.
// r0: used to hold receiver instance type.
// Holds the property dictionary on fall through.
// r1: used to hold receivers map.
__ JumpIfSmi(receiver, miss);
// Check that the receiver is a valid JS object.
__ movp(r1, FieldOperand(receiver, HeapObject::kMapOffset));
__ movb(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
__ cmpb(r0, Immediate(FIRST_SPEC_OBJECT_TYPE));
__ j(below, miss);
// If this assert fails, we have to check upper bound too.
STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
GenerateGlobalInstanceTypeCheck(masm, r0, miss);
// Check for non-global object that requires access check.
__ testb(FieldOperand(r1, Map::kBitFieldOffset),
Immediate((1 << Map::kIsAccessCheckNeeded) |
(1 << Map::kHasNamedInterceptor)));
__ j(not_zero, miss);
__ movp(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
__ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset),
Heap::kHashTableMapRootIndex);
__ j(not_equal, miss);
}
// Helper function used to load a property from a dictionary backing storage.
// This function may return false negatives, so miss_label
// must always call a backup property load that is complete.
@ -959,29 +919,21 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
void LoadIC::GenerateNormal(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- rdx : receiver
// -- rcx : name
// -- rsp[0] : return address
// -----------------------------------
ASSERT(rdx.is(ReceiverRegister()));
ASSERT(rcx.is(NameRegister()));
Label miss, slow;
Register dictionary = rax;
ASSERT(!dictionary.is(ReceiverRegister()));
ASSERT(!dictionary.is(NameRegister()));
GenerateNameDictionaryReceiverCheck(masm, rdx, rax, rbx, &miss);
Label slow;
// rax: elements
// Search the dictionary placing the result in rax.
GenerateDictionaryLoad(masm, &slow, rax, rcx, rbx, rdi, rax);
__ movp(dictionary,
FieldOperand(ReceiverRegister(), JSObject::kPropertiesOffset));
GenerateDictionaryLoad(masm, &slow, dictionary, NameRegister(), rbx, rdi,
rax);
__ ret(0);
// Dictionary load failed, go slow (but don't miss).
__ bind(&slow);
GenerateRuntimeGetProperty(masm);
// Cache miss: Jump to runtime.
__ bind(&miss);
GenerateMiss(masm);
}
@ -1125,16 +1077,15 @@ void StoreIC::GenerateMiss(MacroAssembler* masm) {
void StoreIC::GenerateNormal(MacroAssembler* masm) {
// Return address is on the stack.
Register receiver = ReceiverRegister();
Register name = NameRegister();
Register value = ValueRegister();
Register dictionary = rbx;
Label miss;
GenerateNameDictionaryReceiverCheck(masm, receiver, rbx, rdi, &miss);
GenerateDictionaryStore(masm, &miss, rbx, name, value, r8, r9);
__ movp(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset));
GenerateDictionaryStore(masm, &miss, dictionary, name, value, r8, r9);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->store_normal_hit(), 1);
__ ret(0);