Most built-in properties are not deletable
https://bugs.webkit.org/show_bug.cgi?id=61014

Reviewed by Filip Pizlo.

Source/JavaScriptCore: 

Our static hash tables don't allow for deleting properties.
This is the cause of a bunch of expected failures in LayoutTests/sputnik.

This fixes the problem by reifying all static functions immediately prior
to the first deletion.  Reification is tracked by a flag on the structure,
so properties will no longer 'bounce-back' on later access.

Theoretically there could probably also be an issue with custom accessor
properties, but we probably do not really require any of these to be
Configurable anyway. I'll follow up with a separate patch to address this.

* runtime/ClassInfo.h:
(JSC::ClassInfo::hasStaticProperties):
    - detects static property tables.
* runtime/JSObject.cpp:
(JSC::JSObject::deleteProperty):
    - call reifyStaticFunctions before deletion.
(JSC::JSObject::reifyStaticFunctions):
    - If the class has static functions, set them up now.
* runtime/JSObject.h:
(JSC::JSObject::staticFunctionsReified):
    - returns true if static functions have been reified,
      and as such should no longer be added.
* runtime/Lookup.cpp:
(JSC::setUpStaticFunctionSlot):
    - If static functions have been reified do not add.
* runtime/Lookup.h:
(JSC::HashTable::ConstIterator::ConstIterator):
(JSC::HashTable::ConstIterator::operator->):
(JSC::HashTable::ConstIterator::operator*):
(JSC::HashTable::ConstIterator::operator!=):
(JSC::HashTable::ConstIterator::operator++):
(JSC::HashTable::ConstIterator::skipInvalidKeys):
(JSC::HashTable::begin):
(JSC::HashTable::end):
(JSC::getStaticPropertySlot):
(JSC::getStaticPropertyDescriptor):
(JSC::getStaticFunctionSlot):
(JSC::getStaticFunctionDescriptor):
    - setUpStaticFunctionSlot may not add, returns a bool.
(JSC::lookupPut):
    - remove redundant branch.
* runtime/Structure.cpp:
(JSC::Structure::Structure):
    - initialize new flag in constructors.
* runtime/Structure.h:
(JSC::Structure::staticFunctionsReified):
(JSC::Structure::setStaticFunctionsReified):
    - added flag

LayoutTests: 

Mostly checking in passing results, added a couple of extra test cases to fast/js/delete-syntax.

