Revision: 9584
Author:   [email protected]
Date:     Tue Oct 11 09:02:45 2011
Log:      Refactor and fix polymorphic KeyedStoreIC creation

Review URL: http://codereview.chromium.org/8233011
http://code.google.com/p/v8/source/detail?r=9584

Modified:
 /branches/bleeding_edge/src/arm/stub-cache-arm.cc
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/ic.cc
 /branches/bleeding_edge/src/ic.h
 /branches/bleeding_edge/src/mips/stub-cache-mips.cc
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/stub-cache.h
 /branches/bleeding_edge/src/x64/stub-cache-x64.cc

=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Oct 11 02:33:00 2011 +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Oct 11 09:02:45 2011
@@ -3178,7 +3178,7 @@
 }


-MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
+MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic(
     MapList* receiver_maps,
     CodeList* handler_ics) {
   // ----------- S t a t e -------------
@@ -3274,64 +3274,10 @@
 }


-MaybeObject* KeyedStoreStubCompiler::CompileStoreElementWithTransition(
-    Map* transitioned_map,
-    Map* untransitioned_map_1,
-    Map* untransitioned_map_2) {
-  // ----------- S t a t e -------------
-  //  -- r0    : value
-  //  -- r1    : key
-  //  -- r2    : receiver
-  //  -- lr    : return address
-  //  -- r3    : scratch
-  // -----------------------------------
-
-  // The order of map occurrences in the generated code below is important.
-  // Both IC code and Crankshaft rely on |transitioned_map| being the first
-  // map in the stub.
-
-  Code* notransition_stub;
-  ElementsKind elements_kind = transitioned_map->elements_kind();
-  bool is_js_array = transitioned_map->instance_type() == JS_ARRAY_TYPE;
-  MaybeObject* maybe_stub =
-      KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
-  if (!maybe_stub->To(&notransition_stub)) return maybe_stub;
-
-  Label just_store, miss;
-  __ JumpIfSmi(r2, &miss);
-  __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
-  // r3: receiver->map().
-  __ mov(ip, Operand(Handle<Map>(transitioned_map)));
-  __ cmp(r3, ip);
-  __ b(eq, &just_store);
-  ASSERT_NE(untransitioned_map_1, NULL);
-  __ mov(ip, Operand(Handle<Map>(untransitioned_map_1)));
-  __ cmp(r3, ip);
-  Code* generic_stub = (strict_mode_ == kStrictMode)
- ? isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic_Strict)
-      : isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic);
-  __ Jump(Handle<Code>(generic_stub), RelocInfo::CODE_TARGET, eq);
-  if (untransitioned_map_2 != NULL) {
-    __ mov(ip, Operand(Handle<Map>(untransitioned_map_2)));
-    __ cmp(r3, ip);
-    __ Jump(Handle<Code>(generic_stub), RelocInfo::CODE_TARGET, eq);
-  }
-
-  __ bind(&miss);
-  Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
-  __ Jump(ic, RelocInfo::CODE_TARGET);
-
-  __ bind(&just_store);
-  __ Jump(Handle<Code>(notransition_stub), RelocInfo::CODE_TARGET);
-
-  // Return the generated code.
-  return GetCode(NORMAL, NULL, MEGAMORPHIC);
-}
-
-
-MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
+MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic(
     MapList* receiver_maps,
-    CodeList* handler_ics) {
+    CodeList* handler_stubs,
+    MapList* transitioned_maps) {
   // ----------- S t a t e -------------
   //  -- r0    : value
   //  -- r1    : key
@@ -3344,12 +3290,20 @@

   int receiver_count = receiver_maps->length();
   __ ldr(r3, FieldMemOperand(r2, HeapObject::kMapOffset));
-  for (int current = 0; current < receiver_count; ++current) {
-    Handle<Map> map(receiver_maps->at(current));
-    Handle<Code> code(handler_ics->at(current));
+  for (int i = 0; i < receiver_count; ++i) {
+    Handle<Map> map(receiver_maps->at(i));
+    Handle<Code> code(handler_stubs->at(i));
     __ mov(ip, Operand(map));
     __ cmp(r3, ip);
-    __ Jump(code, RelocInfo::CODE_TARGET, eq);
+    if (transitioned_maps->at(i) == NULL) {
+      __ Jump(code, RelocInfo::CODE_TARGET, eq);
+    } else {
+      Label next_map;
+      __ b(eq, &next_map);
+      __ mov(r4, Operand(Handle<Map>(transitioned_maps->at(i))));
+      __ Jump(code, RelocInfo::CODE_TARGET, al);
+      __ bind(&next_map);
+    }
   }

   __ bind(&miss);
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Oct 11 02:33:00 2011 +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Oct 11 09:02:45 2011
@@ -2755,81 +2755,32 @@
 }


-MaybeObject* KeyedStoreStubCompiler::CompileStoreElementWithTransition(
-    Map* transitioned_map,
-    Map* untransitioned_map_1,
-    Map* untransitioned_map_2) {
+MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic(
+    MapList* receiver_maps,
+    CodeList* handler_stubs,
+    MapList* transitioned_maps) {
   // ----------- S t a t e -------------
   //  -- eax    : value
   //  -- ecx    : key
   //  -- edx    : receiver
   //  -- esp[0] : return address
   // -----------------------------------
-
-  // The order of map occurrences in the generated code below is important.
-  // Both IC code and Crankshaft rely on |transitioned_map| being the first
-  // map in the stub.
-
-  Code* notransition_stub;
-  ElementsKind elements_kind = transitioned_map->elements_kind();
-  bool is_jsarray = transitioned_map->instance_type() == JS_ARRAY_TYPE;
-  MaybeObject* maybe_stub =
-      KeyedStoreElementStub(is_jsarray, elements_kind).TryGetCode();
-  if (!maybe_stub->To(&notransition_stub)) return maybe_stub;
-
-  Label just_store, miss;
+  Label miss;
   __ JumpIfSmi(edx, &miss, Label::kNear);
-  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
   // ebx: receiver->map().
-  __ cmp(ebx, Handle<Map>(transitioned_map));
-  __ j(equal, &just_store);
-  ASSERT_NE(untransitioned_map_1, NULL);
-  __ cmp(ebx, Handle<Map>(untransitioned_map_1));
-  // TODO(jkummerow): When we have specialized code to do the transition,
-  // call that code here, then jump to just_store when the call returns.
-  // <temporary: just use the generic stub>
-  Code* generic_stub = (strict_mode_ == kStrictMode)
- ? isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic_Strict)
-      : isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic);
-  __ j(equal, Handle<Code>(generic_stub));
-  // </temporary>
-  if (untransitioned_map_2 != NULL) {
-    __ cmp(ebx, Handle<Map>(untransitioned_map_2));
-    // <temporary: see above, same here>
-    __ j(equal, Handle<Code>(generic_stub));
-    // </temporary>
-  }
-  __ bind(&miss);
-  Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
-  __ jmp(ic, RelocInfo::CODE_TARGET);
-
-  __ bind(&just_store);
-  __ jmp(Handle<Code>(notransition_stub), RelocInfo::CODE_TARGET);
-
-  // Return the generated code.
-  return GetCode(NORMAL, NULL, MEGAMORPHIC);
-}
-
-
-MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
-    MapList* receiver_maps,
-    CodeList* handler_ics) {
-  // ----------- S t a t e -------------
-  //  -- eax    : value
-  //  -- ecx    : key
-  //  -- edx    : receiver
-  //  -- esp[0] : return address
-  // -----------------------------------
-  Label miss;
-  __ JumpIfSmi(edx, &miss);
-
-  Register map_reg = ebx;
-  __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset));
-  int receiver_count = receiver_maps->length();
-  for (int current = 0; current < receiver_count; ++current) {
-    Handle<Map> map(receiver_maps->at(current));
-    __ cmp(map_reg, map);
-    __ j(equal, Handle<Code>(handler_ics->at(current)));
+  for (int i = 0; i < receiver_maps->length(); ++i) {
+    Handle<Map> map(receiver_maps->at(i));
+    __ cmp(edi, map);
+    if (transitioned_maps->at(i) == NULL) {
+      __ j(equal, Handle<Code>(handler_stubs->at(i)));
+    } else {
+      Label next_map;
+      __ j(not_equal, &next_map, Label::kNear);
+      __ mov(ebx, Immediate(Handle<Map>(transitioned_maps->at(i))));
+      __ jmp(Handle<Code>(handler_stubs->at(i)), RelocInfo::CODE_TARGET);
+      __ bind(&next_map);
+    }
   }
   __ bind(&miss);
   Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss();
@@ -3269,7 +3220,7 @@
 }


-MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
+MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic(
     MapList* receiver_maps,
     CodeList* handler_ics) {
   // ----------- S t a t e -------------
=======================================
--- /branches/bleeding_edge/src/ic.cc   Tue Oct 11 02:33:00 2011
+++ /branches/bleeding_edge/src/ic.cc   Tue Oct 11 09:02:45 2011
@@ -1084,14 +1084,22 @@
 }


-MaybeObject* KeyedLoadIC::ConstructMegamorphicStub(
+MaybeObject* KeyedLoadIC::ComputePolymorphicStub(
     MapList* receiver_maps,
-    CodeList* targets,
     StrictModeFlag strict_mode) {
+  CodeList handler_ics(receiver_maps->length());
+  for (int i = 0; i < receiver_maps->length(); ++i) {
+    Map* receiver_map(receiver_maps->at(i));
+    MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
+        receiver_map, strict_mode);
+    Code* cached_stub;
+    if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
+    handler_ics.Add(cached_stub);
+  }
   Object* object;
   KeyedLoadStubCompiler compiler;
-  MaybeObject* maybe_code = compiler.CompileLoadMegamorphic(receiver_maps,
-                                                            targets);
+  MaybeObject* maybe_code = compiler.CompileLoadPolymorphic(receiver_maps,
+                                                            &handler_ics);
   if (!maybe_code->ToObject(&object)) return maybe_code;
   isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
   PROFILE(isolate(), CodeCreateEvent(
@@ -1625,13 +1633,16 @@
   } else {
     GetReceiverMapsForStub(target(), &target_receiver_maps);
   }
-  Map* new_map = receiver->map();
+  bool map_added =
+      AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map());
   if (IsTransitionStubKind(stub_kind)) {
     MaybeObject* maybe_map = ComputeTransitionedMap(receiver, stub_kind);
+    Map* new_map = NULL;
     if (!maybe_map->To(&new_map)) return maybe_map;
-  }
-  if (!AddOneReceiverMapIfMissing(&target_receiver_maps, new_map)) {
-    // If the miss wasn't due to an unseen map, a MEGAMORPHIC stub
+ map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map);
+  }
+  if (!map_added) {
+    // If the miss wasn't due to an unseen map, a polymorphic stub
     // won't help, use the generic stub.
     return generic_stub;
   }
