Reviewed by Maciej.
authorggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Jul 2006 09:06:57 +0000 (09:06 +0000)
committerggaren <ggaren@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Jul 2006 09:06:57 +0000 (09:06 +0000)
        - Changed the initialize callback to run from least derived class (parent
        class) to most derived class. This enables C++ style initialization,
        and derived class overriding of member data.

        - Added excpetion propopgation to JSObjectMake, to support initialize
        exceptions, and generally round out our policy of making function
        signatures as long as possible.

        * API/JSCallbackObject.h: Use ExecState instead of ContextRef, cuz we're
        in C++ land now.

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

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

index dc05a85ad1f9b28b4b86895185d3087550593ab6..d150fb7030496dc3cb571f6bc22563e4050323e2 100644 (file)
@@ -37,31 +37,34 @@ namespace KJS {
 
 const ClassInfo JSCallbackObject::info = { "CallbackObject", 0, 0, 0 };
 
-JSCallbackObject::JSCallbackObject(JSContextRef ctx, JSClassRef jsClass)
+JSCallbackObject::JSCallbackObject(ExecState* exec, JSClassRef jsClass)
     : JSObject()
 {
-    init(ctx, jsClass);
+    init(exec, jsClass);
 }
 
-JSCallbackObject::JSCallbackObject(JSContextRef ctx, JSClassRef jsClass, JSValue* prototype)
+JSCallbackObject::JSCallbackObject(ExecState* exec, JSClassRef jsClass, JSValue* prototype)
     : JSObject(prototype)
 {
-    init(ctx, jsClass);
+    init(exec, jsClass);
 }
 
-void JSCallbackObject::init(JSContextRef ctx, JSClassRef jsClass)
+void JSCallbackObject::init(ExecState* exec, JSClassRef jsClass)
 {
-    ExecState* exec = toJS(ctx);
-    
     m_privateData = 0;
     m_class = JSClassRetain(jsClass);
 
-    JSObjectRef thisRef = toRef(this);
-    
+    Vector<JSObjectInitializeCallback, 16> initRoutines;
     do {
         if (JSObjectInitializeCallback initialize = jsClass->initialize)
-            initialize(ctx, thisRef, toRef(exec->exceptionSlot()));
+            initRoutines.append(initialize);
     } while ((jsClass = jsClass->parentClass));
+    
+    // initialize from base to derived
+    for (int i = initRoutines.size() - 1; i >= 0; i--) {
+        JSObjectInitializeCallback initialize = initRoutines[i];
+        initialize(toRef(exec), toRef(this), toRef(exec->exceptionSlot()));
+    }
 }
 
 JSCallbackObject::~JSCallbackObject()
index f549a911e9da229e459b21297fad08b0c7ff2b36..569e84425fcd5a08c979c9614393831c7eefe4ad 100644 (file)
@@ -36,8 +36,8 @@ namespace KJS {
 class JSCallbackObject : public JSObject
 {
 public:
-    JSCallbackObject(JSContextRef, JSClassRef);
-    JSCallbackObject(JSContextRef, JSClassRef, JSValue* prototype);
+    JSCallbackObject(ExecState*, JSClassRef);
+    JSCallbackObject(ExecState*, JSClassRef, JSValue* prototype);
     virtual ~JSCallbackObject();
         
     virtual UString className() const;
@@ -77,7 +77,7 @@ private:
     JSCallbackObject(); // prevent default construction
     JSCallbackObject(const JSCallbackObject&);
 
-    void init(JSContextRef, JSClassRef);
+    void init(ExecState*, JSClassRef);
     
     static JSValue* cachedValueGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
     static JSValue* staticValueGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot);
index a7b5635194c7e03d1d38d52509da679e3c4107a6..6b286f4c2d79954428d0b7896c76faaf27733929 100644 (file)
@@ -181,7 +181,7 @@ JSObjectRef JSNode_prototype(JSContextRef context)
 {
     static JSObjectRef prototype;
     if (!prototype) {
-        prototype = JSObjectMake(context, JSNodePrototype_class(context), NULL);
+        prototype = JSObjectMake(context, JSNodePrototype_class(context), NULL, NULL);
         JSValueProtect(context, prototype);
     }
     return prototype;
@@ -191,7 +191,7 @@ JSObjectRef JSNode_new(JSContextRef context, Node* node)
 {
     Node_ref(node);
 
-    JSObjectRef jsNode = JSObjectMake(context, JSNode_class(context), JSNode_prototype(context));
+    JSObjectRef jsNode = JSObjectMake(context, JSNode_class(context), JSNode_prototype(context), NULL);
     JSObjectSetPrivate(jsNode, node);
     return jsNode;
 }
index 6f2007df6399f31d9ae85335b336c215b343e2e2..df4c1c330645287fe81805fd0fbb37e34bda7111 100644 (file)
@@ -114,7 +114,7 @@ static JSObjectRef JSNodeList_prototype(JSContextRef context)
 {
     static JSObjectRef prototype;
     if (!prototype) {
-        prototype = JSObjectMake(context, JSNodeListPrototype_class(context), NULL);
+        prototype = JSObjectMake(context, JSNodeListPrototype_class(context), NULL, NULL);
         JSValueProtect(context, prototype);
     }
     return prototype;
@@ -124,7 +124,7 @@ JSObjectRef JSNodeList_new(JSContextRef context, NodeList* nodeList)
 {
     NodeList_ref(nodeList);
     
-    JSObjectRef jsNodeList = JSObjectMake(context, JSNodeList_class(context), JSNodeList_prototype(context));
+    JSObjectRef jsNodeList = JSObjectMake(context, JSNodeList_class(context), JSNodeList_prototype(context), NULL);
     JSObjectSetPrivate(jsNodeList, nodeList);
     return jsNodeList;
 }
index 99f2f992c999c71a8db7dddd73eaf889b6e33063..e2d64063eb816a6ff516e084cc37e5d71e876d1d 100644 (file)
@@ -59,7 +59,7 @@ void JSClassRelease(JSClassRef jsClass)
         delete jsClass;
 }
 
-JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype)
+JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype, JSValueRef* exception)
 {
     JSLock lock;
 
@@ -69,10 +69,18 @@ JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef protot
     if (!prototype)
         jsPrototype = exec->lexicalInterpreter()->builtinObjectPrototype();
 
-    if (!jsClass)
-        return toRef(new JSObject(jsPrototype)); // slightly more efficient
-    else
-        return toRef(new JSCallbackObject(ctx, jsClass, jsPrototype));
+    JSObjectRef result;
+    if (jsClass) {
+        result = toRef(new JSCallbackObject(exec, jsClass, jsPrototype));
+        if (exec->hadException()) {
+            if (exception)
+                *exception = toRef(exec->exception());
+            exec->clearException();
+        }
+    } else
+        result = toRef(new JSObject(jsPrototype)); // slightly more efficient -- and can't throw
+        
+    return result;
 }
 
 JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction)
