Watch for created string objects that are non-empty due to insertInitialShape, bug 701509.
authorBrian Hackett <bhackett1024@gmail.com>
Fri, 11 Nov 2011 07:50:12 -0800
changeset 82951 23746995da452579d8b1f8403b94d8eaa90112c6
parent 82950 ba62d6c8e943b92fc3cb19bdd52cde8f63c408bf
child 82952 f5fd65e8a4a2866470637222724e6db2d2be1eb6
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs701509
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Watch for created string objects that are non-empty due to insertInitialShape, bug 701509.
js/src/jsscope.cpp
js/src/vm/StringObject-inl.h
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -1382,17 +1382,41 @@ EmptyShape::insertInitialShape(JSContext
 {
     InitialShapeEntry::Lookup lookup(shape->getObjectClass(), proto, shape->getObjectParent(),
                                      shape->numFixedSlots());
 
     InitialShapeSet::Ptr p = cx->compartment->initialShapes.lookup(lookup);
     JS_ASSERT(p);
 
     InitialShapeEntry &entry = const_cast<InitialShapeEntry &>(*p);
+
+    /* The new shape had better be rooted at the old one. */
+#ifdef DEBUG
+    const Shape *nshape = shape;
+    while (!nshape->isEmptyShape())
+        nshape = nshape->previous();
+    JS_ASSERT(nshape == entry.shape);
+#endif
+
     entry.shape = shape;
+
+    /*
+     * This affects the shape that will be produced by the various NewObject
+     * methods, so clear any cache entry referring to the old shape. This is
+     * not required for correctness --- the NewObject must always check for a
+     * nativeEmpty() result and generate the appropriate properties if found.
+     * Clearing the cache entry avoids this duplicate regeneration.
+     */
+    NewObjectCache::Entry *cacheEntry = NULL;
+    if (cx->compartment->newObjectCache.lookup(shape->getObjectClass(),
+                                               shape->getObjectParent(),
+                                               gc::GetGCObjectKind(shape->numFixedSlots()),
+                                               &cacheEntry)) {
+        PodZero(cacheEntry);
+    }
 }
 
 void
 JSCompartment::sweepInitialShapeTable(JSContext *cx)
 {
     if (initialShapes.initialized()) {
         for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) {
             const InitialShapeEntry &entry = e.front();
--- a/js/src/vm/StringObject-inl.h
+++ b/js/src/vm/StringObject-inl.h
@@ -50,28 +50,30 @@ JSObject::asString()
     return static_cast<js::StringObject *>(const_cast<JSObject *>(this));
 }
 
 namespace js {
 
 inline bool
 StringObject::init(JSContext *cx, JSString *str)
 {
-    JS_ASSERT(nativeEmpty());
     JS_ASSERT(gc::GetGCKindSlots(getAllocKind()) == 2);
 
-    if (isDelegate()) {
-        if (!assignInitialShape(cx))
-            return false;
-    } else {
-        Shape *shape = assignInitialShape(cx);
-        if (!shape)
-            return false;
-        EmptyShape::insertInitialShape(cx, shape, getProto());
+    if (nativeEmpty()) {
+        if (isDelegate()) {
+            if (!assignInitialShape(cx))
+                return false;
+        } else {
+            Shape *shape = assignInitialShape(cx);
+            if (!shape)
+                return false;
+            EmptyShape::insertInitialShape(cx, shape, getProto());
+        }
     }
+
     JS_ASSERT(!nativeEmpty());
     JS_ASSERT(nativeLookup(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom))->slot() == LENGTH_SLOT);
 
     setStringThis(str);
     return true;
 }
 
 inline StringObject *