Remove redundant checks in and around GenerateDictionaryLoad.
authorkaznacheev@chromium.org <kaznacheev@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 23 Jun 2010 09:10:21 +0000 (09:10 +0000)
committerkaznacheev@chromium.org <kaznacheev@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 23 Jun 2010 09:10:21 +0000 (09:10 +0000)
Similar or duplicate checks are scattered around the code before doing the dictionary load.
Also the entire branch in GenerateCallNormal that handles global/builtin receiver is
guaranteed to bail out from GenerateDictionaryLoad, so there is no point in generating it at all.

The purpose of the patch is:
- making C++ code more compact and transparent,
- not generating dead code.

There is a tiny performance gain. The patch is ia32 only for now.

Please tell me if I am missing anything.

Review URL: http://codereview.chromium.org/2801007

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4926 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm/ic-arm.cc
src/ia32/ic-ia32.cc
src/ic.h
src/v8-counters.h
src/x64/ic-x64.cc

index c6de4d8ef43b6fcf8544bbcf0af8ba65d4cce320..8dc6d08db3169ac92620767f6e3d1afc6507df63 100644 (file)
@@ -47,71 +47,97 @@ namespace internal {
 
 #define __ ACCESS_MASM(masm)
 
+
+static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
+                                            Register type,
+                                            Label* global_object) {
+  // Register usage:
+  //   type: holds the receiver instance type on entry.
+  __ cmp(type, Operand(JS_GLOBAL_OBJECT_TYPE));
+  __ b(eq, global_object);
+  __ cmp(type, Operand(JS_BUILTINS_OBJECT_TYPE));
+  __ b(eq, global_object);
+  __ cmp(type, Operand(JS_GLOBAL_PROXY_TYPE));
+  __ b(eq, global_object);
+}
+
+
+// Generated code falls through if the receiver is a regular non-global
+// JS object with slow properties and no interceptors.
+static void GenerateDictionaryLoadReceiverCheck(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.
+  __ tst(receiver, Operand(kSmiTagMask));
+  __ b(eq, miss);
+
+  // Check that the receiver is a valid JS object.
+  __ CompareObjectType(receiver, t0, t1, FIRST_JS_OBJECT_TYPE);
+  __ b(lt, miss);
+
+  // If this assert fails, we have to check upper bound too.
+  ASSERT(LAST_TYPE == JS_FUNCTION_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(nz, miss);
+
+  __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+  __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
+  __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
+  __ cmp(t1, ip);
+  __ b(nz, miss);
+}
+
+
 // Helper function used from LoadIC/CallIC GenerateNormal.
-// receiver: Receiver. It is not clobbered if a jump to the miss label is
-//           done
+//
+// elements: Property dictionary. It is not clobbered if a jump to the miss
+//           label is done.
 // name:     Property name. It is not clobbered if a jump to the miss label is
 //           done
 // result:   Register for the result. It is only updated if a jump to the miss
-//           label is not done. Can be the same as receiver or name clobbering
+//           label is not done. Can be the same as elements or name clobbering
 //           one of these in the case of not jumping to the miss label.
-// The three scratch registers need to be different from the receiver, name and
+// The two scratch registers need to be different from elements, name and
 // result.
+// The generated code assumes that the receiver has slow properties,
+// is not a global object and does not have interceptors.
 static void GenerateDictionaryLoad(MacroAssembler* masm,
                                    Label* miss,
-                                   Register receiver,
+                                   Register elements,
                                    Register name,
                                    Register result,
                                    Register scratch1,
-                                   Register scratch2,
-                                   Register scratch3,
-                                   DictionaryCheck check_dictionary) {
+                                   Register scratch2) {
   // Main use of the scratch registers.
-  // scratch1: Used to hold the property dictionary.
-  // scratch2: Used as temporary and to hold the capacity of the property
+  // scratch1: Used as temporary and to hold the capacity of the property
   //           dictionary.
-  // scratch3: Used as temporary.
+  // scratch2: Used as temporary.
 
   Label done;
 
-  // Check for the absence of an interceptor.
-  // Load the map into scratch1.
-  __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kMapOffset));
-
-  // Bail out if the receiver has a named interceptor.
-  __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
-  __ tst(scratch2, Operand(1 << Map::kHasNamedInterceptor));
-  __ b(nz, miss);
-
-  // Bail out if we have a JS global proxy object.
-  __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
-  __ cmp(scratch2, Operand(JS_GLOBAL_PROXY_TYPE));
-  __ b(eq, miss);
-
-  // Possible work-around for http://crbug.com/16276.
-  // See also: http://codereview.chromium.org/155418.
-  __ cmp(scratch2, Operand(JS_GLOBAL_OBJECT_TYPE));
-  __ b(eq, miss);
-  __ cmp(scratch2, Operand(JS_BUILTINS_OBJECT_TYPE));
-  __ b(eq, miss);
-
-  // Load the properties array.
-  __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
-
-  // Check that the properties array is a dictionary.
-  if (check_dictionary == CHECK_DICTIONARY) {
-    __ ldr(scratch2, FieldMemOperand(scratch1, HeapObject::kMapOffset));
-    __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
-    __ cmp(scratch2, ip);
-    __ b(ne, miss);
-  }
-
   // Compute the capacity mask.
   const int kCapacityOffset = StringDictionary::kHeaderSize +
       StringDictionary::kCapacityIndex * kPointerSize;
-  __ ldr(scratch2, FieldMemOperand(scratch1, kCapacityOffset));
-  __ mov(scratch2, Operand(scratch2, ASR, kSmiTagSize));  // convert smi to int
-  __ sub(scratch2, scratch2, Operand(1));
+  __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
+  __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize));  // convert smi to int
+  __ sub(scratch1, scratch1, Operand(1));
 
   const int kElementsStartOffset = StringDictionary::kHeaderSize +
       StringDictionary::kElementsStartIndex * kPointerSize;