index 36a8820e1cbf73b39a4961183bd7cd60cac6de00..3068085c17ee9201a612b787ca18f28945e62cc3 100644 (file)
@@ -66,6 +66,9 @@ typedef unsigned JSPropertyAttributes;
 @discussion If you named your function Initialize, you would declare it like this:
 
 void Initialize(JSContextRef ctx, JSObjectRef object, JSValueRef* exception);
+
+Unlike the other object callbacks, the initialize callback is called on the least
+derived class (the parent class) first, and the most derived class last.
 */
 typedef void
 (*JSObjectInitializeCallback) (JSContextRef ctx, JSObjectRef object, JSValueRef* exception);
@@ -77,6 +80,9 @@ typedef void
 @discussion If you named your function Finalize, you would declare it like this:
 
 void Finalize(JSObjectRef object);
+
+The finalize callback is called on the most derived class first, and the least 
+derived class (the parent class) last.
 */
 typedef void            
 (*JSObjectFinalizeCallback) (JSObjectRef object);
@@ -224,7 +230,6 @@ typedef JSObjectRef
 @param possibleInstance The JSValue being tested to determine if it is an instance of constructor.
 @param exception A pointer to a JSValueRef in which to return an exception, if any.
 @result true if possibleInstance is an instance of constructor, otherwise false.
