Revision: 11685
Author:   [email protected]
Date:     Thu May 31 02:27:39 2012
Log:      Revert r11681 https://chromiumcodereview.appspot.com/10448011
(Keep track of which maps are associated with prototype objects so we can tune the fast-case vs. hash map heuristics accordingly.). Reverting because the dict-mode to fast case transformation loses the iteration order information.
Review URL: https://chromiumcodereview.appspot.com/10448097
http://code.google.com/p/v8/source/detail?r=11685

Deleted:
 /branches/bleeding_edge/test/mjsunit/fast-prototype.js
Modified:
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/runtime.h
 /branches/bleeding_edge/test/cctest/test-heap.cc

=======================================
--- /branches/bleeding_edge/test/mjsunit/fast-prototype.js Wed May 30 07:40:57 2012
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Flags: --allow-natives-syntax
-
-// Check that objects that are used for prototypes are in the fast mode.
-
-function Super() {
-}
-
-
-function Sub() {
-}
-
-
-function AddProps(obj) {
-  for (var i = 0; i < 26; i++) {
-    obj["x" + i] = 0;
-  }
-}
-
-
-function DoProtoMagic(proto, set__proto__) {
-  if (set__proto__) {
-    (new Sub()).__proto__ = proto;
-  } else {
-    Sub.prototype = proto;
-  }
-}
-
-
-function test(use_new, add_first, set__proto__, same_map_as) {
-  var proto = use_new ? new Super() : {};
-
-  // New object is fast.
-  assertTrue(%HasFastProperties(proto));
-
-  if (add_first) {
-    AddProps(proto);
-    // Adding this many properties makes it slow.
-    assertFalse(%HasFastProperties(proto));
-    DoProtoMagic(proto, set__proto__);
-    // Making it a prototype makes it fast again.
-    assertTrue(%HasFastProperties(proto));
-  } else {
-    DoProtoMagic(proto, set__proto__);
-    // Still fast
-    assertTrue(%HasFastProperties(proto));
-    AddProps(proto);
-    // Setting the bit means it is still fast with all these properties.
-    assertTrue(%HasFastProperties(proto));
-  }
-  if (same_map_as && !add_first) {
-    assertTrue(%HaveSameMap(same_map_as, proto));
-  }
-  return proto;
-}
-
-
-for (var i = 0; i < 4; i++) {
-  var set__proto__ = ((i & 1) != 0);
-  var use_new = ((i & 2) != 0);
-
-  test(use_new, true, set__proto__);
-
-  var last = test(use_new, false, set__proto__);
-  test(use_new, false, set__proto__, last);
-}
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Wed May 30 08:15:17 2012
+++ /branches/bleeding_edge/src/objects-inl.h   Thu May 31 02:27:39 2012
@@ -1611,21 +1611,13 @@
 }