@@ -122,26 +148,26 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
   static const int kProbes = 4;
   for (int i = 0; i < kProbes; i++) {
     // Compute the masked index: (hash + i + i * i) & mask.
-    __ ldr(scratch3, FieldMemOperand(name, String::kHashFieldOffset));
+    __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
     if (i > 0) {
       // Add the probe offset (i + i * i) left shifted to avoid right shifting
       // the hash in a separate instruction. The value hash + i + i * i is right
       // shifted in the following and instruction.
       ASSERT(StringDictionary::GetProbeOffset(i) <
              1 << (32 - String::kHashFieldOffset));
-      __ add(scratch3, scratch3, Operand(
+      __ add(scratch2, scratch2, Operand(
           StringDictionary::GetProbeOffset(i) << String::kHashShift));
     }
-    __ and_(scratch3, scratch2, Operand(scratch3, LSR, String::kHashShift));
+    __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
 
     // Scale the index by multiplying by the element size.
     ASSERT(StringDictionary::kEntrySize == 3);
-    // scratch3 = scratch3 * 3.
-    __ add(scratch3, scratch3, Operand(scratch3, LSL, 1));
+    // scratch2 = scratch2 * 3.
+    __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
 
     // Check if the key is identical to the name.
-    __ add(scratch3, scratch1, Operand(scratch3, LSL, 2));
-    __ ldr(ip, FieldMemOperand(scratch3, kElementsStartOffset));
+    __ add(scratch2, elements, Operand(scratch2, LSL, 2));
+    __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
     __ cmp(name, Operand(ip));
     if (i != kProbes - 1) {
       __ b(eq, &done);
@@ -151,15 +177,15 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
   }
 
   // Check that the value is a normal property.
-  __ bind(&done);  // scratch3 == scratch1 + 4 * index
-  __ ldr(scratch2,
-         FieldMemOperand(scratch3, kElementsStartOffset + 2 * kPointerSize));
-  __ tst(scratch2, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
+  __ bind(&done);  // scratch2 == elements + 4 * index
+  __ ldr(scratch1,
+         FieldMemOperand(scratch2, kElementsStartOffset + 2 * kPointerSize));
+  __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
   __ b(ne, miss);
 
   // Get the value at the masked, scaled index and return.
   __ ldr(result,
-         FieldMemOperand(scratch3, kElementsStartOffset + 1 * kPointerSize));
+         FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
 }
 
 
@@ -310,6 +336,7 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
                                            Register receiver,
                                            Register scratch1,
                                            Register scratch2,
+                                           int interceptor_bit,
                                            Label* slow) {
   // Check that the object isn't a smi.
   __ BranchOnSmi(receiver, slow);
@@ -317,8 +344,9 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
   __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
   // Check bit field.
   __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
-  __ tst(scratch2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
-  __ b(ne, slow);
+  __ tst(scratch2,
+         Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
+  __ b(nz, slow);
   // Check that the object is some kind of JS object EXCEPT JS Value type.
   // In the case that the object is a value-wrapper object,
   // we enter the runtime system to make sure that indexing into string
@@ -502,13 +530,11 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
 }
 
 
-static void GenerateNormalHelper(MacroAssembler* masm,
-                                 int argc,
-                                 bool is_global_object,
-                                 Label* miss,
-                                 Register scratch) {
-  // Search dictionary - put result in register r1.
-  GenerateDictionaryLoad(masm, miss, r1, r2, r1, r0, r3, r4, CHECK_DICTIONARY);
+static void GenerateFunctionTailCall(MacroAssembler* masm,
+                                     int argc,
+                                     Label* miss,
+                                     Register scratch) {
+  // r1: function
 
   // Check that the value isn't a smi.
   __ tst(r1, Operand(kSmiTagMask));
@@ -518,13 +544,6 @@ static void GenerateNormalHelper(MacroAssembler* masm,
   __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
   __ b(ne, miss);
 
-  // Patch the receiver with the global proxy if necessary.
-  if (is_global_object) {
-    __ ldr(r0, MemOperand(sp, argc * kPointerSize));
-    __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
-    __ str(r0, MemOperand(sp, argc * kPointerSize));
-  }
-
   // Invoke the function.
   ParameterCount actual(argc);
   __ InvokeFunction(r1, actual, JUMP_FUNCTION);
@@ -536,53 +555,18 @@ static void GenerateCallNormal(MacroAssembler* masm, int argc) {
   //  -- r2    : name
   //  -- lr    : return address
   // -----------------------------------
-  Label miss, global_object, non_global_object;
+  Label miss;
 
   // Get the receiver of the function from the stack into r1.
   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
 
-  // Check that the receiver isn't a smi.
-  __ tst(r1, Operand(kSmiTagMask));
-  __ b(eq, &miss);
-
-  // Check that the receiver is a valid JS object.  Put the map in r3.
-  __ CompareObjectType(r1, r3, r0, FIRST_JS_OBJECT_TYPE);
-  __ b(lt, &miss);
-
-  // If this assert fails, we have to check upper bound too.
-  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
-
-  // Check for access to global object.
-  __ cmp(r0, Operand(JS_GLOBAL_OBJECT_TYPE));
-  __ b(eq, &global_object);
-  __ cmp(r0, Operand(JS_BUILTINS_OBJECT_TYPE));
-  __ b(ne, &non_global_object);
+  GenerateDictionaryLoadReceiverCheck(masm, r1, r0, r3, r4, &miss);
 
-  // Accessing global object: Load and invoke.
-  __ bind(&global_object);
-  // Check that the global object does not require access checks.
-  __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
-  __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
-  __ b(ne, &miss);
-  GenerateNormalHelper(masm, argc, true, &miss, r4);
-
-  // Accessing non-global object: Check for access to global proxy.
-  Label global_proxy, invoke;
-  __ bind(&non_global_object);
-  __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE));
-  __ b(eq, &global_proxy);
-  // Check that the non-global, non-global-proxy object does not
-  // require access checks.
-  __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
-  __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
-  __ b(ne, &miss);
-  __ bind(&invoke);
-  GenerateNormalHelper(masm, argc, false, &miss, r4);
+  // r0: elements
+  // Search the dictionary - put result in register r1.
+  GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
 
-  // Global object access: Check access rights.
-  __ bind(&global_proxy);
-  __ CheckAccessGlobalProxy(r1, r0, &miss);
-  __ b(&invoke);
+  GenerateFunctionTailCall(masm, argc, &miss, r4);
 
   __ bind(&miss);
 }
@@ -594,6 +578,12 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
   //  -- lr    : return address
   // -----------------------------------
 
+  if (id == IC::kCallIC_Miss) {
+    __ IncrementCounter(&Counters::call_miss, 1, r3, r4);
+  } else {
+    __ IncrementCounter(&Counters::keyed_call_miss, 1, r3, r4);
+  }
+
   // Get the receiver of the function from the stack.
   __ ldr(r3, MemOperand(sp, argc * kPointerSize));
 
@@ -614,23 +604,26 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
   __ LeaveInternalFrame();
 
   // Check if the receiver is a global object of some sort.
-  Label invoke, global;
-  __ ldr(r2, MemOperand(sp, argc * kPointerSize));  // receiver
-  __ tst(r2, Operand(kSmiTagMask));
-  __ b(eq, &invoke);
-  __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
-  __ b(eq, &global);
-  __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
-  __ b(ne, &invoke);
-
-  // Patch the receiver on the stack.
-  __ bind(&global);
-  __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
-  __ str(r2, MemOperand(sp, argc * kPointerSize));
+  // This can happen only for regular CallIC but not KeyedCallIC.
+  if (id == IC::kCallIC_Miss) {
+    Label invoke, global;
+    __ ldr(r2, MemOperand(sp, argc * kPointerSize));  // receiver
+    __ tst(r2, Operand(kSmiTagMask));
+    __ b(eq, &invoke);
+    __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
+    __ b(eq, &global);
+    __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
+    __ b(ne, &invoke);
+
+    // Patch the receiver on the stack.
+    __ bind(&global);
+    __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
+    __ str(r2, MemOperand(sp, argc * kPointerSize));
+    __ bind(&invoke);
+  }
 
   // Invoke the function.
   ParameterCount actual(argc);
-  __ bind(&invoke);
   __ InvokeFunction(r1, actual, JUMP_FUNCTION);
 }
 
@@ -698,7 +691,8 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   // Now the key is known to be a smi. This place is also jumped to from below
   // where a numeric string is converted to a smi.
 
-  GenerateKeyedLoadReceiverCheck(masm, r1, r0, r3, &slow_call);
+  GenerateKeyedLoadReceiverCheck(
+      masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
 
   GenerateFastArrayLoad(
       masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
@@ -708,14 +702,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   // receiver in r1 is not used after this point.
   // r2: key
   // r1: function
-
-  // Check that the value in r1 is a JSFunction.
-  __ BranchOnSmi(r1, &slow_call);
-  __ CompareObjectType(r1, r0, r0, JS_FUNCTION_TYPE);
-  __ b(ne, &slow_call);
-  // Invoke the function.
-  ParameterCount actual(argc);
-  __ InvokeFunction(r1, actual, JUMP_FUNCTION);
+  GenerateFunctionTailCall(masm, argc, &slow_call, r0);
 
   __ bind(&check_number_dictionary);
   // r2: key
@@ -751,16 +738,16 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   // If the receiver is a regular JS object with slow properties then do
   // a quick inline probe of the receiver's dictionary.
   // Otherwise do the monomorphic cache probe.
-  GenerateKeyedLoadReceiverCheck(masm, r1, r0, r3, &lookup_monomorphic_cache);
+  GenerateKeyedLoadReceiverCheck(
+      masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
 
-  __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
-  __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
+  __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
   __ cmp(r3, ip);
   __ b(ne, &lookup_monomorphic_cache);
 
-  GenerateDictionaryLoad(
-      masm, &slow_load, r1, r2, r1, r0, r3, r4, DICTIONARY_CHECK_DONE);
+  GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
   __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3);
   __ jmp(&do_call);
 
@@ -826,36 +813,14 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
   //  -- r0    : receiver
   //  -- sp[0] : receiver
   // -----------------------------------
-  Label miss, probe, global;
-
-  // Check that the receiver isn't a smi.
-  __ tst(r0, Operand(kSmiTagMask));
-  __ b(eq, &miss);
-
-  // Check that the receiver is a valid JS object.  Put the map in r3.
-  __ CompareObjectType(r0, r3, r1, FIRST_JS_OBJECT_TYPE);
-  __ b(lt, &miss);
-  // If this assert fails, we have to check upper bound too.
-  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+  Label miss;
 
-  // Check for access to global object (unlikely).
-  __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE));
-  __ b(eq, &global);
+  GenerateDictionaryLoadReceiverCheck(masm, r0, r1, r3, r4, &miss);
 
-  // Check for non-global object that requires access check.
-  __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
-  __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
-  __ b(ne, &miss);
-
-  __ bind(&probe);
-  GenerateDictionaryLoad(masm, &miss, r0, r2, r0, r1, r3, r4, CHECK_DICTIONARY);
+  // r1: elements
+  GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
   __ Ret();
 
-  // Global object access: Check access rights.
-  __ bind(&global);
-  __ CheckAccessGlobalProxy(r0, r1, &miss);
-  __ b(&probe);
-
   // Cache miss: Jump to runtime.
   __ bind(&miss);
   GenerateMiss(masm);
@@ -870,6 +835,8 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
   //  -- sp[0] : receiver
   // -----------------------------------
 
+  __ IncrementCounter(&Counters::load_miss, 1, r3, r4);
+
   __ mov(r3, r0);
   __ Push(r3, r2);
 
@@ -1013,6 +980,8 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
   //  -- r1     : receiver
   // -----------------------------------
 
+  __ IncrementCounter(&Counters::keyed_load_miss, 1, r3, r4);
+
   __ Push(r1, r0);
 
   ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
@@ -1045,14 +1014,15 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   Register key = r0;
   Register receiver = r1;
 
-  GenerateKeyedLoadReceiverCheck(masm, receiver, r2, r3, &slow);
-
   // Check that the key is a smi.
   __ BranchOnNotSmi(key, &check_string);
   __ bind(&index_smi);
   // Now the key is known to be a smi. This place is also jumped to from below
   // where a numeric string is converted to a smi.
 
+  GenerateKeyedLoadReceiverCheck(
+      masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
+
   GenerateFastArrayLoad(
       masm, receiver, key, r4, r3, r2, r0, &check_pixel_array, &slow);
   __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3);
@@ -1095,12 +1065,15 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   __ bind(&check_string);
   GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
 
+  GenerateKeyedLoadReceiverCheck(
+      masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
+
   // If the receiver is a fast-case object, check the keyed lookup
   // cache. Otherwise probe the dictionary.
   __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
-  __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset));
+  __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
-  __ cmp(r3, ip);
+  __ cmp(r4, ip);
   __ b(eq, &probe_dictionary);
 
   // Load the map of the receiver, compute the keyed lookup cache hash
@@ -1148,9 +1121,14 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   // Do a quick inline probe of the receiver's dictionary, if it
   // exists.
   __ bind(&probe_dictionary);
+  // r1: receiver
+  // r0: key
+  // r3: elements
+  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+  GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
   // Load the property to r0.
-  GenerateDictionaryLoad(
-      masm, &slow, r1, r0, r0, r2, r3, r4, DICTIONARY_CHECK_DONE);
+  GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
   __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3);
   __ Ret();
 
index b0c07b7b51a63fa073352ef05ad872543a0556c2..62f878c04846581d30463f0ed7e624c5ec2d1ce5 100644 (file)
@@ -45,72 +45,96 @@ namespace internal {
 #define __ ACCESS_MASM(masm)
 
 
+static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
+                                            Register type,
+                                            Label* global_object) {
+  // Register usage:
+  //   type: holds the receiver instance type on entry.
+  __ cmp(type, JS_GLOBAL_OBJECT_TYPE);
+  __ j(equal, global_object, not_taken);
+  __ cmp(type, JS_BUILTINS_OBJECT_TYPE);
+  __ j(equal, global_object, not_taken);
+  __ cmp(type, JS_GLOBAL_PROXY_TYPE);
+  __ j(equal, global_object, not_taken);
+}
+
+
+// Generated code falls through if the receiver is a regular non-global
+// JS object with slow properties and no interceptors.
+static void GenerateDictionaryLoadReceiverCheck(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.
+  __ test(receiver, Immediate(kSmiTagMask));
+  __ j(zero, miss, not_taken);
+
+  // 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_JS_OBJECT_TYPE);
+  __ j(below, miss, not_taken);
+
+  // If this assert fails, we have to check upper bound too.
+  ASSERT(LAST_TYPE == JS_FUNCTION_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, not_taken);
+
+  __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
+  __ CheckMap(r0, Factory::hash_table_map(), miss, true);
+}
+
+
 // 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.
-// This function is safe to call if the receiver has fast properties,
-// or if name is not a symbol, and will jump to the miss_label in that case.
+// This function is safe to call if name is not a symbol, and will jump to
+// the miss_label in that case.
+// The generated code assumes that the receiver has slow properties,
+// is not a global object and does not have interceptors.
 static void GenerateDictionaryLoad(MacroAssembler* masm,
                                    Label* miss_label,
-                                   Register receiver,
+                                   Register elements,
                                    Register name,
                                    Register r0,
                                    Register r1,
-                                   Register r2,
-                                   Register result,
-                                   DictionaryCheck check_dictionary) {
+                                   Register result) {
   // Register use:
   //
-  // name - holds the name of the property and is unchanged.
-  // receiver - holds the receiver and is unchanged.
+  // elements - holds the property dictionary on entry and is unchanged.
+  //
+  // name - holds the name of the property on entry and is unchanged.
+  //
   // Scratch registers:
-  // r0   - used to hold the property dictionary.
   //
-  // r1   - used for the index into the property dictionary
+  // r0   - used for the index into the property dictionary
   //
-  // r2   - used to hold the capacity of the property dictionary.
+  // r1   - used to hold the capacity of the property dictionary.
   //
   // result - holds the result on exit.
 
   Label done;
 
-  // Check for the absence of an interceptor.
-  // Load the map into r0.
-  __ mov(r0, FieldOperand(receiver, JSObject::kMapOffset));
-
-  // Bail out if the receiver has a named interceptor.
-  __ test(FieldOperand(r0, Map::kBitFieldOffset),
-          Immediate(1 << Map::kHasNamedInterceptor));
-  __ j(not_zero, miss_label, not_taken);
-
-  // Bail out if we have a JS global proxy object.
-  __ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset));
-  __ cmp(r0, JS_GLOBAL_PROXY_TYPE);
-  __ j(equal, miss_label, not_taken);
-
-  // Possible work-around for http://crbug.com/16276.
-  __ cmp(r0, JS_GLOBAL_OBJECT_TYPE);
-  __ j(equal, miss_label, not_taken);
-  __ cmp(r0, JS_BUILTINS_OBJECT_TYPE);
-  __ j(equal, miss_label, not_taken);
-
-  // Load properties array.
-  __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
-
-  // Check that the properties array is a dictionary.
-  if (check_dictionary == CHECK_DICTIONARY) {
-    __ cmp(FieldOperand(r0, HeapObject::kMapOffset),
-           Immediate(Factory::hash_table_map()));
-    __ j(not_equal, miss_label);
-  }
-
   // Compute the capacity mask.
   const int kCapacityOffset =
       StringDictionary::kHeaderSize +
       StringDictionary::kCapacityIndex * kPointerSize;
-  __ mov(r2, FieldOperand(r0, kCapacityOffset));
-  __ shr(r2, kSmiTagSize);  // convert smi to int
-  __ dec(r2);
+  __ mov(r1, FieldOperand(elements, kCapacityOffset));
+  __ shr(r1, kSmiTagSize);  // convert smi to int
+  __ dec(r1);
 
   // Generate an unrolled loop that performs a few probes before
   // giving up. Measurements done on Gmail indicate that 2 probes
@@ -121,20 +145,20 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
       StringDictionary::kElementsStartIndex * kPointerSize;
   for (int i = 0; i < kProbes; i++) {
     // Compute the masked index: (hash + i + i * i) & mask.
-    __ mov(r1, FieldOperand(name, String::kHashFieldOffset));
-    __ shr(r1, String::kHashShift);
+    __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
+    __ shr(r0, String::kHashShift);
     if (i > 0) {
-      __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i)));
+      __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i)));
     }
