Reviewed by Maciej.
authorggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 16 Jul 2006 01:28:25 +0000 (01:28 +0000)
committerggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 16 Jul 2006 01:28:25 +0000 (01:28 +0000)
        - Moved the arguments passed to JSClassCreate into a single structure,
        called JSClassDefinition. This will enable easier structure
        migration/versioning in the future, if necessary.

        - Added support for class names.

        - kJSClassDefinitionNull replaces kJSObjectCallbacksNone.

        - JSClass is becoming a fairly complex struct, so I migrated all of its
        implementation other than reference counting to the sruct.

        - Also moved JSClass* functions in the API to JSObjectRef.cpp, since they're
        declared in JSObjectRef.h

        - Also added some more informative explanation to the class structure doc.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@15462 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/API/JSCallbackObject.cpp
JavaScriptCore/API/JSClassRef.cpp
JavaScriptCore/API/JSClassRef.h
JavaScriptCore/API/JSNode.c
JavaScriptCore/API/JSNodeList.c
JavaScriptCore/API/JSObjectRef.cpp
JavaScriptCore/API/JSObjectRef.h
JavaScriptCore/API/testapi.c
JavaScriptCore/API/testapi.js
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp

index e7ea734109b894f6746023a0c166f14afc68467f..892efc6f9f182aa32ba96198f5237fb3a73a6cc7 100644 (file)
@@ -59,17 +59,17 @@ void JSCallbackObject::init(JSContextRef context, JSClassRef jsClass)
     JSObjectRef thisRef = toRef(this);
     
     do {
-        if (JSObjectInitializeCallback initialize = jsClass->callbacks.initialize)
+        if (JSObjectInitializeCallback initialize = jsClass->initialize)
             initialize(context, thisRef, toRef(exec->exceptionSlot()));
-    } while ((jsClass = jsClass->parent));
+    } while ((jsClass = jsClass->parentClass));
 }
 
 JSCallbackObject::~JSCallbackObject()
 {
     JSObjectRef thisRef = toRef(this);
     
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
-        if (JSObjectFinalizeCallback finalize = jsClass->callbacks.finalize)
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
+        if (JSObjectFinalizeCallback finalize = jsClass->finalize)
             finalize(thisRef);
     
     JSClassRelease(m_class);
@@ -77,7 +77,10 @@ JSCallbackObject::~JSCallbackObject()
 
 UString JSCallbackObject::className() const
 {
-    return classInfo()->className;
+    if (!m_class->className.isNull())
+        return m_class->className;
+    
+    return JSObject::className();
 }
 
 bool JSCallbackObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
@@ -86,14 +89,14 @@ bool JSCallbackObject::getOwnPropertySlot(ExecState* exec, const Identifier& pro
     JSObjectRef thisRef = toRef(this);
     JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
 
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
         // optional optimization to bypass getProperty in cases when we only need to know if the property exists
-        if (JSObjectHasPropertyCallback hasProperty = jsClass->callbacks.hasProperty) {
+        if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) {
             if (hasProperty(context, thisRef, propertyNameRef)) {
                 slot.setCustom(this, callbackGetter);
                 return true;
             }
-        } else if (JSObjectGetPropertyCallback getProperty = jsClass->callbacks.getProperty) {
+        } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) {
             if (JSValueRef value = getProperty(context, thisRef, propertyNameRef, toRef(exec->exceptionSlot()))) {
                 // cache the value so we don't have to compute it again
                 // FIXME: This violates the PropertySlot design a little bit.
@@ -135,8 +138,8 @@ void JSCallbackObject::put(ExecState* exec, const Identifier& propertyName, JSVa
     JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
     JSValueRef valueRef = toRef(value);
 
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
-        if (JSObjectSetPropertyCallback setProperty = jsClass->callbacks.setProperty) {
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
+        if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) {
             if (setProperty(context, thisRef, propertyNameRef, valueRef, toRef(exec->exceptionSlot())))
                 return;
         }
@@ -176,8 +179,8 @@ bool JSCallbackObject::deleteProperty(ExecState* exec, const Identifier& propert
     JSObjectRef thisRef = toRef(this);
     JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
     
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
-        if (JSObjectDeletePropertyCallback deleteProperty = jsClass->callbacks.deleteProperty) {
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
+        if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) {
             if (deleteProperty(context, thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
                 return true;
         }
@@ -209,8 +212,8 @@ bool JSCallbackObject::deleteProperty(ExecState* exec, unsigned propertyName)
 
 bool JSCallbackObject::implementsConstruct() const
 {
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
-        if (jsClass->callbacks.callAsConstructor)
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
+        if (jsClass->callAsConstructor)
             return true;
 
     return false;
@@ -221,8 +224,8 @@ JSObject* JSCallbackObject::construct(ExecState* exec, const List& args)
     JSContextRef execRef = toRef(exec);
     JSObjectRef thisRef = toRef(this);
     
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
-        if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callbacks.callAsConstructor) {
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
+        if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) {
             size_t argumentCount = args.size();
             JSValueRef arguments[argumentCount];
             for (size_t i = 0; i < argumentCount; i++)
@@ -237,8 +240,8 @@ JSObject* JSCallbackObject::construct(ExecState* exec, const List& args)
 
 bool JSCallbackObject::implementsHasInstance() const
 {
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
-        if (jsClass->callbacks.hasInstance)
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
+        if (jsClass->hasInstance)
             return true;
 
     return false;
@@ -249,8 +252,8 @@ bool JSCallbackObject::hasInstance(ExecState *exec, JSValue *value)
     JSContextRef execRef = toRef(exec);
     JSObjectRef thisRef = toRef(this);
 
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
-        if (JSObjectHasInstanceCallback hasInstance = jsClass->callbacks.hasInstance)
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
+        if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance)
             return hasInstance(execRef, thisRef, toRef(value), toRef(exec->exceptionSlot()));
 
     ASSERT(0); // implementsHasInstance should prevent us from reaching here
@@ -260,8 +263,8 @@ bool JSCallbackObject::hasInstance(ExecState *exec, JSValue *value)
 
 bool JSCallbackObject::implementsCall() const
 {
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
-        if (jsClass->callbacks.callAsFunction)
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
+        if (jsClass->callAsFunction)
             return true;
     
     return false;
@@ -273,8 +276,8 @@ JSValue* JSCallbackObject::callAsFunction(ExecState* exec, JSObject* thisObj, co
     JSObjectRef thisRef = toRef(this);
     JSObjectRef thisObjRef = toRef(thisObj);
 
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
-        if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callbacks.callAsFunction) {
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
+        if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) {
             size_t argumentCount = args.size();
             JSValueRef arguments[argumentCount];
             for (size_t i = 0; i < argumentCount; i++)
@@ -291,8 +294,8 @@ void JSCallbackObject::getPropertyList(ReferenceList& propertyList, bool recursi
 {
     JSObjectRef thisRef = toRef(this);
 
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
-        if (JSObjectAddPropertiesToListCallback addPropertiesToList = jsClass->callbacks.addPropertiesToList)
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass) {
+        if (JSObjectAddPropertiesToListCallback addPropertiesToList = jsClass->addPropertiesToList)
             addPropertiesToList(thisRef, toRef(&propertyList));
 
         if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues) {
@@ -326,8 +329,8 @@ double JSCallbackObject::toNumber(ExecState* exec) const
     JSContextRef context = toRef(exec);
     JSObjectRef thisRef = toRef(this);
 
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
-        if (JSObjectConvertToTypeCallback convertToType = jsClass->callbacks.convertToType)
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
+        if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType)
             if (JSValueRef value = convertToType(context, thisRef, kJSTypeNumber, toRef(exec->exceptionSlot())))
                 return toJS(value)->getNumber();
 
@@ -339,8 +342,8 @@ UString JSCallbackObject::toString(ExecState* exec) const
     JSContextRef context = toRef(exec);
     JSObjectRef thisRef = toRef(this);
 
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
-        if (JSObjectConvertToTypeCallback convertToType = jsClass->callbacks.convertToType)
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
+        if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType)
             if (JSValueRef value = convertToType(context, thisRef, kJSTypeString, toRef(exec->exceptionSlot())))
                 return toJS(value)->getString();
 
@@ -359,7 +362,7 @@ void* JSCallbackObject::getPrivate()
 
 bool JSCallbackObject::inherits(JSClassRef c) const
 {
-    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent)
+    for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parentClass)
         if (jsClass == c)
             return true;
 
@@ -381,7 +384,7 @@ JSValue* JSCallbackObject::staticValueGetter(ExecState* exec, JSObject*, const I
     JSObjectRef thisRef = toRef(thisObj);
     JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
 
-    for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parent)
+    for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass)
         if (__JSClass::StaticValuesTable* staticValues = jsClass->staticValues)
             if (StaticValueEntry* entry = staticValues->get(propertyName.ustring().rep()))
                 if (JSObjectGetPropertyCallback getProperty = entry->getProperty)
@@ -399,7 +402,7 @@ JSValue* JSCallbackObject::staticFunctionGetter(ExecState* exec, JSObject*, cons
     if (JSValue* cachedOrOverrideValue = thisObj->getDirect(propertyName))
         return cachedOrOverrideValue;
 
-    for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parent) {
+    for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass) {
         if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
             if (StaticFunctionEntry* entry = staticFunctions->get(propertyName.ustring().rep())) {
                 JSValue* v = toJS(JSObjectMakeFunction(toRef(exec), entry->callAsFunction));
@@ -420,8 +423,8 @@ JSValue* JSCallbackObject::callbackGetter(ExecState* exec, JSObject*, const Iden
     JSObjectRef thisRef = toRef(thisObj);
     JSStringRef propertyNameRef = toRef(propertyName.ustring().rep());
 
-    for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parent)
-        if (JSObjectGetPropertyCallback getProperty = jsClass->callbacks.getProperty)
+    for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parentClass)
+        if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty)
             if (JSValueRef value = getProperty(toRef(exec), thisRef, propertyNameRef, toRef(exec->exceptionSlot())))
                 return toJS(value);
 
index 3bf730dcab61b93cd0979c86b1083e712558def9..09cc0bb16f133f97f6362bb97685b8170ed6d963 100644 (file)
 
 using namespace KJS;
 
-const JSObjectCallbacks kJSObjectCallbacksNone = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+const JSClassDefinition kJSClassDefinitionNull = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 
-JSClassRef JSClassCreate(JSStaticValue* staticValues, JSStaticFunction* staticFunctions, const JSObjectCallbacks* callbacks, JSClassRef parentClass)
+__JSClass::__JSClass(JSClassDefinition* definition) 
+    : refCount(0)
+    , className(definition->className)
+    , parentClass(definition->parentClass)
+    , staticValues(0)
+    , staticFunctions(0)
+    , initialize(definition->initialize)
+    , finalize(definition->finalize)
+    , hasProperty(definition->hasProperty)
+    , getProperty(definition->getProperty)
+    , setProperty(definition->setProperty)
+    , deleteProperty(definition->deleteProperty)
+    , addPropertiesToList(definition->addPropertiesToList)
+    , callAsFunction(definition->callAsFunction)
+    , callAsConstructor(definition->callAsConstructor)
+    , hasInstance(definition->hasInstance)
+    , convertToType(definition->convertToType)
 {
-    JSClassRef jsClass = new __JSClass;
-    if (staticValues) {
-        jsClass->staticValues = new __JSClass::StaticValuesTable();
-        while (staticValues->name) {
-            jsClass->staticValues->add(Identifier(staticValues->name).ustring().rep(), 
-                                       new StaticValueEntry(staticValues->getProperty, staticValues->setProperty, staticValues->attributes));
-            ++staticValues;
+    if (JSStaticValue* staticValue = definition->staticValues) {
+        staticValues = new StaticValuesTable();
+        while (staticValue->name) {
+            staticValues->add(Identifier(staticValue->name).ustring().rep(), 
+                              new StaticValueEntry(staticValue->getProperty, staticValue->setProperty, staticValue->attributes));
+            ++staticValue;
         }
     }
     
-    if (staticFunctions) {
-        jsClass->staticFunctions = new __JSClass::StaticFunctionsTable();
-        while (staticFunctions->name) {
-            jsClass->staticFunctions->add(Identifier(staticFunctions->name).ustring().rep(), 
-                                          new StaticFunctionEntry(staticFunctions->callAsFunction, staticFunctions->attributes));
-            ++staticFunctions;
+    if (JSStaticFunction* staticFunction = definition->staticFunctions) {
+        staticFunctions = new StaticFunctionsTable();
+        while (staticFunction->name) {
+            staticFunctions->add(Identifier(staticFunction->name).ustring().rep(), 
+                                 new StaticFunctionEntry(staticFunction->callAsFunction, staticFunction->attributes));
+            ++staticFunction;
         }
     }
-    
-    if (callbacks)
-        jsClass->callbacks = *callbacks;
-    else
-        jsClass->callbacks = kJSObjectCallbacksNone;
-    
-    jsClass->parent = parentClass;
-    
-    return JSClassRetain(jsClass);
-}
-
-JSClassRef JSClassRetain(JSClassRef jsClass)
-{
-    ++jsClass->refCount;
-    return jsClass;
 }
 
-void JSClassRelease(JSClassRef jsClass)
+__JSClass::~__JSClass()
 {
-    if (--jsClass->refCount == 0) {
-        if (jsClass->staticValues) {
-            deleteAllValues(*jsClass->staticValues);
-            delete jsClass->staticValues;
-        }
-
-        if (jsClass->staticFunctions) {
-            deleteAllValues(*jsClass->staticFunctions);
-            delete jsClass->staticFunctions;
-        }
+    if (staticValues) {
+        deleteAllValues(*staticValues);
+        delete staticValues;
+    }
 
-        delete jsClass;
+    if (staticFunctions) {
+        deleteAllValues(*staticFunctions);
+        delete staticFunctions;
     }
 }
index e2a915156e8f1295ee015133b993f9d72cd41dc8..8290d1333b44b0bbd1a8a672d98d77efa05e6a50 100644 (file)
@@ -53,22 +53,31 @@ struct StaticFunctionEntry {
 };
 
 struct __JSClass {
-    __JSClass() 
-        : refCount(0), staticValues(0), staticFunctions(0)
-    {
-    }
-    
-    unsigned refCount;
+    __JSClass(JSClassDefinition*);
+    ~__JSClass();
     
     typedef HashMap<RefPtr<KJS::UString::Rep>, StaticValueEntry*> StaticValuesTable;
-    StaticValuesTable* staticValues;
-
     typedef HashMap<RefPtr<KJS::UString::Rep>, StaticFunctionEntry*> StaticFunctionsTable;
-    StaticFunctionsTable* staticFunctions;
 
-    KJS::UString name; // FIXME: Not used yet
-    JSObjectCallbacks callbacks;
-    __JSClass* parent;
+    unsigned refCount;
+
+    KJS::UString className;
+    __JSClass* parentClass;
+        
+    StaticValuesTable* staticValues;
+    StaticFunctionsTable* staticFunctions;
+    
+    JSObjectInitializeCallback initialize;
+    JSObjectFinalizeCallback finalize;
+    JSObjectHasPropertyCallback hasProperty;
+    JSObjectGetPropertyCallback getProperty;
+    JSObjectSetPropertyCallback setProperty;
+    JSObjectDeletePropertyCallback deleteProperty;
+    JSObjectAddPropertiesToListCallback addPropertiesToList;
+    JSObjectCallAsFunctionCallback callAsFunction;
+    JSObjectCallAsConstructorCallback callAsConstructor;
+    JSObjectHasInstanceCallback hasInstance;
+    JSObjectConvertToTypeCallback convertToType;
 };
 
 #endif // JSClassRef_h
index 35bb56455e1b4b3c7e23d99455c65fc31f6340aa..c9eb911056e8ef389862de8e784b65a96e5b6ee3 100644 (file)
@@ -107,10 +107,13 @@ static JSStaticFunction JSNodePrototype_staticFunctions[] = {
 
 static JSClassRef JSNodePrototype_class(JSContextRef context)
 {
-    static JSClassRef nodePrototypeClass;
-    if (!nodePrototypeClass)
-        nodePrototypeClass = JSClassCreate(NULL, JSNodePrototype_staticFunctions, &kJSObjectCallbacksNone, NULL);
-    return nodePrototypeClass;
+    static JSClassRef jsClass;
+    if (!jsClass) {
+        JSClassDefinition definition = kJSClassDefinitionNull;
+        definition.staticFunctions = JSNodePrototype_staticFunctions;
+        jsClass = JSClassCreate(&definition);
+    }
+    return jsClass;
 }
 
 static JSValueRef JSNode_getNodeType(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
@@ -163,14 +166,15 @@ static void JSNode_finalize(JSObjectRef object)
 
 static JSClassRef JSNode_class(JSContextRef context)
 {
-    static JSClassRef nodeClass;
-    if (!nodeClass) {
-        JSObjectCallbacks JSNode_callbacks = kJSObjectCallbacksNone;
-        JSNode_callbacks.finalize = JSNode_finalize;
-        
-        nodeClass = JSClassCreate(JSNode_staticValues, NULL, &JSNode_callbacks, NULL);
+    static JSClassRef jsClass;
+    if (!jsClass) {
+        JSClassDefinition definition = kJSClassDefinitionNull;
+        definition.staticValues = JSNode_staticValues;
+        definition.finalize = JSNode_finalize;
+
+        jsClass = JSClassCreate(&definition);
     }
-    return nodeClass;
+    return jsClass;
 }
 
 static JSObjectRef JSNode_prototype(JSContextRef context)
index 63a740aa374bfbe1c7d53b7bb0c547a52f9ff7ee..99f6983901d859cf39ace6b0c162262bf70e124c 100644 (file)
@@ -50,7 +50,9 @@ static JSClassRef JSNodeListPrototype_class(JSContextRef context)
 {
     static JSClassRef jsClass;
     if (!jsClass) {
-        jsClass = JSClassCreate(NULL, JSNodeListPrototype_staticFunctions, &kJSObjectCallbacksNone, NULL);
+        JSClassDefinition definition = kJSClassDefinitionNull;
+        definition.staticFunctions = JSNodeListPrototype_staticFunctions;
+        jsClass = JSClassCreate(&definition);
     }
     
     return jsClass;
@@ -97,11 +99,12 @@ static JSClassRef JSNodeList_class(JSContextRef context)
 {
     static JSClassRef jsClass;
     if (!jsClass) {
-        JSObjectCallbacks callbacks = kJSObjectCallbacksNone;
-        callbacks.getProperty = JSNodeList_getProperty;
-        callbacks.finalize = JSNodeList_finalize;
-        
-        jsClass = JSClassCreate(JSNodeList_staticValues, NULL, &callbacks, NULL);
+        JSClassDefinition definition = kJSClassDefinitionNull;
+        definition.staticValues = JSNodeList_staticValues;
+        definition.getProperty = JSNodeList_getProperty;
+        definition.finalize = JSNodeList_finalize;
+
+        jsClass = JSClassCreate(&definition);
     }
     
     return jsClass;
index 6cd63c6a59c131b3f37bc42b23de431c0b8ec942..3529887b47c03767d27001196c4d342df2103b48 100644 (file)
@@ -30,6 +30,7 @@
 #include "JSCallbackConstructor.h"
 #include "JSCallbackFunction.h"
 #include "JSCallbackObject.h"
+#include "JSClassRef.h"
 
 #include "identifier.h"
 #include "function.h"
 
 using namespace KJS;
 
+JSClassRef JSClassCreate(JSClassDefinition* definition)
+{
+    JSClassRef jsClass = new __JSClass(definition);
+    return JSClassRetain(jsClass);
+}
+
+JSClassRef JSClassRetain(JSClassRef jsClass)
+{
+    ++jsClass->refCount;
+    return jsClass;
+}
+
+void JSClassRelease(JSClassRef jsClass)
+{
+    if (--jsClass->refCount == 0)
+        delete jsClass;
+}
+
 JSObjectRef JSObjectMake(JSContextRef context, JSClassRef jsClass, JSValueRef prototype)
 {
     JSLock lock;
index f2bfe81bfbb79b71575f011a21a5643eb61529f4..61161cfb76e65332c70af1bd09fd9b402dbc028b 100644 (file)
@@ -83,7 +83,7 @@ typedef void
 
 /*! 
 @typedef JSObjectHasPropertyCallback
-@abstract The callback invoked when determining whether an object has a given property.
+@abstract The callback invoked when determining whether an object has a property.
 @param context The current execution context.
 @param object The JSObject to search for the property.
 @param propertyName A JSString containing the name of the property look up.
@@ -92,7 +92,7 @@ typedef void
 
 bool HasProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName);
 
-If this function returns false, the hasProperty request forwards to object's static property table, then its parent class chain (which includes the default object class), then its prototype chain.
+If this function returns false, the hasProperty request forwards to object's statically declared properties, then its parent class chain (which includes the default object class), then its prototype chain.
 
 This callback enables optimization in cases where only a property's existence needs to be known, not its value, and computing its value would be expensive.
 
@@ -103,7 +103,7 @@ typedef bool
 
 /*! 
 @typedef JSObjectGetPropertyCallback
-@abstract The callback invoked when getting a property from an object.
+@abstract The callback invoked when getting a property's value.
 @param context The current execution context.
 @param object The JSObject to search for the property.
 @param propertyName A JSString containing the name of the property to get.
@@ -113,14 +113,14 @@ typedef bool
 
 JSValueRef GetProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception);
 
-If this function returns NULL, the get request forwards to object's static property table, then its parent class chain (which includes the default object class), then its prototype chain.
+If this function returns NULL, the get request forwards to object's statically declared properties, then its parent class chain (which includes the default object class), then its prototype chain.
 */
 typedef JSValueRef
 (*JSObjectGetPropertyCallback) (JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception);
 
 /*! 
 @typedef JSObjectSetPropertyCallback
-@abstract The callback invoked when setting the value of a given property.
+@abstract The callback invoked when setting a property's value.
 @param context The current execution context.
 @param object The JSObject on which to set the property's value.
 @param propertyName A JSString containing the name of the property to set.
@@ -131,14 +131,14 @@ typedef JSValueRef
 
 bool SetProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception);
 
-If this function returns false, the set request forwards to object's static property table, then its parent class chain (which includes the default object class).
+If this function returns false, the set request forwards to object's statically declared properties, then its parent class chain (which includes the default object class).
 */
 typedef bool
 (*JSObjectSetPropertyCallback) (JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception);
 
 /*! 
 @typedef JSObjectDeletePropertyCallback
-@abstract The callback invoked when deleting a given property.
+@abstract The callback invoked when deleting a property.
 @param context The current execution context.
 @param object The JSObject in which to delete the property.
 @param propertyName A JSString containing the name of the property to delete.
@@ -148,7 +148,7 @@ typedef bool
 
 bool DeleteProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception);
 
-If this function returns false, the delete request forwards to object's static property table, then its parent class chain (which includes the default object class).
+If this function returns false, the delete request forwards to object's statically declared properties, then its parent class chain (which includes the default object class).
 */
 typedef bool
 (*JSObjectDeletePropertyCallback) (JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception);
@@ -251,24 +251,75 @@ This function is only invoked when converting an object to number or string. An
 typedef JSValueRef
 (*JSObjectConvertToTypeCallback) (JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception);
 
+/*! 
+@struct JSStaticValue
+@abstract This structure describes a statically declared value property.
+@field name A null-terminated UTF8 string containing the property's name.
+@field getProperty A JSObjectGetPropertyCallback to invoke when getting the property's value.
+@field setProperty A JSObjectSetPropertyCallback to invoke when setting the property's value.
+@field attributes A logically ORed set of JSPropertyAttributes to give to the property.
+*/
+typedef struct {
+    const char* const name; // FIXME: convert UTF8
+    JSObjectGetPropertyCallback getProperty;
+    JSObjectSetPropertyCallback setProperty;
+    JSPropertyAttributes attributes;
+} JSStaticValue;
+
+/*! 
+@struct JSStaticFunction
+@abstract This structure describes a statically declared function property.
+@field name A null-terminated UTF8 string containing the property's name.
+@field callAsFunction A JSObjectCallAsFunctionCallback to invoke when the property is called as a function.
+@field attributes A logically ORed set of JSPropertyAttributes to give to the property.
+*/
+typedef struct {
+    const char* const name; // FIXME: convert UTF8
+    JSObjectCallAsFunctionCallback callAsFunction;
+    JSPropertyAttributes attributes;
+} JSStaticFunction;
+
 /*!
-@struct JSObjectCallbacks
-@abstract This structure contains optional callbacks for supplementing default object behavior. Any callback field can be NULL.
+@struct JSClassDefinition
+@abstract This structure contains properties and callbacks that define a type of object. All fields are optional. Any field may be NULL.
 @field version The version number of this structure. The current version is 0.
-@field initialize The callback invoked when an object is first created. Use this callback in conjunction with JSObjectSetPrivate to initialize private data in your object.
-@field finalize The callback invoked when an object is finalized (prepared for garbage collection). Use this callback to release resources allocated for your object, and perform other cleanup.
-@field hasProperty The callback invoked when determining whether an object has a given property. If this field is NULL, getProperty will be called instead. The hasProperty callback enables optimization in cases where only a property's existence needs to be known, not its value, and computing its value would be expensive. 
-@field getProperty The callback invoked when getting the value of a given property.
-@field setProperty The callback invoked when setting the value of a given property.
-@field deleteProperty The callback invoked when deleting a given property.
+@field className A null-terminated UTF8 string containing the class's name.
+@field parentClass A JSClass to set as the class's parent class. Pass NULL use the default object class.
+@field staticValues A JSStaticValue array containing the class's statically declared value properties. Pass NULL to specify no statically declared value properties. The array must be terminated by a JSStaticValue whose name field is NULL.
+@field staticFunctions A JSStaticFunction array containing the class's statically declared function properties. Pass NULL to specify no statically declared function properties. The array must be terminated by a JSStaticFunction whose name field is NULL.
+@field initialize The callback invoked when an object is first created. Use this callback to initialize the object.
+@field finalize The callback invoked when an object is finalized (prepared for garbage collection). Use this callback to release resources allocated for the object, and perform other cleanup.
+@field hasProperty The callback invoked when determining whether an object has a property. If this field is NULL, getProperty is called instead. The hasProperty callback enables optimization in cases where only a property's existence needs to be known, not its value, and computing its value is expensive. 
+@field getProperty The callback invoked when getting a property's value.
+@field setProperty The callback invoked when setting a property's value.
+@field deleteProperty The callback invoked when deleting a property.
 @field addPropertiesToList The callback invoked when adding an object's properties to a property list.
 @field callAsFunction The callback invoked when an object is called as a function.
 @field hasInstance The callback invoked when an object is used as the target of an 'instanceof' expression.
 @field callAsConstructor The callback invoked when an object is used as a constructor in a 'new' expression.
 @field convertToType The callback invoked when converting an object to a particular JavaScript type.
+@discussion The staticValues and staticFunctions arrays are the simplest and most efficient means for vending custom properties. Statically declared properties autmatically service requests like get, set, and enumerate. Property access callbacks are required only to implement unusual properties, like array indexes, whose names are not known at compile-time.
+
+If you named your getter function "GetX" and your setter function "SetX", you would declare a JSStaticValue array containing "X" like this:
+
+JSStaticValue StaticValueArray[] = {
+    { "X", GetX, SetX, kJSPropertyAttributeNone },
+    { 0, 0, 0, 0 }
+};
+
+Standard JavaScript practice calls for storing functions in prototype objects, so derived objects can share them. Therefore, it is common for prototype classes to have function properties but no value properties, and for object classes to have value properties but no function properties.
+
+A NULL callback specifies that the default object callback should substitute, except in the case of hasProperty, where it specifies that getProperty should substitute.
 */
 typedef struct {
     int                                 version; // current (and only) version is 0
+
+    const char*                         className;
+    JSClassRef                          parentClass;
+        
+    JSStaticValue*                      staticValues;
+    JSStaticFunction*                   staticFunctions;
+    
     JSObjectInitializeCallback          initialize;
     JSObjectFinalizeCallback            finalize;
     JSObjectHasPropertyCallback         hasProperty;
@@ -280,58 +331,27 @@ typedef struct {
     JSObjectCallAsConstructorCallback   callAsConstructor;
     JSObjectHasInstanceCallback         hasInstance;
     JSObjectConvertToTypeCallback       convertToType;
-} JSObjectCallbacks;
+} JSClassDefinition;
 
 /*! 
-@const kJSObjectCallbacksNone 
-@abstract A JSObjectCallbacks structure of the current version, filled with NULL callbacks.
-@discussion Use this constant as a convenience when creating callback structures. For example, to create a callback structure that has only a finalize method:
-
-JSObjectCallbacks callbacks = kJSObjectCallbacksNone;
-
-callbacks.finalize = Finalize;
-*/
-extern const JSObjectCallbacks kJSObjectCallbacksNone;
+@const kJSClassDefinitionNull 
+@abstract A JSClassDefinition structure of the current version, filled with NULL pointers.
+@discussion Use this constant as a convenience when creating class definitions. For example, to create a class definition with only a finalize method:
 
-/*! 
-@struct JSStaticValue
-@abstract This structure describes a static value property.
-@field name A null-terminated UTF8 string containing the property's name.
-@field getProperty A JSObjectGetPropertyCallback to invoke when getting the property's value.
-@field setProperty A JSObjectSetPropertyCallback to invoke when setting the property's value.
-@field attributes A logically ORed set of JSPropertyAttributes to give to the property.
-*/
-typedef struct {
-    const char* const name; // FIXME: convert UTF8
-    JSObjectGetPropertyCallback getProperty;
-    JSObjectSetPropertyCallback setProperty;
-    JSPropertyAttributes attributes;
-} JSStaticValue;
+JSClassDefinition definition = kJSClassDefinitionNull;
 
-/*! 
-@struct JSStaticFunction
-@abstract This structure describes a static function property.
-@field name A null-terminated UTF8 string containing the property's name.
-@field callAsFunction A JSObjectCallAsFunctionCallback to invoke when the property is called as a function.
-@field attributes A logically ORed set of JSPropertyAttributes to give to the property.
+definition.finalize = Finalize;
 */
-typedef struct {
-    const char* const name; // FIXME: convert UTF8
-    JSObjectCallAsFunctionCallback callAsFunction;
-    JSPropertyAttributes attributes;
-} JSStaticFunction;
+extern const JSClassDefinition kJSClassDefinitionNull;
 
 /*!
 @function
-@abstract Creates a JavaScript class suitable for use with JSObjectMake
-@param staticValues A JSStaticValue array representing the class's static value properties. Pass NULL to specify no static value properties. The array must be terminated by a JSStaticValue whose name field is NULL.
-@param staticFunctions A JSStaticFunction array representing the class's static function properties. Pass NULL to specify no static function properties. The array must be terminated by a JSStaticFunction whose name field is NULL.
-@param callbacks A pointer to a JSObjectCallbacks structure holding custom callbacks for supplementing default object behavior. Pass NULL to specify no custom behavior.
-@param parentClass A JSClass to set as the class's parent class. Pass NULL use the default object class.
-@result A JSClass with the given properties, callbacks, and parent class. Ownership follows the Create Rule.
-@discussion The simplest and most efficient way to add custom properties to a class is by specifying static values and functions. Standard JavaScript practice calls for functions to be placed in prototype objects, so that they can be shared among objects.
-*/
-JSClassRef JSClassCreate(JSStaticValue* staticValues, JSStaticFunction* staticFunctions, const JSObjectCallbacks* callbacks, JSClassRef parentClass);
+@abstract Creates a JavaScript class suitable for use with JSObjectMake.
+@param definition A JSClassDefinition that defines the class.
+@result A JSClass with the given definition's name, properties, callbacks, and parent class. Ownership follows the Create Rule.
+*/
+JSClassRef JSClassCreate(JSClassDefinition* definition);
+
 /*!
 @function
 @abstract Retains a JavaScript class.
@@ -403,7 +423,7 @@ void JSObjectSetPrototype(JSObjectRef object, JSValueRef value);
 
 /*!
 @function
-@abstract Tests whether an object has a certain property.
+@abstract Tests whether an object has a given property.
 @param object The JSObject to test.
 @param propertyName A JSString containing the property's name.
 @result true if the object has a property whose name matches propertyName, otherwise false.
@@ -472,7 +492,7 @@ void JSObjectSetPropertyAtIndex(JSContextRef context, JSObjectRef object, unsign
 @abstract Gets a pointer to private data from an object.
 @param object A JSObject whose private data you want to get.
 @result A void* that points to the object's private data, if the object has private data, otherwise NULL.
-@discussion JSObjectGetPrivate and JSObjectSetPrivate only work on custom objects created by JSObjectMake, JSObjectMakeFunction, and JSObjectMakeConstructor.
+@discussion JSObjectGetPrivate and JSObjectSetPrivate only work on objects created by JSObjectMake, JSObjectMakeFunction, and JSObjectMakeConstructor.
 */
 void* JSObjectGetPrivate(JSObjectRef object);
 
@@ -482,7 +502,7 @@ void* JSObjectGetPrivate(JSObjectRef object);
 @param object A JSObject whose private data you want to set.
 @param data A void* that points to the object's private data.
 @result true if the set operation succeeds, otherwise false.
-@discussion JSObjectGetPrivate and JSObjectSetPrivate only work on custom objects created by JSObjectMake, JSObjectMakeFunction, and JSObjectMakeConstructor.
+@discussion JSObjectGetPrivate and JSObjectSetPrivate only work on objects created by JSObjectMake, JSObjectMakeFunction, and JSObjectMakeConstructor.
 */
 bool JSObjectSetPrivate(JSObjectRef object, void* data);
 
@@ -555,7 +575,7 @@ JSStringRef JSPropertyEnumeratorGetNextName(JSPropertyEnumeratorRef enumerator);
 /*!
 @function
 @abstract Adds a property to a property list.
-@discussion Use this method inside a JSObjectAddPropertiesToListCallback to add a custom property to an object's property list.
+@discussion Use this method inside a JSObjectAddPropertiesToListCallback to add a property to an object's property list.
 @param propertyList The JSPropertyList to which you want to add a property.
 @param thisObject The JSObject to which the property belongs.
 @param propertyName A JSString specifying the property's name.
index ed655789b7cc7d6f28861d1ff612d2559a24207c..998dc5c6c0cbb8c8c72dd6af88b00442ac9c80c5 100644 (file)
@@ -240,8 +240,15 @@ static void MyObject_finalize(JSObjectRef object)
     didFinalize = true;
 }
 
-JSObjectCallbacks MyObject_callbacks = {
+JSClassDefinition MyObject_definition = {
     0,
+    
+    "MyObject",
+    NULL,
+    
+    NULL,
+    NULL,
+    
     MyObject_initialize,
     MyObject_finalize,
     MyObject_hasProperty,
@@ -258,9 +265,8 @@ JSObjectCallbacks MyObject_callbacks = {
 static JSClassRef MyObject_class(JSContextRef context)
 {
     static JSClassRef jsClass;
-    if (!jsClass) {
-        jsClass = JSClassCreate(NULL, NULL, &MyObject_callbacks, NULL);
-    }
+    if (!jsClass)
+        jsClass = JSClassCreate(&MyObject_definition);
     
     return jsClass;
 }
@@ -560,8 +566,9 @@ int main(int argc, char* argv[])
     JSPropertyEnumeratorRelease(enumerator);
     assert(count == 1); // jsCFString should not be enumerated
 
-    JSClassRef nullCallbacksClass = JSClassCreate(NULL, NULL, NULL, NULL);
-    JSClassRelease(nullCallbacksClass);
+    JSClassDefinition nullDefinition = kJSClassDefinitionNull;
+    JSClassRef nullClass = JSClassCreate(&nullDefinition);
+    JSClassRelease(nullClass);
     
     functionBody = JSStringCreateWithUTF8CString("return this;");
     function = JSObjectMakeFunctionWithBody(context, functionBody, NULL, 1, NULL);
index 8fa56c2388611f57166d1d54194d3e89719dc828..3a4540d0798449ce3a4245fce9507833580d652e 100644 (file)
@@ -75,7 +75,7 @@ shouldBe("MyObject()", undefined);
 shouldBe("typeof new MyObject()", "object");
 shouldBe("MyObject ? 1 : 0", true); // toBoolean
 shouldBe("+MyObject", 1); // toNumber
-shouldBe("(MyObject.toString())", "[object CallbackObject]"); // toString
+shouldBe("(MyObject.toString())", "[object MyObject]"); // toString
 shouldBe("MyObject - 0", NaN); // toPrimitive
 
 shouldBe("typeof MyConstructor", "object");
index 2649c1d9db0b206a6bac1a9d43f1c90189374dda..b935de2641965417bcbc15b9b86fa15da0646293 100644 (file)
@@ -1,3 +1,23 @@
+2006-07-15  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Maciej.
+
+        - Moved the arguments passed to JSClassCreate into a single structure,
+        called JSClassDefinition. This will enable easier structure 
+        migration/versioning in the future, if necessary.
+        
+        - Added support for class names.
+        
+        - kJSClassDefinitionNull replaces kJSObjectCallbacksNone.
+        
+        - JSClass is becoming a fairly complex struct, so I migrated all of its
+        implementation other than reference counting to the sruct.
+        
+        - Also moved JSClass* functions in the API to JSObjectRef.cpp, since they're
+        declared in JSObjectRef.h
+        
+        - Also added some more informative explanation to the class structure doc.
+        
 2006-07-15  Darin Adler  <darin@apple.com>
 
         Reviewed by Geoff.
index 877145f4e95a4c376ccfb052d79c257ee815c318..9662f2a59b8eaaf3b2ead5bfc05890d95bc6a15f 100644 (file)
@@ -260,7 +260,7 @@ __ZNK3KJS9ExecState18lexicalInterpreterEv
 __ZNK3KJS9Reference15getPropertyNameEv
 __ZTVN3KJS19InternalFunctionImpE
 __ZTVN3KJS8JSObjectE
-_kJSObjectCallbacksNone
+_kJSClassDefinitionNull
 _kjs_pcre_compile
 _kjs_pcre_exec
 _kjs_pcre_free