Example #1
0
/**
 * gjs_context_scan_buffer_for_js_version:
 * @buffer: A UTF-8 string
 * @maxbytes: Maximum number of bytes to scan in buffer
 *
 * Given a buffer of JavaScript source code (in UTF-8), look for a
 * comment in it which tells us which version to enable in the
 * SpiderMonkey engine.
 *
 * The comment is inspired by the Firefox MIME type, see e.g.
 * https://developer.mozilla.org/en/JavaScript/New_in_JavaScript/1.8
 *
 * A valid comment string looks like the following, on its own line:
 * <literal>// application/javascript;version=1.8</literal>
 *
 * Returns: A string suitable for use as the GjsContext::version property.
 *   If the version is unknown or invalid, %NULL will be returned.
 */
const char *
gjs_context_scan_buffer_for_js_version (const char *buffer,
                                        gssize      maxbytes)
{
    const char *prefix = "// application/javascript;version=";
    const char *substr;
    JSVersion ver;
    char buf[20];
    gssize remaining_bytes;
    guint i;

    substr = g_strstr_len(buffer, maxbytes, prefix);
    if (!substr)
        return NULL;

    remaining_bytes = maxbytes - ((substr - buffer) + strlen (prefix));
    /* 20 should give us enough space for all the valid JS version strings; anyways
     * it's really a bug if we're close to the limit anyways. */
    if (remaining_bytes < (gssize)sizeof(buf)-1)
        return NULL;

    buf[sizeof(buf)-1] = '\0';
    strncpy(buf, substr + strlen (prefix), sizeof(buf)-1);
    for (i = 0; i < sizeof(buf)-1; i++) {
        if (buf[i] == '\n') {
            buf[i] = '\0';
            break;
        }
    }

    ver = JS_StringToVersion(buf);
    if (ver == JSVERSION_UNKNOWN)
        return NULL;
    return JS_VersionToString(ver);
}
Example #2
0
JSObject*
Core_initialize (JSContext *cx, const char* path)
{
    JS_BeginRequest(cx);
    JS_SetOptions(cx, JSOPTION_VAROBJFIX|JSOPTION_JIT|JSOPTION_XML);
    JS_SetVersion(cx, JS_StringToVersion("1.8"));

    JSObject* object = JS_NewObject(cx, &Core_class, NULL, NULL);

    if (object && JS_InitStandardClasses(cx, object)) {
        JS_DefineFunctions(cx, object, Core_methods);

        JS_EnterLocalRootScope(cx);

        // Properties
        jsval property;

        std::string rootPath = __Core_getRootPath(cx, path);
        jsval paths[] = {
            STRING_TO_JSVAL(JS_NewString(cx, JS_strdup(cx, rootPath.c_str()), rootPath.length())),
            STRING_TO_JSVAL(JS_NewString(cx, JS_strdup(cx, __LJS_LIBRARY_PATH__), strlen(__LJS_LIBRARY_PATH__)))
        };
        property = OBJECT_TO_JSVAL(JS_NewArrayObject(cx, 2, paths));
        JS_SetProperty(cx, object, "__PATH__", &property);

        property = STRING_TO_JSVAL(JS_NewString(cx, JS_strdup(cx, __LJS_VERSION__), strlen(__LJS_VERSION__)));
        JS_SetProperty(cx, object, "__VERSION__", &property);

        property = OBJECT_TO_JSVAL(object);
        JS_SetProperty(cx, object, "Program", &property);

        JS_LeaveLocalRootScope(cx);
        JS_EndRequest(cx);

        if (__Core_include(cx, __LJS_LIBRARY_PATH__ "/Core")) {
            return object;
        }
    }

    return NULL;
}
Example #3
0
static GObject*
gjs_context_constructor (GType                  type,
                         guint                  n_construct_properties,
                         GObjectConstructParam *construct_params)
{
    GObject *object;
    GjsContext *js_context;
    guint32 options_flags;
    JSVersion js_version;

    object = (* G_OBJECT_CLASS (gjs_context_parent_class)->constructor) (type,
                                                                         n_construct_properties,
                                                                         construct_params);

    js_context = GJS_CONTEXT(object);

    if (js_context->runtime == NULL) {
        js_context->runtime = JS_NewRuntime(32*1024*1024 /* max bytes */);
        if (js_context->runtime == NULL)
            gjs_fatal("Failed to create javascript runtime");
        JS_SetGCParameter(js_context->runtime, JSGC_MAX_BYTES, 0xffffffff);
        js_context->we_own_runtime = TRUE;
        gjs_runtime_init(js_context->runtime);
    }

    js_context->context = JS_NewContext(js_context->runtime, 8192 /* stack chunk size */);
    if (js_context->context == NULL)
        gjs_fatal("Failed to create javascript context");

    JS_BeginRequest(js_context->context);

    /* same as firefox, see discussion at
     * https://bugzilla.mozilla.org/show_bug.cgi?id=420869 */
    JS_SetScriptStackQuota(js_context->context, 100*1024*1024);

    /* JSOPTION_DONT_REPORT_UNCAUGHT: Don't send exceptions to our
     * error report handler; instead leave them set.  This allows us
     * to get at the exception object.
     *
     * JSOPTION_STRICT: Report warnings to error reporter function.
     */
    options_flags = JSOPTION_DONT_REPORT_UNCAUGHT | JSOPTION_STRICT;

    if (!g_getenv("GJS_DISABLE_JIT")) {
        gjs_debug(GJS_DEBUG_CONTEXT, "Enabling JIT");
        options_flags |= JSOPTION_METHODJIT;
    }

    JS_SetOptions(js_context->context,
                  JS_GetOptions(js_context->context) | options_flags);

    JS_SetLocaleCallbacks(js_context->context, &gjs_locale_callbacks);

    JS_SetErrorReporter(js_context->context, gjs_error_reporter);

    /* set ourselves as the private data */
    JS_SetContextPrivate(js_context->context, js_context);

    js_version = JS_StringToVersion(js_context->jsversion_string);
    /* It doesn't make sense to throw here; just use the default if we
     * don't know.
     */
    if (js_version == JSVERSION_UNKNOWN)
        js_version = JSVERSION_DEFAULT;
    /* Set the version if we need to. */
    if (js_version != JSVERSION_DEFAULT && JS_GetVersion(js_context->context) != js_version) {
        gjs_debug(GJS_DEBUG_CONTEXT,
                  "Changing JavaScript version to %s from %s",
                  JS_VersionToString(js_version),
                  JS_VersionToString(JS_GetVersion(js_context->context)));

        JS_SetVersion(js_context->context, js_version);
    }

    if (!gjs_init_context_standard(js_context->context))
        gjs_fatal("Failed to initialize context");
    js_context->global = JS_GetGlobalObject(js_context->context);

    if (!JS_DefineProperty(js_context->context, js_context->global,
                           "window", OBJECT_TO_JSVAL(js_context->global),
                           NULL, NULL,
                           JSPROP_READONLY | JSPROP_PERMANENT))
        gjs_fatal("No memory to export global object as 'window'");

    /* Define a global function called log() */
    if (!JS_DefineFunction(js_context->context, js_context->global,
                           "log",
                           (JSNative)gjs_log,
                           1, GJS_MODULE_PROP_FLAGS))
        gjs_fatal("Failed to define log function");

    if (!JS_DefineFunction(js_context->context, js_context->global,
                           "logError",
                           (JSNative)gjs_log_error,
                           2, GJS_MODULE_PROP_FLAGS))
        gjs_fatal("Failed to define logError function");

    /* Define global functions called print() and printerr() */
    if (!JS_DefineFunction(js_context->context, js_context->global,
                           "print",
                           (JSNative)gjs_print,
                           3, GJS_MODULE_PROP_FLAGS))
        gjs_fatal("Failed to define print function");
    if (!JS_DefineFunction(js_context->context, js_context->global,
                           "printerr",
                           (JSNative)gjs_printerr,
                           4, GJS_MODULE_PROP_FLAGS))
        gjs_fatal("Failed to define printerr function");

    /* We need to know what the default context is, since it's the context whose
     * global object is used to load imported JS modules. We currently say that
     * it's the context of the runtime's owner, but if we needed to support
     * externally created runtimes, we could define it in some other fashion.
     */
    if (js_context->we_own_runtime) {
        gjs_runtime_set_default_context(js_context->runtime, js_context->context);
    } else {
        if (gjs_runtime_get_default_context(js_context->runtime) == NULL)
            gjs_fatal("GjsContext created for a runtime not owned by GJS");
    }

    /* We create the global-to-runtime root importer with the
     * passed-in search path. If someone else already created
     * the root importer, this is a no-op.
     */
    if (!gjs_create_root_importer(js_context->context,
                                  js_context->search_path ?
                                  (const char**) js_context->search_path :
                                  NULL,
                                  TRUE))
        gjs_fatal("Failed to create root importer");

    /* Now copy the global root importer (which we just created,
     * if it didn't exist) to our global object
     */
    if (!gjs_define_root_importer(js_context->context,
                                  js_context->global,
                                  "imports"))
        gjs_fatal("Failed to point 'imports' property at root importer");

    if (js_context->we_own_runtime) {
        js_context->profiler = gjs_profiler_new(js_context->runtime);
    }

    if (!gjs_is_registered_native_module(js_context->context, NULL, "gi"))
        gjs_register_native_module("gi", gjs_define_gi_stuff, GJS_NATIVE_SUPPLIES_MODULE_OBJ);

    /* For GjsDBus */
    {
        char *priv_typelib_dir = g_build_filename (PKGLIBDIR, "girepository-1.0", NULL);
        g_irepository_prepend_search_path(priv_typelib_dir);
        g_free (priv_typelib_dir);
    }

    if (js_context->gc_notifications_enabled)
        JS_SetGCCallback(js_context->context, gjs_on_context_gc);

    JS_EndRequest(js_context->context);

    g_static_mutex_lock (&contexts_lock);
    all_contexts = g_list_prepend(all_contexts, object);
    g_static_mutex_unlock (&contexts_lock);

    return object;
}