-    __ and_(r1, Operand(r2));
+    __ and_(r0, Operand(r1));
 
     // Scale the index by multiplying by the entry size.
     ASSERT(StringDictionary::kEntrySize == 3);
-    __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
+    __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3
 
     // Check if the key is identical to the name.
-    __ cmp(name,
-           Operand(r0, r1, times_4, kElementsStartOffset - kHeapObjectTag));
+    __ cmp(name, Operand(elements, r0, times_4,
+                         kElementsStartOffset - kHeapObjectTag));
     if (i != kProbes - 1) {
       __ j(equal, &done, taken);
     } else {
@@ -145,13 +169,13 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
   // Check that the value is a normal property.
   __ bind(&done);
   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
-  __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag),
+  __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
           Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
   __ j(not_zero, miss_label, not_taken);
 
   // Get the value at the masked, scaled index.
   const int kValueOffset = kElementsStartOffset + kPointerSize;
-  __ mov(result, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag));
+  __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
 }
 
 
@@ -307,6 +331,7 @@ void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
                                            Register receiver,
                                            Register map,
+                                           int interceptor_bit,
                                            Label* slow) {
   // Register use:
   //   receiver - holds the receiver and is unchanged.
@@ -322,7 +347,7 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
 
   // Check bit field.
   __ test_b(FieldOperand(map, Map::kBitFieldOffset),
-            KeyedLoadIC::kSlowCaseBitFieldMask);
+            (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
   __ j(not_zero, slow, not_taken);
   // Check that the object is some kind of JS object EXCEPT JS Value type.
   // In the case that the object is a value-wrapper object,
@@ -432,8 +457,6 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   Label slow, check_string, index_smi, index_string;
   Label check_pixel_array, probe_dictionary, check_number_dictionary;
 
-  GenerateKeyedLoadReceiverCheck(masm, edx, ecx, &slow);
-
   // Check that the key is a smi.
   __ test(eax, Immediate(kSmiTagMask));
   __ j(not_zero, &check_string, not_taken);
@@ -441,6 +464,9 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   // Now the key is known to be a smi. This place is also jumped to from
   // where a numeric string is converted to a smi.
 
+  GenerateKeyedLoadReceiverCheck(
+      masm, edx, ecx, Map::kHasIndexedInterceptor, &slow);
+
   GenerateFastArrayLoad(masm,
                         edx,
                         eax,
@@ -503,6 +529,9 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   __ bind(&check_string);
   GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow);
 
+  GenerateKeyedLoadReceiverCheck(
+      masm, edx, ecx, Map::kHasNamedInterceptor, &slow);
+
   // If the receiver is a fast-case object, check the keyed lookup
   // cache. Otherwise probe the dictionary.
   __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
@@ -555,15 +584,12 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   // Do a quick inline probe of the receiver's dictionary, if it
   // exists.
   __ bind(&probe_dictionary);
-  GenerateDictionaryLoad(masm,
-                         &slow,
-                         edx,
-                         eax,
-                         ebx,
-                         ecx,
-                         edi,
-                         eax,
-                         DICTIONARY_CHECK_DONE);
+
+  __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset));
+  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
+  GenerateGlobalInstanceTypeCheck(masm, ecx, &slow);
+
+  GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax);
   __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
   __ ret(0);
 
