Polymorphism support for load IC.
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 4 Mar 2013 14:03:27 +0000 (14:03 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 4 Mar 2013 14:03:27 +0000 (14:03 +0000)
Review URL: https://chromiumcodereview.appspot.com/12340112

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

26 files changed:
src/arm/code-stubs-arm.cc
src/arm/ic-arm.cc
src/arm/stub-cache-arm.cc
src/builtins.h
src/code-stubs.cc
src/code-stubs.h
src/ia32/code-stubs-ia32.cc
src/ia32/ic-ia32.cc
src/ia32/stub-cache-ia32.cc
src/ic.cc
src/ic.h
src/log.h
src/mips/stub-cache-mips.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/property.h
src/stub-cache.cc
src/stub-cache.h
src/type-info.cc
src/type-info.h
src/utils.h
src/x64/code-stubs-x64.cc
src/x64/ic-x64.cc
src/x64/stub-cache-x64.cc
test/cctest/test-heap.cc

index e016a8c92e34f88fd9e1614486e0f46f57ea3d67..fa8e57b1295b14a3fec62343038fb75410d6084c 100644 (file)
@@ -4698,6 +4698,12 @@ Register InstanceofStub::left() { return r0; }
 Register InstanceofStub::right() { return r1; }
 
 
+void LoadFieldStub::Generate(MacroAssembler* masm) {
+  StubCompiler::DoGenerateFastPropertyLoad(masm, r0, reg_, inobject_, index_);
+  __ Ret();
+}
+
+
 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   // The displacement is the offset of the last parameter (if any)
   // relative to the frame pointer.
index 9c41e734ab9caba36bd7a3bf8103edc88459678b..e8d0fab026b7979c9a09ee7c473069350424ca71 100644 (file)
@@ -656,8 +656,8 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
   // -----------------------------------
 
   // Probe the stub cache.
-  Code::Flags flags =
-      Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
+  Code::Flags flags = Code::ComputeFlags(
+      Code::LOAD_IC, MONOMORPHIC, Code::HANDLER_FRAGMENT);
   Isolate::Current()->stub_cache()->GenerateProbe(
       masm, flags, r0, r2, r3, r4, r5, r6);
 
index 98d05ac5e91f1f3e6caec67e2e4f508ca758ab6b..03aa359903b418de2e4e831d6856bb4a4f8bd2b7 100644 (file)
@@ -328,23 +328,24 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
                                             Register src,
                                             Handle<JSObject> holder,
                                             PropertyIndex index) {
-  if (index.is_header_index()) {
-    int offset = index.header_index() * kPointerSize;
-    __ ldr(dst, FieldMemOperand(src, offset));
-  } else {
-    // Adjust for the number of properties stored in the holder.
-    int slot = index.field_index() - holder->map()->inobject_properties();
-    if (slot < 0) {
-      // Get the property straight out of the holder.
-      int offset = holder->map()->instance_size() + (slot * kPointerSize);
-      __ ldr(dst, FieldMemOperand(src, offset));
-    } else {
-      // Calculate the offset into the properties array.
-      int offset = slot * kPointerSize + FixedArray::kHeaderSize;
-      __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
-      __ ldr(dst, FieldMemOperand(dst, offset));
-    }
+  DoGenerateFastPropertyLoad(
+      masm, dst, src, index.is_inobject(holder), index.translate(holder));
+}
+
+
+void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
+                                              Register dst,
+                                              Register src,
+                                              bool inobject,
+                                              int index) {
+  int offset = index * kPointerSize;
+  if (!inobject) {
+    // Calculate the offset into the properties array.
+    offset = offset + FixedArray::kHeaderSize;
+    __ ldr(dst, FieldMemOperand(src, JSObject::kPropertiesOffset));
+    src = dst;
   }
+  __ ldr(dst, FieldMemOperand(src, offset));
 }
 
 
@@ -1066,6 +1067,11 @@ static void StoreIntAsFloat(MacroAssembler* masm,
 #define __ ACCESS_MASM(masm())
 
 
+void StubCompiler::GenerateTailCall(Handle<Code> code) {
+  __ Jump(code, RelocInfo::CODE_TARGET);
+}
+
+
 Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
                                        Register object_reg,
                                        Handle<JSObject> holder,
@@ -1074,7 +1080,9 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
                                        Register scratch2,
                                        Handle<String> name,
                                        int save_at_depth,
-                                       Label* miss) {
+                                       Label* miss,
+                                       PrototypeCheckType check) {
+  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)
@@ -1115,9 +1123,15 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
       reg = holder_reg;  // From now on the object will be in holder_reg.
       __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
     } else {
-      Handle<Map> current_map(current->map());
-      __ CheckMap(reg, scratch1, current_map, miss, DONT_DO_SMI_CHECK,
-                  ALLOW_ELEMENT_TRANSITION_MAPS);
+      Register map_reg = scratch1;
+      if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+        Handle<Map> current_map(current->map());
+        // CheckMap implicitly loads the map of |reg| into |map_reg|.
+        __ CheckMap(reg, map_reg, current_map, miss, DONT_DO_SMI_CHECK,
+                    ALLOW_ELEMENT_TRANSITION_MAPS);
+      } else {
+        __ ldr(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset));
+      }
 
       // 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
@@ -1130,7 +1144,7 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
       if (heap()->InNewSpace(*prototype)) {
         // The prototype is in new space; we cannot store a reference to it
         // in the code.  Load it from the map.
-        __ ldr(reg, FieldMemOperand(scratch1, Map::kPrototypeOffset));
+        __ ldr(reg, FieldMemOperand(map_reg, Map::kPrototypeOffset));
       } else {
         // The prototype is in old space; load it directly.
         __ mov(reg, Operand(prototype));
@@ -1148,9 +1162,11 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
   // Log the check depth.
   LOG(masm()->isolate(), IntEvent("check-maps-depth", depth + 1));
 
-  // Check the holder map.
-  __ CheckMap(reg, scratch1, Handle<Map>(current->map()), miss,
-              DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+  if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+    // Check the holder map.
+    __ CheckMap(reg, scratch1, Handle<Map>(holder->map()), miss,
+                DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+  }
 
   // Perform security check for access to the global object.
   ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
@@ -1170,9 +1186,11 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
 
 void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
                                                  Label* miss) {
-  __ b(success);
-  __ bind(miss);
-  GenerateLoadMiss(masm(), kind());
+  if (!miss->is_unused()) {
+    __ b(success);
+    __ bind(miss);
+    GenerateLoadMiss(masm(), kind());
+  }
 }
 
 
@@ -1182,12 +1200,10 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
     Handle<JSObject> holder,
     Handle<String> name,
     Label* success,
-    FrontendCheckType check,
     Handle<ExecutableAccessorInfo> callback) {
   Label miss;
 
-  Register reg = HandlerFrontendHeader(
-      object, object_reg, holder, name, &miss, check);
+  Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
 
   if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
     ASSERT(!reg.is(scratch2()));
@@ -1233,8 +1249,7 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend(
     Handle<GlobalObject> global) {
   Label miss;
 
-  Register reg = HandlerFrontendHeader(
-      object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS);
+  Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
 
   // If the last object in the prototype chain is a global object,
   // check that the global property cell is empty.
@@ -2862,7 +2877,7 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
   __ Ret();
 
   // Return the generated code.
-  return GetCode(Code::NONEXISTENT, factory()->empty_string());
+  return GetCode(Code::HANDLER_FRAGMENT, Code::NONEXISTENT, name);
 }
 
 
@@ -2933,8 +2948,10 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
     bool is_dont_delete) {
   Label success, miss;
 
-  HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global),
-                        name, &miss, PERFORM_INITIAL_CHECKS);
+  __ CheckMap(
+      receiver(), scratch1(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
+  HandlerFrontendHeader(
+      object, receiver(), Handle<JSObject>::cast(global), name, &miss);
 
   // Get the value from the cell.
   __ mov(r3, Operand(cell));
@@ -2956,7 +2973,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
   __ Ret();
 
   // Return the generated code.
-  return GetCode(Code::NORMAL, name);
+  return GetCode(Code::IC_FRAGMENT, Code::NORMAL, name);
 }
 
 
@@ -2984,35 +3001,40 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
   __ Jump(ic, RelocInfo::CODE_TARGET);
 
   // Return the generated code.
-  return GetCode(Code::NORMAL, factory()->empty_string());
+  return GetCode(Code::IC_FRAGMENT, Code::NORMAL, factory()->empty_string());
 }
 
 
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
     MapHandleList* receiver_maps,
-    CodeHandleList* handler_ics) {
-  // ----------- S t a t e -------------
-  //  -- lr    : return address
-  //  -- r0    : key
-  //  -- r1    : receiver
-  // -----------------------------------
+    CodeHandleList* handlers,
+    Handle<String> name,
+    Code::StubType type,
+    IcCheckType check) {
   Label miss;
-  __ JumpIfSmi(r1, &miss);
+
+  if (check == PROPERTY) {
+    GenerateNameCheck(name, this->name(), &miss);
+  }
+
+  __ JumpIfSmi(receiver(), &miss);
+  Register map_reg = scratch1();
 
   int receiver_count = receiver_maps->length();
-  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldr(map_reg, FieldMemOperand(receiver(), HeapObject::kMapOffset));
   for (int current = 0; current < receiver_count; ++current) {
     __ mov(ip, Operand(receiver_maps->at(current)));
-    __ cmp(r2, ip);
-    __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET, eq);
+    __ cmp(map_reg, ip);
+    __ Jump(handlers->at(current), RelocInfo::CODE_TARGET, eq);
   }
 
   __ bind(&miss);
-  Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
-  __ Jump(miss_ic, RelocInfo::CODE_TARGET, al);
+  GenerateLoadMiss(masm(), kind());
 
   // Return the generated code.
-  return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
+  InlineCacheState state =
+      receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
+  return GetCode(Code::IC_FRAGMENT, type, name, state);
 }
 
 
