[GLIB] Expose JavaScriptCore options in GLib public API
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Jan 2019 11:09:54 +0000 (11:09 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Jan 2019 11:09:54 +0000 (11:09 +0000)
https://bugs.webkit.org/show_bug.cgi?id=188742

Reviewed by Michael Catanzaro.

Source/JavaScriptCore:

Add new API to set, get and iterate JSC options.

* API/glib/JSCOptions.cpp: Added.
(valueFromGValue):
(valueToGValue):
(jscOptionsSetValue):
(jscOptionsGetValue):
(jsc_options_set_boolean):
(jsc_options_get_boolean):
(jsc_options_set_int):
(jsc_options_get_int):
(jsc_options_set_uint):
(jsc_options_get_uint):
(jsc_options_set_size):
(jsc_options_get_size):
(jsc_options_set_double):
(jsc_options_get_double):
(jsc_options_set_string):
(jsc_options_get_string):
(jsc_options_set_range_string):
(jsc_options_get_range_string):
(jscOptionsType):
(jsc_options_foreach):
(setOptionEntry):
(jsc_options_get_option_group):
* API/glib/JSCOptions.h: Added.
* API/glib/docs/jsc-glib-4.0-sections.txt:
* API/glib/docs/jsc-glib-docs.sgml:
* API/glib/jsc.h:
* GLib.cmake:

Source/WebCore/platform/gtk/po:

* POTFILES.in: Add JSCOptions.cpp

Tools:

Add a test for the new API.

* TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:
(testsJSCOptions):
(main):

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

Source/JavaScriptCore/API/glib/JSCOptions.cpp [new file with mode: 0644]
Source/JavaScriptCore/API/glib/JSCOptions.h [new file with mode: 0644]
Source/JavaScriptCore/API/glib/docs/jsc-glib-4.0-sections.txt
Source/JavaScriptCore/API/glib/docs/jsc-glib-docs.sgml
Source/JavaScriptCore/API/glib/jsc.h
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GLib.cmake
Source/WebCore/platform/gtk/po/ChangeLog
Source/WebCore/platform/gtk/po/POTFILES.in
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp

diff --git a/Source/JavaScriptCore/API/glib/JSCOptions.cpp b/Source/JavaScriptCore/API/glib/JSCOptions.cpp
new file mode 100644 (file)
index 0000000..a9dc7e6
--- /dev/null
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) 2019 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "JSCOptions.h"
+
+#include "Options.h"
+#include <glib/gi18n-lib.h>
+#include <wtf/Vector.h>
+#include <wtf/glib/GUniquePtr.h>
+
+/**
+ * SECTION: JSCOptions
+ * @short_description: JavaScript options
+ * @title: JSCOptions
+ *
+ * JavaScript options allow changing the behavior of the JavaScript engine.
+ * They affect the way the engine works, so it's encouraged to set the options
+ * at the very beginning of the program execution, before any other JavaScript
+ * API call. Most of the options are only useful for testing and debugging.
+ * Only a few of them are documented; you can use the undocumented options at
+ * your own risk. (You can find the list of options in the WebKit source code).
+ *
+ * The API allows to set and get any option using the types defined in #JSCOptionType.
+ * You can also iterate all the available options using jsc_options_foreach() and
+ * passing a #JSCOptionsFunc callback. If your application uses #GOptionContext to handle
+ * command line arguments, you can easily integrate the JSCOptions by adding the
+ * #GOptionGroup returned by jsc_options_get_option_group().
+ *
+ * Since: 2.24
+ */
+
+using namespace JSC;
+
+using int32 = int32_t;
+using size = size_t;
+
+static bool valueFromGValue(const GValue* gValue, bool& value)
+{
+    value = g_value_get_boolean(gValue);
+    return true;
+}
+
+static void valueToGValue(bool value, GValue* gValue)
+{
+    g_value_set_boolean(gValue, value);
+}
+
+static bool valueFromGValue(const GValue* gValue, int32_t& value)
+{
+    value = g_value_get_int(gValue);
+    return true;
+}
+
+static void valueToGValue(int32_t value, GValue* gValue)
+{
+    g_value_set_int(gValue, value);
+}
+
+static bool valueFromGValue(const GValue* gValue, unsigned& value)
+{
+    value = g_value_get_uint(gValue);
+    return true;
+}
+
+static void valueToGValue(unsigned value, GValue* gValue)
+{
+    g_value_set_uint(gValue, value);
+}
+
+static bool valueFromGValue(const GValue* gValue, size_t& value)
+{
+    value = GPOINTER_TO_SIZE(g_value_get_pointer(gValue));
+    return true;
+}
+
+static void valueToGValue(size_t value, GValue* gValue)
+{
+    g_value_set_pointer(gValue, GSIZE_TO_POINTER(value));
+}
+
+static bool valueFromGValue(const GValue* gValue, const char*& value)
+{
+    value = g_value_dup_string(gValue);
+    return true;
+}
+
+static void valueToGValue(const char* value, GValue* gValue)
+{
+    g_value_set_string(gValue, value);
+}
+
+static bool valueFromGValue(const GValue* gValue, double& value)
+{
+    value = g_value_get_double(gValue);
+    return true;
+}
+
+static void valueToGValue(double value, GValue* gValue)
+{
+    g_value_set_double(gValue, value);
+}
+
+static bool valueFromGValue(const GValue* gValue, OptionRange& value)
+{
+    return value.init(g_value_get_string(gValue) ? g_value_get_string(gValue) : "<null>");
+}
+
+static void valueToGValue(const OptionRange& value, GValue* gValue)
+{
+    const char* rangeString = value.rangeString();
+    g_value_set_string(gValue, !g_strcmp0(rangeString, "<null>") ? nullptr : rangeString);
+}
+
+static bool valueFromGValue(const GValue* gValue, GCLogging::Level& value)
+{
+    switch (g_value_get_uint(gValue)) {
+    case 0:
+        value = GCLogging::Level::None;
+        return true;
+    case 1:
+        value = GCLogging::Level::Basic;
+        return true;
+    case 2:
+        value = GCLogging::Level::Verbose;
+        return true;
+    default:
+        break;
+    }
+
+    return false;
+}
+
+static void valueToGValue(GCLogging::Level value, GValue* gValue)
+{
+    switch (value) {
+    case GCLogging::Level::None:
+        g_value_set_uint(gValue, 0);
+        break;
+    case GCLogging::Level::Basic:
+        g_value_set_uint(gValue, 1);
+        break;
+    case GCLogging::Level::Verbose:
+        g_value_set_uint(gValue, 2);
+        break;
+    }
+}
+
+static gboolean jscOptionsSetValue(const char* option, const GValue* value)
+{
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+    if (!g_strcmp0(#name_, option)) {                                   \
+        type_ valueToSet;                                               \
+        if (!valueFromGValue(value, valueToSet))                        \
+            return FALSE;                                               \
+        Options::name_() = valueToSet;                                  \
+        return TRUE;                                                    \
+    }
+
+    Options::initialize();
+    JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+    return FALSE;
+}
+
+static gboolean jscOptionsGetValue(const char* option, GValue* value)
+{
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+    if (!g_strcmp0(#name_, option)) {                                   \
+        type_ valueToGet = Options::name_();                            \
+        valueToGValue(valueToGet, value);                               \
+        return TRUE;                                                    \
+    }
+
+    Options::initialize();
+    JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+    return FALSE;
+}
+
+/**
+ * jsc_options_set_boolean:
+ * @option: the option identifier
+ * @value: the value to set
+ *
+ * Set @option as a #gboolean value.
+ *
+ * Returns: %TRUE if option was correctly set or %FALSE otherwise.
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_set_boolean(const char* option, gboolean value)
+{
+    g_return_val_if_fail(option, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_BOOLEAN);
+    g_value_set_boolean(&gValue, value);
+    return jscOptionsSetValue(option, &gValue);
+}
+
+/**
+ * jsc_options_get_boolean:
+ * @option: the option identifier
+ * @value: (out): return location for the option value
+ *
+ * Get @option as a #gboolean value.
+ *
+ * Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_get_boolean(const char* option, gboolean* value)
+{
+    g_return_val_if_fail(option, FALSE);
+    g_return_val_if_fail(value, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_BOOLEAN);
+    if (!jscOptionsGetValue(option, &gValue))
+        return FALSE;
+
+    *value =  g_value_get_boolean(&gValue);
+    return TRUE;
+}
+
+/**
+ * jsc_options_set_int:
+ * @option: the option identifier
+ * @value: the value to set
+ *
+ * Set @option as a #gint value.
+ *
+ * Returns: %TRUE if option was correctly set or %FALSE otherwise.
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_set_int(const char* option, gint value)
+{
+    g_return_val_if_fail(option, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_INT);
+    g_value_set_int(&gValue, value);
+    return jscOptionsSetValue(option, &gValue);
+}
+
+/**
+ * jsc_options_get_int:
+ * @option: the option identifier
+ * @value: (out): return location for the option value
+ *
+ * Get @option as a #gint value.
+ *
+ * Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_get_int(const char* option, gint* value)
+{
+    g_return_val_if_fail(option, FALSE);
+    g_return_val_if_fail(value, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_INT);
+    if (!jscOptionsGetValue(option, &gValue))
+        return FALSE;
+
+    *value = g_value_get_int(&gValue);
+    return TRUE;
+}
+
+/**
+ * jsc_options_set_uint:
+ * @option: the option identifier
+ * @value: the value to set
+ *
+ * Set @option as a #guint value.
+ *
+ * Returns: %TRUE if option was correctly set or %FALSE otherwise.
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_set_uint(const char* option, guint value)
+{
+    g_return_val_if_fail(option, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_UINT);
+    g_value_set_uint(&gValue, value);
+    return jscOptionsSetValue(option, &gValue);
+}
+
+/**
+ * jsc_options_get_uint:
+ * @option: the option identifier
+ * @value: (out): return location for the option value
+ *
+ * Get @option as a #guint value.
+ *
+ * Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_get_uint(const char* option, guint* value)
+{
+    g_return_val_if_fail(option, FALSE);
+    g_return_val_if_fail(value, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_UINT);
+    if (!jscOptionsGetValue(option, &gValue))
+        return FALSE;
+
+    *value = g_value_get_uint(&gValue);
+    return TRUE;
+}
+
+/**
+ * jsc_options_set_size:
+ * @option: the option identifier
+ * @value: the value to set
+ *
+ * Set @option as a #gsize value.
+ *
+ * Returns: %TRUE if option was correctly set or %FALSE otherwise.
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_set_size(const char* option, gsize value)
+{
+    g_return_val_if_fail(option, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_POINTER);
+    g_value_set_pointer(&gValue, GSIZE_TO_POINTER(value));
+    return jscOptionsSetValue(option, &gValue);
+}
+
+/**
+ * jsc_options_get_size:
+ * @option: the option identifier
+ * @value: (out): return location for the option value
+ *
+ * Get @option as a #gsize value.
+ *
+ * Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_get_size(const char* option, gsize* value)
+{
+    g_return_val_if_fail(option, FALSE);
+    g_return_val_if_fail(value, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_POINTER);
+    if (!jscOptionsGetValue(option, &gValue))
+        return FALSE;
+
+    *value = GPOINTER_TO_SIZE(g_value_get_pointer(&gValue));
+    return TRUE;
+}
+
+/**
+ * jsc_options_set_double:
+ * @option: the option identifier
+ * @value: the value to set
+ *
+ * Set @option as a #gdouble value.
+ *
+ * Returns: %TRUE if option was correctly set or %FALSE otherwise.
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_set_double(const char* option, gdouble value)
+{
+    g_return_val_if_fail(option, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_DOUBLE);
+    g_value_set_double(&gValue, value);
+    return jscOptionsSetValue(option, &gValue);
+}
+
+/**
+ * jsc_options_get_double:
+ * @option: the option identifier
+ * @value: (out): return location for the option value
+ *
+ * Get @option as a #gdouble value.
+ *
+ * Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_get_double(const char* option, gdouble* value)
+{
+    g_return_val_if_fail(option, FALSE);
+    g_return_val_if_fail(value, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_DOUBLE);
+    if (!jscOptionsGetValue(option, &gValue))
+        return FALSE;
+
+    *value = g_value_get_double(&gValue);
+    return TRUE;
+}
+
+/**
+ * jsc_options_set_string:
+ * @option: the option identifier
+ * @value: the value to set
+ *
+ * Set @option as a string.
+ *
+ * Returns: %TRUE if option was correctly set or %FALSE otherwise.
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_set_string(const char* option, const char* value)
+{
+    g_return_val_if_fail(option, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_STRING);
+    g_value_set_string(&gValue, value);
+    bool success = jscOptionsSetValue(option, &gValue);
+    g_value_unset(&gValue);
+    return success;
+}
+
+/**
+ * jsc_options_get_string:
+ * @option: the option identifier
+ * @value: (out): return location for the option value
+ *
+ * Get @option as a string.
+ *
+ * Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_get_string(const char* option, char** value)
+{
+    g_return_val_if_fail(option, FALSE);
+    g_return_val_if_fail(value, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_STRING);
+    if (!jscOptionsGetValue(option, &gValue))
+        return FALSE;
+
+    *value = g_value_dup_string(&gValue);
+    g_value_unset(&gValue);
+    return TRUE;
+}
+
+/**
+ * jsc_options_set_range_string:
+ * @option: the option identifier
+ * @value: the value to set
+ *
+ * Set @option as a range string. The string must be in the
+ * format <emphasis>[!]&lt;low&gt;[:&lt;high&gt;]</emphasis> where low and high are #guint values.
+ * Values between low and high (both included) will be considered in
+ * the range, unless <emphasis>!</emphasis> is used to invert the range.
+ *
+ * Returns: %TRUE if option was correctly set or %FALSE otherwise.
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_set_range_string(const char* option, const char* value)
+{
+    g_return_val_if_fail(option, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_STRING);
+    g_value_set_string(&gValue, value);
+    bool success = jscOptionsSetValue(option, &gValue);
+    g_value_unset(&gValue);
+    return success;
+}
+
+/**
+ * jsc_options_get_range_string:
+ * @option: the option identifier
+ * @value: (out): return location for the option value
+ *
+ * Get @option as a range string. The string must be in the
+ * format <emphasis>[!]&lt;low&gt;[:&lt;high&gt;]</emphasis> where low and high are #guint values.
+ * Values between low and high (both included) will be considered in
+ * the range, unless <emphasis>!</emphasis> is used to invert the range.
+ *
+ * Returns: %TRUE if @value has been set or %FALSE if the option doesn't exist
+ *
+ * Since: 2.24
+ */
+gboolean jsc_options_get_range_string(const char* option, char** value)
+{
+    g_return_val_if_fail(option, FALSE);
+    g_return_val_if_fail(value, FALSE);
+
+    GValue gValue = G_VALUE_INIT;
+    g_value_init(&gValue, G_TYPE_STRING);
+    if (!jscOptionsGetValue(option, &gValue))
+        return FALSE;
+
+    *value = g_value_dup_string(&gValue);
+    g_value_unset(&gValue);
+    return TRUE;
+}
+
+static JSCOptionType jscOptionsType(bool)
+{
+    return JSC_OPTION_BOOLEAN;
+}
+
+static JSCOptionType jscOptionsType(int)
+{
+    return JSC_OPTION_INT;
+}
+
+static JSCOptionType jscOptionsType(unsigned)
+{
+    return JSC_OPTION_UINT;
+}
+
+static JSCOptionType jscOptionsType(size_t)
+{
+    return JSC_OPTION_SIZE;
+}
+
+static JSCOptionType jscOptionsType(double)
+{
+    return JSC_OPTION_DOUBLE;
+}
+
+static JSCOptionType jscOptionsType(const char*)
+{
+    return JSC_OPTION_STRING;
+}
+
+static JSCOptionType jscOptionsType(const OptionRange&)
+{
+    return JSC_OPTION_RANGE_STRING;
+}
+
+/**
+ * JSCOptionType:
+ * @JSC_OPTION_BOOLEAN: A #gboolean option type.
+ * @JSC_OPTION_INT: A #gint option type.
+ * @JSC_OPTION_UINT: A #guint option type.
+ * @JSC_OPTION_SIZE: A #gsize options type.
+ * @JSC_OPTION_DOUBLE: A #gdouble options type.
+ * @JSC_OPTION_STRING: A string option type.
+ * @JSC_OPTION_RANGE_STRING: A range string option type.
+ *
+ * Enum values for options types.
+ *
+ * Since: 2.24
+ */
+
+/**
+ * JSCOptionsFunc:
+ * @option: the option name
+ * @type: the option #JSCOptionType
+ * @description: (nullable): the option description, or %NULL
+ * @user_data: user data
+ *
+ * Function used to iterate options.
+ *
+ * Not that @description string is not localized.
+ *
+ * Returns: %TRUE to stop the iteration, or %FALSE otherwise
+ *
+ * Since: 2.24
+ */
+
+/**
+ * jsc_options_foreach:
+ * @function: (scope call): a #JSCOptionsFunc callback
+ * @user_data: callback user data
+ *
+ * Iterates all available options calling @function for each one. Iteration can
+ * stop early if @function returns %FALSE.
+ *
+ * Since: 2.24
+ */
+void jsc_options_foreach(JSCOptionsFunc function, gpointer userData)
+{
+    g_return_if_fail(function);
+
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+    if (Options::Availability::availability_ == Options::Availability::Normal \
+        || Options::isAvailable(Options::name_##ID, Options::Availability::availability_)) { \
+        type_ defaultValue;                                             \
+        auto optionType = jscOptionsType(defaultValue);                 \
+        if (function (#name_, optionType, description_, userData))      \
+            return;                                                     \
+    }
+
+    Options::initialize();
+    JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+}
+
+static gboolean setOptionEntry(const char* optionNameFull, const char* value, gpointer, GError** error)
+{
+    const char* optionName = optionNameFull + 6; // Remove the --jsc- prefix.
+    GUniquePtr<char> option(g_strdup_printf("%s=%s", optionName, value));
+    if (!Options::setOption(option.get())) {
+        g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, "Failed parse value '%s' for %s", value, optionNameFull);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/**
+ * jsc_options_get_option_group:
+ *
+ * Create a #GOptionGroup to handle JSCOptions as command line arguments.
+ * The options will be exposed as command line arguments with the form
+ * <emphasis>--jsc-&lt;option&gt;=&lt;value&gt;</emphasis>.
+ * Each entry in the returned #GOptionGroup is configured to apply the
+ * corresponding option during command line parsing. Applications only need to
+ * pass the returned group to g_option_context_add_group(), and the rest will
+ * be taken care for automatically.
+ *
+ * Returns: (transfer full): a #GOptionGroup for the JSCOptions
+ *
+ * Since: 2.24
+ */
+GOptionGroup* jsc_options_get_option_group(void)
+{
+    // GOptionEntry works with const strings, so we need to keep the option names around.
+    auto* names = new Vector<GUniquePtr<char>>;
+    GOptionGroup* group = g_option_group_new("jsc", _("JSC Options"), _("Show JSC Options"), names, [] (gpointer data) {
+        delete static_cast<Vector<GUniquePtr<char>>*>(data);
+    });
+    g_option_group_set_translation_domain(group, GETTEXT_PACKAGE);
+
+    GArray* entries = g_array_new(TRUE, TRUE, sizeof(GOptionEntry));
+#define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \
+    if (Options::Availability::availability_ == Options::Availability::Normal \
+        || Options::isAvailable(Options::name_##ID, Options::Availability::availability_)) { \
+        GUniquePtr<char> name(g_strdup_printf("jsc-%s", #name_));       \
+        entries = g_array_set_size(entries, entries->len + 1); \
+        GOptionEntry* entry = &g_array_index(entries, GOptionEntry, entries->len - 1); \
+        entry->long_name = name.get();                                  \
+        entry->arg = G_OPTION_ARG_CALLBACK;                             \
+        entry->arg_data = reinterpret_cast<gpointer>(setOptionEntry);   \
+        entry->description = description_;                              \
+        names->append(WTFMove(name));                                   \
+    }
+
+    Options::initialize();
+    JSC_OPTIONS(FOR_EACH_OPTION)
+#undef FOR_EACH_OPTION
+
+    g_option_group_add_entries(group, reinterpret_cast<GOptionEntry*>(entries->data));
+    return group;
+}
+
+/**
+ * JSC_OPTIONS_USE_JIT:
+ *
+ * Allows the executable pages to be allocated for JIT and thunks if %TRUE.
+ * Option type: %JSC_OPTION_BOOLEAN
+ * Default value: %TRUE.
+ *
+ * Since: 2.24
+ */
+
+/**
+ * JSC_OPTIONS_USE_DFG:
+ *
+ * Allows the DFG JIT to be used if %TRUE.
+ * Option type: %JSC_OPTION_BOOLEAN
+ * Default value: %TRUE.
+ *
+ * Since: 2.24
+ */
+
+/**
+ * JSC_OPTIONS_USE_FTL:
+ *
+ * Allows the FTL JIT to be used if %TRUE.
+ * Option type: %JSC_OPTION_BOOLEAN
+ * Default value: %TRUE.
+ *
+ * Since: 2.24
+ */
+
+/**
+ * JSC_OPTIONS_USE_LLINT:
+ *
+ * Allows the LLINT to be used if %TRUE.
+ * Option type: %JSC_OPTION_BOOLEAN
+ * Default value: %TRUE.
+ *
+ * Since: 2.24
+ */
diff --git a/Source/JavaScriptCore/API/glib/JSCOptions.h b/Source/JavaScriptCore/API/glib/JSCOptions.h
new file mode 100644 (file)
index 0000000..dee97b8
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2019 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#if !defined(__JSC_H_INSIDE__) && !defined(JSC_COMPILATION) && !defined(WEBKIT2_COMPILATION)
+#error "Only <jsc/jsc.h> can be included directly."
+#endif
+
+#ifndef JSCOptions_h
+#define JSCOptions_h
+
+#include <glib-object.h>
+#include <jsc/JSCDefines.h>
+
+G_BEGIN_DECLS
+
+#define JSC_OPTIONS_USE_JIT   "useJIT"
+#define JSC_OPTIONS_USE_DFG   "useDFGJIT"
+#define JSC_OPTIONS_USE_FTL   "useFTLJIT"
+#define JSC_OPTIONS_USE_LLINT "useLLInt"
+
+JSC_API gboolean
+jsc_options_set_boolean       (const char *option,
+                               gboolean    value);
+JSC_API gboolean
+jsc_options_get_boolean       (const char *option,
+                               gboolean   *value);
+
+JSC_API gboolean
+jsc_options_set_int           (const char *option,
+                               gint        value);
+JSC_API gboolean
+jsc_options_get_int           (const char *option,
+                               gint       *value);
+
+JSC_API gboolean
+jsc_options_set_uint          (const char *option,
+                               guint       value);
+JSC_API gboolean
+jsc_options_get_uint          (const char *option,
+                               guint      *value);
+
+JSC_API gboolean
+jsc_options_set_size          (const char *option,
+                               gsize       value);
+JSC_API gboolean
+jsc_options_get_size          (const char *option,
+                               gsize      *value);
+
+JSC_API gboolean
+jsc_options_set_double        (const char *option,
+                               gdouble     value);
+JSC_API gboolean
+jsc_options_get_double        (const char *option,
+                               gdouble    *value);
+
+JSC_API gboolean
+jsc_options_set_string        (const char *option,
+                               const char *value);
+JSC_API gboolean
+jsc_options_get_string        (const char *option,
+                               char       **value);
+
+JSC_API gboolean
+jsc_options_set_range_string  (const char *option,
+                               const char *value);
+JSC_API gboolean
+jsc_options_get_range_string  (const char *option,
+                               char       **value);
+
+typedef enum {
+    JSC_OPTION_BOOLEAN,
+    JSC_OPTION_INT,
+    JSC_OPTION_UINT,
+    JSC_OPTION_SIZE,
+    JSC_OPTION_DOUBLE,
+    JSC_OPTION_STRING,
+    JSC_OPTION_RANGE_STRING
+} JSCOptionType;
+
+typedef gboolean (* JSCOptionsFunc) (const char    *option,
+                                     JSCOptionType  type,
+                                     const char    *description,
+                                     gpointer       user_data);
+
+JSC_API void
+jsc_options_foreach                 (JSCOptionsFunc function,
+                                     gpointer       user_data);
+
+JSC_API GOptionGroup *
+jsc_options_get_option_group        (void);
+
+G_END_DECLS
+
+#endif /* JSCOptions_h */
index add682a..3ae2225 100644 (file)
@@ -212,6 +212,36 @@ jsc_class_get_type
 </SECTION>
 
 <SECTION>
+<FILE>JSCOptions</FILE>
+<TITLE>JSCOptions</TITLE>
+jsc_options_set_boolean
+jsc_options_get_boolean
+jsc_options_set_int
+jsc_options_get_int
+jsc_options_set_uint
+jsc_options_get_uint
+jsc_options_set_size
+jsc_options_get_size
+jsc_options_set_double
+jsc_options_get_double
+jsc_options_set_string
+jsc_options_get_string
+jsc_options_set_range_string
+jsc_options_get_range_string
+
+JSCOptionType
+JSCOptionsFunc
+jsc_options_foreach
+
+jsc_options_get_option_group
+<SUBSECTION>
+JSC_OPTIONS_USE_JIT
+JSC_OPTIONS_USE_DFG
+JSC_OPTIONS_USE_FTL
+JSC_OPTIONS_USE_LLINT
+</SECTION>
+
+<SECTION>
 <FILE>JSCVersion</FILE>
 <TITLE>JSCVersion</TITLE>
 jsc_get_major_version
index 4853a10..1c2db5c 100644 (file)
@@ -17,6 +17,7 @@
     <xi:include href="xml/JSCWeakValue.xml"/>
     <xi:include href="xml/JSCException.xml"/>
     <xi:include href="xml/JSCClass.xml"/>
+    <xi:include href="xml/JSCOptions.xml"/>
     <xi:include href="xml/JSCVersion.xml"/>
   </chapter>
 
     <title>Index</title>
   </index>
 
+  <index id="api-index-2-24" role="2.24">
+    <title>Index of new symbols in 2.24</title>
+    <xi:include href="xml/api-index-2.24.xml"><xi:fallback /></xi:include>
+  </index>
+
   <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
 </book>
index 8a28452..11537f9 100644 (file)
@@ -26,6 +26,7 @@
 #include <jsc/JSCContext.h>
 #include <jsc/JSCDefines.h>
 #include <jsc/JSCException.h>
+#include <jsc/JSCOptions.h>
 #include <jsc/JSCValue.h>
 #include <jsc/JSCVersion.h>
 #include <jsc/JSCVirtualMachine.h>
index 5a4c92f..43d6ca8 100644 (file)
@@ -1,3 +1,41 @@
+2019-01-24  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GLIB] Expose JavaScriptCore options in GLib public API
+        https://bugs.webkit.org/show_bug.cgi?id=188742
+
+        Reviewed by Michael Catanzaro.
+
+        Add new API to set, get and iterate JSC options.
+
+        * API/glib/JSCOptions.cpp: Added.
+        (valueFromGValue):
+        (valueToGValue):
+        (jscOptionsSetValue):
+        (jscOptionsGetValue):
+        (jsc_options_set_boolean):
+        (jsc_options_get_boolean):
+        (jsc_options_set_int):
+        (jsc_options_get_int):
+        (jsc_options_set_uint):
+        (jsc_options_get_uint):
+        (jsc_options_set_size):
+        (jsc_options_get_size):
+        (jsc_options_set_double):
+        (jsc_options_get_double):
+        (jsc_options_set_string):
+        (jsc_options_get_string):
+        (jsc_options_set_range_string):
+        (jsc_options_get_range_string):
+        (jscOptionsType):
+        (jsc_options_foreach):
+        (setOptionEntry):
+        (jsc_options_get_option_group):
+        * API/glib/JSCOptions.h: Added.
+        * API/glib/docs/jsc-glib-4.0-sections.txt:
+        * API/glib/docs/jsc-glib-docs.sgml:
+        * API/glib/jsc.h:
+        * GLib.cmake:
+
 2019-01-23  Mark Lam  <mark.lam@apple.com>
 
         ARM64E should not ENABLE(SEPARATED_WX_HEAP).
index dc85f4e..4d1ffe5 100644 (file)
@@ -8,6 +8,7 @@ list(APPEND JavaScriptCore_SOURCES
     API/glib/JSCClass.cpp
     API/glib/JSCContext.cpp
     API/glib/JSCException.cpp
+    API/glib/JSCOptions.cpp
     API/glib/JSCValue.cpp
     API/glib/JSCVersion.cpp
     API/glib/JSCVirtualMachine.cpp
@@ -28,6 +29,7 @@ set(JavaScriptCore_INSTALLED_HEADERS
     ${JAVASCRIPTCORE_DIR}/API/glib/JSCContext.h
     ${JAVASCRIPTCORE_DIR}/API/glib/JSCDefines.h
     ${JAVASCRIPTCORE_DIR}/API/glib/JSCException.h
+    ${JAVASCRIPTCORE_DIR}/API/glib/JSCOptions.h
     ${JAVASCRIPTCORE_DIR}/API/glib/JSCValue.h
     ${JAVASCRIPTCORE_DIR}/API/glib/JSCVirtualMachine.h
     ${JAVASCRIPTCORE_DIR}/API/glib/JSCWeakValue.h
index 48b092a..25ff2a0 100644 (file)
@@ -1,3 +1,12 @@
+2019-01-24  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        [GLIB] Expose JavaScriptCore options in GLib public API
+        https://bugs.webkit.org/show_bug.cgi?id=188742
+
+        Reviewed by Michael Catanzaro.
+
+        * POTFILES.in: Add JSCOptions.cpp
+
 2019-01-08  Josef Andersson  <josef.andersson@fripost.org>
 
         [GTK] Updated Swedish translation
index b4fb001..3ec09db 100644 (file)
@@ -2,6 +2,7 @@
 LocalizedStringsGtk.cpp
 ../LocalizedStrings.cpp
 ../network/soup/NetworkStorageSessionSoup.cpp
+../../../JavaScriptCore/API/glib/JSCOptions.cpp
 ../../../WebKit/Shared/API/glib/WebKitHitTestResult.cpp
 ../../../WebKit/Shared/API/glib/WebKitURIRequest.cpp
 ../../../WebKit/Shared/API/glib/WebKitURIResponse.cpp
index 2c9f996..4c27d0d 100644 (file)
@@ -1,5 +1,18 @@
 2019-01-24  Carlos Garcia Campos  <cgarcia@igalia.com>
 
+        [GLIB] Expose JavaScriptCore options in GLib public API
+        https://bugs.webkit.org/show_bug.cgi?id=188742
+
+        Reviewed by Michael Catanzaro.
+
+        Add a test for the new API.
+
+        * TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:
+        (testsJSCOptions):
+        (main):
+
+2019-01-24  Carlos Garcia Campos  <cgarcia@igalia.com>
+
         [GTK][WPE] Support JPEG 2000 images
         https://bugs.webkit.org/show_bug.cgi?id=186272
 
index 7e372c3..b22f7e5 100644 (file)
@@ -3227,6 +3227,211 @@ static void testsJSCVirtualMachine()
     }
 }
 
+static void testsJSCOptions()
+{
+    gboolean useJIT;
+    g_assert_true(jsc_options_get_boolean(JSC_OPTIONS_USE_JIT, &useJIT));
+    g_assert_true(useJIT);
+    g_assert_true(jsc_options_set_boolean(JSC_OPTIONS_USE_JIT, FALSE));
+    g_assert_true(jsc_options_get_boolean(JSC_OPTIONS_USE_JIT, &useJIT));
+    g_assert_false(useJIT);
+    g_assert_true(jsc_options_set_boolean(JSC_OPTIONS_USE_JIT, TRUE));
+
+    gint thresholdForJITAfterWarmUp;
+    g_assert_true(jsc_options_get_int("thresholdForJITAfterWarmUp", &thresholdForJITAfterWarmUp));
+    g_assert_cmpint(thresholdForJITAfterWarmUp, ==, 500);
+    g_assert_true(jsc_options_set_int("thresholdForJITAfterWarmUp", 1000));
+    g_assert_true(jsc_options_get_int("thresholdForJITAfterWarmUp", &thresholdForJITAfterWarmUp));
+    g_assert_cmpint(thresholdForJITAfterWarmUp, ==, 1000);
+    g_assert_true(jsc_options_set_int("thresholdForJITAfterWarmUp", 500));
+
+    guint maxPerThreadStackUsage;
+    g_assert_true(jsc_options_get_uint("maxPerThreadStackUsage", &maxPerThreadStackUsage));
+    g_assert_cmpuint(maxPerThreadStackUsage, ==, 4194304);
+    g_assert_true(jsc_options_set_uint("maxPerThreadStackUsage", 4096));
+    g_assert_true(jsc_options_get_uint("maxPerThreadStackUsage", &maxPerThreadStackUsage));
+    g_assert_cmpuint(maxPerThreadStackUsage, ==, 4096);
+    g_assert_true(jsc_options_set_uint("maxPerThreadStackUsage", 4194304));
+
+    gsize webAssemblyPartialCompileLimit;
+    g_assert_true(jsc_options_get_size("webAssemblyPartialCompileLimit", &webAssemblyPartialCompileLimit));
+    g_assert_cmpuint(webAssemblyPartialCompileLimit, ==, 5000);
+    g_assert_true(jsc_options_set_size("webAssemblyPartialCompileLimit", 6000));
+    g_assert_true(jsc_options_get_size("webAssemblyPartialCompileLimit", &webAssemblyPartialCompileLimit));
+    g_assert_cmpuint(webAssemblyPartialCompileLimit, ==, 6000);
+    g_assert_true(jsc_options_set_size("webAssemblyPartialCompileLimit", 5000));
+
+    gdouble smallHeapRAMFraction;
+    g_assert_true(jsc_options_get_double("smallHeapRAMFraction", &smallHeapRAMFraction));
+    g_assert_cmpfloat(smallHeapRAMFraction, ==, 0.25);
+    g_assert_true(jsc_options_set_double("smallHeapRAMFraction", 0.50));
+    g_assert_true(jsc_options_get_double("smallHeapRAMFraction", &smallHeapRAMFraction));
+    g_assert_cmpfloat(smallHeapRAMFraction, ==, 0.50);
+    g_assert_true(jsc_options_set_double("smallHeapRAMFraction", 0.25));
+
+    GUniqueOutPtr<char> configFile;
+    g_assert_true(jsc_options_get_string("configFile", &configFile.outPtr()));
+    g_assert_null(configFile.get());
+    g_assert_true(jsc_options_set_string("configFile", "/tmp/foo"));
+    g_assert_true(jsc_options_get_string("configFile", &configFile.outPtr()));
+    g_assert_cmpstr(configFile.get(), ==, "/tmp/foo");
+    g_assert_true(jsc_options_set_string("configFile", nullptr));
+    g_assert_true(jsc_options_get_string("configFile", &configFile.outPtr()));
+    g_assert_null(configFile.get());
+
+    GUniqueOutPtr<char> bytecodeRangeToJITCompile;
+    g_assert_true(jsc_options_get_range_string("bytecodeRangeToJITCompile", &bytecodeRangeToJITCompile.outPtr()));
+    g_assert_null(bytecodeRangeToJITCompile.get());
+    g_assert_true(jsc_options_set_range_string("bytecodeRangeToJITCompile", "100"));
+    g_assert_true(jsc_options_get_range_string("bytecodeRangeToJITCompile", &bytecodeRangeToJITCompile.outPtr()));
+    g_assert_cmpstr(bytecodeRangeToJITCompile.get(), ==, "100");
+    g_assert_true(jsc_options_set_range_string("bytecodeRangeToJITCompile", "100:200"));
+    g_assert_true(jsc_options_get_range_string("bytecodeRangeToJITCompile", &bytecodeRangeToJITCompile.outPtr()));
+    g_assert_cmpstr(bytecodeRangeToJITCompile.get(), ==, "100:200");
+    g_assert_true(jsc_options_set_range_string("bytecodeRangeToJITCompile", "!100:200"));
+    g_assert_true(jsc_options_get_range_string("bytecodeRangeToJITCompile", &bytecodeRangeToJITCompile.outPtr()));
+    g_assert_cmpstr(bytecodeRangeToJITCompile.get(), ==, "!100:200");
+    g_assert_false(jsc_options_set_range_string("bytecodeRangeToJITCompile", "200:100"));
+    g_assert_true(jsc_options_get_range_string("bytecodeRangeToJITCompile", &bytecodeRangeToJITCompile.outPtr()));
+    g_assert_cmpstr(bytecodeRangeToJITCompile.get(), ==, "!100:200");
+    g_assert_true(jsc_options_set_range_string("bytecodeRangeToJITCompile", nullptr));
+    g_assert_true(jsc_options_get_range_string("bytecodeRangeToJITCompile", &bytecodeRangeToJITCompile.outPtr()));
+    g_assert_null(bytecodeRangeToJITCompile.get());
+
+    guint logGC;
+    g_assert_true(jsc_options_get_uint("logGC", &logGC));
+    g_assert_cmpuint(logGC, ==, 0);
+    g_assert_true(jsc_options_set_uint("logGC", 1));
+    g_assert_true(jsc_options_get_uint("logGC", &logGC));
+    g_assert_cmpuint(logGC, ==, 1);
+    g_assert_true(jsc_options_set_uint("logGC", 2));
+    g_assert_true(jsc_options_get_uint("logGC", &logGC));
+    g_assert_cmpuint(logGC, ==, 2);
+    g_assert_false(jsc_options_set_uint("logGC", 3));
+    g_assert_true(jsc_options_get_uint("logGC", &logGC));
+    g_assert_cmpuint(logGC, ==, 2);
+    g_assert_true(jsc_options_set_uint("logGC", 0));
+    g_assert_true(jsc_options_get_uint("logGC", &logGC));
+    g_assert_cmpuint(logGC, ==, 0);
+
+    gboolean value = TRUE;
+    g_assert_false(jsc_options_get_boolean("InvalidOption", &value));
+    g_assert_true(value);
+    g_assert_false(jsc_options_set_boolean("InvalidOption", TRUE));
+    g_assert_false(jsc_options_get_boolean("InvalidOption", &value));
+    g_assert_true(value);
+
+    // Find a particular option.
+    bool found = false;
+    jsc_options_foreach([](const char* option, JSCOptionType type, const char* description, gpointer userData) -> gboolean {
+        if (!g_strcmp0(option, "useJIT")) {
+            *static_cast<bool*>(userData) = true;
+            return TRUE;
+        }
+        return FALSE;
+    }, &found);
+    g_assert_true(found);
+
+    unsigned optionsCount = 0;
+    jsc_options_foreach([](const char* option, JSCOptionType type, const char* description, gpointer userData) -> gboolean {
+        (*static_cast<unsigned*>(userData))++;
+        return FALSE;
+    }, &optionsCount);
+    g_assert_cmpuint(optionsCount, >, 100);
+    g_assert_cmpuint(optionsCount, <, 500);
+
+    optionsCount = 0;
+    jsc_options_foreach([](const char* option, JSCOptionType type, const char* description, gpointer userData) -> gboolean {
+        if (!g_strcmp0(option, "useJIT"))
+            g_assert_true(type == JSC_OPTION_BOOLEAN);
+        else if (!g_strcmp0(option, "thresholdForJITAfterWarmUp"))
+            g_assert_true(type == JSC_OPTION_INT);
+        else if (!g_strcmp0(option, "maxPerThreadStackUsage"))
+            g_assert_true(type == JSC_OPTION_UINT);
+        else if (!g_strcmp0(option, "webAssemblyPartialCompileLimit"))
+            g_assert_true(type == JSC_OPTION_SIZE);
+        else if (!g_strcmp0(option, "smallHeapRAMFraction"))
+            g_assert_true(type == JSC_OPTION_DOUBLE);
+        else if (!g_strcmp0(option, "configFile"))
+            g_assert_true(type == JSC_OPTION_STRING);
+        else if (!g_strcmp0(option, "bytecodeRangeToJITCompile"))
+            g_assert_true(type == JSC_OPTION_RANGE_STRING);
+        else
+            return FALSE;
+
+        (*static_cast<unsigned*>(userData))++;
+        return FALSE;
+    }, &optionsCount);
+    g_assert_cmpuint(optionsCount, ==, 7);
+
+    GOptionContext* context = g_option_context_new(nullptr);
+    g_option_context_add_group(context, jsc_options_get_option_group());
+    static const char* argv[] = {
+        __FILE__,
+        "--jsc-useJIT=false",
+        "--jsc-thresholdForJITAfterWarmUp=2000",
+        "--jsc-maxPerThreadStackUsage=1024",
+        "--jsc-webAssemblyPartialCompileLimit=4000",
+        "--jsc-smallHeapRAMFraction=0.75",
+        "--jsc-configFile=/tmp/bar",
+        "--jsc-bytecodeRangeToJITCompile=100:300",
+        "--jsc-logGC=1",
+        nullptr
+    };
+    GUniquePtr<char*> copy(g_strdupv(const_cast<char**>(argv)));
+    int argc = g_strv_length(copy.get());
+    auto* copyPtr = copy.get();
+    g_assert_true(g_option_context_parse(context, &argc, &copyPtr, nullptr));
+    g_option_context_free(context);
+
+    g_assert_true(jsc_options_get_boolean(JSC_OPTIONS_USE_JIT, &useJIT));
+    g_assert_false(useJIT);
+    g_assert_true(jsc_options_get_int("thresholdForJITAfterWarmUp", &thresholdForJITAfterWarmUp));
+    g_assert_cmpint(thresholdForJITAfterWarmUp, ==, 2000);
+    g_assert_true(jsc_options_get_uint("maxPerThreadStackUsage", &maxPerThreadStackUsage));
+    g_assert_cmpuint(maxPerThreadStackUsage, ==, 1024);
+    g_assert_true(jsc_options_get_size("webAssemblyPartialCompileLimit", &webAssemblyPartialCompileLimit));
+    g_assert_cmpuint(webAssemblyPartialCompileLimit, ==, 4000);
+    g_assert_true(jsc_options_get_double("smallHeapRAMFraction", &smallHeapRAMFraction));
+    g_assert_cmpfloat(smallHeapRAMFraction, ==, 0.75);
+    g_assert_true(jsc_options_get_string("configFile", &configFile.outPtr()));
+    g_assert_cmpstr(configFile.get(), ==, "/tmp/bar");
+    g_assert_true(jsc_options_get_range_string("bytecodeRangeToJITCompile", &bytecodeRangeToJITCompile.outPtr()));
+    g_assert_cmpstr(bytecodeRangeToJITCompile.get(), ==, "100:300");
+    g_assert_true(jsc_options_get_uint("logGC", &logGC));
+    g_assert_cmpuint(logGC, ==, 1);
+
+    // Restore options their default values.
+    g_assert_true(jsc_options_set_boolean(JSC_OPTIONS_USE_JIT, TRUE));
+    g_assert_true(jsc_options_set_int("thresholdForJITAfterWarmUp", 500));
+    g_assert_true(jsc_options_set_uint("maxPerThreadStackUsage", 4194304));
+    g_assert_true(jsc_options_set_size("webAssemblyPartialCompileLimit", 5000));
+    g_assert_true(jsc_options_set_double("smallHeapRAMFraction", 0.25));
+    g_assert_true(jsc_options_set_string("configFile", nullptr));
+    g_assert_true(jsc_options_set_range_string("bytecodeRangeToJITCompile", nullptr));
+    g_assert_true(jsc_options_set_uint("logGC", 0));
+
+    context = g_option_context_new(nullptr);
+    g_option_context_add_group(context, jsc_options_get_option_group());
+    static const char* argv2[] = { __FILE__, "--jsc-InvalidOption=true", nullptr };
+    copy.reset(g_strdupv(const_cast<char**>(argv2)));
+    argc = g_strv_length(copy.get());
+    copyPtr = copy.get();
+    g_assert_false(g_option_context_parse(context, &argc, &copyPtr, nullptr));
+    g_option_context_free(context);
+
+    context = g_option_context_new(nullptr);
+    g_option_context_add_group(context, jsc_options_get_option_group());
+    static const char* argv3[] = { __FILE__, "--jsc-useJIT=nein", nullptr };
+    copy.reset(g_strdupv(const_cast<char**>(argv3)));
+    argc = g_strv_length(copy.get());
+    copyPtr = copy.get();
+    g_assert_false(g_option_context_parse(context, &argc, &copyPtr, nullptr));
+    g_option_context_free(context);
+    g_assert_true(jsc_options_get_boolean(JSC_OPTIONS_USE_JIT, &useJIT));
+    g_assert_true(useJIT);
+}
+
 #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
 static void testsJSCAutocleanups()
 {
@@ -3270,6 +3475,7 @@ int main(int argc, char** argv)
     g_test_add_func("/jsc/garbage-collector", testJSCGarbageCollector);
     g_test_add_func("/jsc/weak-value", testJSCWeakValue);
     g_test_add_func("/jsc/vm", testsJSCVirtualMachine);
+    g_test_add_func("/jsc/options", testsJSCOptions);
 #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
     g_test_add_func("/jsc/autocleanups", testsJSCAutocleanups);
 #endif