Fixed part of 3674747. The QT guys need this for feature freeze.
authorrjw <rjw@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 6 Aug 2004 01:05:23 +0000 (01:05 +0000)
committerrjw <rjw@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 6 Aug 2004 01:05:23 +0000 (01:05 +0000)
        This patch implements support for the

        - (id)invokeUndefinedMethodFromWebScript:(NSString *)name withArguments:(NSArray *)args

        method of objects bound to JavaScript.

        Reviewed by John.

        * ChangeLog:
        * bindings/objc/objc_class.mm:
        (ObjcClass::methodsNamed):
        (ObjcClass::fieldNamed):
        * bindings/objc/objc_instance.mm:
        (ObjcInstance::invokeMethod):
        * bindings/objc/objc_runtime.h:
        (KJS::Bindings::ObjcMethod::~ObjcMethod):
        (KJS::Bindings::ObjcMethod::isFallbackMethod):
        (KJS::Bindings::ObjcMethod::javaScriptName):
        * bindings/objc/objc_runtime.mm:
        (ObjcMethod::ObjcMethod):
        (ObjcMethod::getMethodSignature):
        (ObjcMethod::setJavaScriptName):
        * bindings/testbindings.mm:

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

JavaScriptCore/ChangeLog
JavaScriptCore/bindings/objc/objc_class.mm
JavaScriptCore/bindings/objc/objc_instance.mm
JavaScriptCore/bindings/objc/objc_runtime.h
JavaScriptCore/bindings/objc/objc_runtime.mm
JavaScriptCore/bindings/testbindings.mm

index a57bdd9405e3a868e8010c44b9a9564350c5f1f3..88af74020c09c0d128cdc3a52c9fd80ae5f07fca 100644 (file)
@@ -1,3 +1,31 @@
+2004-08-05  Richard Williamson   <rjw@apple.com>
+
+        Fixed part of 3674747.  The QT guys need this for feature freeze.
+
+        This patch implements support for the
+
+        - (id)invokeUndefinedMethodFromWebScript:(NSString *)name withArguments:(NSArray *)args
+
+        method of objects bound to JavaScript.
+
+        Reviewed by John.
+
+        * ChangeLog:
+        * bindings/objc/objc_class.mm:
+        (ObjcClass::methodsNamed):
+        (ObjcClass::fieldNamed):
+        * bindings/objc/objc_instance.mm:
+        (ObjcInstance::invokeMethod):
+        * bindings/objc/objc_runtime.h:
+        (KJS::Bindings::ObjcMethod::~ObjcMethod):
+        (KJS::Bindings::ObjcMethod::isFallbackMethod):
+        (KJS::Bindings::ObjcMethod::javaScriptName):
+        * bindings/objc/objc_runtime.mm:
+        (ObjcMethod::ObjcMethod):
+        (ObjcMethod::getMethodSignature):
+        (ObjcMethod::setJavaScriptName):
+        * bindings/testbindings.mm:
+
 2004-08-04  Vicki Murley  <vicki@apple.com>
 
         Reviewed by mjs.
index f6484c6c0d0926db2adfc3ea1b25a4fdcb482e5f..9676b98aead43a13a662be0342b782e00d83b4ab 100644 (file)
@@ -113,8 +113,10 @@ MethodList ObjcClass::methodsNamed(const char *_name) const
                 NSString *mappedName = 0;
             
                 // See if the class wants to exclude the selector from visibility in JavaScript.
-                if ([(id)thisClass isSelectorExcludedFromWebScript:objcMethod->method_name]) {
-                    continue;
+                if ([(id)thisClass respondsToSelector:@selector(isSelectorExcludedFromWebScript:)]){
+                    if ([(id)thisClass isSelectorExcludedFromWebScript:objcMethod->method_name]) {
+                        continue;
+                    }
                 }
                 
                 // See if the class want to provide a different name for the selector in JavaScript.
@@ -136,8 +138,19 @@ MethodList ObjcClass::methodsNamed(const char *_name) const
         thisClass = thisClass->super_class;
     }
 
-    CFRelease (methodName);
+    if (methodList.length() == 0) {
+        thisClass = _isa;
+        if ([(id)thisClass instancesRespondToSelector:@selector(invokeUndefinedMethodFromWebScript:withArguments:)]){
+            // Fallback methods are created for one-shot use.  They are created here 
+            // and deleted in ObjcInstance::invokeMethod().
+            ObjcMethod *fallbackMethod = new ObjcMethod (thisClass, (const char *)@selector(invokeUndefinedMethodFromWebScript:withArguments:));
+            fallbackMethod->setJavaScriptName(methodName);
+            methodList.addMethod ((Method *)fallbackMethod);
+        }
+    }
     