index 83b134c6d2e251cf6456a535989b625dcd67b30a..15abeb1a74f14c0e047c6f7813a9bbd75e2ad995 100644 (file)
@@ -133,7 +133,7 @@ enum BuiltinExtraArguments {
   V(LoadIC_PreMonomorphic,          LOAD_IC, PREMONOMORPHIC,            \
                                     Code::kNoExtraICState)              \
   V(LoadIC_Normal,                  LOAD_IC, MONOMORPHIC,               \
-                                    Code::kNoExtraICState)              \
+                                    Code::IC_FRAGMENT)                  \
   V(LoadIC_Megamorphic,             LOAD_IC, MEGAMORPHIC,               \
                                     Code::kNoExtraICState)              \
   V(LoadIC_Getter_ForDeopt,         LOAD_IC, MONOMORPHIC,               \
index 34d204a054b384a86a6553af4a4a1bc9258f55c4..4a401cdff150191864817cbed34cae8b28348e37 100644 (file)
@@ -98,7 +98,10 @@ Handle<Code> PlatformCodeStub::GenerateCode() {
 
   // Copy the generated code into a heap object.
   Code::Flags flags = Code::ComputeFlags(
-      static_cast<Code::Kind>(GetCodeKind()), GetICState(), GetExtraICState());
+      static_cast<Code::Kind>(GetCodeKind()),
+      GetICState(),
+      GetExtraICState(),
+      GetStubType());
   Handle<Code> new_object = factory->NewCode(
       desc, flags, masm.CodeObject(), NeedsImmovableCode());
   return new_object;
index 0cb3d423f3740ce66cf767c0d50a4a0bb68a8f9c..f7a4eaaf4aa3234b5b517fb9bea79b6b6db57290 100644 (file)
@@ -83,7 +83,9 @@ namespace internal {
   V(TransitionElementsKind)              \
   V(StoreArrayLiteralElement)            \
   V(StubFailureTrampoline)               \
-  V(ProfileEntryHook)
+  V(ProfileEntryHook)                    \
+  /* IC Handler stubs */                 \
+  V(LoadField)
 
 // List of code stubs only used on ARM platforms.
 #ifdef V8_TARGET_ARCH_ARM
@@ -188,6 +190,9 @@ class CodeStub BASE_EMBEDDED {
   virtual Code::ExtraICState GetExtraICState() {
     return Code::kNoExtraICState;
   }
+  virtual Code::StubType GetStubType() {
+    return Code::NORMAL;
+  }
 
   // Returns whether the code generated for this stub needs to be allocated as
   // a fixed (non-moveable) code object.
@@ -611,6 +616,7 @@ class StringLengthStub: public ICStub {
   virtual void Generate(MacroAssembler* masm);
 
  private:
+  STATIC_ASSERT(KindBits::kSize == 4);
   class WrapperModeBits: public BitField<bool, 4, 1> {};
   virtual CodeStub::Major MajorKey() { return StringLength; }
   virtual int MinorKey() {
@@ -632,6 +638,7 @@ class StoreICStub: public ICStub {
   }
 
  private:
+  STATIC_ASSERT(KindBits::kSize == 4);
   class StrictModeBits: public BitField<bool, 4, 1> {};
   virtual int MinorKey() {
     return KindBits::encode(kind()) | StrictModeBits::encode(strict_mode_);
@@ -652,6 +659,48 @@ class StoreArrayLengthStub: public StoreICStub {
 };
 
 
+class HandlerStub: public ICStub {
+ public:
+  explicit HandlerStub(Code::Kind kind) : ICStub(kind) { }
+
+ protected:
+  virtual Code::ExtraICState GetExtraICState() {
+    return Code::HANDLER_FRAGMENT;
+  }
+};
+
+
+class LoadFieldStub: public HandlerStub {
+ public:
+  LoadFieldStub(Register reg, bool inobject, int index)
+      : HandlerStub(Code::LOAD_IC),
+        reg_(reg),
+        inobject_(inobject),
+        index_(index) { }
+  virtual void Generate(MacroAssembler* masm);
+
+ protected:
+  virtual Code::StubType GetStubType() { return Code::FIELD; }
+
+ private:
+  STATIC_ASSERT(KindBits::kSize == 4);
+  class RegisterBits: public BitField<int, 4, 6> {};
+  class InobjectBits: public BitField<bool, 10, 1> {};
+  class IndexBits: public BitField<int, 11, 11> {};
+  virtual CodeStub::Major MajorKey() { return LoadField; }
+  virtual int MinorKey() {
+    return KindBits::encode(kind())
+        | RegisterBits::encode(reg_.code())
+        | InobjectBits::encode(inobject_)
+        | IndexBits::encode(index_);
+  }
+
+  Register reg_;
+  bool inobject_;
+  int index_;
+};
+
+
 class BinaryOpStub: public PlatformCodeStub {
  public:
   BinaryOpStub(Token::Value op, OverwriteMode mode)
index a2237e7a4f682837bfc6ec6e07d3f4513b3912c3..1329a3ef279aaa9268323ebd28df21004aa941d8 100644 (file)
@@ -3408,6 +3408,12 @@ void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
 }
 
 
+void LoadFieldStub::Generate(MacroAssembler* masm) {
+  StubCompiler::DoGenerateFastPropertyLoad(masm, eax, reg_, inobject_, index_);
+  __ ret(0);
+}
+
+
 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   // The key is in edx and the parameter count is in eax.
 
index 0829961ed930c243388eb913633513144d51c058..428d8307027d2fe4f1318c63142b76d3af9f35f6 100644 (file)
@@ -1295,9 +1295,10 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
   // -----------------------------------
 
   // Probe the stub cache.
-  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
-  Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
-                                                  eax);
+  Code::Flags flags = Code::ComputeFlags(
+      Code::LOAD_IC, MONOMORPHIC, Code::HANDLER_FRAGMENT);
+  Isolate::Current()->stub_cache()->GenerateProbe(
+      masm, flags, edx, ecx, ebx, eax);
 
   // Cache miss: Jump to runtime.
   GenerateMiss(masm);
index 0b9befe04f274b576779e32fe91cf21046585c38..34ce36ddd963d00fcdebf0346de7d7ccbcda5815 100644 (file)
@@ -377,23 +377,24 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
                                             Register src,
                                             Handle<JSObject> holder,
                                             PropertyIndex index) {
-  if (index.is_header_index()) {
-    int offset = index.header_index() * kPointerSize;
-    __ mov(dst, FieldOperand(src, offset));
-  } else {
-    // Adjust for the number of properties stored in the holder.
-    int slot = index.field_index() - holder->map()->inobject_properties();
-    if (slot < 0) {
-      // Get the property straight out of the holder.
-      int offset = holder->map()->instance_size() + (slot * kPointerSize);
-      __ mov(dst, FieldOperand(src, offset));
-    } else {
-      // Calculate the offset into the properties array.
-      int offset = slot * kPointerSize + FixedArray::kHeaderSize;
-      __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
-      __ mov(dst, FieldOperand(dst, offset));
-    }
+  DoGenerateFastPropertyLoad(
+      masm, dst, src, index.is_inobject(holder), index.translate(holder));
+}
+
+
+void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
+                                              Register dst,
+                                              Register src,
+                                              bool inobject,
+                                              int index) {
+  int offset = index * kPointerSize;
+  if (!inobject) {
+    // Calculate the offset into the properties array.
+    offset = offset + FixedArray::kHeaderSize;
+    __ mov(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+    src = dst;
   }
+  __ mov(dst, FieldOperand(src, offset));
 }
 
 
@@ -936,6 +937,11 @@ static void GenerateCheckPropertyCells(MacroAssembler* masm,
 #define __ ACCESS_MASM(masm())
 
 
+void StubCompiler::GenerateTailCall(Handle<Code> code) {
+  __ jmp(code, RelocInfo::CODE_TARGET);
+}
+
+
 Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
                                        Register object_reg,
                                        Handle<JSObject> holder,
@@ -944,7 +950,9 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
                                        Register scratch2,
                                        Handle<String> name,
                                        int save_at_depth,
-                                       Label* miss) {
+                                       Label* miss,
+                                       PrototypeCheckType check) {
+  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)
@@ -991,8 +999,10 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
         // Save the map in scratch1 for later.
         __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
       }
-      __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
-                  ALLOW_ELEMENT_TRANSITION_MAPS);
+      if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+        __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
+                    ALLOW_ELEMENT_TRANSITION_MAPS);
+      }
 
       // 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
@@ -1024,9 +1034,11 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
-  // Check the holder map.
-  __ CheckMap(reg, Handle<Map>(holder->map()),
-              miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+  if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+    // Check the holder map.
+    __ CheckMap(reg, Handle<Map>(holder->map()),
+                miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+  }
 
   // Perform security check for access to the global object.
   ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
@@ -1046,9 +1058,11 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
 
 void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
                                                  Label* miss) {
-  __ jmp(success);
-  __ bind(miss);
-  GenerateLoadMiss(masm(), kind());
+  if (!miss->is_unused()) {
+    __ jmp(success);
+    __ bind(miss);
+    GenerateLoadMiss(masm(), kind());
+  }
 }
 
 
@@ -1058,12 +1072,10 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
     Handle<JSObject> holder,
     Handle<String> name,
     Label* success,
-    FrontendCheckType check,
     Handle<ExecutableAccessorInfo> callback) {
   Label miss;
 
-  Register reg = HandlerFrontendHeader(
-      object, object_reg, holder, name, &miss, check);
+  Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
 
   if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
     ASSERT(!reg.is(scratch2()));
@@ -1122,8 +1134,7 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend(
     Handle<GlobalObject> global) {
   Label miss;
 
-  Register reg = HandlerFrontendHeader(
-      object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS);
+  Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
 
   // If the last object in the prototype chain is a global object,
   // check that the global property cell is empty.
@@ -1162,7 +1173,7 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   __ mov(scratch2(), esp);
   ASSERT(!scratch2().is(reg));
   __ push(reg);  // holder
-  // Push data from AccessorInfo.
+  // Push data from ExecutableAccessorInfo.
   if (isolate()->heap()->InNewSpace(callback->data())) {
     __ mov(scratch1(), Immediate(callback));
     __ push(FieldOperand(scratch1(), ExecutableAccessorInfo::kDataOffset));
@@ -1171,8 +1182,8 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   }
   __ push(Immediate(reinterpret_cast<int>(isolate())));
 
-  // Save a pointer to where we pushed the arguments pointer.
-  // This will be passed as the const AccessorInfo& to the C++ callback.
+  // Save a pointer to where we pushed the arguments pointer.  This will be
+  // passed as the const ExecutableAccessorInfo& to the C++ callback.
   __ push(scratch2());
 
   __ push(name());  // name
@@ -2933,7 +2944,7 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
   __ ret(0);
 
   // Return the generated code.
-  return GetCode(Code::NONEXISTENT, factory()->empty_string());
+  return GetCode(Code::HANDLER_FRAGMENT, Code::NONEXISTENT, name);
 }
 
 
@@ -3004,8 +3015,9 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
     bool is_dont_delete) {
   Label success, miss;
 
-  HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global),
-                        name, &miss, PERFORM_INITIAL_CHECKS);
+  __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
+  HandlerFrontendHeader(
+      object, receiver(), Handle<JSObject>::cast(global), name, &miss);
   // Get the value from the cell.
   if (Serializer::enabled()) {
     __ mov(eax, Immediate(cell));
@@ -3032,7 +3044,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
   __ ret(0);
 
   // Return the generated code.
-  return GetCode(Code::NORMAL, name);
+  return GetCode(Code::IC_FRAGMENT, Code::NORMAL, name);
 }
 
 
@@ -3060,34 +3072,38 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
 
   // Return the generated code.
-  return GetCode(Code::NORMAL, factory()->empty_string());
+  return GetCode(Code::IC_FRAGMENT, Code::NORMAL, factory()->empty_string());
 }
 
 
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
     MapHandleList* receiver_maps,
