Commit b2f9cb75 authored by Evan Welsh's avatar Evan Welsh Committed by Philip Chimento

global: Refactor to support multiple global types.

parent ac8f921c
......@@ -601,7 +601,9 @@ lookup_override_function(JSContext *cx,
{
JS::AutoSaveExceptionState saved_exc(cx);
JS::RootedValue importer(cx, gjs_get_global_slot(cx, GJS_GLOBAL_SLOT_IMPORTS));
JS::RootedObject global(cx, gjs_get_import_global(cx));
JS::RootedValue importer(
cx, gjs_get_global_slot(global, GjsGlobalSlot::IMPORTS));
g_assert(importer.isObject());
JS::RootedObject overridespkg(cx), module(cx);
......@@ -644,8 +646,9 @@ JSObject*
gjs_lookup_namespace_object_by_name(JSContext *context,
JS::HandleId ns_name)
{
JS::RootedValue importer(context,
gjs_get_global_slot(context, GJS_GLOBAL_SLOT_IMPORTS));
JS::RootedObject global(context, gjs_get_import_global(context));
JS::RootedValue importer(
context, gjs_get_global_slot(global, GjsGlobalSlot::IMPORTS));
g_assert(importer.isObject());
JS::RootedObject repo(context), importer_obj(context, &importer.toObject());
......
......@@ -494,7 +494,9 @@ GjsContextPrivate::GjsContextPrivate(JSContext* cx, GjsContext* public_context)
m_atoms = new GjsAtoms();
JS::RootedObject global(m_cx, gjs_create_global_object(m_cx));
JS::RootedObject global(
m_cx, gjs_create_global_object(cx, GjsGlobalType::DEFAULT));
if (!global) {
gjs_log_exception(m_cx);
g_error("Failed to initialize global object");
......@@ -519,14 +521,15 @@ GjsContextPrivate::GjsContextPrivate(JSContext* cx, GjsContext* public_context)
g_error("Failed to create root importer");
}
JS::Value v_importer = gjs_get_global_slot(m_cx, GJS_GLOBAL_SLOT_IMPORTS);
JS::Value v_importer = gjs_get_global_slot(global, GjsGlobalSlot::IMPORTS);
g_assert(((void) "Someone else already created root importer",
v_importer.isUndefined()));
gjs_set_global_slot(m_cx, GJS_GLOBAL_SLOT_IMPORTS,
gjs_set_global_slot(global, GjsGlobalSlot::IMPORTS,
JS::ObjectValue(*importer));
if (!gjs_define_global_properties(m_cx, global, "GJS", "default")) {
if (!gjs_define_global_properties(m_cx, global, GjsGlobalType::DEFAULT,
"GJS", "default")) {
gjs_log_exception(m_cx);
g_error("Failed to define properties on global object");
}
......
......@@ -350,8 +350,8 @@ bootstrap_coverage(GjsCoverage *coverage)
JSContext *context = (JSContext *) gjs_context_get_native_context(priv->context);
JSObject *debuggee = gjs_get_import_global(context);
JS::RootedObject debugger_global(context,
gjs_create_global_object(context));
JS::RootedObject debugger_global(
context, gjs_create_global_object(context, GjsGlobalType::DEBUGGER));
{
JSAutoRealm ar(context, debugger_global);
JS::RootedObject debuggeeWrapper(context, debuggee);
......@@ -363,6 +363,7 @@ bootstrap_coverage(GjsCoverage *coverage)
if (!JS_SetPropertyById(context, debugger_global, atoms.debuggee(),
debuggeeWrapperValue) ||
!gjs_define_global_properties(context, debugger_global,
GjsGlobalType::DEBUGGER,
"GJS coverage", "coverage"))
return false;
......
......@@ -135,7 +135,8 @@ void gjs_context_setup_debugger_console(GjsContext* gjs) {
auto cx = static_cast<JSContext*>(gjs_context_get_native_context(gjs));
JS::RootedObject debuggee(cx, gjs_get_import_global(cx));
JS::RootedObject debugger_global(cx, gjs_create_global_object(cx));
JS::RootedObject debugger_global(
cx, gjs_create_global_object(cx, GjsGlobalType::DEBUGGER));
// Enter realm of the debugger and initialize it with the debuggee
JSAutoRealm ar(cx, debugger_global);
......@@ -149,7 +150,8 @@ void gjs_context_setup_debugger_console(GjsContext* gjs) {
JS::RootedValue v_wrapper(cx, JS::ObjectValue(*debuggee_wrapper));
if (!JS_SetPropertyById(cx, debugger_global, atoms.debuggee(), v_wrapper) ||
!JS_DefineFunctions(cx, debugger_global, debugger_funcs) ||
!gjs_define_global_properties(cx, debugger_global, "GJS debugger",
!gjs_define_global_properties(cx, debugger_global,
GjsGlobalType::DEBUGGER, "GJS debugger",
"debugger"))
gjs_log_exception(cx);
}
......@@ -3,6 +3,7 @@
* Copyright (c) 2008 litl, LLC
* Copyright (c) 2009 Red Hat, Inc.
* Copyright (c) 2017 Philip Chimento <philip.chimento@gmail.com>
* Copyright (c) 2020 Evan Welsh <contact@evanwelsh.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
......@@ -29,6 +30,8 @@
#include <glib.h>
#include <js/CallArgs.h> // for CallArgs, CallArgsFromVp
#include <js/CharacterEncoding.h> // for JS_EncodeStringToUTF8
#include <js/Class.h>
#include <js/CompilationAndEvaluation.h>
#include <js/CompileOptions.h>
......@@ -39,6 +42,7 @@
#include <js/RootingAPI.h>
#include <js/SourceText.h>
#include <js/TypeDecls.h>
#include <js/Utility.h> // for UniqueChars
#include <jsapi.h> // for AutoSaveExceptionState, ...
#include "gjs/atoms.h"
......@@ -46,50 +50,123 @@
#include "gjs/engine.h"
#include "gjs/global.h"
#include "gjs/jsapi-util.h"
#include "gjs/native.h"
namespace mozilla {
union Utf8Unit;
}
GJS_JSAPI_RETURN_CONVENTION
static bool
run_bootstrap(JSContext *cx,
const char *bootstrap_script,
JS::HandleObject global)
{
GjsAutoChar uri = g_strdup_printf(
"resource:///org/gnome/gjs/modules/script/_bootstrap/%s.js",
bootstrap_script);
JSAutoRealm ar(cx, global);
JS::CompileOptions options(cx);
options.setFileAndLine(uri, 1).setSourceIsLazy(true);
char* script;
size_t script_len;
if (!gjs_load_internal_source(cx, uri, &script, &script_len))
return false;
JS::SourceText<mozilla::Utf8Unit> source;
if (!source.init(cx, script, script_len,
JS::SourceOwnership::TakeOwnership))
return false;
JS::RootedScript compiled_script(cx, JS::Compile(cx, options, source));
if (!compiled_script)
return false;
JS::RootedValue ignored(cx);
return JS::CloneAndExecuteScript(cx, compiled_script, &ignored);
}
class GjsBaseGlobal {
static JSObject* base(JSContext* cx, const JSClass* clasp,
JS::RealmCreationOptions options) {
options.setBigIntEnabled(true);
options.setFieldsEnabled(true);
JS::RealmBehaviors behaviors;
JS::RealmOptions compartment_options(options, behaviors);
JS::RootedObject global(
cx, JS_NewGlobalObject(cx, clasp, nullptr, JS::FireOnNewGlobalHook,
compartment_options));
if (!global)
return nullptr;
JSAutoRealm ac(cx, global);
if (!JS_InitReflectParse(cx, global) ||
!JS_DefineDebuggerObject(cx, global))
return nullptr;
return global;
}
protected:
GJS_USE
static JSObject* create(JSContext* cx, const JSClass* clasp) {
JS::RealmCreationOptions creation;
creation.setNewCompartmentAndZone();
return base(cx, clasp, creation);
}
GJS_USE
static JSObject* create_with_compartment(JSContext* cx,
JS::HandleObject existing,
const JSClass* clasp) {
JS::RealmCreationOptions creation;
creation.setExistingCompartment(existing);
return base(cx, clasp, creation);
}
GJS_JSAPI_RETURN_CONVENTION
static bool run_bootstrap(JSContext* cx, const char* bootstrap_script,
JS::HandleObject global) {
GjsAutoChar uri = g_strdup_printf(
"resource:///org/gnome/gjs/modules/script/_bootstrap/%s.js",
bootstrap_script);
JSAutoRealm ar(cx, global);
JS::CompileOptions options(cx);
options.setFileAndLine(uri, 1).setSourceIsLazy(true);
char* script;
size_t script_len;
if (!gjs_load_internal_source(cx, uri, &script, &script_len))
return false;
JS::SourceText<mozilla::Utf8Unit> source;
if (!source.init(cx, script, script_len,
JS::SourceOwnership::TakeOwnership))
return false;
JS::RootedScript compiled_script(cx, JS::Compile(cx, options, source));
if (!compiled_script)
return false;
JS::RootedValue ignored(cx);
return JS::CloneAndExecuteScript(cx, compiled_script, &ignored);
}
GJS_JSAPI_RETURN_CONVENTION
static bool load_native_module(JSContext* m_cx, unsigned argc,
JS::Value* vp) {
JS::CallArgs argv = JS::CallArgsFromVp(argc, vp);
// This function should never be directly exposed to user code, so we
// can be strict.
g_assert(argc == 1);
g_assert(argv[0].isString());
JS::RootedString str(m_cx, argv[0].toString());
JS::UniqueChars id(JS_EncodeStringToUTF8(m_cx, str));
if (!id)
return false;
JS::RootedObject native_obj(m_cx);
if (!gjs_load_native_module(m_cx, id.get(), &native_obj)) {
gjs_throw(m_cx, "Failed to load native module: %s", id.get());
return false;
}
argv.rval().setObject(*native_obj);
return true;
}
};
const JSClassOps defaultclassops = JS::DefaultGlobalClassOps;
class GjsGlobal {
class GjsGlobal : GjsBaseGlobal {
static constexpr JSClass klass = {
// Jasmine depends on the class name "GjsGlobal" to detect GJS' global
// object.
"GjsGlobal",
JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(GJS_GLOBAL_SLOT_LAST),
JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(
static_cast<uint32_t>(GjsGlobalSlot::LAST)),
&defaultclassops,
};
......@@ -98,30 +175,14 @@ class GjsGlobal {
public:
GJS_USE
static JSObject *
create(JSContext *cx)
{
JS::RealmBehaviors behaviors;
JS::RealmCreationOptions creation;
creation.setFieldsEnabled(true);
creation.setBigIntEnabled(true);
JS::RealmOptions options(creation, behaviors);
JS::RootedObject global(
cx, JS_NewGlobalObject(cx, &GjsGlobal::klass, nullptr,
JS::FireOnNewGlobalHook, options));
if (!global)
return nullptr;
JSAutoRealm ar(cx, global);
if (!JS_InitReflectParse(cx, global) ||
!JS_DefineDebuggerObject(cx, global))
return nullptr;
static JSObject* create(JSContext* cx) {
return GjsBaseGlobal::create(cx, &klass);
}
return global;
GJS_USE
static JSObject* create_with_compartment(JSContext* cx,
JS::HandleObject cmp_global) {
return GjsBaseGlobal::create_with_compartment(cx, cmp_global, &klass);
}
GJS_JSAPI_RETURN_CONVENTION
......@@ -139,7 +200,8 @@ class GjsGlobal {
// const_cast is allowed here if we never free the realm data
JS::SetRealmPrivate(realm, const_cast<char*>(realm_name));
JS::Value v_importer = gjs_get_global_slot(cx, GJS_GLOBAL_SLOT_IMPORTS);
JS::Value v_importer =
gjs_get_global_slot(global, GjsGlobalSlot::IMPORTS);
g_assert(((void) "importer should be defined before passing null "
"importer to GjsGlobal::define_properties",
v_importer.isObject()));
......@@ -160,6 +222,52 @@ class GjsGlobal {
}
};
class GjsDebuggerGlobal : GjsBaseGlobal {
static constexpr JSClass klass = {
"GjsDebuggerGlobal",
JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(
static_cast<uint32_t>(GjsDebuggerGlobalSlot::LAST)),
&defaultclassops,
};
static constexpr JSFunctionSpec static_funcs[] = {
JS_FN("loadNative", &load_native_module, 1, 0), JS_FS_END};
public:
GJS_USE
static JSObject* create(JSContext* cx) {
return GjsBaseGlobal::create(cx, &klass);
}
GJS_USE
static JSObject* create_with_compartment(JSContext* cx,
JS::HandleObject cmp_global) {
return GjsBaseGlobal::create_with_compartment(cx, cmp_global, &klass);
}
static bool define_properties(JSContext* cx, JS::HandleObject global,
const char* realm_name,
const char* bootstrap_script) {
const GjsAtoms& atoms = GjsContextPrivate::atoms(cx);
if (!JS_DefinePropertyById(cx, global, atoms.window(), global,
JSPROP_READONLY | JSPROP_PERMANENT) ||
!JS_DefineFunctions(cx, global, GjsDebuggerGlobal::static_funcs))
return false;
JS::Realm* realm = JS::GetObjectRealmOrNull(global);
g_assert(realm && "Global object must be associated with a realm");
// const_cast is allowed here if we never free the realm data
JS::SetRealmPrivate(realm, const_cast<char*>(realm_name));
if (bootstrap_script) {
if (!run_bootstrap(cx, bootstrap_script, global))
return false;
}
return true;
}
};
/**
* gjs_create_global_object:
* @cx: a #JSContext
......@@ -169,10 +277,51 @@ class GjsGlobal {
* Returns: the created global object on success, nullptr otherwise, in which
* case an exception is pending on @cx
*/
JSObject *
gjs_create_global_object(JSContext *cx)
{
return GjsGlobal::create(cx);
JSObject* gjs_create_global_object(JSContext* cx, GjsGlobalType global_type,
JS::HandleObject current_global) {
if (current_global) {
switch (global_type) {
case GjsGlobalType::DEFAULT:
return GjsGlobal::create_with_compartment(cx, current_global);
case GjsGlobalType::DEBUGGER:
return GjsDebuggerGlobal::create_with_compartment(
cx, current_global);
default:
return nullptr;
}
}
switch (global_type) {
case GjsGlobalType::DEFAULT:
return GjsGlobal::create(cx);
case GjsGlobalType::DEBUGGER:
return GjsDebuggerGlobal::create(cx);
default:
return nullptr;
}
}
GjsGlobalType gjs_global_get_type(JSContext* cx) {
auto global = JS::CurrentGlobalOrNull(cx);
g_assert(global &&
"gjs_global_get_type called before a realm was entered.");
auto global_type =
gjs_get_global_slot(global, GjsBaseGlobalSlot::GLOBAL_TYPE);
g_assert(global_type.isInt32());
return static_cast<GjsGlobalType>(global_type.toInt32());
}
GjsGlobalType gjs_global_get_type(JSObject* global) {
auto global_type =
gjs_get_global_slot(global, GjsBaseGlobalSlot::GLOBAL_TYPE);
g_assert(global_type.isInt32());
return static_cast<GjsGlobalType>(global_type.toInt32());
}
/**
......@@ -202,28 +351,35 @@ gjs_create_global_object(JSContext *cx)
* pending on @cx
*/
bool gjs_define_global_properties(JSContext* cx, JS::HandleObject global,
GjsGlobalType global_type,
const char* realm_name,
const char* bootstrap_script) {
return GjsGlobal::define_properties(cx, global, realm_name,
bootstrap_script);
gjs_set_global_slot(global.get(), GjsBaseGlobalSlot::GLOBAL_TYPE,
JS::Int32Value(static_cast<uint32_t>(global_type)));
switch (global_type) {
case GjsGlobalType::DEFAULT:
return GjsGlobal::define_properties(cx, global, realm_name,
bootstrap_script);
case GjsGlobalType::DEBUGGER:
return GjsDebuggerGlobal::define_properties(cx, global, realm_name,
bootstrap_script);
default:
return true;
}
}
void
gjs_set_global_slot(JSContext *cx,
GjsGlobalSlot slot,
JS::Value value)
{
JSObject *global = gjs_get_import_global(cx);
void detail::set_global_slot(JSObject* global, uint32_t slot, JS::Value value) {
JS_SetReservedSlot(global, JSCLASS_GLOBAL_SLOT_COUNT + slot, value);
}
JS::Value
gjs_get_global_slot(JSContext *cx,
GjsGlobalSlot slot)
{
JSObject *global = gjs_get_import_global(cx);
JS::Value detail::get_global_slot(JSObject* global, uint32_t slot) {
return JS_GetReservedSlot(global, JSCLASS_GLOBAL_SLOT_COUNT + slot);
}
decltype(GjsGlobal::klass) constexpr GjsGlobal::klass;
decltype(GjsGlobal::static_funcs) constexpr GjsGlobal::static_funcs;
decltype(GjsDebuggerGlobal::klass) constexpr GjsDebuggerGlobal::klass;
decltype(
GjsDebuggerGlobal::static_funcs) constexpr GjsDebuggerGlobal::static_funcs;
/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2017 Philip Chimento <philip.chimento@gmail.com>
* Copyright (c) 2020 Evan Welsh <contact@evanwelsh.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
......@@ -26,47 +27,88 @@
#include <config.h>
#include <js/RootingAPI.h> // for Handle
#include <js/TypeDecls.h>
#include <js/Value.h>
#include <stdint.h>
#include <type_traits> // for is_same
#include "gjs/macros.h"
typedef enum {
GJS_GLOBAL_SLOT_IMPORTS,
GJS_GLOBAL_SLOT_PROTOTYPE_gtype,
GJS_GLOBAL_SLOT_PROTOTYPE_function,
GJS_GLOBAL_SLOT_PROTOTYPE_ns,
GJS_GLOBAL_SLOT_PROTOTYPE_repo,
GJS_GLOBAL_SLOT_PROTOTYPE_importer,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_context,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_gradient,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_image_surface,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_linear_gradient,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_path,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_pattern,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_pdf_surface,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_ps_surface,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_radial_gradient,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_region,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_solid_pattern,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_surface,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_surface_pattern,
GJS_GLOBAL_SLOT_PROTOTYPE_cairo_svg_surface,
GJS_GLOBAL_SLOT_LAST,
} GjsGlobalSlot;
enum class GjsGlobalType {
DEFAULT,
DEBUGGER,
};
enum class GjsBaseGlobalSlot : uint32_t {
GLOBAL_TYPE = 0,
LAST,
};
enum class GjsDebuggerGlobalSlot : uint32_t {
LAST = static_cast<uint32_t>(GjsBaseGlobalSlot::LAST),
};
enum class GjsGlobalSlot : uint32_t {
IMPORTS = static_cast<uint32_t>(GjsBaseGlobalSlot::LAST),
PROTOTYPE_gtype,
PROTOTYPE_importer,
PROTOTYPE_function,
PROTOTYPE_ns,
PROTOTYPE_repo,
PROTOTYPE_cairo_context,
PROTOTYPE_cairo_gradient,
PROTOTYPE_cairo_image_surface,
PROTOTYPE_cairo_linear_gradient,
PROTOTYPE_cairo_path,
PROTOTYPE_cairo_pattern,
PROTOTYPE_cairo_pdf_surface,
PROTOTYPE_cairo_ps_surface,
PROTOTYPE_cairo_radial_gradient,
PROTOTYPE_cairo_region,
PROTOTYPE_cairo_solid_pattern,
PROTOTYPE_cairo_surface,
PROTOTYPE_cairo_surface_pattern,
PROTOTYPE_cairo_svg_surface,
LAST,
};
GjsGlobalType gjs_global_get_type(JSContext* cx);
GjsGlobalType gjs_global_get_type(JSObject* global);
GJS_JSAPI_RETURN_CONVENTION
JSObject *gjs_create_global_object(JSContext *cx);
JSObject* gjs_create_global_object(JSContext* cx, GjsGlobalType global_type,
JS::HandleObject existing_global = nullptr);
GJS_JSAPI_RETURN_CONVENTION
bool gjs_define_global_properties(JSContext* cx, JS::HandleObject global,
GjsGlobalType global_type,
const char* realm_name,
const char* bootstrap_script);
void gjs_set_global_slot(JSContext *context,
GjsGlobalSlot slot,
JS::Value value);
namespace detail {
void set_global_slot(JSObject* global, uint32_t slot, JS::Value value);
JS::Value get_global_slot(JSObject* global, uint32_t slot);
} // namespace detail
template <typename Slot>
inline void gjs_set_global_slot(JSObject* global, Slot slot, JS::Value value) {
static_assert(std::is_same<GjsBaseGlobalSlot, Slot>::value ||
std::is_same<GjsGlobalSlot, Slot>::value ||
std::is_same<GjsDebuggerGlobalSlot, Slot>::value,
"Must use a GJS global slot enum");
detail::set_global_slot(global, static_cast<uint32_t>(slot), value);
}
JS::Value gjs_get_global_slot(JSContext* cx, GjsGlobalSlot slot);
template <typename Slot>
inline JS::Value gjs_get_global_slot(JSObject* global, Slot slot) {
static_assert(std::is_same<GjsBaseGlobalSlot, Slot>::value ||
std::is_same<GjsGlobalSlot, Slot>::value ||
std::is_same<GjsDebuggerGlobalSlot, Slot>::value,
"Must use a GJS global slot enum");
return detail::get_global_slot(global, static_cast<uint32_t>(slot));
}
#endif // GJS_GLOBAL_H_
......@@ -198,8 +198,13 @@ GJS_DEFINE_PROTO_FUNCS_WITH_PARENT(cname, no_parent)
#define _GJS_DEFINE_GET_PROTO(cname) \
GJS_USE JSObject* gjs_##cname##_get_proto(JSContext* cx) { \
JSObject* global = JS::CurrentGlobalOrNull(cx); \
g_assert(global); \
\
JSAutoRealm ar(cx, global); \
JS::RootedValue v_proto( \
cx, gjs_get_global_slot(cx, GJS_GLOBAL_SLOT_PROTOTYPE_##cname)); \
cx, \
gjs_get_global_slot(global, GjsGlobalSlot::PROTOTYPE_##cname)); \
g_assert(((void)"gjs_" #cname "_define_proto() must be called before " \
"gjs_" #cname "_get_proto()", \
!v_proto.isUndefined())); \
......@@ -213,8 +218,14 @@ GJS_DEFINE_PROTO_FUNCS_WITH_PARENT(cname, no_parent)
bool gjs_##cname##_define_proto(JSContext* cx, JS::HandleObject module, \
JS::MutableHandleObject proto) { \
/* If we've been here more than once, we already have the proto */ \
JSObject* global = JS::CurrentGlobalOrNull(cx); \
g_assert(global); \
\
JSAutoRealm ar(cx, global); \
JS::RootedValue v_proto( \
cx, gjs_get_global_slot(cx, GJS_GLOBAL_SLOT_PROTOTYPE_##cname)); \
cx, \
gjs_get_global_slot(global, GjsGlobalSlot::PROTOTYPE_##cname)); \
\
if (!v_proto.isUndefined()) { \
g_assert( \
((void)"Someone stored some weird value in a global slot", \
......@@ -226,7 +237,7 @@ GJS_DEFINE_PROTO_FUNCS_WITH_PARENT(cname, no_parent)
/* If module is not given, we are defining a global class */ \
JS::RootedObject in_obj(cx, module); \
if (!in_obj) \
in_obj = gjs_get_import_global(cx); \
in_obj = global; \
\
/* Create the class, prototype, and constructor */ \
JS::RootedObject parent_proto(cx, gjs_##parent_cname##_get_proto(cx)); \
......@@ -236,7 +247,7 @@ GJS_DEFINE_PROTO_FUNCS_WITH_PARENT(cname, no_parent)
gjs_##cname##_static_funcs)); \
if (!proto) \
return false; \
gjs_set_global_slot(cx, GJS_GLOBAL_SLOT_PROTOTYPE_##cname, \
gjs_set_global_slot(global, GjsGlobalSlot::PROTOTYPE_##cname, \
JS::ObjectValue(*proto)); \
\
/* Look up the constructor */ \
......
/* global debuggee, quit, readline, uneval */
/* global debuggee, quit, loadNative, readline, uneval */
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*-