@@ -1173,24 +1199,18 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
 }
 
 
-static void GenerateNormalHelper(MacroAssembler* masm,
-                                 int argc,
-                                 bool is_global_object,
-                                 Label* miss) {
+static void GenerateFunctionTailCall(MacroAssembler* masm,
+                                     int argc,
+                                     Label* miss) {
   // ----------- S t a t e -------------
   //  -- ecx                 : name
-  //  -- edx                 : receiver
+  //  -- edi                 : function
   //  -- esp[0]              : return address
   //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
   //  -- ...
   //  -- esp[(argc + 1) * 4] : receiver
   // -----------------------------------
 
-  // Search dictionary - put result in register edi.
-  __ mov(edi, edx);
-  GenerateDictionaryLoad(
-      masm, miss, edx, ecx, eax, edi, ebx, edi, CHECK_DICTIONARY);
-
   // Check that the result is not a smi.
   __ test(edi, Immediate(kSmiTagMask));
   __ j(zero, miss, not_taken);
@@ -1199,12 +1219,6 @@ static void GenerateNormalHelper(MacroAssembler* masm,
   __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
   __ j(not_equal, miss, not_taken);
 
-  // Patch the receiver on stack with the global proxy if necessary.
-  if (is_global_object) {
-    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
-    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
-  }
-
   // Invoke the function.
   ParameterCount actual(argc);
   __ InvokeFunction(edi, actual, JUMP_FUNCTION);
@@ -1219,55 +1233,17 @@ static void GenerateCallNormal(MacroAssembler* masm, int argc) {
   //  -- ...
   //  -- esp[(argc + 1) * 4] : receiver
   // -----------------------------------
-  Label miss, global_object, non_global_object;
+  Label miss;
 
   // Get the receiver of the function from the stack; 1 ~ return address.
   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
 
-  // Check that the receiver isn't a smi.
-  __ test(edx, Immediate(kSmiTagMask));
-  __ j(zero, &miss, not_taken);
+  GenerateDictionaryLoadReceiverCheck(masm, edx, eax, ebx, &miss);
 
-  // Check that the receiver is a valid JS object.
-  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
-  __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceTypeOffset));
-  __ cmp(eax, FIRST_JS_OBJECT_TYPE);
-  __ j(below, &miss, not_taken);
-
-  // If this assert fails, we have to check upper bound too.
-  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
-
-  // Check for access to global object.
-  __ cmp(eax, JS_GLOBAL_OBJECT_TYPE);
-  __ j(equal, &global_object);
-  __ cmp(eax, JS_BUILTINS_OBJECT_TYPE);
-  __ j(not_equal, &non_global_object);
-
-  // Accessing global object: Load and invoke.
-  __ bind(&global_object);
-  // Check that the global object does not require access checks.
-  __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
-            1 << Map::kIsAccessCheckNeeded);
-  __ j(not_equal, &miss, not_taken);
-  GenerateNormalHelper(masm, argc, true, &miss);
-
-  // Accessing non-global object: Check for access to global proxy.
-  Label global_proxy, invoke;
-  __ bind(&non_global_object);
-  __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
-  __ j(equal, &global_proxy, not_taken);
-  // Check that the non-global, non-global-proxy object does not
-  // require access checks.
-  __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
-            1 << Map::kIsAccessCheckNeeded);
-  __ j(not_equal, &miss, not_taken);
-  __ bind(&invoke);
-  GenerateNormalHelper(masm, argc, false, &miss);
-
-  // Global object proxy access: Check access rights.
-  __ bind(&global_proxy);
-  __ CheckAccessGlobalProxy(edx, eax, &miss);
-  __ jmp(&invoke);
+  // eax: elements
+  // Search the dictionary placing the result in edi.
+  GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
+  GenerateFunctionTailCall(masm, argc, &miss);
 
   __ bind(&miss);
 }
