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 Mozilla Communicator client code, released
18 : * March 31, 1998.
19 : *
20 : * The Initial Developer of the Original Code is
21 : * Netscape Communications Corporation.
22 : * Portions created by the Initial Developer are Copyright (C) 1998
23 : * the Initial Developer. All Rights Reserved.
24 : *
25 : * Contributor(s):
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 jsobj_h___
42 : #define jsobj_h___
43 :
44 : /*
45 : * JS object definitions.
46 : *
47 : * A JS object consists of a possibly-shared object descriptor containing
48 : * ordered property names, called the map; and a dense vector of property
49 : * values, called slots. The map/slot pointer pair is GC'ed, while the map
50 : * is reference counted and the slot vector is malloc'ed.
51 : */
52 : #include "jsapi.h"
53 : #include "jsatom.h"
54 : #include "jsclass.h"
55 : #include "jsfriendapi.h"
56 : #include "jsinfer.h"
57 : #include "jshash.h"
58 : #include "jspubtd.h"
59 : #include "jsprvtd.h"
60 : #include "jslock.h"
61 : #include "jscell.h"
62 :
63 : #include "gc/Barrier.h"
64 :
65 : #include "vm/ObjectImpl.h"
66 : #include "vm/String.h"
67 :
68 : namespace js {
69 :
70 : class AutoPropDescArrayRooter;
71 : class ProxyHandler;
72 : class CallObject;
73 : struct GCMarker;
74 : struct NativeIterator;
75 :
76 : namespace mjit { class Compiler; }
77 :
78 : static inline PropertyOp
79 299145 : CastAsPropertyOp(JSObject *object)
80 : {
81 299145 : return JS_DATA_TO_FUNC_PTR(PropertyOp, object);
82 : }
83 :
84 : static inline StrictPropertyOp
85 298947 : CastAsStrictPropertyOp(JSObject *object)
86 : {
87 298947 : return JS_DATA_TO_FUNC_PTR(StrictPropertyOp, object);
88 : }
89 :
90 : inline JSObject *
91 2036 : CastAsObject(PropertyOp op)
92 : {
93 2036 : return JS_FUNC_TO_DATA_PTR(JSObject *, op);
94 : }
95 :
96 : inline JSObject *
97 72 : CastAsObject(StrictPropertyOp op)
98 : {
99 72 : return JS_FUNC_TO_DATA_PTR(JSObject *, op);
100 : }
101 :
102 : inline Value
103 2009 : CastAsObjectJsval(PropertyOp op)
104 : {
105 2009 : return ObjectOrNullValue(CastAsObject(op));
106 : }
107 :
108 : inline Value
109 63 : CastAsObjectJsval(StrictPropertyOp op)
110 : {
111 63 : return ObjectOrNullValue(CastAsObject(op));
112 : }
113 :
114 : /*
115 : * JSPropertySpec uses JSAPI JSPropertyOp and JSStrictPropertyOp in function
116 : * signatures, but with JSPROP_NATIVE_ACCESSORS the actual values must be
117 : * JSNatives. To avoid widespread casting, have JS_PSG and JS_PSGS perform
118 : * type-safe casts.
119 : */
120 : #define JS_PSG(name,getter,flags) \
121 : {name, 0, (flags) | JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS, \
122 : (JSPropertyOp)getter, NULL}
123 : #define JS_PSGS(name,getter,setter,flags) \
124 : {name, 0, (flags) | JSPROP_SHARED | JSPROP_NATIVE_ACCESSORS, \
125 : (JSPropertyOp)getter, (JSStrictPropertyOp)setter}
126 : #define JS_PS_END {0, 0, 0, 0, 0}
127 :
128 : /******************************************************************************/
129 :
130 : /*
131 : * A representation of ECMA-262 ed. 5's internal Property Descriptor data
132 : * structure.
133 : */
134 301709 : struct PropDesc {
135 : /*
136 : * Original object from which this descriptor derives, passed through for
137 : * the benefit of proxies.
138 : */
139 : js::Value pd;
140 :
141 : js::Value value, get, set;
142 :
143 : /* Property descriptor boolean fields. */
144 : uint8_t attrs;
145 :
146 : /* Bits indicating which values are set. */
147 : bool hasGet : 1;
148 : bool hasSet : 1;
149 : bool hasValue : 1;
150 : bool hasWritable : 1;
151 : bool hasEnumerable : 1;
152 : bool hasConfigurable : 1;
153 :
154 : friend class js::AutoPropDescArrayRooter;
155 :
156 : PropDesc();
157 :
158 : /*
159 : * 8.10.5 ToPropertyDescriptor(Obj)
160 : *
161 : * If checkAccessors is false, skip steps 7.b and 8.b, which throw a
162 : * TypeError if .get or .set is neither a callable object nor undefined.
163 : *
164 : * (DebuggerObject_defineProperty uses this: the .get and .set properties
165 : * are expected to be Debugger.Object wrappers of functions, which are not
166 : * themselves callable.)
167 : */
168 : bool initialize(JSContext* cx, const js::Value &v, bool checkAccessors=true);
169 :
170 : /*
171 : * 8.10.4 FromPropertyDescriptor(Desc)
172 : *
173 : * initFromPropertyDescriptor sets pd to undefined and populates all the
174 : * other fields of this PropDesc from desc.
175 : *
176 : * makeObject populates pd based on the other fields of *this, creating a
177 : * new property descriptor JSObject and defining properties on it.
178 : */
179 : void initFromPropertyDescriptor(const PropertyDescriptor &desc);
180 : bool makeObject(JSContext *cx);
181 :
182 : /* 8.10.1 IsAccessorDescriptor(desc) */
183 594893 : bool isAccessorDescriptor() const {
184 594893 : return hasGet || hasSet;
185 : }
186 :
187 : /* 8.10.2 IsDataDescriptor(desc) */
188 299746 : bool isDataDescriptor() const {
189 299746 : return hasValue || hasWritable;
190 : }
191 :
192 : /* 8.10.3 IsGenericDescriptor(desc) */
193 297775 : bool isGenericDescriptor() const {
194 297775 : return !isAccessorDescriptor() && !isDataDescriptor();
195 : }
196 :
197 108 : bool configurable() const {
198 108 : return (attrs & JSPROP_PERMANENT) == 0;
199 : }
200 :
201 9 : bool enumerable() const {
202 9 : return (attrs & JSPROP_ENUMERATE) != 0;
203 : }
204 :
205 27 : bool writable() const {
206 27 : return (attrs & JSPROP_READONLY) == 0;
207 : }
208 :
209 298659 : JSObject* getterObject() const {
210 298659 : return get.isUndefined() ? NULL : &get.toObject();
211 : }
212 298785 : JSObject* setterObject() const {
213 298785 : return set.isUndefined() ? NULL : &set.toObject();
214 : }
215 :
216 9 : const js::Value &getterValue() const {
217 9 : return get;
218 : }
219 153 : const js::Value &setterValue() const {
220 153 : return set;
221 : }
222 :
223 298659 : PropertyOp getter() const {
224 298659 : return js::CastAsPropertyOp(getterObject());
225 : }
226 298785 : StrictPropertyOp setter() const {
227 298785 : return js::CastAsStrictPropertyOp(setterObject());
228 : }
229 :
230 : /*
231 : * Throw a TypeError if a getter/setter is present and is neither callable
232 : * nor undefined. These methods do exactly the type checks that are skipped
233 : * by passing false as the checkAccessors parameter of initialize.
234 : */
235 : inline bool checkGetter(JSContext *cx);
236 : inline bool checkSetter(JSContext *cx);
237 : };
238 :
239 : typedef Vector<PropDesc, 1> PropDescArray;
240 :
241 : } /* namespace js */
242 :
243 : /*
244 : * On success, and if id was found, return true with *objp non-null and with a
245 : * property of *objp stored in *propp. If successful but id was not found,
246 : * return true with both *objp and *propp null.
247 : */
248 : extern JS_FRIEND_API(JSBool)
249 : js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
250 : JSProperty **propp);
251 :
252 : namespace js {
253 :
254 : inline bool
255 : LookupProperty(JSContext *cx, JSObject *obj, PropertyName *name,
256 : JSObject **objp, JSProperty **propp)
257 : {
258 : return js_LookupProperty(cx, obj, ATOM_TO_JSID(name), objp, propp);
259 : }
260 :
261 : }
262 :
263 : extern JS_FRIEND_API(JSBool)
264 : js_LookupElement(JSContext *cx, JSObject *obj, uint32_t index,
265 : JSObject **objp, JSProperty **propp);
266 :
267 : extern JSBool
268 : js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value *value,
269 : JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
270 :
271 : extern JSBool
272 : js_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, const js::Value *value,
273 : JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
274 :
275 : extern JSBool
276 : js_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, js::Value *vp);
277 :
278 : extern JSBool
279 : js_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t, js::Value *vp);
280 :
281 : inline JSBool
282 1617 : js_GetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp)
283 : {
284 1617 : return js_GetProperty(cx, obj, obj, id, vp);
285 : }
286 :
287 : inline JSBool
288 : js_GetElement(JSContext *cx, JSObject *obj, uint32_t index, js::Value *vp)
289 : {
290 : return js_GetElement(cx, obj, obj, index, vp);
291 : }
292 :
293 : namespace js {
294 :
295 : extern JSBool
296 : GetPropertyDefault(JSContext *cx, JSObject *obj, jsid id, const Value &def, Value *vp);
297 :
298 : } /* namespace js */
299 :
300 : extern JSBool
301 : js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, unsigned defineHow,
302 : js::Value *vp, JSBool strict);
303 :
304 : namespace js {
305 :
306 : inline bool
307 : SetPropertyHelper(JSContext *cx, JSObject *obj, PropertyName *name, unsigned defineHow,
308 : Value *vp, JSBool strict)
309 : {
310 : return !!js_SetPropertyHelper(cx, obj, ATOM_TO_JSID(name), defineHow, vp, strict);
311 : }
312 :
313 : } /* namespace js */
314 :
315 : extern JSBool
316 : js_SetElementHelper(JSContext *cx, JSObject *obj, uint32_t index, unsigned defineHow,
317 : js::Value *vp, JSBool strict);
318 :
319 : extern JSBool
320 : js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp);
321 :
322 : extern JSBool
323 : js_GetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp);
324 :
325 : extern JSBool
326 : js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp);
327 :
328 : extern JSBool
329 : js_SetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp);
330 :
331 : extern JSBool
332 : js_DeleteProperty(JSContext *cx, JSObject *obj, js::PropertyName *name, js::Value *rval, JSBool strict);
333 :
334 : extern JSBool
335 : js_DeleteElement(JSContext *cx, JSObject *obj, uint32_t index, js::Value *rval, JSBool strict);
336 :
337 : extern JSBool
338 : js_DeleteSpecial(JSContext *cx, JSObject *obj, js::SpecialId sid, js::Value *rval, JSBool strict);
339 :
340 : extern JSBool
341 : js_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, js::Value *rval, JSBool strict);
342 :
343 : extern JSType
344 : js_TypeOf(JSContext *cx, JSObject *obj);
345 :
346 : namespace js {
347 :
348 : /* ES5 8.12.8. */
349 : extern JSBool
350 : DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp);
351 :
352 : extern Class ArrayClass;
353 : extern Class ArrayBufferClass;
354 : extern Class BlockClass;
355 : extern Class BooleanClass;
356 : extern Class CallableObjectClass;
357 : extern Class DateClass;
358 : extern Class ErrorClass;
359 : extern Class ElementIteratorClass;
360 : extern Class GeneratorClass;
361 : extern Class IteratorClass;
362 : extern Class JSONClass;
363 : extern Class MathClass;
364 : extern Class NumberClass;
365 : extern Class NormalArgumentsObjectClass;
366 : extern Class ObjectClass;
367 : extern Class ProxyClass;
368 : extern Class RegExpClass;
369 : extern Class RegExpStaticsClass;
370 : extern Class SlowArrayClass;
371 : extern Class StopIterationClass;
372 : extern Class StringClass;
373 : extern Class StrictArgumentsObjectClass;
374 : extern Class WeakMapClass;
375 : extern Class WithClass;
376 : extern Class XMLFilterClass;
377 :
378 : class ArgumentsObject;
379 : class BlockObject;
380 : class BooleanObject;
381 : class ClonedBlockObject;
382 : class DeclEnvObject;
383 : class ElementIteratorObject;
384 : class GlobalObject;
385 : class NestedScopeObject;
386 : class NewObjectCache;
387 : class NormalArgumentsObject;
388 : class NumberObject;
389 : class ScopeObject;
390 : class StaticBlockObject;
391 : class StrictArgumentsObject;
392 : class StringObject;
393 : class RegExpObject;
394 : class WithObject;
395 :
396 : } /* namespace js */
397 :
398 : /*
399 : * The public interface for an object.
400 : *
401 : * Implementation of the underlying structure occurs in ObjectImpl, from which
402 : * this struct inherits. This inheritance is currently public, but it will
403 : * eventually be made protected. For full details, see vm/ObjectImpl.{h,cpp}.
404 : *
405 : * The JSFunction struct is an extension of this struct allocated from a larger
406 : * GC size-class.
407 : */
408 : struct JSObject : public js::ObjectImpl
409 3385370 : {
410 : private:
411 : friend struct js::Shape;
412 : friend struct js::GCMarker;
413 : friend class js::NewObjectCache;
414 :
415 : /* Make the type object to use for LAZY_TYPE objects. */
416 : void makeLazyType(JSContext *cx);
417 :
418 : public:
419 : /*
420 : * Update the last property, keeping the number of allocated slots in sync
421 : * with the object's new slot span.
422 : */
423 : bool setLastProperty(JSContext *cx, const js::Shape *shape);
424 :
425 : /* As above, but does not change the slot span. */
426 : inline void setLastPropertyInfallible(const js::Shape *shape);
427 :
428 : /* Make a non-array object with the specified initial state. */
429 : static inline JSObject *create(JSContext *cx,
430 : js::gc::AllocKind kind,
431 : js::HandleShape shape,
432 : js::HandleTypeObject type,
433 : js::HeapSlot *slots);
434 :
435 : /* Make a dense array object with the specified initial state. */
436 : static inline JSObject *createDenseArray(JSContext *cx,
437 : js::gc::AllocKind kind,
438 : js::HandleShape shape,
439 : js::HandleTypeObject type,
440 : uint32_t length);
441 :
442 : /*
443 : * Remove the last property of an object, provided that it is safe to do so
444 : * (the shape and previous shape do not carry conflicting information about
445 : * the object itself).
446 : */
447 : inline void removeLastProperty(JSContext *cx);
448 : inline bool canRemoveLastProperty();
449 :
450 : /*
451 : * Update the slot span directly for a dictionary object, and allocate
452 : * slots to cover the new span if necessary.
453 : */
454 : bool setSlotSpan(JSContext *cx, uint32_t span);
455 :
456 : inline bool nativeContains(JSContext *cx, jsid id);
457 : inline bool nativeContains(JSContext *cx, const js::Shape &shape);
458 :
459 : /* Upper bound on the number of elements in an object. */
460 : static const uint32_t NELEMENTS_LIMIT = JS_BIT(28);
461 :
462 : public:
463 : inline bool setDelegate(JSContext *cx);
464 :
465 : inline bool isBoundFunction() const;
466 :
467 : /*
468 : * The meaning of the system object bit is defined by the API client. It is
469 : * set in JS_NewSystemObject and is queried by JS_IsSystemObject, but it
470 : * has no intrinsic meaning to SpiderMonkey.
471 : */
472 : inline bool isSystem() const;
473 : inline bool setSystem(JSContext *cx);
474 :
475 : inline bool hasSpecialEquality() const;
476 :
477 : inline bool watched() const;
478 : inline bool setWatched(JSContext *cx);
479 :
480 : /* See StackFrame::varObj. */
481 : inline bool isVarObj() const;
482 : inline bool setVarObj(JSContext *cx);
483 :
484 : /*
485 : * Objects with an uncacheable proto can have their prototype mutated
486 : * without inducing a shape change on the object. Property cache entries
487 : * and JIT inline caches should not be filled for lookups across prototype
488 : * lookups on the object.
489 : */
490 : inline bool hasUncacheableProto() const;
491 : inline bool setUncacheableProto(JSContext *cx);
492 :
493 286959 : bool generateOwnShape(JSContext *cx, js::Shape *newShape = NULL) {
494 286959 : return replaceWithNewEquivalentShape(cx, lastProperty(), newShape);
495 : }
496 :
497 : private:
498 : js::Shape *replaceWithNewEquivalentShape(JSContext *cx, js::Shape *existingShape,
499 : js::Shape *newShape = NULL);
500 :
501 : enum GenerateShape {
502 : GENERATE_NONE,
503 : GENERATE_SHAPE
504 : };
505 :
506 : bool setFlag(JSContext *cx, /*BaseShape::Flag*/ uint32_t flag,
507 : GenerateShape generateShape = GENERATE_NONE);
508 :
509 : public:
510 : inline bool nativeEmpty() const;
511 :
512 : bool shadowingShapeChange(JSContext *cx, const js::Shape &shape);
513 :
514 : /* Whether there may be indexed properties on this object. */
515 : inline bool isIndexed() const;
516 :
517 : inline uint32_t propertyCount() const;
518 :
519 : inline bool hasPropertyTable() const;
520 :
521 : inline size_t computedSizeOfThisSlotsElements() const;
522 :
523 : inline void sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf,
524 : size_t *slotsSize, size_t *elementsSize,
525 : size_t *miscSize) const;
526 :
527 : static const uint32_t MAX_FIXED_SLOTS = 16;
528 :
529 : public:
530 :
531 : /* Accessors for properties. */
532 :
533 : /* Whether a slot is at a fixed offset from this object. */
534 : inline bool isFixedSlot(size_t slot);
535 :
536 : /* Index into the dynamic slots array to use for a dynamic slot. */
537 : inline size_t dynamicSlotIndex(size_t slot);
538 :
539 : /* Get a raw pointer to the object's properties. */
540 : inline const js::HeapSlot *getRawSlots();
541 :
542 : /*
543 : * Grow or shrink slots immediately before changing the slot span.
544 : * The number of allocated slots is not stored explicitly, and changes to
545 : * the slots must track changes in the slot span.
546 : */
547 : bool growSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount);
548 : void shrinkSlots(JSContext *cx, uint32_t oldCount, uint32_t newCount);
549 :
550 32433901 : bool hasDynamicSlots() const { return slots != NULL; }
551 :
552 : protected:
553 : inline bool updateSlotsForSpan(JSContext *cx, size_t oldSpan, size_t newSpan);
554 :
555 : public:
556 : /*
557 : * Trigger the write barrier on a range of slots that will no longer be
558 : * reachable.
559 : */
560 : inline void prepareSlotRangeForOverwrite(size_t start, size_t end);
561 : inline void prepareElementRangeForOverwrite(size_t start, size_t end);
562 :
563 : void rollbackProperties(JSContext *cx, uint32_t slotSpan);
564 :
565 : inline void nativeSetSlot(unsigned slot, const js::Value &value);
566 : inline void nativeSetSlotWithType(JSContext *cx, const js::Shape *shape, const js::Value &value);
567 :
568 : inline const js::Value &getReservedSlot(unsigned index) const;
569 : inline js::HeapSlot &getReservedSlotRef(unsigned index);
570 : inline void initReservedSlot(unsigned index, const js::Value &v);
571 : inline void setReservedSlot(unsigned index, const js::Value &v);
572 :
573 : /*
574 : * Marks this object as having a singleton type, and leave the type lazy.
575 : * Constructs a new, unique shape for the object.
576 : */
577 : inline bool setSingletonType(JSContext *cx);
578 :
579 : inline js::types::TypeObject *getType(JSContext *cx);
580 :
581 16486827 : const js::HeapPtr<js::types::TypeObject> &typeFromGC() const {
582 : /* Direct field access for use by GC. */
583 16486827 : return type_;
584 : }
585 :
586 : inline void setType(js::types::TypeObject *newType);
587 :
588 : js::types::TypeObject *getNewType(JSContext *cx, JSFunction *fun = NULL);
589 :
590 : #ifdef DEBUG
591 : bool hasNewType(js::types::TypeObject *newType);
592 : #endif
593 :
594 : /*
595 : * Mark an object that has been iterated over and is a singleton. We need
596 : * to recover this information in the object's type information after it
597 : * is purged on GC.
598 : */
599 : inline bool setIteratedSingleton(JSContext *cx);
600 :
601 : /*
602 : * Mark an object as requiring its default 'new' type to have unknown
603 : * properties.
604 : */
605 : bool setNewTypeUnknown(JSContext *cx);
606 :
607 : /* Set a new prototype for an object with a singleton type. */
608 : bool splicePrototype(JSContext *cx, JSObject *proto);
609 :
610 : /*
611 : * For bootstrapping, whether to splice a prototype for Function.prototype
612 : * or the global object.
613 : */
614 : bool shouldSplicePrototype(JSContext *cx);
615 :
616 : /*
617 : * Parents and scope chains.
618 : *
619 : * All script-accessible objects with a NULL parent are global objects,
620 : * and all global objects have a NULL parent. Some builtin objects which
621 : * are not script-accessible also have a NULL parent, such as parser
622 : * created functions for non-compileAndGo scripts.
623 : *
624 : * Except for the non-script-accessible builtins, the global with which an
625 : * object is associated can be reached by following parent links to that
626 : * global (see global()).
627 : *
628 : * The scope chain of an object is the link in the search path when a
629 : * script does a name lookup on a scope object. For JS internal scope
630 : * objects --- Call, DeclEnv and block --- the chain is stored in
631 : * the first fixed slot of the object, and the object's parent is the
632 : * associated global. For other scope objects, the chain is stored in the
633 : * object's parent.
634 : *
635 : * In compileAndGo code, scope chains can contain only internal scope
636 : * objects with a global object at the root as the scope of the outermost
637 : * non-function script. In non-compileAndGo code, the scope of the
638 : * outermost non-function script might not be a global object, and can have
639 : * a mix of other objects above it before the global object is reached.
640 : */
641 :
642 : /* Access the parent link of an object. */
643 : inline JSObject *getParent() const;
644 : bool setParent(JSContext *cx, JSObject *newParent);
645 :
646 : /*
647 : * Get the enclosing scope of an object. When called on non-scope object,
648 : * this will just be the global (the name "enclosing scope" still applies
649 : * in this situation because non-scope objects can be on the scope chain).
650 : */
651 : inline JSObject *enclosingScope();
652 :
653 : inline js::GlobalObject &global() const;
654 :
655 : /* N.B. Infallible: NULL means 'no principal', not an error. */
656 : inline JSPrincipals *principals(JSContext *cx);
657 :
658 : /* Remove the type (and prototype) or parent from a new object. */
659 : inline bool clearType(JSContext *cx);
660 : bool clearParent(JSContext *cx);
661 :
662 : /*
663 : * ES5 meta-object properties and operations.
664 : */
665 :
666 : private:
667 : enum ImmutabilityType { SEAL, FREEZE };
668 :
669 : /*
670 : * The guts of Object.seal (ES5 15.2.3.8) and Object.freeze (ES5 15.2.3.9): mark the
671 : * object as non-extensible, and adjust each property's attributes appropriately: each
672 : * property becomes non-configurable, and if |freeze|, data properties become
673 : * read-only as well.
674 : */
675 : bool sealOrFreeze(JSContext *cx, ImmutabilityType it);
676 :
677 : bool isSealedOrFrozen(JSContext *cx, ImmutabilityType it, bool *resultp);
678 :
679 : static inline unsigned getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it);
680 :
681 : public:
682 : bool preventExtensions(JSContext *cx, js::AutoIdVector *props);
683 :
684 : /* ES5 15.2.3.8: non-extensible, all props non-configurable */
685 315 : inline bool seal(JSContext *cx) { return sealOrFreeze(cx, SEAL); }
686 : /* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */
687 1219359 : bool freeze(JSContext *cx) { return sealOrFreeze(cx, FREEZE); }
688 :
689 567 : bool isSealed(JSContext *cx, bool *resultp) { return isSealedOrFrozen(cx, SEAL, resultp); }
690 572 : bool isFrozen(JSContext *cx, bool *resultp) { return isSealedOrFrozen(cx, FREEZE, resultp); }
691 :
692 : /* Accessors for elements. */
693 :
694 : inline bool ensureElements(JSContext *cx, unsigned cap);
695 : bool growElements(JSContext *cx, unsigned cap);
696 : void shrinkElements(JSContext *cx, unsigned cap);
697 :
698 : inline js::ElementIteratorObject *asElementIterator();
699 :
700 : /*
701 : * Array-specific getters and setters (for both dense and slow arrays).
702 : */
703 :
704 : bool allocateSlowArrayElements(JSContext *cx);
705 :
706 : inline uint32_t getArrayLength() const;
707 : inline void setArrayLength(JSContext *cx, uint32_t length);
708 :
709 : inline uint32_t getDenseArrayCapacity();
710 : inline void setDenseArrayLength(uint32_t length);
711 : inline void setDenseArrayInitializedLength(uint32_t length);
712 : inline void ensureDenseArrayInitializedLength(JSContext *cx, unsigned index, unsigned extra);
713 : inline void setDenseArrayElement(unsigned idx, const js::Value &val);
714 : inline void initDenseArrayElement(unsigned idx, const js::Value &val);
715 : inline void setDenseArrayElementWithType(JSContext *cx, unsigned idx, const js::Value &val);
716 : inline void initDenseArrayElementWithType(JSContext *cx, unsigned idx, const js::Value &val);
717 : inline void copyDenseArrayElements(unsigned dstStart, const js::Value *src, unsigned count);
718 : inline void initDenseArrayElements(unsigned dstStart, const js::Value *src, unsigned count);
719 : inline void moveDenseArrayElements(unsigned dstStart, unsigned srcStart, unsigned count);
720 : inline void moveDenseArrayElementsUnbarriered(unsigned dstStart, unsigned srcStart, unsigned count);
721 : inline bool denseArrayHasInlineSlots() const;
722 :
723 : /* Packed information for this array. */
724 : inline void markDenseArrayNotPacked(JSContext *cx);
725 :
726 : /*
727 : * ensureDenseArrayElements ensures that the dense array can hold at least
728 : * index + extra elements. It returns ED_OK on success, ED_FAILED on
729 : * failure to grow the array, ED_SPARSE when the array is too sparse to
730 : * grow (this includes the case of index + extra overflow). In the last
731 : * two cases the array is kept intact.
732 : */
733 : enum EnsureDenseResult { ED_OK, ED_FAILED, ED_SPARSE };
734 : inline EnsureDenseResult ensureDenseArrayElements(JSContext *cx, unsigned index, unsigned extra);
735 :
736 : /*
737 : * Check if after growing the dense array will be too sparse.
738 : * newElementsHint is an estimated number of elements to be added.
739 : */
740 : bool willBeSparseDenseArray(unsigned requiredCapacity, unsigned newElementsHint);
741 :
742 : JSBool makeDenseArraySlow(JSContext *cx);
743 :
744 : /*
745 : * If this array object has a data property with index i, set *vp to its
746 : * value and return true. If not, do vp->setMagic(JS_ARRAY_HOLE) and return
747 : * true. On OOM, report it and return false.
748 : */
749 : bool arrayGetOwnDataElement(JSContext *cx, size_t i, js::Value *vp);
750 :
751 : public:
752 : bool allocateArrayBufferSlots(JSContext *cx, uint32_t size, uint8_t *contents = NULL);
753 : inline uint32_t arrayBufferByteLength();
754 : inline uint8_t * arrayBufferDataOffset();
755 :
756 : public:
757 : /*
758 : * Date-specific getters and setters.
759 : */
760 :
761 : static const uint32_t JSSLOT_DATE_UTC_TIME = 0;
762 :
763 : /*
764 : * Cached slots holding local properties of the date.
765 : * These are undefined until the first actual lookup occurs
766 : * and are reset to undefined whenever the date's time is modified.
767 : */
768 : static const uint32_t JSSLOT_DATE_COMPONENTS_START = 1;
769 :
770 : static const uint32_t JSSLOT_DATE_LOCAL_TIME = 1;
771 : static const uint32_t JSSLOT_DATE_LOCAL_YEAR = 2;
772 : static const uint32_t JSSLOT_DATE_LOCAL_MONTH = 3;
773 : static const uint32_t JSSLOT_DATE_LOCAL_DATE = 4;
774 : static const uint32_t JSSLOT_DATE_LOCAL_DAY = 5;
775 : static const uint32_t JSSLOT_DATE_LOCAL_HOURS = 6;
776 : static const uint32_t JSSLOT_DATE_LOCAL_MINUTES = 7;
777 : static const uint32_t JSSLOT_DATE_LOCAL_SECONDS = 8;
778 :
779 : static const uint32_t DATE_CLASS_RESERVED_SLOTS = 9;
780 :
781 : inline const js::Value &getDateUTCTime() const;
782 : inline void setDateUTCTime(const js::Value &pthis);
783 :
784 : /*
785 : * Function-specific getters and setters.
786 : */
787 :
788 : friend struct JSFunction;
789 :
790 : inline JSFunction *toFunction();
791 : inline const JSFunction *toFunction() const;
792 :
793 : public:
794 : /*
795 : * Iterator-specific getters and setters.
796 : */
797 :
798 : static const uint32_t ITER_CLASS_NFIXED_SLOTS = 1;
799 :
800 : inline js::NativeIterator *getNativeIterator() const;
801 : inline void setNativeIterator(js::NativeIterator *);
802 :
803 : /*
804 : * XML-related getters and setters.
805 : */
806 :
807 : /*
808 : * Slots for XML-related classes are as follows:
809 : * - NamespaceClass.base reserves the *_NAME_* and *_NAMESPACE_* slots.
810 : * - QNameClass.base, AttributeNameClass, AnyNameClass reserve
811 : * the *_NAME_* and *_QNAME_* slots.
812 : * - Others (XMLClass, js_XMLFilterClass) don't reserve any slots.
813 : */
814 : private:
815 : static const uint32_t JSSLOT_NAME_PREFIX = 0; // shared
816 : static const uint32_t JSSLOT_NAME_URI = 1; // shared
817 :
818 : static const uint32_t JSSLOT_NAMESPACE_DECLARED = 2;
819 :
820 : static const uint32_t JSSLOT_QNAME_LOCAL_NAME = 2;
821 :
822 : public:
823 : static const uint32_t NAMESPACE_CLASS_RESERVED_SLOTS = 3;
824 : static const uint32_t QNAME_CLASS_RESERVED_SLOTS = 3;
825 :
826 : inline JSLinearString *getNamePrefix() const;
827 : inline jsval getNamePrefixVal() const;
828 : inline void setNamePrefix(JSLinearString *prefix);
829 : inline void clearNamePrefix();
830 :
831 : inline JSLinearString *getNameURI() const;
832 : inline jsval getNameURIVal() const;
833 : inline void setNameURI(JSLinearString *uri);
834 :
835 : inline jsval getNamespaceDeclared() const;
836 : inline void setNamespaceDeclared(jsval decl);
837 :
838 : inline JSAtom *getQNameLocalName() const;
839 : inline jsval getQNameLocalNameVal() const;
840 : inline void setQNameLocalName(JSAtom *name);
841 :
842 : /*
843 : * Back to generic stuff.
844 : */
845 : inline bool isCallable();
846 :
847 : inline void finish(js::FreeOp *fop);
848 : JS_ALWAYS_INLINE void finalize(js::FreeOp *fop);
849 :
850 : inline bool hasProperty(JSContext *cx, jsid id, bool *foundp, unsigned flags = 0);
851 :
852 : /*
853 : * Allocate and free an object slot.
854 : *
855 : * FIXME: bug 593129 -- slot allocation should be done by object methods
856 : * after calling object-parameter-free shape methods, avoiding coupling
857 : * logic across the object vs. shape module wall.
858 : */
859 : bool allocSlot(JSContext *cx, uint32_t *slotp);
860 : void freeSlot(JSContext *cx, uint32_t slot);
861 :
862 : public:
863 : bool reportNotConfigurable(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR);
864 : bool reportNotExtensible(JSContext *cx, unsigned report = JSREPORT_ERROR);
865 :
866 : /*
867 : * Get the property with the given id, then call it as a function with the
868 : * given arguments, providing this object as |this|. If the property isn't
869 : * callable a TypeError will be thrown. On success the value returned by
870 : * the call is stored in *vp.
871 : */
872 : bool callMethod(JSContext *cx, jsid id, unsigned argc, js::Value *argv, js::Value *vp);
873 :
874 : private:
875 : js::Shape *getChildProperty(JSContext *cx, js::Shape *parent, js::StackShape &child);
876 :
877 : protected:
878 : /*
879 : * Internal helper that adds a shape not yet mapped by this object.
880 : *
881 : * Notes:
882 : * 1. getter and setter must be normalized based on flags (see jsscope.cpp).
883 : * 2. !isExtensible() checking must be done by callers.
884 : */
885 : js::Shape *addPropertyInternal(JSContext *cx, jsid id,
886 : JSPropertyOp getter, JSStrictPropertyOp setter,
887 : uint32_t slot, unsigned attrs,
888 : unsigned flags, int shortid, js::Shape **spp,
889 : bool allowDictionary);
890 :
891 : private:
892 : bool toDictionaryMode(JSContext *cx);
893 :
894 : struct TradeGutsReserved;
895 : static bool ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
896 : TradeGutsReserved &reserved);
897 :
898 : static void TradeGuts(JSContext *cx, JSObject *a, JSObject *b,
899 : TradeGutsReserved &reserved);
900 :
901 : public:
902 : /* Add a property whose id is not yet in this scope. */
903 : js::Shape *addProperty(JSContext *cx, jsid id,
904 : JSPropertyOp getter, JSStrictPropertyOp setter,
905 : uint32_t slot, unsigned attrs,
906 : unsigned flags, int shortid, bool allowDictionary = true);
907 :
908 : /* Add a data property whose id is not yet in this scope. */
909 143305 : js::Shape *addDataProperty(JSContext *cx, jsid id, uint32_t slot, unsigned attrs) {
910 143305 : JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
911 143305 : return addProperty(cx, id, NULL, NULL, slot, attrs, 0, 0);
912 : }
913 :
914 : /* Add or overwrite a property for id in this scope. */
915 : js::Shape *putProperty(JSContext *cx, jsid id,
916 : JSPropertyOp getter, JSStrictPropertyOp setter,
917 : uint32_t slot, unsigned attrs,
918 : unsigned flags, int shortid);
919 : inline js::Shape *
920 1350 : putProperty(JSContext *cx, js::PropertyName *name,
921 : JSPropertyOp getter, JSStrictPropertyOp setter,
922 : uint32_t slot, unsigned attrs, unsigned flags, int shortid) {
923 1350 : return putProperty(cx, js_CheckForStringIndex(ATOM_TO_JSID(name)), getter, setter, slot, attrs, flags, shortid);
924 : }
925 :
926 : /* Change the given property into a sibling with the same id in this scope. */
927 : js::Shape *changeProperty(JSContext *cx, js::Shape *shape, unsigned attrs, unsigned mask,
928 : JSPropertyOp getter, JSStrictPropertyOp setter);
929 :
930 : inline bool changePropertyAttributes(JSContext *cx, js::Shape *shape, unsigned attrs);
931 :
932 : /* Remove the property named by id from this object. */
933 : bool removeProperty(JSContext *cx, jsid id);
934 :
935 : /* Clear the scope, making it empty. */
936 : void clear(JSContext *cx);
937 :
938 : inline JSBool lookupGeneric(JSContext *cx, jsid id, JSObject **objp, JSProperty **propp);
939 : inline JSBool lookupProperty(JSContext *cx, js::PropertyName *name, JSObject **objp, JSProperty **propp);
940 : inline JSBool lookupElement(JSContext *cx, uint32_t index,
941 : JSObject **objp, JSProperty **propp);
942 : inline JSBool lookupSpecial(JSContext *cx, js::SpecialId sid,
943 : JSObject **objp, JSProperty **propp);
944 :
945 : inline JSBool defineGeneric(JSContext *cx, jsid id, const js::Value &value,
946 : JSPropertyOp getter = JS_PropertyStub,
947 : JSStrictPropertyOp setter = JS_StrictPropertyStub,
948 : unsigned attrs = JSPROP_ENUMERATE);
949 : inline JSBool defineProperty(JSContext *cx, js::PropertyName *name, const js::Value &value,
950 : JSPropertyOp getter = JS_PropertyStub,
951 : JSStrictPropertyOp setter = JS_StrictPropertyStub,
952 : unsigned attrs = JSPROP_ENUMERATE);
953 :
954 : inline JSBool defineElement(JSContext *cx, uint32_t index, const js::Value &value,
955 : JSPropertyOp getter = JS_PropertyStub,
956 : JSStrictPropertyOp setter = JS_StrictPropertyStub,
957 : unsigned attrs = JSPROP_ENUMERATE);
958 : inline JSBool defineSpecial(JSContext *cx, js::SpecialId sid, const js::Value &value,
959 : JSPropertyOp getter = JS_PropertyStub,
960 : JSStrictPropertyOp setter = JS_StrictPropertyStub,
961 : unsigned attrs = JSPROP_ENUMERATE);
962 :
963 : inline JSBool getGeneric(JSContext *cx, JSObject *receiver, jsid id, js::Value *vp);
964 : inline JSBool getProperty(JSContext *cx, JSObject *receiver, js::PropertyName *name,
965 : js::Value *vp);
966 : inline JSBool getElement(JSContext *cx, JSObject *receiver, uint32_t index, js::Value *vp);
967 : /* If element is not present (e.g. array hole) *present is set to
968 : false and the contents of *vp are unusable garbage. */
969 : inline JSBool getElementIfPresent(JSContext *cx, JSObject *receiver, uint32_t index,
970 : js::Value *vp, bool *present);
971 : inline JSBool getSpecial(JSContext *cx, JSObject *receiver, js::SpecialId sid, js::Value *vp);
972 :
973 : inline JSBool getGeneric(JSContext *cx, jsid id, js::Value *vp);
974 : inline JSBool getProperty(JSContext *cx, js::PropertyName *name, js::Value *vp);
975 : inline JSBool getElement(JSContext *cx, uint32_t index, js::Value *vp);
976 : inline JSBool getSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp);
977 :
978 : inline JSBool setGeneric(JSContext *cx, jsid id, js::Value *vp, JSBool strict);
979 : inline JSBool setProperty(JSContext *cx, js::PropertyName *name, js::Value *vp, JSBool strict);
980 : inline JSBool setElement(JSContext *cx, uint32_t index, js::Value *vp, JSBool strict);
981 : inline JSBool setSpecial(JSContext *cx, js::SpecialId sid, js::Value *vp, JSBool strict);
982 :
983 : JSBool nonNativeSetProperty(JSContext *cx, jsid id, js::Value *vp, JSBool strict);
984 : JSBool nonNativeSetElement(JSContext *cx, uint32_t index, js::Value *vp, JSBool strict);
985 :
986 : inline JSBool getGenericAttributes(JSContext *cx, jsid id, unsigned *attrsp);
987 : inline JSBool getPropertyAttributes(JSContext *cx, js::PropertyName *name, unsigned *attrsp);
988 : inline JSBool getElementAttributes(JSContext *cx, uint32_t index, unsigned *attrsp);
989 : inline JSBool getSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrsp);
990 :
991 : inline JSBool setGenericAttributes(JSContext *cx, jsid id, unsigned *attrsp);
992 : inline JSBool setPropertyAttributes(JSContext *cx, js::PropertyName *name, unsigned *attrsp);
993 : inline JSBool setElementAttributes(JSContext *cx, uint32_t index, unsigned *attrsp);
994 : inline JSBool setSpecialAttributes(JSContext *cx, js::SpecialId sid, unsigned *attrsp);
995 :
996 : inline bool deleteProperty(JSContext *cx, js::PropertyName *name, js::Value *rval, bool strict);
997 : inline bool deleteElement(JSContext *cx, uint32_t index, js::Value *rval, bool strict);
998 : inline bool deleteSpecial(JSContext *cx, js::SpecialId sid, js::Value *rval, bool strict);
999 : bool deleteByValue(JSContext *cx, const js::Value &property, js::Value *rval, bool strict);
1000 :
1001 : inline bool enumerate(JSContext *cx, JSIterateOp iterop, js::Value *statep, jsid *idp);
1002 : inline bool defaultValue(JSContext *cx, JSType hint, js::Value *vp);
1003 : inline JSType typeOf(JSContext *cx);
1004 : inline JSObject *thisObject(JSContext *cx);
1005 :
1006 : static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp);
1007 :
1008 : bool swap(JSContext *cx, JSObject *other);
1009 :
1010 : inline void initArrayClass();
1011 :
1012 : /*
1013 : * In addition to the generic object interface provided by JSObject,
1014 : * specific types of objects may provide additional operations. To access,
1015 : * these addition operations, callers should use the pattern:
1016 : *
1017 : * if (obj.isX()) {
1018 : * XObject &x = obj.asX();
1019 : * x.foo();
1020 : * }
1021 : *
1022 : * These XObject classes form a hierarchy. For example, for a cloned block
1023 : * object, the following predicates are true: isClonedBlock, isBlock,
1024 : * isNestedScope and isScope. Each of these has a respective class that
1025 : * derives and adds operations.
1026 : *
1027 : * A class XObject is defined in a vm/XObject{.h, .cpp, -inl.h} file
1028 : * triplet (along with any class YObject that derives XObject).
1029 : *
1030 : * Note that X represents a low-level representation and does not query the
1031 : * [[Class]] property of object defined by the spec (for this, see
1032 : * js::ObjectClassIs).
1033 : *
1034 : * SpiderMonkey has not been completely switched to the isX/asX/XObject
1035 : * pattern so in some cases there is no XObject class and the engine
1036 : * instead pokes directly at reserved slots and getPrivate. In such cases,
1037 : * consider adding the missing XObject class.
1038 : */
1039 :
1040 : /* Direct subtypes of JSObject: */
1041 : inline bool isArguments() const;
1042 : inline bool isArrayBuffer() const;
1043 : inline bool isDate() const;
1044 : inline bool isElementIterator() const;
1045 : inline bool isError() const;
1046 : inline bool isFunction() const;
1047 : inline bool isGenerator() const;
1048 : inline bool isGlobal() const;
1049 : inline bool isIterator() const;
1050 : inline bool isNamespace() const;
1051 : inline bool isObject() const;
1052 : inline bool isQName() const;
1053 : inline bool isPrimitive() const;
1054 : inline bool isProxy() const;
1055 : inline bool isRegExp() const;
1056 : inline bool isRegExpStatics() const;
1057 : inline bool isScope() const;
1058 : inline bool isScript() const;
1059 : inline bool isStopIteration() const;
1060 : inline bool isTypedArray() const;
1061 : inline bool isWeakMap() const;
1062 : inline bool isXML() const;
1063 : inline bool isXMLId() const;
1064 :
1065 : /* Subtypes of ScopeObject. */
1066 : inline bool isBlock() const;
1067 : inline bool isCall() const;
1068 : inline bool isDeclEnv() const;
1069 : inline bool isNestedScope() const;
1070 : inline bool isWith() const;
1071 : inline bool isClonedBlock() const;
1072 : inline bool isStaticBlock() const;
1073 :
1074 : /* Subtypes of PrimitiveObject. */
1075 : inline bool isBoolean() const;
1076 : inline bool isNumber() const;
1077 : inline bool isString() const;
1078 :
1079 : /* Subtypes of ArgumentsObject. */
1080 : inline bool isNormalArguments() const;
1081 : inline bool isStrictArguments() const;
1082 :
1083 : /* Subtypes of Proxy. */
1084 : inline bool isWrapper() const;
1085 : inline bool isFunctionProxy() const;
1086 : inline bool isCrossCompartmentWrapper() const;
1087 :
1088 : inline js::ArgumentsObject &asArguments();
1089 : inline const js::ArgumentsObject &asArguments() const;
1090 : inline js::BlockObject &asBlock();
1091 : inline js::BooleanObject &asBoolean();
1092 : inline js::CallObject &asCall();
1093 : inline js::ClonedBlockObject &asClonedBlock();
1094 : inline js::DeclEnvObject &asDeclEnv();
1095 : inline js::GlobalObject &asGlobal();
1096 : inline js::NestedScopeObject &asNestedScope();
1097 : inline js::NormalArgumentsObject &asNormalArguments();
1098 : inline js::NumberObject &asNumber();
1099 : inline js::RegExpObject &asRegExp();
1100 : inline js::ScopeObject &asScope();
1101 : inline js::StrictArgumentsObject &asStrictArguments();
1102 : inline js::StaticBlockObject &asStaticBlock();
1103 : inline js::StringObject &asString();
1104 : inline js::WithObject &asWith();
1105 :
1106 : static inline js::ThingRootKind rootKind() { return js::THING_ROOT_OBJECT; }
1107 :
1108 : #ifdef DEBUG
1109 : void dump();
1110 : #endif
1111 :
1112 : private:
1113 : static void staticAsserts() {
1114 : MOZ_STATIC_ASSERT(sizeof(JSObject) == sizeof(js::shadow::Object),
1115 : "shadow interface must match actual interface");
1116 : MOZ_STATIC_ASSERT(sizeof(JSObject) == sizeof(js::ObjectImpl),
1117 : "JSObject itself must not have any fields");
1118 : MOZ_STATIC_ASSERT(sizeof(JSObject) % sizeof(js::Value) == 0,
1119 : "fixed slots after an object must be aligned");
1120 : }
1121 : };
1122 :
1123 : /*
1124 : * The only sensible way to compare JSObject with == is by identity. We use
1125 : * const& instead of * as a syntactic way to assert non-null. This leads to an
1126 : * abundance of address-of operators to identity. Hence this overload.
1127 : */
1128 : static JS_ALWAYS_INLINE bool
1129 1529830 : operator==(const JSObject &lhs, const JSObject &rhs)
1130 : {
1131 1529830 : return &lhs == &rhs;
1132 : }
1133 :
1134 : static JS_ALWAYS_INLINE bool
1135 211056 : operator!=(const JSObject &lhs, const JSObject &rhs)
1136 : {
1137 211056 : return &lhs != &rhs;
1138 : }
1139 :
1140 : struct JSObject_Slots2 : JSObject { js::Value fslots[2]; };
1141 : struct JSObject_Slots4 : JSObject { js::Value fslots[4]; };
1142 : struct JSObject_Slots8 : JSObject { js::Value fslots[8]; };
1143 : struct JSObject_Slots12 : JSObject { js::Value fslots[12]; };
1144 3385370 : struct JSObject_Slots16 : JSObject { js::Value fslots[16]; };
1145 :
1146 : #define JSSLOT_FREE(clasp) JSCLASS_RESERVED_SLOTS(clasp)
1147 :
1148 : class JSValueArray {
1149 : public:
1150 : jsval *array;
1151 : size_t length;
1152 :
1153 35322 : JSValueArray(jsval *v, size_t c) : array(v), length(c) {}
1154 : };
1155 :
1156 : class ValueArray {
1157 : public:
1158 : js::Value *array;
1159 : size_t length;
1160 :
1161 : ValueArray(js::Value *v, size_t c) : array(v), length(c) {}
1162 : };
1163 :
1164 : /* For manipulating JSContext::sharpObjectMap. */
1165 : extern bool
1166 : js_EnterSharpObject(JSContext *cx, JSObject *obj, JSIdArray **idap, bool *alreadySeen, bool *isSharp);
1167 :
1168 : extern void
1169 : js_LeaveSharpObject(JSContext *cx, JSIdArray **idap);
1170 :
1171 : /*
1172 : * Mark objects stored in map if GC happens between js_EnterSharpObject
1173 : * and js_LeaveSharpObject. GC calls this when map->depth > 0.
1174 : */
1175 : extern void
1176 : js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map);
1177 :
1178 : extern JSBool
1179 : js_HasOwnPropertyHelper(JSContext *cx, js::LookupGenericOp lookup, unsigned argc,
1180 : js::Value *vp);
1181 :
1182 : extern JSBool
1183 : js_HasOwnProperty(JSContext *cx, js::LookupGenericOp lookup, JSObject *obj, jsid id,
1184 : JSObject **objp, JSProperty **propp);
1185 :
1186 : extern JSBool
1187 : js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, js::Value *vp);
1188 :
1189 : #if JS_HAS_OBJ_PROTO_PROP
1190 : extern JSPropertySpec object_props[];
1191 : #else
1192 : #define object_props NULL
1193 : #endif
1194 :
1195 : extern JSFunctionSpec object_methods[];
1196 : extern JSFunctionSpec object_static_methods[];
1197 :
1198 : namespace js {
1199 :
1200 : bool
1201 : IsStandardClassResolved(JSObject *obj, js::Class *clasp);
1202 :
1203 : void
1204 : MarkStandardClassInitializedNoProto(JSObject *obj, js::Class *clasp);
1205 :
1206 : /*
1207 : * Cache for speeding up repetitive creation of objects in the VM.
1208 : * When an object is created which matches the criteria in the 'key' section
1209 : * below, an entry is filled with the resulting object.
1210 : */
1211 : class NewObjectCache
1212 82570 : {
1213 : struct Entry
1214 3385370 : {
1215 : /* Class of the constructed object. */
1216 : Class *clasp;
1217 :
1218 : /*
1219 : * Key with one of three possible values:
1220 : *
1221 : * - Global for the object. The object must have a standard class for
1222 : * which the global's prototype can be determined, and the object's
1223 : * parent will be the global.
1224 : *
1225 : * - Prototype for the object (cannot be global). The object's parent
1226 : * will be the prototype's parent.
1227 : *
1228 : * - Type for the object. The object's parent will be the type's
1229 : * prototype's parent.
1230 : */
1231 : gc::Cell *key;
1232 :
1233 : /* Allocation kind for the constructed object. */
1234 : gc::AllocKind kind;
1235 :
1236 : /* Number of bytes to copy from the template object. */
1237 : uint32_t nbytes;
1238 :
1239 : /*
1240 : * Template object to copy from, with the initial values of fields,
1241 : * fixed slots (undefined) and private data (NULL).
1242 : */
1243 : JSObject_Slots16 templateObject;
1244 : };
1245 :
1246 : Entry entries[41];
1247 :
1248 : void staticAsserts() {
1249 : JS_STATIC_ASSERT(gc::FINALIZE_OBJECT_LAST == gc::FINALIZE_OBJECT16_BACKGROUND);
1250 : }
1251 :
1252 : public:
1253 :
1254 : typedef int EntryIndex;
1255 :
1256 124982 : void reset() { PodZero(this); }
1257 :
1258 : /*
1259 : * Get the entry index for the given lookup, return whether there was a hit
1260 : * on an existing entry.
1261 : */
1262 : inline bool lookupProto(Class *clasp, JSObject *proto, gc::AllocKind kind, EntryIndex *pentry);
1263 : inline bool lookupGlobal(Class *clasp, js::GlobalObject *global, gc::AllocKind kind, EntryIndex *pentry);
1264 : inline bool lookupType(Class *clasp, js::types::TypeObject *type, gc::AllocKind kind, EntryIndex *pentry);
1265 :
1266 : /* Return a new object from a cache hit produced by a lookup method. */
1267 : inline JSObject *newObjectFromHit(JSContext *cx, EntryIndex entry);
1268 :
1269 : /* Fill an entry after a cache miss. */
1270 : inline void fillProto(EntryIndex entry, Class *clasp, JSObject *proto, gc::AllocKind kind, JSObject *obj);
1271 : inline void fillGlobal(EntryIndex entry, Class *clasp, js::GlobalObject *global, gc::AllocKind kind, JSObject *obj);
1272 : inline void fillType(EntryIndex entry, Class *clasp, js::types::TypeObject *type, gc::AllocKind kind, JSObject *obj);
1273 :
1274 : /* Invalidate any entries which might produce an object with shape/proto. */
1275 : void invalidateEntriesForShape(JSContext *cx, Shape *shape, JSObject *proto);
1276 :
1277 : private:
1278 : inline bool lookup(Class *clasp, gc::Cell *key, gc::AllocKind kind, EntryIndex *pentry);
1279 : inline void fill(EntryIndex entry, Class *clasp, gc::Cell *key, gc::AllocKind kind, JSObject *obj);
1280 : static inline void copyCachedToObject(JSObject *dst, JSObject *src);
1281 : };
1282 :
1283 : } /* namespace js */
1284 :
1285 : /*
1286 : * Select Object.prototype method names shared between jsapi.cpp and jsobj.cpp.
1287 : */
1288 : extern const char js_watch_str[];
1289 : extern const char js_unwatch_str[];
1290 : extern const char js_hasOwnProperty_str[];
1291 : extern const char js_isPrototypeOf_str[];
1292 : extern const char js_propertyIsEnumerable_str[];
1293 :
1294 : #ifdef OLD_GETTER_SETTER_METHODS
1295 : extern const char js_defineGetter_str[];
1296 : extern const char js_defineSetter_str[];
1297 : extern const char js_lookupGetter_str[];
1298 : extern const char js_lookupSetter_str[];
1299 : #endif
1300 :
1301 : extern JSBool
1302 : js_PopulateObject(JSContext *cx, JSObject *newborn, JSObject *props);
1303 :
1304 : /*
1305 : * Fast access to immutable standard objects (constructors and prototypes).
1306 : */
1307 : extern JSBool
1308 : js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key,
1309 : JSObject **objp);
1310 :
1311 : /*
1312 : * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
1313 : * JSProto_Null, clasp must non-null.
1314 : */
1315 : extern JSBool
1316 : js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey key,
1317 : js::Value *vp, js::Class *clasp = NULL);
1318 :
1319 : // Specialized call for constructing |this| with a known function callee,
1320 : // and a known prototype.
1321 : extern JSObject *
1322 : js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *proto);
1323 :
1324 : // Specialized call for constructing |this| with a known function callee.
1325 : extern JSObject *
1326 : js_CreateThisForFunction(JSContext *cx, JSObject *callee, bool newType);
1327 :
1328 : // Generic call for constructing |this|.
1329 : extern JSObject *
1330 : js_CreateThis(JSContext *cx, js::Class *clasp, JSObject *callee);
1331 :
1332 : extern jsid
1333 : js_CheckForStringIndex(jsid id);
1334 :
1335 : /*
1336 : * Find or create a property named by id in obj's scope, with the given getter
1337 : * and setter, slot, attributes, and other members.
1338 : */
1339 : extern js::Shape *
1340 : js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
1341 : JSPropertyOp getter, JSStrictPropertyOp setter, uint32_t slot,
1342 : unsigned attrs, unsigned flags, int shortid);
1343 :
1344 : extern JSBool
1345 : js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id,
1346 : const js::Value &descriptor, JSBool *bp);
1347 :
1348 : namespace js {
1349 :
1350 : /*
1351 : * Flags for the defineHow parameter of js_DefineNativeProperty.
1352 : */
1353 : const unsigned DNP_CACHE_RESULT = 1; /* an interpreter call from JSOP_INITPROP */
1354 : const unsigned DNP_DONT_PURGE = 2; /* suppress js_PurgeScopeChain */
1355 : const unsigned DNP_UNQUALIFIED = 4; /* Unqualified property set. Only used in
1356 : the defineHow argument of
1357 : js_SetPropertyHelper. */
1358 : const unsigned DNP_SKIP_TYPE = 8; /* Don't update type information */
1359 :
1360 : /*
1361 : * Return successfully added or changed shape or NULL on error.
1362 : */
1363 : extern const Shape *
1364 : DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value,
1365 : PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
1366 : unsigned flags, int shortid, unsigned defineHow = 0);
1367 :
1368 : inline const Shape *
1369 57810 : DefineNativeProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value &value,
1370 : PropertyOp getter, StrictPropertyOp setter, unsigned attrs,
1371 : unsigned flags, int shortid, unsigned defineHow = 0)
1372 : {
1373 57810 : return DefineNativeProperty(cx, obj, ATOM_TO_JSID(name), value, getter, setter, attrs, flags,
1374 57810 : shortid, defineHow);
1375 : }
1376 :
1377 : /*
1378 : * Specialized subroutine that allows caller to preset JSRESOLVE_* flags.
1379 : */
1380 : extern bool
1381 : LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
1382 : JSObject **objp, JSProperty **propp);
1383 :
1384 : inline bool
1385 31667 : LookupPropertyWithFlags(JSContext *cx, JSObject *obj, PropertyName *name, unsigned flags,
1386 : JSObject **objp, JSProperty **propp)
1387 : {
1388 31667 : return LookupPropertyWithFlags(cx, obj, ATOM_TO_JSID(name), flags, objp, propp);
1389 : }
1390 :
1391 : /*
1392 : * Call the [[DefineOwnProperty]] internal method of obj.
1393 : *
1394 : * If obj is an array, this follows ES5 15.4.5.1.
1395 : * If obj is any other native object, this follows ES5 8.12.9.
1396 : * If obj is a proxy, this calls the proxy handler's defineProperty method.
1397 : * Otherwise, this reports an error and returns false.
1398 : */
1399 : extern bool
1400 : DefineProperty(JSContext *cx, JSObject *obj, const jsid &id, const PropDesc &desc, bool throwError,
1401 : bool *rval);
1402 :
1403 : /*
1404 : * Read property descriptors from props, as for Object.defineProperties. See
1405 : * ES5 15.2.3.7 steps 3-5.
1406 : */
1407 : extern bool
1408 : ReadPropertyDescriptors(JSContext *cx, JSObject *props, bool checkAccessors,
1409 : AutoIdVector *ids, AutoPropDescArrayRooter *descs);
1410 :
1411 : /*
1412 : * Constant to pass to js_LookupPropertyWithFlags to infer bits from current
1413 : * bytecode.
1414 : */
1415 : static const unsigned RESOLVE_INFER = 0xffff;
1416 :
1417 : /*
1418 : * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success.
1419 : */
1420 : extern bool
1421 : FindPropertyHelper(JSContext *cx, PropertyName *name, bool cacheResult, JSObject *scopeChain,
1422 : JSObject **objp, JSObject **pobjp, JSProperty **propp);
1423 :
1424 : /*
1425 : * Search for name either on the current scope chain or on the scope chain's
1426 : * global object, per the global parameter.
1427 : */
1428 : extern bool
1429 : FindProperty(JSContext *cx, PropertyName *name, JSObject *scopeChain,
1430 : JSObject **objp, JSObject **pobjp, JSProperty **propp);
1431 :
1432 : extern JSObject *
1433 : FindIdentifierBase(JSContext *cx, JSObject *scopeChain, PropertyName *name);
1434 :
1435 : }
1436 :
1437 : extern JSObject *
1438 : js_FindVariableScope(JSContext *cx, JSFunction **funp);
1439 :
1440 : /* JSGET_CACHE_RESULT is the analogue of DNP_CACHE_RESULT for js_GetMethod. */
1441 : const unsigned JSGET_CACHE_RESULT = 1; // from a caching interpreter opcode
1442 :
1443 : /*
1444 : * NB: js_NativeGet and js_NativeSet are called with the scope containing shape
1445 : * (pobj's scope for Get, obj's for Set) locked, and on successful return, that
1446 : * scope is again locked. But on failure, both functions return false with the
1447 : * scope containing shape unlocked.
1448 : */
1449 : extern JSBool
1450 : js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const js::Shape *shape, unsigned getHow,
1451 : js::Value *vp);
1452 :
1453 : extern JSBool
1454 : js_NativeSet(JSContext *cx, JSObject *obj, const js::Shape *shape, bool added,
1455 : bool strict, js::Value *vp);
1456 :
1457 : namespace js {
1458 :
1459 : bool
1460 : GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uint32_t getHow, Value *vp);
1461 :
1462 : inline bool
1463 : GetPropertyHelper(JSContext *cx, JSObject *obj, PropertyName *name, uint32_t getHow, Value *vp)
1464 : {
1465 : return GetPropertyHelper(cx, obj, ATOM_TO_JSID(name), getHow, vp);
1466 : }
1467 :
1468 : bool
1469 : GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, PropertyDescriptor *desc);
1470 :
1471 : bool
1472 : GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, Value *vp);
1473 :
1474 : bool
1475 : NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, Value *vp);
1476 :
1477 : } /* namespace js */
1478 :
1479 : extern JSBool
1480 : js_GetMethod(JSContext *cx, JSObject *obj, jsid id, unsigned getHow, js::Value *vp);
1481 :
1482 : namespace js {
1483 :
1484 : inline bool
1485 : GetMethod(JSContext *cx, JSObject *obj, PropertyName *name, unsigned getHow, Value *vp)
1486 : {
1487 : return js_GetMethod(cx, obj, ATOM_TO_JSID(name), getHow, vp);
1488 : }
1489 :
1490 : } /* namespace js */
1491 :
1492 : namespace js {
1493 :
1494 : /*
1495 : * If obj has an already-resolved data property for id, return true and
1496 : * store the property value in *vp. This helper assumes the caller has already
1497 : * called js_CheckForStringIndex.
1498 : */
1499 : extern bool
1500 : HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp);
1501 :
1502 : inline bool
1503 733383 : HasDataProperty(JSContext *cx, JSObject *obj, JSAtom *atom, Value *vp)
1504 : {
1505 733383 : return HasDataProperty(cx, obj, js_CheckForStringIndex(ATOM_TO_JSID(atom)), vp);
1506 : }
1507 :
1508 : extern JSBool
1509 : CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
1510 : js::Value *vp, unsigned *attrsp);
1511 :
1512 : } /* namespace js */
1513 :
1514 : extern bool
1515 : js_IsDelegate(JSContext *cx, JSObject *obj, const js::Value &v);
1516 :
1517 : /*
1518 : * Wrap boolean, number or string as Boolean, Number or String object.
1519 : * *vp must not be an object, null or undefined.
1520 : */
1521 : extern JSBool
1522 : js_PrimitiveToObject(JSContext *cx, js::Value *vp);
1523 :
1524 : extern JSBool
1525 : js_ValueToObjectOrNull(JSContext *cx, const js::Value &v, JSObject **objp);
1526 :
1527 : /* Throws if v could not be converted to an object. */
1528 : extern JSObject *
1529 : js_ValueToNonNullObject(JSContext *cx, const js::Value &v);
1530 :
1531 : namespace js {
1532 :
1533 : /*
1534 : * Invokes the ES5 ToObject algorithm on *vp, writing back the object to vp.
1535 : * If *vp might already be an object, use ToObject.
1536 : */
1537 : extern JSObject *
1538 : ToObjectSlow(JSContext *cx, Value *vp);
1539 :
1540 : JS_ALWAYS_INLINE JSObject *
1541 17558947 : ToObject(JSContext *cx, Value *vp)
1542 : {
1543 17558947 : if (vp->isObject())
1544 17558637 : return &vp->toObject();
1545 310 : return ToObjectSlow(cx, vp);
1546 : }
1547 :
1548 : /* As for ToObject, but preserves the original value. */
1549 : inline JSObject *
1550 88302916 : ValueToObject(JSContext *cx, const Value &v)
1551 : {
1552 88302916 : if (v.isObject())
1553 87466867 : return &v.toObject();
1554 836049 : return js_ValueToNonNullObject(cx, v);
1555 : }
1556 :
1557 : } /* namespace js */
1558 :
1559 : extern void
1560 : js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize);
1561 :
1562 : extern bool
1563 : js_ClearNative(JSContext *cx, JSObject *obj);
1564 :
1565 : extern JSBool
1566 : js_ReportGetterOnlyAssignment(JSContext *cx);
1567 :
1568 : extern unsigned
1569 : js_InferFlags(JSContext *cx, unsigned defaultFlags);
1570 :
1571 : /* Object constructor native. Exposed only so the JIT can know its address. */
1572 : JSBool
1573 : js_Object(JSContext *cx, unsigned argc, js::Value *vp);
1574 :
1575 : /*
1576 : * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
1577 : * JSProto_Null, clasp must non-null.
1578 : *
1579 : * If protoKey is constant and scope is non-null, use GlobalObject's prototype
1580 : * methods instead.
1581 : */
1582 : extern JS_FRIEND_API(JSBool)
1583 : js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey,
1584 : JSObject **protop, js::Class *clasp = NULL);
1585 :
1586 : namespace js {
1587 :
1588 : extern bool
1589 : SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles);
1590 :
1591 : extern JSString *
1592 : obj_toStringHelper(JSContext *cx, JSObject *obj);
1593 :
1594 : extern JSBool
1595 : eval(JSContext *cx, unsigned argc, Value *vp);
1596 :
1597 : /*
1598 : * Performs a direct eval for the given arguments, which must correspond to the
1599 : * currently-executing stack frame, which must be a script frame. On completion
1600 : * the result is returned in args.rval.
1601 : */
1602 : extern bool
1603 : DirectEval(JSContext *cx, const CallArgs &args);
1604 :
1605 : /*
1606 : * True iff |v| is the built-in eval function for the global object that
1607 : * corresponds to |scopeChain|.
1608 : */
1609 : extern bool
1610 : IsBuiltinEvalForScope(JSObject *scopeChain, const js::Value &v);
1611 :
1612 : /* True iff fun is a built-in eval function. */
1613 : extern bool
1614 : IsAnyBuiltinEval(JSFunction *fun);
1615 :
1616 : /* 'call' should be for the eval/Function native invocation. */
1617 : extern JSPrincipals *
1618 : PrincipalsForCompiledCode(const CallReceiver &call, JSContext *cx);
1619 :
1620 : extern JSObject *
1621 : NonNullObject(JSContext *cx, const Value &v);
1622 :
1623 : extern const char *
1624 : InformalValueTypeName(const Value &v);
1625 :
1626 : inline void
1627 : DestroyIdArray(FreeOp *fop, JSIdArray *ida);
1628 :
1629 : /* Helpers for throwing. These always return false. */
1630 : extern bool
1631 : Throw(JSContext *cx, jsid id, unsigned errorNumber);
1632 :
1633 : extern bool
1634 : Throw(JSContext *cx, JSObject *obj, unsigned errorNumber);
1635 :
1636 : } /* namespace js */
1637 :
1638 : #endif /* jsobj_h___ */
|