-
 @discussion If you named your function HasInstance, you would declare it like this:
 
 bool HasInstance(JSContextRef ctx, JSObjectRef constructor, JSValueRef possibleInstance, JSValueRef* exception);
@@ -378,9 +383,10 @@ void JSClassRelease(JSClassRef jsClass);
 @param ctx The execution context to use.
 @param jsClass The JSClass to assign to the object. Pass NULL to use the default object class.
 @param prototype The prototype to assign to the object. Pass NULL to use the default object prototype.
+@param exception A pointer to a JSValueRef in which to store an exception, if any. Pass NULL if you do not care to store an exception.
 @result A JSObject with the given class and prototype.
 */
-JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype);
+JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, JSValueRef prototype, JSValueRef* exception);
 
 /*!
 @function
index 9f5a73ff939fbaf3dd47e6462e67a2cbd9b0be81..46dd285be15111d066893a378ac19f016f9dd045 100644 (file)
@@ -241,12 +241,12 @@ static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef objec
     return NULL;
 }
 
-static bool didFinalize = false;
+static bool MyObject_didFinalize = false;
 static void MyObject_finalize(JSObjectRef object)
 {
     UNUSED_PARAM(context);
     UNUSED_PARAM(object);
-    didFinalize = true;
+    MyObject_didFinalize = true;
 }
 
 static JSStaticValue evilStaticValues[] = {
@@ -290,6 +290,56 @@ static JSClassRef MyObject_class(JSContextRef context)
     return jsClass;
 }
 
+static void Base_initialize(JSContextRef context, JSObjectRef object, JSValueRef* exception)
+{
+    assert(!JSObjectGetPrivate(object));
+    JSObjectSetPrivate(object, (void*)1);
+}
+
+static bool Base_didFinalize;
+static void Base_finalize(JSObjectRef object)
+{
+    assert((void*)3 == JSObjectGetPrivate(object));
+    Base_didFinalize = true;
+}
+
+static JSClassRef Base_class(JSContextRef context)
+{
+    static JSClassRef jsClass;
+    if (!jsClass) {
+        JSClassDefinition definition = kJSClassDefinitionNull;
+        definition.initialize = Base_initialize;
+        definition.finalize = Base_finalize;
+        jsClass = JSClassCreate(&definition);
+    }
+    return jsClass;
+}
+
+static void Derived_initialize(JSContextRef context, JSObjectRef object, JSValueRef* exception)
+{
+    assert((void*)1 == JSObjectGetPrivate(object));
+    JSObjectSetPrivate(object, (void*)2);
+}
+
+static void Derived_finalize(JSObjectRef object)
+{
+    assert((void*)2 == JSObjectGetPrivate(object));
+    JSObjectSetPrivate(object, (void*)3);
+}
+
+static JSClassRef Derived_class(JSContextRef context)
+{
+    static JSClassRef jsClass;
+    if (!jsClass) {
+        JSClassDefinition definition = kJSClassDefinitionNull;
+        definition.parentClass = Base_class(context);
+        definition.initialize = Derived_initialize;
+        definition.finalize = Derived_finalize;
+        jsClass = JSClassCreate(&definition);
+    }
+    return jsClass;
+}
+
 static JSValueRef print_callAsFunction(JSContextRef context, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
 {
     UNUSED_PARAM(functionObject);
@@ -311,7 +361,7 @@ static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjec
 {
     UNUSED_PARAM(constructorObject);
     
-    JSObjectRef result = JSObjectMake(context, NULL, 0);
+    JSObjectRef result = JSObjectMake(context, NULL, 0, NULL);
     if (argumentCount > 0) {
         JSStringRef value = JSStringCreateWithUTF8CString("value");
         JSObjectSetProperty(context, result, value, arguments[0], kJSPropertyAttributeNone, NULL);
@@ -340,7 +390,7 @@ int main(int argc, char* argv[])
     JSValueRef jsZero = JSValueMakeNumber(context, 0);
     JSValueRef jsOne = JSValueMakeNumber(context, 1);
     JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0);
-    JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, JSValueMakeNull(context));
+    JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, JSValueMakeNull(context), NULL);
 
     // FIXME: test funny utf8 characters
     JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString("");
@@ -394,7 +444,7 @@ int main(int argc, char* argv[])
     assert(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);
 #endif // __APPLE__
 
-    JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
+    JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL, NULL);
     assert(didInitialize);
     JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
     JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);
@@ -508,7 +558,7 @@ int main(int argc, char* argv[])
     CFRelease(cfEmptyString);
 #endif // __APPLE__
     
-    jsGlobalValue = JSObjectMake(context, NULL, NULL);
+    jsGlobalValue = JSObjectMake(context, NULL, NULL, NULL);
     JSValueProtect(context, jsGlobalValue);
     JSGarbageCollect(context);
     assert(JSValueIsObject(context, jsGlobalValue));
@@ -616,7 +666,7 @@ int main(int argc, char* argv[])
     assert(!JSObjectSetPrivate(myConstructor, (void*)1));
     assert(!JSObjectGetPrivate(myConstructor));
     
-    o = JSObjectMake(context, NULL, NULL);
+    o = JSObjectMake(context, NULL, NULL, NULL);
     JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL);
     JSObjectSetProperty(context, o, jsCFIString,  JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL);
     JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o);
@@ -639,7 +689,11 @@ int main(int argc, char* argv[])
     v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
     assert(JSValueIsEqual(context, v, o, NULL));
     
-    
+    exception = NULL;
+    o = JSObjectMake(context, Derived_class(context), NULL, &exception);
+    assert(!exception);
+    assert(JSObjectGetPrivate(o) == (void*)2);
+    o = NULL;
     
     char* scriptUTF8 = createStringWithContentsOfFile("testapi.js");
     JSStringRef script = JSStringCreateWithUTF8CString(scriptUTF8);
@@ -658,10 +712,11 @@ int main(int argc, char* argv[])
     free(scriptUTF8);
 
     // Allocate a few dummies so that at least one will be collected
-    JSObjectMake(context, MyObject_class(context), 0);
-    JSObjectMake(context, MyObject_class(context), 0);
+    JSObjectMake(context, MyObject_class(context), NULL, NULL);
+    JSObjectMake(context, MyObject_class(context), NULL, NULL);
     JSGarbageCollect(context);
-    assert(didFinalize);
+    assert(MyObject_didFinalize);
+    assert(Base_didFinalize);
 
     JSStringRelease(jsEmptyIString);
     JSStringRelease(jsOneIString);
index a32650aee562117b39b8173b368820f2dfe5920c..7419ce63675ee8a40fa79f42a3812c7e23387edf 100644 (file)
@@ -1,3 +1,18 @@
+2006-07-17  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Maciej.
+        
+        - Changed the initialize callback to run from least derived class (parent
+        class) to most derived class. This enables C++ style initialization,
+        and derived class overriding of member data.
+        
+        - Added excpetion propopgation to JSObjectMake, to support initialize
+        exceptions, and generally round out our policy of making function
+        signatures as long as possible.
+
+        * API/JSCallbackObject.h: Use ExecState instead of ContextRef, cuz we're
+        in C++ land now.
+
 2006-07-17  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by Maciej.