Use Type in CheckPrototypes.
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 22 Nov 2013 15:06:20 +0000 (15:06 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 22 Nov 2013 15:06:20 +0000 (15:06 +0000)
R=ishell@chromium.org

Review URL: https://chromiumcodereview.appspot.com/78023002

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

src/arm/stub-cache-arm.cc
src/ia32/stub-cache-ia32.cc
src/ic-inl.h
src/ic.cc
src/ic.h
src/objects.h
src/stub-cache.cc
src/stub-cache.h
src/x64/stub-cache-x64.cc

index 7e82fd0..831268e 100644 (file)
@@ -1038,9 +1038,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     Label miss_cleanup;
     Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
     Register holder =
-        stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
-                                        scratch1, scratch2, scratch3,
-                                        name, depth1, miss);
+        stub_compiler_->CheckPrototypes(
+            IC::CurrentTypeOf(object, masm->isolate()), receiver,
+            interceptor_holder, scratch1, scratch2, scratch3,
+            name, depth1, miss);
 
     // Invoke an interceptor and if it provides a value,
     // branch to |regular_invoke|.
@@ -1054,10 +1055,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     // Check that the maps from interceptor's holder to constant function's
     // holder haven't changed and thus we can use cached constant function.
     if (*interceptor_holder != lookup->holder()) {
-      stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
-                                      Handle<JSObject>(lookup->holder()),
-                                      scratch1, scratch2, scratch3,
-                                      name, depth2, miss);
+      stub_compiler_->CheckPrototypes(
+          IC::CurrentTypeOf(interceptor_holder, masm->isolate()), receiver,
+          handle(lookup->holder()), scratch1, scratch2, scratch3,
+          name, depth2, miss);
     } else {
       // CheckPrototypes has a side effect of fetching a 'holder'
       // for API (object which is instanceof for the signature).  It's
@@ -1104,9 +1105,9 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                       Handle<JSObject> interceptor_holder,
                       Label* miss_label) {
     Register holder =
-        stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
-                                        scratch1, scratch2, scratch3,
-                                        name, miss_label);
+        stub_compiler_->CheckPrototypes(
+            IC::CurrentTypeOf(object, masm->isolate()), receiver,
+            interceptor_holder, scratch1, scratch2, scratch3, name, miss_label);
 
     // Call a runtime function to load the interceptor property.
     FrameScope scope(masm, StackFrame::INTERNAL);
@@ -1152,26 +1153,6 @@ class CallInterceptorCompiler BASE_EMBEDDED {
 };
 
 
-void StubCompiler::GenerateCheckPropertyCells(MacroAssembler* masm,
-                                              Handle<JSObject> object,
-                                              Handle<JSObject> holder,
-                                              Handle<Name> name,
-                                              Register scratch,
-                                              Label* miss) {
-  Handle<JSObject> current = object;
-  while (!current.is_identical_to(holder)) {
-    if (current->IsJSGlobalObject()) {
-      GenerateCheckPropertyCell(masm,
-                                Handle<JSGlobalObject>::cast(current),
-                                name,
-                                scratch,
-                                miss);
-    }
-    current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
-  }
-}
-
-
 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
   __ Jump(code, RelocInfo::CODE_TARGET);
 }
@@ -1181,7 +1162,7 @@ void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
 #define __ ACCESS_MASM(masm())
 
 
-Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
+Register StubCompiler::CheckPrototypes(Handle<Type> type,
                                        Register object_reg,
                                        Handle<JSObject> holder,
                                        Register holder_reg,
@@ -1191,11 +1172,11 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
                                        int save_at_depth,
                                        Label* miss,
                                        PrototypeCheckType check) {
+  Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
   // Make sure that the type feedback oracle harvests the receiver map.
   // TODO(svenpanne) Remove this hack when all ICs are reworked.
-  __ mov(scratch1, Operand(Handle<Map>(object->map())));
+  __ mov(scratch1, Operand(receiver_map));
 
-  Handle<JSObject> first = object;
   // Make sure there's no overlap between holder and object registers.
   ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
   ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
@@ -1210,25 +1191,31 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
     __ str(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize));
   }
 
