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 :
53 : #include "js/Vector.h"
54 :
55 : #include "builtin/RegExp.h"
56 :
57 : extern JSObject *
58 : js_InitObjectClass(JSContext *cx, JSObject *obj);
59 :
60 : extern JSObject *
61 : js_InitFunctionClass(JSContext *cx, JSObject *obj);
62 :
63 : extern JSObject *
64 : js_InitTypedArrayClasses(JSContext *cx, JSObject *obj);
65 :
66 : namespace js {
67 :
68 : class Debugger;
69 :
70 : /*
71 : * Global object slots are reserved as follows:
72 : *
73 : * [0, JSProto_LIMIT)
74 : * Stores the original value of the constructor for the corresponding
75 : * JSProtoKey.
76 : * [JSProto_LIMIT, 2 * JSProto_LIMIT)
77 : * Stores the prototype, if any, for the constructor for the corresponding
78 : * JSProtoKey offset from JSProto_LIMIT.
79 : * [2 * JSProto_LIMIT, 3 * JSProto_LIMIT)
80 : * Stores the current value of the global property named for the JSProtoKey
81 : * for the corresponding JSProtoKey offset from 2 * JSProto_LIMIT.
82 : * [3 * JSProto_LIMIT, RESERVED_SLOTS)
83 : * Various one-off values: ES5 13.2.3's [[ThrowTypeError]], RegExp statics,
84 : * the Namespace object for E4X's function::, the original eval for this
85 : * global object (implementing |var eval = otherWindow.eval; eval(...)| as an
86 : * indirect eval), a bit indicating whether this object has been cleared
87 : * (see JS_ClearScope), and a cache for whether eval is allowed (per the
88 : * global's Content Security Policy).
89 : *
90 : * The first two ranges are necessary to implement js::FindClassObject,
91 : * js::FindClassPrototype, and spec language speaking in terms of "the original
92 : * Array prototype object", or "as if by the expression new Array()" referring
93 : * to the original Array constructor. The third range stores the (writable and
94 : * even deletable) Object, Array, &c. properties (although a slot won't be used
95 : * again if its property is deleted and readded).
96 : */
97 : class GlobalObject : public JSObject {
98 : GlobalObject(const GlobalObject &other) MOZ_DELETE;
99 : void operator=(const GlobalObject &other) MOZ_DELETE;
100 :
101 : /*
102 : * Count of slots to store built-in constructors, prototypes, and initial
103 : * visible properties for the constructors.
104 : */
105 : static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 3;
106 :
107 : /* One-off properties stored after slots for built-ins. */
108 : static const unsigned THROWTYPEERROR = STANDARD_CLASS_SLOTS;
109 : static const unsigned GENERATOR_PROTO = THROWTYPEERROR + 1;
110 : static const unsigned REGEXP_STATICS = GENERATOR_PROTO + 1;
111 : static const unsigned FUNCTION_NS = REGEXP_STATICS + 1;
112 : static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1;
113 : static const unsigned EVAL = RUNTIME_CODEGEN_ENABLED + 1;
114 : static const unsigned FLAGS = EVAL + 1;
115 : static const unsigned DEBUGGERS = FLAGS + 1;
116 :
117 : /* Total reserved-slot count for global objects. */
118 : static const unsigned RESERVED_SLOTS = DEBUGGERS + 1;
119 :
120 : void staticAsserts() {
121 : /*
122 : * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS,
123 : * and we aren't going to expose GlobalObject, so just assert that the
124 : * two values are synchronized.
125 : */
126 : JS_STATIC_ASSERT(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS);
127 : }
128 :
129 : static const int32_t FLAGS_CLEARED = 0x1;
130 :
131 : inline void setFlags(int32_t flags);
132 : inline void initFlags(int32_t flags);
133 :
134 : friend JSObject *
135 : ::js_InitObjectClass(JSContext *cx, JSObject *obj);
136 : friend JSObject *
137 : ::js_InitFunctionClass(JSContext *cx, JSObject *obj);
138 :
139 : /* Initialize the Function and Object classes. Must only be called once! */
140 : JSObject *
141 : initFunctionAndObjectClasses(JSContext *cx);
142 :
143 : inline void setDetailsForKey(JSProtoKey key, JSObject *ctor, JSObject *proto);
144 : inline void setObjectClassDetails(JSFunction *ctor, JSObject *proto);
145 : inline void setFunctionClassDetails(JSFunction *ctor, JSObject *proto);
146 :
147 : inline void setThrowTypeError(JSFunction *fun);
148 :
149 : inline void setOriginalEval(JSObject *evalobj);
150 :
151 3130055 : Value getConstructor(JSProtoKey key) const {
152 3130055 : JS_ASSERT(key <= JSProto_LIMIT);
153 3130055 : return getSlot(key);
154 : }
155 :
156 4825934 : Value getPrototype(JSProtoKey key) const {
157 4825934 : JS_ASSERT(key <= JSProto_LIMIT);
158 4825934 : return getSlot(JSProto_LIMIT + key);
159 : }
160 :
161 3130055 : bool classIsInitialized(JSProtoKey key) const {
162 3130055 : bool inited = !getConstructor(key).isUndefined();
163 3130055 : JS_ASSERT(inited == !getPrototype(key).isUndefined());
164 3130055 : return inited;
165 : }
166 :
167 1434176 : bool functionObjectClassesInitialized() const {
168 1434176 : bool inited = classIsInitialized(JSProto_Function);
169 1434176 : JS_ASSERT(inited == classIsInitialized(JSProto_Object));
170 1434176 : return inited;
171 : }
172 :
173 63631 : bool arrayClassInitialized() const {
174 63631 : return classIsInitialized(JSProto_Array);
175 : }
176 :
177 : bool booleanClassInitialized() const {
178 : return classIsInitialized(JSProto_Boolean);
179 : }
180 : bool numberClassInitialized() const {
181 : return classIsInitialized(JSProto_Number);
182 : }
183 933 : bool stringClassInitialized() const {
184 933 : return classIsInitialized(JSProto_String);
185 : }
186 197121 : bool regexpClassInitialized() const {
187 197121 : return classIsInitialized(JSProto_RegExp);
188 : }
189 : bool arrayBufferClassInitialized() const {
190 : return classIsInitialized(JSProto_ArrayBuffer);
191 : }
192 18 : bool errorClassesInitialized() const {
193 18 : return classIsInitialized(JSProto_Error);
194 : }
195 :
196 : public:
197 : static GlobalObject *create(JSContext *cx, Class *clasp);
198 :
199 : /*
200 : * Create a constructor function with the specified name and length using
201 : * ctor, a method which creates objects with the given class.
202 : */
203 : JSFunction *
204 : createConstructor(JSContext *cx, JSNative ctor, JSAtom *name, unsigned length,
205 : gc::AllocKind kind = JSFunction::FinalizeKind);
206 :
207 : /*
208 : * Create an object to serve as [[Prototype]] for instances of the given
209 : * class, using |Object.prototype| as its [[Prototype]]. Users creating
210 : * prototype objects with particular internal structure (e.g. reserved
211 : * slots guaranteed to contain values of particular types) must immediately
212 : * complete the minimal initialization to make the returned object safe to
213 : * touch.
214 : */
215 : JSObject *createBlankPrototype(JSContext *cx, js::Class *clasp);
216 :
217 : /*
218 : * Identical to createBlankPrototype, but uses proto as the [[Prototype]]
219 : * of the returned blank prototype.
220 : */
221 : JSObject *createBlankPrototypeInheriting(JSContext *cx, js::Class *clasp, JSObject &proto);
222 :
223 462601 : JSObject *getOrCreateObjectPrototype(JSContext *cx) {
224 462601 : GlobalObject *self = this;
225 462601 : if (!functionObjectClassesInitialized()) {
226 46710 : Root<GlobalObject*> root(cx, &self);
227 23355 : if (!initFunctionAndObjectClasses(cx))
228 0 : return NULL;
229 : }
230 462601 : return &self->getPrototype(JSProto_Object).toObject();
231 : }
232 :
233 971575 : JSObject *getOrCreateFunctionPrototype(JSContext *cx) {
234 971575 : GlobalObject *self = this;
235 971575 : if (!functionObjectClassesInitialized()) {
236 20 : Root<GlobalObject*> root(cx, &self);
237 10 : if (!initFunctionAndObjectClasses(cx))
238 0 : return NULL;
239 : }
240 971575 : return &self->getPrototype(JSProto_Function).toObject();
241 : }
242 :
243 63631 : JSObject *getOrCreateArrayPrototype(JSContext *cx) {
244 63631 : GlobalObject *self = this;
245 63631 : if (!arrayClassInitialized()) {
246 64 : Root<GlobalObject*> root(cx, &self);
247 32 : if (!js_InitArrayClass(cx, this))
248 0 : return NULL;
249 : }
250 63631 : return &self->getPrototype(JSProto_Array).toObject();
251 : }
252 :
253 : JSObject *getOrCreateBooleanPrototype(JSContext *cx) {
254 : GlobalObject *self = this;
255 : if (!booleanClassInitialized()) {
256 : Root<GlobalObject*> root(cx, &self);
257 : if (!js_InitBooleanClass(cx, this))
258 : return NULL;
259 : }
260 : return &self->getPrototype(JSProto_Boolean).toObject();
261 : }
262 :
263 : JSObject *getOrCreateNumberPrototype(JSContext *cx) {
264 : GlobalObject *self = this;
265 : if (!numberClassInitialized()) {
266 : Root<GlobalObject*> root(cx, &self);
267 : if (!js_InitNumberClass(cx, this))
268 : return NULL;
269 : }
270 : return &self->getPrototype(JSProto_Number).toObject();
271 : }
272 :
273 933 : JSObject *getOrCreateStringPrototype(JSContext *cx) {
274 933 : GlobalObject *self = this;
275 933 : if (!stringClassInitialized()) {
276 264 : Root<GlobalObject*> root(cx, &self);
277 132 : if (!js_InitStringClass(cx, this))
278 0 : return NULL;
279 : }
280 933 : return &self->getPrototype(JSProto_String).toObject();
281 : }
282 :
283 197121 : JSObject *getOrCreateRegExpPrototype(JSContext *cx) {
284 197121 : GlobalObject *self = this;
285 197121 : if (!regexpClassInitialized()) {
286 0 : Root<GlobalObject*> root(cx, &self);
287 0 : if (!js_InitRegExpClass(cx, this))
288 0 : return NULL;
289 : }
290 197121 : return &self->getPrototype(JSProto_RegExp).toObject();
291 : }
292 :
293 : JSObject *getOrCreateArrayBufferPrototype(JSContext *cx) {
294 : GlobalObject *self = this;
295 : if (!arrayBufferClassInitialized()) {
296 : Root<GlobalObject*> root(cx, &self);
297 : if (!js_InitTypedArrayClasses(cx, this))
298 : return NULL;
299 : }
300 : return &self->getPrototype(JSProto_ArrayBuffer).toObject();
301 : }
302 :
303 18 : JSObject *getOrCreateCustomErrorPrototype(JSContext *cx, int exnType) {
304 18 : GlobalObject *self = this;
305 18 : JSProtoKey key = GetExceptionProtoKey(exnType);
306 18 : if (!errorClassesInitialized()) {
307 36 : Root<GlobalObject*> root(cx, &self);
308 18 : if (!js_InitExceptionClasses(cx, this))
309 0 : return NULL;
310 : }
311 18 : return &self->getPrototype(key).toObject();
312 : }
313 :
314 8352 : JSObject *getOrCreateGeneratorPrototype(JSContext *cx) {
315 8352 : GlobalObject *self = this;
316 8352 : Value v = getSlotRef(GENERATOR_PROTO);
317 8352 : if (!v.isObject()) {
318 972 : Root<GlobalObject*> root(cx, &self);
319 486 : if (!js_InitIteratorClasses(cx, this))
320 0 : return NULL;
321 : }
322 8352 : return &self->getSlot(GENERATOR_PROTO).toObject();
323 : }
324 :
325 : inline RegExpStatics *getRegExpStatics() const;
326 :
327 0 : JSObject *getThrowTypeError() const {
328 0 : JS_ASSERT(functionObjectClassesInitialized());
329 0 : return &getSlot(THROWTYPEERROR).toObject();
330 : }
331 :
332 : void clear(JSContext *cx);
333 :
334 12989162 : bool isCleared() const {
335 12989162 : return getSlot(FLAGS).toInt32() & FLAGS_CLEARED;
336 : }
337 :
338 : bool isRuntimeCodeGenEnabled(JSContext *cx);
339 :
340 167167 : const Value &getOriginalEval() const {
341 167167 : JS_ASSERT(getSlot(EVAL).isObject());
342 167167 : return getSlot(EVAL);
343 : }
344 :
345 : bool getFunctionNamespace(JSContext *cx, Value *vp);
346 :
347 : bool initGeneratorClass(JSContext *cx);
348 : bool initStandardClasses(JSContext *cx);
349 :
350 : typedef js::Vector<js::Debugger *, 0, js::SystemAllocPolicy> DebuggerVector;
351 :
352 : /*
353 : * The collection of Debugger objects debugging this global. If this global
354 : * is not a debuggee, this returns either NULL or an empty vector.
355 : */
356 : DebuggerVector *getDebuggers();
357 :
358 : /*
359 : * The same, but create the empty vector if one does not already
360 : * exist. Returns NULL only on OOM.
361 : */
362 : DebuggerVector *getOrCreateDebuggers(JSContext *cx);
363 :
364 : bool addDebugger(JSContext *cx, Debugger *dbg);
365 : };
366 :
367 : /*
368 : * Define ctor.prototype = proto as non-enumerable, non-configurable, and
369 : * non-writable; define proto.constructor = ctor as non-enumerable but
370 : * configurable and writable.
371 : */
372 : extern bool
373 : LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor, JSObject *proto);
374 :
375 : /*
376 : * Define properties, then functions, on the object, then brand for tracing
377 : * benefits.
378 : */
379 : extern bool
380 : DefinePropertiesAndBrand(JSContext *cx, JSObject *obj, JSPropertySpec *ps, JSFunctionSpec *fs);
381 :
382 : typedef HashSet<GlobalObject *, DefaultHasher<GlobalObject *>, SystemAllocPolicy> GlobalObjectSet;
383 :
384 : } // namespace js
385 :
386 : inline bool
387 1036960927 : JSObject::isGlobal() const
388 : {
389 1036960927 : return !!(js::GetObjectClass(this)->flags & JSCLASS_IS_GLOBAL);
390 : }
391 :
392 : js::GlobalObject &
393 1012287598 : JSObject::asGlobal()
394 : {
395 1012287598 : JS_ASSERT(isGlobal());
396 1012287598 : return *static_cast<js::GlobalObject *>(this);
397 : }
398 :
399 : #endif /* GlobalObject_h___ */
|