* fast/js/delete-syntax-expected.txt:
* fast/js/script-tests/delete-syntax.js:
* ietestcenter/Javascript/11.4.1-4.a-10-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.4_Array/15.4.4/S15.4.4_A1.1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/S15.5.4.1_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/S15.5.4_A1-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.5_String/15.5.4/S15.5.4_A3-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.6_Boolean/15.6.2/S15.6.2.1_A4-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.6_Boolean/15.6.3/15.6.3.1_Boolean.prototype/S15.6.3.1_A1-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.6_Boolean/15.6.4/S15.6.4_A1-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.7_Number/15.7.2/S15.7.2.1_A4-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.7_Number/15.7.3/15.7.3.1_Number.prototype/S15.7.3.1_A2_T1-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.7_Number/15.7.4/S15.7.4_A1-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.4/15.9.4.2_Date.parse/S15.9.4.2_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.4/15.9.4.3_Date.UTC/S15.9.4.3_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.10_Date.prototype.getFullYear/S15.9.5.10_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.11_Date.prototype.getUTCFullYear/S15.9.5.11_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.12_Date.prototype.getMonth/S15.9.5.12_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.13_Date.prototype.getUTCMonth/S15.9.5.13_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.14_Date.prototype.getDate/S15.9.5.14_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.15_Date.prototype.getUTCDate/S15.9.5.15_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.16_Date.prototype.getDay/S15.9.5.16_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.17_Date.prototype.getUTCDay/S15.9.5.17_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.18_Date.prototype.getHours/S15.9.5.18_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.19_Date.prototype.getUTCHours/S15.9.5.19_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.20_Date.prototype.getMinutes/S15.9.5.20_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.21_Date.prototype.getUTCMinutes/S15.9.5.21_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.22_Date.prototype.getSeconds/S15.9.5.22_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.23_Date.prototype.getUTCSeconds/S15.9.5.23_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.24_Date.prototype.getMilliseconds/S15.9.5.24_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.25_Date.prototype.getUTCMilliseconds/S15.9.5.25_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.26_Date.prototype.getTimezoneOffset/S15.9.5.26_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.27_Date.prototype.setTime/S15.9.5.27_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.28_Date.prototype.setMilliseconds/S15.9.5.28_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.29_Date.prototype.setUTCMilliseconds/S15.9.5.29_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.2_Date.prototype.toString/S15.9.5.2_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.30_Date.prototype.setSeconds/S15.9.5.30_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.31_Date.prototype.setUTCSeconds/S15.9.5.31_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.32_Date.prototype.setMinutes/S15.9.5.32_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.33_Date.prototype.setUTCMinutes/S15.9.5.33_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.34_Date.prototype.setHours/S15.9.5.34_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.35_Date.prototype.setUTCHours/S15.9.5.35_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.36_Date.prototype.setDate/S15.9.5.36_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.37_Date.prototype.setUTCDate/S15.9.5.37_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.38_Date.prototype.setMonth/S15.9.5.38_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.39_Date.prototype.setUTCMonth/S15.9.5.39_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.3_Date.prototype.toDateString/S15.9.5.3_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.40_Date.prototype.setFullYear/S15.9.5.40_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.41_Date.prototype.setUTCFullYear/S15.9.5.41_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.42_Date.prototype.toUTCString/S15.9.5.42_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.4_Date.prototype.toTimeString/S15.9.5.4_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.5_Date.prototype.toLocaleString/S15.9.5.5_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.6_Date.prototype.toLocaleDateString/S15.9.5.6_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.7_Date.prototype.toLocaleTimeString/S15.9.5.7_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.8_Date.prototype.valueOf/S15.9.5.8_A1_T2-expected.txt:
* sputnik/Conformance/15_Native_Objects/15.9_Date/15.9.5/15.9.5.9_Date.prototype.getTime/S15.9.5.9_A1_T2-expected.txt:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@97536 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h
index f076a79..96023b8 100644
--- a/Source/JavaScriptCore/runtime/ClassInfo.h
+++ b/Source/JavaScriptCore/runtime/ClassInfo.h
@@ -75,6 +75,15 @@
             return false;
         }
 
+        bool hasStaticProperties() const
+        {
+            for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
+                if (ci->staticPropHashTable || ci->classPropHashTableGetterFunction)
+                    return true;
+            }
+            return false;
+        }
+
         const HashTable* staticPropHashTable;
         typedef const HashTable* (*ClassPropHashTableGetterFunction)(ExecState*);
         const ClassPropHashTableGetterFunction classPropHashTableGetterFunction;
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index d9bf668..0da4760 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -256,6 +256,10 @@
 bool JSObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
 {
     JSObject* thisObject = static_cast<JSObject*>(cell);
+
+    if (!thisObject->staticFunctionsReified())
+        thisObject->reifyStaticFunctionsForDelete(exec);
+
     unsigned attributes;
     JSCell* specificValue;
     if (thisObject->structure()->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) {
@@ -573,6 +577,37 @@
         setStructure(globalData, Structure::preventExtensionsTransition(globalData, structure()));
 }
 
+// This presently will flatten to an uncachable dictionary; this is suitable
+// for use in delete, we may want to do something different elsewhere.
+void JSObject::reifyStaticFunctionsForDelete(ExecState* exec)
+{
+    ASSERT(!staticFunctionsReified());
+    JSGlobalData& globalData = exec->globalData();
+
+    // If this object's ClassInfo has no static properties, then nothing to reify!
+    // We can safely set the flag to avoid the expensive check again in the future.
+    if (!classInfo()->hasStaticProperties()) {
+        structure()->setStaticFunctionsReified();
+        return;
+    }
+
+    if (!structure()->isUncacheableDictionary())
+        setStructure(globalData, Structure::toUncacheableDictionaryTransition(globalData, structure()));
+
+    for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
+        const HashTable* hashTable = info->propHashTable(globalObject()->globalExec());
+        if (!hashTable)
+            continue;
+        PropertySlot slot;
+        for (HashTable::ConstIterator iter = hashTable->begin(globalData); iter != hashTable->end(globalData); ++iter) {
+            if (iter->attributes() & Function)
+                setUpStaticFunctionSlot(globalObject()->globalExec(), *iter, this, Identifier(&globalData, iter->key()), slot);
+        }
+    }
+
+    structure()->setStaticFunctionsReified();
+}
+
 void JSObject::removeDirect(JSGlobalData& globalData, const Identifier& propertyName)
 {
     if (structure()->get(globalData, propertyName) == WTF::notFound)
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 87c6b44..380cec8 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -74,7 +74,7 @@
         friend class JIT;
         friend class JSCell;
         friend class MarkedBlock;
-        friend void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
+        friend bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
 
     public:
         typedef JSCell Base;
@@ -210,6 +210,9 @@
         bool isFrozen(JSGlobalData& globalData) { return structure()->isFrozen(globalData); }
         bool isExtensible() { return structure()->isExtensible(); }
 
+        bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
+        void reifyStaticFunctionsForDelete(ExecState* exec);
+
         void allocatePropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize);
         bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage.get()) == static_cast<const void*>(this + 1); }
 