-bool JSObject::TooManyFastProperties(int properties) {
+int JSObject::MaxFastProperties() {
   // Allow extra fast properties if the object has more than
-  // kFastPropertiesSoftLimit in-object properties. When this is the case,
+  // kMaxFastProperties in-object properties. When this is the case,
   // it is very unlikely that the object is being used as a dictionary
   // and there is a good chance that allowing more map transitions
   // will be worth it.
-  int inobject = map()->inobject_properties();
-
-  int limit;
-  if (map()->used_for_prototype()) {
-    limit = Max(inobject, kMaxFastProperties);
-  } else {
-    limit = Max(inobject, kFastPropertiesSoftLimit);
-  }
-  return properties >= limit;
+  return Max(map()->inobject_properties(), kMaxFastProperties);
 }


@@ -2936,20 +2928,6 @@
 bool Map::is_shared() {
   return ((1 << kIsShared) & bit_field3()) != 0;
 }
-
-
-void Map::set_used_for_prototype(bool value) {
-  if (value) {
-    set_bit_field3(bit_field3() | (1 << kUsedForPrototype));
-  } else {
-    set_bit_field3(bit_field3() & ~(1 << kUsedForPrototype));
-  }
-}
-
-
-bool Map::used_for_prototype() {
-  return ((1 << kUsedForPrototype) & bit_field3()) != 0;
-}


 JSFunction* Map::unchecked_constructor() {
@@ -4101,7 +4079,6 @@
   if (map()->has_non_instance_prototype()) return map()->constructor();
   return instance_prototype();
 }
-

 bool JSFunction::should_have_prototype() {
   return map()->function_with_prototype();
=======================================
--- /branches/bleeding_edge/src/objects.cc      Wed May 30 08:15:17 2012
+++ /branches/bleeding_edge/src/objects.cc      Thu May 31 02:27:39 2012
@@ -1580,7 +1580,7 @@
   }

   if (map()->unused_property_fields() == 0) {
-    if (TooManyFastProperties(properties()->length())) {
+    if (properties()->length() > MaxFastProperties()) {
       Object* obj;
       { MaybeObject* maybe_obj =
             NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
@@ -1833,7 +1833,7 @@
                                                 Object* new_value,
PropertyAttributes attributes) {
   if (map()->unused_property_fields() == 0 &&
-      TooManyFastProperties(properties()->length())) {
+      properties()->length() > MaxFastProperties()) {
     Object* obj;
     { MaybeObject* maybe_obj =
           NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
@@ -5038,7 +5038,6 @@
cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
   return new_map;
 }
-

 void Map::UpdateCodeCache(Handle<Map> map,
                           Handle<String> name,
@@ -7620,59 +7619,11 @@
   if (code->kind() != Code::FUNCTION) return true;
   return code->optimizable();
 }
-
-
-MaybeObject* JSObject::OptimizeAsPrototype() {
-  if (IsGlobalObject()) return this;
-
-  // Make sure prototypes are fast objects and their maps have the bit set
-  // so they remain fast.
-  Map* proto_map = map();
-  if (!proto_map->used_for_prototype()) {
-    if (!HasFastProperties()) {
-      MaybeObject* new_proto = TransformToFastProperties(0);
-      if (new_proto->IsFailure()) return new_proto;
-      ASSERT(new_proto == this);
-      proto_map = map();
-      if (!proto_map->is_shared()) {
-        proto_map->set_used_for_prototype(true);
-      }
-    } else {
-      Heap* heap = GetHeap();
- // We use the hole value as a singleton key in the prototype transition
-      // map so that we don't multiply the number of maps unnecessarily.
-      Map* new_map =
-          proto_map->GetPrototypeTransition(heap->the_hole_value());
-      if (new_map == NULL) {
-        MaybeObject* maybe_new_map = proto_map->CopyDropTransitions();
-        if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
-        new_map->set_used_for_prototype(true);
-        MaybeObject* ok =
-            proto_map->PutPrototypeTransition(heap->the_hole_value(),
-                                              new_map);
-        if (ok->IsFailure()) return ok;
-      }
-      ASSERT(!proto_map->is_shared() && !new_map->is_shared());
-      set_map(new_map);
-    }
-  }
-  return this;
-}


 MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
   ASSERT(value->IsJSReceiver());
   Heap* heap = GetHeap();
-
-  // First some logic for the map of the prototype to make sure the
-  // used_for_prototype flag is set.
-  if (value->IsJSObject()) {
-    MaybeObject* ok = JSObject::cast(value)->OptimizeAsPrototype();
-    if (ok->IsFailure()) return ok;
-  }
-
- // Now some logic for the maps of the objects that are created by using this
-  // function as a constructor.
   if (has_initial_map()) {
     // If the function has allocated the initial map
     // replace it with a copy containing the new prototype.
@@ -8844,7 +8795,7 @@
 }


-Map* Map::GetPrototypeTransition(Object* prototype) {
+Object* Map::GetPrototypeTransition(Object* prototype) {
   FixedArray* cache = prototype_transitions();
   int number_of_transitions = NumberOfProtoTransitions();
   const int proto_offset =
@@ -8854,7 +8805,8 @@
   for (int i = 0; i < number_of_transitions; i++) {
     if (cache->get(proto_offset + i * step) == prototype) {
       Object* map = cache->get(map_offset + i * step);
-      return Map::cast(map);
+      ASSERT(map->IsMap());
+      return map;
     }
   }
   return NULL;
@@ -8962,26 +8914,21 @@
   // Nothing to do if prototype is already set.
   if (map->prototype() == value) return value;

-  if (value->IsJSObject()) {
-    MaybeObject* ok = JSObject::cast(value)->OptimizeAsPrototype();
-    if (ok->IsFailure()) return ok;
-  }
-
-  Map* new_map = map->GetPrototypeTransition(value);
+  Object* new_map = map->GetPrototypeTransition(value);
   if (new_map == NULL) {
     { MaybeObject* maybe_new_map = map->CopyDropTransitions();
-      if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
+      if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
     }

     { MaybeObject* maybe_new_cache =
-          map->PutPrototypeTransition(value, new_map);
+          map->PutPrototypeTransition(value, Map::cast(new_map));
       if (maybe_new_cache->IsFailure()) return maybe_new_cache;
     }

-    new_map->set_prototype(value);
-  }
-  ASSERT(new_map->prototype() == value);
-  real_receiver->set_map(new_map);
+    Map::cast(new_map)->set_prototype(value);
+  }
+  ASSERT(Map::cast(new_map)->prototype() == value);
+  real_receiver->set_map(Map::cast(new_map));

   heap->ClearInstanceofCache();
   ASSERT(size == Size());
=======================================
--- /branches/bleeding_edge/src/objects.h       Wed May 30 08:15:17 2012
+++ /branches/bleeding_edge/src/objects.h       Thu May 31 02:27:39 2012
@@ -1583,8 +1583,6 @@
   MUST_USE_RESULT MaybeObject* DeleteNormalizedProperty(String* name,
                                                         DeleteMode mode);

-  MUST_USE_RESULT MaybeObject* OptimizeAsPrototype();
-
   // Retrieve interceptors.
   InterceptorInfo* GetNamedInterceptor();
   InterceptorInfo* GetIndexedInterceptor();
@@ -2055,7 +2053,7 @@
   // Maximal number of fast properties for the JSObject. Used to
   // restrict the number of map transitions to avoid an explosion in
   // the number of maps for objects used as dictionaries.
-  inline bool TooManyFastProperties(int properties);
+  inline int MaxFastProperties();

   // Maximal number of elements (numbered 0 .. kMaxElementCount - 1).
   // Also maximal value of JSArray's length property.
@@ -2077,8 +2075,7 @@
   static const int kMaxUncheckedOldFastElementsLength = 500;

   static const int kInitialMaxFastElementArray = 100000;
-  static const int kFastPropertiesSoftLimit = 12;
-  static const int kMaxFastProperties = 32;
+  static const int kMaxFastProperties = 12;
   static const int kMaxInstanceSize = 255 * kPointerSize;
   // When extending the backing storage for property values, we increase
// its size by more than the 1 entry necessary, so sequentially adding fields
@@ -4678,16 +4675,9 @@
   // behavior. If true, the map should never be modified, instead a clone
   // should be created and modified.
   inline void set_is_shared(bool value);
+
   inline bool is_shared();

- // Tells whether the map is used for an object that is a prototype for another - // object or is the prototype on a function. Such maps are made faster by - // tweaking the heuristics that distinguish between regular object-oriented - // objects and the objects that are being used as hash maps. This flag is
-  // for optimization, not correctness.
-  inline void set_used_for_prototype(bool value);
-  inline bool used_for_prototype();
-
   // Tells whether the instance needs security checks when accessing its
   // properties.
   inline void set_is_access_check_needed(bool access_check_needed);
@@ -4876,18 +4866,9 @@

   void TraverseTransitionTree(TraverseCallback callback, void* data);

- // When you set the prototype of an object using the __proto__ accessor you - // need a new map for the object (the prototype is stored in the map). In - // order not to multiply maps unnecessarily we store these as transitions in - // the original map. That way we can transition to the same map if the same
-  // prototype is set, rather than creating a new map every time.  The
- // transitions are in the form of a map where the keys are prototype objects
-  // and the values are the maps the are transitioned to.  The special key
-  // the_hole denotes the map we should transition to when the
-  // used_for_prototype flag is set.
   static const int kMaxCachedPrototypeTransitions = 256;

-  Map* GetPrototypeTransition(Object* prototype);
+  Object* GetPrototypeTransition(Object* prototype);

   MUST_USE_RESULT MaybeObject* PutPrototypeTransition(Object* prototype,
                                                       Map* map);
@@ -4980,7 +4961,6 @@
   // Bit positions for bit field 3
   static const int kIsShared = 0;
   static const int kFunctionWithPrototype = 1;
-  static const int kUsedForPrototype = 2;

// Layout of the default cache. It holds alternating name and code objects.
   static const int kCodeCacheEntrySize = 2;
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Wed May 30 07:40:57 2012
+++ /branches/bleeding_edge/src/runtime.cc      Thu May 31 02:27:39 2012
@@ -13455,8 +13455,6 @@
 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
 ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
-// Properties test sitting with elements tests - not fooling anyone.
-ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties)

 #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION

=======================================
--- /branches/bleeding_edge/src/runtime.h       Wed May 30 07:40:57 2012
+++ /branches/bleeding_edge/src/runtime.h       Thu May 31 02:27:39 2012
@@ -380,7 +380,6 @@
   F(HasExternalUnsignedIntElements, 1, 1) \
   F(HasExternalFloatElements, 1, 1) \
   F(HasExternalDoubleElements, 1, 1) \
-  F(HasFastProperties, 1, 1) \
   F(TransitionElementsSmiToDouble, 1, 1) \
   F(TransitionElementsDoubleToObject, 1, 1) \
   F(HaveSameMap, 2, 1) \
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap.cc Wed May 30 07:40:57 2012 +++ /branches/bleeding_edge/test/cctest/test-heap.cc Thu May 31 02:27:39 2012
@@ -1579,23 +1579,18 @@
           *v8::Handle<v8::Object>::Cast(
               v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));

-  // Verify that only dead prototype transitions are cleared.  There is an
-  // extra, 11th, prototype transition on the Object map, which is the
-  // transition to a map with the used_for_prototype flag set (the key is
-  // the_hole).
-  CHECK_EQ(11, baseObject->map()->NumberOfProtoTransitions());
+  // Verify that only dead prototype transitions are cleared.
+  CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
   HEAP->CollectAllGarbage(Heap::kNoGCFlags);
-  const int transitions = 11 - 3;
-  CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
+  CHECK_EQ(10 - 3, baseObject->map()->NumberOfProtoTransitions());

   // Verify that prototype transitions array was compacted.
   FixedArray* trans = baseObject->map()->prototype_transitions();
-  for (int i = 0; i < transitions; i++) {
+  for (int i = 0; i < 10 - 3; i++) {
     int j = Map::kProtoTransitionHeaderSize +
         i * Map::kProtoTransitionElementsPerEntry;
     CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
-    Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
-    CHECK(proto->IsTheHole() || proto->IsJSObject());
+ CHECK(trans->get(j + Map::kProtoTransitionPrototypeOffset)->IsJSObject());
   }

// Make sure next prototype is placed on an old-space evacuation candidate.

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

Reply via email to