-    CodeHandleList* handler_ics) {
-  // ----------- S t a t e -------------
-  //  -- ecx    : key
-  //  -- edx    : receiver
-  //  -- esp[0] : return address
-  // -----------------------------------
+    CodeHandleList* handlers,
+    Handle<String> name,
+    Code::StubType type,
+    IcCheckType check) {
   Label miss;
-  __ JumpIfSmi(edx, &miss);
 
-  Register map_reg = ebx;
-  __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
+  if (check == PROPERTY) {
+    GenerateNameCheck(name, this->name(), &miss);
+  }
+
+  __ JumpIfSmi(receiver(), &miss);
+  Register map_reg = scratch1();
+  __ mov(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
   int receiver_count = receiver_maps->length();
   for (int current = 0; current < receiver_count; ++current) {
     __ cmp(map_reg, receiver_maps->at(current));
-    __ j(equal, handler_ics->at(current));
+    __ j(equal, handlers->at(current));
   }
 
   __ bind(&miss);
-  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+  GenerateLoadMiss(masm(), kind());
 
   // Return the generated code.
-  return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
+  InlineCacheState state =
+      receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
+  return GetCode(Code::IC_FRAGMENT, type, name, state);
 }
 
 
index b330038c704a50d8e744835ab8394cc3ba030615..7fdf6be31fbe5f36f53a22182371963d5e212be1 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -935,6 +935,71 @@ MaybeObject* LoadIC::Load(State state,
 }
 
 
+static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
+                                       Handle<Map> new_receiver_map) {
+  ASSERT(!new_receiver_map.is_null());
+  for (int current = 0; current < receiver_maps->length(); ++current) {
+    if (!receiver_maps->at(current).is_null() &&
+        receiver_maps->at(current).is_identical_to(new_receiver_map)) {
+      return false;
+    }
+  }
+  receiver_maps->Add(new_receiver_map);
+  return true;
+}
+
+
+bool IC::UpdatePolymorphicIC(State state,
+                             StrictModeFlag strict_mode,
+                             Handle<JSObject> receiver,
+                             Handle<String> name,
+                             Handle<Code> code) {
+  if (code->type() == Code::NORMAL) return false;
+  if (target()->ic_state() == MONOMORPHIC &&
+      target()->type() == Code::NORMAL) {
+    return false;
+  }
+  MapHandleList receiver_maps;
+  CodeHandleList handlers;
+  target()->FindAllMaps(&receiver_maps);
+  int number_of_maps = receiver_maps.length();
+  if (number_of_maps == 0 || number_of_maps >= 4) return false;
+
+  target()->FindAllCode(&handlers, receiver_maps.length());
+
+  if (!AddOneReceiverMapIfMissing(&receiver_maps,
+                                  Handle<Map>(receiver->map()))) {
+    return false;
+  }
+
+  handlers.Add(code);
+  Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
+      &receiver_maps, &handlers, name);
+  set_target(*ic);
+  return true;
+}
+
+
+void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+                                 Handle<Code> handler,
+                                 Handle<String> name) {
+  if (handler->type() == Code::NORMAL) return set_target(*handler);
+  Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
+      receiver, handler, name);
+  set_target(*ic);
+}
+
+
+void KeyedLoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+                                      Handle<Code> handler,
+                                      Handle<String> name) {
+  if (handler->type() == Code::NORMAL) return set_target(*handler);
+  Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedMonomorphicIC(
+      receiver, handler, name);
+  set_target(*ic);
+}
+
+
 void IC::PatchCache(State state,
                     StrictModeFlag strict_mode,
                     Handle<JSObject> receiver,
@@ -944,14 +1009,18 @@ void IC::PatchCache(State state,
     case UNINITIALIZED:
     case PREMONOMORPHIC:
     case MONOMORPHIC_PROTOTYPE_FAILURE:
-      set_target(*code);
+      UpdateMonomorphicIC(receiver, code, name);
       break;
     case MONOMORPHIC:
       // Only move to megamorphic if the target changes.
       if (target() != *code) {
-        // We are transitioning from monomorphic to megamorphic case.
-        // Place the current monomorphic stub and stub compiled for
-        // the receiver into stub cache.
+        if (target()->is_load_stub()) {
+          if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
+            break;
+          }
+        }
+        // We are transitioning from monomorphic to megamorphic case.  Place the
+        // stub compiled for the receiver into stub cache.
         Map* map = target()->FindFirstMap();
         if (map != NULL) {
           UpdateMegamorphicCache(map, *name, target());
@@ -967,14 +1036,26 @@ void IC::PatchCache(State state,
       UpdateMegamorphicCache(receiver->map(), *name, *code);
       break;
     case POLYMORPHIC:
-      // When trying to patch a polymorphic stub with anything other than
-      // another polymorphic stub, go generic.
-      // TODO(verwaest): Currently we always go generic since no polymorphic
-      // stubs enter this code path. Replace with proper updating once named
-      // load/store can also be polymorphic.
-      set_target((strict_mode == kStrictMode)
-                 ? *generic_stub_strict()
-                 : *generic_stub());
+      if (target()->is_load_stub()) {
+        if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
+          break;
+        }
+        MapHandleList receiver_maps;
+        CodeHandleList handlers;
+        target()->FindAllMaps(&receiver_maps);
+        target()->FindAllCode(&handlers, receiver_maps.length());
+        for (int i = 0; i < receiver_maps.length(); i++) {
+          UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i));
+        }
+        UpdateMegamorphicCache(receiver->map(), *name, *code);
+        set_target(*megamorphic_stub());
+      } else {
+        // When trying to patch a polymorphic keyed load/store element stub
+        // with anything other than another polymorphic stub, go generic.
+        set_target((strict_mode == kStrictMode)
+                   ? *generic_stub_strict()
+                   : *generic_stub());
+      }
       break;
     case DEBUG_STUB:
       break;
@@ -985,6 +1066,42 @@ void IC::PatchCache(State state,
 }
 
 
+static void GetReceiverMapsForStub(Handle<Code> stub,
+                                   MapHandleList* result) {
+  ASSERT(stub->is_inline_cache_stub());
+  switch (stub->ic_state()) {
+    case MONOMORPHIC: {
+      Map* map = stub->FindFirstMap();
+      if (map != NULL) {
+        result->Add(Handle<Map>(map));
+      }
+      break;
+    }
+    case POLYMORPHIC: {
+      AssertNoAllocation no_allocation;
+      int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+      for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
+        RelocInfo* info = it.rinfo();
+        Handle<Object> object(info->target_object(), stub->GetIsolate());
+        if (object->IsString()) break;
+        ASSERT(object->IsMap());
+        AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
+      }
+      break;
+    }
+    case MEGAMORPHIC:
+      break;
+    case UNINITIALIZED:
+    case PREMONOMORPHIC:
+    case MONOMORPHIC_PROTOTYPE_FAILURE:
+    case GENERIC:
+    case DEBUG_STUB:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
 void LoadIC::UpdateCaches(LookupResult* lookup,
                           State state,
                           Handle<Object> object,
@@ -1004,7 +1121,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
     // setting the monomorphic state.
     code = pre_monomorphic_stub();
   } else {
-    code = ComputeLoadMonomorphic(lookup, receiver, name);
+    code = ComputeLoadHandler(lookup, receiver, name);
     if (code.is_null()) return;
   }
 
@@ -1020,9 +1137,9 @@ void IC::UpdateMegamorphicCache(Map* map, String* name, Code* code) {
 }
 
 
-Handle<Code> LoadIC::ComputeLoadMonomorphic(LookupResult* lookup,
-                                            Handle<JSObject> receiver,
-                                            Handle<String> name) {
+Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
+                                        Handle<JSObject> receiver,
+                                        Handle<String> name) {
   if (!lookup->IsProperty()) {
     // Nonexistent property. The result is undefined.
     return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver);
@@ -1051,7 +1168,7 @@ Handle<Code> LoadIC::ComputeLoadMonomorphic(LookupResult* lookup,
       // property must be found in the receiver for the stub to be
       // applicable.
       if (!holder.is_identical_to(receiver)) break;
-      return isolate()->stub_cache()->ComputeLoadNormal();
+      return isolate()->stub_cache()->ComputeLoadNormal(name, receiver);
     case CALLBACKS: {
       Handle<Object> callback(lookup->GetCallbackObject(), isolate());
       if (callback->IsExecutableAccessorInfo()) {
@@ -1107,56 +1224,6 @@ static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
 }
 
 
-static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
-                                       Handle<Map> new_receiver_map) {
-  ASSERT(!new_receiver_map.is_null());
-  for (int current = 0; current < receiver_maps->length(); ++current) {
-    if (!receiver_maps->at(current).is_null() &&
-        receiver_maps->at(current).is_identical_to(new_receiver_map)) {
-      return false;
-    }
-  }
-  receiver_maps->Add(new_receiver_map);
-  return true;
-}
-
-
-static void GetReceiverMapsForStub(Handle<Code> stub,
-                                   MapHandleList* result) {
-  ASSERT(stub->is_inline_cache_stub());
-  ASSERT(stub->is_keyed_load_stub() || stub->is_keyed_store_stub());
-  switch (stub->ic_state()) {
-    case MONOMORPHIC: {
-      Map* map = stub->FindFirstMap();
-      if (map != NULL) {
-        result->Add(Handle<Map>(map));
-      }
-      break;
-    }
-    case POLYMORPHIC: {
-      AssertNoAllocation no_allocation;
-      int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
-      for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
-        RelocInfo* info = it.rinfo();
-        Handle<Object> object(info->target_object(), stub->GetIsolate());
-        ASSERT(object->IsMap());
-        AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
-      }
-      break;
-    }
-    case MEGAMORPHIC:
-      break;
-    case UNINITIALIZED:
-    case PREMONOMORPHIC:
-    case MONOMORPHIC_PROTOTYPE_FAILURE:
-    case GENERIC:
-    case DEBUG_STUB:
-      UNREACHABLE();
-      break;
-  }
-}
-
-
 Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
   State ic_state = target()->ic_state();
 
@@ -1268,9 +1335,9 @@ MaybeObject* KeyedLoadIC::Load(State state,
 }
 
 
-Handle<Code> KeyedLoadIC::ComputeLoadMonomorphic(LookupResult* lookup,
-                                                 Handle<JSObject> receiver,
-                                                 Handle<String> name) {
+Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup,
+                                             Handle<JSObject> receiver,
+                                             Handle<String> name) {
   // Bail out if we didn't find a result.
   if (!lookup->IsProperty()) return Handle<Code>::null();
 
index a383039d150c78497e0eed1b4f7397298e9f82b7..78c364229ffcf67a0d78306698138b7c95e8e9f5 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -165,6 +165,16 @@ class IC {
   static inline void SetTargetAtAddress(Address address, Code* target);
   static void PostPatching(Address address, Code* target, Code* old_target);
 
+  virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+                                   Handle<Code> handler,
+                                   Handle<String> name) {
+    set_target(*handler);
+  }
+  bool UpdatePolymorphicIC(State state,
+                           StrictModeFlag strict_mode,
+                           Handle<JSObject> receiver,
+                           Handle<String> name,
+                           Handle<Code> code);
   void PatchCache(State state,
                   StrictModeFlag strict_mode,
                   Handle<JSObject> receiver,
@@ -377,9 +387,12 @@ class LoadIC: public IC {
                     State state,
                     Handle<Object> object,
                     Handle<String> name);
-  virtual Handle<Code> ComputeLoadMonomorphic(LookupResult* lookup,
-                                              Handle<JSObject> receiver,
-                                              Handle<String> name);
+  virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+                                   Handle<Code> handler,
+                                   Handle<String> name);
+  virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup,
+                                          Handle<JSObject> receiver,
+                                          Handle<String> name);
 
  private:
   // Stub accessors.
@@ -448,9 +461,12 @@ class KeyedLoadIC: public LoadIC {
   }
 
   // Update the inline cache.
-  virtual Handle<Code> ComputeLoadMonomorphic(LookupResult* lookup,
-                                              Handle<JSObject> receiver,
-                                              Handle<String> name);
+  virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+                                   Handle<Code> handler,
+                                   Handle<String> name);
+  virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup,
+                                          Handle<JSObject> receiver,
+                                          Handle<String> name);
   virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code) { }
 
  private:
index 9532e8b2023171fc2b25746a66398243860ab2b4..718dc02be8f335b3757e8b2fbfe79688a2bae5ad 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -135,6 +135,7 @@ class PositionsRecorder;
   V(KEYED_EXTERNAL_ARRAY_STORE_IC_TAG, "KeyedExternalArrayStoreIC")     \
   V(LAZY_COMPILE_TAG,               "LazyCompile")                      \
   V(LOAD_IC_TAG,                    "LoadIC")                           \
+  V(LOAD_POLYMORPHIC_IC_TAG,        "LoadPolymorphicIC")                \
   V(REG_EXP_TAG,                    "RegExp")                           \
   V(SCRIPT_TAG,                     "Script")                           \
   V(STORE_IC_TAG,                   "StoreIC")                          \
index 70d8a09b0dce842b0c541df1b86164d96c7acf32..599cb10ca2dd12b9cfa253df30dc3ad5244b4dbf 100644 (file)
@@ -3097,9 +3097,9 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
 }
 
 
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
     MapHandleList* receiver_maps,
