[banshee] [JavaScriptCore] Implemented CallAsConstructor



commit a9c021eda7bca8a5970db03ed6dc2657b544fb35
Author: Aaron Bockover <abockover novell com>
Date:   Tue Nov 30 11:50:41 2010 -0500

    [JavaScriptCore] Implemented CallAsConstructor
    
    Fixed crasher in JSClassDefinition static method invocation because
    the delegate invoked by native was being GCed.

 .../JavaScriptCore.Bridge/Tests/RuntimeTests.cs    |    4 +-
 .../JavaScriptCore/JSClassDefinition.cs            |   51 ++++++++++++++------
 .../Banshee.WebBrowser/JavaScriptCore/JSObject.cs  |   11 ++++
 .../Banshee.WebBrowser/JavaScriptCore/JSValue.cs   |    9 ++++
 .../JavaScriptCore/Tests/JSClassTests.cs           |   25 +++++++---
 5 files changed, 75 insertions(+), 25 deletions(-)
---
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore.Bridge/Tests/RuntimeTests.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore.Bridge/Tests/RuntimeTests.cs
index 1ac4ca7..f73e545 100644
--- a/src/Core/Banshee.WebBrowser/JavaScriptCore.Bridge/Tests/RuntimeTests.cs
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore.Bridge/Tests/RuntimeTests.cs
@@ -48,7 +48,7 @@ namespace JavaScriptCore.Bridge.Tests
         [Test]
         public void TestExceptionBoundaryJsCatch ()
         {
-            context.EvaluateScript ("try { mjsc.import = 'foo'; } catch (e) { this.p = e.toString (); }");
+            context.EvaluateScript ("try { mjs.import = 'foo'; } catch (e) { this.p = e.toString (); }");
             Assert.AreEqual ("IllegalOperationError: Setting properties on this object is not allowed",
                 context.GlobalObject.GetProperty ("p").StringValue);
         }
@@ -57,7 +57,7 @@ namespace JavaScriptCore.Bridge.Tests
         public void TestExceptionBoundaryRoundTrip ()
         {
             try {
-                context.EvaluateScript ("mjsc.import = 'foo'");
+                context.EvaluateScript ("mjs.import = 'foo'");
             } catch (JSException e) {
                 Assert.AreEqual ("IllegalOperationError: Setting properties on this object is not allowed",
                     e.Error.StringValue);
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSClassDefinition.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSClassDefinition.cs
index a7f48d2..3308639 100644
--- a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSClassDefinition.cs
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSClassDefinition.cs
@@ -59,6 +59,7 @@ namespace JavaScriptCore
 
         private JSClassDefinitionNative raw;
         private Dictionary<string, MethodInfo> static_methods;
+        private JSObject.CallAsFunctionCallback static_function_callback;
 
         public virtual string ClassName {
             get { return GetType ().FullName.Replace (".", "_"); }
@@ -82,6 +83,7 @@ namespace JavaScriptCore
             Override ("OnJSSetProperty", () => raw.set_property = new JSObject.SetPropertyCallback (JSSetProperty));
             Override ("OnJSDeleteProperty", () => raw.delete_property = new JSObject.DeletePropertyCallback (JSDeleteProperty));
             Override ("OnJSGetPropertyNames", () => raw.get_property_names = new JSObject.GetPropertyNamesCallback (JSGetPropertyNames));
+            Override ("OnCallAsConstructor", () => raw.call_as_constructor = new JSObject.CallAsConstructorCallback (JSCallAsConstructor));
         }
 
         private void InstallStaticMethods ()
@@ -116,10 +118,14 @@ namespace JavaScriptCore
                         methods = new List<JSStaticFunction> ();
                     }
 
+                    if (static_function_callback == null) {
+                        static_function_callback = new JSObject.CallAsFunctionCallback (OnStaticFunctionCallback);
+                    }
+
                     methods.Add (new JSStaticFunction () {
                         Name = attr.Name,
                         Attributes = attr.Attributes,
-                        Callback = OnStaticFunctionCallback
+                        Callback = static_function_callback
                     });
                 }
             }
@@ -128,17 +134,11 @@ namespace JavaScriptCore
                 var size = Marshal.SizeOf (typeof (JSStaticFunction));
                 var ptr = Marshal.AllocHGlobal (size * (methods.Count + 1));
 
-                Console.WriteLine ("ALLOC {0} bytes ({1}b x {2}) @ {3}",
-                    size * (methods.Count + 1), size, methods.Count + 1, ptr);
-
                 for (int i = 0; i < methods.Count; i++) {
-                    Console.WriteLine ("STRUCT [{0}] @ {1}",
-                        methods[i].Name, new IntPtr (ptr.ToInt64 () + size * i));
                     Marshal.StructureToPtr (methods[i],
                         new IntPtr (ptr.ToInt64 () + size * i), false);
                 }
 
-                Console.WriteLine ("EMPTY @ {0}", new IntPtr (ptr.ToInt64 () + size * methods.Count));
                 Marshal.StructureToPtr (new JSStaticFunction (),
                     new IntPtr (ptr.ToInt64 () + size * methods.Count), false);
 
