X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/9dae56ea45a0f5f8136a5c93d6f3a7f99399ca73..6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174:/API/JSClassRef.cpp?ds=inline diff --git a/API/JSClassRef.cpp b/API/JSClassRef.cpp index afde7ce..08fa5c5 100644 --- a/API/JSClassRef.cpp +++ b/API/JSClassRef.cpp @@ -33,11 +33,29 @@ #include #include #include +#include +#include +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 }; +static inline UString tryCreateStringFromUTF8(const char* string) +{ + if (!string) + return UString(); + + size_t length = strlen(string); + Vector buffer(length); + UChar* p = buffer.data(); + if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length)) + return UString(); + + return UString(buffer.data(), p - buffer.data()); +} + OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* protoClass) : parentClass(definition->parentClass) , prototypeClass(0) @@ -52,26 +70,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(tryCreateStringFromUTF8(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)); + UString valueName = tryCreateStringFromUTF8(staticValue->name); + if (!valueName.isNull()) + m_staticValues->set(valueName.impl(), adoptPtr(new StaticValueEntry(staticValue->getProperty, staticValue->setProperty, staticValue->attributes))); ++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)); + UString functionName = tryCreateStringFromUTF8(staticFunction->name); + if (!functionName.isNull()) + m_staticFunctions->set(functionName.impl(), adoptPtr(new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes))); ++staticFunction; } } @@ -82,25 +100,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()->isIdentifier()); +#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->first->isIdentifier()); } 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->first->isIdentifier()); } +#endif if (prototypeClass) JSClassRelease(prototypeClass); @@ -111,102 +126,64 @@ PassRefPtr OpaqueJSClass::createNoAutomaticPrototype(const JSClas return adoptRef(new OpaqueJSClass(definition, 0)); } -static void clearReferenceToPrototype(JSObjectRef prototype) +PassRefPtr OpaqueJSClass::create(const JSClassDefinition* clientDefinition) { - OpaqueJSClassContextData* jsClassData = static_cast(JSObjectGetPrivate(prototype)); - ASSERT(jsClassData); - jsClassData->cachedPrototype = 0; -} - -PassRefPtr 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 protoClass = adoptRef(new OpaqueJSClass(&protoDefinition, 0)); - - // remove functions from the original class - JSClassDefinition objectDefinition = *definition; - objectDefinition.staticFunctions = 0; - - return adoptRef(new OpaqueJSClass(&objectDefinition, protoClass.get())); - } + JSClassDefinition definition = *clientDefinition; // Avoid modifying client copy. - 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 protoClass = adoptRef(new OpaqueJSClass(&protoDefinition, 0)); + return adoptRef(new OpaqueJSClass(&definition, protoClass.get())); } -OpaqueJSClassContextData::OpaqueJSClassContextData(OpaqueJSClass* jsClass) +OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::JSGlobalData&, OpaqueJSClass* jsClass) : m_class(jsClass) - , cachedPrototype(0) { if (jsClass->m_staticValues) { - staticValues = new OpaqueJSClassStaticValuesTable; + staticValues = adoptPtr(new 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->first->isIdentifier()); + staticValues->add(StringImpl::create(it->first->characters(), it->first->length()), adoptPtr(new StaticValueEntry(it->second->getProperty, it->second->setProperty, it->second->attributes))); } - - } else - staticValues = 0; - + } if (jsClass->m_staticFunctions) { - staticFunctions = new OpaqueJSClassStaticFunctionsTable; + staticFunctions = adoptPtr(new 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->first->isIdentifier()); + staticFunctions->add(StringImpl::create(it->first->characters(), it->first->length()), adoptPtr(new StaticFunctionEntry(it->second->callAsFunction, it->second->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; + OwnPtr& contextData = exec->globalData().opaqueJSClassData.add(this, nullptr).iterator->second; if (!contextData) - contextData = new OpaqueJSClassContextData(this); + contextData = adoptPtr(new OpaqueJSClassContextData(exec->globalData(), this)); return *contextData; } UString 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()); + return UString(m_className.characters(), m_className.length()); } 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,7 +203,7 @@ JSObject* OpaqueJSClass::prototype(ExecState* exec) * | | | * DerivedClass | DerivedClassPrototype */ - + if (!prototypeClass) return 0; @@ -234,11 +211,11 @@ JSObject* OpaqueJSClass::prototype(ExecState* exec) if (!jsClassData.cachedPrototype) { // Recursive, but should be good enough for our purposes - jsClassData.cachedPrototype = new (exec) JSCallbackObject(exec, exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData); // set jsClassData as the object's private data, so it can clear our reference on destruction + jsClassData.cachedPrototype = PassWeak(JSCallbackObject::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), prototypeClass, &jsClassData), 0); // 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); + jsClassData.cachedPrototype->setPrototype(exec->globalData(), prototype); } } - return jsClassData.cachedPrototype; + return jsClassData.cachedPrototype.get(); }