@@ -1652,13 +1663,8 @@
     ASSERT(maybe_cached_stub->IsCode());
     return Code::cast(maybe_cached_stub);
   }
-  MaybeObject* maybe_stub = NULL;
-  if (IsTransitionStubKind(stub_kind)) {
-    maybe_stub = ComputePolymorphicStubWithTransition(
-        receiver, &target_receiver_maps, new_map, strict_mode);
-  } else {
- maybe_stub = ComputePolymorphicStub(&target_receiver_maps, strict_mode);
-  }
+  MaybeObject* maybe_stub =
+      ComputePolymorphicStub(&target_receiver_maps, strict_mode);
   Code* stub;
   if (!maybe_stub->To(&stub)) return maybe_stub;
MaybeObject* maybe_update = cache->Update(&target_receiver_maps, flags, stub);
@@ -1705,45 +1711,6 @@
   }
   return result;
 }
-
-
-MaybeObject* KeyedIC::ComputePolymorphicStubWithTransition(
-    JSObject* receiver,
-    MapList* receiver_maps,
-    Map* new_map,
-    StrictModeFlag strict_mode) {
-  Map* existing_transitionable_map = NULL;
-  for (int i = 0; i < receiver_maps->length(); ++i) {
-    Map* map = receiver_maps->at(i);
-    if (map != receiver->map() && map != new_map) {
-      existing_transitionable_map = map;
-      break;
-    }
-  }
-  KeyedStoreStubCompiler compiler(strict_mode);
-  return compiler.CompileStoreElementWithTransition(
-      new_map,
-      receiver->map(),
-      existing_transitionable_map);
-}
-
-
-MaybeObject* KeyedIC::ComputePolymorphicStub(
-    MapList* receiver_maps,
-    StrictModeFlag strict_mode) {
-  // Collect MONOMORPHIC stubs for all target_receiver_maps.
-  CodeList handler_ics(receiver_maps->length());
-  for (int i = 0; i < receiver_maps->length(); ++i) {
-    Map* receiver_map(receiver_maps->at(i));
-    MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
-        receiver_map, strict_mode);
-    Code* cached_stub;
-    if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
-    handler_ics.Add(cached_stub);
-  }
-  // Build the MEGAMORPHIC stub.
- return ConstructMegamorphicStub(receiver_maps, &handler_ics, strict_mode);
-}


 MaybeObject* KeyedIC::ComputeTransitionedMap(JSObject* receiver,
@@ -1768,14 +1735,88 @@
 }


