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/NumberObject.h"
23 #include "vm/Probes.h"
24 #include "vm/ScopeObject.h"
25 #include "vm/StringObject.h"
26 #include "vm/TypedArrayCommon.h"
27
28 #include "jsatominlines.h"
29 #include "jscompartmentinlines.h"
30 #include "jsgcinlines.h"
31
32 #include "vm/TypeInference-inl.h"
33
34 namespace js {
35
36 // This is needed here for ensureShape() below.
37 inline bool
MaybeConvertUnboxedObjectToNative(ExclusiveContext * cx,JSObject * obj)38 MaybeConvertUnboxedObjectToNative(ExclusiveContext* cx, JSObject* obj)
39 {
40 if (obj->is<UnboxedPlainObject>())
41 return UnboxedPlainObject::convertToNative(cx->asJSContext(), obj);
42 if (obj->is<UnboxedArrayObject>())
43 return UnboxedArrayObject::convertToNative(cx->asJSContext(), obj);
44 return true;
45 }
46
47 } // namespace js
48
49 inline js::Shape*
maybeShape()50 JSObject::maybeShape() const
51 {
52 if (is<js::UnboxedPlainObject>() || is<js::UnboxedArrayObject>())
53 return nullptr;
54 return *reinterpret_cast<js::Shape**>(uintptr_t(this) + offsetOfShape());
55 }
56
57 inline js::Shape*
ensureShape(js::ExclusiveContext * cx)58 JSObject::ensureShape(js::ExclusiveContext* cx)
59 {
60 if (!js::MaybeConvertUnboxedObjectToNative(cx, this))
61 return nullptr;
62 js::Shape* shape = maybeShape();
63 MOZ_ASSERT(shape);
64 return shape;
65 }
66
67 inline void
finalize(js::FreeOp * fop)68 JSObject::finalize(js::FreeOp* fop)
69 {
70 js::probes::FinalizeObject(this);
71
72 #ifdef DEBUG
73 MOZ_ASSERT(isTenured());
74 if (!IsBackgroundFinalized(asTenured().getAllocKind())) {
75 /* Assert we're on the main thread. */
76 MOZ_ASSERT(CurrentThreadCanAccessRuntime(fop->runtime()));
77 }
78 #endif
79
80 const js::Class* clasp = getClass();
81 if (clasp->finalize)
82 clasp->finalize(fop, this);
83
84 if (!clasp->isNative())
85 return;
86
87 js::NativeObject* nobj = &as<js::NativeObject>();
88
89 if (nobj->hasDynamicSlots())
90 fop->free_(nobj->slots_);
91
92 if (nobj->hasDynamicElements()) {
93 js::ObjectElements* elements = nobj->getElementsHeader();
94 if (elements->isCopyOnWrite()) {
95 if (elements->ownerObject() == this) {
96 // Don't free the elements until object finalization finishes,
97 // so that other objects can access these elements while they
98 // are themselves finalized.
99 fop->freeLater(elements);
100 }
101 } else {
102 fop->free_(elements);
103 }
104 }
105
106 // For dictionary objects (which must be native), it's possible that
107 // unreachable shapes may be marked whose listp points into this object.
108 // In case this happens, null out the shape's pointer here so that a moving
109 // GC will not try to access the dead object.
110 if (nobj->shape_->listp == &nobj->shape_)
111 nobj->shape_->listp = nullptr;
112 }
113
114 /* static */ inline bool
setSingleton(js::ExclusiveContext * cx,js::HandleObject obj)115 JSObject::setSingleton(js::ExclusiveContext* cx, js::HandleObject obj)
116 {
117 MOZ_ASSERT_IF(cx->isJSContext(), !IsInsideNursery(obj));
118
119 js::ObjectGroup* group = js::ObjectGroup::lazySingletonGroup(cx, obj->getClass(),
120 obj->getTaggedProto());
121 if (!group)
122 return false;
123
124 obj->group_ = group;
125 return true;
126 }
127
128 inline js::ObjectGroup*
getGroup(JSContext * cx)129 JSObject::getGroup(JSContext* cx)
130 {
131 MOZ_ASSERT(cx->compartment() == compartment());
132 if (hasLazyGroup()) {
133 JS::RootedObject self(cx, this);
134 if (cx->compartment() != compartment())
135 MOZ_CRASH();
136 return makeLazyGroup(cx, self);
137 }
138 return group_;
139 }
140
141 inline void
setGroup(js::ObjectGroup * group)142 JSObject::setGroup(js::ObjectGroup* group)
143 {
144 MOZ_ASSERT(group);
145 MOZ_ASSERT(!isSingleton());
146 group_ = group;
147 }
148
149
150 /*** Standard internal methods *******************************************************************/
151
152 inline bool
GetPrototype(JSContext * cx,js::HandleObject obj,js::MutableHandleObject protop)153 js::GetPrototype(JSContext* cx, js::HandleObject obj, js::MutableHandleObject protop)
154 {
155 if (obj->getTaggedProto().isLazy()) {
156 MOZ_ASSERT(obj->is<js::ProxyObject>());
157 return js::Proxy::getPrototype(cx, obj, protop);
158 } else {
159 protop.set(obj->getTaggedProto().toObjectOrNull());
160 return true;
161 }
162 }
163
164 inline bool
IsExtensible(ExclusiveContext * cx,HandleObject obj,bool * extensible)165 js::IsExtensible(ExclusiveContext* cx, HandleObject obj, bool* extensible)
166 {
167 if (obj->is<ProxyObject>()) {
168 if (!cx->shouldBeJSContext())
169 return false;
170 return Proxy::isExtensible(cx->asJSContext(), obj, extensible);
171 }
172
173 *extensible = obj->nonProxyIsExtensible();
174 return true;
175 }
176
177 inline bool
HasProperty(JSContext * cx,HandleObject obj,PropertyName * name,bool * found)178 js::HasProperty(JSContext* cx, HandleObject obj, PropertyName* name, bool* found)
179 {
180 RootedId id(cx, NameToId(name));
181 return HasProperty(cx, obj, id, found);
182 }
183
184 inline bool
GetElement(JSContext * cx,HandleObject obj,HandleValue receiver,uint32_t index,MutableHandleValue vp)185 js::GetElement(JSContext* cx, HandleObject obj, HandleValue receiver, uint32_t index,
186 MutableHandleValue vp)
187 {
188 RootedId id(cx);
189 if (!IndexToId(cx, index, &id))
190 return false;
191 return GetProperty(cx, obj, receiver, id, vp);
192 }
193
194 inline bool
GetElement(JSContext * cx,HandleObject obj,HandleObject receiver,uint32_t index,MutableHandleValue vp)195 js::GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
196 MutableHandleValue vp)
197 {
198 RootedValue receiverValue(cx, ObjectValue(*receiver));
199 return GetElement(cx, obj, receiverValue, index, vp);
200 }
201
202 inline bool
GetElementNoGC(JSContext * cx,JSObject * obj,const Value & receiver,uint32_t index,Value * vp)203 js::GetElementNoGC(JSContext* cx, JSObject* obj, const Value& receiver, uint32_t index, Value* vp)
204 {
205 if (obj->getOps()->getProperty)
206 return false;
207
208 if (index > JSID_INT_MAX)
209 return false;
210 return GetPropertyNoGC(cx, obj, receiver, INT_TO_JSID(index), vp);
211 }
212
213 inline bool
GetElementNoGC(JSContext * cx,JSObject * obj,JSObject * receiver,uint32_t index,Value * vp)214 js::GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index, Value* vp)
215 {
216 return GetElementNoGC(cx, obj, ObjectValue(*receiver), index, vp);
217 }
218
219 inline bool
DeleteProperty(JSContext * cx,HandleObject obj,HandleId id,ObjectOpResult & result)220 js::DeleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result)
221 {
222 MarkTypePropertyNonData(cx, obj, id);
223 if (DeletePropertyOp op = obj->getOps()->deleteProperty)
224 return op(cx, obj, id, result);
225 return NativeDeleteProperty(cx, obj.as<NativeObject>(), id, result);
226 }
227
228 inline bool
DeleteElement(JSContext * cx,HandleObject obj,uint32_t index,ObjectOpResult & result)229 js::DeleteElement(JSContext* cx, HandleObject obj, uint32_t index, ObjectOpResult& result)
230 {
231 RootedId id(cx);
232 if (!IndexToId(cx, index, &id))
233 return false;
234 return DeleteProperty(cx, obj, id, result);
235 }
236
237
238 /* * */
239
240 inline bool
isQualifiedVarObj()241 JSObject::isQualifiedVarObj() const
242 {
243 if (is<js::DebugScopeObject>())
244 return as<js::DebugScopeObject>().scope().isQualifiedVarObj();
245 bool rv = hasAllFlags(js::BaseShape::QUALIFIED_VAROBJ);
246 MOZ_ASSERT_IF(rv,
247 is<js::GlobalObject>() ||
248 is<js::CallObject>() ||
249 is<js::ModuleEnvironmentObject>() ||
250 is<js::NonSyntacticVariablesObject>() ||
251 (is<js::DynamicWithObject>() && !as<js::DynamicWithObject>().isSyntactic()));
252 return rv;
253 }
254
255 inline bool
isUnqualifiedVarObj()256 JSObject::isUnqualifiedVarObj() const
257 {
258 if (is<js::DebugScopeObject>())
259 return as<js::DebugScopeObject>().scope().isUnqualifiedVarObj();
260 return is<js::GlobalObject>() || is<js::NonSyntacticVariablesObject>();
261 }
262
263 namespace js {
264
265 inline bool
ClassCanHaveFixedData(const Class * clasp)266 ClassCanHaveFixedData(const Class* clasp)
267 {
268 // Normally, the number of fixed slots given an object is the maximum
269 // permitted for its size class. For array buffers and non-shared typed
270 // arrays we only use enough to cover the class reserved slots, so that
271 // the remaining space in the object's allocation is available for the
272 // buffer's data.
273 return !clasp->isNative()
274 || clasp == &js::ArrayBufferObject::class_
275 || js::IsTypedArrayClass(clasp);
276 }
277
278 static MOZ_ALWAYS_INLINE void
SetNewObjectMetadata(ExclusiveContext * cxArg,JSObject * obj)279 SetNewObjectMetadata(ExclusiveContext* cxArg, JSObject* obj)
280 {
281 MOZ_ASSERT(!cxArg->compartment()->hasObjectPendingMetadata());
282
283 // The metadata callback is invoked for each object created on the main
284 // thread, except when analysis/compilation is active, to avoid recursion.
285 if (JSContext* cx = cxArg->maybeJSContext()) {
286 if (MOZ_UNLIKELY((size_t)cx->compartment()->hasObjectMetadataCallback()) &&
287 !cx->zone()->types.activeAnalysis &&
288 !cx->zone()->usedByExclusiveThread)
289 {
290 // Use AutoEnterAnalysis to prohibit both any GC activity under the
291 // callback, and any reentering of JS via Invoke() etc.
292 AutoEnterAnalysis enter(cx);
293
294 RootedObject hobj(cx, obj);
295 cx->compartment()->setNewObjectMetadata(cx, hobj);
296 }
297 }
298 }
299
300 } // namespace js
301
302 /* static */ inline JSObject*
create(js::ExclusiveContext * cx,js::gc::AllocKind kind,js::gc::InitialHeap heap,js::HandleShape shape,js::HandleObjectGroup group)303 JSObject::create(js::ExclusiveContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
304 js::HandleShape shape, js::HandleObjectGroup group)
305 {
306 MOZ_ASSERT(shape && group);
307 MOZ_ASSERT(group->clasp() == shape->getObjectClass());
308 MOZ_ASSERT(group->clasp() != &js::ArrayObject::class_);
309 MOZ_ASSERT_IF(!js::ClassCanHaveFixedData(group->clasp()),
310 js::gc::GetGCKindSlots(kind, group->clasp()) == shape->numFixedSlots());
311 MOZ_ASSERT_IF(group->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE,
312 IsBackgroundFinalized(kind));
313 MOZ_ASSERT_IF(group->clasp()->finalize,
314 heap == js::gc::TenuredHeap ||
315 (group->clasp()->flags & JSCLASS_SKIP_NURSERY_FINALIZE));
316 MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(),
317 heap == js::gc::TenuredHeap);
318 MOZ_ASSERT(!cx->compartment()->hasObjectPendingMetadata());
319
320 // Non-native classes cannot have reserved slots or private data, and the
321 // objects can't have any fixed slots, for compatibility with
322 // GetReservedOrProxyPrivateSlot.
323 MOZ_ASSERT_IF(!group->clasp()->isNative(), JSCLASS_RESERVED_SLOTS(group->clasp()) == 0);
324 MOZ_ASSERT_IF(!group->clasp()->isNative(), !group->clasp()->hasPrivate());
325 MOZ_ASSERT_IF(!group->clasp()->isNative(), shape->numFixedSlots() == 0);
326 MOZ_ASSERT_IF(!group->clasp()->isNative(), shape->slotSpan() == 0);
327
328 const js::Class* clasp = group->clasp();
329 size_t nDynamicSlots =
330 js::NativeObject::dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp);
331
332 JSObject* obj = js::Allocate<JSObject>(cx, kind, nDynamicSlots, heap, clasp);
333 if (!obj)
334 return nullptr;
335
336 obj->group_.init(group);
337
338 obj->setInitialShapeMaybeNonNative(shape);
339
340 // Note: slots are created and assigned internally by Allocate<JSObject>.
341 obj->setInitialElementsMaybeNonNative(js::emptyObjectElements);
342
343 if (clasp->hasPrivate())
344 obj->as<js::NativeObject>().privateRef(shape->numFixedSlots()) = nullptr;
345
346 if (size_t span = shape->slotSpan())
347 obj->as<js::NativeObject>().initializeSlotRange(0, span);
348
349 // JSFunction's fixed slots expect POD-style initialization.
350 if (group->clasp()->isJSFunction()) {
351 MOZ_ASSERT(kind == js::gc::AllocKind::FUNCTION ||
352 kind == js::gc::AllocKind::FUNCTION_EXTENDED);
353 size_t size =
354 kind == js::gc::AllocKind::FUNCTION ? sizeof(JSFunction) : sizeof(js::FunctionExtended);
355 memset(obj->as<JSFunction>().fixedSlots(), 0, size - sizeof(js::NativeObject));
356 }
357
358 if (group->clasp()->shouldDelayMetadataCallback())
359 cx->compartment()->setObjectPendingMetadata(cx, obj);
360 else
361 SetNewObjectMetadata(cx, obj);
362
363 js::gc::TraceCreateObject(obj);
364
365 return obj;
366 }
367
368 inline void
setInitialShapeMaybeNonNative(js::Shape * shape)369 JSObject::setInitialShapeMaybeNonNative(js::Shape* shape)
370 {
371 static_cast<js::NativeObject*>(this)->shape_.init(shape);
372 }
373
374 inline void
setShapeMaybeNonNative(js::Shape * shape)375 JSObject::setShapeMaybeNonNative(js::Shape* shape)
376 {
377 MOZ_ASSERT(!is<js::UnboxedPlainObject>());
378 static_cast<js::NativeObject*>(this)->shape_ = shape;
379 }
380
381 inline void
setInitialSlotsMaybeNonNative(js::HeapSlot * slots)382 JSObject::setInitialSlotsMaybeNonNative(js::HeapSlot* slots)
383 {
384 static_cast<js::NativeObject*>(this)->slots_ = slots;
385 }
386
387 inline void
setInitialElementsMaybeNonNative(js::HeapSlot * elements)388 JSObject::setInitialElementsMaybeNonNative(js::HeapSlot* elements)
389 {
390 static_cast<js::NativeObject*>(this)->elements_ = elements;
391 }
392
393 inline js::GlobalObject&
global()394 JSObject::global() const
395 {
396 /*
397 * The global is read-barriered so that it is kept live by access through
398 * the JSCompartment. When accessed through a JSObject, however, the global
399 * will be already be kept live by the black JSObject's parent pointer, so
400 * does not need to be read-barriered.
401 */
402 return *compartment()->unsafeUnbarrieredMaybeGlobal();
403 }
404
405 inline bool
isOwnGlobal()406 JSObject::isOwnGlobal() const
407 {
408 return &global() == this;
409 }
410
411 inline bool
hasAllFlags(js::BaseShape::Flag flags)412 JSObject::hasAllFlags(js::BaseShape::Flag flags) const
413 {
414 MOZ_ASSERT(flags);
415 if (js::Shape* shape = maybeShape())
416 return shape->hasAllObjectFlags(flags);
417 return false;
418 }
419
420 inline bool
nonProxyIsExtensible()421 JSObject::nonProxyIsExtensible() const
422 {
423 MOZ_ASSERT(!uninlinedIsProxy());
424
425 // [[Extensible]] for ordinary non-proxy objects is an object flag.
426 return !hasAllFlags(js::BaseShape::NOT_EXTENSIBLE);
427 }
428
429 inline bool
isBoundFunction()430 JSObject::isBoundFunction() const
431 {
432 return hasAllFlags(js::BaseShape::BOUND_FUNCTION);
433 }
434
435 inline bool
watched()436 JSObject::watched() const
437 {
438 return hasAllFlags(js::BaseShape::WATCHED);
439 }
440
441 inline bool
isDelegate()442 JSObject::isDelegate() const
443 {
444 return hasAllFlags(js::BaseShape::DELEGATE);
445 }
446
447 inline bool
hasUncacheableProto()448 JSObject::hasUncacheableProto() const
449 {
450 return hasAllFlags(js::BaseShape::UNCACHEABLE_PROTO);
451 }
452
453 inline bool
hadElementsAccess()454 JSObject::hadElementsAccess() const
455 {
456 return hasAllFlags(js::BaseShape::HAD_ELEMENTS_ACCESS);
457 }
458
459 inline bool
isIndexed()460 JSObject::isIndexed() const
461 {
462 return hasAllFlags(js::BaseShape::INDEXED);
463 }
464
465 inline bool
nonLazyPrototypeIsImmutable()466 JSObject::nonLazyPrototypeIsImmutable() const
467 {
468 MOZ_ASSERT(!hasLazyPrototype());
469 return hasAllFlags(js::BaseShape::IMMUTABLE_PROTOTYPE);
470 }
471
472 inline bool
isIteratedSingleton()473 JSObject::isIteratedSingleton() const
474 {
475 return hasAllFlags(js::BaseShape::ITERATED_SINGLETON);
476 }
477
478 inline bool
isNewGroupUnknown()479 JSObject::isNewGroupUnknown() const
480 {
481 return hasAllFlags(js::BaseShape::NEW_GROUP_UNKNOWN);
482 }
483
484 inline bool
wasNewScriptCleared()485 JSObject::wasNewScriptCleared() const
486 {
487 return hasAllFlags(js::BaseShape::NEW_SCRIPT_CLEARED);
488 }
489
490 namespace js {
491
492 static MOZ_ALWAYS_INLINE bool
IsFunctionObject(const js::Value & v)493 IsFunctionObject(const js::Value& v)
494 {
495 return v.isObject() && v.toObject().is<JSFunction>();
496 }
497
498 static MOZ_ALWAYS_INLINE bool
IsFunctionObject(const js::Value & v,JSFunction ** fun)499 IsFunctionObject(const js::Value& v, JSFunction** fun)
500 {
501 if (v.isObject() && v.toObject().is<JSFunction>()) {
502 *fun = &v.toObject().as<JSFunction>();
503 return true;
504 }
505 return false;
506 }
507
508 static MOZ_ALWAYS_INLINE bool
IsNativeFunction(const js::Value & v)509 IsNativeFunction(const js::Value& v)
510 {
511 JSFunction* fun;
512 return IsFunctionObject(v, &fun) && fun->isNative();
513 }
514
515 static MOZ_ALWAYS_INLINE bool
IsNativeFunction(const js::Value & v,JSFunction ** fun)516 IsNativeFunction(const js::Value& v, JSFunction** fun)
517 {
518 return IsFunctionObject(v, fun) && (*fun)->isNative();
519 }
520
521 static MOZ_ALWAYS_INLINE bool
IsNativeFunction(const js::Value & v,JSNative native)522 IsNativeFunction(const js::Value& v, JSNative native)
523 {
524 JSFunction* fun;
525 return IsFunctionObject(v, &fun) && fun->maybeNative() == native;
526 }
527
528 /*
529 * When we have an object of a builtin class, we don't quite know what its
530 * valueOf/toString methods are, since these methods may have been overwritten
531 * or shadowed. However, we can still do better than the general case by
532 * hard-coding the necessary properties for us to find the native we expect.
533 *
534 * TODO: a per-thread shape-based cache would be faster and simpler.
535 */
536 static MOZ_ALWAYS_INLINE bool
ClassMethodIsNative(JSContext * cx,NativeObject * obj,const Class * clasp,jsid methodid,JSNative native)537 ClassMethodIsNative(JSContext* cx, NativeObject* obj, const Class* clasp, jsid methodid, JSNative native)
538 {
539 MOZ_ASSERT(obj->getClass() == clasp);
540
541 Value v;
542 if (!HasDataProperty(cx, obj, methodid, &v)) {
543 JSObject* proto = obj->getProto();
544 if (!proto || proto->getClass() != clasp || !HasDataProperty(cx, &proto->as<NativeObject>(), methodid, &v))
545 return false;
546 }
547
548 return IsNativeFunction(v, native);
549 }
550
551 // Return whether looking up 'valueOf' on 'obj' definitely resolves to the
552 // original Object.prototype.valueOf. The method may conservatively return
553 // 'false' in the case of proxies or other non-native objects.
554 static MOZ_ALWAYS_INLINE bool
HasObjectValueOf(JSObject * obj,JSContext * cx)555 HasObjectValueOf(JSObject* obj, JSContext* cx)
556 {
557 if (obj->is<ProxyObject>() || !obj->isNative())
558 return false;
559
560 jsid valueOf = NameToId(cx->names().valueOf);
561
562 Value v;
563 while (!HasDataProperty(cx, &obj->as<NativeObject>(), valueOf, &v)) {
564 obj = obj->getProto();
565 if (!obj || obj->is<ProxyObject>() || !obj->isNative())
566 return false;
567 }
568
569 return IsNativeFunction(v, obj_valueOf);
570 }
571
572 /* ES6 draft rev 28 (2014 Oct 14) 7.1.14 */
573 inline bool
ToPropertyKey(JSContext * cx,Value argument,MutableHandleId result)574 ToPropertyKey(JSContext* cx, Value argument, MutableHandleId result)
575 {
576 // Steps 1-2.
577 RootedValue key(cx, argument);
578 if (!ToPrimitive(cx, JSTYPE_STRING, &key))
579 return false;
580
581 // Steps 3-4.
582 return ValueToId<CanGC>(cx, key, result);
583 }
584
585 /*
586 * Return true if this is a compiler-created internal function accessed by
587 * its own object. Such a function object must not be accessible to script
588 * or embedding code.
589 */
590 inline bool
IsInternalFunctionObject(JSObject & funobj)591 IsInternalFunctionObject(JSObject& funobj)
592 {
593 JSFunction& fun = funobj.as<JSFunction>();
594 MOZ_ASSERT_IF(fun.isLambda(),
595 fun.isInterpreted() || fun.isAsmJSNative());
596 return fun.isLambda() && fun.isInterpreted() && !fun.environment();
597 }
598
599 /*
600 * Make an object with the specified prototype. If parent is null, it will
601 * default to the prototype's global if the prototype is non-null.
602 */
603 JSObject*
604 NewObjectWithGivenTaggedProto(ExclusiveContext* cx, const Class* clasp, Handle<TaggedProto> proto,
605 gc::AllocKind allocKind, NewObjectKind newKind,
606 uint32_t initialShapeFlags = 0);
607
608 inline JSObject*
609 NewObjectWithGivenTaggedProto(ExclusiveContext* cx, const Class* clasp, Handle<TaggedProto> proto,
610 NewObjectKind newKind = GenericObject,
611 uint32_t initialShapeFlags = 0)
612 {
613 gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
614 return NewObjectWithGivenTaggedProto(cx, clasp, proto, allocKind, newKind, initialShapeFlags);
615 }
616
617 template <typename T>
618 inline T*
619 NewObjectWithGivenTaggedProto(ExclusiveContext* cx, Handle<TaggedProto> proto,
620 NewObjectKind newKind = GenericObject,
621 uint32_t initialShapeFlags = 0)
622 {
623 JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, proto, newKind,
624 initialShapeFlags);
625 return obj ? &obj->as<T>() : nullptr;
626 }
627
628 template <typename T>
629 inline T*
630 NewObjectWithNullTaggedProto(ExclusiveContext* cx, NewObjectKind newKind = GenericObject,
631 uint32_t initialShapeFlags = 0)
632 {
633 Rooted<TaggedProto> nullProto(cx, TaggedProto(nullptr));
634 return NewObjectWithGivenTaggedProto<T>(cx, nullProto, newKind, initialShapeFlags);
635 }
636
637 inline JSObject*
NewObjectWithGivenProto(ExclusiveContext * cx,const Class * clasp,HandleObject proto,gc::AllocKind allocKind,NewObjectKind newKind)638 NewObjectWithGivenProto(ExclusiveContext* cx, const Class* clasp, HandleObject proto,
639 gc::AllocKind allocKind, NewObjectKind newKind)
640 {
641 return NewObjectWithGivenTaggedProto(cx, clasp, AsTaggedProto(proto), allocKind,
642 newKind);
643 }
644
645 inline JSObject*
646 NewObjectWithGivenProto(ExclusiveContext* cx, const Class* clasp, HandleObject proto,
647 NewObjectKind newKind = GenericObject)
648 {
649 return NewObjectWithGivenTaggedProto(cx, clasp, AsTaggedProto(proto), newKind);
650 }
651
652 template <typename T>
653 inline T*
654 NewObjectWithGivenProto(ExclusiveContext* cx, HandleObject proto,
655 NewObjectKind newKind = GenericObject)
656 {
657 return NewObjectWithGivenTaggedProto<T>(cx, AsTaggedProto(proto), newKind);
658 }
659
660 template <typename T>
661 inline T*
662 NewObjectWithGivenProto(ExclusiveContext* cx, HandleObject proto,
663 gc::AllocKind allocKind, NewObjectKind newKind = GenericObject)
664 {
665 JSObject* obj = NewObjectWithGivenTaggedProto(cx, &T::class_, AsTaggedProto(proto),
666 allocKind, newKind);
667 return obj ? &obj->as<T>() : nullptr;
668 }
669
670 // Make an object with the prototype set according to the cached prototype or
671 // Object.prototype.
672 JSObject*
673 NewObjectWithClassProtoCommon(ExclusiveContext* cx, const Class* clasp, HandleObject proto,
674 gc::AllocKind allocKind, NewObjectKind newKind);
675
676 inline JSObject*
677 NewObjectWithClassProto(ExclusiveContext* cx, const Class* clasp, HandleObject proto,
678 gc::AllocKind allocKind, NewObjectKind newKind = GenericObject)
679 {
680 return NewObjectWithClassProtoCommon(cx, clasp, proto, allocKind, newKind);
681 }
682
683 inline JSObject*
684 NewObjectWithClassProto(ExclusiveContext* cx, const Class* clasp, HandleObject proto,
685 NewObjectKind newKind = GenericObject)
686 {
687 gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
688 return NewObjectWithClassProto(cx, clasp, proto, allocKind, newKind);
689 }
690
691 template<class T>
692 inline T*
693 NewObjectWithClassProto(ExclusiveContext* cx, HandleObject proto,
694 NewObjectKind newKind = GenericObject)
695 {
696 JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, newKind);
697 return obj ? &obj->as<T>() : nullptr;
698 }
699
700 template <class T>
701 inline T*
702 NewObjectWithClassProto(ExclusiveContext* cx, HandleObject proto, gc::AllocKind allocKind,
703 NewObjectKind newKind = GenericObject)
704 {
705 JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, allocKind, newKind);
706 return obj ? &obj->as<T>() : nullptr;
707 }
708
709 /*
710 * Create a native instance of the given class with parent and proto set
711 * according to the context's active global.
712 */
713 inline JSObject*
714 NewBuiltinClassInstance(ExclusiveContext* cx, const Class* clasp, gc::AllocKind allocKind,
715 NewObjectKind newKind = GenericObject)
716 {
717 return NewObjectWithClassProto(cx, clasp, nullptr, allocKind, newKind);
718 }
719
720 inline JSObject*
721 NewBuiltinClassInstance(ExclusiveContext* cx, const Class* clasp, NewObjectKind newKind = GenericObject)
722 {
723 gc::AllocKind allocKind = gc::GetGCObjectKind(clasp);
724 return NewBuiltinClassInstance(cx, clasp, allocKind, newKind);
725 }
726
727 template<typename T>
728 inline T*
729 NewBuiltinClassInstance(ExclusiveContext* cx, NewObjectKind newKind = GenericObject)
730 {
731 JSObject* obj = NewBuiltinClassInstance(cx, &T::class_, newKind);
732 return obj ? &obj->as<T>() : nullptr;
733 }
734
735 template<typename T>
736 inline T*
737 NewBuiltinClassInstance(ExclusiveContext* cx, gc::AllocKind allocKind, NewObjectKind newKind = GenericObject)
738 {
739 JSObject* obj = NewBuiltinClassInstance(cx, &T::class_, allocKind, newKind);
740 return obj ? &obj->as<T>() : nullptr;
741 }
742
743 // Used to optimize calls to (new Object())
744 bool
745 NewObjectScriptedCall(JSContext* cx, MutableHandleObject obj);
746
747 JSObject*
748 NewObjectWithGroupCommon(ExclusiveContext* cx, HandleObjectGroup group,
749 gc::AllocKind allocKind, NewObjectKind newKind);
750
751 template <typename T>
752 inline T*
753 NewObjectWithGroup(ExclusiveContext* cx, HandleObjectGroup group,
754 gc::AllocKind allocKind, NewObjectKind newKind = GenericObject)
755 {
756 JSObject* obj = NewObjectWithGroupCommon(cx, group, allocKind, newKind);
757 return obj ? &obj->as<T>() : nullptr;
758 }
759
760 template <typename T>
761 inline T*
762 NewObjectWithGroup(ExclusiveContext* cx, HandleObjectGroup group,
763 NewObjectKind newKind = GenericObject)
764 {
765 gc::AllocKind allocKind = gc::GetGCObjectKind(group->clasp());
766 return NewObjectWithGroup<T>(cx, group, allocKind, newKind);
767 }
768
769 /*
770 * As for gc::GetGCObjectKind, where numElements is a guess at the final size of
771 * the object, zero if the final size is unknown. This should only be used for
772 * objects that do not require any fixed slots.
773 */
774 static inline gc::AllocKind
GuessObjectGCKind(size_t numElements)775 GuessObjectGCKind(size_t numElements)
776 {
777 if (numElements)
778 return gc::GetGCObjectKind(numElements);
779 return gc::AllocKind::OBJECT4;
780 }
781
782 static inline gc::AllocKind
GuessArrayGCKind(size_t numElements)783 GuessArrayGCKind(size_t numElements)
784 {
785 if (numElements)
786 return gc::GetGCArrayKind(numElements);
787 return gc::AllocKind::OBJECT8;
788 }
789
790 // Returns ESClass_Other if the value isn't an object, or if the object
791 // isn't of one of the enumerated classes. Otherwise returns the appropriate
792 // class.
793 inline bool
GetClassOfValue(JSContext * cx,HandleValue v,ESClassValue * classValue)794 GetClassOfValue(JSContext* cx, HandleValue v, ESClassValue* classValue)
795 {
796 if (!v.isObject()) {
797 *classValue = ESClass_Other;
798 return true;
799 }
800
801 RootedObject obj(cx, &v.toObject());
802 return GetBuiltinClass(cx, obj, classValue);
803 }
804
805 inline bool
Unbox(JSContext * cx,HandleObject obj,MutableHandleValue vp)806 Unbox(JSContext* cx, HandleObject obj, MutableHandleValue vp)
807 {
808 if (MOZ_UNLIKELY(obj->is<ProxyObject>()))
809 return Proxy::boxedValue_unbox(cx, obj, vp);
810
811 if (obj->is<BooleanObject>())
812 vp.setBoolean(obj->as<BooleanObject>().unbox());
813 else if (obj->is<NumberObject>())
814 vp.setNumber(obj->as<NumberObject>().unbox());
815 else if (obj->is<StringObject>())
816 vp.setString(obj->as<StringObject>().unbox());
817 else if (obj->is<DateObject>())
818 vp.set(obj->as<DateObject>().UTCTime());
819 else
820 vp.setUndefined();
821
822 return true;
823 }
824
825 extern NativeObject*
826 InitClass(JSContext* cx, HandleObject obj, HandleObject parent_proto,
827 const Class* clasp, JSNative constructor, unsigned nargs,
828 const JSPropertySpec* ps, const JSFunctionSpec* fs,
829 const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs,
830 NativeObject** ctorp = nullptr,
831 gc::AllocKind ctorKind = gc::AllocKind::FUNCTION);
832
833 } /* namespace js */
834
835 #endif /* jsobjinlines_h */
836