@@ -167,19 +167,25 @@ namespace JavaScriptCore
         {
             var context = new JSContext (ctx);
             var fn = new JSObject (ctx, function);
+            string fn_name = null;
+            if (fn.HasProperty ("name")) {
+                var prop = fn.GetProperty ("name");
+                if (prop != null && prop.IsString) {
+                    fn_name = prop.StringValue;
+                }
+            }
 
             MethodInfo method = null;
-            if (!static_methods.TryGetValue (fn.GetProperty ("name").StringValue, out method)) {
-                return IntPtr.Zero;
+            if (fn_name == null || !static_methods.TryGetValue (fn_name, out method)) {
+                return JSValue.NewUndefined (context).Raw;
             }
 
-            var args = new JSValue[argumentCount.ToInt32 ()];
-
-            for (int i = 0; i < args.Length; i++) {
-                args[i] = new JSValue (context, Marshal.ReadIntPtr (arguments, i * IntPtr.Size));
-            }
+            var result = method.Invoke (null, new object [] {
+                fn,
+                new JSObject (context, thisObject),
+                JSValue.MarshalArray (ctx, arguments, argumentCount)
+            });
 
-            var result = method.Invoke (null, new object [] { fn, new JSObject (context, thisObject), args });
             return result == null
                 ? JSValue.NewUndefined (context).Raw
                 : ((JSValue)result).Raw;
@@ -260,5 +266,20 @@ namespace JavaScriptCore
         protected virtual void OnJSGetPropertyNames (JSObject obj, JSPropertyNameAccumulator propertyNames)
         {
         }
+
+        private IntPtr JSCallAsConstructor (IntPtr ctx, IntPtr constructor,
+            IntPtr argumentCount, IntPtr arguments, ref IntPtr exception)
+        {
+            var result = OnJSCallAsConstructor (new JSObject (ctx, constructor),
+                JSValue.MarshalArray (ctx, arguments, argumentCount));
+            return result == null
+                ? JSValue.NewUndefined (new JSContext (ctx)).Raw
+                : ((JSValue)result).Raw;
+        }
+
+        protected virtual JSObject OnJSCallAsConstructor (JSObject constructor, JSValue [] args)
+        {
+            return null;
+        }
     }
 }
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSObject.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSObject.cs
index c9ede2a..91bb0c9 100644
--- a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSObject.cs
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSObject.cs
@@ -181,6 +181,17 @@ namespace JavaScriptCore
 #endregion
 
         [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern void JSObjectSetPrivate (IntPtr obj, IntPtr data);
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
+        private static extern IntPtr JSObjectGetPrivate (IntPtr obj);
+
+        public IntPtr UnmanagedPrivate {
+            get { return JSObjectGetPrivate (Raw); }
+            set { JSObjectSetPrivate (Raw, value); }
+        }
+
+        [DllImport (JSContext.NATIVE_IMPORT)]
         private static extern bool JSObjectIsFunction (IntPtr ctx, IntPtr obj);
 
         public bool IsFunction {
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSValue.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSValue.cs
index ae14e57..5614b1c 100644
--- a/src/Core/Banshee.WebBrowser/JavaScriptCore/JSValue.cs
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/JSValue.cs
@@ -277,5 +277,14 @@ namespace JavaScriptCore
         {
             return IsObject ? ToJsonString (0) ?? StringValue : StringValue;
         }
+
+        public static JSValue [] MarshalArray (IntPtr context, IntPtr items, IntPtr itemCount)
+        {
+            var array = new JSValue[itemCount.ToInt32 ()];
+            for (int i = 0; i < array.Length; i++) {
+                array[i] = new JSValue (context, Marshal.ReadIntPtr (items, i * IntPtr.Size));
+            }
+            return array;
+        }
     }
 }
diff --git a/src/Core/Banshee.WebBrowser/JavaScriptCore/Tests/JSClassTests.cs b/src/Core/Banshee.WebBrowser/JavaScriptCore/Tests/JSClassTests.cs
index f460e53..df399ba 100644
--- a/src/Core/Banshee.WebBrowser/JavaScriptCore/Tests/JSClassTests.cs
+++ b/src/Core/Banshee.WebBrowser/JavaScriptCore/Tests/JSClassTests.cs
@@ -36,7 +36,14 @@ namespace JavaScriptCore.Tests
     {
         private JSContext context;
 
-        private class JSClassTest : JSClassDefinition
+        [TestFixtureSetUp]
+        public void Init ()
+        {
+            context = new JSContext ();
+            context.GlobalObject.SetProperty ("x", new JSObject (context, new JSTestStaticClass ().CreateClass ()));
+        }
+
+        private class JSTestStaticClass : JSClassDefinition
         {
             [JSStaticFunction ("return_managed_null")]
             private static JSValue ReturnManagedNull (JSObject function, JSObject thisObject, JSValue [] args)
@@ -96,13 +103,6 @@ namespace JavaScriptCore.Tests
             }
         }
 
-        [TestFixtureSetUp]
-        public void Init ()
-        {
-            context = new JSContext ();
-            context.GlobalObject.SetProperty ("x", new JSObject (context, new JSClassTest ().CreateClass ()));
-        }
-
         [Test]
         public void TestEnsureJavaScriptCoreVoidReturnIsUndefined ()
         {
@@ -150,6 +150,15 @@ namespace JavaScriptCore.Tests
         {
             context.EvaluateScript ("x.args (true, 42, 'banshee', x.args, null, undefined)");
         }
+
+        private class JSTestInstanceClass : JSClassDefinition
+        {
+            protected override JSObject OnJSCallAsConstructor (JSObject constructor, JSValue[] args)
+            {
+                Console.WriteLine ("HELLO!");
+                return null;
+            }
+        }
     }
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]