-    CodeHandleList* handler_ics) {
+    CodeHandleList* handlers) {
   // ----------- S t a t e -------------
   //  -- ra    : return address
   //  -- a0    : key
@@ -3111,13 +3111,12 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
   int receiver_count = receiver_maps->length();
   __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
   for (int current = 0; current < receiver_count; ++current) {
-    __ Jump(handler_ics->at(current), RelocInfo::CODE_TARGET,
+    __ Jump(handlers->at(current), RelocInfo::CODE_TARGET,
         eq, a2, Operand(receiver_maps->at(current)));
   }
 
   __ bind(&miss);
-  Handle<Code> miss_ic = isolate()->builtins()->KeyedLoadIC_Miss();
-  __ Jump(miss_ic, RelocInfo::CODE_TARGET);
+  GenerateLoadMiss(masm(), kind());
 
   // Return the generated code.
   return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
index d1bc520ac0c01a54c1ffb4ac3087bdc22e5aa9fd..374bcbd70c8ac2a9461349bc88527b44d0886d2d 100644 (file)
@@ -3822,12 +3822,6 @@ Code::Flags Code::ComputeFlags(Kind kind,
                                StubType type,
                                int argc,
                                InlineCacheHolderFlag holder) {
-  // Extra IC state is only allowed for call IC stubs or for store IC
-  // stubs.
-  ASSERT(extra_ic_state == kNoExtraICState ||
-         kind == CALL_IC ||
-         kind == STORE_IC ||
-         kind == KEYED_STORE_IC);
   // Compute the bit mask.
   int bits = KindField::encode(kind)
       | ICStateField::encode(ic_state)
index f001d3c6fe35f4c44871a52b7b762f5298c12823..e05ba05dcf17691191281e6c6bc14c8e1c3391ee 100644 (file)
@@ -8752,6 +8752,46 @@ Map* Code::FindFirstMap() {
 }
 
 
+void Code::FindAllMaps(MapHandleList* maps) {
+  ASSERT(is_inline_cache_stub());
+  AssertNoAllocation no_allocation;
+  int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
+  for (RelocIterator it(this, mask); !it.done(); it.next()) {
+    RelocInfo* info = it.rinfo();
+    Object* object = info->target_object();
+    if (object->IsMap()) maps->Add(Handle<Map>(Map::cast(object)));
+  }
+}
+
+
+Code* Code::FindFirstCode() {
+  ASSERT(is_inline_cache_stub());
+  AssertNoAllocation no_allocation;
+  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
+  for (RelocIterator it(this, mask); !it.done(); it.next()) {
+    RelocInfo* info = it.rinfo();
+    return Code::GetCodeFromTargetAddress(info->target_address());
+  }
+  return NULL;
+}
+
+
+void Code::FindAllCode(CodeHandleList* code_list, int length) {
+  ASSERT(is_inline_cache_stub());
+  AssertNoAllocation no_allocation;
+  int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
+  int i = 0;
+  for (RelocIterator it(this, mask); !it.done(); it.next()) {
+    if (i++ == length) return;
+    RelocInfo* info = it.rinfo();
+    Code* code = Code::GetCodeFromTargetAddress(info->target_address());
+    ASSERT(code->is_load_stub());
+    code_list->Add(Handle<Code>(code));
+  }
+  UNREACHABLE();
+}
+
+
 void Code::ClearInlineCaches() {
   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
              RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
index 79e2a5ee974effcdf534a54f1d380bb724b2f64c..bf8c1e85faa09ba0e09b8ea482eeeb75619a6d05 100644 (file)
@@ -4282,6 +4282,11 @@ class Code: public HeapObject {
     NONEXISTENT
   };
 
+  enum IcFragment {
+    IC_FRAGMENT,
+    HANDLER_FRAGMENT
+  };
+
   enum {
     NUMBER_OF_KINDS = LAST_IC_KIND + 1
   };
@@ -4464,6 +4469,11 @@ class Code: public HeapObject {
 
   // Find the first map in an IC stub.
   Map* FindFirstMap();
+  void FindAllMaps(MapHandleList* maps);
+
+  // Find the first code in an IC stub.
+  Code* FindFirstCode();
+  void FindAllCode(CodeHandleList* code_list, int length);
 
   class ExtraICStateStrictMode: public BitField<StrictModeFlag, 0, 1> {};
   class ExtraICStateKeyedAccessGrowMode:
index 2ef27fded298f820ad4bf06b03a6d841c8aec052..941b51d9ec99dc1eb355ac29a8dff563708e8c97 100644 (file)
@@ -155,6 +155,18 @@ class PropertyIndex {
     return value();
   }
 
+  bool is_inobject(Handle<JSObject> holder) {
+    if (is_header_index()) return true;
+    return field_index() < holder->map()->inobject_properties();
+  }
+
+  int translate(Handle<JSObject> holder) {
+    if (is_header_index()) return header_index();
+    int index = field_index() - holder->map()->inobject_properties();
+    if (index >= 0) return index;
+    return index + holder->map()->instance_size() / kPointerSize;
+  }
+
  private:
   static const int kHeaderIndexBit = 1 << 31;
   static const int kIndexMask = ~kHeaderIndexBit;
index 5d42641f78b3a7fbe72808171a358a3117dda3cf..2bc7355d83df903ec632f476c924daf3bc7e7672 100644 (file)
@@ -100,6 +100,68 @@ Code* StubCache::Set(String* name, Map* map, Code* code) {
 }
 
 
+Handle<JSObject> StubCache::StubHolder(Handle<JSObject> receiver,
+                                       Handle<JSObject> holder) {
+  InlineCacheHolderFlag cache_holder =
+      IC::GetCodeCacheForObject(*receiver, *holder);
+  return Handle<JSObject>(IC::GetCodeCacheHolder(
+      isolate_, *receiver, cache_holder));
+}
+
+
+Handle<Code> StubCache::FindStub(Handle<String> name,
+                                 Handle<JSObject> stub_holder,
+                                 Code::Kind kind,
+                                 Code::StubType type,
+                                 Code::IcFragment fragment) {
+  Code::Flags flags = Code::ComputeMonomorphicFlags(kind, fragment, type);
+  Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
+                       isolate_);
+  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  return Handle<Code>::null();
+}
+
+
+Handle<Code> StubCache::FindHandler(Handle<String> name,
+                                    Handle<JSObject> handler_holder,
+                                    Code::Kind kind,
+                                    Code::StubType type) {
+  return FindStub(name, handler_holder, kind, type, Code::HANDLER_FRAGMENT);
+}
+
+
+Handle<Code> StubCache::ComputeMonomorphicIC(Handle<JSObject> receiver,
+                                             Handle<Code> handler,
+                                             Handle<String> name) {
+  Handle<Code> ic = FindStub(name, receiver, Code::LOAD_IC,
+                             handler->type(), Code::IC_FRAGMENT);
+  if (!ic.is_null()) return ic;
+
+  LoadStubCompiler ic_compiler(isolate());
+  ic = ic_compiler.CompileMonomorphicIC(
+      Handle<Map>(receiver->map()), handler, name);
+
+  JSObject::UpdateMapCodeCache(receiver, name, ic);
+  return ic;
+}
+
+
+Handle<Code> StubCache::ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
+                                                  Handle<Code> handler,
+                                                  Handle<String> name) {
+  Handle<Code> ic = FindStub(name, receiver, Code::KEYED_LOAD_IC,
+                             handler->type(), Code::IC_FRAGMENT);
+  if (!ic.is_null()) return ic;
+
+  KeyedLoadStubCompiler ic_compiler(isolate());
+  ic = ic_compiler.CompileMonomorphicIC(
+      Handle<Map>(receiver->map()), handler, name);
+
+  JSObject::UpdateMapCodeCache(receiver, name, ic);
+  return ic;
+}
+
+
 Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
                                                Handle<JSObject> receiver) {
   // If no global objects are present in the prototype chain, the load
@@ -125,19 +187,15 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
 
   // Compile the stub that is either shared for all names or
   // name specific if there are global objects involved.
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::LOAD_IC, Code::kNoExtraICState, Code::NONEXISTENT);
-  Handle<Object> probe(receiver->map()->FindInCodeCache(*cache_name, flags),
-                       isolate_);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  Handle<Code> handler = FindHandler(
+      cache_name, receiver, Code::LOAD_IC, Code::NONEXISTENT);
+  if (!handler.is_null()) return handler;
 
   LoadStubCompiler compiler(isolate_);
-  Handle<Code> code =
+  handler =
       compiler.CompileLoadNonexistent(receiver, current, cache_name, global);
-  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *cache_name));
-  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *cache_name, *code));
-  JSObject::UpdateMapCodeCache(receiver, cache_name, code);
-  return code;
+  JSObject::UpdateMapCodeCache(receiver, cache_name, handler);
+  return handler;
 }
 
 
@@ -145,22 +203,23 @@ Handle<Code> StubCache::ComputeLoadField(Handle<String> name,
                                          Handle<JSObject> receiver,
                                          Handle<JSObject> holder,
                                          PropertyIndex field) {
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*receiver, *holder);
-  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
-      isolate_, *receiver, cache_holder));
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::LOAD_IC, Code::kNoExtraICState, Code::FIELD);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
-                       isolate_);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  if (receiver.is_identical_to(holder)) {
+    LoadFieldStub stub(LoadStubCompiler::receiver(),
+                       field.is_inobject(holder),
+                       field.translate(holder));
+    return stub.GetCode(isolate());
+  }
+
+  Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+  Handle<Code> stub = FindHandler(
+      name, stub_holder, Code::LOAD_IC, Code::FIELD);
+  if (!stub.is_null()) return stub;
 
   LoadStubCompiler compiler(isolate_);
-  Handle<Code> code = compiler.CompileLoadField(receiver, holder, name, field);
-  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
-  return code;
+  Handle<Code> handler =
+      compiler.CompileLoadField(receiver, holder, name, field);
+  JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+  return handler;
 }
 
 
@@ -170,23 +229,16 @@ Handle<Code> StubCache::ComputeLoadCallback(
     Handle<JSObject> holder,
     Handle<ExecutableAccessorInfo> callback) {
   ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*receiver, *holder);
-  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
-      isolate_, *receiver, cache_holder));
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::LOAD_IC, Code::kNoExtraICState, Code::CALLBACKS);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
-                       isolate_);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+  Handle<Code> stub = FindHandler(
+      name, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
+  if (!stub.is_null()) return stub;
 
   LoadStubCompiler compiler(isolate_);
-  Handle<Code> code =
+  Handle<Code> handler =
       compiler.CompileLoadCallback(receiver, holder, name, callback);
-  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
-  return code;
+  JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+  return handler;
 }
 
 
@@ -194,23 +246,16 @@ Handle<Code> StubCache::ComputeLoadViaGetter(Handle<String> name,
                                              Handle<JSObject> receiver,
                                              Handle<JSObject> holder,
                                              Handle<JSFunction> getter) {
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*receiver, *holder);
-  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
-      isolate_, *receiver, cache_holder));
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::LOAD_IC, Code::kNoExtraICState, Code::CALLBACKS);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
-                       isolate_);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+  Handle<Code> stub = FindHandler(
+      name, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
+  if (!stub.is_null()) return stub;
 
   LoadStubCompiler compiler(isolate_);
-  Handle<Code> code =
+  Handle<Code> handler =
       compiler.CompileLoadViaGetter(receiver, holder, name, getter);
-  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
-  return code;
+  JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+  return handler;
 }
 
 
@@ -218,50 +263,37 @@ Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name,
                                             Handle<JSObject> receiver,
                                             Handle<JSObject> holder,
                                             Handle<JSFunction> value) {
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*receiver, *holder);
-  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
-      isolate_, *receiver, cache_holder));
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::LOAD_IC, Code::kNoExtraICState, Code::CONSTANT_FUNCTION);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
-                       isolate_);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+  Handle<Code> handler = FindHandler(
+      name, stub_holder, Code::LOAD_IC, Code::CONSTANT_FUNCTION);
+  if (!handler.is_null()) return handler;
 
   LoadStubCompiler compiler(isolate_);
-  Handle<Code> code =
-        compiler.CompileLoadConstant(receiver, holder, name, value);
-  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
-  return code;
+  handler = compiler.CompileLoadConstant(receiver, holder, name, value);
+  JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+
+  return handler;
 }
 
 
 Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
                                                Handle<JSObject> receiver,
                                                Handle<JSObject> holder) {
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*receiver, *holder);
-  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
-      isolate_, *receiver, cache_holder));
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::LOAD_IC, Code::kNoExtraICState, Code::INTERCEPTOR);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
-                       isolate_);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+  Handle<Code> stub = FindHandler(
+      name, stub_holder, Code::LOAD_IC, Code::INTERCEPTOR);
+  if (!stub.is_null()) return stub;
 
   LoadStubCompiler compiler(isolate_);
