[gjs/wip/coverage-2: 9/10] ff5



commit 6e48143bb5eded789d6a50bf490ad7427152dcff
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Wed Jan 15 18:16:53 2014 -0500

    ff5

 gjs/console.cpp                    |    3 +-
 gjs/coverage.cpp                   |  110 ++++--------
 gjs/coverage.h                     |    4 +-
 gjs/reflected-script.cpp           |  344 ++++++++++++------------------------
 gjs/reflected-script.h             |   10 +-
 installed-tests/gjs-unit.cpp       |    3 +-
 modules/infoReflect.js             |   13 ++-
 test/gjs-test-coverage.cpp         |   15 +--
 test/gjs-test-debug-hooks.cpp      |    5 +-
 test/gjs-test-reflected-script.cpp |   29 ++--
 10 files changed, 187 insertions(+), 349 deletions(-)
---
diff --git a/gjs/console.cpp b/gjs/console.cpp
index d25d890..85d6161 100644
--- a/gjs/console.cpp
+++ b/gjs/console.cpp
@@ -143,8 +143,7 @@ main(int argc, char **argv)
         if (!coverage_output_path)
             g_error("--coverage-output-path is required when taking coverage statistics");
 
-        coverage = gjs_coverage_new(gjs_context_get_debug_hooks(js_context),
-                                    (const gchar **) coverage_paths);
+        coverage = gjs_coverage_new(js_context, (const gchar **) coverage_paths);
     }
 
     /* prepare command line arguments */