diff --git a/Source/JavaScriptCore/runtime/Lookup.cpp b/Source/JavaScriptCore/runtime/Lookup.cpp
index 9946d41..cfda655 100644
--- a/Source/JavaScriptCore/runtime/Lookup.cpp
+++ b/Source/JavaScriptCore/runtime/Lookup.cpp
@@ -71,13 +71,18 @@
     }
 }
 
-void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
+bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
 {
     ASSERT(thisObj->globalObject());
     ASSERT(entry->attributes() & Function);
     WriteBarrierBase<Unknown>* location = thisObj->getDirectLocation(exec->globalData(), propertyName);
 
     if (!location) {
+        // If a property is ever deleted from an object with a static table, then we reify
+        // all static functions at that time - after this we shouldn't be re-adding anything.
+        if (thisObj->staticFunctionsReified())
+            return false;
+    
         JSFunction* function;
         JSGlobalObject* globalObject = thisObj->globalObject();
 #if ENABLE(JIT)
@@ -92,6 +97,7 @@
     }
 
     slot.setValue(thisObj, location->get(), thisObj->offsetForLocation(location));
+    return true;
 }
 
 } // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Lookup.h b/Source/JavaScriptCore/runtime/Lookup.h
index 8b0b8d9..d3592df 100644
--- a/Source/JavaScriptCore/runtime/Lookup.h
+++ b/Source/JavaScriptCore/runtime/Lookup.h
@@ -176,6 +176,63 @@
             return entry(identifier);
         }
 
+        class ConstIterator {
+        public:
+            ConstIterator(const HashTable* table, int position)
+                : m_table(table)
+                , m_position(position)
+            {
+                skipInvalidKeys();
+            }
+
+            const HashEntry* operator->()
+            {
+                return &m_table->table[m_position];
+            }
+
+            const HashEntry* operator*()
+            {
+                return &m_table->table[m_position];
+            }
+
+            bool operator!=(const ConstIterator& other)
+            {
+                ASSERT(m_table == other.m_table);
+                return m_position != other.m_position;
+            }
+            
+            ConstIterator& operator++()
+            {
+                ASSERT(m_position < m_table->compactSize);
+                ++m_position;
+                skipInvalidKeys();
+                return *this;
+            }
+
+        private:
+            void skipInvalidKeys()
+            {
+                ASSERT(m_position <= m_table->compactSize);
+                while (m_position < m_table->compactSize && !m_table->table[m_position].key())
+                    ++m_position;
+                ASSERT(m_position <= m_table->compactSize);
+            }
+            
+            const HashTable* m_table;
+            int m_position;
+        };
+
+        ConstIterator begin(JSGlobalData& globalData) const
+        {
+            initializeIfNeeded(&globalData);
+            return ConstIterator(this, 0);
+        }
+        ConstIterator end(JSGlobalData& globalData) const
+        {
+            initializeIfNeeded(&globalData);
+            return ConstIterator(this, compactSize);
+        }
+
     private:
         ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
         {
@@ -199,7 +256,7 @@
         void createTable(JSGlobalData*) const;
     };
 
