]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - API/JSClassRef.cpp
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / API / JSClassRef.cpp
index afde7ce1a201efbdcd122e1aeed8537c0f0a52e9..452412e33f5f3ee76cd11e9342af79837810008a 100644 (file)
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. 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
 #include "JSClassRef.h"
 
 #include "APICast.h"
+#include "Identifier.h"
+#include "InitializeThreading.h"
 #include "JSCallbackObject.h"
+#include "JSGlobalObject.h"
 #include "JSObjectRef.h"
-#include <runtime/InitializeThreading.h>
-#include <runtime/JSGlobalObject.h>
-#include <runtime/ObjectPrototype.h>
-#include <runtime/Identifier.h>
+#include "ObjectPrototype.h"
+#include "JSCInlines.h"
+#include <wtf/text/StringHash.h>
+#include <wtf/unicode/UTF8.h>
 
+using namespace std;
 using namespace JSC;
+using namespace WTF::Unicode;
 
 const JSClassDefinition kJSClassDefinitionEmpty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
@@ -52,26 +57,26 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass*
     , callAsConstructor(definition->callAsConstructor)
     , hasInstance(definition->hasInstance)
     , convertToType(definition->convertToType)
-    , m_className(UString::Rep::createFromUTF8(definition->className))
-    , m_staticValues(0)
-    , m_staticFunctions(0)
+    , m_className(String::fromUTF8(definition->className))
 {
     initializeThreading();
 
     if (const JSStaticValue* staticValue = definition->staticValues) {
-        m_staticValues = new OpaqueJSClassStaticValuesTable();
+        m_staticValues = adoptPtr(new OpaqueJSClassStaticValuesTable);
         while (staticValue->name) {
-            m_staticValues->add(UString::Rep::createFromUTF8(staticValue->name),
-                              new StaticValueEntry(staticValue->getProperty, staticValue->setProperty, staticValue->attributes));
+            String valueName = String::fromUTF8(staticValue->name);
+            if (!valueName.isNull())
+                m_staticValues->set(valueName.impl(), std::make_unique<StaticValueEntry>(staticValue->getProperty, staticValue->setProperty, staticValue->attributes, valueName));
             ++staticValue;
         }
     }
 
     if (const JSStaticFunction* staticFunction = definition->staticFunctions) {
-        m_staticFunctions = new OpaqueJSClassStaticFunctionsTable();
+        m_staticFunctions = adoptPtr(new OpaqueJSClassStaticFunctionsTable);
         while (staticFunction->name) {
-            m_staticFunctions->add(UString::Rep::createFromUTF8(staticFunction->name),
-                                 new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes));
+            String functionName = String::fromUTF8(staticFunction->name);
+            if (!functionName.isNull())
+                m_staticFunctions->set(functionName.impl(), std::make_unique<StaticFunctionEntry>(staticFunction->callAsFunction, staticFunction->attributes));
             ++staticFunction;
         }
     }