diff --git a/gjs/coverage.cpp b/gjs/coverage.cpp
index ad4eacf..6ef4cbf 100644
--- a/gjs/coverage.cpp
+++ b/gjs/coverage.cpp
@@ -31,23 +31,10 @@
 typedef struct _GjsCoverageBranchData GjsCoverageBranchData;
 
 struct _GjsCoveragePrivate {
+    GjsContext    *context;
     GHashTable    *file_statistics;
-    GjsDebugHooks *debug_hooks;
     gchar         **covered_paths;
 
-    /* A separate context where reflection is performed. We don't
-     * want to use the main context because we don't want to
-     * modify its state while it is being debugged.
-     *
-     * A single context is shared across all reflections because
-     * the reflection functions are effectively const.
-     *
-     * This is created on-demand when debugging is enabled. GjsContext
-     * creates an instance of us by default so we obviously don't want
-     * to recurse into creating an instance of GjsContext by default.
-     */
-    GjsContext *reflection_context;
-
     guint         new_scripts_connection;
     guint         single_step_connection;
     guint         frame_step_connection;
@@ -68,7 +55,7 @@ G_DEFINE_TYPE_WITH_PRIVATE(GjsCoverage,
 
 enum {
     PROP_0,
-    PROP_DEBUG_HOOKS,
+    PROP_CONTEXT,
     PROP_COVERAGE_PATHS,
     PROP_N
 };
@@ -496,13 +483,10 @@ create_statistics_from_reflection(GjsReflectedScript *reflected_script)
 }
 
 static GjsCoverageFileStatistics *
-new_statistics_for_filename(GjsContext *reflection_context,
-                            const char *filename)
+new_statistics_for_filename(GjsContext *context, const char *filename)
 {
-    GjsReflectedScript *reflected_script =
-        gjs_reflected_script_new(filename, reflection_context);
-    GjsCoverageFileStatistics *stats =
-        create_statistics_from_reflection(reflected_script);
+    GjsReflectedScript *reflected_script = gjs_reflected_script_new(context, filename);
+    GjsCoverageFileStatistics *stats = create_statistics_from_reflection(reflected_script);
     g_object_unref(reflected_script);
 
     return stats;
@@ -525,7 +509,7 @@ gjs_coverage_new_script_available_hook(GjsDebugHooks      *reg,
                                                               filename);
 
         if (!statistics) {
-            statistics = new_statistics_for_filename(priv->reflection_context, filename);
+            statistics = new_statistics_for_filename(context, filename);
 
             /* If create_statistics_for_filename returns NULL then we can
              * just bail out here, the stats print function will handle
@@ -836,7 +820,7 @@ copy_source_file_to_coverage_output(const char *source,
 }
 
 typedef struct _StatisticsPrintUserData {
-    GjsContext        *reflection_context;
+    GjsContext        *context;
     GFileOutputStream *ostream;
     const gchar       *output_directory;
 } StatisticsPrintUserData;
@@ -944,8 +928,7 @@ print_statistics_for_files(gpointer key,
     /* If there is no statistics for this file, then we should
      * compile the script and print statistics for it now */
     if (!stats)
-        stats = new_statistics_for_filename(statistics_print_data->reflection_context,
-                                                             filename);
+        stats = new_statistics_for_filename(statistics_print_data->context, filename);
 
     /* Still couldn't create statistics, bail out */
     if (!stats)
@@ -1019,6 +1002,7 @@ gjs_coverage_write_statistics(GjsCoverage *coverage,
     GjsCoveragePrivate *priv = (GjsCoveragePrivate *) gjs_coverage_get_instance_private(coverage);
     GError *error = NULL;
     GFileOutputStream *ostream = NULL;
+    GjsDebugHooks *hooks = gjs_context_get_debug_hooks(priv->context);
 
     /* Create output_directory if it doesn't exist */
     g_mkdir_with_parents(output_directory, 0755);
@@ -1031,7 +1015,7 @@ gjs_coverage_write_statistics(GjsCoverage *coverage,
 
     /* Remove our new script hook so that we don't get spurious calls
      * to it whilst compiling new scripts */
-    gjs_debug_hooks_remove_script_load_hook(priv->debug_hooks, priv->new_scripts_connection);
+    gjs_debug_hooks_remove_script_load_hook(hooks, priv->new_scripts_connection);
     priv->new_scripts_connection = 0;
 
     ostream = g_file_append_to(output_file,
@@ -1052,7 +1036,7 @@ gjs_coverage_write_statistics(GjsCoverage *coverage,
      * case just fine, so there's no need to return if
      * output_file is NULL */
     StatisticsPrintUserData data = {
-        priv->reflection_context,
+        priv->context,
         ostream,
         output_directory
     };
@@ -1065,10 +1049,9 @@ gjs_coverage_write_statistics(GjsCoverage *coverage,
     g_object_unref(output_file);
 
     /* Re-insert our new script hook in case we need it again */
-    priv->new_scripts_connection =
-        gjs_debug_hooks_add_script_load_hook(priv->debug_hooks,
-                                             gjs_coverage_new_script_available_hook,
-                                             coverage);
+    priv->new_scripts_connection = gjs_debug_hooks_add_script_load_hook(hooks,
+                                                                        
gjs_coverage_new_script_available_hook,
+                                                                        coverage);
 }
 
 static void
@@ -1083,7 +1066,6 @@ gjs_coverage_init(GjsCoverage *self)
 {
     GjsCoveragePrivate *priv = (GjsCoveragePrivate *) gjs_coverage_get_instance_private(self);
 
-    priv->reflection_context =  gjs_reflected_script_create_reflection_context();
     priv->file_statistics = g_hash_table_new_full(g_str_hash,
                                                   g_str_equal,
                                                   g_free,
@@ -1098,6 +1080,7 @@ gjs_coverage_constructed(GObject *object)
 
     GjsCoverage *coverage = GJS_DEBUG_COVERAGE(object);
     GjsCoveragePrivate *priv = (GjsCoveragePrivate *) gjs_coverage_get_instance_private(coverage);
+    GjsDebugHooks *hooks = gjs_context_get_debug_hooks(priv->context);
 
     /* Take the list of covered paths and add them to the coverage report */
     if (priv->covered_paths) {
@@ -1116,20 +1099,17 @@ gjs_coverage_constructed(GObject *object)
     }
 
     /* Add hook for new scripts and singlestep execution */
-    priv->new_scripts_connection =
-        gjs_debug_hooks_add_script_load_hook(priv->debug_hooks,
-                                             gjs_coverage_new_script_available_hook,
-                                             coverage);
-
-    priv->single_step_connection =
-        gjs_debug_hooks_add_singlestep_hook(priv->debug_hooks,
-                                            gjs_coverage_single_step_interrupt_hook,
-                                            coverage);
-
-    priv->frame_step_connection =
-        gjs_debug_hooks_add_frame_step_hook(priv->debug_hooks,
-                                            gjs_coverage_frame_execution_hook,
-                                            priv->file_statistics);
+    priv->new_scripts_connection = gjs_debug_hooks_add_script_load_hook(hooks,
+                                                                        
gjs_coverage_new_script_available_hook,
+                                                                        coverage);
+
+    priv->single_step_connection = gjs_debug_hooks_add_singlestep_hook(hooks,
+                                                                       
gjs_coverage_single_step_interrupt_hook,
+                                                                       coverage);
+
+    priv->frame_step_connection = gjs_debug_hooks_add_frame_step_hook(hooks,
+                                                                      gjs_coverage_frame_execution_hook,
+                                                                      priv->file_statistics);
 }
 
 static void
@@ -1141,8 +1121,8 @@ gjs_coverage_set_property(GObject      *object,
     GjsCoverage *coverage = GJS_DEBUG_COVERAGE(object);
     GjsCoveragePrivate *priv = (GjsCoveragePrivate *) gjs_coverage_get_instance_private(coverage);
     switch (prop_id) {
-    case PROP_DEBUG_HOOKS:
-        priv->debug_hooks = GJS_DEBUG_HOOKS(g_value_dup_object(value));
+    case PROP_CONTEXT:
+        priv->context = GJS_CONTEXT(g_value_dup_object(value));
         break;
     case PROP_COVERAGE_PATHS:
         g_assert(priv->covered_paths == NULL);
@@ -1172,13 +1152,13 @@ gjs_coverage_dispose(GObject *object)
 {
     GjsCoverage *coverage = GJS_DEBUG_COVERAGE (object);
     GjsCoveragePrivate *priv = (GjsCoveragePrivate *) gjs_coverage_get_instance_private(coverage);
+    GjsDebugHooks *hooks = gjs_context_get_debug_hooks(priv->context);
 
-    clear_debug_handle(priv->debug_hooks, gjs_debug_hooks_remove_script_load_hook, 
&priv->new_scripts_connection);
-    clear_debug_handle(priv->debug_hooks, gjs_debug_hooks_remove_singlestep_hook, 
&priv->single_step_connection);
-    clear_debug_handle(priv->debug_hooks, gjs_debug_hooks_remove_frame_step_hook, 
&priv->frame_step_connection);
+    clear_debug_handle(hooks, gjs_debug_hooks_remove_script_load_hook, &priv->new_scripts_connection);
+    clear_debug_handle(hooks, gjs_debug_hooks_remove_singlestep_hook, &priv->single_step_connection);
+    clear_debug_handle(hooks, gjs_debug_hooks_remove_frame_step_hook, &priv->frame_step_connection);
 
-    g_clear_object(&priv->debug_hooks);
-    g_clear_object(&priv->reflection_context);
+    g_clear_object(&priv->context);
 
     G_OBJECT_CLASS(gjs_coverage_parent_class)->dispose(object);
 }
@@ -1205,37 +1185,27 @@ gjs_coverage_class_init (GjsCoverageClass *klass)
     object_class->finalize = gjs_coverage_finalize;
     object_class->set_property = gjs_coverage_set_property;
 
-    properties[PROP_DEBUG_HOOKS] = g_param_spec_object("debug-hooks",
-                                                       "Debug Hooks",
-                                                       "Debug Hooks",
-                                                       GJS_TYPE_DEBUG_HOOKS,
-                                                       (GParamFlags) (G_PARAM_CONSTRUCT_ONLY | 
G_PARAM_WRITABLE));
+    properties[PROP_CONTEXT] = g_param_spec_object("context", "", "",
+                                                   GJS_TYPE_CONTEXT,
+                                                   (GParamFlags) (G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE 
| G_PARAM_STATIC_STRINGS));
     properties[PROP_COVERAGE_PATHS] = g_param_spec_boxed("coverage-paths",
                                                          "Coverage Paths",
                                                          "Paths (and included subdirectories) of which to 
perform coverage analysis",
                                                          G_TYPE_STRV,
-                                                         (GParamFlags) (G_PARAM_CONSTRUCT_ONLY | 
G_PARAM_WRITABLE));
+                                                         (GParamFlags) (G_PARAM_CONSTRUCT_ONLY | 
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
 
     g_object_class_install_properties(object_class,
                                       PROP_N,
                                       properties);
 }
 
-/**
- * gjs_coverage_new:
- * @debug_hooks: (transfer full): A #GjsDebugHooks to register callbacks on.
- * @coverage_paths: (transfer none): A null-terminated strv of directories to generate
- * coverage_data for
- *
- * Returns: A #GjsDebugCoverage
- */
 GjsCoverage *
-gjs_coverage_new (GjsDebugHooks *debug_hooks,
-                  const char    **coverage_paths)
+gjs_coverage_new (GjsContext  *context,
+                  const char **coverage_paths)
 {
     GjsCoverage *coverage =
         GJS_DEBUG_COVERAGE(g_object_new(GJS_TYPE_DEBUG_COVERAGE,
-                                        "debug-hooks", debug_hooks,
+                                        "context", context,
                                         "coverage-paths", coverage_paths,
                                         NULL));
 
diff --git a/gjs/coverage.h b/gjs/coverage.h
index 2c872ea..a29df21 100644
--- a/gjs/coverage.h
+++ b/gjs/coverage.h
@@ -78,8 +78,8 @@ GType gjs_debug_coverage_get_type(void);
 void gjs_coverage_write_statistics(GjsCoverage *coverage,
                                    const char  *output_directory);
 
-GjsCoverage * gjs_coverage_new(GjsDebugHooks *debug_hooks,
-                               const char    **covered_directories);
+GjsCoverage * gjs_coverage_new(GjsContext  *context,
+                               const char **covered_directories);
 
 G_END_DECLS
 
diff --git a/gjs/reflected-script.cpp b/gjs/reflected-script.cpp
index fa64c3c..5f2f2d7 100644
--- a/gjs/reflected-script.cpp
+++ b/gjs/reflected-script.cpp
@@ -30,21 +30,12 @@
 #include "reflected-script-private.h"
 
 struct _GjsReflectedScriptPrivate {
-    /* External context where the reflection happens. We take
-     * a reference to it so that we can still do evaluation even
-     * if the original owner of the context goes away
-     *
-     * One important precondition is that the context needs to
-     * be "initialized" to a state that we expect it to be in,
-     * eg, we need to have loaded the infoReflect.js script
-     * and set up some global variables. If it hasn't then
-     * this will trigger an assertion */
-    GjsContext *reflection_context;
+    GjsContext *context;
 
     char *script_filename;
 
-    /* Array of strings, null-terminated */
-    GArray *all_function_names;
+    /* Array of GjsReflectedScriptFunctionInfo */
+    GArray *all_functions;
 
     /* Array of GjsReflectedScriptBranchInfo */
     GArray *all_branches;
@@ -69,7 +60,7 @@ G_DEFINE_TYPE_WITH_PRIVATE(GjsReflectedScript,
 enum {
     PROP_0,
     PROP_SCRIPT_FILENAME,
-    PROP_REFLECTION_CONTEXT,
+    PROP_CONTEXT,
     PROP_N
 };
 
@@ -77,40 +68,6 @@ static GParamSpec *properties[PROP_N];
 
 static void ensure_script_reflected(GjsReflectedScript *script);
 
-GjsReflectedScriptBranchInfo *
-gjs_reflected_script_branch_info_new(unsigned int  branch_point,
-                                     GArray       *alternatives)
-{
-    GjsReflectedScriptBranchInfo *info = g_new0(GjsReflectedScriptBranchInfo, 1);
-    info->branch_point = branch_point;
-    info->branch_alternatives = alternatives;
-    return info;
-}
-
-void
-gjs_reflected_script_branch_info_destroy(gpointer info_data)
-{
-    GjsReflectedScriptBranchInfo *info = (GjsReflectedScriptBranchInfo *) info_data;
-    g_array_free(info->branch_alternatives, TRUE);
-    g_free(info);
-}
-
-unsigned int
-gjs_reflected_script_branch_info_get_branch_point(const GjsReflectedScriptBranchInfo *info)
-{
-    return info->branch_point;
-}
-
-const unsigned int *
-gjs_reflected_script_branch_info_get_branch_alternatives(const GjsReflectedScriptBranchInfo *info,
-                                                         unsigned int                       *n)
-{
-    g_return_val_if_fail(n, NULL);
-
-    *n = info->branch_alternatives->len;
-    return (unsigned int *) info->branch_alternatives->data;
-}
-
 GjsReflectedScriptFunctionInfo *
 gjs_reflected_script_function_info_new(char         *name,
                                        unsigned int  line_number,
@@ -146,16 +103,47 @@ void
 gjs_reflected_script_function_info_destroy(gpointer info_data)
 {
     GjsReflectedScriptFunctionInfo *info = (GjsReflectedScriptFunctionInfo *) info_data;
+    g_free(info->name);
+    g_free(info);
+}
 
-    if (info->name)
-        g_free(info->name);
 
+GjsReflectedScriptBranchInfo *
+gjs_reflected_script_branch_info_new(unsigned int  branch_point,
+                                     GArray       *alternatives)
+{
+    GjsReflectedScriptBranchInfo *info = g_new0(GjsReflectedScriptBranchInfo, 1);
+    info->branch_point = branch_point;
+    info->branch_alternatives = alternatives;
+    return info;
+}
+
+void
+gjs_reflected_script_branch_info_destroy(gpointer info_data)
+{
+    GjsReflectedScriptBranchInfo *info = (GjsReflectedScriptBranchInfo *) info_data;
+    g_array_free(info->branch_alternatives, TRUE);
     g_free(info);
 }
 
+unsigned int
+gjs_reflected_script_branch_info_get_branch_point(const GjsReflectedScriptBranchInfo *info)
+{
+    return info->branch_point;
+}
+
+const unsigned int *
+gjs_reflected_script_branch_info_get_branch_alternatives(const GjsReflectedScriptBranchInfo *info,
+                                                         unsigned int                       *n)
+{
+    g_return_val_if_fail(n, NULL);
 
-const GjsReflectedScriptBranchInfo **
-gjs_reflected_script_get_branches(GjsReflectedScript *script)
+    *n = info->branch_alternatives->len;
+    return (unsigned int *) info->branch_alternatives->data;
+}
+
+const GjsReflectedScriptFunctionInfo **
+gjs_reflected_script_get_functions(GjsReflectedScript *script)
 {
     g_return_val_if_fail(script, NULL);
 
@@ -163,12 +151,12 @@ gjs_reflected_script_get_branches(GjsReflectedScript *script)
 
     ensure_script_reflected(script);
 
-    g_assert(priv->all_branches);
-    return (const GjsReflectedScriptBranchInfo **) priv->all_branches->data;\
+    g_assert(priv->all_functions);
+    return (const GjsReflectedScriptFunctionInfo **) priv->all_functions->data;
 }
 
-const GjsReflectedScriptFunctionInfo **
-gjs_reflected_script_get_functions(GjsReflectedScript *script)
+const GjsReflectedScriptBranchInfo **
+gjs_reflected_script_get_branches(GjsReflectedScript *script)
 {
     g_return_val_if_fail(script, NULL);
 
@@ -176,8 +164,8 @@ gjs_reflected_script_get_functions(GjsReflectedScript *script)
 
     ensure_script_reflected(script);
 
-    g_assert(priv->all_function_names);
-    return (const GjsReflectedScriptFunctionInfo **) priv->all_function_names->data;
+    g_assert(priv->all_branches);
+    return (const GjsReflectedScriptBranchInfo **) priv->all_branches->data;\
 }
 
 const unsigned int *
@@ -206,8 +194,8 @@ static gboolean
 get_array_from_js_value(JSContext             *context,
                         jsval                 *value,
                         size_t                 array_element_size,
-                        GDestroyNotify         element_clear_func,
                         ConvertAndInsertJSVal  inserter,
+                        GDestroyNotify         element_clear_func,
                         GArray                **out_array)
 {
     g_return_val_if_fail(out_array != NULL, FALSE);
@@ -254,33 +242,19 @@ get_array_from_js_value(JSContext             *context,
     return TRUE;
 }
 
-static GArray *
-call_js_function_for_array_return(JSContext             *context,
-                                  JSObject              *object,
-                                  size_t                 array_element_size,
-                                  GDestroyNotify         element_clear_func,
-                                  ConvertAndInsertJSVal  inserter,
-                                  const char            *function_name,
-                                  jsval                 *ast)
+static gboolean
+convert_and_insert_unsigned_int(GArray    *array,
+                                JSContext *context,
+                                jsval     *element)
 {
-    GArray *array = NULL;
-    jsval rval;
-    if (!JS_CallFunctionName(context, object, function_name, 1, ast, &rval)) {
-        gjs_log_exception(context);
-        return NULL;
-    }
-
-    if (!get_array_from_js_value(context,
-                                 &rval,
-                                 array_element_size,
-                                 element_clear_func,
-                                 inserter,
-                                 &array)) {
-        gjs_log_exception(context);
-        return NULL;
+    if (!JSVAL_IS_INT(*element)) {
+        g_critical("Array element is not an integer");
+        return FALSE;
     }
 
-    return array;
+    unsigned int element_integer = JSVAL_TO_INT(*element);
+    g_array_append_val(array, element_integer);
+    return TRUE;
 }
 
 static void
@@ -292,7 +266,7 @@ clear_reflected_script_function_info(gpointer info_location)
 }
 
 static gboolean
-convert_and_insert_function_decl(GArray    *array,
+convert_and_insert_function_info(GArray    *array,
                                  JSContext *context,
                                  jsval     *element)
 {
@@ -355,65 +329,8 @@ convert_and_insert_function_decl(GArray    *array,
     return TRUE;
 }
 
-static GArray *
-get_script_functions_from_reflection(JSContext *context,
-                                     JSObject  *global,
-                                     jsval     *ast)
-{
-    return call_js_function_for_array_return(context,
-                                             global,
-                                             sizeof(GjsReflectedScriptFunctionInfo *),
-                                             clear_reflected_script_function_info,
-                                             convert_and_insert_function_decl,
-                                             "functionsForAST",
-                                             ast);
-}
-
-static gboolean
-convert_and_insert_unsigned_int(GArray    *array,
-                                JSContext *context,
-                                jsval     *element)
-{
-    if (!JSVAL_IS_INT(*element)) {
-        g_critical("Array element is not an integer");
-        return FALSE;
-    }
-
-    unsigned int element_integer = JSVAL_TO_INT(*element);
-    g_array_append_val(array, element_integer);
-    return TRUE;
-}
-
-static int
-uint_compare(gconstpointer left,
-             gconstpointer right)
-{
-    unsigned int *left_int = (unsigned int *) left;
-    unsigned int *right_int = (unsigned int *) right;
-
-    return *left_int - *right_int;
-}
-
-static GArray *
-get_all_lines_with_executable_expressions_from_reflection(JSContext *context,
-                                                          JSObject  *global,
-                                                          jsval     *ast)
-{
-    GArray *all_expressions = call_js_function_for_array_return(context,
-                                                                global,
-                                                                sizeof(unsigned int),
-                                                                NULL,
-                                                                convert_and_insert_unsigned_int,
-                                                                "expressionLinesForAST",
-                                                                ast);
-
-    /* Sort, just to be sure */
-    g_array_sort(all_expressions, uint_compare);
-    return all_expressions;
-}
-
 static void
-gjs_reflected_script_branch_info_clear(gpointer branch_info_location)
+clear_reflected_script_branch_info(gpointer branch_info_location)
 {
     GjsReflectedScriptBranchInfo **info_ptr = (GjsReflectedScriptBranchInfo **) branch_info_location;
     gjs_reflected_script_branch_info_destroy(*info_ptr);
@@ -456,12 +373,8 @@ convert_and_insert_branch_info(GArray    *array,
         return FALSE;
     }
 
-    if (!get_array_from_js_value(context,
-                                 &branch_exits_value,
-                                 sizeof(unsigned int),
-                                 NULL,
-                                 convert_and_insert_unsigned_int,
-                                 &branch_exists_array)) {
+    if (!get_array_from_js_value(context, &branch_exits_value, sizeof(unsigned int),
+                                 convert_and_insert_unsigned_int, NULL, &branch_exists_array)) {
         /* Already logged the exception, no need to do anything here */
         return FALSE;
     }
@@ -474,20 +387,6 @@ convert_and_insert_branch_info(GArray    *array,
     return TRUE;
 }
 
-static GArray *
-get_script_branches_from_reflection(JSContext *context,
-                                    JSObject  *global,
-                                    jsval     *ast)
-{
-    return call_js_function_for_array_return(context,
-                                             global,
-                                             sizeof(GjsReflectedScriptBranchInfo *),
-                                             gjs_reflected_script_branch_info_clear,
-                                             convert_and_insert_branch_info,
-                                             "branchesForAST",
-                                             ast);
-}
-
 static unsigned int
 count_lines_in_script(const char *data)
 {
@@ -545,14 +444,13 @@ load_script_for_reflection(GjsContext   *context,
 }
 
 static gboolean
-perform_reflection_within_compartment(GjsContext         *internal_context,
-                                      GjsReflectedScript *script)
+perform_reflection(GjsContext         *internal_context,
+                   GjsReflectedScript *script)
 {
     GjsReflectedScriptPrivate *priv = (GjsReflectedScriptPrivate *) 
gjs_reflected_script_get_instance_private(script);
-    JSContext *js_context = (JSContext *) gjs_context_get_native_context(internal_context);
-    JSObject *global = JS_GetGlobalObject(js_context);
-
-    JSAutoCompartment ac(js_context, global);
+    JSContext *context = (JSContext *) gjs_context_get_native_context(internal_context);
+    JSObject *global = JS_GetGlobalObject(context);
+    JSAutoCompartment ac(context, global);
 
     int          start_line_number = 1;
     unsigned int script_n_lines;
@@ -565,42 +463,47 @@ perform_reflection_within_compartment(GjsContext         *internal_context,
     if (!str)
         return FALSE;
 
-    jsval reflect_object_value;
-    if (!JS_GetProperty(js_context, global, "Reflect", &reflect_object_value) ||
-        !JSVAL_IS_OBJECT(reflect_object_value)) {
-        gjs_throw(js_context, "'Reflect' object not found in context");
+    jsval reflectScript;
+    if (!gjs_eval_with_scope(context, NULL,
+                             "imports.infoReflect.reflectScript", -1,
+                             "<reflect>", &reflectScript))
+        return FALSE;
+
+    jsval reflectScriptArgs[] = {
+        STRING_TO_JSVAL(str),
+        INT_TO_JSVAL(start_line_number),
+    };
+    jsval reflectScriptRetval;
+    if (!JS_CallFunctionValue(context, NULL, reflectScript,
+                              G_N_ELEMENTS(reflectScriptArgs), reflectScriptArgs,
+                              &reflectScriptRetval))
         return FALSE;
-    }
 
-    JSObject *reflect_object = JSVAL_TO_OBJECT(reflect_object_value);
-    JSObject *reflect_options_object = JS_NewObject(js_context, NULL, NULL, NULL);
+    g_assert(reflectScriptRetval.isObject());
 
-    jsval loc_value = BOOLEAN_TO_JSVAL(JS_TRUE);
-    jsval line_value = INT_TO_JSVAL(start_line_number);
+    JSObject *reflectScriptObj = &reflectScriptRetval.toObject();
 
-    JS_SetProperty(js_context, reflect_options_object, "loc", &loc_value);
-    JS_SetProperty(js_context, reflect_options_object, "line", &line_value);
+    jsval functions;
+    if (!JS_GetProperty(context, reflectScriptObj, "functions", &functions))
+        return FALSE;
+    if (!get_array_from_js_value(context, &functions, sizeof(GjsReflectedScriptFunctionInfo *),
+                                 convert_and_insert_function_info, clear_reflected_script_function_info, 
&priv->all_functions))
+        return FALSE;
 
-    jsval parseArgv[] = {
-        STRING_TO_JSVAL(str),
-        OBJECT_TO_JSVAL(reflect_options_object)
-    };
-    jsval ast_value;
+    jsval branches;
+    if (!JS_GetProperty(context, reflectScriptObj, "branches", &branches))
+        return FALSE;
+    if (!get_array_from_js_value(context, &branches, sizeof(GjsReflectedScriptBranchInfo *),
+                                 convert_and_insert_branch_info, clear_reflected_script_branch_info, 
&priv->all_branches))
+        return FALSE;
 
-    if (!JS_CallFunctionName(js_context, reflect_object, "parse", 2, parseArgv, &ast_value)) {
-        gjs_throw(js_context, "Failed to call Reflect.parse");
+    jsval expressionLines;
+    if (!JS_GetProperty(context, reflectScriptObj, "expressionLines", &expressionLines))
+        return FALSE;
+    if (!get_array_from_js_value(context, &expressionLines, sizeof(unsigned int),
+                                 convert_and_insert_unsigned_int, NULL, &priv->all_expression_lines))
         return FALSE;
-    }
 
-    priv->all_function_names = get_script_functions_from_reflection(js_context,
-                                                                    global,
-                                                                    &ast_value);
-    priv->all_branches = get_script_branches_from_reflection(js_context,
-                                                             global,
-                                                             &ast_value);
-    priv->all_expression_lines = get_all_lines_with_executable_expressions_from_reflection(js_context,
-                                                                                           global,
-                                                                                           &ast_value);
     priv->n_lines = script_n_lines;
 
     return TRUE;
@@ -614,12 +517,12 @@ ensure_script_reflected(GjsReflectedScript *script)
     if (priv->reflection_performed)
         return;
 
-    if (!perform_reflection_within_compartment(priv->reflection_context, script)) {
+    if (!perform_reflection(priv->context, script)) {
         g_warning("Reflecting script %s failed", priv->script_filename);
         /* If the reflection failed, we should make sure that the the reflection
          * details have sane defaults */
+        priv->all_functions = g_array_new(TRUE, TRUE, sizeof(GjsReflectedScriptFunctionInfo));
         priv->all_branches = g_array_new(TRUE, TRUE, sizeof(GjsReflectedScriptBranchInfo));
-        priv->all_function_names = g_array_new(TRUE, TRUE, sizeof(GjsReflectedScriptFunctionInfo));
         priv->all_expression_lines = g_array_new(TRUE, TRUE, sizeof(unsigned int));
         priv->n_lines = 0;
     }
@@ -627,26 +530,6 @@ ensure_script_reflected(GjsReflectedScript *script)
     priv->reflection_performed = TRUE;
 }
 
-GjsContext *
-gjs_reflected_script_create_reflection_context()
-{
-    static const char *resource_path = "resource:///org/gnome/gjs/modules/infoReflect.js";
-
-    GjsContext *context = gjs_context_new();
-
-    if (!gjs_context_eval_file(context,
-                               resource_path,
-                               NULL,
-                               NULL)) {
-        g_object_unref(context);
-        return NULL;
-    }
-
-    gjs_context_pop();
-
-    return context;
-}
-
 unsigned int
 gjs_reflected_script_get_n_lines(GjsReflectedScript *script)
 {
@@ -664,8 +547,8 @@ gjs_reflected_script_init(GjsReflectedScript *script)
 {
     GjsReflectedScriptPrivate *priv = (GjsReflectedScriptPrivate *) 
gjs_reflected_script_get_instance_private(script);
 
+    priv->all_functions = NULL;
     priv->all_branches = NULL;
-    priv->all_function_names = NULL;
     priv->all_expression_lines = NULL;
 }
 
@@ -682,7 +565,7 @@ gjs_reflected_script_dispose(GObject *object)
     GjsReflectedScript *script = GJS_REFLECTED_SCRIPT(object);
     GjsReflectedScriptPrivate *priv = (GjsReflectedScriptPrivate *) 
gjs_reflected_script_get_instance_private(script);
 
-    g_clear_object(&priv->reflection_context);
+    g_clear_object(&priv->context);
 
     G_OBJECT_CLASS(gjs_reflected_script_parent_class)->dispose(object);
 }
@@ -693,8 +576,8 @@ gjs_reflected_script_finalize(GObject *object)
     GjsReflectedScript *script = GJS_REFLECTED_SCRIPT(object);
     GjsReflectedScriptPrivate *priv = (GjsReflectedScriptPrivate *) 
gjs_reflected_script_get_instance_private(script);
 
+    unref_array_if_nonnull(priv->all_functions);
     unref_array_if_nonnull(priv->all_branches);
-    unref_array_if_nonnull(priv->all_function_names);
     unref_array_if_nonnull(priv->all_expression_lines);
 
     g_free(priv->script_filename);
@@ -715,8 +598,8 @@ gjs_reflected_script_set_property(GObject      *object,
     case PROP_SCRIPT_FILENAME:
         priv->script_filename = g_value_dup_string(value);
         break;
-    case PROP_REFLECTION_CONTEXT:
-        priv->reflection_context = (GjsContext *) g_value_dup_object(value);
+    case PROP_CONTEXT:
+        priv->context = (GjsContext *) g_value_dup_object(value);
         break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -737,26 +620,23 @@ gjs_reflected_script_class_init(GjsReflectedScriptClass *klass)
                                                            "Script Filename",
                                                            "Valid path to script",
                                                            NULL,
-                                                           (GParamFlags) (G_PARAM_CONSTRUCT_ONLY | 
G_PARAM_WRITABLE));
-    properties[PROP_REFLECTION_CONTEXT] = g_param_spec_object("reflection-context",
-                                                              "Reflection Context",
-                                                              "Context to perform reflection in. "
-                                                              "This must have been initialized with 
infoReflect.js loaded ",
-                                                              GJS_TYPE_CONTEXT,
-                                                              (GParamFlags) (G_PARAM_CONSTRUCT_ONLY | 
G_PARAM_WRITABLE));
+                                                           (GParamFlags) (G_PARAM_CONSTRUCT_ONLY | 
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+    properties[PROP_CONTEXT] = g_param_spec_object("context", "", "",
+                                                   GJS_TYPE_CONTEXT,
+                                                   (GParamFlags) (G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE 
| G_PARAM_STATIC_STRINGS));
     g_object_class_install_properties(object_class,
                                       PROP_N,
                                       properties);
 }
 
 GjsReflectedScript *
-gjs_reflected_script_new(const char *filename,
-                         GjsContext *reflection_context)
+gjs_reflected_script_new(GjsContext *context,
+                         const char *filename)
 {
     GjsReflectedScript *script =
         GJS_REFLECTED_SCRIPT(g_object_new(GJS_TYPE_REFLECTED_SCRIPT,
+                                          "context", context,
                                           "filename", filename,
-                                          "reflection-context", reflection_context,
                                           NULL));
     return script;
 }
diff --git a/gjs/reflected-script.h b/gjs/reflected-script.h
index 9e2ea17..2eeaa13 100644
--- a/gjs/reflected-script.h
+++ b/gjs/reflected-script.h
@@ -79,14 +79,8 @@ unsigned int gjs_reflected_script_get_n_lines(GjsReflectedScript *script);
 
 GType gjs_reflected_script_get_type(void);
 
-GjsReflectedScript * gjs_reflected_script_new(const char *filename,
-                                              GjsContext *reflection_context);
-
-/* Creates a "reflection context" that can be passed to the constructor of
- * gjs_reflected_script_new. This context will have the script
- * containing the functions which permit reflection pre-defined and can
- * be shared across all reflections */
-GjsContext * gjs_reflected_script_create_reflection_context();
+GjsReflectedScript * gjs_reflected_script_new(GjsContext *context,
+                                              const char *filename);
 
 G_END_DECLS
 
diff --git a/installed-tests/gjs-unit.cpp b/installed-tests/gjs-unit.cpp
index ad7b415..27e1e22 100644
--- a/installed-tests/gjs-unit.cpp
+++ b/installed-tests/gjs-unit.cpp
@@ -76,8 +76,7 @@ setup(GjsTestJSFixture *fix,
             g_error("GJS_UNIT_COVERAGE_OUTPUT is required when using GJS_UNIT_COVERAGE_PATHS");
         }
 
-        fix->coverage = gjs_coverage_new(gjs_context_get_debug_hooks(fix->context),
-                                         (const char **) data->coverage_paths);
+        fix->coverage = gjs_coverage_new(fix->context, (const char **) data->coverage_paths);
     }
 }
 
diff --git a/modules/infoReflect.js b/modules/infoReflect.js
index b1d5cab..ddd8320 100644
--- a/modules/infoReflect.js
+++ b/modules/infoReflect.js
@@ -333,6 +333,17 @@ function deduplicate(list) {
 function expressionLinesForAST(ast) {
     let allExpressions = collectForSubNodes(ast.body, expressionLinesForNode);
     allExpressions = deduplicate(allExpressions);
-
+    allExpressions = allExpressions.sort(function(a, b) {
+        return a - b;
+    });
     return allExpressions;
 }
+
+function reflectScript(script, startLine) {
+    let ast = Reflect.parse(script, { line: startLine, loc: true });
+    return {
+        functions: functionsForAST(ast),
+        branches: branchesForAST(ast),
+        expressionLines: expressionLinesForAST(ast),
+    };
+}
diff --git a/test/gjs-test-coverage.cpp b/test/gjs-test-coverage.cpp
index 465ac4e..aec1656 100644
--- a/test/gjs-test-coverage.cpp
+++ b/test/gjs-test-coverage.cpp
@@ -31,14 +31,11 @@
 #include <glib.h>
 #include <gio/gio.h>
 #include <gjs/gjs.h>
-#include <gjs/debug-hooks.h>
-#include <gjs/debug-hooks-private.h>
 #include <gjs/reflected-script-private.h>
 #include <gjs/coverage.h>
 
 typedef struct _GjsCoverageFixture {
     GjsContext    *context;
-    GjsDebugHooks *debug_hooks;
     GjsCoverage   *coverage;
     char          *temporary_js_script_directory_name;
     char          *temporary_js_script_filename;
@@ -125,9 +122,7 @@ gjs_coverage_fixture_set_up(gpointer      fixture_data,
     };
 
     fixture->context = gjs_context_new_with_search_path((char **) search_paths);
-    fixture->debug_hooks = gjs_debug_hooks_new (fixture->context);
-    fixture->coverage = gjs_coverage_new(fixture->debug_hooks,
-                                         coverage_paths);
+    fixture->coverage = gjs_coverage_new(fixture->context, coverage_paths);
 
     write_to_file(fixture->temporary_js_script_open_handle, js_script);
 }
@@ -144,7 +139,6 @@ gjs_coverage_fixture_tear_down(gpointer      fixture_data,
     g_free(fixture->temporary_js_script_directory_name);
 
     g_object_unref(fixture->coverage);
-    g_object_unref(fixture->debug_hooks);
     g_object_unref(fixture->context);
 }
 
@@ -355,9 +349,7 @@ test_covered_file_is_duplicated_into_output_if_resource(gpointer      fixture_da
     };
 
     g_object_unref(fixture->base_fixture.coverage);
-    fixture->base_fixture.coverage =
-        gjs_coverage_new(fixture->base_fixture.debug_hooks,
-                         coverage_scripts);
+    fixture->base_fixture.coverage = gjs_coverage_new(fixture->base_fixture.context, coverage_scripts);
 
     gjs_context_eval_file(fixture->base_fixture.context,
                           mock_resource_filename,
@@ -1048,8 +1040,7 @@ gjs_coverage_multiple_source_files_to_single_output_fixture_set_up(gpointer fixt
     };
 
     g_object_unref(fixture->base_fixture.base_fixture.coverage);
-    fixture->base_fixture.base_fixture.coverage = 
gjs_coverage_new(fixture->base_fixture.base_fixture.debug_hooks,
-                                                                   coverage_paths);
+    fixture->base_fixture.base_fixture.coverage = 
gjs_coverage_new(fixture->base_fixture.base_fixture.context, coverage_paths);
 
     char *base_name = g_path_get_basename(fixture->base_fixture.base_fixture.temporary_js_script_filename);
     char *base_name_without_extension = g_strndup(base_name,
diff --git a/test/gjs-test-debug-hooks.cpp b/test/gjs-test-debug-hooks.cpp
index be669c4..407c892 100644
--- a/test/gjs-test-debug-hooks.cpp
+++ b/test/gjs-test-debug-hooks.cpp
@@ -292,9 +292,7 @@ test_interrupts_are_received_on_all_executable_lines_in_single_step_mode (gpoint
     write_content_to_file_at_beginning(fixture->temporary_js_script_open_handle,
                                        mock_script);
 
-    GjsContext         *reflection_context = gjs_reflected_script_create_reflection_context();
-    GjsReflectedScript *reflected = gjs_reflected_script_new(fixture->temporary_js_script_filename,
-                                                             reflection_context);
+    GjsReflectedScript *reflected = gjs_reflected_script_new(fixture->context, 
fixture->temporary_js_script_filename);
     unsigned int       n_executable_lines = 0;
     const unsigned int *executable_lines =
         gjs_reflected_script_get_expression_lines(reflected, &n_executable_lines);
@@ -311,7 +309,6 @@ test_interrupts_are_received_on_all_executable_lines_in_single_step_mode (gpoint
     g_array_free(line_tracker, TRUE);
     gjs_debug_hooks_remove_singlestep_hook(fixture->debug_hooks, connection);
     g_object_unref(reflected);
-    g_object_unref(reflection_context);
 }
 
 static void
diff --git a/test/gjs-test-reflected-script.cpp b/test/gjs-test-reflected-script.cpp
index de3ec1e..f723f78 100644
--- a/test/gjs-test-reflected-script.cpp
+++ b/test/gjs-test-reflected-script.cpp
@@ -28,9 +28,9 @@
 #include <gjs/reflected-script.h>
 
 typedef struct _GjsReflectedScriptTestFixture {
-    char       *temporary_js_script_filename;
-    int        temporary_js_script_open_handle;
-    GjsContext *reflection_context;
+    GjsContext *context;
+    char *temporary_js_script_filename;
+    int temporary_js_script_open_handle;
 } GjsReflectedScriptTestFixture;
 
 static void
@@ -42,7 +42,7 @@ gjs_reflected_test_fixture_set_up(gpointer      fixture_data,
     fixture->temporary_js_script_open_handle = g_file_open_tmp("mock-js-XXXXXXX.js",
                                                                &fixture->temporary_js_script_filename,
                                                                NULL);
-    fixture->reflection_context = gjs_reflected_script_create_reflection_context();
+    fixture->context = gjs_context_new();
 
     g_free(current_dir);
 }
@@ -56,7 +56,7 @@ gjs_reflected_test_fixture_tear_down(gpointer      fixture_data,
     g_free(fixture->temporary_js_script_filename);
     close(fixture->temporary_js_script_open_handle);
 
-    g_object_unref(fixture->reflection_context);
+    g_object_unref(fixture->context);
 }
 
 static void
@@ -70,8 +70,7 @@ test_reflect_creation_and_destruction(gpointer      fixture_data,
     if (write(fixture->temporary_js_script_open_handle, mock_script, strlen(mock_script) * sizeof(char)) == 
-1)
         g_error("Failed to write to test script");
 
-    GjsReflectedScript *script = gjs_reflected_script_new(fixture->temporary_js_script_filename,
-                                                          fixture->reflection_context);
+    GjsReflectedScript *script = gjs_reflected_script_new(fixture->context, 
fixture->temporary_js_script_filename);
     g_object_unref(script);
 }
 
@@ -97,13 +96,12 @@ static GjsReflectedScript *
 get_reflected_script_for(const char *script,
                          int         file,
                          const char *filename,
-                         GjsContext *reflection_context)
+                         GjsContext *context)
 {
     if (write(file, script, strlen(script) * sizeof(char)) == -1)
         g_error("Failed to write to test script");
 
-    GjsReflectedScript *reflected_script =
-        gjs_reflected_script_new(filename, reflection_context);
+    GjsReflectedScript *reflected_script = gjs_reflected_script_new(context, filename);
     return reflected_script;
 }
 
@@ -121,7 +119,7 @@ test_reflect_get_all_executable_expression_lines(gpointer      fixture_data,
     GjsReflectedScript *script = get_reflected_script_for(mock_script,
                                                           fixture->temporary_js_script_open_handle,
                                                           fixture->temporary_js_script_filename,
-                                                          fixture->reflection_context);
+                                                          fixture->context);
     unsigned int       n_executable_lines = 0;
     const unsigned int *executable_lines = gjs_reflected_script_get_expression_lines(script,
                                                                                      &n_executable_lines);
@@ -206,7 +204,7 @@ test_reflect_finds_branches(gpointer      fixture_data,
     GjsReflectedScript *script = get_reflected_script_for(mock_script,
                                                           fixture->temporary_js_script_open_handle,
                                                           fixture->temporary_js_script_filename,
-                                                          fixture->reflection_context);
+                                                          fixture->context);
     const GjsReflectedScriptBranchInfo **branches =
         gjs_reflected_script_get_branches(script);
 
@@ -289,7 +287,7 @@ test_reflect_finds_functions(gpointer      fixture_data,
     GjsReflectedScript *script = get_reflected_script_for(mock_script,
                                                           fixture->temporary_js_script_open_handle,
                                                           fixture->temporary_js_script_filename,
-                                                          fixture->reflection_context);
+                                                          fixture->context);
     const GjsReflectedScriptFunctionInfo **functions =
         gjs_reflected_script_get_functions(script);
 
@@ -320,7 +318,7 @@ test_reflect_get_n_lines(gpointer      fixture_data,
     GjsReflectedScript *script = get_reflected_script_for(mock_script,
                                                           fixture->temporary_js_script_open_handle,
                                                           fixture->temporary_js_script_filename,
-                                                          fixture->reflection_context);
+                                                          fixture->context);
     unsigned int n_lines = gjs_reflected_script_get_n_lines(script);
 
     g_assert(n_lines == 4);
@@ -342,8 +340,7 @@ test_reflect_on_nonexistent_script_returns_empty(gpointer      fixture_data,
 {
     GjsReflectedScriptTestFixture *fixture =
         (GjsReflectedScriptTestFixture *) fixture_data;
-    GjsReflectedScript *script = gjs_reflected_script_new("doesnotexist://does_not_exist",
-                                                          fixture->reflection_context);
+    GjsReflectedScript *script = gjs_reflected_script_new(fixture->context, "doesnotexist://does_not_exist");
 
     /* Make the handler shut up so that we don't get an assertion on
      * raised warnings from bad scripts */



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