-MaybeObject* KeyedStoreIC::ConstructMegamorphicStub(
+// If |map| is contained in |maps_list|, returns |map|; otherwise returns NULL.
+Map* GetMapIfPresent(Map* map, MapList* maps_list) {
+  for (int i = 0; i < maps_list->length(); ++i) {
+    if (maps_list->at(i) == map) return map;
+  }
+  return NULL;
+}
+
+
+// Returns the most generic transitioned map for |map| that's found in
+// |maps_list|, or NULL if no transitioned map for |map| is found at all.
+Map* GetTransitionedMap(Map* map, MapList* maps_list) {
+  ElementsKind elements_kind = map->elements_kind();
+  if (elements_kind == FAST_ELEMENTS) {
+    return NULL;
+  }
+  if (elements_kind == FAST_DOUBLE_ELEMENTS) {
+    bool dummy = true;
+ Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy);
+    if (fast_map == NULL) return NULL;
+    return GetMapIfPresent(fast_map, maps_list);
+  }
+  if (elements_kind == FAST_SMI_ONLY_ELEMENTS) {
+    bool dummy = true;
+ Map* double_map = map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
+                                                       &dummy);
+    // In the current implementation, if the DOUBLE map doesn't exist, the
+    // FAST map can't exist either.
+    if (double_map == NULL) return NULL;
+ Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy);
+    if (fast_map == NULL) {
+      return GetMapIfPresent(double_map, maps_list);
+    }
+ // Both double_map and fast_map are non-NULL. Return fast_map if it's in
+    // maps_list, double_map otherwise.
+    Map* fast_map_present = GetMapIfPresent(fast_map, maps_list);
+    if (fast_map_present != NULL) return fast_map_present;
+    return GetMapIfPresent(double_map, maps_list);
+  }
+  return NULL;
+}
+
+
+MaybeObject* KeyedStoreIC::ComputePolymorphicStub(
     MapList* receiver_maps,
-    CodeList* targets,
     StrictModeFlag strict_mode) {
+  // TODO(yangguo): <remove>
+  Code* generic_stub = (strict_mode == kStrictMode)
+ ? isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic_Strict)
+      : isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic);
+  // </remove>
+
+  // Collect MONOMORPHIC stubs for all target_receiver_maps.
+  CodeList handler_ics(receiver_maps->length());
+  MapList transitioned_maps(receiver_maps->length());
+  for (int i = 0; i < receiver_maps->length(); ++i) {
+    Map* receiver_map(receiver_maps->at(i));
+    MaybeObject* maybe_cached_stub = NULL;
+ Map* transitioned_map = GetTransitionedMap(receiver_map, receiver_maps);
+    if (transitioned_map != NULL) {
+      // TODO(yangguo): Enable this code!
+      // maybe_cached_stub = FastElementsConversionStub(
+      //     receiver_map->elements_kind(),  // original elements_kind
+      //     transitioned_map->elements_kind(),
+ // receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array
+      //     strict_mode_).TryGetCode();
+      // TODO(yangguo): <remove>
+      maybe_cached_stub = generic_stub;
+      // </remove>
+    } else {
+      maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
+          receiver_map, strict_mode);
+    }
+    Code* cached_stub;
+    if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
+    handler_ics.Add(cached_stub);
+    transitioned_maps.Add(transitioned_map);
+  }
   Object* object;
   KeyedStoreStubCompiler compiler(strict_mode);
