JSObject-inl.h (21654B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef vm_JSObject_inl_h 8 #define vm_JSObject_inl_h 9 10 #include "vm/JSObject.h" 11 12 #include "gc/Allocator.h" 13 #include "gc/Zone.h" 14 #include "js/Object.h" // JS::GetBuiltinClass 15 #include "vm/ArrayObject.h" 16 #include "vm/BoundFunctionObject.h" 17 #include "vm/EnvironmentObject.h" 18 #include "vm/JSFunction.h" 19 #include "vm/PropertyResult.h" 20 #include "vm/TypedArrayObject.h" 21 #include "gc/BufferAllocator-inl.h" 22 #include "gc/GCContext-inl.h" 23 #include "gc/ObjectKind-inl.h" 24 #include "vm/ObjectOperations-inl.h" // js::MaybeHasInterestingSymbolProperty 25 26 namespace js { 27 28 // Get the GC kind to use for scripted 'new', empty object literals ({}), and 29 // the |Object| constructor. 30 static inline gc::AllocKind NewObjectGCKind() { return gc::AllocKind::OBJECT4; } 31 32 } // namespace js 33 34 MOZ_ALWAYS_INLINE uint32_t js::NativeObject::numDynamicSlots() const { 35 uint32_t slots = getSlotsHeader()->capacity(); 36 MOZ_ASSERT(slots == calculateDynamicSlots()); 37 MOZ_ASSERT_IF(hasDynamicSlots() && !hasUniqueId(), slots != 0); 38 39 return slots; 40 } 41 42 MOZ_ALWAYS_INLINE uint32_t js::NativeObject::calculateDynamicSlots() const { 43 return calculateDynamicSlots(numFixedSlots(), slotSpan(), getClass()); 44 } 45 46 /* static */ MOZ_ALWAYS_INLINE uint32_t js::NativeObject::calculateDynamicSlots( 47 uint32_t nfixed, uint32_t span, const JSClass* clasp) { 48 if (span <= nfixed) { 49 return 0; 50 } 51 52 uint32_t ndynamic = span - nfixed; 53 54 // Increase the slots to SLOT_CAPACITY_MIN to decrease the likelihood 55 // the dynamic slots need to get increased again. ArrayObjects ignore 56 // this because slots are uncommon in that case. 57 if (clasp != &ArrayObject::class_ && ndynamic <= SLOT_CAPACITY_MIN) { 58 #ifdef DEBUG 59 size_t count = SLOT_CAPACITY_MIN + ObjectSlots::VALUES_PER_HEADER; 60 MOZ_ASSERT(count == gc::GetGoodPower2ElementCount(count, sizeof(Value))); 61 #endif 62 return SLOT_CAPACITY_MIN; 63 } 64 65 uint32_t count = gc::GetGoodPower2ElementCount( 66 ndynamic + ObjectSlots::VALUES_PER_HEADER, sizeof(Value)); 67 68 uint32_t slots = count - ObjectSlots::VALUES_PER_HEADER; 69 MOZ_ASSERT(slots >= ndynamic); 70 return slots; 71 } 72 73 /* static */ MOZ_ALWAYS_INLINE uint32_t 74 js::NativeObject::calculateDynamicSlots(SharedShape* shape) { 75 return calculateDynamicSlots(shape->numFixedSlots(), shape->slotSpan(), 76 shape->getObjectClass()); 77 } 78 79 inline void JSObject::finalize(JS::GCContext* gcx) { 80 #ifdef DEBUG 81 MOZ_ASSERT(isTenured()); 82 js::gc::AllocKind kind = asTenured().getAllocKind(); 83 MOZ_ASSERT(IsFinalizedKind(kind)); 84 MOZ_ASSERT_IF(IsForegroundFinalized(kind), 85 js::CurrentThreadCanAccessZone(zoneFromAnyThread())); 86 #endif 87 88 const JSClass* clasp = shape()->getObjectClass(); 89 MOZ_ASSERT(clasp->hasFinalize()); 90 clasp->doFinalize(gcx, this); 91 } 92 93 inline bool JSObject::isQualifiedVarObj() const { 94 if (is<js::DebugEnvironmentProxy>()) { 95 return as<js::DebugEnvironmentProxy>().environment().isQualifiedVarObj(); 96 } 97 bool rv = hasFlag(js::ObjectFlag::QualifiedVarObj); 98 MOZ_ASSERT_IF(rv, is<js::GlobalObject>() || is<js::CallObject>() || 99 is<js::VarEnvironmentObject>() || 100 is<js::ModuleEnvironmentObject>() || 101 is<js::NonSyntacticVariablesObject>() || 102 (is<js::WithEnvironmentObject>() && 103 !as<js::WithEnvironmentObject>().isSyntactic())); 104 return rv; 105 } 106 107 inline bool JSObject::isUnqualifiedVarObj() const { 108 if (is<js::DebugEnvironmentProxy>()) { 109 return as<js::DebugEnvironmentProxy>().environment().isUnqualifiedVarObj(); 110 } 111 return is<js::GlobalObject>() || is<js::NonSyntacticVariablesObject>(); 112 } 113 114 inline bool JSObject::setQualifiedVarObj( 115 JSContext* cx, JS::Handle<js::WithEnvironmentObject*> obj) { 116 MOZ_ASSERT(!obj->isSyntactic()); 117 return setFlag(cx, obj, js::ObjectFlag::QualifiedVarObj); 118 } 119 120 namespace js { 121 122 #ifdef DEBUG 123 inline bool ClassCanHaveFixedData(const JSClass* clasp) { 124 // Normally, the number of fixed slots given an object is the maximum 125 // permitted for its size class. For array buffers and typed arrays we only 126 // use enough to cover the class reserved slots, so that the remaining space 127 // in the object's allocation is available for the buffer's data. 128 return !clasp->isNativeObject() || 129 clasp == &js::FixedLengthArrayBufferObject::class_ || 130 clasp == &js::ResizableArrayBufferObject::class_ || 131 clasp == &js::ImmutableArrayBufferObject::class_ || 132 js::IsTypedArrayClass(clasp); 133 } 134 #endif 135 136 class MOZ_RAII AutoSuppressAllocationMetadataBuilder { 137 JS::Zone* zone; 138 bool saved; 139 140 public: 141 explicit AutoSuppressAllocationMetadataBuilder(JSContext* cx) 142 : zone(cx->zone()), saved(zone->suppressAllocationMetadataBuilder) { 143 zone->suppressAllocationMetadataBuilder = true; 144 } 145 146 ~AutoSuppressAllocationMetadataBuilder() { 147 zone->suppressAllocationMetadataBuilder = saved; 148 } 149 }; 150 151 // This function is meant to be called from allocation fast paths. 152 // 153 // If we do have an allocation metadata builder, it can cause a GC, so the 154 // object must be rooted. The usual way to do this would be to make our callers 155 // pass a HandleObject, but that would require them to pay the cost of rooting 156 // the object unconditionally, even though collecting metadata is rare. Instead, 157 // SetNewObjectMetadata's contract is that the caller must use the pointer 158 // returned in place of the pointer passed. If a GC occurs, the returned pointer 159 // may be the passed pointer, relocated by GC. If no GC could occur, it's just 160 // passed through. We root nothing unless necessary. 161 template <typename T> 162 [[nodiscard]] static inline T* SetNewObjectMetadata(JSContext* cx, T* obj) { 163 MOZ_ASSERT(cx->realm()->hasAllocationMetadataBuilder()); 164 MOZ_ASSERT(!cx->realm()->hasObjectPendingMetadata()); 165 166 // The metadata builder is invoked for each object created on the main thread, 167 // except when it's suppressed or we're throwing over-recursion error. 168 if (!cx->zone()->suppressAllocationMetadataBuilder && 169 !cx->isThrowingOverRecursed()) { 170 // Don't collect metadata on objects that represent metadata, to avoid 171 // recursion. 172 AutoSuppressAllocationMetadataBuilder suppressMetadata(cx); 173 174 Rooted<T*> rooted(cx, obj); 175 cx->realm()->setNewObjectMetadata(cx, rooted); 176 return rooted; 177 } 178 179 return obj; 180 } 181 182 } // namespace js 183 184 inline js::GlobalObject& JSObject::nonCCWGlobal() const { 185 /* 186 * The global is read-barriered so that it is kept live by access through 187 * the Realm. When accessed through a JSObject, however, the global will be 188 * already kept live by the black JSObject's group pointer, so does not 189 * need to be read-barriered. 190 */ 191 return *nonCCWRealm()->unsafeUnbarrieredMaybeGlobal(); 192 } 193 194 inline bool JSObject::nonProxyIsExtensible() const { 195 MOZ_ASSERT(!uninlinedIsProxyObject()); 196 197 // [[Extensible]] for ordinary non-proxy objects is an object flag. 198 return !hasFlag(js::ObjectFlag::NotExtensible); 199 } 200 201 inline bool JSObject::hasInvalidatedTeleporting() const { 202 return hasFlag(js::ObjectFlag::InvalidatedTeleporting); 203 } 204 205 inline bool JSObject::needsProxyGetSetResultValidation() const { 206 return hasFlag(js::ObjectFlag::NeedsProxyGetSetResultValidation); 207 } 208 209 MOZ_ALWAYS_INLINE bool JSObject::maybeHasInterestingSymbolProperty() const { 210 if (is<js::NativeObject>()) { 211 return as<js::NativeObject>().hasInterestingSymbol(); 212 } 213 return true; 214 } 215 216 inline bool JSObject::staticPrototypeIsImmutable() const { 217 MOZ_ASSERT(hasStaticPrototype()); 218 return hasFlag(js::ObjectFlag::ImmutablePrototype); 219 } 220 221 namespace js { 222 223 static MOZ_ALWAYS_INLINE bool IsFunctionObject(const js::Value& v) { 224 return v.isObject() && v.toObject().is<JSFunction>(); 225 } 226 227 static MOZ_ALWAYS_INLINE bool IsFunctionObject(const js::Value& v, 228 JSFunction** fun) { 229 if (v.isObject() && v.toObject().is<JSFunction>()) { 230 *fun = &v.toObject().as<JSFunction>(); 231 return true; 232 } 233 return false; 234 } 235 236 static MOZ_ALWAYS_INLINE bool IsNativeFunction(const js::Value& v, 237 JSNative native) { 238 JSFunction* fun; 239 return IsFunctionObject(v, &fun) && fun->maybeNative() == native; 240 } 241 242 static MOZ_ALWAYS_INLINE bool IsNativeFunction(const JSObject* obj, 243 JSNative native) { 244 return obj->is<JSFunction>() && obj->as<JSFunction>().maybeNative() == native; 245 } 246 247 // Return whether looking up a method on 'obj' definitely resolves to the 248 // original specified native function. The method may conservatively return 249 // 'false' in the case of proxies or other non-native objects. 250 static MOZ_ALWAYS_INLINE bool HasNativeMethodPure(JSObject* obj, 251 PropertyName* name, 252 JSNative native, 253 JSContext* cx) { 254 Value v; 255 if (!GetPropertyPure(cx, obj, NameToId(name), &v)) { 256 return false; 257 } 258 259 return IsNativeFunction(v, native); 260 } 261 262 // Return whether 'obj' definitely has no @@toPrimitive method. 263 static MOZ_ALWAYS_INLINE bool HasNoToPrimitiveMethodPure(JSObject* obj, 264 JSContext* cx) { 265 JS::Symbol* toPrimitive = cx->wellKnownSymbols().toPrimitive; 266 JSObject* holder; 267 if (!MaybeHasInterestingSymbolProperty(cx, obj, toPrimitive, &holder)) { 268 #ifdef DEBUG 269 NativeObject* pobj; 270 PropertyResult prop; 271 MOZ_ASSERT(LookupPropertyPure(cx, obj, PropertyKey::Symbol(toPrimitive), 272 &pobj, &prop)); 273 MOZ_ASSERT(prop.isNotFound()); 274 #endif 275 return true; 276 } 277 278 NativeObject* pobj; 279 PropertyResult prop; 280 if (!LookupPropertyPure(cx, holder, PropertyKey::Symbol(toPrimitive), &pobj, 281 &prop)) { 282 return false; 283 } 284 285 return prop.isNotFound(); 286 } 287 288 extern bool ToPropertyKeySlow(JSContext* cx, HandleValue argument, 289 MutableHandleId result); 290 291 /* ES6 draft rev 28 (2014 Oct 14) 7.1.14 */ 292 MOZ_ALWAYS_INLINE bool ToPropertyKey(JSContext* cx, HandleValue argument, 293 MutableHandleId result) { 294 if (MOZ_LIKELY(argument.isPrimitive())) { 295 return PrimitiveValueToId<CanGC>(cx, argument, result); 296 } 297 298 return ToPropertyKeySlow(cx, argument, result); 299 } 300 301 /* 302 * Return true if this is a compiler-created internal function accessed by 303 * its own object. Such a function object must not be accessible to script 304 * or embedding code. 305 */ 306 inline bool IsInternalFunctionObject(JSObject& funobj) { 307 JSFunction& fun = funobj.as<JSFunction>(); 308 return fun.isInterpreted() && !fun.environment(); 309 } 310 311 inline gc::Heap GetInitialHeap(NewObjectKind newKind, const JSClass* clasp, 312 gc::AllocSite* site = nullptr) { 313 if (newKind != GenericObject) { 314 return gc::Heap::Tenured; 315 } 316 if (clasp->hasFinalize() && !CanNurseryAllocateFinalizedClass(clasp)) { 317 return gc::Heap::Tenured; 318 } 319 if (site) { 320 return site->initialHeap(); 321 } 322 return gc::Heap::Default; 323 } 324 325 /* 326 * Make an object with the specified prototype. If parent is null, it will 327 * default to the prototype's global if the prototype is non-null. 328 */ 329 NativeObject* NewObjectWithGivenTaggedProto(JSContext* cx, const JSClass* clasp, 330 Handle<TaggedProto> proto, 331 gc::AllocKind allocKind, 332 NewObjectKind newKind, 333 ObjectFlags objFlags); 334 335 NativeObject* NewObjectWithGivenTaggedProtoAndAllocSite( 336 JSContext* cx, const JSClass* clasp, Handle<TaggedProto> proto, 337 gc::AllocKind allocKind, NewObjectKind newKind, ObjectFlags objFlags, 338 gc::AllocSite* site); 339 340 template <NewObjectKind NewKind> 341 inline NativeObject* NewObjectWithGivenTaggedProto(JSContext* cx, 342 const JSClass* clasp, 343 Handle<TaggedProto> proto, 344 ObjectFlags objFlags) { 345 gc::AllocKind allocKind = gc::GetGCObjectKind(clasp); 346 return NewObjectWithGivenTaggedProto(cx, clasp, proto, allocKind, NewKind, 347 objFlags); 348 } 349 350 template <NewObjectKind NewKind> 351 inline NativeObject* NewObjectWithGivenTaggedProtoAndAllocSite( 352 JSContext* cx, const JSClass* clasp, Handle<TaggedProto> proto, 353 ObjectFlags objFlags, gc::AllocSite* site) { 354 gc::AllocKind allocKind = gc::GetGCObjectKind(clasp); 355 return NewObjectWithGivenTaggedProtoAndAllocSite(cx, clasp, proto, allocKind, 356 NewKind, objFlags, site); 357 } 358 359 namespace detail { 360 361 template <typename T, NewObjectKind NewKind> 362 inline T* NewObjectWithGivenTaggedProtoForKind(JSContext* cx, 363 Handle<TaggedProto> proto) { 364 JSObject* obj = NewObjectWithGivenTaggedProto<NewKind>(cx, &T::class_, proto, 365 ObjectFlags()); 366 return obj ? &obj->as<T>() : nullptr; 367 } 368 369 } // namespace detail 370 371 template <typename T> 372 inline T* NewObjectWithGivenTaggedProto(JSContext* cx, 373 Handle<TaggedProto> proto) { 374 return detail::NewObjectWithGivenTaggedProtoForKind<T, GenericObject>(cx, 375 proto); 376 } 377 378 inline NativeObject* NewObjectWithGivenProto(JSContext* cx, 379 const JSClass* clasp, 380 HandleObject proto) { 381 return NewObjectWithGivenTaggedProto<GenericObject>( 382 cx, clasp, AsTaggedProto(proto), ObjectFlags()); 383 } 384 385 inline NativeObject* NewObjectWithGivenProtoAndAllocSite( 386 JSContext* cx, const JSClass* clasp, HandleObject proto, 387 js::gc::AllocSite* site) { 388 return NewObjectWithGivenTaggedProtoAndAllocSite<GenericObject>( 389 cx, clasp, AsTaggedProto(proto), ObjectFlags(), site); 390 } 391 392 inline NativeObject* NewTenuredObjectWithGivenProto( 393 JSContext* cx, const JSClass* clasp, HandleObject proto, 394 ObjectFlags objFlags = ObjectFlags()) { 395 return NewObjectWithGivenTaggedProto<TenuredObject>( 396 cx, clasp, AsTaggedProto(proto), objFlags); 397 } 398 399 template <typename T> 400 inline T* NewObjectWithGivenProto(JSContext* cx, HandleObject proto) { 401 return detail::NewObjectWithGivenTaggedProtoForKind<T, GenericObject>( 402 cx, AsTaggedProto(proto)); 403 } 404 405 template <typename T> 406 inline T* NewTenuredObjectWithGivenProto(JSContext* cx, HandleObject proto) { 407 return detail::NewObjectWithGivenTaggedProtoForKind<T, TenuredObject>( 408 cx, AsTaggedProto(proto)); 409 } 410 411 template <typename T> 412 inline T* NewObjectWithGivenProtoAndKinds(JSContext* cx, HandleObject proto, 413 gc::AllocKind allocKind, 414 NewObjectKind newKind) { 415 JSObject* obj = NewObjectWithGivenTaggedProto( 416 cx, &T::class_, AsTaggedProto(proto), allocKind, newKind, ObjectFlags()); 417 return obj ? &obj->as<T>() : nullptr; 418 } 419 420 // Make an object with the prototype set according to the cached prototype or 421 // Object.prototype. 422 NativeObject* NewObjectWithClassProto(JSContext* cx, const JSClass* clasp, 423 HandleObject proto, 424 gc::AllocKind allocKind, 425 NewObjectKind newKind = GenericObject, 426 ObjectFlags objFlags = ObjectFlags()); 427 428 inline NativeObject* NewObjectWithClassProto( 429 JSContext* cx, const JSClass* clasp, HandleObject proto, 430 NewObjectKind newKind = GenericObject, 431 ObjectFlags objFlags = ObjectFlags()) { 432 gc::AllocKind allocKind = gc::GetGCObjectKind(clasp); 433 return NewObjectWithClassProto(cx, clasp, proto, allocKind, newKind, 434 objFlags); 435 } 436 437 template <class T> 438 inline T* NewObjectWithClassProto(JSContext* cx, HandleObject proto) { 439 JSObject* obj = NewObjectWithClassProto(cx, &T::class_, proto, GenericObject); 440 return obj ? &obj->as<T>() : nullptr; 441 } 442 443 template <class T> 444 inline T* NewObjectWithClassProtoAndKind(JSContext* cx, HandleObject proto, 445 NewObjectKind newKind, 446 ObjectFlags objFlags = ObjectFlags()) { 447 JSObject* obj = 448 NewObjectWithClassProto(cx, &T::class_, proto, newKind, objFlags); 449 return obj ? &obj->as<T>() : nullptr; 450 } 451 452 template <class T> 453 inline T* NewObjectWithClassProto(JSContext* cx, HandleObject proto, 454 gc::AllocKind allocKind, 455 NewObjectKind newKind = GenericObject) { 456 NativeObject* obj = 457 NewObjectWithClassProto(cx, &T::class_, proto, allocKind, newKind); 458 return obj ? &obj->as<T>() : nullptr; 459 } 460 461 /* 462 * Create a native instance of the given class with parent and proto set 463 * according to the context's active global. 464 */ 465 inline NativeObject* NewBuiltinClassInstance( 466 JSContext* cx, const JSClass* clasp, gc::AllocKind allocKind, 467 NewObjectKind newKind = GenericObject) { 468 return NewObjectWithClassProto(cx, clasp, nullptr, allocKind, newKind); 469 } 470 471 inline NativeObject* NewBuiltinClassInstance( 472 JSContext* cx, const JSClass* clasp, 473 NewObjectKind newKind = GenericObject) { 474 gc::AllocKind allocKind = gc::GetGCObjectKind(clasp); 475 return NewBuiltinClassInstance(cx, clasp, allocKind, newKind); 476 } 477 478 template <typename T> 479 inline T* NewBuiltinClassInstance(JSContext* cx) { 480 JSObject* obj = NewBuiltinClassInstance(cx, &T::class_, GenericObject); 481 return obj ? &obj->as<T>() : nullptr; 482 } 483 484 template <typename T> 485 inline T* NewTenuredBuiltinClassInstance(JSContext* cx) { 486 JSObject* obj = NewBuiltinClassInstance(cx, &T::class_, TenuredObject); 487 return obj ? &obj->as<T>() : nullptr; 488 } 489 490 template <typename T> 491 inline T* NewBuiltinClassInstanceWithKind(JSContext* cx, 492 NewObjectKind newKind) { 493 JSObject* obj = NewBuiltinClassInstance(cx, &T::class_, newKind); 494 return obj ? &obj->as<T>() : nullptr; 495 } 496 497 template <typename T> 498 inline T* NewBuiltinClassInstance(JSContext* cx, gc::AllocKind allocKind, 499 NewObjectKind newKind = GenericObject) { 500 JSObject* obj = NewBuiltinClassInstance(cx, &T::class_, allocKind, newKind); 501 return obj ? &obj->as<T>() : nullptr; 502 } 503 504 static constexpr gc::AllocKind GuessArrayGCKind(size_t numElements) { 505 if (numElements) { 506 return gc::GetGCArrayKind(numElements); 507 } 508 return gc::AllocKind::OBJECT8; 509 } 510 511 // Returns ESClass::Other if the value isn't an object, or if the object 512 // isn't of one of the enumerated classes. Otherwise returns the appropriate 513 // class. 514 inline bool GetClassOfValue(JSContext* cx, HandleValue v, ESClass* cls) { 515 if (!v.isObject()) { 516 *cls = ESClass::Other; 517 return true; 518 } 519 520 RootedObject obj(cx, &v.toObject()); 521 return JS::GetBuiltinClass(cx, obj, cls); 522 } 523 524 extern NativeObject* InitClass( 525 JSContext* cx, HandleObject obj, const JSClass* protoClass, 526 HandleObject protoProto, const char* name, JSNative constructor, 527 unsigned nargs, const JSPropertySpec* ps, const JSFunctionSpec* fs, 528 const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs, 529 NativeObject** ctorp = nullptr); 530 531 MOZ_ALWAYS_INLINE const char* GetObjectClassName(JSContext* cx, 532 HandleObject obj) { 533 if (obj->is<ProxyObject>()) { 534 return Proxy::className(cx, obj); 535 } 536 537 return obj->getClass()->name; 538 } 539 540 inline bool IsCallable(const Value& v) { 541 return v.isObject() && v.toObject().isCallable(); 542 } 543 544 // ES6 rev 24 (2014 April 27) 7.2.5 IsConstructor 545 inline bool IsConstructor(const Value& v) { 546 return v.isObject() && v.toObject().isConstructor(); 547 } 548 549 static inline bool MaybePreserveDOMWrapper(JSContext* cx, HandleObject obj) { 550 const JSClass* clasp = obj->getClass(); 551 // If this ever changes, we'll just need to reevaluate the check below 552 MOZ_ASSERT_IF(clasp->preservesWrapper(), clasp->isDOMClass()); 553 if (!clasp->isDOMClass()) { 554 return true; 555 } 556 557 if (!obj->zone()->preserveWrapper(obj.get())) { 558 return cx->runtime()->preserveWrapperCallback(cx, obj); 559 } 560 561 return true; 562 } 563 564 } /* namespace js */ 565 566 MOZ_ALWAYS_INLINE bool JSObject::isCallable() const { 567 if (is<JSFunction>()) { 568 return true; 569 } 570 if (is<js::ProxyObject>()) { 571 const js::ProxyObject& p = as<js::ProxyObject>(); 572 return p.handler()->isCallable(const_cast<JSObject*>(this)); 573 } 574 return callHook() != nullptr; 575 } 576 577 MOZ_ALWAYS_INLINE bool JSObject::isConstructor() const { 578 if (is<JSFunction>()) { 579 const JSFunction& fun = as<JSFunction>(); 580 return fun.isConstructor(); 581 } 582 if (is<js::BoundFunctionObject>()) { 583 const js::BoundFunctionObject& bound = as<js::BoundFunctionObject>(); 584 return bound.isConstructor(); 585 } 586 if (is<js::ProxyObject>()) { 587 const js::ProxyObject& p = as<js::ProxyObject>(); 588 return p.handler()->isConstructor(const_cast<JSObject*>(this)); 589 } 590 return constructHook() != nullptr; 591 } 592 593 MOZ_ALWAYS_INLINE JSNative JSObject::callHook() const { 594 return getClass()->getCall(); 595 } 596 597 MOZ_ALWAYS_INLINE JSNative JSObject::constructHook() const { 598 return getClass()->getConstruct(); 599 } 600 601 #endif /* vm_JSObject_inl_h */