@@ -1282,6 +1258,12 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
   //  -- esp[(argc + 1) * 4] : receiver
   // -----------------------------------
 
+  if (id == IC::kCallIC_Miss) {
+    __ IncrementCounter(&Counters::call_miss, 1);
+  } else {
+    __ IncrementCounter(&Counters::keyed_call_miss, 1);
+  }
+
   // Get the receiver of the function from the stack; 1 ~ return address.
   __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
 
@@ -1303,25 +1285,28 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
   __ LeaveInternalFrame();
 
   // Check if the receiver is a global object of some sort.
-  Label invoke, global;
-  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
-  __ test(edx, Immediate(kSmiTagMask));
-  __ j(zero, &invoke, not_taken);
-  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
-  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
-  __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
-  __ j(equal, &global);
-  __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
-  __ j(not_equal, &invoke);
-
-  // Patch the receiver on the stack.
-  __ bind(&global);
-  __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
-  __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
+  // This can happen only for regular CallIC but not KeyedCallIC.
+  if (id == IC::kCallIC_Miss) {
+    Label invoke, global;
+    __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
+    __ test(edx, Immediate(kSmiTagMask));
+    __ j(zero, &invoke, not_taken);
+    __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+    __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
+    __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
+    __ j(equal, &global);
+    __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
+    __ j(not_equal, &invoke);
+
+    // Patch the receiver on the stack.
+    __ bind(&global);
+    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
+    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
+    __ bind(&invoke);
+  }
 
   // Invoke the function.
   ParameterCount actual(argc);
-  __ bind(&invoke);
   __ InvokeFunction(edi, actual, JUMP_FUNCTION);
 }
 
@@ -1393,7 +1378,8 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   // Now the key is known to be a smi. This place is also jumped to from
   // where a numeric string is converted to a smi.
 
-  GenerateKeyedLoadReceiverCheck(masm, edx, eax, &slow_call);
+  GenerateKeyedLoadReceiverCheck(
+      masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
 
   GenerateFastArrayLoad(
       masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
@@ -1403,15 +1389,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   // receiver in edx is not used after this point.
   // ecx: key
   // edi: function
-
-  // Check that the value in edi is a JavaScript function.
-  __ test(edi, Immediate(kSmiTagMask));
-  __ j(zero, &slow_call, not_taken);
-  __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
-  __ j(not_equal, &slow_call, not_taken);
-  // Invoke the function.
-  ParameterCount actual(argc);
-  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
+  GenerateFunctionTailCall(masm, argc, &slow_call);
 
   __ bind(&check_number_dictionary);
   // eax: elements
@@ -1451,15 +1429,13 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   // If the receiver is a regular JS object with slow properties then do
   // a quick inline probe of the receiver's dictionary.
   // Otherwise do the monomorphic cache probe.
-  GenerateKeyedLoadReceiverCheck(masm, edx, eax, &lookup_monomorphic_cache);
+  GenerateKeyedLoadReceiverCheck(
+      masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
 
   __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
-  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
-         Immediate(Factory::hash_table_map()));
-  __ j(not_equal, &lookup_monomorphic_cache, not_taken);
+  __ CheckMap(ebx, Factory::hash_table_map(), &lookup_monomorphic_cache, true);
 
-  GenerateDictionaryLoad(
-      masm, &slow_load, edx, ecx, ebx, eax, edi, edi, DICTIONARY_CHECK_DONE);
+  GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
   __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1);
   __ jmp(&do_call);
 
@@ -1539,49 +1515,15 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
   //  -- ecx    : name
   //  -- esp[0] : return address
   // -----------------------------------
-  Label miss, probe, global;
-
-  // Check that the receiver isn't a smi.
-  __ test(eax, Immediate(kSmiTagMask));
-  __ j(zero, &miss, not_taken);
-
-  // Check that the receiver is a valid JS object.
-  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
-  __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceTypeOffset));
-  __ cmp(edx, FIRST_JS_OBJECT_TYPE);
-  __ j(less, &miss, not_taken);
-
-  // If this assert fails, we have to check upper bound too.
-  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
-
-  // Check for access to global object (unlikely).
-  __ cmp(edx, JS_GLOBAL_PROXY_TYPE);
-  __ j(equal, &global, not_taken);
+  Label miss;
 
-  // Check for non-global object that requires access check.
-  __ test_b(FieldOperand(ebx, Map::kBitFieldOffset),
-            1 << Map::kIsAccessCheckNeeded);
-  __ j(not_zero, &miss, not_taken);
+  GenerateDictionaryLoadReceiverCheck(masm, eax, edx, ebx, &miss);
 
