Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "mozilla/dom/SimpleGlobalObject.h"
8 :
9 : #include "jsapi.h"
10 : #include "js/Class.h"
11 :
12 : #include "nsJSPrincipals.h"
13 : #include "NullPrincipal.h"
14 : #include "nsThreadUtils.h"
15 : #include "nsContentUtils.h"
16 :
17 : #include "xpcprivate.h"
18 :
19 : #include "mozilla/dom/ScriptSettings.h"
20 :
21 : namespace mozilla {
22 : namespace dom {
23 :
24 : NS_IMPL_CYCLE_COLLECTION_CLASS(SimpleGlobalObject)
25 :
26 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SimpleGlobalObject)
27 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
28 0 : tmp->UnlinkHostObjectURIs();
29 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
30 :
31 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SimpleGlobalObject)
32 0 : tmp->TraverseHostObjectURIs(cb);
33 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
34 :
35 0 : NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(SimpleGlobalObject)
36 :
37 4 : NS_IMPL_CYCLE_COLLECTING_ADDREF(SimpleGlobalObject)
38 3 : NS_IMPL_CYCLE_COLLECTING_RELEASE(SimpleGlobalObject)
39 4 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SimpleGlobalObject)
40 3 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
41 3 : NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
42 1 : NS_INTERFACE_MAP_END
43 :
44 : static void
45 0 : SimpleGlobal_finalize(js::FreeOp *fop, JSObject *obj)
46 : {
47 : SimpleGlobalObject* globalObject =
48 0 : static_cast<SimpleGlobalObject*>(JS_GetPrivate(obj));
49 0 : globalObject->ClearWrapper(obj);
50 0 : NS_RELEASE(globalObject);
51 0 : }
52 :
53 : static void
54 0 : SimpleGlobal_moved(JSObject *obj, const JSObject *old)
55 : {
56 : SimpleGlobalObject* globalObject =
57 0 : static_cast<SimpleGlobalObject*>(JS_GetPrivate(obj));
58 0 : globalObject->UpdateWrapper(obj, old);
59 0 : }
60 :
61 : static const js::ClassOps SimpleGlobalClassOps = {
62 : nullptr,
63 : nullptr,
64 : nullptr,
65 : nullptr,
66 : nullptr,
67 : JS_NewEnumerateStandardClasses,
68 : JS_ResolveStandardClass,
69 : JS_MayResolveStandardClass,
70 : SimpleGlobal_finalize,
71 : nullptr,
72 : nullptr,
73 : nullptr,
74 : JS_GlobalObjectTraceHook,
75 : };
76 :
77 : static const js::ClassExtension SimpleGlobalClassExtension = {
78 : nullptr,
79 : SimpleGlobal_moved
80 : };
81 :
82 : const js::Class SimpleGlobalClass = {
83 : "",
84 : JSCLASS_GLOBAL_FLAGS |
85 : JSCLASS_HAS_PRIVATE |
86 : JSCLASS_PRIVATE_IS_NSISUPPORTS |
87 : JSCLASS_FOREGROUND_FINALIZE,
88 : &SimpleGlobalClassOps,
89 : JS_NULL_CLASS_SPEC,
90 : &SimpleGlobalClassExtension,
91 : JS_NULL_OBJECT_OPS
92 : };
93 :
94 : // static
95 : JSObject*
96 1 : SimpleGlobalObject::Create(GlobalType globalType, JS::Handle<JS::Value> proto)
97 : {
98 : // We can't root our return value with our AutoJSAPI because the rooting
99 : // analysis thinks ~AutoJSAPI can GC. So we need to root in a scope outside
100 : // the lifetime of the AutoJSAPI.
101 2 : JS::Rooted<JSObject*> global(RootingCx());
102 :
103 : { // Scope to ensure the AutoJSAPI destructor runs before we end up returning
104 2 : AutoJSAPI jsapi;
105 1 : jsapi.Init();
106 1 : JSContext* cx = jsapi.cx();
107 :
108 1 : JS::CompartmentOptions options;
109 1 : options.creationOptions()
110 1 : .setInvisibleToDebugger(true)
111 : // Put our SimpleGlobalObjects in the system zone, so we won't create
112 : // lots of zones for what are probably very short-lived
113 : // compartments. This should help them be GCed quicker and take up
114 : // less memory before they're GCed.
115 1 : .setSystemZone();
116 :
117 1 : if (NS_IsMainThread()) {
118 2 : nsCOMPtr<nsIPrincipal> principal = NullPrincipal::Create();
119 1 : options.creationOptions().setTrace(xpc::TraceXPCGlobal);
120 2 : global = xpc::CreateGlobalObject(cx, js::Jsvalify(&SimpleGlobalClass),
121 1 : nsJSPrincipals::get(principal),
122 1 : options);
123 : } else {
124 0 : global = JS_NewGlobalObject(cx, js::Jsvalify(&SimpleGlobalClass),
125 : nullptr,
126 0 : JS::DontFireOnNewGlobalHook, options);
127 : }
128 :
129 1 : if (!global) {
130 0 : jsapi.ClearException();
131 0 : return nullptr;
132 : }
133 :
134 2 : JSAutoCompartment ac(cx, global);
135 :
136 : // It's important to create the nsIGlobalObject for our new global before we
137 : // start trying to wrap things like the prototype into its compartment,
138 : // because the wrap operation relies on the global having its
139 : // nsIGlobalObject already.
140 : RefPtr<SimpleGlobalObject> globalObject =
141 3 : new SimpleGlobalObject(global, globalType);
142 :
143 : // Pass on ownership of globalObject to |global|.
144 1 : JS_SetPrivate(global, globalObject.forget().take());
145 :
146 1 : if (proto.isObjectOrNull()) {
147 0 : JS::Rooted<JSObject*> protoObj(cx, proto.toObjectOrNull());
148 0 : if (!JS_WrapObject(cx, &protoObj)) {
149 0 : jsapi.ClearException();
150 0 : return nullptr;
151 : }
152 :
153 0 : if (!JS_SplicePrototype(cx, global, protoObj)) {
154 0 : jsapi.ClearException();
155 0 : return nullptr;
156 : }
157 1 : } else if (!proto.isUndefined()) {
158 : // Bogus proto.
159 0 : return nullptr;
160 : }
161 :
162 1 : JS_FireOnNewGlobalObject(cx, global);
163 : }
164 :
165 1 : return global;
166 : }
167 :
168 : // static
169 : SimpleGlobalObject::GlobalType
170 0 : SimpleGlobalObject::SimpleGlobalType(JSObject* obj)
171 : {
172 0 : if (js::GetObjectClass(obj) != &SimpleGlobalClass) {
173 0 : return SimpleGlobalObject::GlobalType::NotSimpleGlobal;
174 : }
175 :
176 : SimpleGlobalObject* globalObject =
177 0 : static_cast<SimpleGlobalObject*>(JS_GetPrivate(obj));
178 0 : return globalObject->Type();
179 : }
180 :
181 : } // namespace mozilla
182 : } // namespace dom
|