|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
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 |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef vm_GlobalObject_h |
|
8 #define vm_GlobalObject_h |
|
9 |
|
10 #include "jsarray.h" |
|
11 #include "jsbool.h" |
|
12 #include "jsexn.h" |
|
13 #include "jsfun.h" |
|
14 #include "jsnum.h" |
|
15 |
|
16 #include "builtin/RegExp.h" |
|
17 #include "js/Vector.h" |
|
18 #include "vm/ArrayBufferObject.h" |
|
19 #include "vm/ErrorObject.h" |
|
20 |
|
21 extern JSObject * |
|
22 js_InitObjectClass(JSContext *cx, js::HandleObject obj); |
|
23 |
|
24 extern JSObject * |
|
25 js_InitFunctionClass(JSContext *cx, js::HandleObject obj); |
|
26 |
|
27 extern JSObject * |
|
28 js_InitTypedArrayClasses(JSContext *cx, js::HandleObject obj); |
|
29 |
|
30 extern JSObject * |
|
31 js_InitSharedArrayBufferClass(JSContext *cx, js::HandleObject obj); |
|
32 |
|
33 namespace js { |
|
34 |
|
35 class Debugger; |
|
36 class TypedObjectModuleObject; |
|
37 |
|
38 /* |
|
39 * Global object slots are reserved as follows: |
|
40 * |
|
41 * [0, APPLICATION_SLOTS) |
|
42 * Pre-reserved slots in all global objects set aside for the embedding's |
|
43 * use. As with all reserved slots these start out as UndefinedValue() and |
|
44 * are traced for GC purposes. Apart from that the engine never touches |
|
45 * these slots, so the embedding can do whatever it wants with them. |
|
46 * [APPLICATION_SLOTS, APPLICATION_SLOTS + JSProto_LIMIT) |
|
47 * Stores the original value of the constructor for the corresponding |
|
48 * JSProtoKey. |
|
49 * [APPLICATION_SLOTS + JSProto_LIMIT, APPLICATION_SLOTS + 2 * JSProto_LIMIT) |
|
50 * Stores the prototype, if any, for the constructor for the corresponding |
|
51 * JSProtoKey offset from JSProto_LIMIT. |
|
52 * [APPLICATION_SLOTS + 2 * JSProto_LIMIT, APPLICATION_SLOTS + 3 * JSProto_LIMIT) |
|
53 * Stores the current value of the global property named for the JSProtoKey |
|
54 * for the corresponding JSProtoKey offset from 2 * JSProto_LIMIT. |
|
55 * [APPLICATION_SLOTS + 3 * JSProto_LIMIT, RESERVED_SLOTS) |
|
56 * Various one-off values: ES5 13.2.3's [[ThrowTypeError]], RegExp statics, |
|
57 * the original eval for this global object (implementing |var eval = |
|
58 * otherWindow.eval; eval(...)| as an indirect eval), a bit indicating |
|
59 * whether this object has been cleared (see JS_ClearScope), and a cache for |
|
60 * whether eval is allowed (per the global's Content Security Policy). |
|
61 * |
|
62 * The first two JSProto_LIMIT-sized ranges are necessary to implement |
|
63 * js::FindClassObject, and spec language speaking in terms of "the original |
|
64 * Array prototype object", or "as if by the expression new Array()" referring |
|
65 * to the original Array constructor. The third range stores the (writable and |
|
66 * even deletable) Object, Array, &c. properties (although a slot won't be used |
|
67 * again if its property is deleted and readded). |
|
68 */ |
|
69 class GlobalObject : public JSObject |
|
70 { |
|
71 /* Count of slots set aside for application use. */ |
|
72 static const unsigned APPLICATION_SLOTS = 3; |
|
73 |
|
74 /* |
|
75 * Count of slots to store built-in constructors, prototypes, and initial |
|
76 * visible properties for the constructors. |
|
77 */ |
|
78 static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 3; |
|
79 |
|
80 /* Various function values needed by the engine. */ |
|
81 static const unsigned EVAL = APPLICATION_SLOTS + STANDARD_CLASS_SLOTS; |
|
82 static const unsigned CREATE_DATAVIEW_FOR_THIS = EVAL + 1; |
|
83 static const unsigned THROWTYPEERROR = CREATE_DATAVIEW_FOR_THIS + 1; |
|
84 static const unsigned PROTO_GETTER = THROWTYPEERROR + 1; |
|
85 |
|
86 /* |
|
87 * Instances of the internal createArrayFromBuffer function used by the |
|
88 * typed array code, one per typed array element type. |
|
89 */ |
|
90 static const unsigned FROM_BUFFER_UINT8 = PROTO_GETTER + 1; |
|
91 static const unsigned FROM_BUFFER_INT8 = FROM_BUFFER_UINT8 + 1; |
|
92 static const unsigned FROM_BUFFER_UINT16 = FROM_BUFFER_INT8 + 1; |
|
93 static const unsigned FROM_BUFFER_INT16 = FROM_BUFFER_UINT16 + 1; |
|
94 static const unsigned FROM_BUFFER_UINT32 = FROM_BUFFER_INT16 + 1; |
|
95 static const unsigned FROM_BUFFER_INT32 = FROM_BUFFER_UINT32 + 1; |
|
96 static const unsigned FROM_BUFFER_FLOAT32 = FROM_BUFFER_INT32 + 1; |
|
97 static const unsigned FROM_BUFFER_FLOAT64 = FROM_BUFFER_FLOAT32 + 1; |
|
98 static const unsigned FROM_BUFFER_UINT8CLAMPED = FROM_BUFFER_FLOAT64 + 1; |
|
99 |
|
100 /* One-off properties stored after slots for built-ins. */ |
|
101 static const unsigned ARRAY_ITERATOR_PROTO = FROM_BUFFER_UINT8CLAMPED + 1; |
|
102 static const unsigned STRING_ITERATOR_PROTO = ARRAY_ITERATOR_PROTO + 1; |
|
103 static const unsigned LEGACY_GENERATOR_OBJECT_PROTO = STRING_ITERATOR_PROTO + 1; |
|
104 static const unsigned STAR_GENERATOR_OBJECT_PROTO = LEGACY_GENERATOR_OBJECT_PROTO + 1; |
|
105 static const unsigned MAP_ITERATOR_PROTO = STAR_GENERATOR_OBJECT_PROTO + 1; |
|
106 static const unsigned SET_ITERATOR_PROTO = MAP_ITERATOR_PROTO + 1; |
|
107 static const unsigned COLLATOR_PROTO = SET_ITERATOR_PROTO + 1; |
|
108 static const unsigned NUMBER_FORMAT_PROTO = COLLATOR_PROTO + 1; |
|
109 static const unsigned DATE_TIME_FORMAT_PROTO = NUMBER_FORMAT_PROTO + 1; |
|
110 static const unsigned REGEXP_STATICS = DATE_TIME_FORMAT_PROTO + 1; |
|
111 static const unsigned WARNED_WATCH_DEPRECATED = REGEXP_STATICS + 1; |
|
112 static const unsigned WARNED_PROTO_SETTING_SLOW = WARNED_WATCH_DEPRECATED + 1; |
|
113 static const unsigned RUNTIME_CODEGEN_ENABLED = WARNED_PROTO_SETTING_SLOW + 1; |
|
114 static const unsigned DEBUGGERS = RUNTIME_CODEGEN_ENABLED + 1; |
|
115 static const unsigned INTRINSICS = DEBUGGERS + 1; |
|
116 static const unsigned FLOAT32X4_TYPE_DESCR = INTRINSICS + 1; |
|
117 static const unsigned INT32X4_TYPE_DESCR = FLOAT32X4_TYPE_DESCR + 1; |
|
118 static const unsigned FOR_OF_PIC_CHAIN = INT32X4_TYPE_DESCR + 1; |
|
119 |
|
120 /* Total reserved-slot count for global objects. */ |
|
121 static const unsigned RESERVED_SLOTS = FOR_OF_PIC_CHAIN + 1; |
|
122 |
|
123 /* |
|
124 * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, and |
|
125 * we won't expose GlobalObject, so just assert that the two values are |
|
126 * synchronized. |
|
127 */ |
|
128 static_assert(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS, |
|
129 "global object slot counts are inconsistent"); |
|
130 |
|
131 /* Initialize the Function and Object classes. Must only be called once! */ |
|
132 JSObject * |
|
133 initFunctionAndObjectClasses(JSContext *cx); |
|
134 |
|
135 void setThrowTypeError(JSFunction *fun) { |
|
136 JS_ASSERT(getSlotRef(THROWTYPEERROR).isUndefined()); |
|
137 setSlot(THROWTYPEERROR, ObjectValue(*fun)); |
|
138 } |
|
139 |
|
140 void setOriginalEval(JSObject *evalobj) { |
|
141 JS_ASSERT(getSlotRef(EVAL).isUndefined()); |
|
142 setSlot(EVAL, ObjectValue(*evalobj)); |
|
143 } |
|
144 |
|
145 void setProtoGetter(JSFunction *protoGetter) { |
|
146 JS_ASSERT(getSlotRef(PROTO_GETTER).isUndefined()); |
|
147 setSlot(PROTO_GETTER, ObjectValue(*protoGetter)); |
|
148 } |
|
149 |
|
150 void setIntrinsicsHolder(JSObject *obj) { |
|
151 JS_ASSERT(getSlotRef(INTRINSICS).isUndefined()); |
|
152 setSlot(INTRINSICS, ObjectValue(*obj)); |
|
153 } |
|
154 |
|
155 // Emit the specified warning if the given slot in |obj|'s global isn't |
|
156 // true, then set the slot to true. Thus calling this method warns once |
|
157 // for each global object it's called on, and every other call does |
|
158 // nothing. |
|
159 static bool |
|
160 warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber); |
|
161 |
|
162 public: |
|
163 Value getConstructor(JSProtoKey key) const { |
|
164 JS_ASSERT(key <= JSProto_LIMIT); |
|
165 return getSlot(APPLICATION_SLOTS + key); |
|
166 } |
|
167 static bool ensureConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key); |
|
168 static bool resolveConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key); |
|
169 static bool initBuiltinConstructor(JSContext *cx, Handle<GlobalObject*> global, |
|
170 JSProtoKey key, HandleObject ctor, HandleObject proto); |
|
171 |
|
172 void setConstructor(JSProtoKey key, const Value &v) { |
|
173 JS_ASSERT(key <= JSProto_LIMIT); |
|
174 setSlot(APPLICATION_SLOTS + key, v); |
|
175 } |
|
176 |
|
177 Value getPrototype(JSProtoKey key) const { |
|
178 JS_ASSERT(key <= JSProto_LIMIT); |
|
179 return getSlot(APPLICATION_SLOTS + JSProto_LIMIT + key); |
|
180 } |
|
181 |
|
182 void setPrototype(JSProtoKey key, const Value &value) { |
|
183 JS_ASSERT(key <= JSProto_LIMIT); |
|
184 setSlot(APPLICATION_SLOTS + JSProto_LIMIT + key, value); |
|
185 } |
|
186 |
|
187 static uint32_t constructorPropertySlot(JSProtoKey key) { |
|
188 JS_ASSERT(key <= JSProto_LIMIT); |
|
189 return APPLICATION_SLOTS + JSProto_LIMIT * 2 + key; |
|
190 } |
|
191 |
|
192 Value getConstructorPropertySlot(JSProtoKey key) { |
|
193 return getSlot(constructorPropertySlot(key)); |
|
194 } |
|
195 |
|
196 void setConstructorPropertySlot(JSProtoKey key, const Value &ctor) { |
|
197 setSlot(constructorPropertySlot(key), ctor); |
|
198 } |
|
199 |
|
200 bool classIsInitialized(JSProtoKey key) const { |
|
201 bool inited = !getConstructor(key).isUndefined(); |
|
202 JS_ASSERT(inited == !getPrototype(key).isUndefined()); |
|
203 return inited; |
|
204 } |
|
205 |
|
206 bool functionObjectClassesInitialized() const { |
|
207 bool inited = classIsInitialized(JSProto_Function); |
|
208 JS_ASSERT(inited == classIsInitialized(JSProto_Object)); |
|
209 return inited; |
|
210 } |
|
211 |
|
212 /* |
|
213 * Lazy standard classes need a way to indicate they have been initialized. |
|
214 * Otherwise, when we delete them, we might accidentally recreate them via |
|
215 * a lazy initialization. We use the presence of an object in the |
|
216 * getConstructor(key) reserved slot to indicate that they've been |
|
217 * initialized. |
|
218 * |
|
219 * Note: A few builtin objects, like JSON and Math, are not constructors, |
|
220 * so getConstructor is a bit of a misnomer. |
|
221 */ |
|
222 bool isStandardClassResolved(JSProtoKey key) const { |
|
223 // If the constructor is undefined, then it hasn't been initialized. |
|
224 MOZ_ASSERT(getConstructor(key).isUndefined() || |
|
225 getConstructor(key).isObject()); |
|
226 return !getConstructor(key).isUndefined(); |
|
227 } |
|
228 |
|
229 bool isStandardClassResolved(const js::Class *clasp) const { |
|
230 JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp); |
|
231 return isStandardClassResolved(key); |
|
232 } |
|
233 |
|
234 private: |
|
235 void setDetailsForKey(JSProtoKey key, JSObject *ctor, JSObject *proto) { |
|
236 JS_ASSERT(getConstructor(key).isUndefined()); |
|
237 JS_ASSERT(getPrototype(key).isUndefined()); |
|
238 JS_ASSERT(getConstructorPropertySlot(key).isUndefined()); |
|
239 setConstructor(key, ObjectValue(*ctor)); |
|
240 setPrototype(key, ObjectValue(*proto)); |
|
241 setConstructorPropertySlot(key, ObjectValue(*ctor)); |
|
242 } |
|
243 |
|
244 void setObjectClassDetails(JSFunction *ctor, JSObject *proto) { |
|
245 setDetailsForKey(JSProto_Object, ctor, proto); |
|
246 } |
|
247 |
|
248 void setFunctionClassDetails(JSFunction *ctor, JSObject *proto) { |
|
249 setDetailsForKey(JSProto_Function, ctor, proto); |
|
250 } |
|
251 |
|
252 bool arrayClassInitialized() const { |
|
253 return classIsInitialized(JSProto_Array); |
|
254 } |
|
255 |
|
256 bool booleanClassInitialized() const { |
|
257 return classIsInitialized(JSProto_Boolean); |
|
258 } |
|
259 bool numberClassInitialized() const { |
|
260 return classIsInitialized(JSProto_Number); |
|
261 } |
|
262 bool stringClassInitialized() const { |
|
263 return classIsInitialized(JSProto_String); |
|
264 } |
|
265 bool regexpClassInitialized() const { |
|
266 return classIsInitialized(JSProto_RegExp); |
|
267 } |
|
268 bool arrayBufferClassInitialized() const { |
|
269 return classIsInitialized(JSProto_ArrayBuffer); |
|
270 } |
|
271 bool sharedArrayBufferClassInitialized() const { |
|
272 return classIsInitialized(JSProto_SharedArrayBuffer); |
|
273 } |
|
274 bool errorClassesInitialized() const { |
|
275 return classIsInitialized(JSProto_Error); |
|
276 } |
|
277 bool dataViewClassInitialized() const { |
|
278 return classIsInitialized(JSProto_DataView); |
|
279 } |
|
280 bool typedArrayClassesInitialized() const { |
|
281 // This alias exists only for clarity: in reality all the typed array |
|
282 // classes constitute a (semi-)coherent whole. |
|
283 return classIsInitialized(JSProto_DataView); |
|
284 } |
|
285 |
|
286 Value createArrayFromBufferHelper(uint32_t slot) const { |
|
287 JS_ASSERT(typedArrayClassesInitialized()); |
|
288 JS_ASSERT(FROM_BUFFER_UINT8 <= slot && slot <= FROM_BUFFER_UINT8CLAMPED); |
|
289 return getSlot(slot); |
|
290 } |
|
291 |
|
292 void setCreateArrayFromBufferHelper(uint32_t slot, Handle<JSFunction*> fun) { |
|
293 JS_ASSERT(getSlotRef(slot).isUndefined()); |
|
294 setSlot(slot, ObjectValue(*fun)); |
|
295 } |
|
296 |
|
297 public: |
|
298 /* XXX Privatize me! */ |
|
299 void setCreateDataViewForThis(Handle<JSFunction*> fun) { |
|
300 JS_ASSERT(getSlotRef(CREATE_DATAVIEW_FOR_THIS).isUndefined()); |
|
301 setSlot(CREATE_DATAVIEW_FOR_THIS, ObjectValue(*fun)); |
|
302 } |
|
303 |
|
304 template<typename T> |
|
305 inline void setCreateArrayFromBuffer(Handle<JSFunction*> fun); |
|
306 |
|
307 public: |
|
308 static GlobalObject *create(JSContext *cx, const Class *clasp); |
|
309 |
|
310 /* |
|
311 * Create a constructor function with the specified name and length using |
|
312 * ctor, a method which creates objects with the given class. |
|
313 */ |
|
314 JSFunction * |
|
315 createConstructor(JSContext *cx, JSNative ctor, JSAtom *name, unsigned length, |
|
316 gc::AllocKind kind = JSFunction::FinalizeKind); |
|
317 |
|
318 /* |
|
319 * Create an object to serve as [[Prototype]] for instances of the given |
|
320 * class, using |Object.prototype| as its [[Prototype]]. Users creating |
|
321 * prototype objects with particular internal structure (e.g. reserved |
|
322 * slots guaranteed to contain values of particular types) must immediately |
|
323 * complete the minimal initialization to make the returned object safe to |
|
324 * touch. |
|
325 */ |
|
326 JSObject *createBlankPrototype(JSContext *cx, const js::Class *clasp); |
|
327 |
|
328 /* |
|
329 * Identical to createBlankPrototype, but uses proto as the [[Prototype]] |
|
330 * of the returned blank prototype. |
|
331 */ |
|
332 JSObject *createBlankPrototypeInheriting(JSContext *cx, const js::Class *clasp, JSObject &proto); |
|
333 |
|
334 JSObject *getOrCreateObjectPrototype(JSContext *cx) { |
|
335 if (functionObjectClassesInitialized()) |
|
336 return &getPrototype(JSProto_Object).toObject(); |
|
337 Rooted<GlobalObject*> self(cx, this); |
|
338 if (!initFunctionAndObjectClasses(cx)) |
|
339 return nullptr; |
|
340 return &self->getPrototype(JSProto_Object).toObject(); |
|
341 } |
|
342 |
|
343 JSObject *getOrCreateFunctionPrototype(JSContext *cx) { |
|
344 if (functionObjectClassesInitialized()) |
|
345 return &getPrototype(JSProto_Function).toObject(); |
|
346 Rooted<GlobalObject*> self(cx, this); |
|
347 if (!initFunctionAndObjectClasses(cx)) |
|
348 return nullptr; |
|
349 return &self->getPrototype(JSProto_Function).toObject(); |
|
350 } |
|
351 |
|
352 static JSObject *getOrCreateArrayPrototype(JSContext *cx, Handle<GlobalObject*> global) { |
|
353 if (!ensureConstructor(cx, global, JSProto_Array)) |
|
354 return nullptr; |
|
355 return &global->getPrototype(JSProto_Array).toObject(); |
|
356 } |
|
357 |
|
358 JSObject *maybeGetArrayPrototype() { |
|
359 if (arrayClassInitialized()) |
|
360 return &getPrototype(JSProto_Array).toObject(); |
|
361 return nullptr; |
|
362 } |
|
363 |
|
364 static JSObject *getOrCreateBooleanPrototype(JSContext *cx, Handle<GlobalObject*> global) { |
|
365 if (!ensureConstructor(cx, global, JSProto_Boolean)) |
|
366 return nullptr; |
|
367 return &global->getPrototype(JSProto_Boolean).toObject(); |
|
368 } |
|
369 |
|
370 static JSObject *getOrCreateNumberPrototype(JSContext *cx, Handle<GlobalObject*> global) { |
|
371 if (!ensureConstructor(cx, global, JSProto_Number)) |
|
372 return nullptr; |
|
373 return &global->getPrototype(JSProto_Number).toObject(); |
|
374 } |
|
375 |
|
376 static JSObject *getOrCreateStringPrototype(JSContext *cx, Handle<GlobalObject*> global) { |
|
377 if (!ensureConstructor(cx, global, JSProto_String)) |
|
378 return nullptr; |
|
379 return &global->getPrototype(JSProto_String).toObject(); |
|
380 } |
|
381 |
|
382 static JSObject *getOrCreateRegExpPrototype(JSContext *cx, Handle<GlobalObject*> global) { |
|
383 if (!ensureConstructor(cx, global, JSProto_RegExp)) |
|
384 return nullptr; |
|
385 return &global->getPrototype(JSProto_RegExp).toObject(); |
|
386 } |
|
387 |
|
388 JSObject *maybeGetRegExpPrototype() { |
|
389 if (regexpClassInitialized()) |
|
390 return &getPrototype(JSProto_RegExp).toObject(); |
|
391 return nullptr; |
|
392 } |
|
393 |
|
394 static JSObject *getOrCreateArrayBufferPrototype(JSContext *cx, Handle<GlobalObject*> global) { |
|
395 if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) |
|
396 return nullptr; |
|
397 return &global->getPrototype(JSProto_ArrayBuffer).toObject(); |
|
398 } |
|
399 |
|
400 JSObject *getOrCreateSharedArrayBufferPrototype(JSContext *cx, Handle<GlobalObject*> global) { |
|
401 if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer)) |
|
402 return nullptr; |
|
403 return &global->getPrototype(JSProto_SharedArrayBuffer).toObject(); |
|
404 } |
|
405 |
|
406 static JSObject *getOrCreateCustomErrorPrototype(JSContext *cx, |
|
407 Handle<GlobalObject*> global, |
|
408 JSExnType exnType) |
|
409 { |
|
410 JSProtoKey key = GetExceptionProtoKey(exnType); |
|
411 if (!ensureConstructor(cx, global, key)) |
|
412 return nullptr; |
|
413 return &global->getPrototype(key).toObject(); |
|
414 } |
|
415 |
|
416 JSObject *getOrCreateIntlObject(JSContext *cx) { |
|
417 return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Intl, initIntlObject); |
|
418 } |
|
419 |
|
420 JSObject *getOrCreateTypedObjectModule(JSContext *cx) { |
|
421 return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_TypedObject, initTypedObjectModule); |
|
422 } |
|
423 |
|
424 void setFloat32x4TypeDescr(JSObject &obj) { |
|
425 JS_ASSERT(getSlotRef(FLOAT32X4_TYPE_DESCR).isUndefined()); |
|
426 setSlot(FLOAT32X4_TYPE_DESCR, ObjectValue(obj)); |
|
427 } |
|
428 |
|
429 JSObject &float32x4TypeDescr() { |
|
430 JS_ASSERT(getSlotRef(FLOAT32X4_TYPE_DESCR).isObject()); |
|
431 return getSlotRef(FLOAT32X4_TYPE_DESCR).toObject(); |
|
432 } |
|
433 |
|
434 void setInt32x4TypeDescr(JSObject &obj) { |
|
435 JS_ASSERT(getSlotRef(INT32X4_TYPE_DESCR).isUndefined()); |
|
436 setSlot(INT32X4_TYPE_DESCR, ObjectValue(obj)); |
|
437 } |
|
438 |
|
439 JSObject &int32x4TypeDescr() { |
|
440 JS_ASSERT(getSlotRef(INT32X4_TYPE_DESCR).isObject()); |
|
441 return getSlotRef(INT32X4_TYPE_DESCR).toObject(); |
|
442 } |
|
443 |
|
444 TypedObjectModuleObject &getTypedObjectModule() const; |
|
445 |
|
446 JSObject *getIteratorPrototype() { |
|
447 return &getPrototype(JSProto_Iterator).toObject(); |
|
448 } |
|
449 |
|
450 JSObject *getOrCreateCollatorPrototype(JSContext *cx) { |
|
451 return getOrCreateObject(cx, COLLATOR_PROTO, initCollatorProto); |
|
452 } |
|
453 |
|
454 JSObject *getOrCreateNumberFormatPrototype(JSContext *cx) { |
|
455 return getOrCreateObject(cx, NUMBER_FORMAT_PROTO, initNumberFormatProto); |
|
456 } |
|
457 |
|
458 JSObject *getOrCreateDateTimeFormatPrototype(JSContext *cx) { |
|
459 return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initDateTimeFormatProto); |
|
460 } |
|
461 |
|
462 private: |
|
463 typedef bool (*ObjectInitOp)(JSContext *cx, Handle<GlobalObject*> global); |
|
464 |
|
465 JSObject *getOrCreateObject(JSContext *cx, unsigned slot, ObjectInitOp init) { |
|
466 Value v = getSlotRef(slot); |
|
467 if (v.isObject()) |
|
468 return &v.toObject(); |
|
469 Rooted<GlobalObject*> self(cx, this); |
|
470 if (!init(cx, self)) |
|
471 return nullptr; |
|
472 return &self->getSlot(slot).toObject(); |
|
473 } |
|
474 |
|
475 public: |
|
476 static JSObject *getOrCreateIteratorPrototype(JSContext *cx, |
|
477 Handle<GlobalObject*> global) |
|
478 { |
|
479 if (!ensureConstructor(cx, global, JSProto_Iterator)) |
|
480 return nullptr; |
|
481 return &global->getSlot(APPLICATION_SLOTS + JSProto_LIMIT + JSProto_Iterator).toObject(); |
|
482 } |
|
483 |
|
484 static JSObject *getOrCreateArrayIteratorPrototype(JSContext *cx, |
|
485 Handle<GlobalObject*> global) |
|
486 { |
|
487 if (!ensureConstructor(cx, global, JSProto_Iterator)) |
|
488 return nullptr; |
|
489 return &global->getSlot(ARRAY_ITERATOR_PROTO).toObject(); |
|
490 } |
|
491 |
|
492 static JSObject *getOrCreateStringIteratorPrototype(JSContext *cx, |
|
493 Handle<GlobalObject*> global) |
|
494 { |
|
495 if (!ensureConstructor(cx, global, JSProto_Iterator)) |
|
496 return nullptr; |
|
497 return &global->getSlot(STRING_ITERATOR_PROTO).toObject(); |
|
498 } |
|
499 |
|
500 static JSObject *getOrCreateLegacyGeneratorObjectPrototype(JSContext *cx, |
|
501 Handle<GlobalObject*> global) |
|
502 { |
|
503 if (!ensureConstructor(cx, global, JSProto_Iterator)) |
|
504 return nullptr; |
|
505 return &global->getSlot(LEGACY_GENERATOR_OBJECT_PROTO).toObject(); |
|
506 } |
|
507 |
|
508 static JSObject *getOrCreateStarGeneratorObjectPrototype(JSContext *cx, |
|
509 Handle<GlobalObject*> global) |
|
510 { |
|
511 if (!ensureConstructor(cx, global, JSProto_Iterator)) |
|
512 return nullptr; |
|
513 return &global->getSlot(STAR_GENERATOR_OBJECT_PROTO).toObject(); |
|
514 } |
|
515 |
|
516 static JSObject *getOrCreateStarGeneratorFunctionPrototype(JSContext *cx, |
|
517 Handle<GlobalObject*> global) |
|
518 { |
|
519 if (!ensureConstructor(cx, global, JSProto_Iterator)) |
|
520 return nullptr; |
|
521 return &global->getSlot(APPLICATION_SLOTS + JSProto_LIMIT + JSProto_GeneratorFunction).toObject(); |
|
522 } |
|
523 |
|
524 static JSObject *getOrCreateStarGeneratorFunction(JSContext *cx, |
|
525 Handle<GlobalObject*> global) |
|
526 { |
|
527 if (!ensureConstructor(cx, global, JSProto_Iterator)) |
|
528 return nullptr; |
|
529 return &global->getSlot(APPLICATION_SLOTS + JSProto_GeneratorFunction).toObject(); |
|
530 } |
|
531 |
|
532 static JSObject *getOrCreateMapIteratorPrototype(JSContext *cx, |
|
533 Handle<GlobalObject*> global) |
|
534 { |
|
535 return global->getOrCreateObject(cx, MAP_ITERATOR_PROTO, initMapIteratorProto); |
|
536 } |
|
537 |
|
538 static JSObject *getOrCreateSetIteratorPrototype(JSContext *cx, |
|
539 Handle<GlobalObject*> global) |
|
540 { |
|
541 return global->getOrCreateObject(cx, SET_ITERATOR_PROTO, initSetIteratorProto); |
|
542 } |
|
543 |
|
544 JSObject *getOrCreateDataViewPrototype(JSContext *cx) { |
|
545 Rooted<GlobalObject*> self(cx, this); |
|
546 if (!ensureConstructor(cx, self, JSProto_DataView)) |
|
547 return nullptr; |
|
548 return &self->getPrototype(JSProto_DataView).toObject(); |
|
549 } |
|
550 |
|
551 JSObject *intrinsicsHolder() { |
|
552 JS_ASSERT(!getSlot(INTRINSICS).isUndefined()); |
|
553 return &getSlot(INTRINSICS).toObject(); |
|
554 } |
|
555 |
|
556 bool maybeGetIntrinsicValue(jsid id, Value *vp) { |
|
557 JSObject *holder = intrinsicsHolder(); |
|
558 |
|
559 if (Shape *shape = holder->nativeLookupPure(id)) { |
|
560 *vp = holder->getSlot(shape->slot()); |
|
561 return true; |
|
562 } |
|
563 return false; |
|
564 } |
|
565 bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) { |
|
566 return maybeGetIntrinsicValue(NameToId(name), vp); |
|
567 } |
|
568 |
|
569 static bool getIntrinsicValue(JSContext *cx, Handle<GlobalObject*> global, |
|
570 HandlePropertyName name, MutableHandleValue value) |
|
571 { |
|
572 if (global->maybeGetIntrinsicValue(name, value.address())) |
|
573 return true; |
|
574 if (!cx->runtime()->cloneSelfHostedValue(cx, name, value)) |
|
575 return false; |
|
576 RootedId id(cx, NameToId(name)); |
|
577 return global->addIntrinsicValue(cx, id, value); |
|
578 } |
|
579 |
|
580 bool addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value); |
|
581 |
|
582 bool setIntrinsicValue(JSContext *cx, PropertyName *name, HandleValue value) { |
|
583 #ifdef DEBUG |
|
584 RootedObject self(cx, this); |
|
585 JS_ASSERT(cx->runtime()->isSelfHostingGlobal(self)); |
|
586 #endif |
|
587 RootedObject holder(cx, intrinsicsHolder()); |
|
588 RootedValue valCopy(cx, value); |
|
589 return JSObject::setProperty(cx, holder, holder, name, &valCopy, false); |
|
590 } |
|
591 |
|
592 bool getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, HandleAtom name, |
|
593 unsigned nargs, MutableHandleValue funVal); |
|
594 |
|
595 RegExpStatics *getRegExpStatics() const { |
|
596 JSObject &resObj = getSlot(REGEXP_STATICS).toObject(); |
|
597 return static_cast<RegExpStatics *>(resObj.getPrivate(/* nfixed = */ 1)); |
|
598 } |
|
599 |
|
600 JSObject *getThrowTypeError() const { |
|
601 JS_ASSERT(functionObjectClassesInitialized()); |
|
602 return &getSlot(THROWTYPEERROR).toObject(); |
|
603 } |
|
604 |
|
605 Value createDataViewForThis() const { |
|
606 JS_ASSERT(dataViewClassInitialized()); |
|
607 return getSlot(CREATE_DATAVIEW_FOR_THIS); |
|
608 } |
|
609 |
|
610 template<typename T> |
|
611 inline Value createArrayFromBuffer() const; |
|
612 |
|
613 Value protoGetter() const { |
|
614 JS_ASSERT(functionObjectClassesInitialized()); |
|
615 return getSlot(PROTO_GETTER); |
|
616 } |
|
617 |
|
618 static bool isRuntimeCodeGenEnabled(JSContext *cx, Handle<GlobalObject*> global); |
|
619 |
|
620 // Warn about use of the deprecated watch/unwatch functions in the global |
|
621 // in which |obj| was created, if no prior warning was given. |
|
622 static bool warnOnceAboutWatch(JSContext *cx, HandleObject obj) { |
|
623 // Temporarily disabled until we've provided a watch/unwatch workaround for |
|
624 // debuggers like Firebug (bug 934669). |
|
625 //return warnOnceAbout(cx, obj, WARNED_WATCH_DEPRECATED, JSMSG_OBJECT_WATCH_DEPRECATED); |
|
626 return true; |
|
627 } |
|
628 |
|
629 // Warn about use of the given __proto__ setter to attempt to mutate an |
|
630 // object's [[Prototype]], if no prior warning was given. |
|
631 static bool warnOnceAboutPrototypeMutation(JSContext *cx, HandleObject protoSetter) { |
|
632 return warnOnceAbout(cx, protoSetter, WARNED_PROTO_SETTING_SLOW, JSMSG_PROTO_SETTING_SLOW); |
|
633 } |
|
634 |
|
635 static bool getOrCreateEval(JSContext *cx, Handle<GlobalObject*> global, |
|
636 MutableHandleObject eval); |
|
637 |
|
638 // Infallibly test whether the given value is the eval function for this global. |
|
639 bool valueIsEval(Value val); |
|
640 |
|
641 // Implemented in jsiter.cpp. |
|
642 static bool initIteratorClasses(JSContext *cx, Handle<GlobalObject*> global); |
|
643 |
|
644 // Implemented in builtin/MapObject.cpp. |
|
645 static bool initMapIteratorProto(JSContext *cx, Handle<GlobalObject*> global); |
|
646 static bool initSetIteratorProto(JSContext *cx, Handle<GlobalObject*> global); |
|
647 |
|
648 // Implemented in Intl.cpp. |
|
649 static bool initIntlObject(JSContext *cx, Handle<GlobalObject*> global); |
|
650 static bool initCollatorProto(JSContext *cx, Handle<GlobalObject*> global); |
|
651 static bool initNumberFormatProto(JSContext *cx, Handle<GlobalObject*> global); |
|
652 static bool initDateTimeFormatProto(JSContext *cx, Handle<GlobalObject*> global); |
|
653 |
|
654 // Implemented in builtin/TypedObject.cpp |
|
655 static bool initTypedObjectModule(JSContext *cx, Handle<GlobalObject*> global); |
|
656 |
|
657 static bool initStandardClasses(JSContext *cx, Handle<GlobalObject*> global); |
|
658 |
|
659 typedef js::Vector<js::Debugger *, 0, js::SystemAllocPolicy> DebuggerVector; |
|
660 |
|
661 /* |
|
662 * The collection of Debugger objects debugging this global. If this global |
|
663 * is not a debuggee, this returns either nullptr or an empty vector. |
|
664 */ |
|
665 DebuggerVector *getDebuggers(); |
|
666 |
|
667 /* |
|
668 * The same, but create the empty vector if one does not already |
|
669 * exist. Returns nullptr only on OOM. |
|
670 */ |
|
671 static DebuggerVector *getOrCreateDebuggers(JSContext *cx, Handle<GlobalObject*> global); |
|
672 |
|
673 inline JSObject *getForOfPICObject() { |
|
674 Value forOfPIC = getReservedSlot(FOR_OF_PIC_CHAIN); |
|
675 if (forOfPIC.isUndefined()) |
|
676 return nullptr; |
|
677 return &forOfPIC.toObject(); |
|
678 } |
|
679 static JSObject *getOrCreateForOfPICObject(JSContext *cx, Handle<GlobalObject*> global); |
|
680 |
|
681 static bool addDebugger(JSContext *cx, Handle<GlobalObject*> global, Debugger *dbg); |
|
682 }; |
|
683 |
|
684 template<> |
|
685 inline void |
|
686 GlobalObject::setCreateArrayFromBuffer<uint8_t>(Handle<JSFunction*> fun) |
|
687 { |
|
688 setCreateArrayFromBufferHelper(FROM_BUFFER_UINT8, fun); |
|
689 } |
|
690 |
|
691 template<> |
|
692 inline void |
|
693 GlobalObject::setCreateArrayFromBuffer<int8_t>(Handle<JSFunction*> fun) |
|
694 { |
|
695 setCreateArrayFromBufferHelper(FROM_BUFFER_INT8, fun); |
|
696 } |
|
697 |
|
698 template<> |
|
699 inline void |
|
700 GlobalObject::setCreateArrayFromBuffer<uint16_t>(Handle<JSFunction*> fun) |
|
701 { |
|
702 setCreateArrayFromBufferHelper(FROM_BUFFER_UINT16, fun); |
|
703 } |
|
704 |
|
705 template<> |
|
706 inline void |
|
707 GlobalObject::setCreateArrayFromBuffer<int16_t>(Handle<JSFunction*> fun) |
|
708 { |
|
709 setCreateArrayFromBufferHelper(FROM_BUFFER_INT16, fun); |
|
710 } |
|
711 |
|
712 template<> |
|
713 inline void |
|
714 GlobalObject::setCreateArrayFromBuffer<uint32_t>(Handle<JSFunction*> fun) |
|
715 { |
|
716 setCreateArrayFromBufferHelper(FROM_BUFFER_UINT32, fun); |
|
717 } |
|
718 |
|
719 template<> |
|
720 inline void |
|
721 GlobalObject::setCreateArrayFromBuffer<int32_t>(Handle<JSFunction*> fun) |
|
722 { |
|
723 setCreateArrayFromBufferHelper(FROM_BUFFER_INT32, fun); |
|
724 } |
|
725 |
|
726 template<> |
|
727 inline void |
|
728 GlobalObject::setCreateArrayFromBuffer<float>(Handle<JSFunction*> fun) |
|
729 { |
|
730 setCreateArrayFromBufferHelper(FROM_BUFFER_FLOAT32, fun); |
|
731 } |
|
732 |
|
733 template<> |
|
734 inline void |
|
735 GlobalObject::setCreateArrayFromBuffer<double>(Handle<JSFunction*> fun) |
|
736 { |
|
737 setCreateArrayFromBufferHelper(FROM_BUFFER_FLOAT64, fun); |
|
738 } |
|
739 |
|
740 template<> |
|
741 inline void |
|
742 GlobalObject::setCreateArrayFromBuffer<uint8_clamped>(Handle<JSFunction*> fun) |
|
743 { |
|
744 setCreateArrayFromBufferHelper(FROM_BUFFER_UINT8CLAMPED, fun); |
|
745 } |
|
746 |
|
747 template<> |
|
748 inline Value |
|
749 GlobalObject::createArrayFromBuffer<uint8_t>() const |
|
750 { |
|
751 return createArrayFromBufferHelper(FROM_BUFFER_UINT8); |
|
752 } |
|
753 |
|
754 template<> |
|
755 inline Value |
|
756 GlobalObject::createArrayFromBuffer<int8_t>() const |
|
757 { |
|
758 return createArrayFromBufferHelper(FROM_BUFFER_INT8); |
|
759 } |
|
760 |
|
761 template<> |
|
762 inline Value |
|
763 GlobalObject::createArrayFromBuffer<uint16_t>() const |
|
764 { |
|
765 return createArrayFromBufferHelper(FROM_BUFFER_UINT16); |
|
766 } |
|
767 |
|
768 template<> |
|
769 inline Value |
|
770 GlobalObject::createArrayFromBuffer<int16_t>() const |
|
771 { |
|
772 return createArrayFromBufferHelper(FROM_BUFFER_INT16); |
|
773 } |
|
774 |
|
775 template<> |
|
776 inline Value |
|
777 GlobalObject::createArrayFromBuffer<uint32_t>() const |
|
778 { |
|
779 return createArrayFromBufferHelper(FROM_BUFFER_UINT32); |
|
780 } |
|
781 |
|
782 template<> |
|
783 inline Value |
|
784 GlobalObject::createArrayFromBuffer<int32_t>() const |
|
785 { |
|
786 return createArrayFromBufferHelper(FROM_BUFFER_INT32); |
|
787 } |
|
788 |
|
789 template<> |
|
790 inline Value |
|
791 GlobalObject::createArrayFromBuffer<float>() const |
|
792 { |
|
793 return createArrayFromBufferHelper(FROM_BUFFER_FLOAT32); |
|
794 } |
|
795 |
|
796 template<> |
|
797 inline Value |
|
798 GlobalObject::createArrayFromBuffer<double>() const |
|
799 { |
|
800 return createArrayFromBufferHelper(FROM_BUFFER_FLOAT64); |
|
801 } |
|
802 |
|
803 template<> |
|
804 inline Value |
|
805 GlobalObject::createArrayFromBuffer<uint8_clamped>() const |
|
806 { |
|
807 return createArrayFromBufferHelper(FROM_BUFFER_UINT8CLAMPED); |
|
808 } |
|
809 |
|
810 /* |
|
811 * Define ctor.prototype = proto as non-enumerable, non-configurable, and |
|
812 * non-writable; define proto.constructor = ctor as non-enumerable but |
|
813 * configurable and writable. |
|
814 */ |
|
815 extern bool |
|
816 LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor, JSObject *proto); |
|
817 |
|
818 /* |
|
819 * Define properties, then functions, on the object, then brand for tracing |
|
820 * benefits. |
|
821 */ |
|
822 extern bool |
|
823 DefinePropertiesAndBrand(JSContext *cx, JSObject *obj, |
|
824 const JSPropertySpec *ps, const JSFunctionSpec *fs); |
|
825 |
|
826 typedef HashSet<GlobalObject *, DefaultHasher<GlobalObject *>, SystemAllocPolicy> GlobalObjectSet; |
|
827 |
|
828 /* |
|
829 * Convenience templates to generic constructor and prototype creation functions |
|
830 * for ClassSpecs. |
|
831 */ |
|
832 |
|
833 template<JSNative ctor, size_t atomOffset, unsigned length> |
|
834 JSObject * |
|
835 GenericCreateConstructor(JSContext *cx, JSProtoKey key) |
|
836 { |
|
837 JSAtom *atom = AtomStateOffsetToName(cx->names(), atomOffset); |
|
838 return cx->global()->createConstructor(cx, ctor, atom, length); |
|
839 } |
|
840 |
|
841 template<const Class *clasp> |
|
842 JSObject * |
|
843 GenericCreatePrototype(JSContext *cx, JSProtoKey key) |
|
844 { |
|
845 return cx->global()->createBlankPrototype(cx, clasp); |
|
846 } |
|
847 |
|
848 } // namespace js |
|
849 |
|
850 template<> |
|
851 inline bool |
|
852 JSObject::is<js::GlobalObject>() const |
|
853 { |
|
854 return !!(getClass()->flags & JSCLASS_IS_GLOBAL); |
|
855 } |
|
856 |
|
857 #endif /* vm_GlobalObject_h */ |