+  // edx: elements
   // Search the dictionary placing the result in eax.
-  __ bind(&probe);
-  GenerateDictionaryLoad(masm,
-                         &miss,
-                         eax,
-                         ecx,
-                         edx,
-                         edi,
-                         ebx,
-                         edi,
-                         CHECK_DICTIONARY);
-  __ mov(eax, edi);
+  GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax);
   __ ret(0);
 
-  // Global object access: Check access rights.
-  __ bind(&global);
-  __ CheckAccessGlobalProxy(eax, edx, &miss);
-  __ jmp(&probe);
-
   // Cache miss: Jump to runtime.
   __ bind(&miss);
   GenerateMiss(masm);
@@ -1595,6 +1537,8 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
   //  -- esp[0] : return address
   // -----------------------------------
 
+  __ IncrementCounter(&Counters::load_miss, 1);
+
   __ pop(ebx);
   __ push(eax);  // receiver
   __ push(ecx);  // name
@@ -1711,6 +1655,8 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
   //  -- esp[0] : return address
   // -----------------------------------
 
+  __ IncrementCounter(&Counters::keyed_load_miss, 1);
+
   __ pop(ebx);
   __ push(edx);  // receiver
   __ push(eax);  // name
index 5fd5078fedffd8d78260ec6734c211068ab532b5..738b6f4e6890870c8c488d86488a494f9beee2a5 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
 namespace v8 {
 namespace internal {
 
-// Flag indicating whether an IC stub needs to check that a backing
-// store is in dictionary case.
-enum DictionaryCheck { CHECK_DICTIONARY, DICTIONARY_CHECK_DONE };
-
 
 // IC_UTIL_LIST defines all utility functions called from generated
 // inline caching code. The argument for the macro, ICU, is the function name.
index 10b810246031f09a22b469218393bc67ad105f81..93fecd1fe87c7e630d69f39b7fd26178d6e8d403 100644 (file)
@@ -153,6 +153,10 @@ namespace internal {
   SC(keyed_store_inline_miss, V8.KeyedStoreInlineMiss)                \
   SC(named_store_global_inline, V8.NamedStoreGlobalInline)            \
   SC(named_store_global_inline_miss, V8.NamedStoreGlobalInlineMiss)   \
+  SC(call_miss, V8.CallMiss)                                          \
+  SC(keyed_call_miss, V8.KeyedCallMiss)                               \
+  SC(load_miss, V8.LoadMiss)                                          \
+  SC(keyed_load_miss, V8.KeyedLoadMiss)                               \
   SC(call_const, V8.CallConst)                                        \
   SC(call_const_fast_api, V8.CallConstFastApi)                        \
   SC(call_const_interceptor, V8.CallConstInterceptor)                 \
index 6e77c892d7ec6ca69651d0ddf7296efb419d3cc6..20ed734b8a57ebe6139ae7331b3fbf56c4f318fe 100644 (file)
@@ -45,71 +45,93 @@ namespace internal {
 #define __ ACCESS_MASM(masm)
 
 
+static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
+                                            Register type,
+                                            Label* global_object) {
+  // Register usage:
+  //   type: holds the receiver instance type on entry.
+  __ cmpb(type, Immediate(JS_GLOBAL_OBJECT_TYPE));
+  __ j(equal, global_object);
+  __ cmpb(type, Immediate(JS_BUILTINS_OBJECT_TYPE));
+  __ j(equal, global_object);
+  __ cmpb(type, Immediate(JS_GLOBAL_PROXY_TYPE));
+  __ j(equal, global_object);
+}
+
+
+// Generated code falls through if the receiver is a regular non-global
+// JS object with slow properties and no interceptors.
+static void GenerateDictionaryLoadReceiverCheck(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.
+  __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset));
+  __ movb(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
+  __ cmpb(r0, Immediate(FIRST_JS_OBJECT_TYPE));
+  __ j(below, miss);
+
+  // If this assert fails, we have to check upper bound too.
+  ASSERT(LAST_TYPE == JS_FUNCTION_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);
+
+  __ movq(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.
-// This function is safe to call if the receiver has fast properties,
-// or if name is not a symbol, and will jump to the miss_label in that case.
+// This function is safe to call if name is not a symbol, and will jump to
+// the miss_label in that case.
+// The generated code assumes that the receiver has slow properties,
+// is not a global object and does not have interceptors.
 static void GenerateDictionaryLoad(MacroAssembler* masm,
                                    Label* miss_label,
+                                   Register elements,
+                                   Register name,
                                    Register r0,
                                    Register r1,
-                                   Register r2,
-                                   Register name,
-                                   Register r4,
-                                   Register result,
-                                   DictionaryCheck check_dictionary) {
+                                   Register result) {
   // Register use:
   //
-  // r0   - used to hold the property dictionary and is unchanged.
-  //
-  // r1   - used to hold the receiver and is unchanged.
+  // elements - holds the property dictionary on entry and is unchanged.
   //
-  // r2   - used to hold the capacity of the property dictionary.
+  // name - holds the name of the property on entry and is unchanged.
   //
-  // name - holds the name of the property and is unchanged.
+  // r0   - used to hold the capacity of the property dictionary.
   //
-  // r4   - used to hold the index into the property dictionary.
+  // r1   - used to hold the index into the property dictionary.
   //
   // result - holds the result on exit if the load succeeded.
 
   Label done;
 
-  // Check for the absence of an interceptor.
-  // Load the map into r0.
-  __ movq(r0, FieldOperand(r1, JSObject::kMapOffset));
-
-  // Bail out if the receiver has a named interceptor.
-  __ testl(FieldOperand(r0, Map::kBitFieldOffset),
-           Immediate(1 << Map::kHasNamedInterceptor));
-  __ j(not_zero, miss_label);
-
-  // Bail out if we have a JS global proxy object.
-  __ movzxbq(r0, FieldOperand(r0, Map::kInstanceTypeOffset));
-  __ cmpb(r0, Immediate(JS_GLOBAL_PROXY_TYPE));
-  __ j(equal, miss_label);
-
-  // Possible work-around for http://crbug.com/16276.
-  __ cmpb(r0, Immediate(JS_GLOBAL_OBJECT_TYPE));
-  __ j(equal, miss_label);
-  __ cmpb(r0, Immediate(JS_BUILTINS_OBJECT_TYPE));
-  __ j(equal, miss_label);
-
-  // Load properties array.
-  __ movq(r0, FieldOperand(r1, JSObject::kPropertiesOffset));
-
-  if (check_dictionary == CHECK_DICTIONARY) {
-    // Check that the properties array is a dictionary.
-    __ Cmp(FieldOperand(r0, HeapObject::kMapOffset), Factory::hash_table_map());
-    __ j(not_equal, miss_label);
-  }
-
   // Compute the capacity mask.
   const int kCapacityOffset =
       StringDictionary::kHeaderSize +
       StringDictionary::kCapacityIndex * kPointerSize;
-  __ SmiToInteger32(r2, FieldOperand(r0, kCapacityOffset));
-  __ decl(r2);
+  __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset));
+  __ decl(r0);
 
   // Generate an unrolled loop that performs a few probes before
   // giving up. Measurements done on Gmail indicate that 2 probes
@@ -120,19 +142,19 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
       StringDictionary::kElementsStartIndex * kPointerSize;
   for (int i = 0; i < kProbes; i++) {
     // Compute the masked index: (hash + i + i * i) & mask.
-    __ movl(r4, FieldOperand(name, String::kHashFieldOffset));
-    __ shrl(r4, Immediate(String::kHashShift));
+    __ movl(r1, FieldOperand(name, String::kHashFieldOffset));
+    __ shrl(r1, Immediate(String::kHashShift));
     if (i > 0) {
-      __ addl(r4, Immediate(StringDictionary::GetProbeOffset(i)));
+      __ addl(r1, Immediate(StringDictionary::GetProbeOffset(i)));
     }
-    __ and_(r4, r2);
+    __ and_(r1, r0);
 
     // Scale the index by multiplying by the entry size.
     ASSERT(StringDictionary::kEntrySize == 3);
-    __ lea(r4, Operand(r4, r4, times_2, 0));  // r4 = r4 * 3
+    __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
 
     // Check if the key is identical to the name.
-    __ cmpq(name, Operand(r0, r4, times_pointer_size,
+    __ cmpq(name, Operand(elements, r1, times_pointer_size,
                           kElementsStartOffset - kHeapObjectTag));
     if (i != kProbes - 1) {
       __ j(equal, &done);
@@ -144,14 +166,16 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
   // Check that the value is a normal property.
   __ bind(&done);
   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
-  __ Test(Operand(r0, r4, times_pointer_size, kDetailsOffset - kHeapObjectTag),
+  __ Test(Operand(elements, r1, times_pointer_size,
+                  kDetailsOffset - kHeapObjectTag),
           Smi::FromInt(PropertyDetails::TypeField::mask()));
   __ j(not_zero, miss_label);
 
   // Get the value at the masked, scaled index.
   const int kValueOffset = kElementsStartOffset + kPointerSize;
   __ movq(result,
-          Operand(r0, r4, times_pointer_size, kValueOffset - kHeapObjectTag));
+          Operand(elements, r1, times_pointer_size,
+                  kValueOffset - kHeapObjectTag));
 }
 
 
@@ -327,6 +351,8 @@ void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
   //  -- rsp[0]  : return address
   // -----------------------------------
 
+  __ IncrementCounter(&Counters::keyed_load_miss, 1);
+
   __ pop(rbx);
   __ push(rdx);  // receiver
   __ push(rax);  // name
@@ -360,6 +386,7 @@ void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
                                            Register receiver,
                                            Register map,
+                                           int interceptor_bit,
                                            Label* slow) {
   // Register use:
   //   receiver - holds the receiver and is unchanged.
@@ -379,7 +406,8 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
 
   // Check bit field.
   __ testb(FieldOperand(map, Map::kBitFieldOffset),
-           Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
+           Immediate((1 << Map::kIsAccessCheckNeeded) |
+                     (1 << interceptor_bit)));
   __ j(not_zero, slow);
 }
 
@@ -500,14 +528,15 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   Label slow, check_string, index_smi, index_string;
   Label check_pixel_array, probe_dictionary, check_number_dictionary;
 
-  GenerateKeyedLoadReceiverCheck(masm, rdx, rcx, &slow);
-
   // Check that the key is a smi.
   __ JumpIfNotSmi(rax, &check_string);
   __ bind(&index_smi);
   // Now the key is known to be a smi. This place is also jumped to from below
   // where a numeric string is converted to a smi.
 
+  GenerateKeyedLoadReceiverCheck(
+      masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow);
+
   GenerateFastArrayLoad(masm,
                         rdx,
                         rax,
@@ -557,6 +586,9 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   __ bind(&check_string);
   GenerateKeyStringCheck(masm, rax, rcx, rbx, &index_string, &slow);
 
+  GenerateKeyedLoadReceiverCheck(
+      masm, rdx, rcx, Map::kHasNamedInterceptor, &slow);
+
   // If the receiver is a fast-case object, check the keyed lookup
   // cache. Otherwise probe the dictionary leaving result in rcx.
   __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
@@ -608,15 +640,13 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
   __ bind(&probe_dictionary);
   // rdx: receiver
   // rax: key
-  GenerateDictionaryLoad(masm,
-                         &slow,
-                         rbx,
-                         rdx,
-                         rcx,
-                         rax,
-                         rdi,
-                         rax,
-                         DICTIONARY_CHECK_DONE);
+  // rbx: elements
+
+  __ movq(rcx, FieldOperand(rdx, JSObject::kMapOffset));
+  __ movb(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
+  GenerateGlobalInstanceTypeCheck(masm, rcx, &slow);
+
+  GenerateDictionaryLoad(masm, &slow, rbx, rax, rcx, rdi, rax);
   __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
   __ ret(0);
 
@@ -1212,6 +1242,13 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
   // rsp[argc * 8]            : argument 1
   // rsp[(argc + 1) * 8]      : argument 0 = receiver
   // -----------------------------------
+
+  if (id == IC::kCallIC_Miss) {
+    __ IncrementCounter(&Counters::call_miss, 1);
+  } else {
+    __ IncrementCounter(&Counters::keyed_call_miss, 1);
+  }
+
   // Get the receiver of the function from the stack; 1 ~ return address.
   __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
 
@@ -1233,22 +1270,25 @@ static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
   __ LeaveInternalFrame();
 
   // Check if the receiver is a global object of some sort.
-  Label invoke, global;
-  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));  // receiver
-  __ JumpIfSmi(rdx, &invoke);
-  __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
-  __ j(equal, &global);
-  __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
-  __ j(not_equal, &invoke);
-
-  // Patch the receiver on the stack.
-  __ bind(&global);
-  __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
-  __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+  // This can happen only for regular CallIC but not KeyedCallIC.
+  if (id == IC::kCallIC_Miss) {
+    Label invoke, global;
+    __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));  // receiver
+    __ JumpIfSmi(rdx, &invoke);
+    __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
+    __ j(equal, &global);
+    __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
+    __ j(not_equal, &invoke);
+
+    // Patch the receiver on the stack.
+    __ bind(&global);
+    __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
+    __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
+    __ bind(&invoke);
+  }
 
   // Invoke the function.
   ParameterCount actual(argc);
-  __ bind(&invoke);
   __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
 }
 
@@ -1309,13 +1349,12 @@ static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
 }
 
 
-static void GenerateNormalHelper(MacroAssembler* masm,
-                                 int argc,
-                                 bool is_global_object,
-                                 Label* miss) {
+static void GenerateFunctionTailCall(MacroAssembler* masm,
+                                     int argc,
+                                     Label* miss) {
   // ----------- S t a t e -------------
   // rcx                    : function name
-  // rdx                    : receiver
+  // rdi                    : function
   // rsp[0]                 : return address
   // rsp[8]                 : argument argc
   // rsp[16]                : argument argc - 1
@@ -1323,21 +1362,11 @@ static void GenerateNormalHelper(MacroAssembler* masm,
   // rsp[argc * 8]          : argument 1
   // rsp[(argc + 1) * 8]    : argument 0 = receiver
   // -----------------------------------
-  // Search dictionary - put result in register rdx.
-  GenerateDictionaryLoad(
-     masm, miss, rax, rdx, rbx, rcx, rdi, rdi, CHECK_DICTIONARY);
-
   __ JumpIfSmi(rdi, miss);
   // Check that the value is a JavaScript function.
   __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx);
   __ j(not_equal, miss);
 
-  // Patch the receiver with the global proxy if necessary.
-  if (is_global_object) {
-    __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
-    __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
-  }
-
   // Invoke the function.
   ParameterCount actual(argc);
   __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
@@ -1355,56 +1384,18 @@ static void GenerateCallNormal(MacroAssembler* masm, int argc) {
   // rsp[argc * 8]          : argument 1
   // rsp[(argc + 1) * 8]    : argument 0 = receiver
   // -----------------------------------
-  Label miss, global_object, non_global_object;
+  Label miss;
 
   // Get the receiver of the function from the stack.
   __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
 
-  // Check that the receiver isn't a smi.
-  __ JumpIfSmi(rdx, &miss);
+  GenerateDictionaryLoadReceiverCheck(masm, rdx, rax, rbx, &miss);
 
-  // Check that the receiver is a valid JS object.
-  // Because there are so many map checks and type checks, do not
-  // use CmpObjectType, but load map and type into registers.
-  __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
-  __ movb(rax, FieldOperand(rbx, Map::kInstanceTypeOffset));
-  __ cmpb(rax, Immediate(FIRST_JS_OBJECT_TYPE));
-  __ j(below, &miss);
-
-  // If this assert fails, we have to check upper bound too.
-  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
-
-  // Check for access to global object.
-  __ cmpb(rax, Immediate(JS_GLOBAL_OBJECT_TYPE));
-  __ j(equal, &global_object);
-  __ cmpb(rax, Immediate(JS_BUILTINS_OBJECT_TYPE));
-  __ j(not_equal, &non_global_object);
-
-  // Accessing global object: Load and invoke.
-  __ bind(&global_object);
-  // Check that the global object does not require access checks.
-  __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset));
-  __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded));
-  __ j(not_equal, &miss);
-  GenerateNormalHelper(masm, argc, true, &miss);
-
-  // Accessing non-global object: Check for access to global proxy.
-  Label global_proxy, invoke;
-  __ bind(&non_global_object);
-  __ cmpb(rax, Immediate(JS_GLOBAL_PROXY_TYPE));
-  __ j(equal, &global_proxy);
-  // Check that the non-global, non-global-proxy object does not
-  // require access checks.
-  __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset));
-  __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded));
-  __ j(not_equal, &miss);
-  __ bind(&invoke);
-  GenerateNormalHelper(masm, argc, false, &miss);
+  // rax: elements
+  // Search the dictionary placing the result in rdi.
+  GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi);
 