-  MaybeObject* maybe_code = compiler.CompileStoreMegamorphic(receiver_maps,
-                                                             targets);
+  MaybeObject* maybe_code = compiler.CompileStorePolymorphic(
+      receiver_maps, &handler_ics, &transitioned_maps);
   if (!maybe_code->ToObject(&object)) return maybe_code;
   isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
   PROFILE(isolate(), CodeCreateEvent(
=======================================
--- /branches/bleeding_edge/src/ic.h    Tue Oct 11 02:33:00 2011
+++ /branches/bleeding_edge/src/ic.h    Tue Oct 11 09:02:45 2011
@@ -368,31 +368,21 @@
                            StrictModeFlag strict_mode,
                            Code* default_stub);

-  virtual MaybeObject* ConstructMegamorphicStub(
-      MapList* receiver_maps,
-      CodeList* targets,
-      StrictModeFlag strict_mode) = 0;
-
- private:
-  void GetReceiverMapsForStub(Code* stub, MapList* result);
+  virtual MaybeObject* ComputePolymorphicStub(MapList* receiver_maps,
+ StrictModeFlag strict_mode) = 0;

   MaybeObject* ComputeMonomorphicStubWithoutMapCheck(
       Map* receiver_map,
       StrictModeFlag strict_mode);

+ private:
+  void GetReceiverMapsForStub(Code* stub, MapList* result);
+
   MaybeObject* ComputeMonomorphicStub(JSObject* receiver,
                                       StubKind stub_kind,
                                       StrictModeFlag strict_mode,
                                       Code* default_stub);

-  MaybeObject* ComputePolymorphicStubWithTransition(JSObject* receiver,
-                                                    MapList* receiver_maps,
-                                                    Map* new_map,
- StrictModeFlag strict_mode);
-
-  MaybeObject* ComputePolymorphicStub(MapList* receiver_maps,
-                                      StrictModeFlag strict_mode);
-
MaybeObject* ComputeTransitionedMap(JSObject* receiver, StubKind stub_kind);

   static bool IsTransitionStubKind(StubKind stub_kind) {
@@ -440,9 +430,8 @@
  protected:
   virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }

-  virtual MaybeObject* ConstructMegamorphicStub(
+  virtual MaybeObject* ComputePolymorphicStub(
       MapList* receiver_maps,
-      CodeList* targets,
       StrictModeFlag strict_mode);

   virtual Code* string_stub() {
@@ -591,9 +580,8 @@
  protected:
   virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }

-  virtual MaybeObject* ConstructMegamorphicStub(
+  virtual MaybeObject* ComputePolymorphicStub(
       MapList* receiver_maps,
-      CodeList* targets,
       StrictModeFlag strict_mode);

   private:
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Thu Sep 22 04:30:04 2011 +++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Tue Oct 11 09:02:45 2011
@@ -3130,7 +3130,7 @@
 }


-MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
+MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic(
     MapList* receiver_maps,
     CodeList* handler_ics) {
   // ----------- S t a t e -------------
=======================================
--- /branches/bleeding_edge/src/objects.cc      Tue Oct 11 04:35:04 2011
+++ /branches/bleeding_edge/src/objects.cc      Tue Oct 11 09:02:45 2011
@@ -2163,15 +2163,16 @@
 }


-// Returns the contents of |map|'s descriptor array for the given string
-// (which might be NULL). |safe_to_add_transition| is set to false and NULL
-// is returned if adding transitions is not allowed.
-static Object* GetDescriptorContents(Map* map,
-                                     String* sentinel_name,
-                                     bool* safe_to_add_transition) {
+String* Map::elements_transition_sentinel_name() {
+  return GetHeap()->empty_symbol();
+}
+
+
+Object* Map::GetDescriptorContents(String* sentinel_name,
+                                   bool* safe_to_add_transition) {
   // Get the cached index for the descriptors lookup, or find and cache it.
-  DescriptorArray* descriptors = map->instance_descriptors();
- DescriptorLookupCache* cache = map->GetIsolate()->descriptor_lookup_cache();
+  DescriptorArray* descriptors = instance_descriptors();
+  DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache();
   int index = cache->Lookup(descriptors, sentinel_name);
   if (index == DescriptorLookupCache::kAbsent) {
     index = descriptors->Search(sentinel_name);
@@ -2190,31 +2191,20 @@
 }


-// Returns the map that |original_map| transitions to if its elements_kind
-// is changed to |elements_kind|, or NULL if no such map is cached yet.
-// |safe_to_add_transitions| is set to false if adding transitions is not
-// allowed.
-static Map* LookupElementsTransitionMap(Map* original_map,
-                                        ElementsKind elements_kind,
-                                        String* sentinel_name,
-                                        bool* safe_to_add_transition) {
+Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
+                                      bool* safe_to_add_transition) {
   // Special case: indirect SMI->FAST transition (cf. comment in
   // AddElementsTransition()).
-  if (original_map->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
+  if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
       elements_kind == FAST_ELEMENTS) {
-    Map* double_map = LookupElementsTransitionMap(
-        original_map,
-        FAST_DOUBLE_ELEMENTS,
-        sentinel_name,
-        safe_to_add_transition);
+ Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, + safe_to_add_transition);
     if (double_map == NULL) return double_map;
-    return LookupElementsTransitionMap(double_map,
-                                       FAST_ELEMENTS,
-                                       sentinel_name,
-                                       safe_to_add_transition);
+    return double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
+                                                   safe_to_add_transition);
   }
   Object* descriptor_contents = GetDescriptorContents(
-      original_map, sentinel_name, safe_to_add_transition);
+      elements_transition_sentinel_name(), safe_to_add_transition);
   if (descriptor_contents != NULL) {
     Map* maybe_transition_map =
         GetElementsTransitionMapFromDescriptor(descriptor_contents,
@@ -2226,41 +2216,34 @@
 }


-// Adds an entry to |original_map|'s descriptor array for a transition to
-// |transitioned_map| when its elements_kind is changed to |elements_kind|,
-// using |sentinel_name| as key for the entry.
-static MaybeObject* AddElementsTransition(Map* original_map,
-                                          ElementsKind elements_kind,
-                                          Map* transitioned_map,
-                                          String* sentinel_name) {
+MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
+                                        Map* transitioned_map) {
   // The map transition graph should be a tree, therefore the transition
   // from SMI to FAST elements is not done directly, but by going through
   // DOUBLE elements first.
-  if (original_map->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
+  if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
       elements_kind == FAST_ELEMENTS) {
     bool safe_to_add = true;
-    Map* double_map = LookupElementsTransitionMap(
-        original_map, FAST_DOUBLE_ELEMENTS, sentinel_name, &safe_to_add);
+    Map* double_map = this->LookupElementsTransitionMap(
+        FAST_DOUBLE_ELEMENTS, &safe_to_add);
// This method is only called when safe_to_add_transition has been found
     // to be true earlier.
     ASSERT(safe_to_add);

     if (double_map == NULL) {
-      MaybeObject* maybe_map = original_map->CopyDropTransitions();
+      MaybeObject* maybe_map = this->CopyDropTransitions();
       if (!maybe_map->To(&double_map)) return maybe_map;
       double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
-      MaybeObject* maybe_double_transition = AddElementsTransition(
-          original_map, FAST_DOUBLE_ELEMENTS, double_map, sentinel_name);
+      MaybeObject* maybe_double_transition = this->AddElementsTransition(
+          FAST_DOUBLE_ELEMENTS, double_map);
if (maybe_double_transition->IsFailure()) return maybe_double_transition;
     }
-    return AddElementsTransition(
-        double_map, FAST_ELEMENTS, transitioned_map, sentinel_name);
+ return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map);
   }

-  DescriptorArray* descriptors = original_map->instance_descriptors();
   bool safe_to_add_transition = true;
   Object* descriptor_contents = GetDescriptorContents(
-      original_map, sentinel_name, &safe_to_add_transition);
+      elements_transition_sentinel_name(), &safe_to_add_transition);
   // This method is only called when safe_to_add_transition has been found
   // to be true earlier.
   ASSERT(safe_to_add_transition);
@@ -2272,24 +2255,22 @@
     return maybe_new_contents;
   }

-  ElementsTransitionDescriptor desc(sentinel_name, new_contents);
+  ElementsTransitionDescriptor desc(elements_transition_sentinel_name(),
+                                    new_contents);
   Object* new_descriptors;
   MaybeObject* maybe_new_descriptors =
-      descriptors->CopyInsert(&desc, KEEP_TRANSITIONS);
+      instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS);
   if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
     return maybe_new_descriptors;
   }