-  Handle<Code> code =
+  Handle<Code> handler =
         compiler.CompileLoadInterceptor(receiver, holder, name);
-  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
-  return code;
+  JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+  return handler;
 }
 
 
-Handle<Code> StubCache::ComputeLoadNormal() {
+Handle<Code> StubCache::ComputeLoadNormal(Handle<String> name,
+                                          Handle<JSObject> receiver) {
   return isolate_->builtins()->LoadIC_Normal();
 }
 
@@ -271,22 +303,16 @@ Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name,
                                           Handle<GlobalObject> holder,
                                           Handle<JSGlobalPropertyCell> cell,
                                           bool is_dont_delete) {
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*receiver, *holder);
-  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
-      isolate_, *receiver, cache_holder));
-  Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
-                       isolate_);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+  Handle<Code> stub = FindStub(
+      name, stub_holder, Code::LOAD_IC, Code::NORMAL, Code::IC_FRAGMENT);
+  if (!stub.is_null()) return stub;
 
   LoadStubCompiler compiler(isolate_);
-  Handle<Code> code =
+  Handle<Code> ic =
       compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
-  PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
-  return code;
+  JSObject::UpdateMapCodeCache(stub_holder, name, ic);
+  return ic;
 }
 
 
@@ -294,22 +320,23 @@ Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name,
                                               Handle<JSObject> receiver,
                                               Handle<JSObject> holder,
                                               PropertyIndex field) {
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*receiver, *holder);
-  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
-      isolate_, *receiver, cache_holder));
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::FIELD);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
-                       isolate_);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  if (receiver.is_identical_to(holder)) {
+    LoadFieldStub stub(KeyedLoadStubCompiler::receiver(),
+                       field.is_inobject(holder),
+                       field.translate(holder));
+    return stub.GetCode(isolate());
+  }
+
+  Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+  Handle<Code> stub = FindHandler(
+      name, stub_holder, Code::KEYED_LOAD_IC, Code::FIELD);
+  if (!stub.is_null()) return stub;
 
   KeyedLoadStubCompiler compiler(isolate_);
-  Handle<Code> code = compiler.CompileLoadField(receiver, holder, name, field);
-  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
-  return code;
+  Handle<Code> handler =
+      compiler.CompileLoadField(receiver, holder, name, field);
+  JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+  return handler;
 }
 
 
@@ -317,45 +344,31 @@ Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name,
                                                  Handle<JSObject> receiver,
                                                  Handle<JSObject> holder,
                                                  Handle<JSFunction> value) {
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*receiver, *holder);
-  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
-      isolate_, *receiver, cache_holder));
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::CONSTANT_FUNCTION);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
-                       isolate_);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+  Handle<Code> handler = FindHandler(
+      name, stub_holder, Code::KEYED_LOAD_IC, Code::CONSTANT_FUNCTION);
+  if (!handler.is_null()) return handler;
 
   KeyedLoadStubCompiler compiler(isolate_);
-  Handle<Code> code =
-      compiler.CompileLoadConstant(receiver, holder, name, value);
-  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
-  return code;
+  handler = compiler.CompileLoadConstant(receiver, holder, name, value);
+  JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+  return handler;
 }
 
 
 Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
                                                     Handle<JSObject> receiver,
                                                     Handle<JSObject> holder) {
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*receiver, *holder);
-  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
-      isolate_, *receiver, cache_holder));
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::INTERCEPTOR);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
-                       isolate_);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+  Handle<Code> stub = FindHandler(
+      name, stub_holder, Code::KEYED_LOAD_IC, Code::INTERCEPTOR);
+  if (!stub.is_null()) return stub;
 
   KeyedLoadStubCompiler compiler(isolate_);
-  Handle<Code> code = compiler.CompileLoadInterceptor(receiver, holder, name);
-  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
-  return code;
+  Handle<Code> handler =
+      compiler.CompileLoadInterceptor(receiver, holder, name);
+  JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+  return handler;
 }
 
 
@@ -364,23 +377,16 @@ Handle<Code> StubCache::ComputeKeyedLoadCallback(
     Handle<JSObject> receiver,
     Handle<JSObject> holder,
     Handle<ExecutableAccessorInfo> callback) {
-  InlineCacheHolderFlag cache_holder =
-      IC::GetCodeCacheForObject(*receiver, *holder);
-  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
-      isolate_, *receiver, cache_holder));
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::KEYED_LOAD_IC, Code::kNoExtraICState, Code::CALLBACKS);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
-                       isolate_);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
+  Handle<JSObject> stub_holder = StubHolder(receiver, holder);
+  Handle<Code> stub = FindHandler(
+      name, stub_holder, Code::KEYED_LOAD_IC, Code::CALLBACKS);
+  if (!stub.is_null()) return stub;
 
   KeyedLoadStubCompiler compiler(isolate_);
-  Handle<Code> code =
+  Handle<Code> handler =
       compiler.CompileLoadCallback(receiver, holder, name, callback);
-  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
-  return code;
+  JSObject::UpdateMapCodeCache(stub_holder, name, handler);
+  return handler;
 }
 
 
@@ -400,8 +406,6 @@ Handle<Code> StubCache::ComputeStoreField(Handle<String> name,
   StoreStubCompiler compiler(isolate_, strict_mode);
   Handle<Code> code =
       compiler.CompileStoreField(receiver, field_index, transition, name);
-  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
   JSObject::UpdateMapCodeCache(receiver, name, code);
   return code;
 }
@@ -418,7 +422,6 @@ Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
   KeyedLoadStubCompiler compiler(isolate());
   Handle<Code> code = compiler.CompileLoadElement(receiver_map);
 
-  PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
   Map::UpdateCodeCache(receiver_map, name, code);
   return code;
 }
@@ -447,7 +450,6 @@ Handle<Code> StubCache::ComputeKeyedStoreElement(
   KeyedStoreStubCompiler compiler(isolate(), strict_mode, grow_mode);
   Handle<Code> code = compiler.CompileStoreElement(receiver_map);
 
-  PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
   Map::UpdateCodeCache(receiver_map, name, code);
   return code;
 }
@@ -472,8 +474,6 @@ Handle<Code> StubCache::ComputeStoreGlobal(Handle<String> name,
 
   StoreStubCompiler compiler(isolate_, strict_mode);
   Handle<Code> code = compiler.CompileStoreGlobal(receiver, cell, name);
-  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
   JSObject::UpdateMapCodeCache(receiver, name, code);
   return code;
 }
@@ -495,8 +495,6 @@ Handle<Code> StubCache::ComputeStoreCallback(
   StoreStubCompiler compiler(isolate_, strict_mode);
   Handle<Code> code =
       compiler.CompileStoreCallback(name, receiver, holder, callback);
-  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
   JSObject::UpdateMapCodeCache(receiver, name, code);
   return code;
 }
@@ -516,8 +514,6 @@ Handle<Code> StubCache::ComputeStoreViaSetter(Handle<String> name,
   StoreStubCompiler compiler(isolate_, strict_mode);
   Handle<Code> code =
       compiler.CompileStoreViaSetter(name, receiver, holder, setter);
-  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
   JSObject::UpdateMapCodeCache(receiver, name, code);
   return code;
 }
@@ -534,8 +530,6 @@ Handle<Code> StubCache::ComputeStoreInterceptor(Handle<String> name,
 
   StoreStubCompiler compiler(isolate_, strict_mode);
   Handle<Code> code = compiler.CompileStoreInterceptor(receiver, name);
-  PROFILE(isolate_, CodeCreateEvent(Logger::STORE_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::STORE_IC, *name, *code));
   JSObject::UpdateMapCodeCache(receiver, name, code);
   return code;
 }
@@ -557,8 +551,6 @@ Handle<Code> StubCache::ComputeKeyedStoreField(Handle<String> name,
                                   DO_NOT_ALLOW_JSARRAY_GROWTH);
   Handle<Code> code =
       compiler.CompileStoreField(receiver, field_index, transition, name);
-  PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::KEYED_STORE_IC, *name, *code));
   JSObject::UpdateMapCodeCache(receiver, name, code);
   return code;
 }
@@ -577,8 +569,8 @@ Handle<Code> StubCache::ComputeCallConstant(int argc,
   // Compute the check type and the map.
   InlineCacheHolderFlag cache_holder =
       IC::GetCodeCacheForObject(*object, *holder);
-  Handle<JSObject> map_holder(
-      IC::GetCodeCacheHolder(isolate_, *object, cache_holder));
+  Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
+      isolate_, *object, cache_holder));
 
   // Compute check type based on receiver/holder.
   CheckType check = RECEIVER_MAP_CHECK;