-  // Global object proxy access: Check access rights.
-  __ bind(&global_proxy);
-  __ CheckAccessGlobalProxy(rdx, rax, &miss);
-  __ jmp(&invoke);
+  GenerateFunctionTailCall(masm, argc, &miss);
 
   __ bind(&miss);
 }
@@ -1498,7 +1489,8 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   // Now the key is known to be a smi. This place is also jumped to from below
   // where a numeric string is converted to a smi.
 
-  GenerateKeyedLoadReceiverCheck(masm, rdx, rax, &slow_call);
+  GenerateKeyedLoadReceiverCheck(
+      masm, rdx, rax, Map::kHasIndexedInterceptor, &slow_call);
 
   GenerateFastArrayLoad(
       masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load);
@@ -1508,14 +1500,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   // receiver in rdx is not used after this point.
   // rcx: key
   // rdi: function
-
-  // Check that the value in edi is a JavaScript function.
-  __ JumpIfSmi(rdi, &slow_call);
-  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
-  __ j(not_equal, &slow_call);
-  // Invoke the function.
-  ParameterCount actual(argc);
-  __ InvokeFunction(rdi, actual, JUMP_FUNCTION);
+  GenerateFunctionTailCall(masm, argc, &slow_call);
 
   __ bind(&check_number_dictionary);
   // eax: elements
