Diff
Modified: trunk/Source/_javascript_Core/API/glib/JSCClass.cpp (231692 => 231693)
--- trunk/Source/_javascript_Core/API/glib/JSCClass.cpp 2018-05-11 05:34:20 UTC (rev 231692)
+++ trunk/Source/_javascript_Core/API/glib/JSCClass.cpp 2018-05-11 06:56:57 UTC (rev 231693)
@@ -521,8 +521,26 @@
return jscClass->priv->parentClass;
}
+static GRefPtr<JSCValue> jscClassCreateConstructor(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, Vector<GType>&& parameters)
+{
+ JSCClassPrivate* priv = jscClass->priv;
+ GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
+ JSC::ExecState* exec = toJS(jscContextGetJSContext(priv->context));
+ JSC::VM& vm = exec->vm();
+ JSC::JSLockHolder locker(vm);
+ auto* functionObject = JSC::JSCCallbackFunction::create(vm, exec->lexicalGlobalObject(), String::fromUTF8(name),
+ JSC::JSCCallbackFunction::Type::Constructor, jscClass, WTFMove(closure), returnType, WTFMove(parameters));
+ auto constructor = jscContextGetOrCreateValue(priv->context, toRef(functionObject));
+ GRefPtr<JSCValue> prototype = jscContextGetOrCreateValue(priv->context, toRef(priv->prototype.get()));
+ auto nonEnumerable = static_cast<JSCValuePropertyFlags>(JSC_VALUE_PROPERTY_CONFIGURABLE | JSC_VALUE_PROPERTY_WRITABLE);
+ jsc_value_object_define_property_data(constructor.get(), "prototype", nonEnumerable, prototype.get());
+ jsc_value_object_define_property_data(prototype.get(), "constructor", nonEnumerable, constructor.get());
+ priv->constructors.set(name, functionObject);
+ return constructor;
+}
+
/**
- * jsc_class_add_constructor:
+ * jsc_class_add_constructor: (skip)
* @jsc_class: a #JSCClass
* @name: (nullable): the constructor name or %NULL
* @callback: (scope async): a #GCallback to be called to create an instance of @jsc_class
@@ -563,23 +581,70 @@
}
va_end(args);
+ return jscClassCreateConstructor(jscClass, name ? name : priv->name.data(), callback, userData, destroyNotify, returnType, WTFMove(parameters)).leakRef();
+
+}
+
+/**
+ * jsc_class_add_constructorv: (rename-to jsc_class_add_constructor)
+ * @jsc_class: a #JSCClass
+ * @name: (nullable): the constructor name or %NULL
+ * @callback: (scope async): a #GCallback to be called to create an instance of @jsc_class
+ * @user_data: (closure): user data to pass to @callback
+ * @destroy_notify: (nullable): destroy notifier for @user_data
+ * @return_type: the #GType of the constructor return value
+ * @n_parameters: the number of parameters
+ * @parameter_types: (nullable) (array length=n_parameters) (element-type GType): a list of #GType<!-- -->s, one for each parameter, or %NULL
+ *
+ * Add a constructor to @jsc_class. If @name is %NULL, the class name will be used. When <function>new</function>
+ * is used with the constructor or jsc_value_constructor_call() is called, @callback is invoked receiving the
+ * parameters and @user_data as the last parameter. When the constructor object is cleared in the #JSCClass context,
+ * @destroy_notify is called with @user_data as parameter.
+ *
+ * This function creates the constructor, that needs to be added to an object as a property to be able to use it. Use
+ * jsc_context_set_value() to make the constructor available in the global object.
+ *
+ * Returns: (transfer full): a #JSCValue representing the class constructor.
+ */
+JSCValue* jsc_class_add_constructorv(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned parametersCount, GType* parameterTypes)
+{
+ g_return_val_if_fail(JSC_IS_CLASS(jscClass), nullptr);
+ g_return_val_if_fail(callback, nullptr);
+ g_return_val_if_fail(!parametersCount || parameterTypes, nullptr);
+
+ JSCClassPrivate* priv = jscClass->priv;
+ g_return_val_if_fail(priv->context, nullptr);
+
+ if (!name)
+ name = priv->name.data();
+
+ Vector<GType> parameters;
+ if (parametersCount) {
+ parameters.reserveInitialCapacity(parametersCount);
+ for (unsigned i = 0; i < parametersCount; ++i)
+ parameters.uncheckedAppend(parameterTypes[i]);
+ }
+
+ return jscClassCreateConstructor(jscClass, name ? name : priv->name.data(), callback, userData, destroyNotify, returnType, WTFMove(parameters)).leakRef();
+}
+
+static void jscClassAddMethod(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, Vector<GType>&& parameters)
+{
+ JSCClassPrivate* priv = jscClass->priv;
GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
JSC::ExecState* exec = toJS(jscContextGetJSContext(priv->context));
JSC::VM& vm = exec->vm();
JSC::JSLockHolder locker(vm);
- auto* functionObject = JSC::JSCCallbackFunction::create(vm, exec->lexicalGlobalObject(), String::fromUTF8(name),
- JSC::JSCCallbackFunction::Type::Constructor, jscClass, WTFMove(closure), returnType, WTFMove(parameters));
- auto constructor = jscContextGetOrCreateValue(priv->context, toRef(functionObject));
+ auto* functionObject = toRef(JSC::JSCCallbackFunction::create(vm, exec->lexicalGlobalObject(), String::fromUTF8(name),
+ JSC::JSCCallbackFunction::Type::Method, jscClass, WTFMove(closure), returnType, WTFMove(parameters)));
+ auto method = jscContextGetOrCreateValue(priv->context, functionObject);
GRefPtr<JSCValue> prototype = jscContextGetOrCreateValue(priv->context, toRef(priv->prototype.get()));
auto nonEnumerable = static_cast<JSCValuePropertyFlags>(JSC_VALUE_PROPERTY_CONFIGURABLE | JSC_VALUE_PROPERTY_WRITABLE);
- jsc_value_object_define_property_data(constructor.get(), "prototype", nonEnumerable, prototype.get());
- jsc_value_object_define_property_data(prototype.get(), "constructor", nonEnumerable, constructor.get());
- priv->constructors.set(name, functionObject);
- return constructor.leakRef();
+ jsc_value_object_define_property_data(prototype.get(), name, nonEnumerable, method.get());
}
/**
- * jsc_class_add_method:
+ * jsc_class_add_method: (skip)
* @jsc_class: a #JSCClass
* @name: the method name
* @callback: (scope async): a #GCallback to be called to invoke method @name of @jsc_class
@@ -599,10 +664,8 @@
g_return_if_fail(JSC_IS_CLASS(jscClass));
g_return_if_fail(name);
g_return_if_fail(callback);
+ g_return_if_fail(jscClass->priv->context);
- JSCClassPrivate* priv = jscClass->priv;
- g_return_if_fail(priv->context);
-
va_list args;
va_start(args, paramCount);
Vector<GType> parameters;
@@ -613,19 +676,44 @@
}
va_end(args);
- GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
- JSC::ExecState* exec = toJS(jscContextGetJSContext(priv->context));
- JSC::VM& vm = exec->vm();
- JSC::JSLockHolder locker(vm);
- auto* functionObject = toRef(JSC::JSCCallbackFunction::create(vm, exec->lexicalGlobalObject(), String::fromUTF8(name),
- JSC::JSCCallbackFunction::Type::Method, jscClass, WTFMove(closure), returnType, WTFMove(parameters)));
- auto method = jscContextGetOrCreateValue(priv->context, functionObject);
- GRefPtr<JSCValue> prototype = jscContextGetOrCreateValue(priv->context, toRef(priv->prototype.get()));
- auto nonEnumerable = static_cast<JSCValuePropertyFlags>(JSC_VALUE_PROPERTY_CONFIGURABLE | JSC_VALUE_PROPERTY_WRITABLE);
- jsc_value_object_define_property_data(prototype.get(), name, nonEnumerable, method.get());
+ jscClassAddMethod(jscClass, name, callback, userData, destroyNotify, returnType, WTFMove(parameters));
}
/**
+ * jsc_class_add_methodv: (rename-to jsc_class_add_method)
+ * @jsc_class: a #JSCClass
+ * @name: the method name
+ * @callback: (scope async): a #GCallback to be called to invoke method @name of @jsc_class
+ * @user_data: (closure): user data to pass to @callback
+ * @destroy_notify: (nullable): destroy notifier for @user_data
+ * @return_type: the #GType of the method return value, or %G_TYPE_NONE if the method is void.
+ * @n_parameters: the number of parameter types to follow or 0 if the method doesn't receive parameters.
+ * @parameter_types: (nullable) (array length=n_parameters) (element-type GType): a list of #GType<!-- -->s, one for each parameter, or %NULL
+ *
+ * Add method with @name to @jsc_class. When the method is called by _javascript_ or jsc_value_object_invoke_method(),
+ * @callback is called receiving the class instance as first parameter, followed by the method parameters and then
+ * @user_data as last parameter. When the method is cleared in the #JSCClass context, @destroy_notify is called with
+ * @user_data as parameter.
+ */
+void jsc_class_add_methodv(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned parametersCount, GType *parameterTypes)
+{
+ g_return_if_fail(JSC_IS_CLASS(jscClass));
+ g_return_if_fail(name);
+ g_return_if_fail(callback);
+ g_return_if_fail(!parametersCount || parameterTypes);
+ g_return_if_fail(jscClass->priv->context);
+
+ Vector<GType> parameters;
+ if (parametersCount) {
+ parameters.reserveInitialCapacity(parametersCount);
+ for (unsigned i = 0; i < parametersCount; ++i)
+ parameters.uncheckedAppend(parameterTypes[i]);
+ }
+
+ jscClassAddMethod(jscClass, name, callback, userData, destroyNotify, returnType, WTFMove(parameters));
+}
+
+/**
* jsc_class_add_property:
* @jsc_class: a #JSCClass
* @name: the property name
Modified: trunk/Source/_javascript_Core/API/glib/JSCClass.h (231692 => 231693)
--- trunk/Source/_javascript_Core/API/glib/JSCClass.h 2018-05-11 05:34:20 UTC (rev 231692)
+++ trunk/Source/_javascript_Core/API/glib/JSCClass.h 2018-05-11 06:56:57 UTC (rev 231693)
@@ -76,43 +76,63 @@
} JSCClassVTable;
JSC_API GType
-jsc_class_get_type (void);
+jsc_class_get_type (void);
JSC_API const char *
-jsc_class_get_name (JSCClass *jsc_class);
+jsc_class_get_name (JSCClass *jsc_class);
JSC_API JSCClass *
-jsc_class_get_parent (JSCClass *jsc_class);
+jsc_class_get_parent (JSCClass *jsc_class);
JSC_API JSCValue *
-jsc_class_add_constructor (JSCClass *jsc_class,
- const char *name,
- GCallback callback,
- gpointer user_data,
- GDestroyNotify destroy_notify,
- GType return_type,
- unsigned n_params,
- ...);
+jsc_class_add_constructor (JSCClass *jsc_class,
+ const char *name,
+ GCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy_notify,
+ GType return_type,
+ guint n_params,
+ ...);
+JSC_API JSCValue *
+jsc_class_add_constructorv (JSCClass *jsc_class,
+ const char *name,
+ GCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy_notify,
+ GType return_type,
+ guint n_parameters,
+ GType *parameter_types);
+
JSC_API void
-jsc_class_add_method (JSCClass *jsc_class,
- const char *name,
- GCallback callback,
- gpointer user_data,
- GDestroyNotify destroy_notify,
- GType return_type,
- unsigned n_params,
- ...);
+jsc_class_add_method (JSCClass *jsc_class,
+ const char *name,
+ GCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy_notify,
+ GType return_type,
+ guint n_params,
+ ...);
JSC_API void
-jsc_class_add_property (JSCClass *jsc_class,
- const char *name,
- GType property_type,
- GCallback getter,
- GCallback setter,
- gpointer user_data,
- GDestroyNotify destroy_notify);
+jsc_class_add_methodv (JSCClass *jsc_class,
+ const char *name,
+ GCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy_notify,
+ GType return_type,
+ guint n_parameters,
+ GType *parameter_types);
+JSC_API void
+jsc_class_add_property (JSCClass *jsc_class,
+ const char *name,
+ GType property_type,
+ GCallback getter,
+ GCallback setter,
+ gpointer user_data,
+ GDestroyNotify destroy_notify);
+
G_END_DECLS
#endif /* JSCClass_h */
Modified: trunk/Source/_javascript_Core/API/glib/JSCValue.cpp (231692 => 231693)
--- trunk/Source/_javascript_Core/API/glib/JSCValue.cpp 2018-05-11 05:34:20 UTC (rev 231692)
+++ trunk/Source/_javascript_Core/API/glib/JSCValue.cpp 2018-05-11 06:56:57 UTC (rev 231693)
@@ -457,7 +457,7 @@
}
/**
- * jsc_value_new_array:
+ * jsc_value_new_array: (skip)
* @context: a #JSCContext
* @first_item_type: #GType of first item, or %G_TYPE_NONE
* @...: value of the first item, followed optionally by more type/value pairs, followed by %G_TYPE_NONE.
@@ -831,6 +831,22 @@
return result;
}
+static JSValueRef jsObjectCall(JSGlobalContextRef jsContext, JSObjectRef function, JSC::JSCCallbackFunction::Type functionType, JSObjectRef thisObject, const Vector<JSValueRef>& arguments, JSValueRef* exception)
+{
+ switch (functionType) {
+ case JSC::JSCCallbackFunction::Type::Constructor:
+ return JSObjectCallAsConstructor(jsContext, function, arguments.size(), arguments.data(), exception);
+ break;
+ case JSC::JSCCallbackFunction::Type::Method:
+ ASSERT(thisObject);
+ FALLTHROUGH;
+ case JSC::JSCCallbackFunction::Type::Function:
+ return JSObjectCallAsFunction(jsContext, function, thisObject, arguments.size(), arguments.data(), exception);
+ break;
+ }
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
static GRefPtr<JSCValue> jscValueCallFunction(JSCValue* value, JSObjectRef function, JSC::JSCCallbackFunction::Type functionType, JSObjectRef thisObject, GType firstParameterType, va_list args)
{
JSCValuePrivate* priv = value->priv;
@@ -858,18 +874,7 @@
parameterType = va_arg(args, GType);
}
- JSValueRef result;
- switch (functionType) {
- case JSC::JSCCallbackFunction::Type::Constructor:
- result = JSObjectCallAsConstructor(jsContext, function, arguments.size(), arguments.data(), &exception);
- break;
- case JSC::JSCCallbackFunction::Type::Method:
- ASSERT(thisObject);
- FALLTHROUGH;
- case JSC::JSCCallbackFunction::Type::Function:
- result = JSObjectCallAsFunction(jsContext, function, thisObject, arguments.size(), arguments.data(), &exception);
- break;
- }
+ auto result = jsObjectCall(jsContext, function, functionType, thisObject, arguments, &exception);
if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
return adoptGRef(jsc_value_new_undefined(priv->context.get()));
@@ -877,7 +882,7 @@
}
/**
- * jsc_value_object_invoke_method:
+ * jsc_value_object_invoke_method: (skip)
* @value: a #JSCValue
* @name: the method name
* @first_parameter_type: #GType of first parameter, or %G_TYPE_NONE
@@ -924,6 +929,60 @@
}
/**
+ * jsc_value_object_invoke_methodv: (rename-to jsc_value_object_invoke_method)
+ * @value: a #JSCValue
+ * @name: the method name
+ * @n_parameters: the number of parameters
+ * @parameters: (nullable) (array length=n_parameters) (element-type JSCValue): the #JSCValue<!-- -->s to pass as parameters to the method, or %NULL
+ *
+ * Invoke method with @name on object referenced by @value, passing the given @parameters. If
+ * @n_parameters is 0 no parameters will be passed to the method.
+ * The object instance will be handled automatically even when the method is a custom one
+ * registered with jsc_class_add_method(), so it should never be passed explicitly as parameter
+ * of this function.
+ *
+ * This function always returns a #JSCValue, in case of void methods a #JSCValue referencing
+ * <function>undefined</function> is returned.
+ *
+ * Returns: (transfer full): a #JSCValue with the return value of the method.
+ */
+JSCValue* jsc_value_object_invoke_methodv(JSCValue* value, const char* name, unsigned parametersCount, JSCValue** parameters)
+{
+ g_return_val_if_fail(JSC_IS_VALUE(value), nullptr);
+ g_return_val_if_fail(name, nullptr);
+ g_return_val_if_fail(!parametersCount || parameters, nullptr);
+
+ JSCValuePrivate* priv = value->priv;
+ auto* jsContext = jscContextGetJSContext(priv->context.get());
+ JSValueRef exception = nullptr;
+ JSObjectRef object = JSValueToObject(jsContext, priv->jsValue, &exception);
+ if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
+ return jsc_value_new_undefined(priv->context.get());
+
+ JSRetainPtr<JSStringRef> methodName(Adopt, JSStringCreateWithUTF8CString(name));
+ JSValueRef functionValue = JSObjectGetProperty(jsContext, object, methodName.get(), &exception);
+ if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
+ return jsc_value_new_undefined(priv->context.get());
+
+ JSObjectRef function = JSValueToObject(jsContext, functionValue, &exception);
+ if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
+ return jsc_value_new_undefined(priv->context.get());
+
+ Vector<JSValueRef> arguments;
+ if (parametersCount) {
+ arguments.reserveInitialCapacity(parametersCount);
+ for (unsigned i = 0; i < parametersCount; ++i)
+ arguments.uncheckedAppend(jscValueGetJSValue(parameters[i]));
+ }
+
+ auto result = jsObjectCall(jsContext, function, JSC::JSCCallbackFunction::Type::Method, object, arguments, &exception);
+ if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
+ jsc_value_new_undefined(priv->context.get());
+
+ return jscContextGetOrCreateValue(priv->context.get(), result).leakRef();
+}
+
+/**
* JSCValuePropertyFlags:
* @JSC_VALUE_PROPERTY_CONFIGURABLE: the type of the property descriptor may be changed and the
* property may be deleted from the corresponding object.
@@ -1021,8 +1080,19 @@
JSC_TYPE_VALUE, value, G_TYPE_STRING, propertyName, JSC_TYPE_VALUE, descriptor.get(), G_TYPE_NONE));
}
+static GRefPtr<JSCValue> jscValueFunctionCreate(JSCContext* context, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, Vector<GType>&& parameters)
+{
+ GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
+ JSC::ExecState* exec = toJS(jscContextGetJSContext(context));
+ JSC::VM& vm = exec->vm();
+ JSC::JSLockHolder locker(vm);
+ auto* functionObject = toRef(JSC::JSCCallbackFunction::create(vm, exec->lexicalGlobalObject(), name ? String::fromUTF8(name) : ASCIILiteral("anonymous"),
+ JSC::JSCCallbackFunction::Type::Function, nullptr, WTFMove(closure), returnType, WTFMove(parameters)));
+ return jscContextGetOrCreateValue(context, functionObject);
+}
+
/**
- * jsc_value_new_function:
+ * jsc_value_new_function: (skip)
* @context: a #JSCContext:
* @name: (nullable): the function name or %NULL
* @callback: (scope async): a #GCallback.
@@ -1054,16 +1124,44 @@
}
va_end(args);
- GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
- JSC::ExecState* exec = toJS(jscContextGetJSContext(context));
- JSC::VM& vm = exec->vm();
- JSC::JSLockHolder locker(vm);
- auto* functionObject = toRef(JSC::JSCCallbackFunction::create(vm, exec->lexicalGlobalObject(), name ? String::fromUTF8(name) : ASCIILiteral("anonymous"),
- JSC::JSCCallbackFunction::Type::Function, nullptr, WTFMove(closure), returnType, WTFMove(parameters)));
- return jscContextGetOrCreateValue(context, functionObject).leakRef();
+ return jscValueFunctionCreate(context, name, callback, userData, destroyNotify, returnType, WTFMove(parameters)).leakRef();
}
/**
+ * jsc_value_new_functionv: (rename-to jsc_value_new_function)
+ * @context: a #JSCContext:
+ * @name: (nullable): the function name or %NULL
+ * @callback: (scope async): a #GCallback.
+ * @user_data: (closure): user data to pass to @callback.
+ * @destroy_notify: (nullable): destroy notifier for @user_data
+ * @return_type: the #GType of the function return value, or %G_TYPE_NONE if the function is void.
+ * @n_parameters: the number of parameters
+ * @parameter_types: (nullable) (array length=n_parameters) (element-type GType): a list of #GType<!-- -->s, one for each parameter, or %NULL
+ *
+ * Create a function in @context. If @name is %NULL an anonymous function will be created.
+ * When the function is called by _javascript_ or jsc_value_function_call(), @callback is called
+ * receiving the function parameters and then @user_data as last parameter. When the function is
+ * cleared in @context, @destroy_notify is called with @user_data as parameter.
+ *
+ * Returns: (transfer full): a #JSCValue.
+ */
+JSCValue* jsc_value_new_functionv(JSCContext* context, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, unsigned parametersCount, GType *parameterTypes)
+{
+ g_return_val_if_fail(JSC_IS_CONTEXT(context), nullptr);
+ g_return_val_if_fail(callback, nullptr);
+ g_return_val_if_fail(!parametersCount || parameterTypes, nullptr);
+
+ Vector<GType> parameters;
+ if (parametersCount) {
+ parameters.reserveInitialCapacity(parametersCount);
+ for (unsigned i = 0; i < parametersCount; ++i)
+ parameters.uncheckedAppend(parameterTypes[i]);
+ }
+
+ return jscValueFunctionCreate(context, name, callback, userData, destroyNotify, returnType, WTFMove(parameters)).leakRef();
+}
+
+/**
* jsc_value_is_function:
* @value: a #JSCValue
*
@@ -1083,7 +1181,7 @@
}
/**
- * jsc_value_function_call:
+ * jsc_value_function_call: (skip)
* @value: a #JSCValue
* @first_parameter_type: #GType of first parameter, or %G_TYPE_NONE
* @...: value of the first parameter, followed optionally by more type/value pairs, followed by %G_TYPE_NONE
@@ -1116,6 +1214,46 @@
}
/**
+ * jsc_value_function_callv: (rename-to jsc_value_function_call)
+ * @value: a #JSCValue
+ * @n_parameters: the number of parameters
+ * @parameters: (nullable) (array length=n_parameters) (element-type JSCValue): the #JSCValue<!-- -->s to pass as parameters to the function, or %NULL
+ *
+ * Call function referenced by @value, passing the given @parameters. If @n_parameters
+ * is 0 no parameters will be passed to the function.
+ *
+ * This function always returns a #JSCValue, in case of void functions a #JSCValue referencing
+ * <function>undefined</function> is returned
+ *
+ * Returns: (transfer full): a #JSCValue with the return value of the function.
+ */
+JSCValue* jsc_value_function_callv(JSCValue* value, unsigned parametersCount, JSCValue** parameters)
+{
+ g_return_val_if_fail(JSC_IS_VALUE(value), nullptr);
+ g_return_val_if_fail(!parametersCount || parameters, nullptr);
+
+ JSCValuePrivate* priv = value->priv;
+ auto* jsContext = jscContextGetJSContext(priv->context.get());
+ JSValueRef exception = nullptr;
+ JSObjectRef function = JSValueToObject(jsContext, priv->jsValue, &exception);
+ if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
+ return jsc_value_new_undefined(priv->context.get());
+
+ Vector<JSValueRef> arguments;
+ if (parametersCount) {
+ arguments.reserveInitialCapacity(parametersCount);
+ for (unsigned i = 0; i < parametersCount; ++i)
+ arguments.uncheckedAppend(jscValueGetJSValue(parameters[i]));
+ }
+
+ auto result = jsObjectCall(jsContext, function, JSC::JSCCallbackFunction::Type::Function, nullptr, arguments, &exception);
+ if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
+ return jsc_value_new_undefined(priv->context.get());
+
+ return jscContextGetOrCreateValue(priv->context.get(), result).leakRef();
+}
+
+/**
* jsc_value_is_constructor:
* @value: a #JSCValue
*
@@ -1135,7 +1273,7 @@
}
/**
- * jsc_value_constructor_call:
+ * jsc_value_constructor_call: (skip)
* @value: a #JSCValue
* @first_parameter_type: #GType of first parameter, or %G_TYPE_NONE
* @...: value of the first parameter, followed optionally by more type/value pairs, followed by %G_TYPE_NONE
@@ -1163,3 +1301,40 @@
return result.leakRef();
}
+
+/**
+ * jsc_value_constructor_callv: (rename-to jsc_value_constructor_call)
+ * @value: a #JSCValue
+ * @n_parameters: the number of parameters
+ * @parameters: (nullable) (array length=n_parameters) (element-type JSCValue): the #JSCValue<!-- -->s to pass as parameters to the constructor, or %NULL
+ *
+ * Invoke <function>new</function> with constructor referenced by @value. If @n_parameters
+ * is 0 no parameters will be passed to the constructor.
+ *
+ * Returns: (transfer full): a #JSCValue referencing the newly created object instance.
+ */
+JSCValue* jsc_value_constructor_callv(JSCValue* value, unsigned parametersCount, JSCValue** parameters)
+{
+ g_return_val_if_fail(JSC_IS_VALUE(value), nullptr);
+ g_return_val_if_fail(!parametersCount || parameters, nullptr);
+
+ JSCValuePrivate* priv = value->priv;
+ auto* jsContext = jscContextGetJSContext(priv->context.get());
+ JSValueRef exception = nullptr;
+ JSObjectRef function = JSValueToObject(jsContext, priv->jsValue, &exception);
+ if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
+ return jsc_value_new_undefined(priv->context.get());
+
+ Vector<JSValueRef> arguments;
+ if (parametersCount) {
+ arguments.reserveInitialCapacity(parametersCount);
+ for (unsigned i = 0; i < parametersCount; ++i)
+ arguments.uncheckedAppend(jscValueGetJSValue(parameters[i]));
+ }
+
+ auto result = jsObjectCall(jsContext, function, JSC::JSCCallbackFunction::Type::Constructor, nullptr, arguments, &exception);
+ if (jscContextHandleExceptionIfNeeded(priv->context.get(), exception))
+ return jsc_value_new_undefined(priv->context.get());
+
+ return jscContextGetOrCreateValue(priv->context.get(), result).leakRef();
+}
Modified: trunk/Source/_javascript_Core/API/glib/JSCValue.h (231692 => 231693)
--- trunk/Source/_javascript_Core/API/glib/JSCValue.h 2018-05-11 05:34:20 UTC (rev 231692)
+++ trunk/Source/_javascript_Core/API/glib/JSCValue.h 2018-05-11 06:56:57 UTC (rev 231693)
@@ -180,6 +180,12 @@
GType first_parameter_type,
...);
+JSC_API JSCValue *
+jsc_value_object_invoke_methodv (JSCValue *value,
+ const char *name,
+ guint n_parameters,
+ JSCValue **parameters);
+
JSC_API void
jsc_value_object_define_property_data (JSCValue *value,
const char *property_name,
@@ -206,6 +212,16 @@
guint n_params,
...);
+JSC_API JSCValue *
+jsc_value_new_functionv (JSCContext *context,
+ const char *name,
+ GCallback callback,
+ gpointer user_data,
+ GDestroyNotify destroy_notify,
+ GType return_type,
+ guint n_parameters,
+ GType *parameter_types);
+
JSC_API gboolean
jsc_value_is_function (JSCValue *value);
@@ -214,6 +230,11 @@
GType first_parameter_type,
...);
+JSC_API JSCValue *
+jsc_value_function_callv (JSCValue *value,
+ guint n_parameters,
+ JSCValue **parameters);
+
JSC_API gboolean
jsc_value_is_constructor (JSCValue *value);
@@ -222,6 +243,11 @@
GType first_parameter_type,
...);
+JSC_API JSCValue *
+jsc_value_constructor_callv (JSCValue *value,
+ guint n_parameters,
+ JSCValue **parameters);
+
G_END_DECLS
#endif /* JSCValue_h */
Modified: trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt (231692 => 231693)
--- trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt 2018-05-11 05:34:20 UTC (rev 231692)
+++ trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt 2018-05-11 06:56:57 UTC (rev 231693)
@@ -92,13 +92,17 @@
jsc_value_object_delete_property
jsc_value_object_enumerate_properties
jsc_value_object_invoke_method
+jsc_value_object_invoke_methodv
jsc_value_object_define_property_data
jsc_value_object_define_property_accessor
jsc_value_new_function
+jsc_value_new_functionv
jsc_value_is_function
jsc_value_function_call
+jsc_value_function_callv
jsc_value_is_constructor
jsc_value_constructor_call
+jsc_value_constructor_callv
<SUBSECTION Standard>
JSCValueClass
@@ -171,7 +175,9 @@
jsc_class_get_name
jsc_class_get_parent
jsc_class_add_constructor
+jsc_class_add_constructorv
jsc_class_add_method
+jsc_class_add_methodv
jsc_class_add_property
<SUBSECTION Standard>
Modified: trunk/Source/_javascript_Core/ChangeLog (231692 => 231693)
--- trunk/Source/_javascript_Core/ChangeLog 2018-05-11 05:34:20 UTC (rev 231692)
+++ trunk/Source/_javascript_Core/ChangeLog 2018-05-11 06:56:57 UTC (rev 231693)
@@ -1,3 +1,30 @@
+2018-05-10 Carlos Garcia Campos <cgar...@igalia.com>
+
+ [JSC][GLIB] Add introspectable alternatives to functions using vargars
+ https://bugs.webkit.org/show_bug.cgi?id=185508
+
+ Reviewed by Michael Catanzaro.
+
+ * 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:
+
2018-05-10 Yusuke Suzuki <utatane....@gmail.com>
[JSC] Make return types of construction functions tight
Modified: trunk/Tools/ChangeLog (231692 => 231693)
--- trunk/Tools/ChangeLog 2018-05-11 05:34:20 UTC (rev 231692)
+++ trunk/Tools/ChangeLog 2018-05-11 06:56:57 UTC (rev 231693)
@@ -1,3 +1,16 @@
+2018-05-10 Carlos Garcia Campos <cgar...@igalia.com>
+
+ [JSC][GLIB] Add introspectable alternatives to functions using vargars
+ https://bugs.webkit.org/show_bug.cgi?id=185508
+
+ Reviewed by Michael Catanzaro.
+
+ Add test cases for the new API.
+
+ * TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp:
+ (testJSCFunction):
+ (testJSCObject):
+
2018-05-10 Leo Balter <leonardo.bal...@gmail.com>
[Build Bot] Restore configuration options to the Test262 Runner
Modified: trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp (231692 => 231693)
--- trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp 2018-05-11 05:34:20 UTC (rev 231692)
+++ trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp 2018-05-11 06:56:57 UTC (rev 231693)
@@ -581,6 +581,14 @@
GRefPtr<JSCValue> value = adoptGRef(jsc_value_function_call(function.get(), G_TYPE_INT, 200, G_TYPE_NONE));
checker.watch(value.get());
g_assert_true(value.get() == result.get());
+
+ GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new_with_free_func(g_object_unref));
+ auto* parameter = jsc_value_new_number(context.get(), 200);
+ checker.watch(parameter);
+ g_ptr_array_add(parameters.get(), parameter);
+ value = adoptGRef(jsc_value_function_callv(function.get(), parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
+ checker.watch(value.get());
+ g_assert_true(value.get() == result.get());
}
{
@@ -589,6 +597,34 @@
checker.watch(context.get());
ExceptionHandler exceptionHandler(context.get());
+ GType parameterTypes[] = { G_TYPE_INT };
+ GRefPtr<JSCValue> function = adoptGRef(jsc_value_new_functionv(context.get(), "foo", G_CALLBACK(foo), nullptr, nullptr, G_TYPE_INT, 1, parameterTypes));
+ checker.watch(function.get());
+ jsc_context_set_value(context.get(), "foo", function.get());
+ GRefPtr<JSCValue> result = adoptGRef(jsc_context_evaluate(context.get(), "foo(200)", -1));
+ checker.watch(result.get());
+ g_assert_true(jsc_value_is_number(result.get()));
+ g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 400);
+
+ GRefPtr<JSCValue> value = adoptGRef(jsc_value_function_call(function.get(), G_TYPE_INT, 200, G_TYPE_NONE));
+ checker.watch(value.get());
+ g_assert_true(value.get() == result.get());
+
+ GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new_with_free_func(g_object_unref));
+ auto* parameter = jsc_value_new_number(context.get(), 200);
+ checker.watch(parameter);
+ g_ptr_array_add(parameters.get(), parameter);
+ value = adoptGRef(jsc_value_function_callv(function.get(), parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
+ checker.watch(value.get());
+ g_assert_true(value.get() == result.get());
+ }
+
+ {
+ LeakChecker checker;
+ GRefPtr<JSCContext> context = adoptGRef(jsc_context_new());
+ checker.watch(context.get());
+ ExceptionHandler exceptionHandler(context.get());
+
GRefPtr<JSCValue> function = adoptGRef(jsc_context_evaluate(context.get(), "foo = function(n) { return n * 2; }", -1));
checker.watch(function.get());
@@ -600,6 +636,14 @@
GRefPtr<JSCValue> value = adoptGRef(jsc_value_function_call(function.get(), G_TYPE_INT, 200, G_TYPE_NONE));
checker.watch(value.get());
g_assert_true(value.get() == result.get());
+
+ GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new_with_free_func(g_object_unref));
+ auto* parameter = jsc_value_new_number(context.get(), 200);
+ checker.watch(parameter);
+ g_ptr_array_add(parameters.get(), parameter);
+ value = adoptGRef(jsc_value_function_callv(function.get(), parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
+ checker.watch(value.get());
+ g_assert_true(value.get() == result.get());
}
{
@@ -631,6 +675,15 @@
checker.watch(result.get());
g_assert_true(jsc_value_is_number(result.get()));
g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 400);
+
+ GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new());
+ g_ptr_array_add(parameters.get(), dbl.get());
+ value = adoptGRef(jsc_value_function_callv(function.get(), parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
+ checker.watch(value.get());
+ result = adoptGRef(jsc_context_evaluate(context.get(), "result", -1));
+ checker.watch(result.get());
+ g_assert_true(jsc_value_is_number(result.get()));
+ g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 400);
}
{
@@ -715,6 +768,15 @@
g_assert_true(jsc_value_is_number(result.get()));
g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 400);
+ GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new_with_free_func(g_object_unref));
+ auto* parameter = jsc_value_new_number(context.get(), 200);
+ checker.watch(parameter);
+ g_ptr_array_add(parameters.get(), parameter);
+ result = adoptGRef(jsc_value_object_invoke_methodv(foo.get(), "foo", parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
+ checker.watch(result.get());
+ g_assert_true(jsc_value_is_number(result.get()));
+ g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 400);
+
g_assert_false(jsc_value_object_has_property(foo.get(), "bar"));
bool didThrow = false;
g_assert_throw_begin(exceptionHandler, didThrow);
@@ -723,6 +785,12 @@
g_assert_true(jsc_value_is_undefined(result.get()));
g_assert_did_throw(exceptionHandler, didThrow);
+ g_assert_throw_begin(exceptionHandler, didThrow);
+ result = adoptGRef(jsc_value_object_invoke_methodv(foo.get(), "bar", parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
+ checker.watch(result.get());
+ g_assert_true(jsc_value_is_undefined(result.get()));
+ g_assert_did_throw(exceptionHandler, didThrow);
+
GRefPtr<JSCValue> constructor = adoptGRef(jsc_context_evaluate(context.get(), "Foo", -1));
checker.watch(constructor.get());
g_assert_true(jsc_value_is_constructor(constructor.get()));
@@ -747,6 +815,12 @@
checker.watch(result.get());
g_assert_true(jsc_value_is_number(result.get()));
g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 1000);
+
+ GRefPtr<JSCValue> foo2 = adoptGRef(jsc_value_constructor_callv(constructor.get(), 0, nullptr));
+ checker.watch(foo2.get());
+ g_assert_true(jsc_value_is_object(foo2.get()));
+ g_assert_true(jsc_value_object_is_instance_of(foo2.get(), "Foo"));
+ g_assert_false(foo.get() == foo2.get());
}
{
@@ -1182,12 +1256,18 @@
g_assert_true(jsc_value_is_number(value.get()));
g_assert_cmpint(jsc_value_to_int32(value.get()), ==, 0);
+ value = adoptGRef(jsc_value_object_invoke_methodv(foo.get(), "getFoo", 0, nullptr));
+ checker.watch(value.get());
+ g_assert_true(jsc_value_is_number(value.get()));
+ g_assert_cmpint(jsc_value_to_int32(value.get()), ==, 0);
+
GRefPtr<JSCValue> value2 = adoptGRef(jsc_context_evaluate(context.get(), "f.getFoo()", -1));
checker.watch(value2.get());
g_assert_true(value.get() == value2.get());
g_assert_false(jsc_value_object_has_property(foo.get(), "setFoo"));
- jsc_class_add_method(jscClass, "setFoo", G_CALLBACK(setFoo), nullptr, nullptr, G_TYPE_NONE, 1, G_TYPE_INT);
+ GType parameterTypes[] = { G_TYPE_INT };
+ jsc_class_add_methodv(jscClass, "setFoo", G_CALLBACK(setFoo), nullptr, nullptr, G_TYPE_NONE, 1, parameterTypes);
g_assert_true(jsc_value_object_has_property(foo.get(), "setFoo"));
properties.reset(jsc_value_object_enumerate_properties(foo.get()));
g_assert_null(properties.get());
@@ -1205,7 +1285,12 @@
g_assert_true(jsc_value_is_number(value.get()));
g_assert_cmpint(jsc_value_to_int32(value.get()), ==, 45);
- GRefPtr<JSCValue> constructor2 = adoptGRef(jsc_class_add_constructor(jscClass, "CreateWithFoo", G_CALLBACK(fooCreateWithFoo), nullptr, nullptr, G_TYPE_POINTER, 1, G_TYPE_INT));
+ value = adoptGRef(jsc_value_object_invoke_methodv(foo.get(), "getFoo", 0, nullptr));
+ checker.watch(value.get());
+ g_assert_true(jsc_value_is_number(value.get()));
+ g_assert_cmpint(jsc_value_to_int32(value.get()), ==, 45);
+
+ GRefPtr<JSCValue> constructor2 = adoptGRef(jsc_class_add_constructorv(jscClass, "CreateWithFoo", G_CALLBACK(fooCreateWithFoo), nullptr, nullptr, G_TYPE_POINTER, 1, parameterTypes));
checker.watch(constructor2.get());
g_assert_true(jsc_value_is_constructor(constructor2.get()));
jsc_value_object_set_property(constructor.get(), "CreateWithFoo", constructor2.get());
@@ -1311,7 +1396,7 @@
JSCClass* jscClass = jsc_context_register_class(context.get(), "Foo", nullptr, nullptr, reinterpret_cast<GDestroyNotify>(fooFree));
checker.watch(jscClass);
- GRefPtr<JSCValue> constructor = adoptGRef(jsc_class_add_constructor(jscClass, nullptr, G_CALLBACK(fooCreate), nullptr, nullptr, G_TYPE_POINTER, 0, G_TYPE_NONE));
+ GRefPtr<JSCValue> constructor = adoptGRef(jsc_class_add_constructorv(jscClass, nullptr, G_CALLBACK(fooCreate), nullptr, nullptr, G_TYPE_POINTER, 0, nullptr));
checker.watch(constructor.get());
g_assert_true(jsc_value_is_constructor(constructor.get()));
jsc_context_set_value(context.get(), jsc_class_get_name(jscClass), constructor.get());
@@ -1554,7 +1639,12 @@
g_assert_true(jsc_value_is_number(result.get()));
g_assert_cmpint(jsc_value_to_int32(result.get()), ==, 42);
- GRefPtr<JSCValue> foo3 = adoptGRef(jsc_value_constructor_call(constructor2.get(), G_TYPE_INT, 62, G_TYPE_NONE));
+ GRefPtr<GPtrArray> parameters = adoptGRef(g_ptr_array_new_with_free_func(g_object_unref));
+ auto* parameter = jsc_value_new_number(context.get(), 62);
+ checker.watch(parameter);
+ g_ptr_array_add(parameters.get(), parameter);
+
+ GRefPtr<JSCValue> foo3 = adoptGRef(jsc_value_constructor_callv(constructor2.get(), parameters->len, reinterpret_cast<JSCValue**>(parameters->pdata)));
checker.watch(foo3.get());
g_assert_true(jsc_value_is_object(foo3.get()));
g_assert_true(jsc_value_object_is_instance_of(foo3.get(), "wk.Foo"));