@@ -602,7 +594,7 @@ Handle<Code> StubCache::ComputeCallConstant(int argc,
 
   Code::Flags flags = Code::ComputeMonomorphicFlags(
       kind, extra_state, Code::CONSTANT_FUNCTION, argc, cache_holder);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+  Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
 
@@ -614,7 +606,7 @@ Handle<Code> StubCache::ComputeCallConstant(int argc,
   PROFILE(isolate_,
           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
+  JSObject::UpdateMapCodeCache(stub_holder, name, code);
   return code;
 }
 
@@ -629,8 +621,8 @@ Handle<Code> StubCache::ComputeCallField(int argc,
   // Compute the check type and the map.
   InlineCacheHolderFlag cache_holder =
       IC::GetCodeCacheForObject(*object, *holder);
-  Handle<JSObject> map_holder(
-      IC::GetCodeCacheHolder(isolate_, *object, cache_holder));
+  Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
+      isolate_, *object, cache_holder));
 
   // TODO(1233596): We cannot do receiver map check for non-JS objects
   // because they may be represented as immediates without a
@@ -642,7 +634,7 @@ Handle<Code> StubCache::ComputeCallField(int argc,
 
   Code::Flags flags = Code::ComputeMonomorphicFlags(
       kind, extra_state, Code::FIELD, argc, cache_holder);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+  Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
 
@@ -654,7 +646,7 @@ Handle<Code> StubCache::ComputeCallField(int argc,
   PROFILE(isolate_,
           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
+  JSObject::UpdateMapCodeCache(stub_holder, name, code);
   return code;
 }
 
@@ -668,8 +660,8 @@ Handle<Code> StubCache::ComputeCallInterceptor(int argc,
   // Compute the check type and the map.
   InlineCacheHolderFlag cache_holder =
       IC::GetCodeCacheForObject(*object, *holder);
-  Handle<JSObject> map_holder(
-      IC::GetCodeCacheHolder(isolate_, *object, cache_holder));
+  Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
+      isolate_, *object, cache_holder));
 
   // TODO(1233596): We cannot do receiver map check for non-JS objects
   // because they may be represented as immediates without a
@@ -681,7 +673,7 @@ Handle<Code> StubCache::ComputeCallInterceptor(int argc,
 
   Code::Flags flags = Code::ComputeMonomorphicFlags(
       kind, extra_state, Code::INTERCEPTOR, argc, cache_holder);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+  Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
 
@@ -693,7 +685,7 @@ Handle<Code> StubCache::ComputeCallInterceptor(int argc,
   PROFILE(isolate(),
           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
+  JSObject::UpdateMapCodeCache(stub_holder, name, code);
   return code;
 }
 
@@ -708,11 +700,11 @@ Handle<Code> StubCache::ComputeCallGlobal(int argc,
                                           Handle<JSFunction> function) {
   InlineCacheHolderFlag cache_holder =
       IC::GetCodeCacheForObject(*receiver, *holder);
-  Handle<JSObject> map_holder(IC::GetCodeCacheHolder(
+  Handle<JSObject> stub_holder(IC::GetCodeCacheHolder(
       isolate_, *receiver, cache_holder));
   Code::Flags flags = Code::ComputeMonomorphicFlags(
       kind, extra_state, Code::NORMAL, argc, cache_holder);
-  Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
+  Handle<Object> probe(stub_holder->map()->FindInCodeCache(*name, flags),
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
 
@@ -723,7 +715,7 @@ Handle<Code> StubCache::ComputeCallGlobal(int argc,
   PROFILE(isolate(),
           CodeCreateEvent(CALL_LOGGER_TAG(kind, CALL_IC_TAG), *code, *name));
   GDBJIT(AddCode(GDBJITInterface::CALL_IC, *name, *code));
-  JSObject::UpdateMapCodeCache(map_holder, name, code);
+  JSObject::UpdateMapCodeCache(stub_holder, name, code);
   return code;
 }
 
@@ -885,13 +877,30 @@ Handle<Code> StubCache::ComputeLoadElementPolymorphic(
   Handle<Object> probe = cache->Lookup(receiver_maps, flags);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
 
+  CodeHandleList handlers(receiver_maps->length());
   KeyedLoadStubCompiler compiler(isolate_);
-  Handle<Code> code = compiler.CompileLoadElementPolymorphic(receiver_maps);
+  compiler.CompileElementHandlers(receiver_maps, &handlers);
+  Handle<Code> code = compiler.CompilePolymorphicIC(
+      receiver_maps, &handlers, factory()->empty_string(),
+      Code::NORMAL, ELEMENT);
+
+  isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
+
   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
   return code;
 }
 
 
+Handle<Code> StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps,
+                                             CodeHandleList* handlers,
+                                             Handle<String> name) {
+  LoadStubCompiler ic_compiler(isolate_);
+  Handle<Code> ic = ic_compiler.CompilePolymorphicIC(
+      receiver_maps, handlers, name, Code::NORMAL, PROPERTY);
+  return ic;
+}
+
+
 Handle<Code> StubCache::ComputeStoreElementPolymorphic(
     MapHandleList* receiver_maps,
     KeyedAccessGrowMode grow_mode,
@@ -1386,18 +1395,11 @@ Register BaseLoadStubCompiler::HandlerFrontendHeader(Handle<JSObject> object,
                                                      Register object_reg,
                                                      Handle<JSObject> holder,
                                                      Handle<String> name,
-                                                     Label* miss,
-                                                     FrontendCheckType check) {
-  if (check == PERFORM_INITIAL_CHECKS) {
-    GenerateNameCheck(name, this->name(), miss);
-    // Check that the receiver isn't a smi.
-    __ JumpIfSmi(object_reg, miss);
-  }
-
+                                                     Label* miss) {
   // Check the prototype chain.
   return CheckPrototypes(object, object_reg, holder,
                          scratch1(), scratch2(), scratch3(),
-                         name, miss);
+                         name, miss, SKIP_RECEIVER);
 }
 
 
@@ -1405,12 +1407,10 @@ Register BaseLoadStubCompiler::HandlerFrontend(Handle<JSObject> object,
                                                Register object_reg,
                                                Handle<JSObject> holder,
                                                Handle<String> name,
-                                               Label* success,
-                                               FrontendCheckType check) {
+                                               Label* success) {
   Label miss;
 
-  Register reg = HandlerFrontendHeader(
-      object, object_reg, holder, name, &miss, check);
+  Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
 
   HandlerFrontendFooter(success, &miss);
   return reg;
@@ -1420,15 +1420,19 @@ Register BaseLoadStubCompiler::HandlerFrontend(Handle<JSObject> object,
 Handle<Code> BaseLoadStubCompiler::CompileLoadField(Handle<JSObject> object,
                                                     Handle<JSObject> holder,
                                                     Handle<String> name,
-                                                    PropertyIndex index) {
-  Label success;
-  Register reg = HandlerFrontend(object, receiver(), holder, name,
-                                 &success, PERFORM_INITIAL_CHECKS);
-  __ bind(&success);
-  GenerateLoadField(reg, holder, index);
+                                                    PropertyIndex field) {
+  Label miss;
+
+  Register reg = HandlerFrontendHeader(object, receiver(), holder, name, &miss);
+
+  LoadFieldStub stub(reg, field.is_inobject(holder), field.translate(holder));
+  GenerateTailCall(stub.GetCode(isolate()));
+
+  __ bind(&miss);
+  GenerateLoadMiss(masm(), kind());
 
   // Return the generated code.
-  return GetCode(Code::FIELD, name);
+  return GetCode(Code::HANDLER_FRAGMENT, Code::FIELD, name);
 }
 
 
@@ -1438,13 +1442,12 @@ Handle<Code> BaseLoadStubCompiler::CompileLoadConstant(
     Handle<String> name,
     Handle<JSFunction> value) {
   Label success;
-  HandlerFrontend(object, receiver(), holder, name,
-                  &success, PERFORM_INITIAL_CHECKS);
+  HandlerFrontend(object, receiver(), holder, name, &success);
   __ bind(&success);
   GenerateLoadConstant(value);
 
   // Return the generated code.
-  return GetCode(Code::CONSTANT_FUNCTION, name);
+  return GetCode(Code::HANDLER_FRAGMENT, Code::CONSTANT_FUNCTION, name);
 }
 
 
@@ -1456,13 +1459,12 @@ Handle<Code> BaseLoadStubCompiler::CompileLoadCallback(
   Label success;
 
   Register reg = CallbackHandlerFrontend(
-      object, receiver(), holder, name, &success,
-      PERFORM_INITIAL_CHECKS, callback);
+      object, receiver(), holder, name, &success, callback);
   __ bind(&success);
   GenerateLoadCallback(reg, callback);
 
   // Return the generated code.
-  return GetCode(Code::CALLBACKS, name);
+  return GetCode(Code::HANDLER_FRAGMENT, Code::CALLBACKS, name);
 }
 
 
@@ -1475,15 +1477,14 @@ Handle<Code> BaseLoadStubCompiler::CompileLoadInterceptor(
   LookupResult lookup(isolate());
   LookupPostInterceptor(holder, name, &lookup);
 
-  Register reg = HandlerFrontend(object, receiver(), holder, name,
-                                 &success, PERFORM_INITIAL_CHECKS);
+  Register reg = HandlerFrontend(object, receiver(), holder, name, &success);
   __ bind(&success);
   // TODO(368): Compile in the whole chain: all the interceptors in
   // prototypes and ultimate answer.
   GenerateLoadInterceptor(reg, object, holder, &lookup, name);
 
   // Return the generated code.
-  return GetCode(Code::INTERCEPTOR, name);
+  return GetCode(Code::HANDLER_FRAGMENT, Code::INTERCEPTOR, name);
 }
 
 
@@ -1495,12 +1496,20 @@ void BaseLoadStubCompiler::GenerateLoadPostInterceptor(
   Label success;
   Handle<JSObject> holder(lookup->holder());
   if (lookup->IsField()) {
-    // We found FIELD property in prototype chain of interceptor's holder.
-    // Retrieve a field from field's holder.
-    Register reg = HandlerFrontend(interceptor_holder, interceptor_reg, holder,
-                                   name, &success, SKIP_INITIAL_CHECKS);
-    __ bind(&success);
-    GenerateLoadField(reg, holder, lookup->GetFieldIndex());
+    PropertyIndex field = lookup->GetFieldIndex();
+    if (interceptor_holder.is_identical_to(holder)) {
+      LoadFieldStub stub(interceptor_reg,
+                         field.is_inobject(holder),
+                         field.translate(holder));
+      GenerateTailCall(stub.GetCode(isolate()));
+    } else {
+      // We found FIELD property in prototype chain of interceptor's holder.
+      // Retrieve a field from field's holder.
+      Register reg = HandlerFrontend(
+          interceptor_holder, interceptor_reg, holder, name, &success);
+      __ bind(&success);
+      GenerateLoadField(reg, holder, field);
+    }
   } else {
     // We found CALLBACKS property in prototype chain of interceptor's
     // holder.
@@ -1510,61 +1519,69 @@ void BaseLoadStubCompiler::GenerateLoadPostInterceptor(
     ASSERT(callback->getter() != NULL);
 
     Register reg = CallbackHandlerFrontend(
-        interceptor_holder, interceptor_reg, holder,
-        name, &success, SKIP_INITIAL_CHECKS, callback);
+        interceptor_holder, interceptor_reg, holder, name, &success, callback);
     __ bind(&success);
     GenerateLoadCallback(reg, callback);
   }
 }
 
 
+Handle<Code> BaseLoadStubCompiler::CompileMonomorphicIC(
+    Handle<Map> receiver_map,
+    Handle<Code> handler,
+    Handle<String> name) {
+  MapHandleList receiver_maps(1);
+  receiver_maps.Add(receiver_map);
+  CodeHandleList handlers(1);
+  handlers.Add(handler);
+  Code::StubType type = handler->type();
+  return CompilePolymorphicIC(&receiver_maps, &handlers, name, type, PROPERTY);
+}
+
+
 Handle<Code> LoadStubCompiler::CompileLoadViaGetter(
     Handle<JSObject> object,
     Handle<JSObject> holder,
     Handle<String> name,
     Handle<JSFunction> getter) {
   Label success;
-  HandlerFrontend(object, receiver(), holder, name,
-                  &success, PERFORM_INITIAL_CHECKS);
+  HandlerFrontend(object, receiver(), holder, name, &success);
 
   __ bind(&success);
   GenerateLoadViaGetter(masm(), getter);
 
   // Return the generated code.
-  return GetCode(Code::CALLBACKS, name);
+  return GetCode(Code::HANDLER_FRAGMENT, Code::CALLBACKS, name);
 }
 
 
 #undef __
 
 
-Handle<Code> LoadStubCompiler::GetCode(Code::StubType type,
-                                       Handle<String> name,
-                                       InlineCacheState state) {
-  Code::Flags flags = Code::ComputeMonomorphicFlags(
-      Code::LOAD_IC, Code::kNoExtraICState, type);
-  Handle<Code> code = GetCodeWithFlags(flags, name);
-  PROFILE(isolate(), CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
+void LoadStubCompiler::JitEvent(Handle<String> name, Handle<Code> code) {
   GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
-  return code;
 }
 
 
-Handle<Code> KeyedLoadStubCompiler::GetCode(Code::StubType type,
-                                            Handle<String> name,
-                                            InlineCacheState state) {
-  Code::Flags flags = Code::ComputeFlags(
-      Code::KEYED_LOAD_IC, state, Code::kNoExtraICState, type);
+void KeyedLoadStubCompiler::JitEvent(Handle<String> name, Handle<Code> code) {
+  GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
+}
+
+
+Handle<Code> BaseLoadStubCompiler::GetCode(Code::IcFragment fragment,
+                                           Code::StubType type,
+                                           Handle<String> name,
+                                           InlineCacheState state) {
+  Code::Flags flags = Code::ComputeFlags(kind(), state, fragment, type);
   Handle<Code> code = GetCodeWithFlags(flags, name);
-  PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
-  GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
+  PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
+  JitEvent(name, code);
   return code;
 }
 
 
-Handle<Code> KeyedLoadStubCompiler::CompileLoadElementPolymorphic(
-    MapHandleList* receiver_maps) {
-  CodeHandleList handler_ics(receiver_maps->length());
+void KeyedLoadStubCompiler::CompileElementHandlers(MapHandleList* receiver_maps,
+                                                   CodeHandleList* handlers) {
   for (int i = 0; i < receiver_maps->length(); ++i) {
     Handle<Map> receiver_map = receiver_maps->at(i);
     Handle<Code> cached_stub;
@@ -1586,17 +1603,11 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadElementPolymorphic(
       }
     }
 
-    handler_ics.Add(cached_stub);
+    handlers->Add(cached_stub);
   }
-  Handle<Code> code = CompileLoadPolymorphic(receiver_maps, &handler_ics);
-  isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
-  PROFILE(isolate(),
-          CodeCreateEvent(Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG, *code, 0));
-  return code;
 }
 
 
-
 Handle<Code> StoreStubCompiler::GetCode(Code::StubType type,
                                         Handle<String> name) {
   Code::Flags flags = Code::ComputeMonomorphicFlags(
@@ -1625,7 +1636,7 @@ Handle<Code> KeyedStoreStubCompiler::GetCode(Code::StubType type,
 Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
     MapHandleList* receiver_maps) {
   // Collect MONOMORPHIC stubs for all |receiver_maps|.
-  CodeHandleList handler_ics(receiver_maps->length());
+  CodeHandleList handlers(receiver_maps->length());
   MapHandleList transitioned_maps(receiver_maps->length());
   for (int i = 0; i < receiver_maps->length(); ++i) {
     Handle<Map> receiver_map(receiver_maps->at(i));
@@ -1654,11 +1665,11 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
           grow_mode_).GetCode(isolate());
     }
     ASSERT(!cached_stub.is_null());
-    handler_ics.Add(cached_stub);
+    handlers.Add(cached_stub);
     transitioned_maps.Add(transitioned_map);
   }
   Handle<Code> code =
-      CompileStorePolymorphic(receiver_maps, &handler_ics, &transitioned_maps);
+      CompileStorePolymorphic(receiver_maps, &handlers, &transitioned_maps);
   isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
   PROFILE(isolate(),
           CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
index 775340648b6d5ddac46d01a61215141d48f0dd49..5e3fbfcd7364a7426bf41c49df6ff0c20a417e81 100644 (file)
@@ -74,6 +74,26 @@ class StubCache {
 
   void Initialize();
 
+  Handle<JSObject> StubHolder(Handle<JSObject> receiver,
+                              Handle<JSObject> holder);
+
+  Handle<Code> FindStub(Handle<String> name,
+                        Handle<JSObject> stub_holder,
+                        Code::Kind kind,
+                        Code::StubType type,
+                        Code::IcFragment fragment);
+
+  Handle<Code> FindHandler(Handle<String> name,
+                           Handle<JSObject> stub_holder,
+                           Code::Kind kind,
+                           Code::StubType type);
+
+  Handle<Code> ComputeMonomorphicIC(Handle<JSObject> receiver,
+                                    Handle<Code> handler,
+                                    Handle<String> name);
+  Handle<Code> ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
+                                         Handle<Code> handler,
+                                         Handle<String> name);
 
   // Computes the right stub matching. Inserts the result in the
   // cache before returning.  This might compile a stub if needed.
@@ -104,7 +124,8 @@ class StubCache {
                                       Handle<JSObject> object,
                                       Handle<JSObject> holder);
 
-  Handle<Code> ComputeLoadNormal();
+  Handle<Code> ComputeLoadNormal(Handle<String> name,
+                                 Handle<JSObject> object);
 
   Handle<Code> ComputeLoadGlobal(Handle<String> name,
                                  Handle<JSObject> object,
@@ -245,6 +266,10 @@ class StubCache {
                                               KeyedAccessGrowMode grow_mode,
                                               StrictModeFlag strict_mode);
 
+  Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
+                                    CodeHandleList* handlers,
+                                    Handle<String> name);
+
   // Finds the Code object stored in the Heap::non_monomorphic_cache().
   Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind);
 
@@ -414,6 +439,10 @@ DECLARE_RUNTIME_FUNCTION(MaybeObject*, CallInterceptorProperty);
 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadPropertyWithInterceptor);
 
 
+enum PrototypeCheckType { CHECK_ALL_MAPS, SKIP_RECEIVER };
+enum IcCheckType { ELEMENT, PROPERTY };
+
+
 // The stub compilers compile stubs for the stub cache.
 class StubCompiler BASE_EMBEDDED {
  public:
@@ -455,6 +484,11 @@ class StubCompiler BASE_EMBEDDED {
                                        Register src,
                                        Handle<JSObject> holder,
                                        PropertyIndex index);
+  static void DoGenerateFastPropertyLoad(MacroAssembler* masm,
+                                         Register dst,
+                                         Register src,
+                                         bool inobject,
+                                         int index);
 
   static void GenerateLoadArrayLength(MacroAssembler* masm,
                                       Register receiver,
@@ -512,9 +546,10 @@ class StubCompiler BASE_EMBEDDED {
                            Register scratch1,
                            Register scratch2,
                            Handle<String> name,
-                           Label* miss) {
+                           Label* miss,
+                           PrototypeCheckType check = CHECK_ALL_MAPS) {
     return CheckPrototypes(object, object_reg, holder, holder_reg, scratch1,
-                           scratch2, name, kInvalidProtoDepth, miss);
+                           scratch2, name, kInvalidProtoDepth, miss, check);
   }
 
   Register CheckPrototypes(Handle<JSObject> object,
@@ -525,7 +560,8 @@ class StubCompiler BASE_EMBEDDED {
                            Register scratch2,
                            Handle<String> name,
                            int save_at_depth,
-                           Label* miss);
+                           Label* miss,
+                           PrototypeCheckType check = CHECK_ALL_MAPS);
 
 
  protected:
@@ -543,6 +579,8 @@ class StubCompiler BASE_EMBEDDED {
   Heap* heap() { return isolate()->heap(); }
   Factory* factory() { return isolate()->factory(); }
 
+  void GenerateTailCall(Handle<Code> code);
+
  private:
   Isolate* isolate_;
   MacroAssembler masm_;
@@ -578,27 +616,33 @@ class BaseLoadStubCompiler: public StubCompiler {
                                       Handle<JSObject> holder,
                                       Handle<String> name);
 
+  Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map,
+                                    Handle<Code> handler,
+                                    Handle<String> name);
+  Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps,
+                                    CodeHandleList* handlers,
+                                    Handle<String> name,
+                                    Code::StubType type,
+                                    IcCheckType check);
+
  protected:
   Register HandlerFrontendHeader(Handle<JSObject> object,
                                  Register object_reg,
                                  Handle<JSObject> holder,
                                  Handle<String> name,
-                                 Label* success,
-                                 FrontendCheckType check);
+                                 Label* success);
   void HandlerFrontendFooter(Label* success, Label* miss);
 
   Register HandlerFrontend(Handle<JSObject> object,
                            Register object_reg,
                            Handle<JSObject> holder,
                            Handle<String> name,
-                           Label* success,
-                           FrontendCheckType check);
+                           Label* success);
   Register CallbackHandlerFrontend(Handle<JSObject> object,
                                    Register object_reg,
                                    Handle<JSObject> holder,
                                    Handle<String> name,
                                    Label* success,
-                                   FrontendCheckType check,
                                    Handle<ExecutableAccessorInfo> callback);
   void NonexistentHandlerFrontend(Handle<JSObject> object,
                                   Handle<JSObject> last,
@@ -622,6 +666,10 @@ class BaseLoadStubCompiler: public StubCompiler {
                                    Handle<String> name,
                                    LookupResult* lookup);
 
+  Handle<Code> GetCode(Code::IcFragment fragment,
+                       Code::StubType type,
+                       Handle<String> name,
+                       InlineCacheState state = MONOMORPHIC);
 
   Register receiver() { return registers_[0]; }
   Register name()     { return registers_[1]; }
@@ -632,12 +680,11 @@ class BaseLoadStubCompiler: public StubCompiler {
 
  private:
   virtual Code::Kind kind() = 0;
+  virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) = 0;
+  virtual void JitEvent(Handle<String> name, Handle<Code> code) = 0;
   virtual void GenerateNameCheck(Handle<String> name,
                                  Register name_reg,
                                  Label* miss) { }
-  virtual Handle<Code> GetCode(Code::StubType type,
-                               Handle<String> name,
-                               InlineCacheState state = MONOMORPHIC) = 0;
   Register* registers_;
 };
 
@@ -666,12 +713,16 @@ class LoadStubCompiler: public BaseLoadStubCompiler {
                                  Handle<String> name,
                                  bool is_dont_delete);
 
+  static Register receiver() { return registers()[0]; }
+
  private:
-  Register* registers();
+  static Register* registers();
   virtual Code::Kind kind() { return Code::LOAD_IC; }
-  virtual Handle<Code> GetCode(Code::StubType type,
-                               Handle<String> name,
-                               InlineCacheState state = MONOMORPHIC);
+  virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) {
+    return code->ic_state() == MONOMORPHIC
+        ? Logger::LOAD_IC_TAG : Logger::LOAD_POLYMORPHIC_IC_TAG;
+  }
+  virtual void JitEvent(Handle<String> name, Handle<Code> code);
 };
 
 
@@ -682,19 +733,23 @@ class KeyedLoadStubCompiler: public BaseLoadStubCompiler {
 
   Handle<Code> CompileLoadElement(Handle<Map> receiver_map);
 
-  Handle<Code> CompileLoadPolymorphic(MapHandleList* receiver_maps,
-                                      CodeHandleList* handler_ics);
+  void CompileElementHandlers(MapHandleList* receiver_maps,
+                              CodeHandleList* handlers);
 
   Handle<Code> CompileLoadElementPolymorphic(MapHandleList* receiver_maps);
 
   static void GenerateLoadDictionaryElement(MacroAssembler* masm);
 
+  static Register receiver() { return registers()[0]; }
+
  private:
-  Register* registers();
+  static Register* registers();
   virtual Code::Kind kind() { return Code::KEYED_LOAD_IC; }
-  virtual Handle<Code> GetCode(Code::StubType type,
-                               Handle<String> name,
-                               InlineCacheState state = MONOMORPHIC);
+  virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) {
+    return code->ic_state() == MONOMORPHIC
+        ? Logger::KEYED_LOAD_IC_TAG : Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG;
+  }
+  virtual void JitEvent(Handle<String> name, Handle<Code> code);
   virtual void GenerateNameCheck(Handle<String> name,
                                  Register name_reg,
                                  Label* miss);
index fc88c3c55da100fd4b9e5d08ec12da0f65dfa085..62ca32479d9747b48f8c63d6cbb369af778e2253 100644 (file)
@@ -338,6 +338,7 @@ bool TypeFeedbackOracle::LoadIsStub(Property* expr, ICStub* stub) {
   if (!object->IsCode()) return false;
   Handle<Code> code = Handle<Code>::cast(object);
   if (!code->is_load_stub()) return false;
+  if (code->ic_state() != MONOMORPHIC) return false;
   return stub->Describes(*code);
 }
 
@@ -514,6 +515,29 @@ TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) {
 }
 
 
+static void AddMapIfMissing(Handle<Map> map, SmallMapList* list,
+                            Zone* zone) {
+  for (int i = 0; i < list->length(); ++i) {
+    if (list->at(i).is_identical_to(map)) return;
+  }
+  list->Add(map, zone);
+}
+
+
+void TypeFeedbackOracle::CollectPolymorphicMaps(Handle<Code> code,
+                                                SmallMapList* types) {
+  MapHandleList maps;
+  code->FindAllMaps(&maps);
+  types->Reserve(maps.length(), zone());
+  for (int i = 0; i < maps.length(); i++) {
+    Handle<Map> map(maps.at(i));
+    if (!CanRetainOtherContext(*map, *native_context_)) {
+      AddMapIfMissing(map, types, zone());
+    }
+  }
+}
+
+
 void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
                                               Handle<String> name,
                                               Code::Flags flags,
@@ -527,6 +551,8 @@ void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id,
     ASSERT(Handle<Code>::cast(object)->ic_state() == GENERIC);
   } else if (object->IsMap()) {
     types->Add(Handle<Map>::cast(object), zone());
+  } else if (Handle<Code>::cast(object)->ic_state() == POLYMORPHIC) {
+    CollectPolymorphicMaps(Handle<Code>::cast(object), types);
   } else if (FLAG_collect_megamorphic_maps_from_stub_cache &&
       Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) {
     types->Reserve(4, zone());
@@ -574,15 +600,6 @@ bool TypeFeedbackOracle::CanRetainOtherContext(JSFunction* function,
 }
 
 
-static void AddMapIfMissing(Handle<Map> map, SmallMapList* list,
-                            Zone* zone) {
-  for (int i = 0; i < list->length(); ++i) {
-    if (list->at(i).is_identical_to(map)) return;
-  }
-  list->Add(map, zone);
-}
-
-
 void TypeFeedbackOracle::CollectKeyedReceiverTypes(TypeFeedbackId ast_id,
                                                    SmallMapList* types) {
   Handle<Object> object = GetInfo(ast_id);
@@ -590,18 +607,7 @@ void TypeFeedbackOracle::CollectKeyedReceiverTypes(TypeFeedbackId ast_id,
   Handle<Code> code = Handle<Code>::cast(object);
   if (code->kind() == Code::KEYED_LOAD_IC ||
       code->kind() == Code::KEYED_STORE_IC) {
-    AssertNoAllocation no_allocation;
-    int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
-    for (RelocIterator it(*code, mask); !it.done(); it.next()) {
-      RelocInfo* info = it.rinfo();
-      Object* object = info->target_object();
-      if (object->IsMap()) {
-        Map* map = Map::cast(object);
-        if (!CanRetainOtherContext(map, *native_context_)) {
-          AddMapIfMissing(Handle<Map>(map), types, zone());
-        }
-      }
-    }
+    CollectPolymorphicMaps(code, types);
   }
 }
 
index a962803dabf403ac2d7a98a7e416a6a056bf9342..2b50bf483f429212cc050cb47336dab6218ee68a 100644 (file)
@@ -272,6 +272,8 @@ class TypeFeedbackOracle: public ZoneObject {
   static bool CanRetainOtherContext(JSFunction* function,
                                     Context* native_context);
 
+  void CollectPolymorphicMaps(Handle<Code> code, SmallMapList* types);
+
   CheckType GetCallCheckType(Call* expr);
   Handle<JSObject> GetPrototypeForPrimitiveCheck(CheckType check);
 
index 9080bd641f3f8951460ed2a1a19c46f91ce28c30..c391b9c4327f4bca495e723511289e7abfd2c887 100644 (file)
@@ -249,6 +249,7 @@ class BitField {
   // using a shift count of 32.
   static const uint32_t kMask = ((1U << shift) << size) - (1U << shift);
   static const uint32_t kShift = shift;
+  static const uint32_t kSize = size;
 
   // Value for the field with all bits set.
   static const T kMax = static_cast<T>((1U << size) - 1);
index 49db9fe1638577470244d57bb813bff2412c7eba..6aa890356ad23897175040cae22648ab4334d66a 100644 (file)
@@ -2523,6 +2523,12 @@ void StoreArrayLengthStub::Generate(MacroAssembler* masm) {
 }
 
 
+void LoadFieldStub::Generate(MacroAssembler* masm) {
+  StubCompiler::DoGenerateFastPropertyLoad(masm, rax, reg_, inobject_, index_);
+  __ ret(0);
+}
+
+
 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
   // The key is in rdx and the parameter count is in rax.
 
index 02302a9dd32e394f2599e89e51ea65a31b08ab8a..15423e47b69aaa5e48f35ee867634c58af31e638 100644 (file)
@@ -1321,9 +1321,10 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
   // -----------------------------------
 
   // Probe the stub cache.
-  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
-  Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rax, rcx, rbx,
-                                                  rdx);
+  Code::Flags flags = Code::ComputeFlags(
+      Code::LOAD_IC, MONOMORPHIC, Code::HANDLER_FRAGMENT);
+  Isolate::Current()->stub_cache()->GenerateProbe(
+      masm, flags, rax, rcx, rbx, rdx);
 
   // Cache miss: Jump to runtime.
   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
index 3184dc9a8f69d130ab81f7fd34010f60b30f2698..c471569f20839fdaf9edcfbbca4cab3c1ea2eba7 100644 (file)
@@ -351,23 +351,24 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
                                             Register src,
                                             Handle<JSObject> holder,
                                             PropertyIndex index) {
-  if (index.is_header_index()) {
-    int offset = index.header_index() * kPointerSize;
-    __ movq(dst, FieldOperand(src, offset));
-  } else {
-    // Adjust for the number of properties stored in the holder.
-    int slot = index.field_index() - holder->map()->inobject_properties();
-    if (slot < 0) {
-      // Get the property straight out of the holder.
-      int offset = holder->map()->instance_size() + (slot * kPointerSize);
-      __ movq(dst, FieldOperand(src, offset));
-    } else {
-      // Calculate the offset into the properties array.
-      int offset = slot * kPointerSize + FixedArray::kHeaderSize;
-      __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
-      __ movq(dst, FieldOperand(dst, offset));
-    }
+  DoGenerateFastPropertyLoad(
+      masm, dst, src, index.is_inobject(holder), index.translate(holder));
+}
+
+
+void StubCompiler::DoGenerateFastPropertyLoad(MacroAssembler* masm,
+                                              Register dst,
+                                              Register src,
+                                              bool inobject,
+                                              int index) {
+  int offset = index * kPointerSize;
+  if (!inobject) {
+    // Calculate the offset into the properties array.
+    offset = offset + FixedArray::kHeaderSize;
+    __ movq(dst, FieldOperand(src, JSObject::kPropertiesOffset));
+    src = dst;
   }
+  __ movq(dst, FieldOperand(src, offset));
 }
 
 
@@ -911,6 +912,11 @@ static void GenerateCheckPropertyCells(MacroAssembler* masm,
 #define __ ACCESS_MASM((masm()))
 
 
+void StubCompiler::GenerateTailCall(Handle<Code> code) {
+  __ jmp(code, RelocInfo::CODE_TARGET);
+}
+
+
 Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
                                        Register object_reg,
                                        Handle<JSObject> holder,
@@ -919,7 +925,9 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
                                        Register scratch2,
                                        Handle<String> name,
                                        int save_at_depth,
-                                       Label* miss) {
+                                       Label* miss,
+                                       PrototypeCheckType check) {
+  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)
@@ -968,8 +976,10 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
         // Save the map in scratch1 for later.
         __ movq(scratch1, FieldOperand(reg, HeapObject::kMapOffset));
       }
-      __ CheckMap(reg, Handle<Map>(current_map),
-                  miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+      if (!current.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+        __ CheckMap(reg, current_map, miss, DONT_DO_SMI_CHECK,
+                    ALLOW_ELEMENT_TRANSITION_MAPS);
+      }
 
       // 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
@@ -1001,9 +1011,11 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
   // Log the check depth.
   LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
 
-  // Check the holder map.
-  __ CheckMap(reg, Handle<Map>(holder->map()),
-              miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+  if (!holder.is_identical_to(first) || check == CHECK_ALL_MAPS) {
+    // Check the holder map.
+    __ CheckMap(reg, Handle<Map>(holder->map()),
+                miss, DONT_DO_SMI_CHECK, ALLOW_ELEMENT_TRANSITION_MAPS);
+  }
 
   // Perform security check for access to the global object.
   ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded());
@@ -1023,9 +1035,11 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object,
 
 void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
                                                  Label* miss) {
-  __ jmp(success);
-  __ bind(miss);
-  GenerateLoadMiss(masm(), kind());
+  if (!miss->is_unused()) {
+    __ jmp(success);
+    __ bind(miss);
+    GenerateLoadMiss(masm(), kind());
+  }
 }
 
 
@@ -1035,12 +1049,10 @@ Register BaseLoadStubCompiler::CallbackHandlerFrontend(
     Handle<JSObject> holder,
     Handle<String> name,
     Label* success,
-    FrontendCheckType check,
     Handle<ExecutableAccessorInfo> callback) {
   Label miss;
 
-  Register reg = HandlerFrontendHeader(
-      object, object_reg, holder, name, &miss, check);
+  Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
 
   if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) {
     ASSERT(!reg.is(scratch2()));
@@ -1090,8 +1102,7 @@ void BaseLoadStubCompiler::NonexistentHandlerFrontend(
     Handle<GlobalObject> global) {
   Label miss;
 
-  Register reg = HandlerFrontendHeader(
-      object, receiver(), last, name, &miss, PERFORM_INITIAL_CHECKS);
+  Register reg = HandlerFrontendHeader(object, receiver(), last, name, &miss);
 
   // If the last object in the prototype chain is a global object,
   // check that the global property cell is empty.
@@ -1137,8 +1148,8 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   }
   __ PushAddress(ExternalReference::isolate_address());  // isolate
   __ push(name());  // name
-  // Save a pointer to where we pushed the arguments pointer.
-  // This will be passed as the const AccessorInfo& to the C++ callback.
+  // Save a pointer to where we pushed the arguments pointer.  This will be
+  // passed as the const ExecutableAccessorInfo& to the C++ callback.
 
 #if defined(__MINGW64__)
   Register accessor_info_arg = rdx;
@@ -2758,7 +2769,7 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
   __ ret(0);
 
   // Return the generated code.
-  return GetCode(Code::NONEXISTENT, factory()->empty_string());
+  return GetCode(Code::HANDLER_FRAGMENT, Code::NONEXISTENT, name);
 }
 
 
@@ -2832,8 +2843,9 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
   // rax is used as receiver(), which we would otherwise clobber before a
   // potential miss.
 
-  HandlerFrontendHeader(object, receiver(), Handle<JSObject>::cast(global),
-                        name, &miss, PERFORM_INITIAL_CHECKS);
+  __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
+  HandlerFrontendHeader(
+      object, receiver(), Handle<JSObject>::cast(global), name, &miss);
 
   // Get the value from the cell.
   __ Move(rbx, cell);
@@ -2857,7 +2869,7 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
   __ ret(0);
 
   // Return the generated code.
-  return GetCode(Code::NORMAL, name);
+  return GetCode(Code::IC_FRAGMENT, Code::NORMAL, name);
 }
 
 
@@ -2884,35 +2896,39 @@ Handle<Code> KeyedLoadStubCompiler::CompileLoadElement(
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
 
   // Return the generated code.
-  return GetCode(Code::NORMAL, factory()->empty_string());
+  return GetCode(Code::IC_FRAGMENT, Code::NORMAL, factory()->empty_string());
 }
 
 
-Handle<Code> KeyedLoadStubCompiler::CompileLoadPolymorphic(
+Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
     MapHandleList* receiver_maps,
-    CodeHandleList* handler_ics) {
-  // ----------- S t a t e -------------
-  //  -- rax    : key
-  //  -- rdx    : receiver
-  //  -- rsp[0] : return address
-  // -----------------------------------
+    CodeHandleList* handlers,
+    Handle<String> name,
+    Code::StubType type,
+    IcCheckType check) {
   Label miss;
-  __ JumpIfSmi(rdx, &miss);
 
-  Register map_reg = rbx;
-  __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset));
+  if (check == PROPERTY) {
+    GenerateNameCheck(name, this->name(), &miss);
+  }
+
+  __ JumpIfSmi(receiver(), &miss);
+  Register map_reg = scratch1();
+  __ movq(map_reg, FieldOperand(receiver(), HeapObject::kMapOffset));
   int receiver_count = receiver_maps->length();
   for (int current = 0; current < receiver_count; ++current) {
     // Check map and tail call if there's a match
     __ Cmp(map_reg, receiver_maps->at(current));
-    __ j(equal, handler_ics->at(current), RelocInfo::CODE_TARGET);
+    __ j(equal, handlers->at(current), RelocInfo::CODE_TARGET);
   }
 
   __  bind(&miss);
-  GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
+  GenerateLoadMiss(masm(), kind());
 
   // Return the generated code.
-  return GetCode(Code::NORMAL, factory()->empty_string(), POLYMORPHIC);
+  InlineCacheState state =
+      receiver_maps->length() > 1 ? POLYMORPHIC : MONOMORPHIC;
+  return GetCode(Code::IC_FRAGMENT, type, name, state);
 }
 
 
index a0fb06dd676ef1439d36c08e785aac9e934739e3..c45c7b61f25b1ca372802931098f80349377ac5e 100644 (file)
@@ -2422,7 +2422,7 @@ TEST(IncrementalMarkingClearsPolymorhpicIC) {
               v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
 
   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_before->ic_state() == MEGAMORPHIC);
+  CHECK(ic_before->ic_state() == POLYMORPHIC);
 
   // Fire context dispose notification.
   v8::V8::ContextDisposedNotification();