Ignore:
Timestamp:
Jul 23, 2008, 3:15:16 AM (17 years ago)
Author:
[email protected]
Message:

Reviewed by Geoff Garen.

JSClassRef is created context-free, but gets infatuated with the first context it sees.

The implicit API contract is that JSClassRef can be used with any context on any thread.
This no longer worked, because UStrings in the class were turned into per-context
identifiers, and the cached JSObject prototype was tied to JSGlobalData, too.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/API/JSClassRef.cpp

    r34854 r35293  
    4141
    4242OpaqueJSClass::OpaqueJSClass(const JSClassDefinition* definition, OpaqueJSClass* protoClass)
    43     : className(UString::Rep::createFromUTF8(definition->className))
    44     , parentClass(definition->parentClass)
     43    : parentClass(definition->parentClass)
    4544    , prototypeClass(0)
    46     , staticValues(0)
    47     , staticFunctions(0)
    4845    , initialize(definition->initialize)
    4946    , finalize(definition->finalize)
     
    5754    , hasInstance(definition->hasInstance)
    5855    , convertToType(definition->convertToType)
    59     , cachedPrototype(0)
     56    , m_className(UString::Rep::createFromUTF8(definition->className))
     57    , m_staticValues(0)
     58    , m_staticFunctions(0)
    6059{
    6160    initializeThreading();
    6261
    6362    if (const JSStaticValue* staticValue = definition->staticValues) {
    64         staticValues = new StaticValuesTable();
     63        m_staticValues = new OpaqueJSClassStaticValuesTable();
    6564        while (staticValue->name) {
    66             staticValues->add(UString::Rep::createFromUTF8(staticValue->name),
     65            m_staticValues->add(UString::Rep::createFromUTF8(staticValue->name),
    6766                              new StaticValueEntry(staticValue->getProperty, staticValue->setProperty, staticValue->attributes));
    6867            ++staticValue;
    6968        }
    7069    }
    71    
     70
    7271    if (const JSStaticFunction* staticFunction = definition->staticFunctions) {
    73         staticFunctions = new StaticFunctionsTable();
     72        m_staticFunctions = new OpaqueJSClassStaticFunctionsTable();
    7473        while (staticFunction->name) {
    75             staticFunctions->add(UString::Rep::createFromUTF8(staticFunction->name),
     74            m_staticFunctions->add(UString::Rep::createFromUTF8(staticFunction->name),
    7675                                 new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes));
    7776            ++staticFunction;
     
    8584OpaqueJSClass::~OpaqueJSClass()
    8685{
    87     if (staticValues) {
    88         deleteAllValues(*staticValues);
    89         delete staticValues;
    90     }
    91 
    92     if (staticFunctions) {
    93         deleteAllValues(*staticFunctions);
    94         delete staticFunctions;
     86    ASSERT(!m_className.rep()->identifierTable);
     87
     88    if (m_staticValues) {
     89        OpaqueJSClassStaticValuesTable::const_iterator end = m_staticValues->end();
     90        for (OpaqueJSClassStaticValuesTable::const_iterator it = m_staticValues->begin(); it != end; ++it) {
     91            ASSERT(!it->first->identifierTable);
     92            delete it->second;
     93        }
     94        delete m_staticValues;
     95    }
     96
     97    if (m_staticFunctions) {
     98        OpaqueJSClassStaticFunctionsTable::const_iterator end = m_staticFunctions->end();
     99        for (OpaqueJSClassStaticFunctionsTable::const_iterator it = m_staticFunctions->begin(); it != end; ++it) {
     100            ASSERT(!it->first->identifierTable);
     101            delete it->second;
     102        }
     103        delete m_staticFunctions;
    95104    }
    96105   
     
    106115void clearReferenceToPrototype(JSObjectRef prototype)
    107116{
    108     OpaqueJSClass* jsClass = static_cast<OpaqueJSClass*>(JSObjectGetPrivate(prototype));
    109     ASSERT(jsClass);
    110     jsClass->cachedPrototype = 0;
     117    OpaqueJSClassContextData* jsClassData = static_cast<OpaqueJSClassContextData*>(JSObjectGetPrivate(prototype));
     118    ASSERT(jsClassData);
     119    jsClassData->cachedPrototype = 0;
    111120}
    112121
     
    133142}
    134143
     144OpaqueJSClassContextData::OpaqueJSClassContextData(OpaqueJSClass* jsClass)
     145    : m_class(jsClass)
     146    , cachedPrototype(0)
     147{
     148    if (jsClass->m_staticValues) {
     149        staticValues = new OpaqueJSClassStaticValuesTable;
     150        OpaqueJSClassStaticValuesTable::const_iterator end = jsClass->m_staticValues->end();
     151        for (OpaqueJSClassStaticValuesTable::const_iterator it = jsClass->m_staticValues->begin(); it != end; ++it) {
     152            ASSERT(!it->first->identifierTable);
     153            staticValues->add(UString::Rep::createCopying(it->first->data(), it->first->size()),
     154                              new StaticValueEntry(it->second->getProperty, it->second->setProperty, it->second->attributes));
     155        }
     156           
     157    } else
     158        staticValues = 0;
     159       
     160
     161    if (jsClass->m_staticFunctions) {
     162        staticFunctions = new OpaqueJSClassStaticFunctionsTable;
     163        OpaqueJSClassStaticFunctionsTable::const_iterator end = jsClass->m_staticFunctions->end();
     164        for (OpaqueJSClassStaticFunctionsTable::const_iterator it = jsClass->m_staticFunctions->begin(); it != end; ++it) {
     165            ASSERT(!it->first->identifierTable);
     166            staticFunctions->add(UString::Rep::createCopying(it->first->data(), it->first->size()),
     167                              new StaticFunctionEntry(it->second->callAsFunction, it->second->attributes));
     168        }
     169           
     170    } else
     171        staticFunctions = 0;
     172}
     173
     174OpaqueJSClassContextData::~OpaqueJSClassContextData()
     175{
     176    if (staticValues) {
     177        deleteAllValues(*staticValues);
     178        delete staticValues;
     179    }
     180
     181    if (staticFunctions) {
     182        deleteAllValues(*staticFunctions);
     183        delete staticFunctions;
     184    }
     185}
     186
     187OpaqueJSClassContextData& OpaqueJSClass::contextData(ExecState* exec)
     188{
     189    HashMap<OpaqueJSClass*, OpaqueJSClassContextData*>* contextDataMap = exec->globalData().opaqueJSClassData;
     190    HashMap<OpaqueJSClass*, OpaqueJSClassContextData*>::iterator iter = contextDataMap->find(this);
     191    if (iter != contextDataMap->end())
     192        return *iter->second;
     193    return *contextDataMap->add(this, new OpaqueJSClassContextData(this)).first->second;
     194}
     195
     196UString OpaqueJSClass::className()
     197{
     198    // Make a deep copy, so that the caller has no chance to put the original into IdentifierTable.
     199    return UString(m_className.data(), m_className.size());
     200}
     201
     202OpaqueJSClassStaticValuesTable* OpaqueJSClass::staticValues(KJS::ExecState* exec)
     203{
     204    OpaqueJSClassContextData& jsClassData = contextData(exec);
     205    return jsClassData.staticValues;
     206}
     207
     208OpaqueJSClassStaticFunctionsTable* OpaqueJSClass::staticFunctions(KJS::ExecState* exec)
     209{
     210    OpaqueJSClassContextData& jsClassData = contextData(exec);
     211    return jsClassData.staticFunctions;
     212}
     213
    135214/*!
    136215// Doc here in case we make this public. (Hopefully we won't.)
     
    141220 @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.
    142221*/
    143 JSObject* OpaqueJSClass::prototype(JSContextRef ctx)
     222JSObject* OpaqueJSClass::prototype(ExecState* exec)
    144223{
    145224    /* Class (C++) and prototype (JS) inheritance are parallel, so:
     
    153232    if (!prototypeClass)
    154233        return 0;
    155    
    156     ExecState* exec = toJS(ctx);
    157    
    158     if (!cachedPrototype) {
     234
     235    OpaqueJSClassContextData& jsClassData = contextData(exec);
     236
     237    if (!jsClassData.cachedPrototype) {
    159238        // Recursive, but should be good enough for our purposes
    160239        JSObject* parentPrototype = 0;
    161240        if (parentClass)
    162             parentPrototype = parentClass->prototype(ctx); // can be null
     241            parentPrototype = parentClass->prototype(exec); // can be null
    163242        if (!parentPrototype)
    164243            parentPrototype = exec->dynamicGlobalObject()->objectPrototype();
    165         cachedPrototype = new (exec) JSCallbackObject<JSObject>(exec, prototypeClass, parentPrototype, this); // set ourself as the object's private data, so it can clear our reference on destruction
    166     }
    167     return cachedPrototype;
    168 }
     244        jsClassData.cachedPrototype = new (exec) JSCallbackObject<JSObject>(exec, prototypeClass, parentPrototype, &jsClassData); // set jsClassData as the object's private data, so it can clear our reference on destruction
     245    }
     246    return jsClassData.cachedPrototype;
     247}
Note: See TracChangeset for help on using the changeset viewer.