Line data Source code
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 jsobj_h
8 : #define jsobj_h
9 :
10 : /*
11 : * JS object definitions.
12 : *
13 : * A JS object consists of a possibly-shared object descriptor containing
14 : * ordered property names, called the map; and a dense vector of property
15 : * values, called slots. The map/slot pointer pair is GC'ed, while the map
16 : * is reference counted and the slot vector is malloc'ed.
17 : */
18 :
19 : #include "mozilla/MemoryReporting.h"
20 :
21 : #include "gc/Barrier.h"
22 : #include "gc/Marking.h"
23 : #include "js/Conversions.h"
24 : #include "js/GCAPI.h"
25 : #include "js/GCVector.h"
26 : #include "js/HeapAPI.h"
27 : #include "vm/Shape.h"
28 : #include "vm/String.h"
29 : #include "vm/Xdr.h"
30 :
31 : namespace JS {
32 : struct ClassInfo;
33 : } // namespace JS
34 :
35 : namespace js {
36 :
37 : using PropertyDescriptorVector = JS::GCVector<JS::PropertyDescriptor>;
38 : class GCMarker;
39 : class Nursery;
40 :
41 : namespace gc {
42 : class RelocationOverlay;
43 : } // namespace gc
44 :
45 : inline JSObject*
46 : CastAsObject(GetterOp op)
47 : {
48 : return JS_FUNC_TO_DATA_PTR(JSObject*, op);
49 : }
50 :
51 : inline JSObject*
52 : CastAsObject(SetterOp op)
53 : {
54 : return JS_FUNC_TO_DATA_PTR(JSObject*, op);
55 : }
56 :
57 : inline Value
58 : CastAsObjectJsval(GetterOp op)
59 : {
60 : return ObjectOrNullValue(CastAsObject(op));
61 : }
62 :
63 : inline Value
64 : CastAsObjectJsval(SetterOp op)
65 : {
66 : return ObjectOrNullValue(CastAsObject(op));
67 : }
68 :
69 : /******************************************************************************/
70 :
71 : extern const Class IntlClass;
72 : extern const Class JSONClass;
73 : extern const Class MathClass;
74 :
75 : class GlobalObject;
76 : class NewObjectCache;
77 :
78 : enum class IntegrityLevel {
79 : Sealed,
80 : Frozen
81 : };
82 :
83 : // Forward declarations, required for later friend declarations.
84 : bool PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result, IntegrityLevel level = IntegrityLevel::Sealed);
85 : bool SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded);
86 :
87 : } /* namespace js */
88 :
89 : /*
90 : * A JavaScript object. The members common to all objects are as follows:
91 : *
92 : * - The |group_| member stores the group of the object, which contains its
93 : * prototype object, its class and the possible types of its properties.
94 : *
95 : * Subclasses of JSObject --- mainly NativeObject and JSFunction --- add more
96 : * members. Notable among these is the object's shape, which stores flags and
97 : * some other state, and, for native objects, the layout of all its properties.
98 : * The second word of a JSObject generally stores its shape; if the second word
99 : * stores anything else, the value stored cannot be a valid Shape* pointer, so
100 : * that shape guards can be performed on objects without regard to the specific
101 : * layout in use.
102 : */
103 : class JSObject : public js::gc::Cell
104 : {
105 : protected:
106 : js::GCPtrObjectGroup group_;
107 :
108 : private:
109 : friend class js::Shape;
110 : friend class js::GCMarker;
111 : friend class js::NewObjectCache;
112 : friend class js::Nursery;
113 : friend class js::gc::RelocationOverlay;
114 : friend bool js::PreventExtensions(JSContext* cx, JS::HandleObject obj, JS::ObjectOpResult& result, js::IntegrityLevel level);
115 : friend bool js::SetImmutablePrototype(JSContext* cx, JS::HandleObject obj,
116 : bool* succeeded);
117 :
118 : // Make a new group to use for a singleton object.
119 : static js::ObjectGroup* makeLazyGroup(JSContext* cx, js::HandleObject obj);
120 :
121 : public:
122 2851340 : bool isNative() const {
123 2851340 : return getClass()->isNative();
124 : }
125 :
126 12502547 : const js::Class* getClass() const {
127 12502547 : return group_->clasp();
128 : }
129 10130 : const JSClass* getJSClass() const {
130 10130 : return Jsvalify(getClass());
131 : }
132 5629 : bool hasClass(const js::Class* c) const {
133 5629 : return getClass() == c;
134 : }
135 :
136 49187 : js::LookupPropertyOp getOpsLookupProperty() const { return getClass()->getOpsLookupProperty(); }
137 98392 : js::DefinePropertyOp getOpsDefineProperty() const { return getClass()->getOpsDefineProperty(); }
138 20665 : js::HasPropertyOp getOpsHasProperty() const { return getClass()->getOpsHasProperty(); }
139 98770 : js::GetPropertyOp getOpsGetProperty() const { return getClass()->getOpsGetProperty(); }
140 10486 : js::SetPropertyOp getOpsSetProperty() const { return getClass()->getOpsSetProperty(); }
141 20160 : js::GetOwnPropertyOp getOpsGetOwnPropertyDescriptor()
142 20160 : const { return getClass()->getOpsGetOwnPropertyDescriptor(); }
143 874 : js::DeletePropertyOp getOpsDeleteProperty() const { return getClass()->getOpsDeleteProperty(); }
144 0 : js::WatchOp getOpsWatch() const { return getClass()->getOpsWatch(); }
145 0 : js::UnwatchOp getOpsUnwatch() const { return getClass()->getOpsUnwatch(); }
146 84 : js::GetElementsOp getOpsGetElements() const { return getClass()->getOpsGetElements(); }
147 0 : JSFunToStringOp getOpsFunToString() const { return getClass()->getOpsFunToString(); }
148 :
149 422229 : js::ObjectGroup* group() const {
150 422229 : MOZ_ASSERT(!hasLazyGroup());
151 422219 : return groupRaw();
152 : }
153 :
154 580141 : js::ObjectGroup* groupRaw() const {
155 580141 : return group_;
156 : }
157 :
158 : /*
159 : * Whether this is the only object which has its specified group. This
160 : * object will have its group constructed lazily as needed by analysis.
161 : */
162 438445 : bool isSingleton() const {
163 438445 : return group_->singleton();
164 : }
165 :
166 : /*
167 : * Whether the object's group has not been constructed yet. If an object
168 : * might have a lazy group, use getGroup() below, otherwise group().
169 : */
170 657015 : bool hasLazyGroup() const {
171 657015 : return group_->lazy();
172 : }
173 :
174 1843200 : JSCompartment* compartment() const { return group_->compartment(); }
175 6869 : JSCompartment* maybeCompartment() const { return compartment(); }
176 :
177 : inline js::Shape* maybeShape() const;
178 : inline js::Shape* ensureShape(JSContext* cx);
179 :
180 : // Set the initial slots and elements of an object. These pointers are only
181 : // valid for native objects, but during initialization are set for all
182 : // objects. For non-native objects, these must not be dynamically allocated
183 : // pointers which leak when the non-native object finishes initialization.
184 : inline void setInitialSlotsMaybeNonNative(js::HeapSlot* slots);
185 : inline void setInitialElementsMaybeNonNative(js::HeapSlot* elements);
186 :
187 : enum GenerateShape {
188 : GENERATE_NONE,
189 : GENERATE_SHAPE
190 : };
191 :
192 : static bool setFlags(JSContext* cx, JS::HandleObject obj, js::BaseShape::Flag flags,
193 : GenerateShape generateShape = GENERATE_NONE);
194 : inline bool hasAllFlags(js::BaseShape::Flag flags) const;
195 :
196 : /*
197 : * An object is a delegate if it is on another object's prototype or scope
198 : * chain, and therefore the delegate might be asked implicitly to get or
199 : * set a property on behalf of another object. Delegates may be accessed
200 : * directly too, as may any object, but only those objects linked after the
201 : * head of any prototype or scope chain are flagged as delegates. This
202 : * definition helps to optimize shape-based property cache invalidation
203 : * (see Purge{Scope,Proto}Chain in jsobj.cpp).
204 : */
205 : inline bool isDelegate() const;
206 8294 : static bool setDelegate(JSContext* cx, JS::HandleObject obj) {
207 8294 : return setFlags(cx, obj, js::BaseShape::DELEGATE, GENERATE_SHAPE);
208 : }
209 :
210 : inline bool isBoundFunction() const;
211 : inline bool hasSpecialEquality() const;
212 :
213 : inline bool watched() const;
214 0 : static bool setWatched(JSContext* cx, JS::HandleObject obj) {
215 0 : return setFlags(cx, obj, js::BaseShape::WATCHED, GENERATE_SHAPE);
216 : }
217 :
218 : // A "qualified" varobj is the object on which "qualified" variable
219 : // declarations (i.e., those defined with "var") are kept.
220 : //
221 : // Conceptually, when a var binding is defined, it is defined on the
222 : // innermost qualified varobj on the scope chain.
223 : //
224 : // Function scopes (CallObjects) are qualified varobjs, and there can be
225 : // no other qualified varobj that is more inner for var bindings in that
226 : // function. As such, all references to local var bindings in a function
227 : // may be statically bound to the function scope. This is subject to
228 : // further optimization. Unaliased bindings inside functions reside
229 : // entirely on the frame, not in CallObjects.
230 : //
231 : // Global scopes are also qualified varobjs. It is possible to statically
232 : // know, for a given script, that are no more inner qualified varobjs, so
233 : // free variable references can be statically bound to the global.
234 : //
235 : // Finally, there are non-syntactic qualified varobjs used by embedders
236 : // (e.g., Gecko and XPConnect), as they often wish to run scripts under a
237 : // scope that captures var bindings.
238 : inline bool isQualifiedVarObj() const;
239 542 : static bool setQualifiedVarObj(JSContext* cx, JS::HandleObject obj) {
240 542 : return setFlags(cx, obj, js::BaseShape::QUALIFIED_VAROBJ);
241 : }
242 :
243 : // An "unqualified" varobj is the object on which "unqualified"
244 : // assignments (i.e., bareword assignments for which the LHS does not
245 : // exist on the scope chain) are kept.
246 : inline bool isUnqualifiedVarObj() const;
247 :
248 : // Objects with an uncacheable proto can have their prototype mutated
249 : // without inducing a shape change on the object. JIT inline caches should
250 : // do an explicit group guard to guard against this. Singletons always
251 : // generate a new shape when their prototype changes, regardless of this
252 : // hasUncacheableProto flag.
253 : inline bool hasUncacheableProto() const;
254 630 : static bool setUncacheableProto(JSContext* cx, JS::HandleObject obj) {
255 630 : MOZ_ASSERT(obj->hasStaticPrototype(),
256 : "uncacheability as a concept is only applicable to static "
257 : "(not dynamically-computed) prototypes");
258 630 : return setFlags(cx, obj, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE);
259 : }
260 :
261 : /*
262 : * Whether SETLELEM was used to access this object. See also the comment near
263 : * PropertyTree::MAX_HEIGHT.
264 : */
265 : inline bool hadElementsAccess() const;
266 10 : static bool setHadElementsAccess(JSContext* cx, JS::HandleObject obj) {
267 10 : return setFlags(cx, obj, js::BaseShape::HAD_ELEMENTS_ACCESS);
268 : }
269 :
270 : /*
271 : * Whether there may be indexed properties on this object, excluding any in
272 : * the object's elements.
273 : */
274 : inline bool isIndexed() const;
275 :
276 : /*
277 : * Whether there may be "interesting symbol" properties on this object. An
278 : * interesting symbol is a symbol for which symbol->isInterestingSymbol()
279 : * returns true.
280 : */
281 : MOZ_ALWAYS_INLINE bool maybeHasInterestingSymbolProperty() const;
282 :
283 : /*
284 : * If this object was instantiated with `new Ctor`, return the constructor's
285 : * display atom. Otherwise, return nullptr.
286 : */
287 : static bool constructorDisplayAtom(JSContext* cx, js::HandleObject obj,
288 : js::MutableHandleAtom name);
289 :
290 : /*
291 : * The same as constructorDisplayAtom above, however if this object has a
292 : * lazy group, nullptr is returned. This allows for use in situations that
293 : * cannot GC and where having some information, even if it is inconsistently
294 : * available, is better than no information.
295 : */
296 : JSAtom* maybeConstructorDisplayAtom() const;
297 :
298 : /* GC support. */
299 :
300 : void traceChildren(JSTracer* trc);
301 :
302 : void fixupAfterMovingGC();
303 :
304 : static const JS::TraceKind TraceKind = JS::TraceKind::Object;
305 : static const size_t MaxTagBits = 3;
306 :
307 353289 : MOZ_ALWAYS_INLINE JS::Zone* zone() const {
308 353289 : return group_->zone();
309 : }
310 0 : MOZ_ALWAYS_INLINE JS::shadow::Zone* shadowZone() const {
311 0 : return JS::shadow::Zone::asShadowZone(zone());
312 : }
313 1585329 : MOZ_ALWAYS_INLINE JS::Zone* zoneFromAnyThread() const {
314 1585329 : return group_->zoneFromAnyThread();
315 : }
316 8390 : MOZ_ALWAYS_INLINE JS::shadow::Zone* shadowZoneFromAnyThread() const {
317 8390 : return JS::shadow::Zone::asShadowZone(zoneFromAnyThread());
318 : }
319 : static MOZ_ALWAYS_INLINE void readBarrier(JSObject* obj);
320 : static MOZ_ALWAYS_INLINE void writeBarrierPre(JSObject* obj);
321 : static MOZ_ALWAYS_INLINE void writeBarrierPost(void* cellp, JSObject* prev, JSObject* next);
322 :
323 : /* Return the allocKind we would use if we were to tenure this object. */
324 : js::gc::AllocKind allocKindForTenure(const js::Nursery& nursery) const;
325 :
326 6 : size_t tenuredSizeOfThis() const {
327 6 : MOZ_ASSERT(isTenured());
328 6 : return js::gc::Arena::thingSize(asTenured().getAllocKind());
329 : }
330 :
331 : void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo* info);
332 :
333 : // We can only use addSizeOfExcludingThis on tenured objects: it assumes it
334 : // can apply mallocSizeOf to bits and pieces of the object, whereas objects
335 : // in the nursery may have those bits and pieces allocated in the nursery
336 : // along with them, and are not each their own malloc blocks.
337 : size_t sizeOfIncludingThisInNursery() const;
338 :
339 : // Marks this object as having a singleton group, and leave the group lazy.
340 : // Constructs a new, unique shape for the object. This should only be
341 : // called for an object that was just created.
342 : static inline bool setSingleton(JSContext* cx, js::HandleObject obj);
343 :
344 : // Change an existing object to have a singleton group.
345 : static bool changeToSingleton(JSContext* cx, js::HandleObject obj);
346 :
347 : static inline js::ObjectGroup* getGroup(JSContext* cx, js::HandleObject obj);
348 :
349 1488 : const js::GCPtrObjectGroup& groupFromGC() const {
350 : /* Direct field access for use by GC. */
351 1488 : return group_;
352 : }
353 :
354 : #ifdef DEBUG
355 : static void debugCheckNewObject(js::ObjectGroup* group, js::Shape* shape,
356 : js::gc::AllocKind allocKind, js::gc::InitialHeap heap);
357 : #else
358 : static void debugCheckNewObject(js::ObjectGroup* group, js::Shape* shape,
359 : js::gc::AllocKind allocKind, js::gc::InitialHeap heap)
360 : {}
361 : #endif
362 :
363 : /*
364 : * We permit proxies to dynamically compute their prototype if desired.
365 : * (Not all proxies will so desire: in particular, most DOM proxies can
366 : * track their prototype with a single, nullable JSObject*.) If a proxy
367 : * so desires, we store (JSObject*)0x1 in the proto field of the object's
368 : * group.
369 : *
370 : * We offer three ways to get an object's prototype:
371 : *
372 : * 1. obj->staticPrototype() returns the prototype, but it asserts if obj
373 : * is a proxy, and the proxy has opted to dynamically compute its
374 : * prototype using a getPrototype() handler.
375 : * 2. obj->taggedProto() returns a TaggedProto, which can be tested to
376 : * check if the proto is an object, nullptr, or lazily computed.
377 : * 3. js::GetPrototype(cx, obj, &proto) computes the proto of an object.
378 : * If obj is a proxy with dynamically-computed prototype, this code may
379 : * perform arbitrary behavior (allocation, GC, run JS) while computing
380 : * the proto.
381 : */
382 :
383 730304 : js::TaggedProto taggedProto() const {
384 730304 : return group_->proto();
385 : }
386 :
387 : bool hasTenuredProto() const;
388 :
389 : bool uninlinedIsProxy() const;
390 :
391 297293 : JSObject* staticPrototype() const {
392 297293 : MOZ_ASSERT(hasStaticPrototype());
393 297293 : return taggedProto().toObjectOrNull();
394 : }
395 :
396 : // Normal objects and a subset of proxies have an uninteresting, static
397 : // (albeit perhaps mutable) [[Prototype]]. For such objects the
398 : // [[Prototype]] is just a value returned when needed for accesses, or
399 : // modified in response to requests. These objects store the
400 : // [[Prototype]] directly within |obj->group_|.
401 321945 : bool hasStaticPrototype() const {
402 321945 : return !hasDynamicPrototype();
403 : }
404 :
405 : // The remaining proxies have a [[Prototype]] requiring dynamic computation
406 : // for every access, going through the proxy handler {get,set}Prototype and
407 : // setImmutablePrototype methods. (Wrappers particularly use this to keep
408 : // the wrapper/wrappee [[Prototype]]s consistent.)
409 330097 : bool hasDynamicPrototype() const {
410 330097 : bool dynamic = taggedProto().isDynamic();
411 330096 : MOZ_ASSERT_IF(dynamic, uninlinedIsProxy());
412 330096 : MOZ_ASSERT_IF(dynamic, !isNative());
413 330096 : return dynamic;
414 : }
415 :
416 : // True iff this object's [[Prototype]] is immutable. Must be called only
417 : // on objects with a static [[Prototype]]!
418 : inline bool staticPrototypeIsImmutable() const;
419 :
420 : inline void setGroup(js::ObjectGroup* group);
421 :
422 : /*
423 : * Mark an object that has been iterated over and is a singleton. We need
424 : * to recover this information in the object's type information after it
425 : * is purged on GC.
426 : */
427 : inline bool isIteratedSingleton() const;
428 31 : static bool setIteratedSingleton(JSContext* cx, JS::HandleObject obj) {
429 31 : return setFlags(cx, obj, js::BaseShape::ITERATED_SINGLETON);
430 : }
431 :
432 : /*
433 : * Mark an object as requiring its default 'new' type to have unknown
434 : * properties.
435 : */
436 : inline bool isNewGroupUnknown() const;
437 : static bool setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj);
438 :
439 : // Mark an object as having its 'new' script information cleared.
440 : inline bool wasNewScriptCleared() const;
441 8 : static bool setNewScriptCleared(JSContext* cx, JS::HandleObject obj) {
442 8 : return setFlags(cx, obj, js::BaseShape::NEW_SCRIPT_CLEARED);
443 : }
444 :
445 : /* Set a new prototype for an object with a singleton type. */
446 : static bool splicePrototype(JSContext* cx, js::HandleObject obj, const js::Class* clasp,
447 : js::Handle<js::TaggedProto> proto);
448 :
449 : /*
450 : * For bootstrapping, whether to splice a prototype for Function.prototype
451 : * or the global object.
452 : */
453 : bool shouldSplicePrototype();
454 :
455 : /*
456 : * Environment chains.
457 : *
458 : * The environment chain of an object is the link in the search path when
459 : * a script does a name lookup on an environment object. For JS internal
460 : * environment objects --- Call, LexicalEnvironment, and WithEnvironment
461 : * --- the chain is stored in the first fixed slot of the object. For
462 : * other environment objects, the chain goes directly to the global.
463 : *
464 : * In code which is not marked hasNonSyntacticScope, environment chains
465 : * can contain only syntactic environment objects (see
466 : * IsSyntacticEnvironment) with a global object at the root as the
467 : * environment of the outermost non-function script. In
468 : * hasNonSyntacticScope code, the environment of the outermost
469 : * non-function script might not be a global object, and can have a mix of
470 : * other objects above it before the global object is reached.
471 : */
472 :
473 : /*
474 : * Get the enclosing environment of an object. When called on a
475 : * non-EnvironmentObject, this will just be the global (the name
476 : * "enclosing environment" still applies in this situation because
477 : * non-EnvironmentObjects can be on the environment chain).
478 : */
479 : inline JSObject* enclosingEnvironment() const;
480 :
481 : inline js::GlobalObject& global() const;
482 :
483 : // In some rare cases the global object's compartment's global may not be
484 : // the same global object. For this reason, we need to take extra care when
485 : // tracing.
486 : //
487 : // These cases are:
488 : // 1) The off-thread parsing task uses a dummy global since it cannot
489 : // share with the actual global being used concurrently on the active
490 : // thread.
491 : // 2) A GC may occur when creating the GlobalObject, in which case the
492 : // compartment global pointer may not yet be set. In this case there is
493 : // nothing interesting to trace in the compartment.
494 : inline bool isOwnGlobal(JSTracer*) const;
495 : inline js::GlobalObject* globalForTracing(JSTracer*) const;
496 :
497 : /*
498 : * ES5 meta-object properties and operations.
499 : */
500 :
501 : public:
502 : // Indicates whether a non-proxy is extensible. Don't call on proxies!
503 : // This method really shouldn't exist -- but there are a few internal
504 : // places that want it (JITs and the like), and it'd be a pain to mark them
505 : // all as friends.
506 : inline bool nonProxyIsExtensible() const;
507 : bool uninlinedNonProxyIsExtensible() const;
508 :
509 : public:
510 : /*
511 : * Iterator-specific getters and setters.
512 : */
513 :
514 : static const uint32_t ITER_CLASS_NFIXED_SLOTS = 1;
515 :
516 : /*
517 : * Back to generic stuff.
518 : */
519 : MOZ_ALWAYS_INLINE bool isCallable() const;
520 : MOZ_ALWAYS_INLINE bool isConstructor() const;
521 : MOZ_ALWAYS_INLINE JSNative callHook() const;
522 : MOZ_ALWAYS_INLINE JSNative constructHook() const;
523 :
524 : MOZ_ALWAYS_INLINE void finalize(js::FreeOp* fop);
525 :
526 : public:
527 : static bool reportReadOnly(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR);
528 : static bool reportNotConfigurable(JSContext* cx, jsid id, unsigned report = JSREPORT_ERROR);
529 : static bool reportNotExtensible(JSContext* cx, js::HandleObject obj,
530 : unsigned report = JSREPORT_ERROR);
531 :
532 : static bool nonNativeSetProperty(JSContext* cx, js::HandleObject obj, js::HandleId id,
533 : js::HandleValue v, js::HandleValue receiver,
534 : JS::ObjectOpResult& result);
535 : static bool nonNativeSetElement(JSContext* cx, js::HandleObject obj, uint32_t index,
536 : js::HandleValue v, js::HandleValue receiver,
537 : JS::ObjectOpResult& result);
538 :
539 : static bool swap(JSContext* cx, JS::HandleObject a, JS::HandleObject b);
540 :
541 : private:
542 : void fixDictionaryShapeAfterSwap();
543 :
544 : public:
545 : inline void initArrayClass();
546 :
547 : /*
548 : * In addition to the generic object interface provided by JSObject,
549 : * specific types of objects may provide additional operations. To access,
550 : * these addition operations, callers should use the pattern:
551 : *
552 : * if (obj.is<XObject>()) {
553 : * XObject& x = obj.as<XObject>();
554 : * x.foo();
555 : * }
556 : *
557 : * These XObject classes form a hierarchy. For example, for a cloned block
558 : * object, the following predicates are true: is<ClonedBlockObject>,
559 : * is<NestedScopeObject> and is<ScopeObject>. Each of these has a
560 : * respective class that derives and adds operations.
561 : *
562 : * A class XObject is defined in a vm/XObject{.h, .cpp, -inl.h} file
563 : * triplet (along with any class YObject that derives XObject).
564 : *
565 : * Note that X represents a low-level representation and does not query the
566 : * [[Class]] property of object defined by the spec (for this, see
567 : * js::GetBuiltinClass).
568 : */
569 :
570 : template <class T>
571 4061178 : inline bool is() const { return getClass() == &T::class_; }
572 :
573 : template <class T>
574 1901433 : T& as() {
575 1901433 : MOZ_ASSERT(this->is<T>());
576 1901427 : return *static_cast<T*>(this);
577 : }
578 :
579 : template <class T>
580 805711 : const T& as() const {
581 805711 : MOZ_ASSERT(this->is<T>());
582 805710 : return *static_cast<const T*>(this);
583 : }
584 :
585 : #ifdef DEBUG
586 : void dump(FILE* fp) const;
587 : void dump() const;
588 : #endif
589 :
590 : /* JIT Accessors */
591 :
592 739 : static size_t offsetOfGroup() { return offsetof(JSObject, group_); }
593 :
594 : // Maximum size in bytes of a JSObject.
595 : static const size_t MAX_BYTE_SIZE = 4 * sizeof(void*) + 16 * sizeof(JS::Value);
596 :
597 : private:
598 : JSObject() = delete;
599 : JSObject(const JSObject& other) = delete;
600 : void operator=(const JSObject& other) = delete;
601 : };
602 :
603 : template <typename Wrapper>
604 : template <typename U>
605 : MOZ_ALWAYS_INLINE JS::Handle<U*>
606 5003 : js::RootedBase<JSObject*, Wrapper>::as() const
607 : {
608 5003 : const Wrapper& self = *static_cast<const Wrapper*>(this);
609 5003 : MOZ_ASSERT(self->template is<U>());
610 5003 : return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
611 : }
612 :
613 : template <typename Wrapper>
614 : template <class U>
615 : MOZ_ALWAYS_INLINE JS::Handle<U*>
616 240021 : js::HandleBase<JSObject*, Wrapper>::as() const
617 : {
618 240021 : const JS::Handle<JSObject*>& self = *static_cast<const JS::Handle<JSObject*>*>(this);
619 240021 : MOZ_ASSERT(self->template is<U>());
620 240021 : return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
621 : }
622 :
623 : /*
624 : * The only sensible way to compare JSObject with == is by identity. We use
625 : * const& instead of * as a syntactic way to assert non-null. This leads to an
626 : * abundance of address-of operators to identity. Hence this overload.
627 : */
628 : static MOZ_ALWAYS_INLINE bool
629 21508 : operator==(const JSObject& lhs, const JSObject& rhs)
630 : {
631 21508 : return &lhs == &rhs;
632 : }
633 :
634 : static MOZ_ALWAYS_INLINE bool
635 : operator!=(const JSObject& lhs, const JSObject& rhs)
636 : {
637 : return &lhs != &rhs;
638 : }
639 :
640 : // Size of the various GC thing allocation sizes used for objects.
641 : struct JSObject_Slots0 : JSObject { void* data[3]; };
642 : struct JSObject_Slots2 : JSObject { void* data[3]; js::Value fslots[2]; };
643 : struct JSObject_Slots4 : JSObject { void* data[3]; js::Value fslots[4]; };
644 : struct JSObject_Slots8 : JSObject { void* data[3]; js::Value fslots[8]; };
645 : struct JSObject_Slots12 : JSObject { void* data[3]; js::Value fslots[12]; };
646 : struct JSObject_Slots16 : JSObject { void* data[3]; js::Value fslots[16]; };
647 :
648 : /* static */ MOZ_ALWAYS_INLINE void
649 95230 : JSObject::readBarrier(JSObject* obj)
650 : {
651 95230 : if (obj && obj->isTenured())
652 94126 : obj->asTenured().readBarrier(&obj->asTenured());
653 95230 : }
654 :
655 : /* static */ MOZ_ALWAYS_INLINE void
656 119269 : JSObject::writeBarrierPre(JSObject* obj)
657 : {
658 119269 : if (obj && obj->isTenured())
659 18143 : obj->asTenured().writeBarrierPre(&obj->asTenured());
660 119269 : }
661 :
662 : /* static */ MOZ_ALWAYS_INLINE void
663 385120 : JSObject::writeBarrierPost(void* cellp, JSObject* prev, JSObject* next)
664 : {
665 385120 : MOZ_ASSERT(cellp);
666 :
667 : // If the target needs an entry, add it.
668 : js::gc::StoreBuffer* buffer;
669 385120 : if (next && (buffer = next->storeBuffer())) {
670 : // If we know that the prev has already inserted an entry, we can skip
671 : // doing the lookup to add the new entry. Note that we cannot safely
672 : // assert the presence of the entry because it may have been added
673 : // via a different store buffer.
674 7191 : if (prev && prev->storeBuffer())
675 13 : return;
676 7178 : buffer->putCell(static_cast<js::gc::Cell**>(cellp));
677 7178 : return;
678 : }
679 :
680 : // Remove the prev entry if the new value does not need it. There will only
681 : // be a prev entry if the prev value was in the nursery.
682 377927 : if (prev && (buffer = prev->storeBuffer()))
683 624 : buffer->unputCell(static_cast<js::gc::Cell**>(cellp));
684 : }
685 :
686 : class JSValueArray {
687 : public:
688 : const js::Value* array;
689 : size_t length;
690 :
691 272 : JSValueArray(const js::Value* v, size_t c) : array(v), length(c) {}
692 : };
693 :
694 : class ValueArray {
695 : public:
696 : js::Value* array;
697 : size_t length;
698 :
699 : ValueArray(js::Value* v, size_t c) : array(v), length(c) {}
700 : };
701 :
702 : namespace js {
703 :
704 : /*** Standard internal methods ********************************************************************
705 : *
706 : * The functions below are the fundamental operations on objects. See the
707 : * comment about "Standard internal methods" in jsapi.h.
708 : */
709 :
710 : /*
711 : * ES6 [[GetPrototypeOf]]. Get obj's prototype, storing it in protop.
712 : *
713 : * If obj is definitely not a proxy, the infallible obj->getProto() can be used
714 : * instead. See the comment on JSObject::getTaggedProto().
715 : */
716 : inline bool
717 : GetPrototype(JSContext* cx, HandleObject obj, MutableHandleObject protop);
718 :
719 : /*
720 : * ES6 [[SetPrototypeOf]]. Change obj's prototype to proto.
721 : *
722 : * Returns false on error, success of operation in *result. For example, if
723 : * obj is not extensible, its prototype is fixed. js::SetPrototype will return
724 : * true, because no exception is thrown for this; but *result will be false.
725 : */
726 : extern bool
727 : SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto,
728 : ObjectOpResult& result);
729 :
730 : /* Convenience function: like the above, but throw on failure. */
731 : extern bool
732 : SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto);
733 :
734 : /*
735 : * ES6 [[IsExtensible]]. Extensible objects can have new properties defined on
736 : * them. Inextensible objects can't, and their [[Prototype]] slot is fixed as
737 : * well.
738 : */
739 : inline bool
740 : IsExtensible(JSContext* cx, HandleObject obj, bool* extensible);
741 :
742 : /*
743 : * ES6 [[PreventExtensions]]. Attempt to change the [[Extensible]] bit on |obj|
744 : * to false. Indicate success or failure through the |result| outparam, or
745 : * actual error through the return value.
746 : *
747 : * The `level` argument is SM-specific. `obj` should have an integrity level of
748 : * at least `level`.
749 : */
750 : extern bool
751 : PreventExtensions(JSContext* cx, HandleObject obj, ObjectOpResult& result, IntegrityLevel level);
752 :
753 : /* Convenience function. As above, but throw on failure. */
754 : extern bool
755 : PreventExtensions(JSContext* cx, HandleObject obj, IntegrityLevel level = IntegrityLevel::Sealed);
756 :
757 : /*
758 : * ES6 [[GetOwnProperty]]. Get a description of one of obj's own properties.
759 : *
760 : * If no such property exists on obj, return true with desc.object() set to
761 : * null.
762 : */
763 : extern bool
764 : GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
765 : MutableHandle<JS::PropertyDescriptor> desc);
766 :
767 : /* ES6 [[DefineOwnProperty]]. Define a property on obj. */
768 : extern bool
769 : DefineProperty(JSContext* cx, HandleObject obj, HandleId id,
770 : Handle<JS::PropertyDescriptor> desc, ObjectOpResult& result);
771 :
772 : extern bool
773 : DefineProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
774 : JSGetterOp getter, JSSetterOp setter, unsigned attrs, ObjectOpResult& result);
775 :
776 : extern bool
777 : DefineProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue value,
778 : JSGetterOp getter, JSSetterOp setter, unsigned attrs, ObjectOpResult& result);
779 :
780 : extern bool
781 : DefineElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue value,
782 : JSGetterOp getter, JSSetterOp setter, unsigned attrs, ObjectOpResult& result);
783 :
784 : /*
785 : * When the 'result' out-param is omitted, the behavior is the same as above, except
786 : * that any failure results in a TypeError.
787 : */
788 : extern bool
789 : DefineProperty(JSContext* cx, HandleObject obj, HandleId id, Handle<JS::PropertyDescriptor> desc);
790 :
791 : extern bool
792 : DefineProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue value,
793 : JSGetterOp getter = nullptr,
794 : JSSetterOp setter = nullptr,
795 : unsigned attrs = JSPROP_ENUMERATE);
796 :
797 : extern bool
798 : DefineProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue value,
799 : JSGetterOp getter = nullptr,
800 : JSSetterOp setter = nullptr,
801 : unsigned attrs = JSPROP_ENUMERATE);
802 :
803 : extern bool
804 : DefineElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue value,
805 : JSGetterOp getter = nullptr,
806 : JSSetterOp setter = nullptr,
807 : unsigned attrs = JSPROP_ENUMERATE);
808 :
809 : /*
810 : * ES6 [[Has]]. Set *foundp to true if `id in obj` (that is, if obj has an own
811 : * or inherited property obj[id]), false otherwise.
812 : */
813 : inline bool
814 : HasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
815 :
816 : inline bool
817 : HasProperty(JSContext* cx, HandleObject obj, PropertyName* name, bool* foundp);
818 :
819 : /*
820 : * ES6 [[Get]]. Get the value of the property `obj[id]`, or undefined if no
821 : * such property exists.
822 : *
823 : * Typically obj == receiver; if obj != receiver then the caller is most likely
824 : * a proxy using GetProperty to finish a property get that started out as
825 : * `receiver[id]`, and we've already searched the prototype chain up to `obj`.
826 : */
827 : inline bool
828 : GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
829 : MutableHandleValue vp);
830 :
831 : inline bool
832 38167 : GetProperty(JSContext* cx, HandleObject obj, HandleValue receiver, PropertyName* name,
833 : MutableHandleValue vp)
834 : {
835 76334 : RootedId id(cx, NameToId(name));
836 76334 : return GetProperty(cx, obj, receiver, id, vp);
837 : }
838 :
839 : inline bool
840 9432 : GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, HandleId id,
841 : MutableHandleValue vp)
842 : {
843 18864 : RootedValue receiverValue(cx, ObjectValue(*receiver));
844 18864 : return GetProperty(cx, obj, receiverValue, id, vp);
845 : }
846 :
847 : inline bool
848 1208 : GetProperty(JSContext* cx, HandleObject obj, HandleObject receiver, PropertyName* name,
849 : MutableHandleValue vp)
850 : {
851 2416 : RootedValue receiverValue(cx, ObjectValue(*receiver));
852 2416 : return GetProperty(cx, obj, receiverValue, name, vp);
853 : }
854 :
855 : inline bool
856 : GetElement(JSContext* cx, HandleObject obj, HandleValue receiver, uint32_t index,
857 : MutableHandleValue vp);
858 :
859 : inline bool
860 : GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
861 : MutableHandleValue vp);
862 :
863 : inline bool
864 : GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, jsid id, Value* vp);
865 :
866 : inline bool
867 : GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, jsid id, Value* vp)
868 : {
869 : return GetPropertyNoGC(cx, obj, ObjectValue(*receiver), id, vp);
870 : }
871 :
872 : inline bool
873 1648 : GetPropertyNoGC(JSContext* cx, JSObject* obj, const Value& receiver, PropertyName* name, Value* vp)
874 : {
875 1648 : return GetPropertyNoGC(cx, obj, receiver, NameToId(name), vp);
876 : }
877 :
878 : inline bool
879 : GetPropertyNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, PropertyName* name, Value* vp)
880 : {
881 : return GetPropertyNoGC(cx, obj, ObjectValue(*receiver), name, vp);
882 : }
883 :
884 : inline bool
885 : GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t index, Value* vp);
886 :
887 : inline bool
888 : GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp);
889 :
890 : // Returns whether |obj| or an object on its proto chain may have an interesting
891 : // symbol property (see JSObject::hasInterestingSymbolProperty). If it returns
892 : // true, *holder is set to the object that may have this property.
893 : MOZ_ALWAYS_INLINE bool
894 : MaybeHasInterestingSymbolProperty(JSContext* cx, JSObject* obj, Symbol* symbol,
895 : JSObject** holder = nullptr);
896 :
897 : // Like GetProperty but optimized for interesting symbol properties like
898 : // @@toStringTag.
899 : MOZ_ALWAYS_INLINE bool
900 : GetInterestingSymbolProperty(JSContext* cx, HandleObject obj, Symbol* sym, MutableHandleValue vp);
901 :
902 : /*
903 : * ES6 [[Set]]. Carry out the assignment `obj[id] = v`.
904 : *
905 : * The `receiver` argument has to do with how [[Set]] interacts with the
906 : * prototype chain and proxies. It's hard to explain and ES6 doesn't really
907 : * try. Long story short, if you just want bog-standard assignment, pass
908 : * `ObjectValue(*obj)` as receiver. Or better, use one of the signatures that
909 : * doesn't have a receiver parameter.
910 : *
911 : * Callers pass obj != receiver e.g. when a proxy is involved, obj is the
912 : * proxy's target, and the proxy is using SetProperty to finish an assignment
913 : * that started out as `receiver[id] = v`, by delegating it to obj.
914 : */
915 : inline bool
916 : SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
917 : HandleValue receiver, ObjectOpResult& result);
918 :
919 : inline bool
920 113 : SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
921 : {
922 226 : RootedValue receiver(cx, ObjectValue(*obj));
923 113 : ObjectOpResult result;
924 452 : return SetProperty(cx, obj, id, v, receiver, result) &&
925 339 : result.checkStrict(cx, obj, id);
926 : }
927 :
928 : inline bool
929 : SetProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue v,
930 : HandleValue receiver, ObjectOpResult& result)
931 : {
932 : RootedId id(cx, NameToId(name));
933 : return SetProperty(cx, obj, id, v, receiver, result);
934 : }
935 :
936 : inline bool
937 149 : SetProperty(JSContext* cx, HandleObject obj, PropertyName* name, HandleValue v)
938 : {
939 298 : RootedId id(cx, NameToId(name));
940 298 : RootedValue receiver(cx, ObjectValue(*obj));
941 149 : ObjectOpResult result;
942 745 : return SetProperty(cx, obj, id, v, receiver, result) &&
943 596 : result.checkStrict(cx, obj, id);
944 : }
945 :
946 : inline bool
947 : SetElement(JSContext* cx, HandleObject obj, uint32_t index, HandleValue v,
948 : HandleValue receiver, ObjectOpResult& result);
949 :
950 : /*
951 : * ES6 draft rev 31 (15 Jan 2015) 7.3.3 Put (O, P, V, Throw), except that on
952 : * success, the spec says this is supposed to return a boolean value, which we
953 : * don't bother doing.
954 : */
955 : inline bool
956 127 : PutProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, bool strict)
957 : {
958 254 : RootedValue receiver(cx, ObjectValue(*obj));
959 127 : ObjectOpResult result;
960 508 : return SetProperty(cx, obj, id, v, receiver, result) &&
961 381 : result.checkStrictErrorOrWarning(cx, obj, id, strict);
962 : }
963 :
964 : /*
965 : * ES6 [[Delete]]. Equivalent to the JS code `delete obj[id]`.
966 : */
967 : inline bool
968 : DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result);
969 :
970 : inline bool
971 : DeleteElement(JSContext* cx, HandleObject obj, uint32_t index, ObjectOpResult& result);
972 :
973 :
974 : /*** SpiderMonkey nonstandard internal methods ***************************************************/
975 :
976 : /**
977 : * If |obj| (underneath any functionally-transparent wrapper proxies) has as
978 : * its [[GetPrototypeOf]] trap the ordinary [[GetPrototypeOf]] behavior defined
979 : * for ordinary objects, set |*isOrdinary = true| and store |obj|'s prototype
980 : * in |result|. Otherwise set |*isOrdinary = false|. In case of error, both
981 : * outparams have unspecified value.
982 : */
983 : extern bool
984 : GetPrototypeIfOrdinary(JSContext* cx, HandleObject obj, bool* isOrdinary,
985 : MutableHandleObject protop);
986 :
987 : /*
988 : * Attempt to make |obj|'s [[Prototype]] immutable, such that subsequently
989 : * trying to change it will not work. If an internal error occurred,
990 : * returns false. Otherwise, |*succeeded| is set to true iff |obj|'s
991 : * [[Prototype]] is now immutable.
992 : */
993 : extern bool
994 : SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded);
995 :
996 : extern bool
997 : GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
998 : MutableHandle<JS::PropertyDescriptor> desc);
999 :
1000 : /*
1001 : * Deprecated. A version of HasProperty that also returns the object on which
1002 : * the property was found (but that information is unreliable for proxies), and
1003 : * the Shape of the property, if native.
1004 : */
1005 : extern bool
1006 : LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
1007 : MutableHandleObject objp, MutableHandle<PropertyResult> propp);
1008 :
1009 : inline bool
1010 3141 : LookupProperty(JSContext* cx, HandleObject obj, PropertyName* name,
1011 : MutableHandleObject objp, MutableHandle<PropertyResult> propp)
1012 : {
1013 6282 : RootedId id(cx, NameToId(name));
1014 6282 : return LookupProperty(cx, obj, id, objp, propp);
1015 : }
1016 :
1017 : /* Set *result to tell whether obj has an own property with the given id. */
1018 : extern bool
1019 : HasOwnProperty(JSContext* cx, HandleObject obj, HandleId id, bool* result);
1020 :
1021 : /**
1022 : * This enum is used to select whether the defined functions should be marked as
1023 : * builtin native instrinsics for self-hosted code.
1024 : */
1025 : enum DefineAsIntrinsic {
1026 : NotIntrinsic,
1027 : AsIntrinsic
1028 : };
1029 :
1030 : extern bool
1031 : DefineFunctions(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs,
1032 : DefineAsIntrinsic intrinsic);
1033 :
1034 : /*
1035 : * Set a watchpoint: a synchronous callback when the given property of the
1036 : * given object is set.
1037 : *
1038 : * Watchpoints are nonstandard and do not fit in well with the way ES6
1039 : * specifies [[Set]]. They are also insufficient for implementing
1040 : * Object.observe.
1041 : */
1042 : extern bool
1043 : WatchProperty(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
1044 :
1045 : /* Clear a watchpoint. */
1046 : extern bool
1047 : UnwatchProperty(JSContext* cx, HandleObject obj, HandleId id);
1048 :
1049 : /* ES6 draft rev 36 (2015 March 17) 7.1.1 ToPrimitive(vp[, preferredType]) */
1050 : extern bool
1051 : ToPrimitiveSlow(JSContext* cx, JSType hint, MutableHandleValue vp);
1052 :
1053 : inline bool
1054 2140 : ToPrimitive(JSContext* cx, MutableHandleValue vp)
1055 : {
1056 2140 : if (vp.isPrimitive())
1057 2097 : return true;
1058 43 : return ToPrimitiveSlow(cx, JSTYPE_UNDEFINED, vp);
1059 : }
1060 :
1061 : inline bool
1062 8488 : ToPrimitive(JSContext* cx, JSType preferredType, MutableHandleValue vp)
1063 : {
1064 8488 : if (vp.isPrimitive())
1065 7626 : return true;
1066 862 : return ToPrimitiveSlow(cx, preferredType, vp);
1067 : }
1068 :
1069 : /*
1070 : * toString support. (This isn't called GetClassName because there's a macro in
1071 : * <windows.h> with that name.)
1072 : */
1073 : MOZ_ALWAYS_INLINE const char*
1074 : GetObjectClassName(JSContext* cx, HandleObject obj);
1075 :
1076 : /*
1077 : * Return an object that may be used as `this` in place of obj. For most
1078 : * objects this just returns obj.
1079 : *
1080 : * Some JSObjects shouldn't be exposed directly to script. This includes (at
1081 : * least) WithEnvironmentObjects and Window objects. However, since both of
1082 : * those can be on scope chains, we sometimes would expose those as `this` if
1083 : * we were not so vigilant about calling GetThisValue where appropriate.
1084 : *
1085 : * See comments at ComputeImplicitThis.
1086 : */
1087 : Value
1088 : GetThisValue(JSObject* obj);
1089 :
1090 : /* * */
1091 :
1092 : typedef JSObject* (*ClassInitializerOp)(JSContext* cx, JS::HandleObject obj);
1093 :
1094 : /* Fast access to builtin constructors and prototypes. */
1095 : bool
1096 : GetBuiltinConstructor(JSContext* cx, JSProtoKey key, MutableHandleObject objp);
1097 :
1098 : bool
1099 : GetBuiltinPrototype(JSContext* cx, JSProtoKey key, MutableHandleObject objp);
1100 :
1101 : JSObject*
1102 : GetBuiltinPrototypePure(GlobalObject* global, JSProtoKey protoKey);
1103 :
1104 : extern bool
1105 : SetClassAndProto(JSContext* cx, HandleObject obj,
1106 : const Class* clasp, Handle<TaggedProto> proto);
1107 :
1108 : extern bool
1109 : IsStandardPrototype(JSObject* obj, JSProtoKey key);
1110 :
1111 : } /* namespace js */
1112 :
1113 : /*
1114 : * Select Object.prototype method names shared between jsapi.cpp and jsobj.cpp.
1115 : */
1116 : extern const char js_watch_str[];
1117 : extern const char js_unwatch_str[];
1118 : extern const char js_hasOwnProperty_str[];
1119 : extern const char js_isPrototypeOf_str[];
1120 : extern const char js_propertyIsEnumerable_str[];
1121 :
1122 : #ifdef JS_OLD_GETTER_SETTER_METHODS
1123 : extern const char js_defineGetter_str[];
1124 : extern const char js_defineSetter_str[];
1125 : extern const char js_lookupGetter_str[];
1126 : extern const char js_lookupSetter_str[];
1127 : #endif
1128 :
1129 : namespace js {
1130 :
1131 : inline gc::InitialHeap
1132 160690 : GetInitialHeap(NewObjectKind newKind, const Class* clasp)
1133 : {
1134 160690 : if (newKind == NurseryAllocatedProxy) {
1135 3401 : MOZ_ASSERT(clasp->isProxy());
1136 3401 : MOZ_ASSERT(clasp->hasFinalize());
1137 3401 : MOZ_ASSERT(!CanNurseryAllocateFinalizedClass(clasp));
1138 3401 : return gc::DefaultHeap;
1139 : }
1140 157289 : if (newKind != GenericObject)
1141 121727 : return gc::TenuredHeap;
1142 35562 : if (clasp->hasFinalize() && !CanNurseryAllocateFinalizedClass(clasp))
1143 10912 : return gc::TenuredHeap;
1144 24650 : return gc::DefaultHeap;
1145 : }
1146 :
1147 : bool
1148 : NewObjectWithTaggedProtoIsCachable(JSContext* cx, Handle<TaggedProto> proto,
1149 : NewObjectKind newKind, const Class* clasp);
1150 :
1151 : // ES6 9.1.15 GetPrototypeFromConstructor.
1152 : extern bool
1153 : GetPrototypeFromConstructor(JSContext* cx, js::HandleObject newTarget, js::MutableHandleObject proto);
1154 :
1155 : MOZ_ALWAYS_INLINE bool
1156 644 : GetPrototypeFromBuiltinConstructor(JSContext* cx, const CallArgs& args, js::MutableHandleObject proto)
1157 : {
1158 : // When proto is set to nullptr, the caller is expected to select the
1159 : // correct default built-in prototype for this constructor.
1160 644 : if (!args.isConstructing() || &args.newTarget().toObject() == &args.callee()) {
1161 617 : proto.set(nullptr);
1162 617 : return true;
1163 : }
1164 :
1165 : // We're calling this constructor from a derived class, retrieve the
1166 : // actual prototype from newTarget.
1167 54 : RootedObject newTarget(cx, &args.newTarget().toObject());
1168 27 : return GetPrototypeFromConstructor(cx, newTarget, proto);
1169 : }
1170 :
1171 : // Specialized call for constructing |this| with a known function callee,
1172 : // and a known prototype.
1173 : extern JSObject*
1174 : CreateThisForFunctionWithProto(JSContext* cx, js::HandleObject callee, HandleObject newTarget,
1175 : HandleObject proto, NewObjectKind newKind = GenericObject);
1176 :
1177 : // Specialized call for constructing |this| with a known function callee.
1178 : extern JSObject*
1179 : CreateThisForFunction(JSContext* cx, js::HandleObject callee, js::HandleObject newTarget,
1180 : NewObjectKind newKind);
1181 :
1182 : // Generic call for constructing |this|.
1183 : extern JSObject*
1184 : CreateThis(JSContext* cx, const js::Class* clasp, js::HandleObject callee);
1185 :
1186 : extern JSObject*
1187 : CloneObject(JSContext* cx, HandleObject obj, Handle<js::TaggedProto> proto);
1188 :
1189 : extern JSObject*
1190 : DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKind = GenericObject);
1191 :
1192 : inline JSGetterOp
1193 918 : CastAsGetterOp(JSObject* object)
1194 : {
1195 918 : return JS_DATA_TO_FUNC_PTR(JSGetterOp, object);
1196 : }
1197 :
1198 : inline JSSetterOp
1199 107 : CastAsSetterOp(JSObject* object)
1200 : {
1201 107 : return JS_DATA_TO_FUNC_PTR(JSSetterOp, object);
1202 : }
1203 :
1204 : /* ES6 draft rev 32 (2015 Feb 2) 6.2.4.5 ToPropertyDescriptor(Obj) */
1205 : bool
1206 : ToPropertyDescriptor(JSContext* cx, HandleValue descval, bool checkAccessors,
1207 : MutableHandle<JS::PropertyDescriptor> desc);
1208 :
1209 : /*
1210 : * Throw a TypeError if desc.getterObject() or setterObject() is not
1211 : * callable. This performs exactly the checks omitted by ToPropertyDescriptor
1212 : * when checkAccessors is false.
1213 : */
1214 : Result<>
1215 : CheckPropertyDescriptorAccessors(JSContext* cx, Handle<JS::PropertyDescriptor> desc);
1216 :
1217 : void
1218 : CompletePropertyDescriptor(MutableHandle<JS::PropertyDescriptor> desc);
1219 :
1220 : /*
1221 : * Read property descriptors from props, as for Object.defineProperties. See
1222 : * ES5 15.2.3.7 steps 3-5.
1223 : */
1224 : extern bool
1225 : ReadPropertyDescriptors(JSContext* cx, HandleObject props, bool checkAccessors,
1226 : AutoIdVector* ids, MutableHandle<PropertyDescriptorVector> descs);
1227 :
1228 : /* Read the name using a dynamic lookup on the scopeChain. */
1229 : extern bool
1230 : LookupName(JSContext* cx, HandlePropertyName name, HandleObject scopeChain,
1231 : MutableHandleObject objp, MutableHandleObject pobjp, MutableHandle<PropertyResult> propp);
1232 :
1233 : extern bool
1234 : LookupNameNoGC(JSContext* cx, PropertyName* name, JSObject* scopeChain,
1235 : JSObject** objp, JSObject** pobjp, PropertyResult* propp);
1236 :
1237 : /*
1238 : * Like LookupName except returns the global object if 'name' is not found in
1239 : * any preceding scope.
1240 : *
1241 : * Additionally, pobjp and propp are not needed by callers so they are not
1242 : * returned.
1243 : */
1244 : extern bool
1245 : LookupNameWithGlobalDefault(JSContext* cx, HandlePropertyName name, HandleObject scopeChain,
1246 : MutableHandleObject objp);
1247 :
1248 : /*
1249 : * Like LookupName except returns the unqualified var object if 'name' is not
1250 : * found in any preceding scope. Normally the unqualified var object is the
1251 : * global. If the value for the name in the looked-up scope is an
1252 : * uninitialized lexical, an UninitializedLexicalObject is returned.
1253 : *
1254 : * Additionally, pobjp is not needed by callers so it is not returned.
1255 : */
1256 : extern bool
1257 : LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject scopeChain,
1258 : MutableHandleObject objp);
1259 :
1260 : } // namespace js
1261 :
1262 : namespace js {
1263 :
1264 : extern JSObject*
1265 : FindVariableScope(JSContext* cx, JSFunction** funp);
1266 :
1267 : bool
1268 : LookupPropertyPure(JSContext* cx, JSObject* obj, jsid id, JSObject** objp,
1269 : PropertyResult* propp);
1270 :
1271 : bool
1272 : LookupOwnPropertyPure(JSContext* cx, JSObject* obj, jsid id, PropertyResult* propp,
1273 : bool* isTypedArrayOutOfRange = nullptr);
1274 :
1275 : bool
1276 : GetPropertyPure(JSContext* cx, JSObject* obj, jsid id, Value* vp);
1277 :
1278 : bool
1279 : GetGetterPure(JSContext* cx, JSObject* obj, jsid id, JSFunction** fp);
1280 :
1281 : bool
1282 : GetOwnGetterPure(JSContext* cx, JSObject* obj, jsid id, JSFunction** fp);
1283 :
1284 : bool
1285 : GetOwnNativeGetterPure(JSContext* cx, JSObject* obj, jsid id, JSNative* native);
1286 :
1287 : bool
1288 : HasOwnDataPropertyPure(JSContext* cx, JSObject* obj, jsid id, bool* result);
1289 :
1290 : bool
1291 : GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
1292 : MutableHandle<JS::PropertyDescriptor> desc);
1293 :
1294 : bool
1295 : GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp);
1296 :
1297 : /*
1298 : * Like JS::FromPropertyDescriptor, but ignore desc.object() and always set vp
1299 : * to an object on success.
1300 : *
1301 : * Use JS::FromPropertyDescriptor for getOwnPropertyDescriptor, since desc.object()
1302 : * is used to indicate whether a result was found or not. Use this instead for
1303 : * defineProperty: it would be senseless to define a "missing" property.
1304 : */
1305 : extern bool
1306 : FromPropertyDescriptorToObject(JSContext* cx, Handle<JS::PropertyDescriptor> desc,
1307 : MutableHandleValue vp);
1308 :
1309 : extern bool
1310 : IsDelegate(JSContext* cx, HandleObject obj, const Value& v, bool* result);
1311 :
1312 : // obj is a JSObject*, but we root it immediately up front. We do it
1313 : // that way because we need a Rooted temporary in this method anyway.
1314 : extern bool
1315 : IsDelegateOfObject(JSContext* cx, HandleObject protoObj, JSObject* obj, bool* result);
1316 :
1317 : /* Wrap boolean, number or string as Boolean, Number or String object. */
1318 : extern JSObject*
1319 : PrimitiveToObject(JSContext* cx, const Value& v);
1320 :
1321 : } /* namespace js */
1322 :
1323 : namespace js {
1324 :
1325 : /* For converting stack values to objects. */
1326 : MOZ_ALWAYS_INLINE JSObject*
1327 44521 : ToObjectFromStack(JSContext* cx, HandleValue vp)
1328 : {
1329 44521 : if (vp.isObject())
1330 44519 : return &vp.toObject();
1331 2 : return js::ToObjectSlow(cx, vp, true);
1332 : }
1333 :
1334 : template<XDRMode mode>
1335 : bool
1336 : XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj);
1337 :
1338 : /*
1339 : * Report a TypeError: "so-and-so is not an object".
1340 : * Using NotNullObject is usually less code.
1341 : */
1342 : extern void
1343 : ReportNotObject(JSContext* cx, const Value& v);
1344 :
1345 : inline JSObject*
1346 0 : NonNullObject(JSContext* cx, const Value& v)
1347 : {
1348 0 : if (v.isObject())
1349 0 : return &v.toObject();
1350 0 : ReportNotObject(cx, v);
1351 0 : return nullptr;
1352 : }
1353 :
1354 :
1355 : /*
1356 : * Report a TypeError: "N-th argument of FUN must be an object, got VALUE".
1357 : * Using NotNullObjectArg is usually less code.
1358 : */
1359 : extern void
1360 : ReportNotObjectArg(JSContext* cx, const char* nth, const char* fun, HandleValue v);
1361 :
1362 : inline JSObject*
1363 134 : NonNullObjectArg(JSContext* cx, const char* nth, const char* fun, HandleValue v)
1364 : {
1365 134 : if (v.isObject())
1366 134 : return &v.toObject();
1367 0 : ReportNotObjectArg(cx, nth, fun, v);
1368 0 : return nullptr;
1369 : }
1370 :
1371 : /*
1372 : * Report a TypeError: "SOMETHING must be an object, got VALUE".
1373 : * Using NotNullObjectWithName is usually less code.
1374 : */
1375 : extern void
1376 : ReportNotObjectWithName(JSContext* cx, const char* name, HandleValue v);
1377 :
1378 : inline JSObject*
1379 2317 : NonNullObjectWithName(JSContext* cx, const char* name, HandleValue v)
1380 : {
1381 2317 : if (v.isObject())
1382 2317 : return &v.toObject();
1383 0 : ReportNotObjectWithName(cx, name, v);
1384 0 : return nullptr;
1385 : }
1386 :
1387 :
1388 : extern bool
1389 : GetFirstArgumentAsObject(JSContext* cx, const CallArgs& args, const char* method,
1390 : MutableHandleObject objp);
1391 :
1392 : /* Helpers for throwing. These always return false. */
1393 : extern bool
1394 : Throw(JSContext* cx, jsid id, unsigned errorNumber);
1395 :
1396 : extern bool
1397 : Throw(JSContext* cx, JSObject* obj, unsigned errorNumber);
1398 :
1399 : /*
1400 : * ES6 rev 29 (6 Dec 2014) 7.3.13. Mark obj as non-extensible, and adjust each
1401 : * of obj's own properties' attributes appropriately: each property becomes
1402 : * non-configurable, and if level == Frozen, data properties become
1403 : * non-writable as well.
1404 : */
1405 : extern bool
1406 : SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level);
1407 :
1408 : inline bool
1409 2216 : FreezeObject(JSContext* cx, HandleObject obj)
1410 : {
1411 2216 : return SetIntegrityLevel(cx, obj, IntegrityLevel::Frozen);
1412 : }
1413 :
1414 : /*
1415 : * ES6 rev 29 (6 Dec 2014) 7.3.14. Code shared by Object.isSealed and
1416 : * Object.isFrozen.
1417 : */
1418 : extern bool
1419 : TestIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level, bool* resultp);
1420 :
1421 : extern bool
1422 : SpeciesConstructor(JSContext* cx, HandleObject obj, HandleValue defaultCtor, MutableHandleValue pctor);
1423 :
1424 : extern bool
1425 : SpeciesConstructor(JSContext* cx, HandleObject obj, JSProtoKey ctorKey, MutableHandleValue pctor);
1426 :
1427 : extern bool
1428 : GetObjectFromIncumbentGlobal(JSContext* cx, MutableHandleObject obj);
1429 :
1430 :
1431 : #ifdef DEBUG
1432 : inline bool
1433 310268 : IsObjectValueInCompartment(const Value& v, JSCompartment* comp)
1434 : {
1435 310268 : if (!v.isObject())
1436 165372 : return true;
1437 144897 : return v.toObject().compartment() == comp;
1438 : }
1439 : #endif
1440 :
1441 : } /* namespace js */
1442 :
1443 : #endif /* jsobj_h */
|