Capture missing globals from current environment, not the tree entry map when extending a side exit (495958, r=graydon).
authorAndreas Gal <gal@mozilla.com>
Wed, 03 Jun 2009 12:43:38 -0700
changeset 25869 5bb3a53e5ddda80bfeaca6d300103ce41ed5e3d6
parent 25868 4484277f94346ea90e7df5afcb8cea9096548674
child 25870 b35ad456cbf6c50475f6e43cf41707d4ed7b2356
child 25885 692408b4952470b766c57583501056dd912b37a7
push id1645
push userrsayre@mozilla.com
push dateThu, 04 Jun 2009 16:54:53 +0000
reviewersgraydon
bugs495958
milestone1.9.1pre
Capture missing globals from current environment, not the tree entry map when extending a side exit (495958, r=graydon).
js/src/jstracer.cpp
js/src/jstracer.h
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -1313,29 +1313,16 @@ TypeMap::captureMissingGlobalTypes(JSCon
 bool
 TypeMap::matches(TypeMap& other) const
 {
     if (length() != other.length())
         return false;
     return !memcmp(data(), other.data(), length());
 }
 
-/* Use the provided storage area to create a new type map that contains the partial type map
-   with the rest of it filled up from the complete type map. */
-static void
-mergeTypeMaps(uint8** partial, unsigned* plength, uint8* complete, unsigned clength, uint8* mem)
-{
-    unsigned l = *plength;
-    JS_ASSERT(l < clength);
-    memcpy(mem, *partial, l * sizeof(uint8));
-    memcpy(mem + l, complete + l, (clength - l) * sizeof(uint8));
-    *partial = mem;
-    *plength = clength;
-}
-
 /* Specializes a tree to any missing globals, including any dependent trees. */
 static JS_REQUIRES_STACK void
 specializeTreesToMissingGlobals(JSContext* cx, TreeInfo* root)
 {
     TreeInfo* ti = root;
 
     ti->typeMap.captureMissingGlobalTypes(cx, *ti->globalSlots, ti->nStackTypes);
     JS_ASSERT(ti->globalSlots->length() == ti->typeMap.length() - ti->nStackTypes);
@@ -2095,39 +2082,26 @@ TraceRecorder::import(LIns* base, ptrdif
                         (void*)p, name, typestr[t & 7], t >> 3);)
 #endif
 }
 
 JS_REQUIRES_STACK void
 TraceRecorder::import(TreeInfo* treeInfo, LIns* sp, unsigned stackSlots, unsigned ngslots,
                       unsigned callDepth, uint8* typeMap)
 {
-    /* If we get a partial list that doesn't have all the types (i.e. recording from a side
-       exit that was recorded but we added more global slots later), merge the missing types
-       from the entry type map. This is safe because at the loop edge we verify that we
-       have compatible types for all globals (entry type and loop edge type match). While
-       a different trace of the tree might have had a guard with a different type map for
-       these slots we just filled in here (the guard we continue from didn't know about them),
-       since we didn't take that particular guard the only way we could have ended up here
-       is if that other trace had at its end a compatible type distribution with the entry
-       map. Since thats exactly what we used to fill in the types our current side exit
-       didn't provide, this is always safe to do. */
-
-    uint8* globalTypeMap = typeMap + stackSlots;
-    unsigned length = treeInfo->nGlobalTypes();
-
     /*
-     * This is potentially the typemap of the side exit and thus shorter than the tree's
-     * global type map.
+     * If we get a partial list that doesn't have all the types, capture the missing types
+     * from the current environment.
      */
-    if (ngslots < length) {
-        mergeTypeMaps(&globalTypeMap/*out param*/, &ngslots/*out param*/,
-                      treeInfo->globalTypeMap(), length,
-                      (uint8*)alloca(sizeof(uint8) * length));
-    }
+    TypeMap fullTypeMap(typeMap, stackSlots + ngslots);
+    if (ngslots < treeInfo->globalSlots->length()) {
+        fullTypeMap.captureMissingGlobalTypes(cx, *treeInfo->globalSlots, stackSlots);
+        ngslots = treeInfo->globalSlots->length();
+    }
+    uint8* globalTypeMap = fullTypeMap.data() + stackSlots;
     JS_ASSERT(ngslots == treeInfo->nGlobalTypes());
 
     /*
      * Check whether there are any values on the stack we have to unbox and do that first
      * before we waste any time fetching the state from the stack.
      */
     ptrdiff_t offset = -treeInfo->nativeStackBase;
     uint8* m = typeMap;
--- a/js/src/jstracer.h
+++ b/js/src/jstracer.h
@@ -72,16 +72,23 @@ class Queue : public avmplus::GCObject {
     }
 public:
     Queue(unsigned max = 16) {
         this->_max = max;
         this->_len = 0;
         this->_data = (T*)malloc(max * sizeof(T));
     }
 
+    Queue(T* data, unsigned length) {
+        this->_max =
+        this->_len = length;
+        this->_data = (T*)malloc(length * sizeof(T));
+        memcpy(this->_data, data, length);
+    }
+
     ~Queue() {
         free(_data);
     }
 
     bool contains(T a) {
         for (unsigned n = 0; n < _len; ++n) {
             if (_data[n] == a)
                 return true;
@@ -185,16 +192,22 @@ public:
         clearDemotability();
     }
 };
 
 typedef Queue<uint16> SlotList;
 
 class TypeMap : public Queue<uint8> {
 public:
+    TypeMap() : Queue<uint8>() {
+    }
+
+    TypeMap(uint8* partial, unsigned length) : Queue<uint8>(partial, length) {
+    }
+
     JS_REQUIRES_STACK void captureTypes(JSContext* cx, SlotList& slots, unsigned callDepth);
     JS_REQUIRES_STACK void captureMissingGlobalTypes(JSContext* cx,
                                                      SlotList& slots,
                                                      unsigned stackSlots);
     bool matches(TypeMap& other) const;
 };
 
 enum ExitType {