* 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 };
, 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;
}
}
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);
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();
}
/*!
* | | |
* 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;
}