@@ -82,25 +87,22 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass*
 
 OpaqueJSClass::~OpaqueJSClass()
 {
-    ASSERT(!m_className.rep()->identifierTable());
+    // The empty string is shared across threads & is an identifier, in all other cases we should have done a deep copy in className(), below. 
+    ASSERT(!m_className.length() || !m_className.impl()->isAtomic());
 
+#ifndef NDEBUG
     if (m_staticValues) {
         OpaqueJSClassStaticValuesTable::const_iterator end = m_staticValues->end();
-        for (OpaqueJSClassStaticValuesTable::const_iterator it = m_staticValues->begin(); it != end; ++it) {
-            ASSERT(!it->first->identifierTable());
-            delete it->second;
-        }
-        delete m_staticValues;
+        for (OpaqueJSClassStaticValuesTable::const_iterator it = m_staticValues->begin(); it != end; ++it)
+            ASSERT(!it->key->isAtomic());
     }
 
     if (m_staticFunctions) {
         OpaqueJSClassStaticFunctionsTable::const_iterator end = m_staticFunctions->end();
-        for (OpaqueJSClassStaticFunctionsTable::const_iterator it = m_staticFunctions->begin(); it != end; ++it) {
-            ASSERT(!it->first->identifierTable());
-            delete it->second;
-        }
-        delete m_staticFunctions;
+        for (OpaqueJSClassStaticFunctionsTable::const_iterator it = m_staticFunctions->begin(); it != end; ++it)
+            ASSERT(!it->key->isAtomic());
     }
+#endif
     
     if (prototypeClass)
         JSClassRelease(prototypeClass);
@@ -111,102 +113,65 @@ PassRefPtr<OpaqueJSClass> OpaqueJSClass::createNoAutomaticPrototype(const JSClas
     return adoptRef(new OpaqueJSClass(definition, 0));
 }
 
-static void clearReferenceToPrototype(JSObjectRef prototype)
+PassRefPtr<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* clientDefinition)
 {
-    OpaqueJSClassContextData* jsClassData = static_cast<OpaqueJSClassContextData*>(JSObjectGetPrivate(prototype));
-    ASSERT(jsClassData);
-    jsClassData->cachedPrototype = 0;
-}
-
-PassRefPtr<OpaqueJSClass> OpaqueJSClass::create(const JSClassDefinition* definition)
-{
-    if (const JSStaticFunction* staticFunctions = definition->staticFunctions) {
-        // copy functions into a prototype class
-        JSClassDefinition protoDefinition = kJSClassDefinitionEmpty;
-        protoDefinition.staticFunctions = staticFunctions;
-        protoDefinition.finalize = clearReferenceToPrototype;
-        
-        // We are supposed to use JSClassRetain/Release but since we know that we currently have
-        // the only reference to this class object we cheat and use a RefPtr instead.
-        RefPtr<OpaqueJSClass> protoClass = adoptRef(new OpaqueJSClass(&protoDefinition, 0));
-
-        // remove functions from the original class
-        JSClassDefinition objectDefinition = *definition;
-        objectDefinition.staticFunctions = 0;
+    JSClassDefinition definition = *clientDefinition; // Avoid modifying client copy.
 
-        return adoptRef(new OpaqueJSClass(&objectDefinition, protoClass.get()));
-    }
-
-    return adoptRef(new OpaqueJSClass(definition, 0));
+    JSClassDefinition protoDefinition = kJSClassDefinitionEmpty;
+    protoDefinition.finalize = 0;
+    swap(definition.staticFunctions, protoDefinition.staticFunctions); // Move static functions to the prototype.
+    
+    // We are supposed to use JSClassRetain/Release but since we know that we currently have
+    // the only reference to this class object we cheat and use a RefPtr instead.
+    RefPtr<OpaqueJSClass> protoClass = adoptRef(new OpaqueJSClass(&protoDefinition, 0));
+    return adoptRef(new OpaqueJSClass(&definition, protoClass.get()));
 }
 
-OpaqueJSClassContextData::OpaqueJSClassContextData(OpaqueJSClass* jsClass)
+OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::VM&, OpaqueJSClass* jsClass)
     : m_class(jsClass)
-    , cachedPrototype(0)
 {
     if (jsClass->m_staticValues) {
-        staticValues = new OpaqueJSClassStaticValuesTable;
+        staticValues = std::make_unique<OpaqueJSClassStaticValuesTable>();
         OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end();
         for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) {
-            ASSERT(!it->first->identifierTable());
-            staticValues->add(UString::Rep::createCopying(it->first->data(), it->first->size()),
-                              new StaticValueEntry(it->second->getProperty, it->second->setProperty, it->second->attributes));
+            ASSERT(!it->key->isAtomic());
+            String valueName = it->key->isolatedCopy();
+            staticValues->add(valueName.impl(), std::make_unique<StaticValueEntry>(it->value->getProperty, it->value->setProperty, it->value->attributes, valueName));
         }
-            
-    } else
-        staticValues = 0;
-        
+    }
 
     if (jsClass->m_staticFunctions) {
-        staticFunctions = new OpaqueJSClassStaticFunctionsTable;
+        staticFunctions = std::make_unique<OpaqueJSClassStaticFunctionsTable>();
         OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end();
         for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) {
-            ASSERT(!it->first->identifierTable());
-            staticFunctions->add(UString::Rep::createCopying(it->first->data(), it->first->size()),
-                              new StaticFunctionEntry(it->second->callAsFunction, it->second->attributes));
+            ASSERT(!it->key->isAtomic());
+            staticFunctions->add(it->key->isolatedCopy(), std::make_unique<StaticFunctionEntry>(it->value->callAsFunction, it->value->attributes));
         }
