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 jsobjinlines_h
8 : #define jsobjinlines_h
9 :
10 : #include "jsobj.h"
11 :
12 : #include "mozilla/DebugOnly.h"
13 :
14 : #include "jsfriendapi.h"
15 : #include "jsfun.h"
16 :
17 : #include "builtin/MapObject.h"
18 : #include "builtin/TypedObject.h"
19 : #include "gc/Allocator.h"
20 : #include "vm/ArrayObject.h"
21 : #include "vm/DateObject.h"
22 : #include "vm/EnvironmentObject.h"
23 : #include "vm/NumberObject.h"
24 : #include "vm/Probes.h"
25 : #include "vm/StringObject.h"
26 : #include "vm/TypedArrayObject.h"
27 :
28 : #include "jsatominlines.h"
29 : #include "jscompartmentinlines.h"
30 : #include "jsgcinlines.h"
31 :
32 : #include "vm/ShapedObject-inl.h"
33 : #include "vm/TypeInference-inl.h"
34 :
35 : namespace js {
36 :
37 : // This is needed here for ensureShape() below.
38 : inline bool
39 13435 : MaybeConvertUnboxedObjectToNative(JSContext* cx, JSObject* obj)
40 : {
41 13435 : if (obj->is<UnboxedPlainObject>())
42 0 : return UnboxedPlainObject::convertToNative(cx, obj);
43 13435 : if (obj->is<UnboxedArrayObject>())
44 0 : return UnboxedArrayObject::convertToNative(cx, obj);
45 13435 : return true;
46 : }
47 :
48 : static MOZ_ALWAYS_INLINE bool
49 13561 : ClassMayResolveId(const JSAtomState& names, const Class* clasp, jsid id, JSObject* maybeObj)
50 : {
51 13561 : MOZ_ASSERT_IF(maybeObj, maybeObj->getClass() == clasp);
52 :
53 13561 : if (!clasp->getResolve()) {
54 : // Sanity check: we should only have a mayResolve hook if we have a
55 : // resolve hook.
56 12124 : MOZ_ASSERT(!clasp->getMayResolve(), "Class with mayResolve hook but no resolve hook");
57 12124 : return false;
58 : }
59 :
60 1437 : if (JSMayResolveOp mayResolve = clasp->getMayResolve()) {
61 : // Tell the analysis our mayResolve hooks won't trigger GC.
62 300 : JS::AutoSuppressGCAnalysis nogc;
63 283 : if (!mayResolve(names, id, maybeObj))
64 266 : return false;
65 : }
66 :
67 1171 : return true;
68 : }
69 :
70 : } // namespace js
71 :
72 : inline js::Shape*
73 728433 : JSObject::maybeShape() const
74 : {
75 728433 : if (!is<js::ShapedObject>())
76 197 : return nullptr;
77 :
78 728236 : return as<js::ShapedObject>().shape();
79 : }
80 :
81 : inline js::Shape*
82 10037 : JSObject::ensureShape(JSContext* cx)
83 : {
84 10037 : if (!js::MaybeConvertUnboxedObjectToNative(cx, this))
85 0 : return nullptr;
86 10037 : js::Shape* shape = maybeShape();
87 10037 : MOZ_ASSERT(shape);
88 10037 : return shape;
89 : }
90 :
91 : inline void
92 0 : JSObject::finalize(js::FreeOp* fop)
93 : {
94 0 : js::probes::FinalizeObject(this);
95 :
96 : #ifdef DEBUG
97 0 : MOZ_ASSERT(isTenured());
98 0 : if (!IsBackgroundFinalized(asTenured().getAllocKind())) {
99 : /* Assert we're on the active thread. */
100 0 : MOZ_ASSERT(CurrentThreadCanAccessZone(zone()));
101 : }
102 : #endif
103 :
104 0 : const js::Class* clasp = getClass();
105 0 : js::NativeObject* nobj = nullptr;
106 0 : if (clasp->isNative())
107 0 : nobj = &as<js::NativeObject>();
108 0 : if (clasp->hasFinalize())
109 0 : clasp->doFinalize(fop, this);
110 :
111 0 : if (!nobj)
112 0 : return;
113 :
114 0 : if (nobj->hasDynamicSlots())
115 0 : fop->free_(nobj->slots_);
116 :
117 0 : if (nobj->hasDynamicElements()) {
118 0 : js::ObjectElements* elements = nobj->getElementsHeader();
119 0 : if (elements->isCopyOnWrite()) {
120 0 : if (elements->ownerObject() == this) {
121 : // Don't free the elements until object finalization finishes,
122 : // so that other objects can access these elements while they
123 : // are themselves finalized.
124 0 : MOZ_ASSERT(elements->numShiftedElements() == 0);
125 0 : fop->freeLater(elements);
126 : }
127 : } else {
128 0 : fop->free_(nobj->getUnshiftedElementsHeader());
129 : }
130 : }
131 :
132 0 : nobj->sweepDictionaryListPointer();
133 : }
134 :
135 : MOZ_ALWAYS_INLINE void
136 0 : js::NativeObject::sweepDictionaryListPointer()
137 : {
138 : // For dictionary objects (which must be native), it's possible that
139 : // unreachable shapes may be marked whose listp points into this object. In
140 : // case this happens, null out the shape's pointer so that a moving GC will
141 : // not try to access the dead object.
142 0 : if (shape_->listp == &shape_)
143 0 : shape_->listp = nullptr;
144 0 : }
145 :
146 : /* static */ inline bool
147 78619 : JSObject::setSingleton(JSContext* cx, js::HandleObject obj)
148 : {
149 78619 : MOZ_ASSERT(!IsInsideNursery(obj));
150 :
151 78619 : js::ObjectGroup* group = js::ObjectGroup::lazySingletonGroup(cx, obj->getClass(),
152 157237 : obj->taggedProto());
153 78618 : if (!group)
154 0 : return false;
155 :
156 78618 : obj->group_ = group;
157 78619 : return true;
158 : }
159 :
160 : /* static */ inline js::ObjectGroup*
161 9199 : JSObject::getGroup(JSContext* cx, js::HandleObject obj)
162 : {
163 9199 : MOZ_ASSERT(cx->compartment() == obj->compartment());
164 9199 : if (obj->hasLazyGroup()) {
165 3862 : if (cx->compartment() != obj->compartment())
166 0 : MOZ_CRASH();
167 3862 : return makeLazyGroup(cx, obj);
168 : }
169 5337 : return obj->group_;
170 : }
171 :
172 : inline void
173 43274 : JSObject::setGroup(js::ObjectGroup* group)
174 : {
175 43274 : MOZ_RELEASE_ASSERT(group);
176 43274 : MOZ_ASSERT(!isSingleton());
177 43274 : group_ = group;
178 43274 : }
179 :
180 :
181 : /*** Standard internal methods *******************************************************************/
182 :
183 : inline bool
184 2904 : js::GetPrototype(JSContext* cx, js::HandleObject obj, js::MutableHandleObject protop)
185 : {
186 2904 : if (obj->hasDynamicPrototype()) {
187 440 : MOZ_ASSERT(obj->is<js::ProxyObject>());
188 440 : return js::Proxy::getPrototype(cx, obj, protop);
189 : }
190 :
191 2464 : protop.set(obj->taggedProto().toObjectOrNull());
192 2464 : return true;
193 : }
194 :
195 : inline bool
196 724 : js::IsExtensible(JSContext* cx, HandleObject obj, bool* extensible)
197 : {
198 724 : if (obj->is<ProxyObject>()) {
199 0 : MOZ_ASSERT(!cx->helperThread());
200 0 : return Proxy::isExtensible(cx, obj, extensible);
201 : }
202 :
203 724 : *extensible = obj->nonProxyIsExtensible();
204 724 : return true;
205 : }
206 :
207 : inline bool
208 0 : js::HasProperty(JSContext* cx, HandleObject obj, PropertyName* name, bool* found)
209 : {
210 0 : RootedId id(cx, NameToId(name));
211 0 : return HasProperty(cx, obj, id, found);
212 : }
213 :
214 : inline bool
215 1888 : js::GetElement(JSContext* cx, HandleObject obj, HandleValue receiver, uint32_t index,
216 : MutableHandleValue vp)
217 : {
218 3776 : RootedId id(cx);
219 1888 : if (!IndexToId(cx, index, &id))
220 0 : return false;
221 1888 : return GetProperty(cx, obj, receiver, id, vp);
222 : }
223 :
224 : inline bool
225 1797 : js::GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
226 : MutableHandleValue vp)
227 : {
228 3594 : RootedValue receiverValue(cx, ObjectValue(*receiver));
229 3594 : return GetElement(cx, obj, receiverValue, index, vp);
230 : }
231 :
232 : inline bool
233 1504 : js::GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t index, Value* vp)
234 : {
235 1504 : if (obj->getOpsGetProperty())
236 77 : return false;
237 :
238 1427 : if (index > JSID_INT_MAX)
239 0 : return false;
240 1427 : return GetPropertyNoGC(cx, obj, receiver, INT_TO_JSID(index), vp);
241 : }
242 :
243 : inline bool
244 : js::GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp)
245 : {
246 : return GetElementNoGC(cx, obj, ObjectValue(*receiver), index, vp);
247 : }
248 :
249 : inline bool
250 874 : js::DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
251 : {
252 874 : MarkTypePropertyNonData(cx, obj, id);
253 874 : if (DeletePropertyOp op = obj->getOpsDeleteProperty())
254 414 : return op(cx, obj, id, result);
255 460 : return NativeDeleteProperty(cx, obj.as<NativeObject>(), id, result);
256 : }
257 :
258 : inline bool
259 0 : js::DeleteElement(JSContext* cx, HandleObject obj, uint32_t index, ObjectOpResult& result)
260 : {
261 0 : RootedId id(cx);
262 0 : if (!IndexToId(cx, index, &id))
263 0 : return false;
264 0 : return DeleteProperty(cx, obj, id, result);
265 : }
266 :
267 : MOZ_ALWAYS_INLINE bool
268 942 : js::MaybeHasInterestingSymbolProperty(JSContext* cx, JSObject* obj, Symbol* symbol,
269 : JSObject** holder)
270 : {
271 942 : MOZ_ASSERT(symbol->isInterestingSymbol());
272 :
273 942 : jsid id = SYMBOL_TO_JSID(symbol);
274 184 : do {
275 3342 : if (obj->maybeHasInterestingSymbolProperty() ||
276 2475 : obj->hasDynamicPrototype() ||
277 1349 : MOZ_UNLIKELY(ClassMayResolveId(cx->names(), obj->getClass(), id, obj) ||
278 : obj->getClass()->getGetProperty()))
279 : {
280 867 : if (holder)
281 867 : *holder = obj;
282 867 : return true;
283 : }
284 259 : obj = obj->staticPrototype();
285 259 : } while (obj);
286 :
287 75 : return false;
288 : }
289 :
290 : MOZ_ALWAYS_INLINE bool
291 942 : js::GetInterestingSymbolProperty(JSContext* cx, HandleObject obj, Symbol* sym, MutableHandleValue vp)
292 : {
293 : JSObject* holder;
294 942 : if (!MaybeHasInterestingSymbolProperty(cx, obj, sym, &holder)) {
295 : #ifdef DEBUG
296 150 : RootedValue receiver(cx, ObjectValue(*obj));
297 150 : RootedId id(cx, SYMBOL_TO_JSID(sym));
298 75 : if (!GetProperty(cx, obj, receiver, id, vp))
299 0 : return false;
300 75 : MOZ_ASSERT(vp.isUndefined());
301 : #endif
302 75 : vp.setUndefined();
303 75 : return true;
304 : }
305 :
306 1734 : RootedObject holderRoot(cx, holder);
307 1734 : RootedValue receiver(cx, ObjectValue(*obj));
308 1734 : RootedId id(cx, SYMBOL_TO_JSID(sym));
309 867 : return GetProperty(cx, holderRoot, receiver, id, vp);
310 : }
311 :
312 : /* * */
313 :
314 : inline bool
315 7849 : JSObject::isQualifiedVarObj() const
316 : {
317 7849 : if (is<js::DebugEnvironmentProxy>())
318 0 : return as<js::DebugEnvironmentProxy>().environment().isQualifiedVarObj();
319 7849 : bool rv = hasAllFlags(js::BaseShape::QUALIFIED_VAROBJ);
320 7849 : MOZ_ASSERT_IF(rv,
321 : is<js::GlobalObject>() ||
322 : is<js::CallObject>() ||
323 : is<js::VarEnvironmentObject>() ||
324 : is<js::ModuleEnvironmentObject>() ||
325 : is<js::NonSyntacticVariablesObject>() ||
326 : (is<js::WithEnvironmentObject>() &&
327 : !as<js::WithEnvironmentObject>().isSyntactic()));
328 7849 : return rv;
329 : }
330 :
331 : inline bool
332 2871 : JSObject::isUnqualifiedVarObj() const
333 : {
334 2871 : if (is<js::DebugEnvironmentProxy>())
335 0 : return as<js::DebugEnvironmentProxy>().environment().isUnqualifiedVarObj();
336 2871 : return is<js::GlobalObject>() || is<js::NonSyntacticVariablesObject>();
337 : }
338 :
339 : namespace js {
340 :
341 : inline bool
342 265010 : ClassCanHaveFixedData(const Class* clasp)
343 : {
344 : // Normally, the number of fixed slots given an object is the maximum
345 : // permitted for its size class. For array buffers and non-shared typed
346 : // arrays we only use enough to cover the class reserved slots, so that
347 : // the remaining space in the object's allocation is available for the
348 : // buffer's data.
349 265010 : return !clasp->isNative()
350 255625 : || clasp == &js::ArrayBufferObject::class_
351 520637 : || js::IsTypedArrayClass(clasp);
352 : }
353 :
354 : // This function is meant to be called from allocation fast paths.
355 : //
356 : // If we do have an allocation metadata builder, it can cause a GC, so the object
357 : // must be rooted. The usual way to do this would be to make our callers pass a
358 : // HandleObject, but that would require them to pay the cost of rooting the
359 : // object unconditionally, even though collecting metadata is rare. Instead,
360 : // SetNewObjectMetadata's contract is that the caller must use the pointer
361 : // returned in place of the pointer passed. If a GC occurs, the returned pointer
362 : // may be the passed pointer, relocated by GC. If no GC could occur, it's just
363 : // passed through. We root nothing unless necessary.
364 : template <typename T>
365 : static MOZ_ALWAYS_INLINE MOZ_MUST_USE T*
366 168426 : SetNewObjectMetadata(JSContext* cx, T* obj)
367 : {
368 168426 : MOZ_ASSERT(!cx->compartment()->hasObjectPendingMetadata());
369 :
370 : // The metadata builder is invoked for each object created on the active
371 : // thread, except when analysis/compilation is active, to avoid recursion.
372 168426 : if (!cx->helperThread()) {
373 160729 : if (MOZ_UNLIKELY((size_t)cx->compartment()->hasAllocationMetadataBuilder()) &&
374 0 : !cx->zone()->suppressAllocationMetadataBuilder)
375 : {
376 : // Don't collect metadata on objects that represent metadata.
377 0 : AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
378 :
379 0 : Rooted<T*> rooted(cx, obj);
380 0 : cx->compartment()->setNewObjectMetadata(cx, rooted);
381 0 : return rooted;
382 : }
383 : }
384 :
385 168426 : return obj;
386 : }
387 :
388 : } // namespace js
389 :
390 : inline void
391 168669 : JSObject::setInitialSlotsMaybeNonNative(js::HeapSlot* slots)
392 : {
393 168669 : static_cast<js::NativeObject*>(this)->slots_ = slots;
394 168669 : }
395 :
396 : inline void
397 131360 : JSObject::setInitialElementsMaybeNonNative(js::HeapSlot* elements)
398 : {
399 131360 : static_cast<js::NativeObject*>(this)->elements_ = elements;
400 131360 : }
401 :
402 : inline js::GlobalObject&
403 123826 : JSObject::global() const
404 : {
405 : /*
406 : * The global is read-barriered so that it is kept live by access through
407 : * the JSCompartment. When accessed through a JSObject, however, the global
408 : * will be already be kept live by the black JSObject's parent pointer, so
409 : * does not need to be read-barriered.
410 : */
411 123826 : return *compartment()->unsafeUnbarrieredMaybeGlobal();
412 : }
413 :
414 : inline js::GlobalObject*
415 26 : JSObject::globalForTracing(JSTracer*) const
416 : {
417 26 : return compartment()->unsafeUnbarrieredMaybeGlobal();
418 : }
419 :
420 : inline bool
421 26 : JSObject::isOwnGlobal(JSTracer* trc) const
422 : {
423 26 : return globalForTracing(trc) == this;
424 : }
425 :
426 : inline bool
427 687546 : JSObject::hasAllFlags(js::BaseShape::Flag flags) const
428 : {
429 687546 : MOZ_ASSERT(flags);
430 687546 : if (js::Shape* shape = maybeShape())
431 687424 : return shape->hasAllObjectFlags(flags);
432 130 : return false;
433 : }
434 :
435 : inline bool
436 279942 : JSObject::nonProxyIsExtensible() const
437 : {
438 279942 : MOZ_ASSERT(!uninlinedIsProxy());
439 :
440 : // [[Extensible]] for ordinary non-proxy objects is an object flag.
441 279944 : return !hasAllFlags(js::BaseShape::NOT_EXTENSIBLE);
442 : }
443 :
444 : inline bool
445 973 : JSObject::isBoundFunction() const
446 : {
447 973 : return is<JSFunction>() && as<JSFunction>().isBoundFunction();
448 : }
449 :
450 : inline bool
451 13101 : JSObject::watched() const
452 : {
453 13101 : return hasAllFlags(js::BaseShape::WATCHED);
454 : }
455 :
456 : inline bool
457 217512 : JSObject::isDelegate() const
458 : {
459 217512 : return hasAllFlags(js::BaseShape::DELEGATE);
460 : }
461 :
462 : inline bool
463 2773 : JSObject::hasUncacheableProto() const
464 : {
465 2773 : return hasAllFlags(js::BaseShape::UNCACHEABLE_PROTO);
466 : }
467 :
468 : inline bool
469 115885 : JSObject::hadElementsAccess() const
470 : {
471 115885 : return hasAllFlags(js::BaseShape::HAD_ELEMENTS_ACCESS);
472 : }
473 :
474 : inline bool
475 18326 : JSObject::isIndexed() const
476 : {
477 18326 : return hasAllFlags(js::BaseShape::INDEXED);
478 : }
479 :
480 : MOZ_ALWAYS_INLINE bool
481 1126 : JSObject::maybeHasInterestingSymbolProperty() const
482 : {
483 : const js::NativeObject* nobj;
484 1126 : if (isNative()) {
485 1125 : nobj = &as<js::NativeObject>();
486 1 : } else if (is<js::UnboxedPlainObject>()) {
487 0 : nobj = as<js::UnboxedPlainObject>().maybeExpando();
488 0 : if (!nobj)
489 0 : return false;
490 : } else {
491 1 : return true;
492 : }
493 :
494 1125 : return nobj->hasAllFlags(js::BaseShape::HAS_INTERESTING_SYMBOL);
495 : }
496 :
497 : inline bool
498 6716 : JSObject::staticPrototypeIsImmutable() const
499 : {
500 6716 : MOZ_ASSERT(hasStaticPrototype());
501 6716 : return hasAllFlags(js::BaseShape::IMMUTABLE_PROTOTYPE);
502 : }
503 :
504 : inline bool
505 3859 : JSObject::isIteratedSingleton() const
506 : {
507 3859 : return hasAllFlags(js::BaseShape::ITERATED_SINGLETON);
508 : }
509 :
510 : inline bool
511 6419 : JSObject::isNewGroupUnknown() const
512 : {
513 6419 : return hasAllFlags(js::BaseShape::NEW_GROUP_UNKNOWN);
514 : }
515 :
516 : inline bool
517 528 : JSObject::wasNewScriptCleared() const
518 : {
519 528 : return hasAllFlags(js::BaseShape::NEW_SCRIPT_CLEARED);
520 : }
521 :
522 : namespace js {
523 :
524 : static MOZ_ALWAYS_INLINE bool
525 8 : IsFunctionObject(const js::Value& v)
526 : {
527 8 : return v.isObject() && v.toObject().is<JSFunction>();
528 : }
529 :
530 : static MOZ_ALWAYS_INLINE bool
531 32515 : IsFunctionObject(const js::Value& v, JSFunction** fun)
532 : {
533 32515 : if (v.isObject() && v.toObject().is<JSFunction>()) {
534 29270 : *fun = &v.toObject().as<JSFunction>();
535 29270 : return true;
536 : }
537 3245 : return false;
538 : }
539 :
540 : static MOZ_ALWAYS_INLINE bool
541 : IsNativeFunction(const js::Value& v)
542 : {
543 : JSFunction* fun;
544 : return IsFunctionObject(v, &fun) && fun->isNative();
545 : }
546 :
547 : static MOZ_ALWAYS_INLINE bool
548 : IsNativeFunction(const js::Value& v, JSFunction** fun)
549 : {
550 : return IsFunctionObject(v, fun) && (*fun)->isNative();
551 : }
552 :
553 : static MOZ_ALWAYS_INLINE bool
554 437 : IsNativeFunction(const js::Value& v, JSNative native)
555 : {
556 : JSFunction* fun;
557 437 : return IsFunctionObject(v, &fun) && fun->maybeNative() == native;
558 : }
559 :
560 :
561 : // Return whether looking up a method on 'obj' definitely resolves to the
562 : // original specified native function. The method may conservatively return
563 : // 'false' in the case of proxies or other non-native objects.
564 : static MOZ_ALWAYS_INLINE bool
565 1 : HasNativeMethodPure(JSObject* obj, PropertyName* name, JSNative native, JSContext* cx)
566 : {
567 1 : Value v;
568 1 : if (!GetPropertyPure(cx, obj, NameToId(name), &v))
569 0 : return false;
570 :
571 1 : return IsNativeFunction(v, native);
572 : }
573 :
574 : // Return whether 'obj' definitely has no @@toPrimitive method.
575 : static MOZ_ALWAYS_INLINE bool
576 1 : HasNoToPrimitiveMethodPure(JSObject* obj, JSContext* cx)
577 : {
578 1 : jsid id = SYMBOL_TO_JSID(cx->wellKnownSymbols().toPrimitive);
579 : JSObject* pobj;
580 1 : PropertyResult prop;
581 1 : if (!LookupPropertyPure(cx, obj, id, &pobj, &prop))
582 0 : return false;
583 :
584 1 : return !prop;
585 : }
586 :
587 : /* ES6 draft rev 28 (2014 Oct 14) 7.1.14 */
588 : inline bool
589 8227 : ToPropertyKey(JSContext* cx, HandleValue argument, MutableHandleId result)
590 : {
591 : // Steps 1-2.
592 16454 : RootedValue key(cx, argument);
593 8227 : if (!ToPrimitive(cx, JSTYPE_STRING, &key))
594 0 : return false;
595 :
596 : // Steps 3-4.
597 8227 : return ValueToId<CanGC>(cx, key, result);
598 : }
599 :
600 : /*
601 : * Return true if this is a compiler-created internal function accessed by
602 : * its own object. Such a function object must not be accessible to script
603 : * or embedding code.
604 : */
605 : inline bool
606 2641 : IsInternalFunctionObject(JSObject& funobj)
607 : {
608 2641 : JSFunction& fun = funobj.as<JSFunction>();
609 2641 : return fun.isInterpreted() && !fun.environment();
610 : }
611 :
612 : /*
613 : * Make an object with the specified prototype. If parent is null, it will
614 : * default to the prototype's global if the prototype is non-null.
615 : */
616 : JSObject*
617 : NewObjectWithGivenTaggedProto(JSContext* cx, const Class* clasp, Handle<TaggedProto> proto,
618 : gc::AllocKind allocKind, NewObjectKind newKind,
619 : uint32_t initialShapeFlags = 0);
620 :
621 : inline JSObject*
622 22544 : NewObjectWithGivenTaggedProto(JSContext* cx, const Class* clasp, Handle<TaggedProto> proto,
623 : NewObjectKind newKind = GenericObject,
624 : uint32_t initialShapeFlags = 0)
625 : {
626 22544 : gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
627 22544 : return NewObjectWithGivenTaggedProto(cx, clasp, proto, allocKind, newKind, initialShapeFlags);
628 : }
629 :
630 : template <typename T>
631 : inline T*
632 5816 : NewObjectWithGivenTaggedProto(JSContext* cx, Handle<TaggedProto> proto,
633 : NewObjectKind newKind = GenericObject,
634 : uint32_t initialShapeFlags = 0)
635 : {
636 : JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, proto, newKind,
637 5816 : initialShapeFlags);
638 5816 : return obj ? &obj->as<T>() : nullptr;
639 : }
640 :
641 : template <typename T>
642 : inline T*
643 1634 : NewObjectWithNullTaggedProto(JSContext* cx, NewObjectKind newKind = GenericObject,
644 : uint32_t initialShapeFlags = 0)
645 : {
646 3268 : Rooted<TaggedProto> nullProto(cx, TaggedProto(nullptr));
647 3268 : return NewObjectWithGivenTaggedProto<T>(cx, nullProto, newKind, initialShapeFlags);
648 : }
649 :
650 : inline JSObject*
651 62 : NewObjectWithGivenProto(JSContext* cx, const Class* clasp, HandleObject proto,
652 : gc::AllocKind allocKind, NewObjectKind newKind)
653 : {
654 62 : return NewObjectWithGivenTaggedProto(cx, clasp, AsTaggedProto(proto), allocKind,
655 62 : newKind);
656 : }
657 :
658 : inline JSObject*
659 16727 : NewObjectWithGivenProto(JSContext* cx, const Class* clasp, HandleObject proto,
660 : NewObjectKind newKind = GenericObject)
661 : {
662 16727 : return NewObjectWithGivenTaggedProto(cx, clasp, AsTaggedProto(proto), newKind);
663 : }
664 :
665 : template <typename T>
666 : inline T*
667 4182 : NewObjectWithGivenProto(JSContext* cx, HandleObject proto,
668 : NewObjectKind newKind = GenericObject)
669 : {
670 4182 : return NewObjectWithGivenTaggedProto<T>(cx, AsTaggedProto(proto), newKind);
671 : }
672 :
673 : template <typename T>
674 : inline T*
675 66 : NewObjectWithGivenProto(JSContext* cx, HandleObject proto,
676 : gc::AllocKind allocKind, NewObjectKind newKind = GenericObject)
677 : {
678 66 : JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, AsTaggedProto(proto),
679 66 : allocKind, newKind);
680 66 : return obj ? &obj->as<T>() : nullptr;
681 : }
682 :
683 : // Make an object with the prototype set according to the cached prototype or
684 : // Object.prototype.
685 : JSObject*
686 : NewObjectWithClassProtoCommon(JSContext* cx, const Class* clasp, HandleObject proto,
687 : gc::AllocKind allocKind, NewObjectKind newKind);
688 :
689 : inline JSObject*
690 117050 : NewObjectWithClassProto(JSContext* cx, const Class* clasp, HandleObject proto,
691 : gc::AllocKind allocKind, NewObjectKind newKind = GenericObject)
692 : {
693 117050 : return NewObjectWithClassProtoCommon(cx, clasp, proto, allocKind, newKind);
694 : }
695 :
696 : inline JSObject*
697 2153 : NewObjectWithClassProto(JSContext* cx, const Class* clasp, HandleObject proto,
698 : NewObjectKind newKind = GenericObject)
699 : {
700 2153 : gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
701 2153 : return NewObjectWithClassProto(cx, clasp, proto, allocKind, newKind);
702 : }
703 :
704 : template<class T>
705 : inline T*
706 2000 : NewObjectWithClassProto(JSContext* cx, HandleObject proto = nullptr,
707 : NewObjectKind newKind = GenericObject)
708 : {
709 2000 : JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, newKind);
710 2000 : return obj ? &obj->as<T>() : nullptr;
711 : }
712 :
713 : template <class T>
714 : inline T*
715 0 : NewObjectWithClassProto(JSContext* cx, HandleObject proto, gc::AllocKind allocKind,
716 : NewObjectKind newKind = GenericObject)
717 : {
718 0 : JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, allocKind, newKind);
719 0 : return obj ? &obj->as<T>() : nullptr;
720 : }
721 :
722 : /*
723 : * Create a native instance of the given class with parent and proto set
724 : * according to the context's active global.
725 : */
726 : inline JSObject*
727 7507 : NewBuiltinClassInstance(JSContext* cx, const Class* clasp, gc::AllocKind allocKind,
728 : NewObjectKind newKind = GenericObject)
729 : {
730 7507 : return NewObjectWithClassProto(cx, clasp, nullptr, allocKind, newKind);
731 : }
732 :
733 : inline JSObject*
734 1020 : NewBuiltinClassInstance(JSContext* cx, const Class* clasp, NewObjectKind newKind = GenericObject)
735 : {
736 1020 : gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
737 1020 : return NewBuiltinClassInstance(cx, clasp, allocKind, newKind);
738 : }
739 :
740 : template<typename T>
741 : inline T*
742 1019 : NewBuiltinClassInstance(JSContext* cx, NewObjectKind newKind = GenericObject)
743 : {
744 1019 : JSObject* obj = NewBuiltinClassInstance(cx, &T::class_, newKind);
745 1019 : return obj ? &obj->as<T>() : nullptr;
746 : }
747 :
748 : template<typename T>
749 : inline T*
750 6487 : NewBuiltinClassInstance(JSContext* cx, gc::AllocKind allocKind, NewObjectKind newKind = GenericObject)
751 : {
752 6487 : JSObject* obj = NewBuiltinClassInstance(cx, &T::class_, allocKind, newKind);
753 6487 : return obj ? &obj->as<T>() : nullptr;
754 : }
755 :
756 : // Used to optimize calls to (new Object())
757 : bool
758 : NewObjectScriptedCall(JSContext* cx, MutableHandleObject obj);
759 :
760 : JSObject*
761 : NewObjectWithGroupCommon(JSContext* cx, HandleObjectGroup group,
762 : gc::AllocKind allocKind, NewObjectKind newKind);
763 :
764 : template <typename T>
765 : inline T*
766 5699 : NewObjectWithGroup(JSContext* cx, HandleObjectGroup group,
767 : gc::AllocKind allocKind, NewObjectKind newKind = GenericObject)
768 : {
769 5699 : JSObject* obj = NewObjectWithGroupCommon(cx, group, allocKind, newKind);
770 5699 : return obj ? &obj->as<T>() : nullptr;
771 : }
772 :
773 : template <typename T>
774 : inline T*
775 223 : NewObjectWithGroup(JSContext* cx, HandleObjectGroup group,
776 : NewObjectKind newKind = GenericObject)
777 : {
778 223 : gc::AllocKind allocKind = gc::GetGCObjectKind(group->clasp());
779 223 : return NewObjectWithGroup<T>(cx, group, allocKind, newKind);
780 : }
781 :
782 : /*
783 : * As for gc::GetGCObjectKind, where numElements is a guess at the final size of
784 : * the object, zero if the final size is unknown. This should only be used for
785 : * objects that do not require any fixed slots.
786 : */
787 : static inline gc::AllocKind
788 577 : GuessObjectGCKind(size_t numElements)
789 : {
790 577 : if (numElements)
791 446 : return gc::GetGCObjectKind(numElements);
792 131 : return gc::AllocKind::OBJECT4;
793 : }
794 :
795 : static inline gc::AllocKind
796 5815 : GuessArrayGCKind(size_t numElements)
797 : {
798 5815 : if (numElements)
799 4288 : return gc::GetGCArrayKind(numElements);
800 1527 : return gc::AllocKind::OBJECT8;
801 : }
802 :
803 : // Returns ESClass::Other if the value isn't an object, or if the object
804 : // isn't of one of the enumerated classes. Otherwise returns the appropriate
805 : // class.
806 : inline bool
807 2 : GetClassOfValue(JSContext* cx, HandleValue v, ESClass* cls)
808 : {
809 2 : if (!v.isObject()) {
810 2 : *cls = ESClass::Other;
811 2 : return true;
812 : }
813 :
814 0 : RootedObject obj(cx, &v.toObject());
815 0 : return GetBuiltinClass(cx, obj, cls);
816 : }
817 :
818 : extern NativeObject*
819 : InitClass(JSContext* cx, HandleObject obj, HandleObject parent_proto,
820 : const Class* clasp, JSNative constructor, unsigned nargs,
821 : const JSPropertySpec* ps, const JSFunctionSpec* fs,
822 : const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs,
823 : NativeObject** ctorp = nullptr,
824 : gc::AllocKind ctorKind = gc::AllocKind::FUNCTION);
825 :
826 : MOZ_ALWAYS_INLINE const char*
827 1 : GetObjectClassName(JSContext* cx, HandleObject obj)
828 : {
829 1 : assertSameCompartment(cx, obj);
830 :
831 1 : if (obj->is<ProxyObject>())
832 0 : return Proxy::className(cx, obj);
833 :
834 1 : return obj->getClass()->name;
835 : }
836 :
837 : inline bool
838 4993 : IsCallable(const Value& v)
839 : {
840 4993 : return v.isObject() && v.toObject().isCallable();
841 : }
842 :
843 : // ES6 rev 24 (2014 April 27) 7.2.5 IsConstructor
844 : inline bool
845 4133 : IsConstructor(const Value& v)
846 : {
847 4133 : return v.isObject() && v.toObject().isConstructor();
848 : }
849 :
850 : } /* namespace js */
851 :
852 : MOZ_ALWAYS_INLINE bool
853 26087 : JSObject::isCallable() const
854 : {
855 26087 : if (is<JSFunction>())
856 24758 : return true;
857 1329 : return callHook() != nullptr;
858 : }
859 :
860 : MOZ_ALWAYS_INLINE bool
861 4813 : JSObject::isConstructor() const
862 : {
863 4813 : if (is<JSFunction>()) {
864 3924 : const JSFunction& fun = as<JSFunction>();
865 3924 : return fun.isConstructor();
866 : }
867 889 : return constructHook() != nullptr;
868 : }
869 :
870 : MOZ_ALWAYS_INLINE JSNative
871 6371 : JSObject::callHook() const
872 : {
873 6371 : const js::Class* clasp = getClass();
874 :
875 6371 : if (JSNative call = clasp->getCall())
876 116 : return call;
877 :
878 6255 : if (is<js::ProxyObject>()) {
879 5546 : const js::ProxyObject& p = as<js::ProxyObject>();
880 5546 : if (p.handler()->isCallable(const_cast<JSObject*>(this)))
881 5312 : return js::proxy_Call;
882 : }
883 943 : return nullptr;
884 : }
885 :
886 : MOZ_ALWAYS_INLINE JSNative
887 1141 : JSObject::constructHook() const
888 : {
889 1141 : const js::Class* clasp = getClass();
890 :
891 1141 : if (JSNative construct = clasp->getConstruct())
892 226 : return construct;
893 :
894 915 : if (is<js::ProxyObject>()) {
895 900 : const js::ProxyObject& p = as<js::ProxyObject>();
896 900 : if (p.handler()->isConstructor(const_cast<JSObject*>(this)))
897 882 : return js::proxy_Construct;
898 : }
899 33 : return nullptr;
900 : }
901 :
902 : #endif /* jsobjinlines_h */
|