@@ -1523,6 +1508,7 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   // Check whether the elements is a number dictionary.
   __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
                  Heap::kHashTableMapRootIndex);
+  __ j(not_equal, &slow_load);
   __ SmiToInteger32(rbx, rcx);
   // ebx: untagged index
   GenerateNumberDictionaryLoad(masm, &slow_load, rax, rcx, rbx, r9, rdi, rdi);
@@ -1550,15 +1536,15 @@ void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
   // If the receiver is a regular JS object with slow properties then do
   // a quick inline probe of the receiver's dictionary.
   // Otherwise do the monomorphic cache probe.
-  GenerateKeyedLoadReceiverCheck(masm, rdx, rax, &lookup_monomorphic_cache);
+  GenerateKeyedLoadReceiverCheck(
+      masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
 
   __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
   __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
                  Heap::kHashTableMapRootIndex);
   __ j(not_equal, &lookup_monomorphic_cache);
 
-  GenerateDictionaryLoad(
-      masm, &slow_load, rbx, rdx, rax, rcx, rdi, rdi, DICTIONARY_CHECK_DONE);
+  GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi);
   __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1);
   __ jmp(&do_call);
 
@@ -1620,6 +1606,8 @@ void LoadIC::GenerateMiss(MacroAssembler* masm) {
   //  -- rsp[0] : return address
   // -----------------------------------
 
+  __ IncrementCounter(&Counters::load_miss, 1);
+
   __ pop(rbx);
   __ push(rax);  // receiver
   __ push(rcx);  // name
@@ -1683,38 +1671,15 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
   //  -- rcx    : name
   //  -- rsp[0] : return address
   // -----------------------------------
-  Label miss, probe, global;
-
-  // Check that the receiver isn't a smi.
-  __ JumpIfSmi(rax, &miss);
-
-  // Check that the receiver is a valid JS object.
-  __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx);
-  __ j(below, &miss);
-
-  // If this assert fails, we have to check upper bound too.
-  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+  Label miss;
 
-  // Check for access to global object (unlikely).
-  __ CmpInstanceType(rbx, JS_GLOBAL_PROXY_TYPE);
-  __ j(equal, &global);
-
-  // Check for non-global object that requires access check.
-  __ testl(FieldOperand(rbx, Map::kBitFieldOffset),
-           Immediate(1 << Map::kIsAccessCheckNeeded));
-  __ j(not_zero, &miss);
+  GenerateDictionaryLoadReceiverCheck(masm, rax, rdx, rbx, &miss);
 
+  //  rdx: elements
   // Search the dictionary placing the result in rax.
-  __ bind(&probe);
-  GenerateDictionaryLoad(masm, &miss, rdx, rax, rbx,
-                         rcx, rdi, rax, CHECK_DICTIONARY);
+  GenerateDictionaryLoad(masm, &miss, rdx, rcx, rbx, rdi, rax);
   __ ret(0);
 
-  // Global object access: Check access rights.
-  __ bind(&global);
-  __ CheckAccessGlobalProxy(rax, rdx, &miss);
-  __ jmp(&probe);
-
   // Cache miss: Jump to runtime.
   __ bind(&miss);
   GenerateMiss(masm);