+    CFRelease (methodName);
+
     return methodList;
 }
 
@@ -153,6 +166,8 @@ Field *ObjcClass::fieldNamed(const char *name) const
         return aField;
     }
 
+    // FIX ME.  See if the instance implement attributeKeys.  Will need to 
+    // change fieldNamed() signature to take a Bindings::Instance.
     while (thisClass != 0) {
         struct objc_ivar_list *fieldsInClass = thisClass->ivars;
         if (fieldsInClass) {
@@ -162,8 +177,10 @@ Field *ObjcClass::fieldNamed(const char *name) const
                 NSString *mappedName = 0;
 
                 // See if the class wants to exclude the selector from visibility in JavaScript.
-                if ([(id)thisClass isKeyExcludedFromWebScript:objcIVar->ivar_name]) {
-                    continue;
+                if ([(id)thisClass respondsToSelector:@selector(isKeyExcludedFromWebScript:)]) {
+                    if ([(id)thisClass isKeyExcludedFromWebScript:objcIVar->ivar_name]) {
+                        continue;
+                    }
                 }
                 
                 // See if the class want to provide a different name for the selector in JavaScript.
index 78a879a7b1968b36ff16756bfda40b28addc3bb6..8951ee2b50a68f01c6aba5fa917ebb4490568338 100644 (file)
@@ -138,52 +138,75 @@ NS_DURING
     [invocation setTarget:_instance];
     unsigned i, count = args.size();
     
-    if (count != [signature numberOfArguments] - 2){
-        return Undefined();
-    }
-    
-    for (i = 2; i < count+2; i++) {
-        const char *type = [signature getArgumentTypeAtIndex:i];
-        ObjcValueType objcValueType = objcValueTypeForType (type);
-
-        // Must have a valid argument type.  This method signature should have
-        // been filtered already to ensure that it has acceptable argument
-        // types.
-        assert (objcValueType != ObjcInvalidType && objcValueType != ObjcVoidType);
+    if (method->isFallbackMethod()) {
+        // invokeUndefinedMethodFromWebScript:withArguments: implementation must return an
+        // object.
+        if (strcmp ([signature methodReturnType], "@") != 0) {
+            OBJC_LOG ("incorrect signature for invokeUndefinedMethodFromWebScript:withArguments:, expected object return type");
+            delete method;
+            return Undefined();
+        }
         
-        ObjcValue value = convertValueToObjcValue (exec, args.at(i-2), objcValueType);
+        // Invoke invokeUndefinedMethodFromWebScript:withArguments:, pass JavaScript function
+        // name as first (actually at 2) argument and array of args as second.
+        NSString *jsName = (NSString *)method->javaScriptName();
+        [invocation setArgument:&jsName atIndex:2];
         
-        switch (objcValueType) {
-            case ObjcObjectType:
-                [invocation setArgument:&value.objectValue atIndex:i];
-                break;
-            case ObjcCharType:
-                [invocation setArgument:&value.charValue atIndex:i];
-                break;
-            case ObjcShortType:
-                [invocation setArgument:&value.shortValue atIndex:i];
-                break;
-            case ObjcIntType:
-                [invocation setArgument:&value.intValue atIndex:i];
-                break;
-            case ObjcLongType:
-                [invocation setArgument:&value.longValue atIndex:i];
-                break;
-            case ObjcFloatType:
-                [invocation setArgument:&value.floatValue atIndex:i];
-                break;
-            case ObjcDoubleType:
-                [invocation setArgument:&value.doubleValue atIndex:i];
-                break;
-            default:
-                // Should never get here.  Argument types are filtered (and
-                // the assert above should have fired in the impossible case
-                // of an invalid type anyway).
-                fprintf (stderr, "%s:  invalid type (%d)\n", __PRETTY_FUNCTION__, (int)objcValueType);
-                assert (true);
+        NSMutableArray *objcArgs = [NSMutableArray array];
+        for (i = 0; i < count; i++) {
+            ObjcValue value = convertValueToObjcValue (exec, args.at(i), ObjcObjectType);
+            [objcArgs addObject:value.objectValue];
         }
+        [invocation setArgument:&objcArgs atIndex:3];
     }
+    else {
+        if (count != [signature numberOfArguments] - 2){
+            return Undefined();
+        }
+        
+        for (i = 2; i < count+2; i++) {
+            const char *type = [signature getArgumentTypeAtIndex:i];
+            ObjcValueType objcValueType = objcValueTypeForType (type);
 
+            // Must have a valid argument type.  This method signature should have
+            // been filtered already to ensure that it has acceptable argument
+            // types.
+            assert (objcValueType != ObjcInvalidType && objcValueType != ObjcVoidType);
+            
+            ObjcValue value = convertValueToObjcValue (exec, args.at(i-2), objcValueType);
+            
+            switch (objcValueType) {
+                case ObjcObjectType:
+                    [invocation setArgument:&value.objectValue atIndex:i];
+                    break;
+                case ObjcCharType:
+                    [invocation setArgument:&value.charValue atIndex:i];
+                    break;
+                case ObjcShortType:
+                    [invocation setArgument:&value.shortValue atIndex:i];
+                    break;
+                case ObjcIntType:
+                    [invocation setArgument:&value.intValue atIndex:i];
+                    break;
+                case ObjcLongType:
+                    [invocation setArgument:&value.longValue atIndex:i];
+                    break;
+                case ObjcFloatType:
+                    [invocation setArgument:&value.floatValue atIndex:i];
+                    break;
+                case ObjcDoubleType:
+                    [invocation setArgument:&value.doubleValue atIndex:i];
+                    break;
+                default:
+                    // Should never get here.  Argument types are filtered (and
+                    // the assert above should have fired in the impossible case
+                    // of an invalid type anyway).
+                    fprintf (stderr, "%s:  invalid type (%d)\n", __PRETTY_FUNCTION__, (int)objcValueType);
+                    assert (true);
+            }
+        }
+    }
+    
     // Invoke the ObjectiveC method.
     [invocation invoke];
 
@@ -209,6 +232,11 @@ NS_DURING
         [invocation getReturnValue:buffer];
         resultValue = convertObjcValueToValue (exec, buffer, objcValueType);
     }
+
+    // Fallback methods are created for one-shot use.  They are created in 
+    // ObjcClass::methodsNamed() and deleted here.
+    if (method->isFallbackMethod())
+        delete method;
     
 NS_HANDLER
     
index 2e1bc9430f4d86e2e5985a24e5d4c721df31f811..9ade5a31b38d4ae3162b2a188d8e01cb60fa4bdb 100644 (file)
@@ -77,6 +77,8 @@ public:
 
     ObjcMethod(struct objc_class *aClass, const char *_selector);
     ~ObjcMethod () {
+        if (_javaScriptName);
+            CFRelease (_javaScriptName);
     };
 
     ObjcMethod(const ObjcMethod &other) : Method() {
@@ -100,9 +102,14 @@ public:
     
     NSMethodSignature *getMethodSignature() const;
     
+    bool isFallbackMethod() const { return strcmp(_selector, "invokeUndefinedMethodFromWebScript:withArguments:") == 0; }
+    void setJavaScriptName (CFStringRef n);
+    CFStringRef javaScriptName() const { return _javaScriptName; }
+    
 private:
     struct objc_class *_objcClass;
     const char *_selector;
+    CFStringRef _javaScriptName;
 };
 
 class ObjcArray : public Array
index dae9d8958ea33f1ec9b5d7f706752689b48df86f..cdb3103cfc093ac243b0f70453db552096c6331d 100644 (file)
@@ -43,6 +43,7 @@ ObjcMethod::ObjcMethod(ClassStructPtr aClass, const char *name)
 {
     _objcClass = aClass;
     _selector = name;   // Assume ObjC runtime keeps these around forever.
+    _javaScriptName = 0;
 }
 
 const char *ObjcMethod::name() const
@@ -61,6 +62,15 @@ NSMethodSignature *ObjcMethod::getMethodSignature() const
     return [(id)_objcClass instanceMethodSignatureForSelector:(SEL)_selector];
 }
 
+void ObjcMethod::setJavaScriptName (CFStringRef n)
+{
+    if (n != _javaScriptName) {
+        if (_javaScriptName != 0)
+            CFRelease (_javaScriptName);
+        _javaScriptName = (CFStringRef)CFRetain (n);
+    }
+}
+
 // ---------------------- ObjcField ----------------------
 
 
index d1ea852a2a2d424673f61391d5f5e739cd746fbd..516410e65e4eeb9f8b37f302a47f09e300b47641 100644 (file)
     return nil;
 }
 
+- (id)invokeUndefinedMethodFromWebScript:(NSString *)name withArguments:(NSArray *)args;
+{
+       NSLog (@"Call to undefined method %@", name);
+       NSLog (@"%d args\n", [args count]);
+       int i;
+       for (i = 0; i < [args count]; i++) {
+               NSLog (@"%d: %@\n", i, [args objectAtIndex:i]);
+       }
+       return @"success";
+}
+
 - init
 {
     LOG ("\n");