-            
-    } else
-        staticFunctions = 0;
-}
-
-OpaqueJSClassContextData::~OpaqueJSClassContextData()
-{
-    if (staticValues) {
-        deleteAllValues(*staticValues);
-        delete staticValues;
-    }
-
-    if (staticFunctions) {
-        deleteAllValues(*staticFunctions);
-        delete staticFunctions;
     }
 }
 
 OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec)
 {
-    OpaqueJSClassContextData*& contextData = exec->globalData().opaqueJSClassData.add(this, 0).first->second;
+    std::unique_ptr<OpaqueJSClassContextData>& contextData = exec->lexicalGlobalObject()->opaqueJSClassData().add(this, nullptr).iterator->value;
     if (!contextData)
-        contextData = new OpaqueJSClassContextData(this);
+        contextData = std::make_unique<OpaqueJSClassContextData>(exec->vm(), this);
     return *contextData;
 }
 
-UString OpaqueJSClass::className()
+String OpaqueJSClass::className()
 {
-    // Make a deep copy, so that the caller has no chance to put the original into IdentifierTable.
-    return UString(m_className.data(), m_className.size());
+    // Make a deep copy, so that the caller has no chance to put the original into AtomicStringTable.
+    return m_className.isolatedCopy();
 }
 
 OpaqueJSClassStaticValuesTable* OpaqueJSClass::staticValues(JSC::ExecState* exec)
 {
-    OpaqueJSClassContextData& jsClassData = contextData(exec);
-    return jsClassData.staticValues;
+    return contextData(exec).staticValues.get();
 }
 
 OpaqueJSClassStaticFunctionsTable* OpaqueJSClass::staticFunctions(JSC::ExecState* exec)
 {
-    OpaqueJSClassContextData& jsClassData = contextData(exec);
-    return jsClassData.staticFunctions;
+    return contextData(exec).staticFunctions.get();
 }
 
 /*!
@@ -226,19 +191,22 @@ JSObject* OpaqueJSClass::prototype(ExecState* exec)
      *       |        |          |
      *  DerivedClass  |  DerivedClassPrototype
      */
-    
+
     if (!prototypeClass)
         return 0;
 
     OpaqueJSClassContextData& jsClassData = contextData(exec);
 
-    if (!jsClassData.cachedPrototype) {
-        // Recursive, but should be good enough for our purposes
-        jsClassData.cachedPrototype = new (exec) JSCallbackObject<JSObject>(exec, exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData); // set jsClassData as the object's private data, so it can clear our reference on destruction
-        if (parentClass) {
-            if (JSObject* prototype = parentClass->prototype(exec))
-                jsClassData.cachedPrototype->setPrototype(prototype);
-        }
+    if (JSObject* prototype = jsClassData.cachedPrototype.get())
+        return prototype;
+
+    // Recursive, but should be good enough for our purposes
+    JSObject* prototype = JSCallbackObject<JSDestructibleObject>::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData); // set jsClassData as the object's private data, so it can clear our reference on destruction
+    if (parentClass) {
+        if (JSObject* parentPrototype = parentClass->prototype(exec))
+            prototype->setPrototype(exec->vm(), parentPrototype);
     }
-    return jsClassData.cachedPrototype;
+
+    jsClassData.cachedPrototype = Weak<JSObject>(prototype);
+    return prototype;
 }