-  // Check the maps in the prototype chain.
-  // Traverse the prototype chain from the object and do map checks.
-  Handle<JSObject> current = object;
-  while (!current.is_identical_to(holder)) {
+  Handle<JSObject> current = Handle<JSObject>::null();
+  if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant());
+  Handle<JSObject> prototype = Handle<JSObject>::null();
+  Handle<Map> current_map = receiver_map;
+  Handle<Map> holder_map(holder->map());
+  // Traverse the prototype chain and check the maps in the prototype chain for
+  // fast and global objects or do negative lookup for normal objects.
+  while (!current_map.is_identical_to(holder_map)) {
     ++depth;
 
     // Only global objects and objects that do not require access
     // checks are allowed in stubs.
-    ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
+    ASSERT(current_map->IsJSGlobalProxyMap() ||
+           !current_map->is_access_check_needed());
 
-    Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
-    if (!current->HasFastProperties() &&
-        !current->IsJSGlobalObject() &&
-        !current->IsJSGlobalProxy()) {
+    prototype = handle(JSObject::cast(current_map->prototype()));
+    if (current_map->is_dictionary_map() &&
+        !current_map->IsJSGlobalObjectMap() &&
+        !current_map->IsJSGlobalProxyMap()) {
       if (!name->IsUniqueName()) {
         ASSERT(name->IsString());
         name = factory()->InternalizeString(Handle<String>::cast(name));
       }
-      ASSERT(current->property_dictionary()->FindEntry(*name) ==
+      ASSERT(current.is_null() ||
+             current->property_dictionary()->FindEntry(*name) ==
              NameDictionary::kNotFound);
 
       GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
@@ -1239,8 +1226,7 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
       __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
     } else {
       Register map_reg = scratch1;
-      if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
-        Handle<Map> current_map(current->map());
+      if (depth != 1 || check == CHECK_ALL_MAPS) {
         // CheckMap implicitly loads the map of |reg| into |map_reg|.
         __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK);
       } else {
@@ -1250,9 +1236,14 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
       // Check access rights to the global object.  This has to happen after
       // the map check so that we know that the object is actually a global
       // object.
-      if (current->IsJSGlobalProxy()) {
+      if (current_map->IsJSGlobalProxyMap()) {
         __ CheckAccessGlobalProxy(reg, scratch2, miss);
+      } else if (current_map->IsJSGlobalObjectMap()) {
+        GenerateCheckPropertyCell(
+            masm(), Handle<JSGlobalObject>::cast(current), name,
+            scratch2, miss);
       }
+
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
       if (heap()->InNewSpace(*prototype)) {
@@ -1271,28 +1262,24 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
 
     // Go to the next object in the prototype chain.
     current = prototype;
+    current_map = handle(current->map());
   }
 
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
-  if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+  if (depth != 0 || check == CHECK_ALL_MAPS) {
     // Check the holder map.
-    __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
-                DONT_DO_SMI_CHECK);
+    __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK);
   }
 
   // Perform security check for access to the global object.
-  ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
-  if (holder->IsJSGlobalProxy()) {
+  ASSERT(current_map->IsJSGlobalProxyMap() ||
+         !current_map->is_access_check_needed());
+  if (current_map->IsJSGlobalProxyMap()) {
     __ CheckAccessGlobalProxy(reg, scratch1, miss);
   }
 
-  // If we've skipped any global objects, it's not enough to verify that
-  // their maps haven't changed.  We also need to check that the property
-  // cell for the property is still empty.
-  GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
-
   // Return the register containing the holder.
   return reg;
 }
@@ -1576,7 +1563,8 @@ void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
 
   // Check that the maps haven't changed.
   __ JumpIfSmi(r0, miss);
-  CheckPrototypes(object, r0, holder, r3, r1, r4, name, miss);
+  CheckPrototypes(
+      IC::CurrentTypeOf(object, isolate()), r0, holder, r3, r1, r4, name, miss);
 }
 
 
@@ -1639,7 +1627,9 @@ Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
   __ JumpIfSmi(r0, &miss);
 
   // Do the right check and compute the holder register.
-  Register reg = CheckPrototypes(object, r0, holder, r1, r3, r4, name, &miss);
+  Register reg = CheckPrototypes(
+      IC::CurrentTypeOf(object, isolate()),
+      r0, holder, r1, r3, r4, name, &miss);
   GenerateFastPropertyLoad(masm(), r1, reg, index.is_inobject(holder),
                            index.translate(holder), Representation::Tagged());
 
@@ -1675,8 +1665,9 @@ Handle<Code> CallStubCompiler::CompileArrayCodeCall(
     __ JumpIfSmi(receiver, &miss);
 
     // Check that the maps haven't changed.
-    CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, r3, r0,
-                    r4, name, &miss);
+    CheckPrototypes(
+        IC::CurrentTypeOf(object, isolate()), receiver, holder,
+        r3, r0, r4, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -1736,8 +1727,9 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall(
   __ JumpIfSmi(receiver, &miss);
 
   // Check that the maps haven't changed.
-  CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, r3, r0, r4,
-                  name, &miss);
+  CheckPrototypes(
+      IC::CurrentTypeOf(object, isolate()), receiver, holder,
+      r3, r0, r4, name, &miss);
 
   if (argc == 0) {
     // Nothing to do, just return the length.
@@ -1994,8 +1986,8 @@ Handle<Code> CallStubCompiler::CompileArrayPopCall(
   __ JumpIfSmi(receiver, &miss);
 
   // Check that the maps haven't changed.
-  CheckPrototypes(Handle<JSObject>::cast(object), receiver, holder, elements,
-                  r4, r0, name, &miss);
+  CheckPrototypes(IC::CurrentTypeOf(object, isolate()), receiver, holder,
+                  elements, r4, r0, name, &miss);
 
   // Get the elements array of the object.
   __ ldr(elements, FieldMemOperand(receiver, JSArray::kElementsOffset));
@@ -2084,8 +2076,9 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
                                             r0,
                                             &miss);
   ASSERT(!object.is_identical_to(holder));
+  Handle<JSObject> prototype(JSObject::cast(object->GetPrototype(isolate())));
   CheckPrototypes(
-      Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+      IC::CurrentTypeOf(prototype, isolate()),
       r0, holder, r1, r3, r4, name, &miss);
 
   Register receiver = r1;
@@ -2166,8 +2159,9 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
                                             r0,
                                             &miss);
   ASSERT(!object.is_identical_to(holder));
+  Handle<JSObject> prototype(JSObject::cast(object->GetPrototype(isolate())));
   CheckPrototypes(
-      Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+      IC::CurrentTypeOf(prototype, isolate()),
       r0, holder, r1, r3, r4, name, &miss);
 
   Register receiver = r0;
@@ -2243,8 +2237,9 @@ Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
 
     __ JumpIfSmi(r1, &miss);
 
-    CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
-                    name, &miss);
+    CheckPrototypes(
+        IC::CurrentTypeOf(object, isolate()),
+        r1, holder, r0, r3, r4, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -2313,8 +2308,9 @@ Handle<Code> CallStubCompiler::CompileMathFloorCall(
   if (cell.is_null()) {
     __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
     __ JumpIfSmi(r1, &miss);
-    CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
-                    name, &miss);
+    CheckPrototypes(
+        IC::CurrentTypeOf(object, isolate()),
+        r1, holder, r0, r3, r4, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -2421,8 +2417,9 @@ Handle<Code> CallStubCompiler::CompileMathAbsCall(
   if (cell.is_null()) {
     __ ldr(r1, MemOperand(sp, 1 * kPointerSize));
     __ JumpIfSmi(r1, &miss);
-    CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
-                    name, &miss);
+    CheckPrototypes(
+        IC::CurrentTypeOf(object, isolate()),
+        r1, holder, r0, r3, r4, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -2530,8 +2527,9 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
   ReserveSpaceForFastApiCall(masm(), r0);
 
   // Check that the maps haven't changed and find a Holder as a side effect.
-  CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4, name,
-                  depth, &miss);
+  CheckPrototypes(
+      IC::CurrentTypeOf(object, isolate()),
+      r1, holder, r0, r3, r4, name, depth, &miss);
 
   GenerateFastApiDirectCall(masm(), optimization, argc, false);
 
@@ -2587,8 +2585,9 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       __ IncrementCounter(isolate()->counters()->call_const(), 1, r0, r3);
 
       // Check that the maps haven't changed.
-      CheckPrototypes(Handle<JSObject>::cast(object), r1, holder, r0, r3, r4,
-                      name, &miss);
+      CheckPrototypes(
+          IC::CurrentTypeOf(object, isolate()),
+          r1, holder, r0, r3, r4, name, &miss);
 
       // Patch the receiver on the stack with the global proxy if
       // necessary.
@@ -2598,30 +2597,32 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       }
       break;
 
-    case STRING_CHECK:
+    case STRING_CHECK: {
       // Check that the object is a string.
       __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
       __ b(ge, &miss);
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::STRING_FUNCTION_INDEX, r0, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           r0, holder, r3, r1, r4, name, &miss);
       break;
-
-    case SYMBOL_CHECK:
+    }
+    case SYMBOL_CHECK: {
       // Check that the object is a symbol.
       __ CompareObjectType(r1, r1, r3, SYMBOL_TYPE);
       __ b(ne, &miss);
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::SYMBOL_FUNCTION_INDEX, r0, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           r0, holder, r3, r1, r4, name, &miss);
       break;
-
+    }
     case NUMBER_CHECK: {
       Label fast;
       // Check that the object is a smi or a heap number.
@@ -2632,8 +2633,9 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           r0, holder, r3, r1, r4, name, &miss);
       break;
     }
@@ -2643,8 +2645,9 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           r0, holder, r3, r1, r4, name, &miss);
       break;
     }