-    void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
+    bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
 
     /**
      * This method does it all (looking in the hashtable, checking for function
@@ -216,10 +273,9 @@
             return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
 
         if (entry->attributes() & Function)
-            setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
-        else
-            slot.setCacheableCustom(thisObj, entry->propertyGetter());
+            return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
 
+        slot.setCacheableCustom(thisObj, entry->propertyGetter());
         return true;
     }
 
@@ -232,11 +288,14 @@
             return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
  
         PropertySlot slot;
-        if (entry->attributes() & Function)
-            setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
-        else
-            slot.setCustom(thisObj, entry->propertyGetter());
+        if (entry->attributes() & Function) {
+            bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+            if (present)
+                descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
+            return present;
+        }
 
+        slot.setCustom(thisObj, entry->propertyGetter());
         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
         return true;
     }
@@ -256,8 +315,7 @@
         if (!entry)
             return false;
 
-        setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
-        return true;
+        return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
     }
     
     /**
@@ -276,9 +334,10 @@
             return false;
         
         PropertySlot slot;
-        setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
-        descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
-        return true;
+        bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+        if (present)
+            descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
+        return present;
     }
 
     /**
@@ -331,12 +390,10 @@
         if (!entry)
             return false;
 
-        if (entry->attributes() & Function) { // function: put as override property
-            if (LIKELY(value.isCell()))
-                thisObj->putDirect(exec->globalData(), propertyName, value.asCell());
-            else
-                thisObj->putDirect(exec->globalData(), propertyName, value);
-        } else if (!(entry->attributes() & ReadOnly))
+        // If this is a function put it as an override property.
+        if (entry->attributes() & Function)
+            thisObj->putDirect(exec->globalData(), propertyName, value);
+        else if (!(entry->attributes() & ReadOnly))
             entry->propertyPutter()(exec, thisObj, value);
 
         return true;
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index 479df56..3aa9dcf 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -172,6 +172,7 @@
     , m_specificFunctionThrashCount(0)
     , m_preventExtensions(false)
     , m_didTransition(false)
+    , m_staticFunctionReified(false)
 {
 }
 
@@ -192,6 +193,7 @@
     , m_specificFunctionThrashCount(0)
     , m_preventExtensions(false)
     , m_didTransition(false)
+    , m_staticFunctionReified(false)
 {
 }
 
@@ -210,6 +212,7 @@
     , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount)
     , m_preventExtensions(previous->m_preventExtensions)
     , m_didTransition(true)
+    , m_staticFunctionReified(previous->m_staticFunctionReified)
 {
     if (previous->m_globalObject)
         m_globalObject.set(globalData, this, previous->m_globalObject.get());
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index 235b682..3b14b94 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -26,6 +26,7 @@
 #ifndef Structure_h
 #define Structure_h
 
+#include "ClassInfo.h"
 #include "Identifier.h"
 #include "JSCell.h"
 #include "JSType.h"
@@ -162,6 +163,16 @@
         JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
         void getPropertyNames(JSGlobalData&, PropertyNameArray&, EnumerationMode mode);
 
+        bool staticFunctionsReified()
+        {
+            return m_staticFunctionReified;
+        }
+
+        void setStaticFunctionsReified()
+        {
+            m_staticFunctionReified = true;
+        }
+
         const ClassInfo* classInfo() const { return m_classInfo; }
 
         static ptrdiff_t prototypeOffset()
@@ -281,7 +292,7 @@
         unsigned m_specificFunctionThrashCount : 2;
         unsigned m_preventExtensions : 1;
         unsigned m_didTransition : 1;
-        // 8 free bits
+        unsigned m_staticFunctionReified;
     };
 
     inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName)