Changeset 243283 in webkit
- Timestamp:
- Mar 21, 2019, 2:43:15 AM (7 years ago)
- Location:
- trunk
- Files:
-
- 6 edited
-
Source/JavaScriptCore/API/glib/JSCCallbackFunction.cpp (modified) (1 diff)
-
Source/JavaScriptCore/API/glib/JSCClass.cpp (modified) (7 diffs)
-
Source/JavaScriptCore/API/glib/JSCValue.cpp (modified) (5 diffs)
-
Source/JavaScriptCore/ChangeLog (modified) (1 diff)
-
Tools/ChangeLog (modified) (1 diff)
-
Tools/TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/API/glib/JSCCallbackFunction.cpp
r242349 r243283 205 205 switch (g_type_fundamental(G_VALUE_TYPE(&returnValue))) { 206 206 case G_TYPE_POINTER: 207 case G_TYPE_BOXED: 207 208 case G_TYPE_OBJECT: 208 209 if (auto* ptr = returnValue.data[0].v_pointer) -
trunk/Source/JavaScriptCore/API/glib/JSCClass.cpp
r239427 r243283 590 590 * jsc_context_set_value() to make the constructor available in the global object. 591 591 * 592 * Note that the value returned by @callback is adopted by @jsc_class, and the #GDestroyNotify passed to 593 * jsc_context_register_class() is responsible for disposing of it. 594 * 592 595 * Returns: (transfer full): a #JSCValue representing the class constructor. 593 596 */ … … 636 639 * jsc_context_set_value() to make the constructor available in the global object. 637 640 * 641 * Note that the value returned by @callback is adopted by @jsc_class, and the #GDestroyNotify passed to 642 * jsc_context_register_class() is responsible for disposing of it. 643 * 638 644 * Returns: (transfer full): a #JSCValue representing the class constructor. 639 645 */ … … 676 682 * This function creates the constructor, which needs to be added to an object as a property to be able to use it. Use 677 683 * jsc_context_set_value() to make the constructor available in the global object. 684 * 685 * Note that the value returned by @callback is adopted by @jsc_class, and the #GDestroyNotify passed to 686 * jsc_context_register_class() is responsible for disposing of it. 678 687 * 679 688 * Returns: (transfer full): a #JSCValue representing the class constructor. … … 723 732 * @user_data as last parameter. When the method is cleared in the #JSCClass context, @destroy_notify is called with 724 733 * @user_data as parameter. 734 * 735 * Note that the value returned by @callback must be transfer full. In case of non-refcounted boxed types, you should use 736 * %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used. 737 * If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created 738 * with jsc_value_new_object() that receives the copy as the instance parameter. 725 739 */ 726 740 void jsc_class_add_method(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned paramCount, ...) … … 759 773 * @user_data as last parameter. When the method is cleared in the #JSCClass context, @destroy_notify is called with 760 774 * @user_data as parameter. 775 * 776 * Note that the value returned by @callback must be transfer full. In case of non-refcounted boxed types, you should use 777 * %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used. 778 * If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created 779 * with jsc_value_new_object() that receives the copy as the instance parameter. 761 780 */ 762 781 void jsc_class_add_methodv(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned parametersCount, GType *parameterTypes) … … 791 810 * with the method arguments and then @user_data as last parameter. When the method is cleared in the #JSCClass context, 792 811 * @destroy_notify is called with @user_data as parameter. 812 * 813 * Note that the value returned by @callback must be transfer full. In case of non-refcounted boxed types, you should use 814 * %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used. 815 * If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created 816 * with jsc_value_new_object() that receives the copy as the instance parameter. 793 817 */ 794 818 void jsc_class_add_method_variadic(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType) … … 817 841 * by the value to be set and then @user_data as the last parameter. When the property is cleared in the 818 842 * #JSCClass context, @destroy_notify is called with @user_data as parameter. 843 * 844 * Note that the value returned by @getter must be transfer full. In case of non-refcounted boxed types, you should use 845 * %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used. 846 * If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created 847 * with jsc_value_new_object() that receives the copy as the instance parameter. 819 848 */ 820 849 void jsc_class_add_property(JSCClass* jscClass, const char* name, GType propertyType, GCallback getter, GCallback setter, gpointer userData, GDestroyNotify destroyNotify) -
trunk/Source/JavaScriptCore/API/glib/JSCValue.cpp
r243200 r243283 589 589 * jsc_value_new_object: 590 590 * @context: a #JSCContext 591 * @instance: (nullable) : an object instance or %NULL591 * @instance: (nullable) (transfer full): an object instance or %NULL 592 592 * @jsc_class: (nullable): the #JSCClass of @instance 593 593 * 594 594 * Create a new #JSCValue from @instance. If @instance is %NULL a new empty object is created. 595 * When @instance is provided, @jsc_class must be provided too. 595 * When @instance is provided, @jsc_class must be provided too. @jsc_class takes ownership of 596 * @instance that will be freed by the #GDestroyNotify passed to jsc_context_register_class(). 596 597 * 597 598 * Returns: (transfer full): a #JSCValue. … … 1084 1085 * @user_data as parameter. This is equivalent to JavaScript <function>Object.defineProperty()</function> 1085 1086 * when used with an accessor descriptor. 1087 * 1088 * Note that the value returned by @getter must be fully transferred. In case of boxed types, you could use 1089 * %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used. 1090 * If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created 1091 * with jsc_value_new_object() that receives the copy as instance parameter. 1086 1092 */ 1087 1093 void jsc_value_object_define_property_accessor(JSCValue* value, const char* propertyName, JSCValuePropertyFlags flags, GType propertyType, GCallback getter, GCallback setter, gpointer userData, GDestroyNotify destroyNotify) … … 1160 1166 * cleared in @context, @destroy_notify is called with @user_data as parameter. 1161 1167 * 1168 * Note that the value returned by @callback must be fully transferred. In case of boxed types, you could use 1169 * %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used. 1170 * If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created 1171 * with jsc_value_new_object() that receives the copy as instance parameter. 1172 * 1162 1173 * Returns: (transfer full): a #JSCValue. 1163 1174 */ … … 1196 1207 * cleared in @context, @destroy_notify is called with @user_data as parameter. 1197 1208 * 1209 * Note that the value returned by @callback must be fully transferred. In case of boxed types, you could use 1210 * %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used. 1211 * If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created 1212 * with jsc_value_new_object() that receives the copy as instance parameter. 1213 * 1198 1214 * Returns: (transfer full): a #JSCValue. 1199 1215 */ … … 1228 1244 * When the function is cleared in @context, @destroy_notify is called with @user_data as parameter. 1229 1245 * 1246 * Note that the value returned by @callback must be fully transferred. In case of boxed types, you could use 1247 * %G_TYPE_POINTER instead of the actual boxed #GType to ensure that the instance owned by #JSCClass is used. 1248 * If you really want to return a new copy of the boxed type, use #JSC_TYPE_VALUE and return a #JSCValue created 1249 * with jsc_value_new_object() that receives the copy as instance parameter. 1250 * 1230 1251 * Returns: (transfer full): a #JSCValue. 1231 1252 */ -
trunk/Source/JavaScriptCore/ChangeLog
r243280 r243283 1 2019-03-21 Carlos Garcia Campos <cgarcia@igalia.com> 2 3 [GLib] Returning G_TYPE_OBJECT from a method does not work 4 https://bugs.webkit.org/show_bug.cgi?id=195574 5 6 Reviewed by Michael Catanzaro. 7 8 Add more documentation to clarify the ownership of wrapped objects when created and when returned by functions. 9 10 * API/glib/JSCCallbackFunction.cpp: 11 (JSC::JSCCallbackFunction::construct): Also allow to return boxed types from a constructor. 12 * API/glib/JSCClass.cpp: 13 * API/glib/JSCValue.cpp: 14 1 15 2019-03-21 Mark Lam <mark.lam@apple.com> 2 16 -
trunk/Tools/ChangeLog
r243278 r243283 1 2019-03-21 Carlos Garcia Campos <cgarcia@igalia.com> 2 3 [GLib] Returning G_TYPE_OBJECT from a method does not work 4 https://bugs.webkit.org/show_bug.cgi?id=195574 5 6 Reviewed by Michael Catanzaro. 7 8 Add new test cases to check the behavior of constructors and functions returning GObject and boxed types. 9 10 * TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp: 11 (getGFile): 12 (getParent): 13 (createGString): 14 (getGString): 15 (getGStringCopyWillRaise): 16 (getGStringCopy): 17 (getGStringStr): 18 (getGStringLen): 19 (freeGString): 20 (testJSCClass): 21 1 22 2019-03-20 Saam Barati <sbarati@apple.com> 2 23 -
trunk/Tools/TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp
r242349 r243283 1598 1598 } 1599 1599 1600 static GFile* getGFile(GFile* file) 1601 { 1602 return G_FILE(g_object_ref(file)); 1603 } 1604 1605 static JSCValue* getParent(GFile* file, JSCClass* jscClass) 1606 { 1607 auto* checker = static_cast<LeakChecker*>(g_object_get_data(G_OBJECT(jsc_context_get_current()), "leak-checker")); 1608 GFile* parent = g_file_get_parent(file); 1609 checker->watch(parent); 1610 auto* value = jsc_value_new_object(jsc_context_get_current(), parent, jscClass); 1611 checker->watch(value); 1612 return value; 1613 } 1614 1615 static GString* createGString(const char* str) 1616 { 1617 return g_string_new(str); 1618 } 1619 1620 static GString* getGString(GString* str) 1621 { 1622 return str; 1623 } 1624 1625 static GString* getGStringCopyWillRaise(GString* str) 1626 { 1627 return static_cast<GString*>(g_boxed_copy(G_TYPE_GSTRING, str)); 1628 } 1629 1630 static JSCValue* getGStringCopy(GString *str, JSCClass* jscClass) 1631 { 1632 auto* checker = static_cast<LeakChecker*>(g_object_get_data(G_OBJECT(jsc_context_get_current()), "leak-checker")); 1633 auto* copy = getGStringCopyWillRaise(str); 1634 auto* value = jsc_value_new_object(jsc_context_get_current(), copy, jscClass); 1635 checker->watch(value); 1636 return value; 1637 } 1638 1639 static char* getGStringStr(GString* str) 1640 { 1641 return g_strdup(str->str); 1642 } 1643 1644 static guint64 getGStringLen(GString* str) 1645 { 1646 return str->len; 1647 } 1648 1649 static void freeGString(GString* str) 1650 { 1651 g_string_free(str, TRUE); 1652 } 1653 1600 1654 static void testJSCClass() 1601 1655 { … … 2297 2351 resultString.reset(jsc_value_to_string(value2.get())); 2298 2352 g_assert_cmpstr(resultString.get(), ==, currentDirectory.get()); 2353 2354 jsc_class_add_method(jscClass, "getGFile", G_CALLBACK(getGFile), nullptr, nullptr, G_TYPE_OBJECT, 0, G_TYPE_NONE); 2355 result = adoptGRef(jsc_context_evaluate(context.get(), "f = new GFile('.'); f2 = f.getGFile(); f2.getPath()", -1)); 2356 checker.watch(result.get()); 2357 g_assert_true(jsc_value_is_string(result.get())); 2358 resultString.reset(jsc_value_to_string(result.get())); 2359 g_assert_cmpstr(resultString.get(), ==, currentDirectory.get()); 2360 2361 value = adoptGRef(jsc_value_object_invoke_method(file.get(), "getGFile", G_TYPE_NONE)); 2362 checker.watch(value.get()); 2363 g_assert_true(value.get() == file.get()); 2364 2365 jsc_class_add_method(jscClass, "getParent", G_CALLBACK(getParent), jscClass, nullptr, JSC_TYPE_VALUE, 0, G_TYPE_NONE); 2366 result = adoptGRef(jsc_context_evaluate(context.get(), "f = new GFile('.'); p = f.getParent(); p.getPath()", -1)); 2367 checker.watch(result.get()); 2368 g_assert_true(jsc_value_is_string(result.get())); 2369 resultString.reset(jsc_value_to_string(result.get())); 2370 GUniquePtr<char> parentDirectory(g_path_get_dirname(currentDirectory.get())); 2371 g_assert_cmpstr(resultString.get(), ==, parentDirectory.get()); 2372 2373 jsc_class_add_method(jscClass, "equal", G_CALLBACK(g_file_equal), nullptr, nullptr, G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT); 2374 result = adoptGRef(jsc_context_evaluate(context.get(), "f1 = new GFile('.'); f2 = new GFile('.'); f1.equal(f2);", -1)); 2375 checker.watch(result.get()); 2376 g_assert_true(jsc_value_is_boolean(result.get())); 2377 g_assert_true(jsc_value_to_boolean(result.get())); 2378 2379 GFile* fileObject = g_file_new_for_path("."); 2380 checker.watch(fileObject); 2381 GRefPtr<JSCValue> fileValue = adoptGRef(jsc_value_new_object(context.get(), fileObject, jscClass)); 2382 checker.watch(fileValue.get()); 2383 2384 result = adoptGRef(jsc_value_object_invoke_method(file.get(), "equal", G_TYPE_OBJECT, fileObject, G_TYPE_NONE)); 2385 checker.watch(result.get()); 2386 g_assert_true(jsc_value_is_boolean(result.get())); 2387 g_assert_true(jsc_value_to_boolean(result.get())); 2388 2389 result = adoptGRef(jsc_value_object_invoke_method(file.get(), "equal", JSC_TYPE_VALUE, fileValue.get(), G_TYPE_NONE)); 2390 checker.watch(result.get()); 2391 g_assert_true(jsc_value_is_boolean(result.get())); 2392 g_assert_true(jsc_value_to_boolean(result.get())); 2393 } 2394 2395 { 2396 LeakChecker checker; 2397 GRefPtr<JSCContext> context = adoptGRef(jsc_context_new()); 2398 checker.watch(context.get()); 2399 g_object_set_data(G_OBJECT(context.get()), "leak-checker", &checker); 2400 ExceptionHandler exceptionHandler(context.get()); 2401 2402 JSCClass* jscClass = jsc_context_register_class(context.get(), "GString", nullptr, nullptr, reinterpret_cast<GDestroyNotify>(freeGString)); 2403 checker.watch(jscClass); 2404 2405 GRefPtr<JSCValue> constructor = adoptGRef(jsc_class_add_constructor(jscClass, nullptr, G_CALLBACK(createGString), nullptr, nullptr, G_TYPE_GSTRING, 1, G_TYPE_STRING)); 2406 checker.watch(constructor.get()); 2407 g_assert_true(jsc_value_is_constructor(constructor.get())); 2408 2409 jsc_class_add_property(jscClass, "str", G_TYPE_STRING, G_CALLBACK(getGStringStr), nullptr, nullptr, nullptr); 2410 jsc_class_add_property(jscClass, "len", G_TYPE_UINT64, G_CALLBACK(getGStringLen), nullptr, nullptr, nullptr); 2411 2412 jsc_context_set_value(context.get(), jsc_class_get_name(jscClass), constructor.get()); 2413 2414 GRefPtr<JSCValue> str = adoptGRef(jsc_context_evaluate(context.get(), "s = new GString('Foo');", -1)); 2415 checker.watch(str.get()); 2416 g_assert_true(jsc_value_is_object(str.get())); 2417 g_assert_true(jsc_value_object_is_instance_of(str.get(), jsc_class_get_name(jscClass))); 2418 GRefPtr<JSCValue> result = adoptGRef(jsc_context_evaluate(context.get(), "s instanceof GString;", -1)); 2419 checker.watch(result.get()); 2420 g_assert_true(jsc_value_is_boolean(result.get())); 2421 g_assert_true(jsc_value_to_boolean(result.get())); 2422 2423 g_assert_true(jsc_value_object_has_property(str.get(), "str")); 2424 GRefPtr<JSCValue> value = adoptGRef(jsc_value_object_get_property(str.get(), "str")); 2425 checker.watch(value.get()); 2426 g_assert_true(jsc_value_is_string(value.get())); 2427 GUniquePtr<char> resultString(jsc_value_to_string(value.get())); 2428 g_assert_cmpstr(resultString.get(), ==, "Foo"); 2429 2430 GRefPtr<JSCValue> value2 = adoptGRef(jsc_context_evaluate(context.get(), "s.str", -1)); 2431 checker.watch(value2.get()); 2432 g_assert_true(jsc_value_is_string(value2.get())); 2433 resultString.reset(jsc_value_to_string(value2.get())); 2434 g_assert_cmpstr(resultString.get(), ==, "Foo"); 2435 2436 GRefPtr<JSCValue> value3 = adoptGRef(jsc_context_evaluate(context.get(), "s.len", -1)); 2437 checker.watch(value3.get()); 2438 g_assert_true(jsc_value_is_number(value3.get())); 2439 g_assert_cmpint(jsc_value_to_int32(value3.get()), ==, 3); 2440 2441 jsc_class_add_method(jscClass, "getGString", G_CALLBACK(getGString), nullptr, nullptr, G_TYPE_POINTER, 0, G_TYPE_NONE); 2442 result = adoptGRef(jsc_context_evaluate(context.get(), "s = new GString('Self'); s2 = s.getGString(); s2.str;", -1)); 2443 checker.watch(result.get()); 2444 g_assert_true(jsc_value_is_string(result.get())); 2445 resultString.reset(jsc_value_to_string(result.get())); 2446 g_assert_cmpstr(resultString.get(), ==, "Self"); 2447 2448 jsc_class_add_method(jscClass, "getGStringCopy", G_CALLBACK(getGStringCopy), jscClass, nullptr, JSC_TYPE_VALUE, 0, G_TYPE_NONE); 2449 result = adoptGRef(jsc_context_evaluate(context.get(), "s = new GString('Copy'); s2 = s.getGStringCopy(); s2.str;", -1)); 2450 checker.watch(result.get()); 2451 g_assert_true(jsc_value_is_string(result.get())); 2452 resultString.reset(jsc_value_to_string(result.get())); 2453 g_assert_cmpstr(resultString.get(), ==, "Copy"); 2454 2455 jsc_class_add_method(jscClass, "getGStringCopyWillRaise", G_CALLBACK(getGStringCopyWillRaise), nullptr, nullptr, G_TYPE_GSTRING, 0, G_TYPE_NONE); 2456 bool didThrow = false; 2457 g_assert_throw_begin(exceptionHandler, didThrow); 2458 result = adoptGRef(jsc_context_evaluate(context.get(), "s = new GString('Copy'); s2 = s.getGStringCopyWillRaise(); s2.str;", -1)); 2459 checker.watch(result.get()); 2460 g_assert_true(jsc_value_is_undefined(result.get())); 2461 g_assert_did_throw(exceptionHandler, didThrow); 2462 2463 jsc_class_add_method(jscClass, "equal", G_CALLBACK(g_string_equal), nullptr, nullptr, G_TYPE_BOOLEAN, 1, G_TYPE_GSTRING); 2464 result = adoptGRef(jsc_context_evaluate(context.get(), "s1 = new GString('Bar'); s2 = new GString('Bar'); s1.equal(s2);", -1)); 2465 checker.watch(result.get()); 2466 g_assert_true(jsc_value_is_boolean(result.get())); 2467 g_assert_true(jsc_value_to_boolean(result.get())); 2468 2469 GString* strBoxed = g_string_new("Foo"); 2470 GRefPtr<JSCValue> strValue = adoptGRef(jsc_value_new_object(context.get(), strBoxed, jscClass)); 2471 checker.watch(strValue.get()); 2472 2473 result = adoptGRef(jsc_value_object_invoke_method(str.get(), "equal", G_TYPE_GSTRING, strBoxed, G_TYPE_NONE)); 2474 checker.watch(result.get()); 2475 g_assert_true(jsc_value_is_boolean(result.get())); 2476 g_assert_true(jsc_value_to_boolean(result.get())); 2477 2478 result = adoptGRef(jsc_value_object_invoke_method(str.get(), "equal", JSC_TYPE_VALUE, strValue.get(), G_TYPE_NONE)); 2479 checker.watch(result.get()); 2480 g_assert_true(jsc_value_is_boolean(result.get())); 2481 g_assert_true(jsc_value_to_boolean(result.get())); 2299 2482 } 2300 2483 }
Note:
See TracChangeset
for help on using the changeset viewer.