index adbef17..58f3708 100644 (file)
@@ -723,9 +723,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     Label miss_cleanup;
     Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
     Register holder =
-        stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
-                                        scratch1, scratch2, scratch3,
-                                        name, depth1, miss);
+        stub_compiler_->CheckPrototypes(
+            IC::CurrentTypeOf(object, masm->isolate()), receiver,
+            interceptor_holder, scratch1, scratch2, scratch3,
+            name, depth1, miss);
 
     // Invoke an interceptor and if it provides a value,
     // branch to |regular_invoke|.
@@ -739,10 +740,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     // Check that the maps from interceptor's holder to constant function's
     // holder haven't changed and thus we can use cached constant function.
     if (*interceptor_holder != lookup->holder()) {
-      stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
-                                      Handle<JSObject>(lookup->holder()),
-                                      scratch1, scratch2, scratch3,
-                                      name, depth2, miss);
+      stub_compiler_->CheckPrototypes(
+          IC::CurrentTypeOf(interceptor_holder, masm->isolate()), receiver,
+          handle(lookup->holder()), scratch1, scratch2, scratch3,
+          name, depth2, miss);
     } else {
       // CheckPrototypes has a side effect of fetching a 'holder'
       // for API (object which is instanceof for the signature).  It's
@@ -788,9 +789,9 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                       Handle<JSObject> interceptor_holder,
                       Label* miss_label) {
     Register holder =
-        stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
-                                        scratch1, scratch2, scratch3,
-                                        name, miss_label);
+        stub_compiler_->CheckPrototypes(
+            IC::CurrentTypeOf(object, masm->isolate()), receiver,
+            interceptor_holder, scratch1, scratch2, scratch3, name, miss_label);
 
     FrameScope scope(masm, StackFrame::INTERNAL);
     // Save the name_ register across the call.
@@ -1184,26 +1185,6 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
 }
 
 
-void StubCompiler::GenerateCheckPropertyCells(MacroAssembler* masm,
-                                              Handle<JSObject> object,
-                                              Handle<JSObject> holder,
-                                              Handle<Name> name,
-                                              Register scratch,
-                                              Label* miss) {
-  Handle<JSObject> current = object;
-  while (!current.is_identical_to(holder)) {
-    if (current->IsJSGlobalObject()) {
-      GenerateCheckPropertyCell(masm,
-                                Handle<JSGlobalObject>::cast(current),
-                                name,
-                                scratch,
-                                miss);
-    }
-    current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
-  }
-}
-
-
 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
   __ jmp(code, RelocInfo::CODE_TARGET);
 }
@@ -1213,7 +1194,7 @@ void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
 #define __ ACCESS_MASM(masm())
 
 
-Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
+Register StubCompiler::CheckPrototypes(Handle<Type> type,
                                        Register object_reg,
                                        Handle<JSObject> holder,
                                        Register holder_reg,
@@ -1223,12 +1204,11 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
                                        int save_at_depth,
                                        Label* miss,
                                        PrototypeCheckType check) {
-  const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1;
+  Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
   // Make sure that the type feedback oracle harvests the receiver map.
   // TODO(svenpanne) Remove this hack when all ICs are reworked.
-  __ mov(scratch1, Handle<Map>(object->map()));
+  __ mov(scratch1, receiver_map);
 
-  Handle<JSObject> first = object;
   // Make sure there's no overlap between holder and object registers.
   ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
   ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
@@ -1236,31 +1216,38 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
 
   // Keep track of the current object in register reg.
   Register reg = object_reg;
-  Handle<JSObject> current = object;
   int depth = 0;
 
+  const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1;
   if (save_at_depth == depth) {
     __ mov(Operand(esp, kHolderIndex * kPointerSize), reg);
   }
 
+  Handle<JSObject> current = Handle<JSObject>::null();
+  if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant());
+  Handle<JSObject> prototype = Handle<JSObject>::null();
+  Handle<Map> current_map = receiver_map;
+  Handle<Map> holder_map(holder->map());
   // Traverse the prototype chain and check the maps in the prototype chain for
   // fast and global objects or do negative lookup for normal objects.
-  while (!current.is_identical_to(holder)) {
+  while (!current_map.is_identical_to(holder_map)) {
     ++depth;
 
     // Only global objects and objects that do not require access
     // checks are allowed in stubs.
-    ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
+    ASSERT(current_map->IsJSGlobalProxyMap() ||
+           !current_map->is_access_check_needed());
 
-    Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
-    if (!current->HasFastProperties() &&
-        !current->IsJSGlobalObject() &&
-        !current->IsJSGlobalProxy()) {
+    prototype = handle(JSObject::cast(current_map->prototype()));
+    if (current_map->is_dictionary_map() &&
+        !current_map->IsJSGlobalObjectMap() &&
+        !current_map->IsJSGlobalProxyMap()) {
       if (!name->IsUniqueName()) {
         ASSERT(name->IsString());
         name = factory()->InternalizeString(Handle<String>::cast(name));
       }
-      ASSERT(current->property_dictionary()->FindEntry(*name) ==
+      ASSERT(current.is_null() ||
+             current->property_dictionary()->FindEntry(*name) ==
              NameDictionary::kNotFound);
 
       GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
@@ -1271,16 +1258,19 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
       __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
     } else {
       bool in_new_space = heap()->InNewSpace(*prototype);
-      Handle<Map> current_map(current->map());
-      if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+      if (depth != 1 || check == CHECK_ALL_MAPS) {
         __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
       }
 
       // Check access rights to the global object.  This has to happen after
       // the map check so that we know that the object is actually a global
       // object.
-      if (current->IsJSGlobalProxy()) {
+      if (current_map->IsJSGlobalProxyMap()) {
         __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
+      } else if (current_map->IsJSGlobalObjectMap()) {
+        GenerateCheckPropertyCell(
+            masm(), Handle<JSGlobalObject>::cast(current), name,
+            scratch2, miss);
       }
 
       if (in_new_space) {
@@ -1306,28 +1296,24 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
 
     // Go to the next object in the prototype chain.
     current = prototype;
+    current_map = handle(current->map());
   }
-  ASSERT(current.is_identical_to(holder));
 
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
-  if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+  if (depth != 0 || check == CHECK_ALL_MAPS) {
     // Check the holder map.
-    __ CheckMap(reg, Handle<Map>(holder->map()), miss, DONT_DO_SMI_CHECK);
+    __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
   }
 
   // Perform security check for access to the global object.
-  ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
-  if (holder->IsJSGlobalProxy()) {
+  ASSERT(current_map->IsJSGlobalProxyMap() ||
+         !current_map->is_access_check_needed());
+  if (current_map->IsJSGlobalProxyMap()) {
     __ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
   }
 
-  // If we've skipped any global objects, it's not enough to verify that
-  // their maps haven't changed.  We also need to check that the property
-  // cell for the property is still empty.
-  GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
-
   // Return the register containing the holder.
   return reg;
 }
@@ -1638,7 +1624,8 @@ void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
 
   // Check that the maps haven't changed.
   __ JumpIfSmi(edx, miss);
-  CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss);
+  CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
+                  ebx, eax, edi, name, miss);
 }
 
 
@@ -1707,8 +1694,8 @@ Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
   __ JumpIfSmi(edx, &miss);
 
   // Do the right check and compute the holder register.
-  Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi,
-                                 name, &miss);
+  Register reg = CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx,
+                                 holder, ebx, eax, edi, name, &miss);
 
   GenerateFastPropertyLoad(
       masm(), edi, reg, index.is_inobject(holder),
@@ -1761,8 +1748,8 @@ Handle<Code> CallStubCompiler::CompileArrayCodeCall(
 
     // Check that the receiver isn't a smi.
     __ JumpIfSmi(edx, &miss);
-    CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
-                    name, &miss);
+    CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
+                    ebx, eax, edi, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -1821,8 +1808,8 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall(
   // Check that the receiver isn't a smi.
   __ JumpIfSmi(edx, &miss);
 
-  CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
-                  name, &miss);
+  CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
+                  ebx, eax, edi, name, &miss);
 
   if (argc == 0) {
     // Noop, return the length.
@@ -2081,8 +2068,8 @@ Handle<Code> CallStubCompiler::CompileArrayPopCall(
 
   // Check that the receiver isn't a smi.
   __ JumpIfSmi(edx, &miss);
-  CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
-                  name, &miss);
+  CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
+                  ebx, eax, edi, name, &miss);
 
   // Get the elements array of the object.
   __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset));
@@ -2175,8 +2162,9 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
                                             eax,
                                             &miss);
   ASSERT(!object.is_identical_to(holder));
+  Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
   CheckPrototypes(
-      Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+      IC::CurrentTypeOf(prototype, isolate()),
       eax, holder, ebx, edx, edi, name, &miss);
 
   Register receiver = ebx;
@@ -2260,8 +2248,9 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
                                             eax,
                                             &miss);
   ASSERT(!object.is_identical_to(holder));
+  Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
   CheckPrototypes(
-      Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+      IC::CurrentTypeOf(prototype, isolate()),
       eax, holder, ebx, edx, edi, name, &miss);
 
   Register receiver = eax;
@@ -2336,8 +2325,8 @@ Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
     __ mov(edx, Operand(esp, 2 * kPointerSize));
     STATIC_ASSERT(kSmiTag == 0);
     __ JumpIfSmi(edx, &miss);
