1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=78:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is SpiderMonkey global object code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * the Mozilla Foundation.
21 : * Portions created by the Initial Developer are Copyright (C) 2011
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Jeff Walden <jwalden+code@mit.edu> (original author)
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef GlobalObject_h___
42 : #define GlobalObject_h___
43 :
44 : #include "mozilla/Attributes.h"
45 :
46 : #include "jsarray.h"
47 : #include "jsbool.h"
48 : #include "jsexn.h"
49 : #include "jsfun.h"
50 : #include "jsiter.h"
51 : #include "jsnum.h"
52 : #include "jstypedarray.h"
53 :
54 : #include "js/Vector.h"
55 :
56 : #include "builtin/RegExp.h"
57 :
58 : extern JSObject *
59 : js_InitObjectClass(JSContext *cx, JSObject *obj);
60 :
61 : extern JSObject *
62 : js_InitFunctionClass(JSContext *cx, JSObject *obj);
63 :
64 : namespace js {
65 :
66 : class Debugger;
67 :
68 : /*
69 : * Global object slots are reserved as follows:
70 : *
71 : * [0, JSProto_LIMIT)
72 : * Stores the original value of the constructor for the corresponding
73 : * JSProtoKey.
74 : * [JSProto_LIMIT, 2 * JSProto_LIMIT)
75 : * Stores the prototype, if any, for the constructor for the corresponding
76 : * JSProtoKey offset from JSProto_LIMIT.
77 : * [2 * JSProto_LIMIT, 3 * JSProto_LIMIT)
78 : * Stores the current value of the global property named for the JSProtoKey
79 : * for the corresponding JSProtoKey offset from 2 * JSProto_LIMIT.
80 : * [3 * JSProto_LIMIT, RESERVED_SLOTS)
81 : * Various one-off values: ES5 13.2.3's [[ThrowTypeError]], RegExp statics,
82 : * the Namespace object for E4X's function::, the original eval for this
83 : * global object (implementing |var eval = otherWindow.eval; eval(...)| as an
84 : * indirect eval), a bit indicating whether this object has been cleared
85 : * (see JS_ClearScope), and a cache for whether eval is allowed (per the
86 : * global's Content Security Policy).
87 : *
88 : * The first two ranges are necessary to implement js::FindClassObject,
89 : * js::FindClassPrototype, and spec language speaking in terms of "the original
90 : * Array prototype object", or "as if by the expression new Array()" referring
91 : * to the original Array constructor. The third range stores the (writable and
92 : * even deletable) Object, Array, &c. properties (although a slot won't be used
93 : * again if its property is deleted and readded).
94 : */
95 : class GlobalObject : public JSObject {
96 : GlobalObject(const GlobalObject &other) MOZ_DELETE;
97 : void operator=(const GlobalObject &other) MOZ_DELETE;
98 :
99 : /*
100 : * Count of slots to store built-in constructors, prototypes, and initial
101 : * visible properties for the constructors.
102 : */
103 : static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 3;
104 :
105 : /* One-off properties stored after slots for built-ins. */
106 : static const unsigned THROWTYPEERROR = STANDARD_CLASS_SLOTS;
107 : static const unsigned GENERATOR_PROTO = THROWTYPEERROR + 1;
108 : static const unsigned REGEXP_STATICS = GENERATOR_PROTO + 1;
109 : static const unsigned FUNCTION_NS = REGEXP_STATICS + 1;
110 : static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1;
111 : static const unsigned EVAL = RUNTIME_CODEGEN_ENABLED + 1;
112 : static const unsigned FLAGS = EVAL + 1;
113 : static const unsigned DEBUGGERS = FLAGS + 1;
114 :
115 : /* Total reserved-slot count for global objects. */
116 : static const unsigned RESERVED_SLOTS = DEBUGGERS + 1;
117 :
118 : void staticAsserts() {
119 : /*
120 : * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS,
121 : * and we aren't going to expose GlobalObject, so just assert that the
122 : * two values are synchronized.
123 : */
124 : JS_STATIC_ASSERT(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS);
125 : }
126 :
127 : static const int32_t FLAGS_CLEARED = 0x1;
128 :
129 : inline void setFlags(int32_t flags);
130 : inline void initFlags(int32_t flags);
131 :
132 : friend JSObject *
133 : ::js_InitObjectClass(JSContext *cx, JSObject *obj);
134 : friend JSObject *
135 : ::js_InitFunctionClass(JSContext *cx, JSObject *obj);
136 :
137 : /* Initialize the Function and Object classes. Must only be called once! */
138 : JSObject *
139 : initFunctionAndObjectClasses(JSContext *cx);
140 :
141 : inline void setDetailsForKey(JSProtoKey key, JSObject *ctor, JSObject *proto);
142 : inline void setObjectClassDetails(JSFunction *ctor, JSObject *proto);
143 : inline void setFunctionClassDetails(JSFunction *ctor, JSObject *proto);
144 :
145 : inline void setThrowTypeError(JSFunction *fun);
146 :
147 : inline void setOriginalEval(JSObject *evalobj);
148 :
149 6993300 : Value getConstructor(JSProtoKey key) const {
150 6993300 : JS_ASSERT(key <= JSProto_LIMIT);
151 6993300 : return getSlot(key);
152 : }
153 :
154 10798083 : Value getPrototype(JSProtoKey key) const {
155 10798083 : JS_ASSERT(key <= JSProto_LIMIT);
156 10798083 : return getSlot(JSProto_LIMIT + key);
157 : }
158 :
159 6993300 : bool classIsInitialized(JSProtoKey key) const {
160 6993300 : bool inited = !getConstructor(key).isUndefined();
161 6993300 : JS_ASSERT(inited == !getPrototype(key).isUndefined());
162 6993300 : return inited;
163 : }
164 :
165 3188517 : bool functionObjectClassesInitialized() const {
166 3188517 : bool inited = classIsInitialized(JSProto_Function);
167 3188517 : JS_ASSERT(inited == classIsInitialized(JSProto_Object));
168 3188517 : return inited;
169 : }
170 :
171 63704 : bool arrayClassInitialized() const {
172 63704 : return classIsInitialized(JSProto_Array);
173 : }
174 :
175 : bool booleanClassInitialized() const {
176 : return classIsInitialized(JSProto_Boolean);
177 : }
178 : bool numberClassInitialized() const {
179 : return classIsInitialized(JSProto_Number);
180 : }
181 930 : bool stringClassInitialized() const {
182 930 : return classIsInitialized(JSProto_String);
183 : }
184 551614 : bool regexpClassInitialized() const {
185 551614 : return classIsInitialized(JSProto_RegExp);
186 : }
187 : bool arrayBufferClassInitialized() const {
188 : return classIsInitialized(JSProto_ArrayBuffer);
189 : }
190 18 : bool errorClassesInitialized() const {
191 18 : return classIsInitialized(JSProto_Error);
192 : }
193 :
194 : public:
195 : static GlobalObject *create(JSContext *cx, Class *clasp);
196 :
197 : /*
198 : * Create a constructor function with the specified name and length using
199 : * ctor, a method which creates objects with the given class.
200 : */
201 : JSFunction *
202 : createConstructor(JSContext *cx, JSNative ctor, Class *clasp, JSAtom *name, unsigned length,
203 : gc::AllocKind kind = JSFunction::FinalizeKind);
204 :
205 : /*
206 : * Create an object to serve as [[Prototype]] for instances of the given
207 : * class, using |Object.prototype| as its [[Prototype]]. Users creating
208 : * prototype objects with particular internal structure (e.g. reserved
209 : * slots guaranteed to contain values of particular types) must immediately
210 : * complete the minimal initialization to make the returned object safe to
211 : * touch.
212 : */
213 : JSObject *createBlankPrototype(JSContext *cx, js::Class *clasp);
214 :
215 : /*
216 : * Identical to createBlankPrototype, but uses proto as the [[Prototype]]
217 : * of the returned blank prototype.
218 : */
219 : JSObject *createBlankPrototypeInheriting(JSContext *cx, js::Class *clasp, JSObject &proto);
220 :
221 807870 : JSObject *getOrCreateObjectPrototype(JSContext *cx) {
222 807870 : GlobalObject *self = this;
223 807870 : if (!functionObjectClassesInitialized()) {
224 76176 : Root<GlobalObject*> root(cx, &self);
225 38088 : if (!initFunctionAndObjectClasses(cx))
226 0 : return NULL;
227 : }
228 807870 : return &self->getPrototype(JSProto_Object).toObject();
229 : }
230 :
231 2380647 : JSObject *getOrCreateFunctionPrototype(JSContext *cx) {
232 2380647 : GlobalObject *self = this;
233 2380647 : if (!functionObjectClassesInitialized()) {
234 32 : Root<GlobalObject*> root(cx, &self);
235 16 : if (!initFunctionAndObjectClasses(cx))
236 0 : return NULL;
237 : }
238 2380647 : return &self->getPrototype(JSProto_Function).toObject();
239 : }
240 :
241 63704 : JSObject *getOrCreateArrayPrototype(JSContext *cx) {
242 63704 : GlobalObject *self = this;
243 63704 : if (!arrayClassInitialized()) {
244 64 : Root<GlobalObject*> root(cx, &self);
245 32 : if (!js_InitArrayClass(cx, this))
246 0 : return NULL;
247 : }
248 63704 : return &self->getPrototype(JSProto_Array).toObject();
249 : }
250 :
251 : JSObject *getOrCreateBooleanPrototype(JSContext *cx) {
252 : GlobalObject *self = this;
253 : if (!booleanClassInitialized()) {
254 : Root<GlobalObject*> root(cx, &self);
255 : if (!js_InitBooleanClass(cx, this))
256 : return NULL;
257 : }
258 : return &self->getPrototype(JSProto_Boolean).toObject();
259 : }
260 :
261 : JSObject *getOrCreateNumberPrototype(JSContext *cx) {
262 : GlobalObject *self = this;
263 : if (!numberClassInitialized()) {
264 : Root<GlobalObject*> root(cx, &self);
265 : if (!js_InitNumberClass(cx, this))
266 : return NULL;
267 : }
268 : return &self->getPrototype(JSProto_Number).toObject();
269 : }
270 :
271 930 : JSObject *getOrCreateStringPrototype(JSContext *cx) {
272 930 : GlobalObject *self = this;
273 930 : if (!stringClassInitialized()) {
274 268 : Root<GlobalObject*> root(cx, &self);
275 134 : if (!js_InitStringClass(cx, this))
276 0 : return NULL;
277 : }
278 930 : return &self->getPrototype(JSProto_String).toObject();
279 : }
280 :
281 551614 : JSObject *getOrCreateRegExpPrototype(JSContext *cx) {
282 551614 : GlobalObject *self = this;
283 551614 : if (!regexpClassInitialized()) {
284 0 : Root<GlobalObject*> root(cx, &self);
285 0 : if (!js_InitRegExpClass(cx, this))
286 0 : return NULL;
287 : }
288 551614 : return &self->getPrototype(JSProto_RegExp).toObject();
289 : }
290 :
291 : JSObject *getOrCreateArrayBufferPrototype(JSContext *cx) {
292 : GlobalObject *self = this;
293 : if (!arrayBufferClassInitialized()) {
294 : Root<GlobalObject*> root(cx, &self);
295 : if (!js_InitTypedArrayClasses(cx, this))
296 : return NULL;
297 : }
298 : return &self->getPrototype(JSProto_ArrayBuffer).toObject();
299 : }
300 :
301 18 : JSObject *getOrCreateCustomErrorPrototype(JSContext *cx, int exnType) {
302 18 : GlobalObject *self = this;
303 18 : JSProtoKey key = GetExceptionProtoKey(exnType);
304 18 : if (!errorClassesInitialized()) {
305 36 : Root<GlobalObject*> root(cx, &self);
306 18 : if (!js_InitExceptionClasses(cx, this))
307 0 : return NULL;
308 : }
309 18 : return &self->getPrototype(key).toObject();
310 : }
311 :
312 12399 : JSObject *getOrCreateGeneratorPrototype(JSContext *cx) {
313 12399 : GlobalObject *self = this;
314 12399 : Value v = getSlotRef(GENERATOR_PROTO);
315 12399 : if (!v.isObject()) {
316 2788 : Root<GlobalObject*> root(cx, &self);
317 1394 : if (!js_InitIteratorClasses(cx, this))
318 0 : return NULL;
319 : }
320 12399 : return &self->getSlot(GENERATOR_PROTO).toObject();
321 : }
322 :
323 : inline RegExpStatics *getRegExpStatics() const;
324 :
325 0 : JSObject *getThrowTypeError() const {
326 0 : JS_ASSERT(functionObjectClassesInitialized());
327 0 : return &getSlot(THROWTYPEERROR).toObject();
328 : }
329 :
330 : void clear(JSContext *cx);
331 :
332 12964505 : bool isCleared() const {
333 12964505 : return getSlot(FLAGS).toInt32() & FLAGS_CLEARED;
334 : }
335 :
336 : bool isRuntimeCodeGenEnabled(JSContext *cx);
337 :
338 168159 : const Value &getOriginalEval() const {
339 168159 : JS_ASSERT(getSlot(EVAL).isObject());
340 168159 : return getSlot(EVAL);
341 : }
342 :
343 : bool getFunctionNamespace(JSContext *cx, Value *vp);
344 :
345 : bool initGeneratorClass(JSContext *cx);
346 : bool initStandardClasses(JSContext *cx);
347 :
348 : typedef js::Vector<js::Debugger *, 0, js::SystemAllocPolicy> DebuggerVector;
349 :
350 : /*
351 : * The collection of Debugger objects debugging this global. If this global
352 : * is not a debuggee, this returns either NULL or an empty vector.
353 : */
354 : DebuggerVector *getDebuggers();
355 :
356 : /*
357 : * The same, but create the empty vector if one does not already
358 : * exist. Returns NULL only on OOM.
359 : */
360 : DebuggerVector *getOrCreateDebuggers(JSContext *cx);
361 :
362 : bool addDebugger(JSContext *cx, Debugger *dbg);
363 : };
364 :
365 : /*
366 : * Define ctor.prototype = proto as non-enumerable, non-configurable, and
367 : * non-writable; define proto.constructor = ctor as non-enumerable but
368 : * configurable and writable.
369 : */
370 : extern bool
371 : LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor, JSObject *proto);
372 :
373 : /*
374 : * Define properties, then functions, on the object, then brand for tracing
375 : * benefits.
376 : */
377 : extern bool
378 : DefinePropertiesAndBrand(JSContext *cx, JSObject *obj, JSPropertySpec *ps, JSFunctionSpec *fs);
379 :
380 : typedef HashSet<GlobalObject *, DefaultHasher<GlobalObject *>, SystemAllocPolicy> GlobalObjectSet;
381 :
382 : } // namespace js
383 :
384 : inline bool
385 1077811232 : JSObject::isGlobal() const
386 : {
387 1077811232 : return !!(js::GetObjectClass(this)->flags & JSCLASS_IS_GLOBAL);
388 : }
389 :
390 : js::GlobalObject &
391 1032825446 : JSObject::asGlobal()
392 : {
393 1032825446 : JS_ASSERT(isGlobal());
394 1032825446 : return *static_cast<js::GlobalObject *>(this);
395 : }
396 :
397 : #endif /* GlobalObject_h___ */
|