Changeset 231693 in webkit


Ignore:
Timestamp:
May 10, 2018 11:56:57 PM (6 years ago)
Author:
Carlos Garcia Campos
Message:

[JSC][GLIB] Add introspectable alternatives to functions using vargars
https://bugs.webkit.org/show_bug.cgi?id=185508

Reviewed by Michael Catanzaro.

Source/JavaScriptCore:

  • API/glib/JSCClass.cpp:

(jscClassCreateConstructor):
(jsc_class_add_constructor):
(jsc_class_add_constructorv):
(jscClassAddMethod):
(jsc_class_add_method):
(jsc_class_add_methodv):

  • API/glib/JSCClass.h:
  • API/glib/JSCValue.cpp:

(jsObjectCall):
(jscValueCallFunction):
(jsc_value_object_invoke_methodv):
(jscValueFunctionCreate):
(jsc_value_new_function):
(jsc_value_new_functionv):
(jsc_value_function_callv):
(jsc_value_constructor_callv):

  • API/glib/JSCValue.h:
  • API/glib/docs/jsc-glib-4.0-sections.txt:

Tools:

Add test cases for the new API.

  • TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:

(testJSCFunction):
(testJSCObject):

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/glib/JSCClass.cpp

    r231565 r231693  
    522522}
    523523
    524 /**
    525  * jsc_class_add_constructor:
    526  * @jsc_class: a #JSCClass
    527  * @name: (nullable): the constructor name or %NULL
    528  * @callback: (scope async): a #GCallback to be called to create an instance of @jsc_class
    529  * @user_data: (closure): user data to pass to @callback
    530  * @destroy_notify: (nullable): destroy notifier for @user_data
    531  * @return_type: the #GType of the constructor return value
    532  * @n_params: the number of parameter types to follow or 0 if constructor doesn't receive parameters.
    533  * @...: a list of #GType<!-- -->s, one for each parameter.
    534  *
    535  * Add a constructor to @jsc_class. If @name is %NULL, the class name will be used. When <function>new</function>
    536  * is used with the constructor or jsc_value_constructor_call() is called, @callback is invoked receiving the
    537  * parameters and @user_data as the last parameter. When the constructor object is cleared in the #JSCClass context,
    538  * @destroy_notify is called with @user_data as parameter.
    539  *
    540  * This function creates the constructor, that needs to be added to an object as a property to be able to use it. Use
    541  * jsc_context_set_value() to make the constructor available in the global object.
    542  *
    543  * Returns: (transfer full): a #JSCValue representing the class constructor.
    544  */
    545 JSCValue* jsc_class_add_constructor(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned paramCount, ...)
    546 {
    547     g_return_val_if_fail(JSC_IS_CLASS(jscClass), nullptr);
    548     g_return_val_if_fail(callback, nullptr);
    549 
     524static GRefPtr<JSCValue> jscClassCreateConstructor(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, Vector<GType>&& parameters)
     525{
    550526    JSCClassPrivate* priv = jscClass->priv;
    551     g_return_val_if_fail(priv->context, nullptr);
    552 
    553     if (!name)
    554         name = priv->name.data();
    555 
    556     va_list args;
    557     va_start(args, paramCount);
    558     Vector<GType> parameters;
    559     if (paramCount) {
    560         parameters.reserveInitialCapacity(paramCount);
    561         for (unsigned i = 0; i < paramCount; ++i)
    562             parameters.uncheckedAppend(va_arg(args, GType));
    563     }
    564     va_end(args);
    565 
    566527    GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
    567528    JSC::ExecState* exec = toJS(jscContextGetJSContext(priv->context));
     
    576537    jsc_value_object_define_property_data(prototype.get(), "constructor", nonEnumerable, constructor.get());
    577538    priv->constructors.set(name, functionObject);
    578     return constructor.leakRef();
    579 }
    580 
    581 /**
    582  * jsc_class_add_method:
    583  * @jsc_class: a #JSCClass
    584  * @name: the method name
    585  * @callback: (scope async): a #GCallback to be called to invoke method @name of @jsc_class
     539    return constructor;
     540}
     541
     542/**
     543 * jsc_class_add_constructor: (skip)
     544 * @jsc_class: a #JSCClass
     545 * @name: (nullable): the constructor name or %NULL
     546 * @callback: (scope async): a #GCallback to be called to create an instance of @jsc_class
    586547 * @user_data: (closure): user data to pass to @callback
    587548 * @destroy_notify: (nullable): destroy notifier for @user_data
    588  * @return_type: the #GType of the method return value, or %G_TYPE_NONE if the method is void.
    589  * @n_params: the number of parameter types to follow or 0 if the method doesn't receive parameters.
     549 * @return_type: the #GType of the constructor return value
     550 * @n_params: the number of parameter types to follow or 0 if constructor doesn't receive parameters.
    590551 * @...: a list of #GType<!-- -->s, one for each parameter.
    591552 *
    592  * Add method with @name to @jsc_class. When the method is called by JavaScript or jsc_value_object_invoke_method(),
    593  * @callback is called receiving the class instance as first parameter, followed by the method parameters and then
    594  * @user_data as last parameter. When the method is cleared in the #JSCClass context, @destroy_notify is called with
    595  * @user_data as parameter.
    596  */
    597 void jsc_class_add_method(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned paramCount, ...)
    598 {
    599     g_return_if_fail(JSC_IS_CLASS(jscClass));
    600     g_return_if_fail(name);
    601     g_return_if_fail(callback);
     553 * Add a constructor to @jsc_class. If @name is %NULL, the class name will be used. When <function>new</function>
     554 * is used with the constructor or jsc_value_constructor_call() is called, @callback is invoked receiving the
     555 * parameters and @user_data as the last parameter. When the constructor object is cleared in the #JSCClass context,
     556 * @destroy_notify is called with @user_data as parameter.
     557 *
     558 * This function creates the constructor, that needs to be added to an object as a property to be able to use it. Use
     559 * jsc_context_set_value() to make the constructor available in the global object.
     560 *
     561 * Returns: (transfer full): a #JSCValue representing the class constructor.
     562 */
     563JSCValue* jsc_class_add_constructor(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned paramCount, ...)
     564{
     565    g_return_val_if_fail(JSC_IS_CLASS(jscClass), nullptr);
     566    g_return_val_if_fail(callback, nullptr);
    602567
    603568    JSCClassPrivate* priv = jscClass->priv;
    604     g_return_if_fail(priv->context);
     569    g_return_val_if_fail(priv->context, nullptr);
     570
     571    if (!name)
     572        name = priv->name.data();
    605573
    606574    va_list args;
     
    614582    va_end(args);
    615583
     584    return jscClassCreateConstructor(jscClass, name ? name : priv->name.data(), callback, userData, destroyNotify, returnType, WTFMove(parameters)).leakRef();
     585
     586}
     587
     588/**
     589 * jsc_class_add_constructorv: (rename-to jsc_class_add_constructor)
     590 * @jsc_class: a #JSCClass
     591 * @name: (nullable): the constructor name or %NULL
     592 * @callback: (scope async): a #GCallback to be called to create an instance of @jsc_class
     593 * @user_data: (closure): user data to pass to @callback
     594 * @destroy_notify: (nullable): destroy notifier for @user_data
     595 * @return_type: the #GType of the constructor return value
     596 * @n_parameters: the number of parameters
     597 * @parameter_types: (nullable) (array length=n_parameters) (element-type GType): a list of #GType<!-- -->s, one for each parameter, or %NULL
     598 *
     599 * Add a constructor to @jsc_class. If @name is %NULL, the class name will be used. When <function>new</function>
     600 * is used with the constructor or jsc_value_constructor_call() is called, @callback is invoked receiving the
     601 * parameters and @user_data as the last parameter. When the constructor object is cleared in the #JSCClass context,
     602 * @destroy_notify is called with @user_data as parameter.
     603 *
     604 * This function creates the constructor, that needs to be added to an object as a property to be able to use it. Use
     605 * jsc_context_set_value() to make the constructor available in the global object.
     606 *
     607 * Returns: (transfer full): a #JSCValue representing the class constructor.
     608 */
     609JSCValue* jsc_class_add_constructorv(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned parametersCount, GType* parameterTypes)
     610{
     611    g_return_val_if_fail(JSC_IS_CLASS(jscClass), nullptr);
     612    g_return_val_if_fail(callback, nullptr);
     613    g_return_val_if_fail(!parametersCount || parameterTypes, nullptr);
     614
     615    JSCClassPrivate* priv = jscClass->priv;
     616    g_return_val_if_fail(priv->context, nullptr);
     617
     618    if (!name)
     619        name = priv->name.data();
     620
     621    Vector<GType> parameters;
     622    if (parametersCount) {
     623        parameters.reserveInitialCapacity(parametersCount);
     624        for (unsigned i = 0; i < parametersCount; ++i)
     625            parameters.uncheckedAppend(parameterTypes[i]);
     626    }
     627
     628    return jscClassCreateConstructor(jscClass, name ? name : priv->name.data(), callback, userData, destroyNotify, returnType, WTFMove(parameters)).leakRef();
     629}
     630
     631static void jscClassAddMethod(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, Vector<GType>&& parameters)
     632{
     633    JSCClassPrivate* priv = jscClass->priv;
    616634    GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
    617635    JSC::ExecState* exec = toJS(jscContextGetJSContext(priv->context));
     
    627645
    628646/**
     647 * jsc_class_add_method: (skip)
     648 * @jsc_class: a #JSCClass
     649 * @name: the method name
     650 * @callback: (scope async): a #GCallback to be called to invoke method @name of @jsc_class
     651 * @user_data: (closure): user data to pass to @callback
     652 * @destroy_notify: (nullable): destroy notifier for @user_data
     653 * @return_type: the #GType of the method return value, or %G_TYPE_NONE if the method is void.
     654 * @n_params: the number of parameter types to follow or 0 if the method doesn't receive parameters.
     655 * @...: a list of #GType<!-- -->s, one for each parameter.
     656 *
     657 * Add method with @name to @jsc_class. When the method is called by JavaScript or jsc_value_object_invoke_method(),
     658 * @callback is called receiving the class instance as first parameter, followed by the method parameters and then
     659 * @user_data as last parameter. When the method is cleared in the #JSCClass context, @destroy_notify is called with
     660 * @user_data as parameter.
     661 */
     662void jsc_class_add_method(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned paramCount, ...)
     663{
     664    g_return_if_fail(JSC_IS_CLASS(jscClass));
     665    g_return_if_fail(name);
     666    g_return_if_fail(callback);
     667    g_return_if_fail(jscClass->priv->context);
     668
     669    va_list args;
     670    va_start(args, paramCount);
     671    Vector<GType> parameters;
     672    if (paramCount) {
     673        parameters.reserveInitialCapacity(paramCount);
     674        for (unsigned i = 0; i < paramCount; ++i)
     675            parameters.uncheckedAppend(va_arg(args, GType));
     676    }
     677    va_end(args);
     678
     679    jscClassAddMethod(jscClass, name, callback, userData, destroyNotify, returnType, WTFMove(parameters));
     680}
     681
     682/**
     683 * jsc_class_add_methodv: (rename-to jsc_class_add_method)
     684 * @jsc_class: a #JSCClass
     685 * @name: the method name
     686 * @callback: (scope async): a #GCallback to be called to invoke method @name of @jsc_class
     687 * @user_data: (closure): user data to pass to @callback
     688 * @destroy_notify: (nullable): destroy notifier for @user_data
     689 * @return_type: the #GType of the method return value, or %G_TYPE_NONE if the method is void.
     690 * @n_parameters: the number of parameter types to follow or 0 if the method doesn't receive parameters.
     691 * @parameter_types: (nullable) (array length=n_parameters) (element-type GType): a list of #GType<!-- -->s, one for each parameter, or %NULL
     692 *
     693 * Add method with @name to @jsc_class. When the method is called by JavaScript or jsc_value_object_invoke_method(),
     694 * @callback is called receiving the class instance as first parameter, followed by the method parameters and then
     695 * @user_data as last parameter. When the method is cleared in the #JSCClass context, @destroy_notify is called with
     696 * @user_data as parameter.
     697 */
     698void jsc_class_add_methodv(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned parametersCount, GType *parameterTypes)
     699{
     700    g_return_if_fail(JSC_IS_CLASS(jscClass));
     701    g_return_if_fail(name);
     702    g_return_if_fail(callback);
     703    g_return_if_fail(!parametersCount || parameterTypes);
     704    g_return_if_fail(jscClass->priv->context);
     705
     706    Vector<GType> parameters;
     707    if (parametersCount) {
     708        parameters.reserveInitialCapacity(parametersCount);
     709        for (unsigned i = 0; i < parametersCount; ++i)
     710            parameters.uncheckedAppend(parameterTypes[i]);
     711    }
     712
     713    jscClassAddMethod(jscClass, name, callback, userData, destroyNotify, returnType, WTFMove(parameters));
     714}
     715
     716/**
    629717 * jsc_class_add_property:
    630718 * @jsc_class: a #JSCClass
  • trunk/Source/JavaScriptCore/API/glib/JSCClass.h

    r230753 r231693  
    7777
    7878JSC_API GType
    79 jsc_class_get_type        (void);
     79jsc_class_get_type         (void);
    8080
    8181JSC_API const char *
    82 jsc_class_get_name        (JSCClass      *jsc_class);
     82jsc_class_get_name         (JSCClass      *jsc_class);
    8383
    8484JSC_API JSCClass *
    85 jsc_class_get_parent      (JSCClass      *jsc_class);
     85jsc_class_get_parent       (JSCClass      *jsc_class);
    8686
    8787JSC_API JSCValue *
    88 jsc_class_add_constructor (JSCClass      *jsc_class,
    89                            const char    *name,
    90                            GCallback      callback,
    91                            gpointer       user_data,
    92                            GDestroyNotify destroy_notify,
    93                            GType          return_type,
    94                            unsigned       n_params,
    95                            ...);
     88jsc_class_add_constructor  (JSCClass      *jsc_class,
     89                            const char    *name,
     90                            GCallback      callback,
     91                            gpointer       user_data,
     92                            GDestroyNotify destroy_notify,
     93                            GType          return_type,
     94                            guint          n_params,
     95                            ...);
     96
     97JSC_API JSCValue *
     98jsc_class_add_constructorv (JSCClass      *jsc_class,
     99                            const char    *name,
     100                            GCallback      callback,
     101                            gpointer       user_data,
     102                            GDestroyNotify destroy_notify,
     103                            GType          return_type,
     104                            guint          n_parameters,
     105                            GType         *parameter_types);
    96106
    97107JSC_API void
    98 jsc_class_add_method      (JSCClass      *jsc_class,
    99                            const char    *name,
    100                            GCallback      callback,
    101                            gpointer       user_data,
    102                            GDestroyNotify destroy_notify,
    103                            GType          return_type,
    104                            unsigned       n_params,
    105                            ...);
     108jsc_class_add_method       (JSCClass      *jsc_class,
     109                            const char    *name,
     110                            GCallback      callback,
     111                            gpointer       user_data,
     112                            GDestroyNotify destroy_notify,
     113                            GType          return_type,
     114                            guint          n_params,
     115                            ...);
    106116
    107117JSC_API void
    108 jsc_class_add_property    (JSCClass      *jsc_class,
    109                            const char    *name,
    110                            GType          property_type,
    111                            GCallback      getter,
    112                            GCallback      setter,
    113                            gpointer       user_data,
    114                            GDestroyNotify destroy_notify);
     118jsc_class_add_methodv      (JSCClass      *jsc_class,
     119                            const char    *name,
     120                            GCallback      callback,
     121                            gpointer       user_data,
     122                            GDestroyNotify destroy_notify,
     123                            GType          return_type,
     124                            guint          n_parameters,
     125                            GType         *parameter_types);
     126
     127JSC_API void
     128jsc_class_add_property     (JSCClass      *jsc_class,
     129                            const char    *name,
     130                            GType          property_type,
     131                            GCallback      getter,
     132                            GCallback      setter,
     133                            gpointer       user_data,
     134                            GDestroyNotify destroy_notify);
    115135
    116136G_END_DECLS
  • trunk/Source/JavaScriptCore/API/glib/JSCValue.cpp

    r231565 r231693  
    458458
    459459/**
    460  * jsc_value_new_array:
     460 * jsc_value_new_array: (skip)
    461461 * @context: a #JSCContext
    462462 * @first_item_type: #GType of first item, or %G_TYPE_NONE
     
    832832}
    833833
     834static JSValueRef jsObjectCall(JSGlobalContextRef jsContext, JSObjectRef function, JSC::JSCCallbackFunction::Type functionType, JSObjectRef thisObject, const Vector<JSValueRef>& arguments, JSValueRef* exception)
     835{
     836    switch (functionType) {
     837    case JSC::JSCCallbackFunction::Type::Constructor:
     838        return JSObjectCallAsConstructor(jsContext, function, arguments.size(), arguments.data(), exception);
     839        break;
     840    case JSC::JSCCallbackFunction::Type::Method:
     841        ASSERT(thisObject);
     842        FALLTHROUGH;
     843    case JSC::JSCCallbackFunction::Type::Function:
     844        return JSObjectCallAsFunction(jsContext, function, thisObject, arguments.size(), arguments.data(), exception);
     845        break;
     846    }
     847    RELEASE_ASSERT_NOT_REACHED();
     848}
     849
    834850static GRefPtr<JSCValue> jscValueCallFunction(JSCValue* value, JSObjectRef function, JSC::JSCCallbackFunction::Type functionType, JSObjectRef thisObject, GType firstParameterType, va_list args)
    835851{
     
    859875    }
    860876
    861     JSValueRef result;
    862     switch (functionType) {
    863     case JSC::JSCCallbackFunction::Type::Constructor:
    864         result = JSObjectCallAsConstructor(jsContext, function, arguments.size(), arguments.data(), &exception);
    865         break;
    866     case JSC::JSCCallbackFunction::Type::Method:
    867         ASSERT(thisObject);
    868         FALLTHROUGH;
    869     case JSC::JSCCallbackFunction::Type::Function:
    870         result = JSObjectCallAsFunction(jsContext, function, thisObject, arguments.size(), arguments.data(), &exception);
    871         break;
    872     }
     877    auto result = jsObjectCall(jsContext, function, functionType, thisObject, arguments, &exception);
    873878    if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
    874879        return adoptGRef(jsc_value_new_undefined(priv->context.get()));
     
    878883
    879884/**
    880  * jsc_value_object_invoke_method:
     885 * jsc_value_object_invoke_method: (skip)
    881886 * @value: a #JSCValue
    882887 * @name: the method name
     
    922927
    923928    return result.leakRef();
     929}
     930
     931/**
     932 * jsc_value_object_invoke_methodv: (rename-to jsc_value_object_invoke_method)
     933 * @value: a #JSCValue
     934 * @name: the method name
     935 * @n_parameters: the number of parameters
     936 * @parameters: (nullable) (array length=n_parameters) (element-type JSCValue): the #JSCValue<!-- -->s to pass as parameters to the method, or %NULL
     937 *
     938 * Invoke method with @name on object referenced by @value, passing the given @parameters. If
     939 * @n_parameters is 0 no parameters will be passed to the method.
     940 * The object instance will be handled automatically even when the method is a custom one
     941 * registered with jsc_class_add_method(), so it should never be passed explicitly as parameter
     942 * of this function.
     943 *
     944 * This function always returns a #JSCValue, in case of void methods a #JSCValue referencing
     945 * <function>undefined</function> is returned.
     946 *
     947 * Returns: (transfer full): a #JSCValue with the return value of the method.
     948 */
     949JSCValue* jsc_value_object_invoke_methodv(JSCValue* value, const char* name, unsigned parametersCount, JSCValue** parameters)
     950{
     951    g_return_val_if_fail(JSC_IS_VALUE(value), nullptr);
     952    g_return_val_if_fail(name, nullptr);
     953    g_return_val_if_fail(!parametersCount || parameters, nullptr);
     954
     955    JSCValuePrivate* priv = value->priv;
     956    auto* jsContext = jscContextGetJSContext(priv->context.get());
     957    JSValueRef exception = nullptr;
     958    JSObjectRef object = JSValueToObject(jsContext, priv->jsValue, &exception);
     959    if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
     960        return jsc_value_new_undefined(priv->context.get());
     961
     962    JSRetainPtr<JSStringRef> methodName(Adopt, JSStringCreateWithUTF8CString(name));
     963    JSValueRef functionValue = JSObjectGetProperty(jsContext, object, methodName.get(), &exception);
     964    if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
     965        return jsc_value_new_undefined(priv->context.get());
     966
     967    JSObjectRef function = JSValueToObject(jsContext, functionValue, &exception);
     968    if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
     969        return jsc_value_new_undefined(priv->context.get());
     970
     971    Vector<JSValueRef> arguments;
     972    if (parametersCount) {
     973        arguments.reserveInitialCapacity(parametersCount);
     974        for (unsigned i = 0; i < parametersCount; ++i)
     975            arguments.uncheckedAppend(jscValueGetJSValue(parameters[i]));
     976    }
     977
     978    auto result = jsObjectCall(jsContext, function, JSC::JSCCallbackFunction::Type::Method, object, arguments, &exception);
     979    if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
     980        jsc_value_new_undefined(priv->context.get());
     981
     982    return jscContextGetOrCreateValue(priv->context.get(), result).leakRef();
    924983}
    925984
     
    10221081}
    10231082
    1024 /**
    1025  * jsc_value_new_function:
     1083static GRefPtr<JSCValue> jscValueFunctionCreate(JSCContext* context, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, Vector<GType>&& parameters)
     1084{
     1085    GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
     1086    JSC::ExecState* exec = toJS(jscContextGetJSContext(context));
     1087    JSC::VM& vm = exec->vm();
     1088    JSC::JSLockHolder locker(vm);
     1089    auto* functionObject = toRef(JSC::JSCCallbackFunction::create(vm, exec->lexicalGlobalObject(), name ? String::fromUTF8(name) : ASCIILiteral("anonymous"),
     1090        JSC::JSCCallbackFunction::Type::Function, nullptr, WTFMove(closure), returnType, WTFMove(parameters)));
     1091    return jscContextGetOrCreateValue(context, functionObject);
     1092}
     1093
     1094/**
     1095 * jsc_value_new_function: (skip)
    10261096 * @context: a #JSCContext:
    10271097 * @name: (nullable): the function name or %NULL
     
    10551125    va_end(args);
    10561126
    1057     GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
    1058     JSC::ExecState* exec = toJS(jscContextGetJSContext(context));
    1059     JSC::VM& vm = exec->vm();
    1060     JSC::JSLockHolder locker(vm);
    1061     auto* functionObject = toRef(JSC::JSCCallbackFunction::create(vm, exec->lexicalGlobalObject(), name ? String::fromUTF8(name) : ASCIILiteral("anonymous"),
    1062         JSC::JSCCallbackFunction::Type::Function, nullptr, WTFMove(closure), returnType, WTFMove(parameters)));
    1063     return jscContextGetOrCreateValue(context, functionObject).leakRef();
     1127    return jscValueFunctionCreate(context, name, callback, userData, destroyNotify, returnType, WTFMove(parameters)).leakRef();
     1128}
     1129
     1130/**
     1131 * jsc_value_new_functionv: (rename-to jsc_value_new_function)
     1132 * @context: a #JSCContext:
     1133 * @name: (nullable): the function name or %NULL
     1134 * @callback: (scope async): a #GCallback.
     1135 * @user_data: (closure): user data to pass to @callback.
     1136 * @destroy_notify: (nullable): destroy notifier for @user_data
     1137 * @return_type: the #GType of the function return value, or %G_TYPE_NONE if the function is void.
     1138 * @n_parameters: the number of parameters
     1139 * @parameter_types: (nullable) (array length=n_parameters) (element-type GType): a list of #GType<!-- -->s, one for each parameter, or %NULL
     1140 *
     1141 * Create a function in @context. If @name is %NULL an anonymous function will be created.
     1142 * When the function is called by JavaScript or jsc_value_function_call(), @callback is called
     1143 * receiving the function parameters and then @user_data as last parameter. When the function is
     1144 * cleared in @context, @destroy_notify is called with @user_data as parameter.
     1145 *
     1146 * Returns: (transfer full): a #JSCValue.
     1147 */
     1148JSCValue* jsc_value_new_functionv(JSCContext* context, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned parametersCount, GType *parameterTypes)
     1149{
     1150    g_return_val_if_fail(JSC_IS_CONTEXT(context), nullptr);
     1151    g_return_val_if_fail(callback, nullptr);
     1152    g_return_val_if_fail(!parametersCount || parameterTypes, nullptr);
     1153
     1154    Vector<GType> parameters;
     1155    if (parametersCount) {
     1156        parameters.reserveInitialCapacity(parametersCount);
     1157        for (unsigned i = 0; i < parametersCount; ++i)
     1158            parameters.uncheckedAppend(parameterTypes[i]);
     1159    }
     1160
     1161    return jscValueFunctionCreate(context, name, callback, userData, destroyNotify, returnType, WTFMove(parameters)).leakRef();
    10641162}
    10651163
     
    10841182
    10851183/**
    1086  * jsc_value_function_call:
     1184 * jsc_value_function_call: (skip)
    10871185 * @value: a #JSCValue
    10881186 * @first_parameter_type: #GType of first parameter, or %G_TYPE_NONE
     
    11171215
    11181216/**
     1217 * jsc_value_function_callv: (rename-to jsc_value_function_call)
     1218 * @value: a #JSCValue
     1219 * @n_parameters: the number of parameters
     1220 * @parameters: (nullable) (array length=n_parameters) (element-type JSCValue): the #JSCValue<!-- -->s to pass as parameters to the function, or %NULL
     1221 *
     1222 * Call function referenced by @value, passing the given @parameters. If @n_parameters
     1223 * is 0 no parameters will be passed to the function.
     1224 *
     1225 * This function always returns a #JSCValue, in case of void functions a #JSCValue referencing
     1226 * <function>undefined</function> is returned
     1227 *
     1228 * Returns: (transfer full): a #JSCValue with the return value of the function.
     1229 */
     1230JSCValue* jsc_value_function_callv(JSCValue* value, unsigned parametersCount, JSCValue** parameters)
     1231{
     1232    g_return_val_if_fail(JSC_IS_VALUE(value), nullptr);
     1233    g_return_val_if_fail(!parametersCount || parameters, nullptr);
     1234
     1235    JSCValuePrivate* priv = value->priv;
     1236    auto* jsContext = jscContextGetJSContext(priv->context.get());
     1237    JSValueRef exception = nullptr;
     1238    JSObjectRef function = JSValueToObject(jsContext, priv->jsValue, &exception);
     1239    if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
     1240        return jsc_value_new_undefined(priv->context.get());
     1241
     1242    Vector<JSValueRef> arguments;
     1243    if (parametersCount) {
     1244        arguments.reserveInitialCapacity(parametersCount);
     1245        for (unsigned i = 0; i < parametersCount; ++i)
     1246            arguments.uncheckedAppend(jscValueGetJSValue(parameters[i]));
     1247    }
     1248
     1249    auto result = jsObjectCall(jsContext, function, JSC::JSCCallbackFunction::Type::Function, nullptr, arguments, &exception);
     1250    if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
     1251        return jsc_value_new_undefined(priv->context.get());
     1252
     1253    return jscContextGetOrCreateValue(priv->context.get(), result).leakRef();
     1254}
     1255
     1256/**
    11191257 * jsc_value_is_constructor:
    11201258 * @value: a #JSCValue
     
    11361274
    11371275/**
    1138  * jsc_value_constructor_call:
     1276 * jsc_value_constructor_call: (skip)
    11391277 * @value: a #JSCValue
    11401278 * @first_parameter_type: #GType of first parameter, or %G_TYPE_NONE
     
    11641302    return result.leakRef();
    11651303}
     1304
     1305/**
     1306 * jsc_value_constructor_callv: (rename-to jsc_value_constructor_call)
     1307 * @value: a #JSCValue
     1308 * @n_parameters: the number of parameters
     1309 * @parameters: (nullable) (array length=n_parameters) (element-type JSCValue): the #JSCValue<!-- -->s to pass as parameters to the constructor, or %NULL
     1310 *
     1311 * Invoke <function>new</function> with constructor referenced by @value. If @n_parameters
     1312 * is 0 no parameters will be passed to the constructor.
     1313 *
     1314 * Returns: (transfer full): a #JSCValue referencing the newly created object instance.
     1315 */
     1316JSCValue* jsc_value_constructor_callv(JSCValue* value, unsigned parametersCount, JSCValue** parameters)
     1317{
     1318    g_return_val_if_fail(JSC_IS_VALUE(value), nullptr);
     1319    g_return_val_if_fail(!parametersCount || parameters, nullptr);
     1320
     1321    JSCValuePrivate* priv = value->priv;
     1322    auto* jsContext = jscContextGetJSContext(priv->context.get());
     1323    JSValueRef exception = nullptr;
     1324    JSObjectRef function = JSValueToObject(jsContext, priv->jsValue, &exception);
     1325    if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
     1326        return jsc_value_new_undefined(priv->context.get());
     1327
     1328    Vector<JSValueRef> arguments;
     1329    if (parametersCount) {
     1330        arguments.reserveInitialCapacity(parametersCount);
     1331        for (unsigned i = 0; i < parametersCount; ++i)
     1332            arguments.uncheckedAppend(jscValueGetJSValue(parameters[i]));
     1333    }
     1334
     1335    auto result = jsObjectCall(jsContext, function, JSC::JSCCallbackFunction::Type::Constructor, nullptr, arguments, &exception);
     1336    if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
     1337        return jsc_value_new_undefined(priv->context.get());
     1338
     1339    return jscContextGetOrCreateValue(priv->context.get(), result).leakRef();
     1340}
  • trunk/Source/JavaScriptCore/API/glib/JSCValue.h

    r230704 r231693  
    181181                                           ...);
    182182
     183JSC_API JSCValue *
     184jsc_value_object_invoke_methodv           (JSCValue             *value,
     185                                           const char           *name,
     186                                           guint                 n_parameters,
     187                                           JSCValue            **parameters);
     188
    183189JSC_API void
    184190jsc_value_object_define_property_data     (JSCValue             *value,
     
    207213                                           ...);
    208214
     215JSC_API JSCValue *
     216jsc_value_new_functionv                   (JSCContext           *context,
     217                                           const char           *name,
     218                                           GCallback             callback,
     219                                           gpointer              user_data,
     220                                           GDestroyNotify        destroy_notify,
     221                                           GType                 return_type,
     222                                           guint                 n_parameters,
     223                                           GType                *parameter_types);
     224
    209225JSC_API gboolean
    210226jsc_value_is_function                     (JSCValue             *value);
     
    215231                                           ...);
    216232
     233JSC_API JSCValue *
     234jsc_value_function_callv                  (JSCValue             *value,
     235                                           guint                 n_parameters,
     236                                           JSCValue            **parameters);
     237
    217238JSC_API gboolean
    218239jsc_value_is_constructor                  (JSCValue             *value);
     
    223244                                           ...);
    224245
     246JSC_API JSCValue *
     247jsc_value_constructor_callv               (JSCValue             *value,
     248                                           guint                 n_parameters,
     249                                           JSCValue            **parameters);
     250
    225251G_END_DECLS
    226252
  • trunk/Source/JavaScriptCore/API/glib/docs/jsc-glib-4.0-sections.txt

    r230753 r231693  
    9393jsc_value_object_enumerate_properties
    9494jsc_value_object_invoke_method
     95jsc_value_object_invoke_methodv
    9596jsc_value_object_define_property_data
    9697jsc_value_object_define_property_accessor
    9798jsc_value_new_function
     99jsc_value_new_functionv
    98100jsc_value_is_function
    99101jsc_value_function_call
     102jsc_value_function_callv
    100103jsc_value_is_constructor
    101104jsc_value_constructor_call
     105jsc_value_constructor_callv
    102106
    103107<SUBSECTION Standard>
     
    172176jsc_class_get_parent
    173177jsc_class_add_constructor
     178jsc_class_add_constructorv
    174179jsc_class_add_method
     180jsc_class_add_methodv
    175181jsc_class_add_property
    176182
  • trunk/Source/JavaScriptCore/ChangeLog

    r231688 r231693  
     12018-05-10  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [JSC][GLIB] Add introspectable alternatives to functions using vargars
     4        https://bugs.webkit.org/show_bug.cgi?id=185508
     5
     6        Reviewed by Michael Catanzaro.
     7
     8        * API/glib/JSCClass.cpp:
     9        (jscClassCreateConstructor):
     10        (jsc_class_add_constructor):
     11        (jsc_class_add_constructorv):
     12        (jscClassAddMethod):
     13        (jsc_class_add_method):
     14        (jsc_class_add_methodv):
     15        * API/glib/JSCClass.h:
     16        * API/glib/JSCValue.cpp:
     17        (jsObjectCall):
     18        (jscValueCallFunction):
     19        (jsc_value_object_invoke_methodv):
     20        (jscValueFunctionCreate):
     21        (jsc_value_new_function):
     22        (jsc_value_new_functionv):
     23        (jsc_value_function_callv):
     24        (jsc_value_constructor_callv):
     25        * API/glib/JSCValue.h:
     26        * API/glib/docs/jsc-glib-4.0-sections.txt:
     27
    1282018-05-10  Yusuke Suzuki  <utatane.tea@gmail.com>
    229
  • trunk/Tools/ChangeLog

    r231686 r231693  
     12018-05-10  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [JSC][GLIB] Add introspectable alternatives to functions using vargars
     4        https://bugs.webkit.org/show_bug.cgi?id=185508
     5
     6        Reviewed by Michael Catanzaro.
     7
     8        Add test cases for the new API.
     9
     10        * TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:
     11        (testJSCFunction):
     12        (testJSCObject):
     13
    1142018-05-10  Leo Balter  <leonardo.balter@gmail.com>
    215
  • trunk/Tools/TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp

    r230889 r231693  
    582582        checker.watch(value.get());
    583583        g_assert_true(value.get() == result.get());
     584
     585        GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new_with_free_func(g_object_unref));
     586        auto* parameter = jsc_value_new_number(context.get(), 200);
     587        checker.watch(parameter);
     588        g_ptr_array_add(parameters.get(), parameter);
     589        value = adoptGRef(jsc_value_function_callv(function.get(), parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
     590        checker.watch(value.get());
     591        g_assert_true(value.get() == result.get());
     592    }
     593
     594    {
     595        LeakChecker checker;
     596        GRefPtr<JSCContext> context = adoptGRef(jsc_context_new());
     597        checker.watch(context.get());
     598        ExceptionHandler exceptionHandler(context.get());
     599
     600        GType parameterTypes[] = { G_TYPE_INT };
     601        GRefPtr<JSCValue> function = adoptGRef(jsc_value_new_functionv(context.get(), "foo", G_CALLBACK(foo), nullptr, nullptr,  G_TYPE_INT, 1, parameterTypes));
     602        checker.watch(function.get());
     603        jsc_context_set_value(context.get(), "foo", function.get());
     604        GRefPtr<JSCValue> result = adoptGRef(jsc_context_evaluate(context.get(), "foo(200)", -1));
     605        checker.watch(result.get());
     606        g_assert_true(jsc_value_is_number(result.get()));
     607        g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 400);
     608
     609        GRefPtr<JSCValue> value = adoptGRef(jsc_value_function_call(function.get(), G_TYPE_INT, 200, G_TYPE_NONE));
     610        checker.watch(value.get());
     611        g_assert_true(value.get() == result.get());
     612
     613        GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new_with_free_func(g_object_unref));
     614        auto* parameter = jsc_value_new_number(context.get(), 200);
     615        checker.watch(parameter);
     616        g_ptr_array_add(parameters.get(), parameter);
     617        value = adoptGRef(jsc_value_function_callv(function.get(), parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
     618        checker.watch(value.get());
     619        g_assert_true(value.get() == result.get());
    584620    }
    585621
     
    599635
    600636        GRefPtr<JSCValue> value = adoptGRef(jsc_value_function_call(function.get(), G_TYPE_INT, 200, G_TYPE_NONE));
     637        checker.watch(value.get());
     638        g_assert_true(value.get() == result.get());
     639
     640        GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new_with_free_func(g_object_unref));
     641        auto* parameter = jsc_value_new_number(context.get(), 200);
     642        checker.watch(parameter);
     643        g_ptr_array_add(parameters.get(), parameter);
     644        value = adoptGRef(jsc_value_function_callv(function.get(), parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
    601645        checker.watch(value.get());
    602646        g_assert_true(value.get() == result.get());
     
    627671        checker.watch(dbl.get());
    628672        GRefPtr<JSCValue> value = adoptGRef(jsc_value_function_call(function.get(), JSC_TYPE_VALUE, dbl.get(), G_TYPE_NONE));
     673        checker.watch(value.get());
     674        result = adoptGRef(jsc_context_evaluate(context.get(), "result", -1));
     675        checker.watch(result.get());
     676        g_assert_true(jsc_value_is_number(result.get()));
     677        g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 400);
     678
     679        GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new());
     680        g_ptr_array_add(parameters.get(), dbl.get());
     681        value = adoptGRef(jsc_value_function_callv(function.get(), parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
    629682        checker.watch(value.get());
    630683        result = adoptGRef(jsc_context_evaluate(context.get(), "result", -1));
     
    716769        g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 400);
    717770
     771        GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new_with_free_func(g_object_unref));
     772        auto* parameter = jsc_value_new_number(context.get(), 200);
     773        checker.watch(parameter);
     774        g_ptr_array_add(parameters.get(), parameter);
     775        result = adoptGRef(jsc_value_object_invoke_methodv(foo.get(), "foo", parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
     776        checker.watch(result.get());
     777        g_assert_true(jsc_value_is_number(result.get()));
     778        g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 400);
     779
    718780        g_assert_false(jsc_value_object_has_property(foo.get(), "bar"));
    719781        bool didThrow = false;
     
    724786        g_assert_did_throw(exceptionHandler, didThrow);
    725787
     788        g_assert_throw_begin(exceptionHandler, didThrow);
     789        result = adoptGRef(jsc_value_object_invoke_methodv(foo.get(), "bar", parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
     790        checker.watch(result.get());
     791        g_assert_true(jsc_value_is_undefined(result.get()));
     792        g_assert_did_throw(exceptionHandler, didThrow);
     793
    726794        GRefPtr<JSCValue> constructor = adoptGRef(jsc_context_evaluate(context.get(), "Foo", -1));
    727795        checker.watch(constructor.get());
     
    748816        g_assert_true(jsc_value_is_number(result.get()));
    749817        g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 1000);
     818
     819        GRefPtr<JSCValue> foo2 = adoptGRef(jsc_value_constructor_callv(constructor.get(), 0, nullptr));
     820        checker.watch(foo2.get());
     821        g_assert_true(jsc_value_is_object(foo2.get()));
     822        g_assert_true(jsc_value_object_is_instance_of(foo2.get(), "Foo"));
     823        g_assert_false(foo.get() == foo2.get());
    750824    }
    751825
     
    11831257        g_assert_cmpint(jsc_value_to_int32(value.get()), ==, 0);
    11841258
     1259        value = adoptGRef(jsc_value_object_invoke_methodv(foo.get(), "getFoo", 0, nullptr));
     1260        checker.watch(value.get());
     1261        g_assert_true(jsc_value_is_number(value.get()));
     1262        g_assert_cmpint(jsc_value_to_int32(value.get()), ==, 0);
     1263
    11851264        GRefPtr<JSCValue> value2 = adoptGRef(jsc_context_evaluate(context.get(), "f.getFoo()", -1));
    11861265        checker.watch(value2.get());
     
    11881267
    11891268        g_assert_false(jsc_value_object_has_property(foo.get(), "setFoo"));
    1190         jsc_class_add_method(jscClass, "setFoo", G_CALLBACK(setFoo), nullptr, nullptr, G_TYPE_NONE, 1, G_TYPE_INT);
     1269        GType parameterTypes[] = { G_TYPE_INT };
     1270        jsc_class_add_methodv(jscClass, "setFoo", G_CALLBACK(setFoo), nullptr, nullptr, G_TYPE_NONE, 1, parameterTypes);
    11911271        g_assert_true(jsc_value_object_has_property(foo.get(), "setFoo"));
    11921272        properties.reset(jsc_value_object_enumerate_properties(foo.get()));
     
    12061286        g_assert_cmpint(jsc_value_to_int32(value.get()), ==, 45);
    12071287
    1208         GRefPtr<JSCValue> constructor2 = adoptGRef(jsc_class_add_constructor(jscClass, "CreateWithFoo", G_CALLBACK(fooCreateWithFoo), nullptr, nullptr, G_TYPE_POINTER, 1, G_TYPE_INT));
     1288        value = adoptGRef(jsc_value_object_invoke_methodv(foo.get(), "getFoo", 0, nullptr));
     1289        checker.watch(value.get());
     1290        g_assert_true(jsc_value_is_number(value.get()));
     1291        g_assert_cmpint(jsc_value_to_int32(value.get()), ==, 45);
     1292
     1293        GRefPtr<JSCValue> constructor2 = adoptGRef(jsc_class_add_constructorv(jscClass, "CreateWithFoo", G_CALLBACK(fooCreateWithFoo), nullptr, nullptr, G_TYPE_POINTER, 1, parameterTypes));
    12091294        checker.watch(constructor2.get());
    12101295        g_assert_true(jsc_value_is_constructor(constructor2.get()));
     
    13121397        checker.watch(jscClass);
    13131398
    1314         GRefPtr<JSCValue> constructor = adoptGRef(jsc_class_add_constructor(jscClass, nullptr, G_CALLBACK(fooCreate), nullptr, nullptr, G_TYPE_POINTER, 0, G_TYPE_NONE));
     1399        GRefPtr<JSCValue> constructor = adoptGRef(jsc_class_add_constructorv(jscClass, nullptr, G_CALLBACK(fooCreate), nullptr, nullptr, G_TYPE_POINTER, 0, nullptr));
    13151400        checker.watch(constructor.get());
    13161401        g_assert_true(jsc_value_is_constructor(constructor.get()));
     
    15551640        g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 42);
    15561641
    1557         GRefPtr<JSCValue> foo3 = adoptGRef(jsc_value_constructor_call(constructor2.get(), G_TYPE_INT, 62, G_TYPE_NONE));
     1642        GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new_with_free_func(g_object_unref));
     1643        auto* parameter = jsc_value_new_number(context.get(), 62);
     1644        checker.watch(parameter);
     1645        g_ptr_array_add(parameters.get(), parameter);
     1646
     1647        GRefPtr<JSCValue> foo3 = adoptGRef(jsc_value_constructor_callv(constructor2.get(), parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
    15581648        checker.watch(foo3.get());
    15591649        g_assert_true(jsc_value_is_object(foo3.get()));
Note: See TracChangeset for help on using the changeset viewer.