-    CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
-                    name, &miss);
+    CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
+                    ebx, eax, edi, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -2421,8 +2410,8 @@ Handle<Code> CallStubCompiler::CompileMathFloorCall(
     STATIC_ASSERT(kSmiTag == 0);
     __ JumpIfSmi(edx, &miss);
 
-    CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
-                    name, &miss);
+    CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
+                    ebx, eax, edi, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -2547,8 +2536,8 @@ Handle<Code> CallStubCompiler::CompileMathAbsCall(
     STATIC_ASSERT(kSmiTag == 0);
     __ JumpIfSmi(edx, &miss);
 
-    CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
-                    name, &miss);
+    CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
+                    ebx, eax, edi, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -2661,8 +2650,8 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
   __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize));
 
   // Check that the maps haven't changed and find a Holder as a side effect.
-  CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax, edi,
-                  name, depth, &miss);
+  CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
+                  ebx, eax, edi, name, depth, &miss);
 
   // Move the return address on top of the stack.
   __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
@@ -2725,8 +2714,8 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       __ IncrementCounter(isolate()->counters()->call_const(), 1);
 
       // Check that the maps haven't changed.
-      CheckPrototypes(Handle<JSObject>::cast(object), edx, holder, ebx, eax,
-                      edi, name, &miss);
+      CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder,
+                      ebx, eax, edi, name, &miss);
 
       // Patch the receiver on the stack with the global proxy if
       // necessary.
@@ -2736,30 +2725,32 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       }
       break;
 
-    case STRING_CHECK:
+    case STRING_CHECK: {
       // Check that the object is a string.
       __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax);
       __ j(above_equal, &miss);
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           eax, holder, ebx, edx, edi, name, &miss);
       break;
-
-    case SYMBOL_CHECK:
+    }
+    case SYMBOL_CHECK: {
       // Check that the object is a symbol.
       __ CmpObjectType(edx, SYMBOL_TYPE, eax);
       __ j(not_equal, &miss);
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::SYMBOL_FUNCTION_INDEX, eax, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           eax, holder, ebx, edx, edi, name, &miss);
       break;
-
+    }
     case NUMBER_CHECK: {
       Label fast;
       // Check that the object is a smi or a heap number.
@@ -2770,8 +2761,9 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           eax, holder, ebx, edx, edi, name, &miss);
       break;
     }
@@ -2780,8 +2772,9 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           eax, holder, ebx, edx, edi, name, &miss);
       break;
     }
index bd45c3e..1840587 100644 (file)
@@ -149,7 +149,7 @@ Handle<Map> IC::GetCodeCacheHolder(InlineCacheHolderFlag flag,
     }
     return handle(JSObject::cast(constructor->instance_prototype())->map());
   }
-  return type->AsClass();
+  return TypeToMap(type, isolate);
 }
 
 
index 96f1804..5774cf3 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -783,7 +783,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
       : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())),
                          isolate());
 
-  PatchCache(handle(Type::OfCurrently(cache_object), isolate()), name, code);
+  PatchCache(CurrentTypeOf(cache_object, isolate()), name, code);
   TRACE_IC("CallIC", name);
 }
 
@@ -989,7 +989,7 @@ bool IC::UpdatePolymorphicIC(Handle<Type> type,
     // If the receiver type is already in the polymorphic IC, this indicates
     // there was a prototoype chain failure. In that case, just overwrite the
     // handler.
-    } else if (type->Is(current_type)) {
+    } else if (type->IsCurrently(current_type)) {
       ASSERT(handler_to_overwrite == -1);
       number_of_valid_types--;
       handler_to_overwrite = i;
@@ -1015,9 +1015,20 @@ bool IC::UpdatePolymorphicIC(Handle<Type> type,
 }
 
 
+Handle<Type> IC::CurrentTypeOf(Handle<Object> object, Isolate* isolate) {
+  Type* type = object->IsJSGlobalObject()
+      ? Type::Constant(Handle<JSGlobalObject>::cast(object))
+      : Type::OfCurrently(object);
+  return handle(type, isolate);
+}
+
+
 Handle<Map> IC::TypeToMap(Type* type, Isolate* isolate) {
   if (type->Is(Type::Number())) return isolate->factory()->heap_number_map();
   if (type->Is(Type::Boolean())) return isolate->factory()->oddball_map();
+  if (type->IsConstant()) {
+    return handle(Handle<JSGlobalObject>::cast(type->AsConstant())->map());
+  }
   ASSERT(type->IsClass());
   return type->AsClass();
 }
@@ -1148,7 +1159,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
     code = ComputeHandler(lookup, object, name);
   }
 
-  PatchCache(handle(Type::OfCurrently(object), isolate()), name, code);
+  PatchCache(CurrentTypeOf(object, isolate()), name, code);
   TRACE_IC("LoadIC", name);
 }
 
@@ -1609,7 +1620,7 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
 
   Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
 
-  PatchCache(handle(Type::OfCurrently(receiver), isolate()), name, code);
+  PatchCache(CurrentTypeOf(receiver, isolate()), name, code);
   TRACE_IC("StoreIC", name);
 }
 
