/src/mozilla-central/dom/bindings/SimpleGlobalObject.cpp
Line | Count | Source (jump to first uncovered line) |
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 "nsThreadUtils.h" |
14 | | #include "nsContentUtils.h" |
15 | | |
16 | | #include "xpcprivate.h" |
17 | | |
18 | | #include "mozilla/dom/ScriptSettings.h" |
19 | | #include "mozilla/NullPrincipal.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 | | NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(SimpleGlobalObject) |
36 | | |
37 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(SimpleGlobalObject) |
38 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(SimpleGlobalObject) |
39 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SimpleGlobalObject) |
40 | 0 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
41 | 0 | NS_INTERFACE_MAP_ENTRY(nsIGlobalObject) |
42 | 0 | NS_INTERFACE_MAP_END |
43 | | |
44 | | static void |
45 | | SimpleGlobal_finalize(js::FreeOp *fop, JSObject *obj) |
46 | 0 | { |
47 | 0 | SimpleGlobalObject* globalObject = |
48 | 0 | static_cast<SimpleGlobalObject*>(JS_GetPrivate(obj)); |
49 | 0 | if (globalObject) { |
50 | 0 | globalObject->ClearWrapper(obj); |
51 | 0 | NS_RELEASE(globalObject); |
52 | 0 | } |
53 | 0 | } |
54 | | |
55 | | static size_t |
56 | | SimpleGlobal_moved(JSObject *obj, JSObject *old) |
57 | 0 | { |
58 | 0 | SimpleGlobalObject* globalObject = |
59 | 0 | static_cast<SimpleGlobalObject*>(JS_GetPrivate(obj)); |
60 | 0 | if (globalObject) { |
61 | 0 | globalObject->UpdateWrapper(obj, old); |
62 | 0 | } |
63 | 0 | return 0; |
64 | 0 | } |
65 | | |
66 | | static const js::ClassOps SimpleGlobalClassOps = { |
67 | | nullptr, |
68 | | nullptr, |
69 | | nullptr, |
70 | | JS_NewEnumerateStandardClasses, |
71 | | JS_ResolveStandardClass, |
72 | | JS_MayResolveStandardClass, |
73 | | SimpleGlobal_finalize, |
74 | | nullptr, |
75 | | nullptr, |
76 | | nullptr, |
77 | | JS_GlobalObjectTraceHook, |
78 | | }; |
79 | | |
80 | | static const js::ClassExtension SimpleGlobalClassExtension = { |
81 | | nullptr, |
82 | | SimpleGlobal_moved |
83 | | }; |
84 | | |
85 | | const js::Class SimpleGlobalClass = { |
86 | | "", |
87 | | JSCLASS_GLOBAL_FLAGS | |
88 | | JSCLASS_HAS_PRIVATE | |
89 | | JSCLASS_PRIVATE_IS_NSISUPPORTS | |
90 | | JSCLASS_FOREGROUND_FINALIZE, |
91 | | &SimpleGlobalClassOps, |
92 | | JS_NULL_CLASS_SPEC, |
93 | | &SimpleGlobalClassExtension, |
94 | | JS_NULL_OBJECT_OPS |
95 | | }; |
96 | | |
97 | | // static |
98 | | JSObject* |
99 | | SimpleGlobalObject::Create(GlobalType globalType, JS::Handle<JS::Value> proto) |
100 | 0 | { |
101 | 0 | // We can't root our return value with our AutoJSAPI because the rooting |
102 | 0 | // analysis thinks ~AutoJSAPI can GC. So we need to root in a scope outside |
103 | 0 | // the lifetime of the AutoJSAPI. |
104 | 0 | JS::Rooted<JSObject*> global(RootingCx()); |
105 | 0 |
|
106 | 0 | { // Scope to ensure the AutoJSAPI destructor runs before we end up returning |
107 | 0 | AutoJSAPI jsapi; |
108 | 0 | jsapi.Init(); |
109 | 0 | JSContext* cx = jsapi.cx(); |
110 | 0 |
|
111 | 0 | JS::RealmOptions options; |
112 | 0 | options.creationOptions() |
113 | 0 | .setInvisibleToDebugger(true) |
114 | 0 | // Put our SimpleGlobalObjects in the system zone, so we won't create |
115 | 0 | // lots of zones for what are probably very short-lived |
116 | 0 | // compartments. This should help them be GCed quicker and take up |
117 | 0 | // less memory before they're GCed. |
118 | 0 | .setNewCompartmentInSystemZone(); |
119 | 0 |
|
120 | 0 | if (NS_IsMainThread()) { |
121 | 0 | nsCOMPtr<nsIPrincipal> principal = NullPrincipal::CreateWithoutOriginAttributes(); |
122 | 0 | options.creationOptions().setTrace(xpc::TraceXPCGlobal); |
123 | 0 | global = xpc::CreateGlobalObject(cx, js::Jsvalify(&SimpleGlobalClass), |
124 | 0 | nsJSPrincipals::get(principal), |
125 | 0 | options); |
126 | 0 | } else { |
127 | 0 | global = JS_NewGlobalObject(cx, js::Jsvalify(&SimpleGlobalClass), |
128 | 0 | nullptr, |
129 | 0 | JS::DontFireOnNewGlobalHook, options); |
130 | 0 | } |
131 | 0 |
|
132 | 0 | if (!global) { |
133 | 0 | jsapi.ClearException(); |
134 | 0 | return nullptr; |
135 | 0 | } |
136 | 0 | |
137 | 0 | JSAutoRealm ar(cx, global); |
138 | 0 |
|
139 | 0 | // It's important to create the nsIGlobalObject for our new global before we |
140 | 0 | // start trying to wrap things like the prototype into its compartment, |
141 | 0 | // because the wrap operation relies on the global having its |
142 | 0 | // nsIGlobalObject already. |
143 | 0 | RefPtr<SimpleGlobalObject> globalObject = |
144 | 0 | new SimpleGlobalObject(global, globalType); |
145 | 0 |
|
146 | 0 | // Pass on ownership of globalObject to |global|. |
147 | 0 | JS_SetPrivate(global, globalObject.forget().take()); |
148 | 0 |
|
149 | 0 | if (proto.isObjectOrNull()) { |
150 | 0 | JS::Rooted<JSObject*> protoObj(cx, proto.toObjectOrNull()); |
151 | 0 | if (!JS_WrapObject(cx, &protoObj)) { |
152 | 0 | jsapi.ClearException(); |
153 | 0 | return nullptr; |
154 | 0 | } |
155 | 0 | |
156 | 0 | if (!JS_SplicePrototype(cx, global, protoObj)) { |
157 | 0 | jsapi.ClearException(); |
158 | 0 | return nullptr; |
159 | 0 | } |
160 | 0 | } else if (!proto.isUndefined()) { |
161 | 0 | // Bogus proto. |
162 | 0 | return nullptr; |
163 | 0 | } |
164 | 0 | |
165 | 0 | JS_FireOnNewGlobalObject(cx, global); |
166 | 0 | } |
167 | 0 |
|
168 | 0 | return global; |
169 | 0 | } |
170 | | |
171 | | // static |
172 | | SimpleGlobalObject::GlobalType |
173 | | SimpleGlobalObject::SimpleGlobalType(JSObject* obj) |
174 | 0 | { |
175 | 0 | if (js::GetObjectClass(obj) != &SimpleGlobalClass) { |
176 | 0 | return SimpleGlobalObject::GlobalType::NotSimpleGlobal; |
177 | 0 | } |
178 | 0 | |
179 | 0 | SimpleGlobalObject* globalObject = |
180 | 0 | static_cast<SimpleGlobalObject*>(JS_GetPrivate(obj)); |
181 | 0 | return globalObject->Type(); |
182 | 0 | } |
183 | | |
184 | | } // namespace mozilla |
185 | | } // namespace dom |