-  descriptors = DescriptorArray::cast(new_descriptors);
-  original_map->set_instance_descriptors(descriptors);
-  return original_map;
+  set_instance_descriptors(DescriptorArray::cast(new_descriptors));
+  return this;
 }


 MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind to_kind) {
-  Heap* current_heap = GetHeap();
   Map* current_map = map();
   ElementsKind from_kind = current_map->elements_kind();
-  String* elements_transition_sentinel_name = current_heap->empty_symbol();

   if (from_kind == to_kind) return current_map;

@@ -2309,9 +2290,8 @@
   if (safe_to_add_transition) {
     // It's only safe to manipulate the descriptor array if it would be
     // safe to add a transition.
-    Map* maybe_transition_map = LookupElementsTransitionMap(
-        current_map, to_kind, elements_transition_sentinel_name,
-        &safe_to_add_transition);
+    Map* maybe_transition_map = current_map->LookupElementsTransitionMap(
+        to_kind, &safe_to_add_transition);
     if (maybe_transition_map != NULL) {
       return maybe_transition_map;
     }
@@ -2334,8 +2314,8 @@
(GetIsolate()->context()->global_context()->object_function()->map() !=
        map());
   if (allow_map_transition) {
-    MaybeObject* maybe_transition = AddElementsTransition(
-        current_map, to_kind, new_map, elements_transition_sentinel_name);
+    MaybeObject* maybe_transition =
+        current_map->AddElementsTransition(to_kind, new_map);
     if (maybe_transition->IsFailure()) return maybe_transition;
   }
   return new_map;
=======================================
--- /branches/bleeding_edge/src/objects.h       Tue Oct 11 01:41:19 2011
+++ /branches/bleeding_edge/src/objects.h       Tue Oct 11 09:02:45 2011
@@ -4269,6 +4269,24 @@
   bool EquivalentTo(Map* other) {
     return EquivalentToForNormalization(other, KEEP_INOBJECT_PROPERTIES);
   }
+
+ // Returns the contents of this map's descriptor array for the given string.
+  // May return NULL. |safe_to_add_transition| is set to false and NULL
+  // is returned if adding transitions is not allowed.
+  Object* GetDescriptorContents(String* sentinel_name,
+                                bool* safe_to_add_transitions);
+
+  // Returns the map that this map transitions to if its elements_kind
+  // is changed to |elements_kind|, or NULL if no such map is cached yet.
+  // |safe_to_add_transitions| is set to false if adding transitions is not
+  // allowed.
+  Map* LookupElementsTransitionMap(ElementsKind elements_kind,
+                                   bool* safe_to_add_transition);
+
+  // Adds an entry to this map's descriptor array for a transition to
+ // |transitioned_map| when its elements_kind is changed to | elements_kind|.
+  MaybeObject* AddElementsTransition(ElementsKind elements_kind,
+                                     Map* transitioned_map);

   // Dispatched behavior.
 #ifdef OBJECT_PRINT
@@ -4387,6 +4405,7 @@
                               kSize> BodyDescriptor;

  private:
+  String* elements_transition_sentinel_name();
   DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
 };

=======================================
--- /branches/bleeding_edge/src/stub-cache.h    Tue Oct 11 02:33:00 2011
+++ /branches/bleeding_edge/src/stub-cache.h    Tue Oct 11 09:02:45 2011
@@ -641,7 +641,7 @@

   MUST_USE_RESULT MaybeObject* CompileLoadElement(Map* receiver_map);

-  MUST_USE_RESULT MaybeObject* CompileLoadMegamorphic(
+  MUST_USE_RESULT MaybeObject* CompileLoadPolymorphic(
       MapList* receiver_maps,
       CodeList* handler_ics);

@@ -700,14 +700,10 @@

   MUST_USE_RESULT MaybeObject* CompileStoreElement(Map* receiver_map);

-  MUST_USE_RESULT MaybeObject* CompileStoreElementWithTransition(
-      Map* transitioned_map,
-      Map* untransitioned_map_1,
-      Map* untransitioned_map_2 = NULL);
-
-  MUST_USE_RESULT MaybeObject* CompileStoreMegamorphic(
+  MUST_USE_RESULT MaybeObject* CompileStorePolymorphic(
       MapList* receiver_maps,
-      CodeList* handler_ics);
+      CodeList* handler_stubs,
+      MapList* transitioned_maps);

   static void GenerateStoreFastElement(MacroAssembler* masm,
                                        bool is_js_array,
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Oct 11 02:33:00 2011 +++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Oct 11 09:02:45 2011
@@ -2603,59 +2603,10 @@
 }


-MaybeObject* KeyedStoreStubCompiler::CompileStoreElementWithTransition(
-    Map* transitioned_map,
-    Map* untransitioned_map_1,
-    Map* untransitioned_map_2) {
-  // ----------- S t a t e -------------
-  //  -- rax    : value
-  //  -- rcx    : key
-  //  -- rdx    : receiver
-  //  -- rsp[0] : return address
-  // -----------------------------------
-
-  // The order of map occurrences in the generated code below is important.
-  // Both IC code and Crankshaft rely on |transitioned_map| being the first
-  // map in the stub.
-
-  Code* notransition_stub;
-  ElementsKind elements_kind = transitioned_map->elements_kind();
-  bool is_js_array = transitioned_map->instance_type() == JS_ARRAY_TYPE;
-  MaybeObject* maybe_stub =
-      KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
-  if (!maybe_stub->To(&notransition_stub)) return maybe_stub;
-
-  Label just_store, miss;
-  __ JumpIfSmi(rdx, &miss, Label::kNear);
-  __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
-  // rbx: receiver->map().
-  __ Cmp(rbx, Handle<Map>(transitioned_map));
-  __ j(equal, &just_store);
-  ASSERT_NE(untransitioned_map_1, NULL);
-  __ Cmp(rbx, Handle<Map>(untransitioned_map_1));
-  Code* generic_stub = (strict_mode_ == kStrictMode)
- ? isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic_Strict)
-      : isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic);
-  __ j(equal, Handle<Code>(generic_stub), RelocInfo::CODE_TARGET);
-  if (untransitioned_map_2 != NULL) {
-    __ Cmp(rbx, Handle<Map>(untransitioned_map_2));
-    __ j(equal, Handle<Code>(generic_stub), RelocInfo::CODE_TARGET);
-  }
-  __ bind(&miss);
-  Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
-  __ jmp(ic, RelocInfo::CODE_TARGET);
-
-  __ bind(&just_store);
-  __ jmp(Handle<Code>(notransition_stub), RelocInfo::CODE_TARGET);
-
-  // Return the generated code.
-  return GetCode(NORMAL, NULL, MEGAMORPHIC);
-}
-
-
-MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic(
+MaybeObject* KeyedStoreStubCompiler::CompileStorePolymorphic(
     MapList* receiver_maps,
-    CodeList* handler_ics) {
+    CodeList* handler_stubs,
+    MapList* transitioned_maps) {
   // ----------- S t a t e -------------
   //  -- rax    : value
   //  -- rcx    : key
@@ -2663,18 +2614,25 @@
   //  -- rsp[0] : return address
   // -----------------------------------
   Label miss;
-  __ JumpIfSmi(rdx, &miss);
-
-  Register map_reg = rbx;
-  __ movq(map_reg, FieldOperand(rdx, HeapObject::kMapOffset));
+  __ JumpIfSmi(rdx, &miss, Label::kNear);
+
+  __ movq(rdi, FieldOperand(rdx, HeapObject::kMapOffset));
   int receiver_count = receiver_maps->length();
-  for (int current = 0; current < receiver_count; ++current) {
+  for (int i = 0; i < receiver_count; ++i) {
     // Check map and tail call if there's a match
-    Handle<Map> map(receiver_maps->at(current));
-    __ Cmp(map_reg, map);
-    __ j(equal,
-         Handle<Code>(handler_ics->at(current)),
-         RelocInfo::CODE_TARGET);
+    Handle<Map> map(receiver_maps->at(i));
+    __ Cmp(rdi, map);
+    if (transitioned_maps->at(i) == NULL) {
+ __ j(equal, Handle<Code>(handler_stubs->at(i)), RelocInfo::CODE_TARGET);
+    } else {
+      Label next_map;
+      __ j(not_equal, &next_map, Label::kNear);
+      __ movq(rbx,
+              Handle<Map>(transitioned_maps->at(i)),
+              RelocInfo::EMBEDDED_OBJECT);
+      __ jmp(Handle<Code>(handler_stubs->at(i)), RelocInfo::CODE_TARGET);
+      __ bind(&next_map);
+    }
   }

   __ bind(&miss);
@@ -3110,7 +3068,7 @@
 }


-MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic(
+MaybeObject* KeyedLoadStubCompiler::CompileLoadPolymorphic(
     MapList* receiver_maps,
     CodeList* handler_ics) {
   // ----------- S t a t e -------------

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to