index 7113b0b..4a3e716 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -165,6 +165,7 @@ class IC {
   // - The oddball map is only used for booleans.
   static Handle<Map> TypeToMap(Type* type, Isolate* isolate);
   static Type* MapToType(Handle<Map> type);
+  static Handle<Type> CurrentTypeOf(Handle<Object> object, Isolate* isolate);
 
  protected:
   // Get the call-site target; used for determining the state.
index 8e2a831..93d35bf 100644 (file)
@@ -6198,6 +6198,16 @@ class Map: public HeapObject {
   bool IsJSObjectMap() {
     return instance_type() >= FIRST_JS_OBJECT_TYPE;
   }
+  bool IsJSGlobalProxyMap() {
+    return instance_type() == JS_GLOBAL_PROXY_TYPE;
+  }
+  bool IsJSGlobalObjectMap() {
+    return instance_type() == JS_GLOBAL_OBJECT_TYPE;
+  }
+  bool IsGlobalObjectMap() {
+    const InstanceType type = instance_type();
+    return type == JS_GLOBAL_OBJECT_TYPE || type == JS_BUILTINS_OBJECT_TYPE;
+  }
 
   // Fires when the layout of an object with a leaf map changes.
   // This includes adding transitions to the leaf map or changing
index 6fdd6d9..756ab27 100644 (file)
@@ -1168,9 +1168,9 @@ Register LoadStubCompiler::HandlerFrontendHeader(
   }
 
   // Check that the maps starting from the prototype haven't changed.
-  return CheckPrototypes(receiver, object_reg, holder,
-                         scratch1(), scratch2(), scratch3(),
-                         name, miss, check_type);
+  return CheckPrototypes(
+      IC::CurrentTypeOf(receiver, isolate()), object_reg, holder,
+      scratch1(), scratch2(), scratch3(), name, miss, check_type);
 }
 
 
@@ -1182,9 +1182,9 @@ Register StoreStubCompiler::HandlerFrontendHeader(
     Handle<JSObject> holder,
     Handle<Name> name,
     Label* miss) {
-  return CheckPrototypes(Handle<JSObject>::cast(object), object_reg, holder,
-                         this->name(), scratch1(), scratch2(),
-                         name, miss, SKIP_RECEIVER);
+  return CheckPrototypes(
+      IC::CurrentTypeOf(object, isolate()), object_reg, holder, this->name(),
+      scratch1(), scratch2(), name, miss, SKIP_RECEIVER);
 }
 
 
index 91f3409..5a80ca5 100644 (file)
@@ -443,15 +443,6 @@ class StubCompiler BASE_EMBEDDED {
                                         Register scratch,
                                         Label* miss);
 
-  // Calls GenerateCheckPropertyCell for each global object in the prototype
-  // chain from object to (but not including) holder.
-  static void GenerateCheckPropertyCells(MacroAssembler* masm,
-                                         Handle<JSObject> object,
-                                         Handle<JSObject> holder,
-                                         Handle<Name> name,
-                                         Register scratch,
-                                         Label* miss);
-
   static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
 
   // Generates code that verifies that the property holder has not changed
@@ -469,7 +460,7 @@ class StubCompiler BASE_EMBEDDED {
   // The function can optionally (when save_at_depth !=
   // kInvalidProtoDepth) save the object at the given depth by moving
   // it to [esp + kPointerSize].
-  Register CheckPrototypes(Handle<JSObject> object,
+  Register CheckPrototypes(Handle<Type> type,
                            Register object_reg,
                            Handle<JSObject> holder,
                            Register holder_reg,
@@ -478,11 +469,11 @@ class StubCompiler BASE_EMBEDDED {
                            Handle<Name> name,
                            Label* miss,
                            PrototypeCheckType check = CHECK_ALL_MAPS) {
-    return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1,
+    return CheckPrototypes(type, object_reg, holder, holder_reg, scratch1,
                            scratch2, name, kInvalidProtoDepth, miss, check);
   }
 
-  Register CheckPrototypes(Handle<JSObject> object,
+  Register CheckPrototypes(Handle<Type> type,
                            Register object_reg,
                            Handle<JSObject> holder,
                            Register holder_reg,
index 963bc12..5a7bd10 100644 (file)
@@ -720,9 +720,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     Label miss_cleanup;
     Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
     Register holder =
-        stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
-                                        scratch1, scratch2, scratch3,
-                                        name, depth1, miss);
+        stub_compiler_->CheckPrototypes(
+            IC::CurrentTypeOf(object, masm->isolate()), receiver,
+            interceptor_holder, scratch1, scratch2, scratch3,
+            name, depth1, miss);
 
     // Invoke an interceptor and if it provides a value,
     // branch to |regular_invoke|.
@@ -736,10 +737,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
     // Check that the maps from interceptor's holder to constant function's
     // holder haven't changed and thus we can use cached constant function.
     if (*interceptor_holder != lookup->holder()) {
-      stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
-                                      Handle<JSObject>(lookup->holder()),
-                                      scratch1, scratch2, scratch3,
-                                      name, depth2, miss);
+      stub_compiler_->CheckPrototypes(
+          IC::CurrentTypeOf(interceptor_holder, masm->isolate()), receiver,
+          handle(lookup->holder()), scratch1, scratch2, scratch3,
+          name, depth2, miss);
     } else {
       // CheckPrototypes has a side effect of fetching a 'holder'
       // for API (object which is instanceof for the signature).  It's
@@ -785,9 +786,9 @@ class CallInterceptorCompiler BASE_EMBEDDED {
                       Handle<JSObject> interceptor_holder,
                       Label* miss_label) {
     Register holder =
-        stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
-                                        scratch1, scratch2, scratch3,
-                                        name, miss_label);
+        stub_compiler_->CheckPrototypes(
+            IC::CurrentTypeOf(object, masm->isolate()), receiver,
+            interceptor_holder, scratch1, scratch2, scratch3, name, miss_label);
 
     FrameScope scope(masm, StackFrame::INTERNAL);
     // Save the name_ register across the call.
@@ -1122,26 +1123,6 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
 }
 
 
-void StubCompiler::GenerateCheckPropertyCells(MacroAssembler* masm,
-                                              Handle<JSObject> object,
-                                              Handle<JSObject> holder,
-                                              Handle<Name> name,
-                                              Register scratch,
-                                              Label* miss) {
-  Handle<JSObject> current = object;
-  while (!current.is_identical_to(holder)) {
-    if (current->IsJSGlobalObject()) {
-      GenerateCheckPropertyCell(masm,
-                                Handle<JSGlobalObject>::cast(current),
-                                name,
-                                scratch,
-                                miss);
-    }
-    current = Handle<JSObject>(JSObject::cast(current->GetPrototype()));
-  }
-}
-
-
 void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
   __ jmp(code, RelocInfo::CODE_TARGET);
 }
@@ -1151,7 +1132,7 @@ void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
 #define __ ACCESS_MASM((masm()))
 
 
-Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
+Register StubCompiler::CheckPrototypes(Handle<Type> type,
                                        Register object_reg,
                                        Handle<JSObject> holder,
                                        Register holder_reg,
@@ -1161,11 +1142,11 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
                                        int save_at_depth,
                                        Label* miss,
                                        PrototypeCheckType check) {
+  Handle<Map> receiver_map(IC::TypeToMap(*type, isolate()));
   // Make sure that the type feedback oracle harvests the receiver map.
   // TODO(svenpanne) Remove this hack when all ICs are reworked.
-  __ Move(scratch1, Handle<Map>(object->map()));
+  __ Move(scratch1, receiver_map);
 
-  Handle<JSObject> first = object;
   // Make sure there's no overlap between holder and object registers.
   ASSERT(!scratch1.is(object_reg) && !scratch1.is(holder_reg));
   ASSERT(!scratch2.is(object_reg) && !scratch2.is(holder_reg)
@@ -1186,25 +1167,31 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
     __ movq(args.GetArgumentOperand(kHolderIndex), object_reg);
   }
 
-  // Check the maps in the prototype chain.
-  // Traverse the prototype chain from the object and do map checks.
-  Handle<JSObject> current = object;
-  while (!current.is_identical_to(holder)) {
+  Handle<JSObject> current = Handle<JSObject>::null();
+  if (type->IsConstant()) current = Handle<JSObject>::cast(type->AsConstant());
+  Handle<JSObject> prototype = Handle<JSObject>::null();
+  Handle<Map> current_map = receiver_map;
+  Handle<Map> holder_map(holder->map());
+  // Traverse the prototype chain and check the maps in the prototype chain for
+  // fast and global objects or do negative lookup for normal objects.
+  while (!current_map.is_identical_to(holder_map)) {
     ++depth;
 
     // Only global objects and objects that do not require access
     // checks are allowed in stubs.
-    ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
+    ASSERT(current_map->IsJSGlobalProxyMap() ||
+           !current_map->is_access_check_needed());
 
-    Handle<JSObject> prototype(JSObject::cast(current->GetPrototype()));
-    if (!current->HasFastProperties() &&
-        !current->IsJSGlobalObject() &&
-        !current->IsJSGlobalProxy()) {
+    prototype = handle(JSObject::cast(current_map->prototype()));
+    if (current_map->is_dictionary_map() &&
+        !current_map->IsJSGlobalObjectMap() &&
+        !current_map->IsJSGlobalProxyMap()) {
       if (!name->IsUniqueName()) {
         ASSERT(name->IsString());
         name = factory()->InternalizeString(Handle<String>::cast(name));
       }
-      ASSERT(current->property_dictionary()->FindEntry(*name) ==
+      ASSERT(current.is_null() ||
+             current->property_dictionary()->FindEntry(*name) ==
              NameDictionary::kNotFound);
 
       GenerateDictionaryNegativeLookup(masm(), miss, reg, name,
@@ -1215,20 +1202,23 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
       __ movq(reg, FieldOperand(scratch1, Map::kPrototypeOffset));
     } else {
       bool in_new_space = heap()->InNewSpace(*prototype);
-      Handle<Map> current_map(current->map());
       if (in_new_space) {
         // Save the map in scratch1 for later.
         __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
       }
-      if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+      if (depth != 1 || check == CHECK_ALL_MAPS) {
         __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
       }
 
       // Check access rights to the global object.  This has to happen after
       // the map check so that we know that the object is actually a global
       // object.
-      if (current->IsJSGlobalProxy()) {
+      if (current_map->IsJSGlobalProxyMap()) {
         __ CheckAccessGlobalProxy(reg, scratch2, miss);
+      } else if (current_map->IsJSGlobalObjectMap()) {
+        GenerateCheckPropertyCell(
+            masm(), Handle<JSGlobalObject>::cast(current), name,
+            scratch2, miss);
       }
       reg = holder_reg;  // From now on the object will be in holder_reg.
 
@@ -1248,28 +1238,24 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
 
     // Go to the next object in the prototype chain.
     current = prototype;
+    current_map = handle(current->map());
   }
-  ASSERT(current.is_identical_to(holder));
 
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
-  if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+  if (depth != 0 || check == CHECK_ALL_MAPS) {
     // Check the holder map.
-    __ CheckMap(reg, Handle<Map>(holder->map()), miss, DONT_DO_SMI_CHECK);
+    __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK);
   }
 
   // Perform security check for access to the global object.
-  ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
-  if (current->IsJSGlobalProxy()) {
+  ASSERT(current_map->IsJSGlobalProxyMap() ||
+         !current_map->is_access_check_needed());
+  if (current_map->IsJSGlobalProxyMap()) {
     __ CheckAccessGlobalProxy(reg, scratch1, miss);
   }
 
-  // If we've skipped any global objects, it's not enough to verify that
-  // their maps haven't changed.  We also need to check that the property
-  // cell for the property is still empty.
-  GenerateCheckPropertyCells(masm(), object, holder, name, scratch1, miss);
-
   // Return the register containing the holder.
   return reg;
 }
@@ -1575,7 +1561,8 @@ void CallStubCompiler::GenerateGlobalReceiverCheck(Handle<JSObject> object,
 
   // Check that the maps haven't changed.
   __ JumpIfSmi(rdx, miss);
-  CheckPrototypes(object, rdx, holder, rbx, rax, rdi, name, miss);
+  CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
+                  rbx, rax, rdi, name, miss);
 }
 
 
@@ -1641,8 +1628,8 @@ Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
   __ JumpIfSmi(rdx, &miss);
 
   // Do the right check and compute the holder register.
-  Register reg = CheckPrototypes(object, rdx, holder, rbx, rax, rdi,
-                                 name, &miss);
+  Register reg = CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx,
+                                 holder, rbx, rax, rdi, name, &miss);
 
   GenerateFastPropertyLoad(masm(), rdi, reg, index.is_inobject(holder),
                            index.translate(holder), Representation::Tagged());
@@ -1694,8 +1681,8 @@ Handle<Code> CallStubCompiler::CompileArrayCodeCall(
 
     // Check that the receiver isn't a smi.
     __ JumpIfSmi(rdx, &miss);
-    CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
-                    name, &miss);
+    CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
+                    rbx, rax, rdi, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -1753,8 +1740,8 @@ Handle<Code> CallStubCompiler::CompileArrayPushCall(
   // Check that the receiver isn't a smi.
   __ JumpIfSmi(rdx, &miss);
 
-  CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
-                  name, &miss);
+  CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
+                  rbx, rax, rdi, name, &miss);
 
   if (argc == 0) {
     // Noop, return the length.
@@ -2008,8 +1995,8 @@ Handle<Code> CallStubCompiler::CompileArrayPopCall(
   // Check that the receiver isn't a smi.
   __ JumpIfSmi(rdx, &miss);
 
-  CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
-                  name, &miss);
+  CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
+                  rbx, rax, rdi, name, &miss);
 
   // Get the elements array of the object.
   __ movq(rbx, FieldOperand(rdx, JSArray::kElementsOffset));
@@ -2100,8 +2087,9 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall(
                                             rax,
                                             &miss);
   ASSERT(!object.is_identical_to(holder));
+  Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
   CheckPrototypes(
-      Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+      IC::CurrentTypeOf(prototype, isolate()),
       rax, holder, rbx, rdx, rdi, name, &miss);
 
   Register receiver = rbx;
@@ -2182,8 +2170,9 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall(
                                             rax,
                                             &miss);
   ASSERT(!object.is_identical_to(holder));
+  Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
   CheckPrototypes(
-      Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+      IC::CurrentTypeOf(prototype, isolate()),
       rax, holder, rbx, rdx, rdi, name, &miss);
 
   Register receiver = rax;
@@ -2254,8 +2243,8 @@ Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall(
   if (cell.is_null()) {
     __ movq(rdx, args.GetReceiverOperand());
     __ JumpIfSmi(rdx, &miss);
-    CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
-                    name, &miss);
+    CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
+                    rbx, rax, rdi, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -2332,8 +2321,8 @@ Handle<Code> CallStubCompiler::CompileMathFloorCall(
     STATIC_ASSERT(kSmiTag == 0);
     __ JumpIfSmi(rdx, &miss);
 
-    CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
-                    name, &miss);
+    CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
+                    rbx, rax, rdi, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -2455,8 +2444,8 @@ Handle<Code> CallStubCompiler::CompileMathAbsCall(
   if (cell.is_null()) {
     __ movq(rdx, args.GetReceiverOperand());
     __ JumpIfSmi(rdx, &miss);
-    CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
-                    name, &miss);
+    CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
+                    rbx, rax, rdi, name, &miss);
   } else {
     ASSERT(cell->value() == *function);
     GenerateGlobalReceiverCheck(Handle<JSObject>::cast(object), holder, name,
@@ -2569,8 +2558,8 @@ Handle<Code> CallStubCompiler::CompileFastApiCall(
   __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
 
   // Check that the maps haven't changed and find a Holder as a side effect.
-  CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax, rdi,
-                  name, depth, &miss);
+  CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
+                  rbx, rax, rdi, name, depth, &miss);
 
   // Move the return address on top of the stack.
   __ movq(rax,
@@ -2635,8 +2624,8 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       __ IncrementCounter(counters->call_const(), 1);
 
       // Check that the maps haven't changed.
-      CheckPrototypes(Handle<JSObject>::cast(object), rdx, holder, rbx, rax,
-                      rdi, name, &miss);
+      CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder,
+                      rbx, rax, rdi, name, &miss);
 
       // Patch the receiver on the stack with the global proxy if
       // necessary.
@@ -2646,30 +2635,32 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       }
       break;
 
-    case STRING_CHECK:
+    case STRING_CHECK: {
       // Check that the object is a string.
       __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
       __ j(above_equal, &miss);
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           rax, holder, rbx, rdx, rdi, name, &miss);
       break;
-
-    case SYMBOL_CHECK:
+    }
+    case SYMBOL_CHECK: {
       // Check that the object is a symbol.
       __ CmpObjectType(rdx, SYMBOL_TYPE, rax);
       __ j(not_equal, &miss);
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::SYMBOL_FUNCTION_INDEX, rax, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           rax, holder, rbx, rdx, rdi, name, &miss);
       break;
-
+    }
     case NUMBER_CHECK: {
       Label fast;
       // Check that the object is a smi or a heap number.
@@ -2680,8 +2671,9 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           rax, holder, rbx, rdx, rdi, name, &miss);
       break;
     }
@@ -2690,8 +2682,9 @@ void CallStubCompiler::CompileHandlerFrontend(Handle<Object> object,
       // Check that the maps starting from the prototype haven't changed.
       GenerateDirectLoadGlobalFunctionPrototype(
           masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
+      Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
       CheckPrototypes(
-          Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate()))),
+          IC::CurrentTypeOf(prototype, isolate()),
           rax, holder, rbx, rdx, rdi, name, &miss);
       break;
     }