X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/b37bf2e156556c589aea3e1f58a377f2b1189665..81345200c95645a1b0d2635520f96ad55dfde63f:/API/JSClassRef.cpp?ds=sidebyside diff --git a/API/JSClassRef.cpp b/API/JSClassRef.cpp index 98aaaf5..452412e 100644 --- a/API/JSClassRef.cpp +++ b/API/JSClassRef.cpp @@ -1,4 +1,3 @@ -// -*- mode: c++; c-basic-offset: 4 -*- /* * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. * @@ -11,10 +10,10 @@ * 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 @@ -28,23 +27,25 @@ #include "JSClassRef.h" #include "APICast.h" +#include "Identifier.h" +#include "InitializeThreading.h" #include "JSCallbackObject.h" +#include "JSGlobalObject.h" #include "JSObjectRef.h" -#include -#include -#include +#include "ObjectPrototype.h" +#include "JSCInlines.h" +#include +#include -using namespace KJS; +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 }; OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* protoClass) - // FIXME: - : className(definition->className) - , parentClass(definition->parentClass) + : parentClass(definition->parentClass) , prototypeClass(0) - , staticValues(0) - , staticFunctions(0) , initialize(definition->initialize) , finalize(definition->finalize) , hasProperty(definition->hasProperty) @@ -56,24 +57,26 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* , callAsConstructor(definition->callAsConstructor) , hasInstance(definition->hasInstance) , convertToType(definition->convertToType) - , cachedPrototype(0) + , m_className(String::fromUTF8(definition->className)) { + initializeThreading(); + if (const JSStaticValue* staticValue = definition->staticValues) { - staticValues = new StaticValuesTable(); + m_staticValues = adoptPtr(new OpaqueJSClassStaticValuesTable); while (staticValue->name) { - // FIXME: - staticValues->add(Identifier(staticValue->name).ustring().rep(), - 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(staticValue->getProperty, staticValue->setProperty, staticValue->attributes, valueName)); ++staticValue; } } - + if (const JSStaticFunction* staticFunction = definition->staticFunctions) { - staticFunctions = new StaticFunctionsTable(); + m_staticFunctions = adoptPtr(new OpaqueJSClassStaticFunctionsTable); while (staticFunction->name) { - // FIXME: - staticFunctions->add(Identifier(staticFunction->name).ustring().rep(), - new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes)); + String functionName = String::fromUTF8(staticFunction->name); + if (!functionName.isNull()) + m_staticFunctions->set(functionName.impl(), std::make_unique(staticFunction->callAsFunction, staticFunction->attributes)); ++staticFunction; } } @@ -84,48 +87,91 @@ OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* OpaqueJSClass::~OpaqueJSClass() { - if (staticValues) { - deleteAllValues(*staticValues); - delete staticValues; + // 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->key->isAtomic()); } - if (staticFunctions) { - deleteAllValues(*staticFunctions); - delete staticFunctions; + if (m_staticFunctions) { + OpaqueJSClassStaticFunctionsTable::const_iterator end = m_staticFunctions->end(); + for (OpaqueJSClassStaticFunctionsTable::const_iterator it = m_staticFunctions->begin(); it != end; ++it) + ASSERT(!it->key->isAtomic()); } +#endif if (prototypeClass) JSClassRelease(prototypeClass); } -JSClassRef OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition* definition) +PassRefPtr OpaqueJSClass::createNoAutomaticPrototype(const JSClassDefinition* definition) { - return new OpaqueJSClass(definition, 0); + return adoptRef(new OpaqueJSClass(definition, 0)); } -void clearReferenceToPrototype(JSObjectRef prototype) +PassRefPtr OpaqueJSClass::create(const JSClassDefinition* clientDefinition) { - OpaqueJSClass* jsClass = static_cast(JSObjectGetPrivate(prototype)); - ASSERT(jsClass); - jsClass->cachedPrototype = 0; + JSClassDefinition definition = *clientDefinition; // Avoid modifying client copy. + + 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())); } -JSClassRef OpaqueJSClass::create(const JSClassDefinition* definition) +OpaqueJSClassContextData::OpaqueJSClassContextData(JSC::VM&, OpaqueJSClass* jsClass) + : m_class(jsClass) { - if (const JSStaticFunction* staticFunctions = definition->staticFunctions) { - // copy functions into a prototype class - JSClassDefinition protoDefinition = kJSClassDefinitionEmpty; - protoDefinition.staticFunctions = staticFunctions; - protoDefinition.finalize = clearReferenceToPrototype; - OpaqueJSClass* protoClass = new OpaqueJSClass(&protoDefinition, 0); - - // remove functions from the original class - JSClassDefinition objectDefinition = *definition; - objectDefinition.staticFunctions = 0; - return new OpaqueJSClass(&objectDefinition, protoClass); + if (jsClass->m_staticValues) { + staticValues = std::make_unique(); + OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end(); + for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) { + ASSERT(!it->key->isAtomic()); + String valueName = it->key->isolatedCopy(); + staticValues->add(valueName.impl(), std::make_unique(it->value->getProperty, it->value->setProperty, it->value->attributes, valueName)); + } } - return new OpaqueJSClass(definition, 0); + if (jsClass->m_staticFunctions) { + staticFunctions = std::make_unique(); + OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end(); + for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) { + ASSERT(!it->key->isAtomic()); + staticFunctions->add(it->key->isolatedCopy(), std::make_unique(it->value->callAsFunction, it->value->attributes)); + } + } +} + +OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec) +{ + std::unique_ptr& contextData = exec->lexicalGlobalObject()->opaqueJSClassData().add(this, nullptr).iterator->value; + if (!contextData) + contextData = std::make_unique(exec->vm(), this); + return *contextData; +} + +String OpaqueJSClass::className() +{ + // 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) +{ + return contextData(exec).staticValues.get(); +} + +OpaqueJSClassStaticFunctionsTable* OpaqueJSClass::staticFunctions(JSC::ExecState* exec) +{ + return contextData(exec).staticFunctions.get(); } /*! @@ -136,7 +182,7 @@ JSClassRef OpaqueJSClass::create(const JSClassDefinition* definition) @param jsClass A JSClass whose prototype you want to get. @result The JSObject prototype that was automatically generated for jsClass, or NULL if no prototype was automatically generated. This is the prototype that will be used when constructing an object using jsClass. */ -JSObject* OpaqueJSClass::prototype(JSContextRef ctx) +JSObject* OpaqueJSClass::prototype(ExecState* exec) { /* Class (C++) and prototype (JS) inheritance are parallel, so: * (C++) | (JS) @@ -145,20 +191,22 @@ JSObject* OpaqueJSClass::prototype(JSContextRef ctx) * | | | * DerivedClass | DerivedClassPrototype */ - + if (!prototypeClass) return 0; - - ExecState* exec = toJS(ctx); - - if (!cachedPrototype) { - // Recursive, but should be good enough for our purposes - JSObject* parentPrototype = 0; - if (parentClass) - parentPrototype = parentClass->prototype(ctx); // can be null - if (!parentPrototype) - parentPrototype = exec->dynamicGlobalObject()->objectPrototype(); - cachedPrototype = new JSCallbackObject(exec, prototypeClass, parentPrototype, this); // set ourself as the object's private data, so it can clear our reference on destruction + + OpaqueJSClassContextData& jsClassData = contextData(exec); + + if (JSObject* prototype = jsClassData.cachedPrototype.get()) + return prototype; + + // Recursive, but should be good enough for our purposes + JSObject* prototype = JSCallbackObject::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 cachedPrototype; + + jsClassData.cachedPrototype = Weak(prototype); + return prototype; }