1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsobjinlines.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1115 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jsobjinlines_h 1.11 +#define jsobjinlines_h 1.12 + 1.13 +#include "jsobj.h" 1.14 + 1.15 +#include "vm/ArrayObject.h" 1.16 +#include "vm/DateObject.h" 1.17 +#include "vm/NumberObject.h" 1.18 +#include "vm/Probes.h" 1.19 +#include "vm/ScopeObject.h" 1.20 +#include "vm/StringObject.h" 1.21 + 1.22 +#include "jsatominlines.h" 1.23 +#include "jscompartmentinlines.h" 1.24 +#include "jsgcinlines.h" 1.25 +#include "jsinferinlines.h" 1.26 + 1.27 +#include "vm/ObjectImpl-inl.h" 1.28 + 1.29 +/* static */ inline bool 1.30 +JSObject::setGenericAttributes(JSContext *cx, js::HandleObject obj, 1.31 + js::HandleId id, unsigned *attrsp) 1.32 +{ 1.33 + js::types::MarkTypePropertyNonData(cx, obj, id); 1.34 + js::GenericAttributesOp op = obj->getOps()->setGenericAttributes; 1.35 + return (op ? op : js::baseops::SetAttributes)(cx, obj, id, attrsp); 1.36 +} 1.37 + 1.38 +/* static */ inline bool 1.39 +JSObject::changePropertyAttributes(JSContext *cx, js::HandleObject obj, 1.40 + js::HandleShape shape, unsigned attrs) 1.41 +{ 1.42 + return !!changeProperty<js::SequentialExecution>(cx, obj, shape, attrs, 0, 1.43 + shape->getter(), shape->setter()); 1.44 +} 1.45 + 1.46 +/* static */ inline bool 1.47 +JSObject::deleteProperty(JSContext *cx, js::HandleObject obj, js::HandlePropertyName name, 1.48 + bool *succeeded) 1.49 +{ 1.50 + JS::RootedId id(cx, js::NameToId(name)); 1.51 + js::types::MarkTypePropertyNonData(cx, obj, id); 1.52 + js::DeletePropertyOp op = obj->getOps()->deleteProperty; 1.53 + return (op ? op : js::baseops::DeleteProperty)(cx, obj, name, succeeded); 1.54 +} 1.55 + 1.56 +/* static */ inline bool 1.57 +JSObject::deleteElement(JSContext *cx, js::HandleObject obj, uint32_t index, bool *succeeded) 1.58 +{ 1.59 + JS::RootedId id(cx); 1.60 + if (!js::IndexToId(cx, index, &id)) 1.61 + return false; 1.62 + js::types::MarkTypePropertyNonData(cx, obj, id); 1.63 + js::DeleteElementOp op = obj->getOps()->deleteElement; 1.64 + return (op ? op : js::baseops::DeleteElement)(cx, obj, index, succeeded); 1.65 +} 1.66 + 1.67 +/* static */ inline bool 1.68 +JSObject::watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, 1.69 + JS::HandleObject callable) 1.70 +{ 1.71 + js::WatchOp op = obj->getOps()->watch; 1.72 + return (op ? op : js::baseops::Watch)(cx, obj, id, callable); 1.73 +} 1.74 + 1.75 +/* static */ inline bool 1.76 +JSObject::unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id) 1.77 +{ 1.78 + js::UnwatchOp op = obj->getOps()->unwatch; 1.79 + return (op ? op : js::baseops::Unwatch)(cx, obj, id); 1.80 +} 1.81 + 1.82 +inline void 1.83 +JSObject::finalize(js::FreeOp *fop) 1.84 +{ 1.85 + js::probes::FinalizeObject(this); 1.86 + 1.87 +#ifdef DEBUG 1.88 + JS_ASSERT(isTenured()); 1.89 + if (!IsBackgroundFinalized(tenuredGetAllocKind())) { 1.90 + /* Assert we're on the main thread. */ 1.91 + JS_ASSERT(CurrentThreadCanAccessRuntime(fop->runtime())); 1.92 + } 1.93 +#endif 1.94 + const js::Class *clasp = getClass(); 1.95 + if (clasp->finalize) 1.96 + clasp->finalize(fop, this); 1.97 + 1.98 + finish(fop); 1.99 +} 1.100 + 1.101 +inline void 1.102 +JSObject::setLastPropertyInfallible(js::Shape *shape) 1.103 +{ 1.104 + JS_ASSERT(!shape->inDictionary()); 1.105 + JS_ASSERT(shape->compartment() == compartment()); 1.106 + JS_ASSERT(!inDictionaryMode()); 1.107 + JS_ASSERT(slotSpan() == shape->slotSpan()); 1.108 + JS_ASSERT(numFixedSlots() == shape->numFixedSlots()); 1.109 + 1.110 + shape_ = shape; 1.111 +} 1.112 + 1.113 +inline void 1.114 +JSObject::removeLastProperty(js::ExclusiveContext *cx) 1.115 +{ 1.116 + JS_ASSERT(canRemoveLastProperty()); 1.117 + JS::RootedObject self(cx, this); 1.118 + js::RootedShape prev(cx, lastProperty()->previous()); 1.119 + JS_ALWAYS_TRUE(setLastProperty(cx, self, prev)); 1.120 +} 1.121 + 1.122 +inline bool 1.123 +JSObject::canRemoveLastProperty() 1.124 +{ 1.125 + /* 1.126 + * Check that the information about the object stored in the last 1.127 + * property's base shape is consistent with that stored in the previous 1.128 + * shape. If not consistent, then the last property cannot be removed as it 1.129 + * will induce a change in the object itself, and the object must be 1.130 + * converted to dictionary mode instead. See BaseShape comment in jsscope.h 1.131 + */ 1.132 + JS_ASSERT(!inDictionaryMode()); 1.133 + js::Shape *previous = lastProperty()->previous().get(); 1.134 + return previous->getObjectParent() == lastProperty()->getObjectParent() 1.135 + && previous->getObjectMetadata() == lastProperty()->getObjectMetadata() 1.136 + && previous->getObjectFlags() == lastProperty()->getObjectFlags(); 1.137 +} 1.138 + 1.139 +inline void 1.140 +JSObject::setShouldConvertDoubleElements() 1.141 +{ 1.142 + JS_ASSERT(is<js::ArrayObject>() && !hasEmptyElements()); 1.143 + getElementsHeader()->setShouldConvertDoubleElements(); 1.144 +} 1.145 + 1.146 +inline void 1.147 +JSObject::clearShouldConvertDoubleElements() 1.148 +{ 1.149 + JS_ASSERT(is<js::ArrayObject>() && !hasEmptyElements()); 1.150 + getElementsHeader()->clearShouldConvertDoubleElements(); 1.151 +} 1.152 + 1.153 +inline bool 1.154 +JSObject::setDenseElementIfHasType(uint32_t index, const js::Value &val) 1.155 +{ 1.156 + if (!js::types::HasTypePropertyId(this, JSID_VOID, val)) 1.157 + return false; 1.158 + setDenseElementMaybeConvertDouble(index, val); 1.159 + return true; 1.160 +} 1.161 + 1.162 +inline void 1.163 +JSObject::setDenseElementWithType(js::ExclusiveContext *cx, uint32_t index, 1.164 + const js::Value &val) 1.165 +{ 1.166 + // Avoid a slow AddTypePropertyId call if the type is the same as the type 1.167 + // of the previous element. 1.168 + js::types::Type thisType = js::types::GetValueType(val); 1.169 + if (index == 0 || js::types::GetValueType(elements[index - 1]) != thisType) 1.170 + js::types::AddTypePropertyId(cx, this, JSID_VOID, thisType); 1.171 + setDenseElementMaybeConvertDouble(index, val); 1.172 +} 1.173 + 1.174 +inline void 1.175 +JSObject::initDenseElementWithType(js::ExclusiveContext *cx, uint32_t index, 1.176 + const js::Value &val) 1.177 +{ 1.178 + JS_ASSERT(!shouldConvertDoubleElements()); 1.179 + js::types::AddTypePropertyId(cx, this, JSID_VOID, val); 1.180 + initDenseElement(index, val); 1.181 +} 1.182 + 1.183 +inline void 1.184 +JSObject::setDenseElementHole(js::ExclusiveContext *cx, uint32_t index) 1.185 +{ 1.186 + js::types::MarkTypeObjectFlags(cx, this, js::types::OBJECT_FLAG_NON_PACKED); 1.187 + setDenseElement(index, js::MagicValue(JS_ELEMENTS_HOLE)); 1.188 +} 1.189 + 1.190 +/* static */ inline void 1.191 +JSObject::removeDenseElementForSparseIndex(js::ExclusiveContext *cx, 1.192 + js::HandleObject obj, uint32_t index) 1.193 +{ 1.194 + js::types::MarkTypeObjectFlags(cx, obj, 1.195 + js::types::OBJECT_FLAG_NON_PACKED | 1.196 + js::types::OBJECT_FLAG_SPARSE_INDEXES); 1.197 + if (obj->containsDenseElement(index)) 1.198 + obj->setDenseElement(index, js::MagicValue(JS_ELEMENTS_HOLE)); 1.199 +} 1.200 + 1.201 +inline bool 1.202 +JSObject::writeToIndexWouldMarkNotPacked(uint32_t index) 1.203 +{ 1.204 + return getElementsHeader()->initializedLength < index; 1.205 +} 1.206 + 1.207 +inline void 1.208 +JSObject::markDenseElementsNotPacked(js::ExclusiveContext *cx) 1.209 +{ 1.210 + JS_ASSERT(isNative()); 1.211 + MarkTypeObjectFlags(cx, this, js::types::OBJECT_FLAG_NON_PACKED); 1.212 +} 1.213 + 1.214 +inline void 1.215 +JSObject::ensureDenseInitializedLengthNoPackedCheck(js::ThreadSafeContext *cx, uint32_t index, 1.216 + uint32_t extra) 1.217 +{ 1.218 + JS_ASSERT(cx->isThreadLocal(this)); 1.219 + 1.220 + /* 1.221 + * Ensure that the array's contents have been initialized up to index, and 1.222 + * mark the elements through 'index + extra' as initialized in preparation 1.223 + * for a write. 1.224 + */ 1.225 + JS_ASSERT(index + extra <= getDenseCapacity()); 1.226 + uint32_t &initlen = getElementsHeader()->initializedLength; 1.227 + 1.228 + if (initlen < index + extra) { 1.229 + JSRuntime *rt = runtimeFromAnyThread(); 1.230 + size_t offset = initlen; 1.231 + for (js::HeapSlot *sp = elements + initlen; 1.232 + sp != elements + (index + extra); 1.233 + sp++, offset++) 1.234 + sp->init(rt, this, js::HeapSlot::Element, offset, js::MagicValue(JS_ELEMENTS_HOLE)); 1.235 + initlen = index + extra; 1.236 + } 1.237 +} 1.238 + 1.239 +inline void 1.240 +JSObject::ensureDenseInitializedLength(js::ExclusiveContext *cx, uint32_t index, uint32_t extra) 1.241 +{ 1.242 + if (writeToIndexWouldMarkNotPacked(index)) 1.243 + markDenseElementsNotPacked(cx); 1.244 + ensureDenseInitializedLengthNoPackedCheck(cx, index, extra); 1.245 +} 1.246 + 1.247 +inline void 1.248 +JSObject::ensureDenseInitializedLengthPreservePackedFlag(js::ThreadSafeContext *cx, 1.249 + uint32_t index, uint32_t extra) 1.250 +{ 1.251 + JS_ASSERT(!writeToIndexWouldMarkNotPacked(index)); 1.252 + ensureDenseInitializedLengthNoPackedCheck(cx, index, extra); 1.253 +} 1.254 + 1.255 +JSObject::EnsureDenseResult 1.256 +JSObject::extendDenseElements(js::ThreadSafeContext *cx, 1.257 + uint32_t requiredCapacity, uint32_t extra) 1.258 +{ 1.259 + JS_ASSERT(cx->isThreadLocal(this)); 1.260 + 1.261 + /* 1.262 + * Don't grow elements for non-extensible objects or watched objects. Dense 1.263 + * elements can be added/written with no extensible or watchpoint checks as 1.264 + * long as there is capacity for them. 1.265 + */ 1.266 + if (!nonProxyIsExtensible() || watched()) { 1.267 + JS_ASSERT(getDenseCapacity() == 0); 1.268 + return ED_SPARSE; 1.269 + } 1.270 + 1.271 + /* 1.272 + * Don't grow elements for objects which already have sparse indexes. 1.273 + * This avoids needing to count non-hole elements in willBeSparseElements 1.274 + * every time a new index is added. 1.275 + */ 1.276 + if (isIndexed()) 1.277 + return ED_SPARSE; 1.278 + 1.279 + /* 1.280 + * We use the extra argument also as a hint about number of non-hole 1.281 + * elements to be inserted. 1.282 + */ 1.283 + if (requiredCapacity > MIN_SPARSE_INDEX && 1.284 + willBeSparseElements(requiredCapacity, extra)) { 1.285 + return ED_SPARSE; 1.286 + } 1.287 + 1.288 + if (!growElements(cx, requiredCapacity)) 1.289 + return ED_FAILED; 1.290 + 1.291 + return ED_OK; 1.292 +} 1.293 + 1.294 +inline JSObject::EnsureDenseResult 1.295 +JSObject::ensureDenseElementsNoPackedCheck(js::ThreadSafeContext *cx, uint32_t index, uint32_t extra) 1.296 +{ 1.297 + JS_ASSERT(isNative()); 1.298 + 1.299 + uint32_t currentCapacity = getDenseCapacity(); 1.300 + 1.301 + uint32_t requiredCapacity; 1.302 + if (extra == 1) { 1.303 + /* Optimize for the common case. */ 1.304 + if (index < currentCapacity) { 1.305 + ensureDenseInitializedLengthNoPackedCheck(cx, index, 1); 1.306 + return ED_OK; 1.307 + } 1.308 + requiredCapacity = index + 1; 1.309 + if (requiredCapacity == 0) { 1.310 + /* Overflow. */ 1.311 + return ED_SPARSE; 1.312 + } 1.313 + } else { 1.314 + requiredCapacity = index + extra; 1.315 + if (requiredCapacity < index) { 1.316 + /* Overflow. */ 1.317 + return ED_SPARSE; 1.318 + } 1.319 + if (requiredCapacity <= currentCapacity) { 1.320 + ensureDenseInitializedLengthNoPackedCheck(cx, index, extra); 1.321 + return ED_OK; 1.322 + } 1.323 + } 1.324 + 1.325 + EnsureDenseResult edr = extendDenseElements(cx, requiredCapacity, extra); 1.326 + if (edr != ED_OK) 1.327 + return edr; 1.328 + 1.329 + ensureDenseInitializedLengthNoPackedCheck(cx, index, extra); 1.330 + return ED_OK; 1.331 +} 1.332 + 1.333 +inline JSObject::EnsureDenseResult 1.334 +JSObject::ensureDenseElements(js::ExclusiveContext *cx, uint32_t index, uint32_t extra) 1.335 +{ 1.336 + if (writeToIndexWouldMarkNotPacked(index)) 1.337 + markDenseElementsNotPacked(cx); 1.338 + return ensureDenseElementsNoPackedCheck(cx, index, extra); 1.339 +} 1.340 + 1.341 +inline JSObject::EnsureDenseResult 1.342 +JSObject::ensureDenseElementsPreservePackedFlag(js::ThreadSafeContext *cx, uint32_t index, 1.343 + uint32_t extra) 1.344 +{ 1.345 + JS_ASSERT(!writeToIndexWouldMarkNotPacked(index)); 1.346 + return ensureDenseElementsNoPackedCheck(cx, index, extra); 1.347 +} 1.348 + 1.349 +inline js::Value 1.350 +JSObject::getDenseOrTypedArrayElement(uint32_t idx) 1.351 +{ 1.352 + if (is<js::TypedArrayObject>()) 1.353 + return as<js::TypedArrayObject>().getElement(idx); 1.354 + return getDenseElement(idx); 1.355 +} 1.356 + 1.357 +/* static */ inline bool 1.358 +JSObject::setSingletonType(js::ExclusiveContext *cx, js::HandleObject obj) 1.359 +{ 1.360 + JS_ASSERT_IF(cx->isJSContext(), 1.361 + !IsInsideNursery(cx->asJSContext()->runtime(), obj.get())); 1.362 + 1.363 + js::types::TypeObject *type = cx->getSingletonType(obj->getClass(), obj->getTaggedProto()); 1.364 + if (!type) 1.365 + return false; 1.366 + 1.367 + obj->type_ = type; 1.368 + return true; 1.369 +} 1.370 + 1.371 +inline js::types::TypeObject* 1.372 +JSObject::getType(JSContext *cx) 1.373 +{ 1.374 + JS_ASSERT(cx->compartment() == compartment()); 1.375 + if (hasLazyType()) { 1.376 + JS::RootedObject self(cx, this); 1.377 + if (cx->compartment() != compartment()) 1.378 + MOZ_CRASH(); 1.379 + return makeLazyType(cx, self); 1.380 + } 1.381 + return static_cast<js::types::TypeObject*>(type_); 1.382 +} 1.383 + 1.384 +/* static */ inline bool 1.385 +JSObject::clearType(JSContext *cx, js::HandleObject obj) 1.386 +{ 1.387 + JS_ASSERT(!obj->hasSingletonType()); 1.388 + JS_ASSERT(cx->compartment() == obj->compartment()); 1.389 + 1.390 + js::types::TypeObject *type = cx->getNewType(obj->getClass(), nullptr); 1.391 + if (!type) 1.392 + return false; 1.393 + 1.394 + obj->type_ = type; 1.395 + return true; 1.396 +} 1.397 + 1.398 +inline void 1.399 +JSObject::setType(js::types::TypeObject *newType) 1.400 +{ 1.401 + JS_ASSERT(newType); 1.402 + JS_ASSERT(!hasSingletonType()); 1.403 + type_ = newType; 1.404 +} 1.405 + 1.406 +/* static */ inline bool 1.407 +JSObject::getProto(JSContext *cx, js::HandleObject obj, js::MutableHandleObject protop) 1.408 +{ 1.409 + if (obj->getTaggedProto().isLazy()) { 1.410 + JS_ASSERT(obj->is<js::ProxyObject>()); 1.411 + return js::Proxy::getPrototypeOf(cx, obj, protop); 1.412 + } else { 1.413 + protop.set(obj->getTaggedProto().toObjectOrNull()); 1.414 + return true; 1.415 + } 1.416 +} 1.417 + 1.418 +/* static */ inline bool 1.419 +JSObject::setProto(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto, bool *succeeded) 1.420 +{ 1.421 + /* Proxies live in their own little world. */ 1.422 + if (obj->getTaggedProto().isLazy()) { 1.423 + JS_ASSERT(obj->is<js::ProxyObject>()); 1.424 + return js::Proxy::setPrototypeOf(cx, obj, proto, succeeded); 1.425 + } 1.426 + 1.427 + /* 1.428 + * Disallow mutating the [[Prototype]] on ArrayBuffer objects, which 1.429 + * due to their complicated delegate-object shenanigans can't easily 1.430 + * have a mutable [[Prototype]]. 1.431 + */ 1.432 + if (obj->is<js::ArrayBufferObject>()) { 1.433 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_SETPROTOTYPEOF_FAIL, 1.434 + "incompatible ArrayBuffer"); 1.435 + return false; 1.436 + } 1.437 + 1.438 + /* 1.439 + * Disallow mutating the [[Prototype]] on Typed Objects, per the spec. 1.440 + */ 1.441 + if (obj->is<js::TypedObject>()) { 1.442 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_SETPROTOTYPEOF_FAIL, 1.443 + "incompatible TypedObject"); 1.444 + return false; 1.445 + } 1.446 + 1.447 + /* 1.448 + * Explicitly disallow mutating the [[Prototype]] of Location objects 1.449 + * for flash-related security reasons. 1.450 + */ 1.451 + if (!strcmp(obj->getClass()->name, "Location")) { 1.452 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_SETPROTOTYPEOF_FAIL, 1.453 + "incompatible Location object"); 1.454 + return false; 1.455 + } 1.456 + 1.457 + /* ES6 9.1.2 step 5 forbids changing [[Prototype]] if not [[Extensible]]. */ 1.458 + bool extensible; 1.459 + if (!JSObject::isExtensible(cx, obj, &extensible)) 1.460 + return false; 1.461 + if (!extensible) { 1.462 + *succeeded = false; 1.463 + return true; 1.464 + } 1.465 + 1.466 + /* ES6 9.1.2 step 6 forbids generating cyclical prototype chains. */ 1.467 + js::RootedObject obj2(cx); 1.468 + for (obj2 = proto; obj2; ) { 1.469 + if (obj2 == obj) { 1.470 + *succeeded = false; 1.471 + return true; 1.472 + } 1.473 + 1.474 + if (!JSObject::getProto(cx, obj2, &obj2)) 1.475 + return false; 1.476 + } 1.477 + 1.478 + return SetClassAndProto(cx, obj, obj->getClass(), proto, succeeded); 1.479 +} 1.480 + 1.481 +inline bool 1.482 +JSObject::isVarObj() 1.483 +{ 1.484 + if (is<js::DebugScopeObject>()) 1.485 + return as<js::DebugScopeObject>().scope().isVarObj(); 1.486 + return lastProperty()->hasObjectFlag(js::BaseShape::VAROBJ); 1.487 +} 1.488 + 1.489 +/* static */ inline JSObject * 1.490 +JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::InitialHeap heap, 1.491 + js::HandleShape shape, js::HandleTypeObject type, 1.492 + js::HeapSlot *extantSlots /* = nullptr */) 1.493 +{ 1.494 + /* 1.495 + * Callers must use dynamicSlotsCount to size the initial slot array of the 1.496 + * object. We can't check the allocated capacity of the dynamic slots, but 1.497 + * make sure their presence is consistent with the shape. 1.498 + */ 1.499 + JS_ASSERT(shape && type); 1.500 + JS_ASSERT(type->clasp() == shape->getObjectClass()); 1.501 + JS_ASSERT(type->clasp() != &js::ArrayObject::class_); 1.502 + JS_ASSERT_IF(!ClassCanHaveFixedData(type->clasp()), 1.503 + js::gc::GetGCKindSlots(kind, type->clasp()) == shape->numFixedSlots()); 1.504 + JS_ASSERT_IF(type->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind)); 1.505 + JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap); 1.506 + JS_ASSERT_IF(extantSlots, dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), 1.507 + type->clasp())); 1.508 + 1.509 + const js::Class *clasp = type->clasp(); 1.510 + size_t nDynamicSlots = 0; 1.511 + if (!extantSlots) 1.512 + nDynamicSlots = dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp); 1.513 + 1.514 + JSObject *obj = js::NewGCObject<js::CanGC>(cx, kind, nDynamicSlots, heap); 1.515 + if (!obj) 1.516 + return nullptr; 1.517 + 1.518 + obj->shape_.init(shape); 1.519 + obj->type_.init(type); 1.520 + if (extantSlots) { 1.521 +#ifdef JSGC_GENERATIONAL 1.522 + if (cx->isJSContext()) 1.523 + cx->asJSContext()->runtime()->gcNursery.notifyInitialSlots(obj, extantSlots); 1.524 +#endif 1.525 + obj->slots = extantSlots; 1.526 + } 1.527 + obj->elements = js::emptyObjectElements; 1.528 + 1.529 + if (clasp->hasPrivate()) 1.530 + obj->privateRef(shape->numFixedSlots()) = nullptr; 1.531 + 1.532 + size_t span = shape->slotSpan(); 1.533 + if (span) 1.534 + obj->initializeSlotRange(0, span); 1.535 + 1.536 + // JSFunction's fixed slots expect POD-style initialization. 1.537 + if (type->clasp()->isJSFunction()) 1.538 + memset(obj->fixedSlots(), 0, sizeof(js::HeapSlot) * GetGCKindSlots(kind)); 1.539 + 1.540 + return obj; 1.541 +} 1.542 + 1.543 +/* static */ inline js::ArrayObject * 1.544 +JSObject::createArray(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::InitialHeap heap, 1.545 + js::HandleShape shape, js::HandleTypeObject type, 1.546 + uint32_t length) 1.547 +{ 1.548 + JS_ASSERT(shape && type); 1.549 + JS_ASSERT(type->clasp() == shape->getObjectClass()); 1.550 + JS_ASSERT(type->clasp() == &js::ArrayObject::class_); 1.551 + JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap); 1.552 + 1.553 + /* 1.554 + * Arrays use their fixed slots to store elements, and must have enough 1.555 + * space for the elements header and also be marked as having no space for 1.556 + * named properties stored in those fixed slots. 1.557 + */ 1.558 + JS_ASSERT(shape->numFixedSlots() == 0); 1.559 + size_t nDynamicSlots = dynamicSlotsCount(0, shape->slotSpan(), type->clasp()); 1.560 + JSObject *obj = js::NewGCObject<js::CanGC>(cx, kind, nDynamicSlots, heap); 1.561 + if (!obj) 1.562 + return nullptr; 1.563 + 1.564 + uint32_t capacity = js::gc::GetGCKindSlots(kind) - js::ObjectElements::VALUES_PER_HEADER; 1.565 + 1.566 + obj->shape_.init(shape); 1.567 + obj->type_.init(type); 1.568 + obj->setFixedElements(); 1.569 + new (obj->getElementsHeader()) js::ObjectElements(capacity, length); 1.570 + 1.571 + size_t span = shape->slotSpan(); 1.572 + if (span) 1.573 + obj->initializeSlotRange(0, span); 1.574 + 1.575 + return &obj->as<js::ArrayObject>(); 1.576 +} 1.577 + 1.578 +inline void 1.579 +JSObject::finish(js::FreeOp *fop) 1.580 +{ 1.581 + if (hasDynamicSlots()) 1.582 + fop->free_(slots); 1.583 + 1.584 + if (hasDynamicElements()) { 1.585 + js::ObjectElements *elements = getElementsHeader(); 1.586 + fop->free_(elements); 1.587 + } 1.588 +} 1.589 + 1.590 +/* static */ inline bool 1.591 +JSObject::hasProperty(JSContext *cx, js::HandleObject obj, 1.592 + js::HandleId id, bool *foundp) 1.593 +{ 1.594 + JS::RootedObject pobj(cx); 1.595 + js::RootedShape prop(cx); 1.596 + if (!lookupGeneric(cx, obj, id, &pobj, &prop)) { 1.597 + *foundp = false; /* initialize to shut GCC up */ 1.598 + return false; 1.599 + } 1.600 + *foundp = !!prop; 1.601 + return true; 1.602 +} 1.603 + 1.604 +inline bool 1.605 +JSObject::nativeSetSlotIfHasType(js::Shape *shape, const js::Value &value) 1.606 +{ 1.607 + if (!js::types::HasTypePropertyId(this, shape->propid(), value)) 1.608 + return false; 1.609 + nativeSetSlot(shape->slot(), value); 1.610 + return true; 1.611 +} 1.612 + 1.613 +inline void 1.614 +JSObject::nativeSetSlotWithType(js::ExclusiveContext *cx, js::Shape *shape, 1.615 + const js::Value &value) 1.616 +{ 1.617 + nativeSetSlot(shape->slot(), value); 1.618 + js::types::AddTypePropertyId(cx, this, shape->propid(), value); 1.619 +} 1.620 + 1.621 +/* static */ inline bool 1.622 +JSObject::getElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver, 1.623 + uint32_t index, js::MutableHandleValue vp) 1.624 +{ 1.625 + js::ElementIdOp op = obj->getOps()->getElement; 1.626 + if (op) 1.627 + return op(cx, obj, receiver, index, vp); 1.628 + 1.629 + JS::RootedId id(cx); 1.630 + if (!js::IndexToId(cx, index, &id)) 1.631 + return false; 1.632 + return getGeneric(cx, obj, receiver, id, vp); 1.633 +} 1.634 + 1.635 +/* static */ inline bool 1.636 +JSObject::getElementNoGC(JSContext *cx, JSObject *obj, JSObject *receiver, 1.637 + uint32_t index, js::Value *vp) 1.638 +{ 1.639 + js::ElementIdOp op = obj->getOps()->getElement; 1.640 + if (op) 1.641 + return false; 1.642 + 1.643 + if (index > JSID_INT_MAX) 1.644 + return false; 1.645 + return getGenericNoGC(cx, obj, receiver, INT_TO_JSID(index), vp); 1.646 +} 1.647 + 1.648 +inline js::GlobalObject & 1.649 +JSObject::global() const 1.650 +{ 1.651 +#ifdef DEBUG 1.652 + JSObject *obj = const_cast<JSObject *>(this); 1.653 + while (JSObject *parent = obj->getParent()) 1.654 + obj = parent; 1.655 +#endif 1.656 + return *compartment()->maybeGlobal(); 1.657 +} 1.658 + 1.659 +inline bool 1.660 +JSObject::isOwnGlobal() const 1.661 +{ 1.662 + return &global() == this; 1.663 +} 1.664 + 1.665 +namespace js { 1.666 + 1.667 +PropDesc::PropDesc(const Value &getter, const Value &setter, 1.668 + Enumerability enumerable, Configurability configurable) 1.669 + : pd_(UndefinedValue()), 1.670 + value_(UndefinedValue()), 1.671 + get_(getter), set_(setter), 1.672 + attrs(JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED | 1.673 + (enumerable ? JSPROP_ENUMERATE : 0) | 1.674 + (configurable ? 0 : JSPROP_PERMANENT)), 1.675 + hasGet_(true), hasSet_(true), 1.676 + hasValue_(false), hasWritable_(false), hasEnumerable_(true), hasConfigurable_(true), 1.677 + isUndefined_(false) 1.678 +{ 1.679 + MOZ_ASSERT(getter.isUndefined() || js_IsCallable(getter)); 1.680 + MOZ_ASSERT(setter.isUndefined() || js_IsCallable(setter)); 1.681 +} 1.682 + 1.683 +static MOZ_ALWAYS_INLINE bool 1.684 +IsFunctionObject(const js::Value &v) 1.685 +{ 1.686 + return v.isObject() && v.toObject().is<JSFunction>(); 1.687 +} 1.688 + 1.689 +static MOZ_ALWAYS_INLINE bool 1.690 +IsFunctionObject(const js::Value &v, JSFunction **fun) 1.691 +{ 1.692 + if (v.isObject() && v.toObject().is<JSFunction>()) { 1.693 + *fun = &v.toObject().as<JSFunction>(); 1.694 + return true; 1.695 + } 1.696 + return false; 1.697 +} 1.698 + 1.699 +static MOZ_ALWAYS_INLINE bool 1.700 +IsNativeFunction(const js::Value &v) 1.701 +{ 1.702 + JSFunction *fun; 1.703 + return IsFunctionObject(v, &fun) && fun->isNative(); 1.704 +} 1.705 + 1.706 +static MOZ_ALWAYS_INLINE bool 1.707 +IsNativeFunction(const js::Value &v, JSFunction **fun) 1.708 +{ 1.709 + return IsFunctionObject(v, fun) && (*fun)->isNative(); 1.710 +} 1.711 + 1.712 +static MOZ_ALWAYS_INLINE bool 1.713 +IsNativeFunction(const js::Value &v, JSNative native) 1.714 +{ 1.715 + JSFunction *fun; 1.716 + return IsFunctionObject(v, &fun) && fun->maybeNative() == native; 1.717 +} 1.718 + 1.719 +/* 1.720 + * When we have an object of a builtin class, we don't quite know what its 1.721 + * valueOf/toString methods are, since these methods may have been overwritten 1.722 + * or shadowed. However, we can still do better than the general case by 1.723 + * hard-coding the necessary properties for us to find the native we expect. 1.724 + * 1.725 + * TODO: a per-thread shape-based cache would be faster and simpler. 1.726 + */ 1.727 +static MOZ_ALWAYS_INLINE bool 1.728 +ClassMethodIsNative(JSContext *cx, JSObject *obj, const Class *clasp, jsid methodid, JSNative native) 1.729 +{ 1.730 + JS_ASSERT(!obj->is<ProxyObject>()); 1.731 + JS_ASSERT(obj->getClass() == clasp); 1.732 + 1.733 + Value v; 1.734 + if (!HasDataProperty(cx, obj, methodid, &v)) { 1.735 + JSObject *proto = obj->getProto(); 1.736 + if (!proto || proto->getClass() != clasp || !HasDataProperty(cx, proto, methodid, &v)) 1.737 + return false; 1.738 + } 1.739 + 1.740 + return js::IsNativeFunction(v, native); 1.741 +} 1.742 + 1.743 +/* ES5 9.1 ToPrimitive(input). */ 1.744 +static MOZ_ALWAYS_INLINE bool 1.745 +ToPrimitive(JSContext *cx, MutableHandleValue vp) 1.746 +{ 1.747 + if (vp.isPrimitive()) 1.748 + return true; 1.749 + 1.750 + JSObject *obj = &vp.toObject(); 1.751 + 1.752 + /* Optimize new String(...).valueOf(). */ 1.753 + if (obj->is<StringObject>()) { 1.754 + jsid id = NameToId(cx->names().valueOf); 1.755 + if (ClassMethodIsNative(cx, obj, &StringObject::class_, id, js_str_toString)) { 1.756 + vp.setString(obj->as<StringObject>().unbox()); 1.757 + return true; 1.758 + } 1.759 + } 1.760 + 1.761 + /* Optimize new Number(...).valueOf(). */ 1.762 + if (obj->is<NumberObject>()) { 1.763 + jsid id = NameToId(cx->names().valueOf); 1.764 + if (ClassMethodIsNative(cx, obj, &NumberObject::class_, id, js_num_valueOf)) { 1.765 + vp.setNumber(obj->as<NumberObject>().unbox()); 1.766 + return true; 1.767 + } 1.768 + } 1.769 + 1.770 + RootedObject objRoot(cx, obj); 1.771 + return JSObject::defaultValue(cx, objRoot, JSTYPE_VOID, vp); 1.772 +} 1.773 + 1.774 +/* ES5 9.1 ToPrimitive(input, PreferredType). */ 1.775 +static MOZ_ALWAYS_INLINE bool 1.776 +ToPrimitive(JSContext *cx, JSType preferredType, MutableHandleValue vp) 1.777 +{ 1.778 + JS_ASSERT(preferredType != JSTYPE_VOID); /* Use the other ToPrimitive! */ 1.779 + if (vp.isPrimitive()) 1.780 + return true; 1.781 + RootedObject obj(cx, &vp.toObject()); 1.782 + return JSObject::defaultValue(cx, obj, preferredType, vp); 1.783 +} 1.784 + 1.785 +/* 1.786 + * Return true if this is a compiler-created internal function accessed by 1.787 + * its own object. Such a function object must not be accessible to script 1.788 + * or embedding code. 1.789 + */ 1.790 +inline bool 1.791 +IsInternalFunctionObject(JSObject *funobj) 1.792 +{ 1.793 + JSFunction *fun = &funobj->as<JSFunction>(); 1.794 + return fun->isLambda() && !funobj->getParent(); 1.795 +} 1.796 + 1.797 +class AutoPropDescArrayRooter : private AutoGCRooter 1.798 +{ 1.799 + public: 1.800 + AutoPropDescArrayRooter(JSContext *cx) 1.801 + : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx) 1.802 + { } 1.803 + 1.804 + PropDesc *append() { 1.805 + if (!descriptors.append(PropDesc())) 1.806 + return nullptr; 1.807 + return &descriptors.back(); 1.808 + } 1.809 + 1.810 + bool reserve(size_t n) { 1.811 + return descriptors.reserve(n); 1.812 + } 1.813 + 1.814 + PropDesc& operator[](size_t i) { 1.815 + JS_ASSERT(i < descriptors.length()); 1.816 + return descriptors[i]; 1.817 + } 1.818 + 1.819 + friend void AutoGCRooter::trace(JSTracer *trc); 1.820 + 1.821 + private: 1.822 + PropDescArray descriptors; 1.823 +}; 1.824 + 1.825 +/* 1.826 + * Make an object with the specified prototype. If parent is null, it will 1.827 + * default to the prototype's global if the prototype is non-null. 1.828 + */ 1.829 +JSObject * 1.830 +NewObjectWithGivenProto(ExclusiveContext *cx, const js::Class *clasp, TaggedProto proto, JSObject *parent, 1.831 + gc::AllocKind allocKind, NewObjectKind newKind); 1.832 + 1.833 +inline JSObject * 1.834 +NewObjectWithGivenProto(ExclusiveContext *cx, const js::Class *clasp, TaggedProto proto, JSObject *parent, 1.835 + NewObjectKind newKind = GenericObject) 1.836 +{ 1.837 + gc::AllocKind allocKind = gc::GetGCObjectKind(clasp); 1.838 + return NewObjectWithGivenProto(cx, clasp, proto, parent, allocKind, newKind); 1.839 +} 1.840 + 1.841 +inline JSObject * 1.842 +NewObjectWithGivenProto(ExclusiveContext *cx, const js::Class *clasp, JSObject *proto, JSObject *parent, 1.843 + NewObjectKind newKind = GenericObject) 1.844 +{ 1.845 + return NewObjectWithGivenProto(cx, clasp, TaggedProto(proto), parent, newKind); 1.846 +} 1.847 + 1.848 +inline JSProtoKey 1.849 +GetClassProtoKey(const js::Class *clasp) 1.850 +{ 1.851 + JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp); 1.852 + if (key != JSProto_Null) 1.853 + return key; 1.854 + if (clasp->flags & JSCLASS_IS_ANONYMOUS) 1.855 + return JSProto_Object; 1.856 + return JSProto_Null; 1.857 +} 1.858 + 1.859 +inline bool 1.860 +FindProto(ExclusiveContext *cx, const js::Class *clasp, MutableHandleObject proto) 1.861 +{ 1.862 + if (!FindClassPrototype(cx, proto, clasp)) 1.863 + return false; 1.864 + 1.865 + if (!proto) { 1.866 + // We're looking for the prototype of a class that is currently being 1.867 + // resolved; the global object's resolve hook is on the 1.868 + // stack. js::FindClassPrototype detects this goofy case and returns 1.869 + // true with proto null. Fall back on Object.prototype. 1.870 + JS_ASSERT(JSCLASS_CACHED_PROTO_KEY(clasp) == JSProto_Null); 1.871 + return GetBuiltinPrototype(cx, JSProto_Object, proto); 1.872 + } 1.873 + return true; 1.874 +} 1.875 + 1.876 +/* 1.877 + * Make an object with the prototype set according to the specified prototype or class: 1.878 + * 1.879 + * if proto is non-null: 1.880 + * use the specified proto 1.881 + * for a built-in class: 1.882 + * use the memoized original value of the class constructor .prototype 1.883 + * property object 1.884 + * else if available 1.885 + * the current value of .prototype 1.886 + * else 1.887 + * Object.prototype. 1.888 + * 1.889 + * The class prototype will be fetched from the parent's global. If global is 1.890 + * null, the context's active global will be used, and the resulting object's 1.891 + * parent will be that global. 1.892 + */ 1.893 +JSObject * 1.894 +NewObjectWithClassProtoCommon(ExclusiveContext *cx, const js::Class *clasp, JSObject *proto, JSObject *parent, 1.895 + gc::AllocKind allocKind, NewObjectKind newKind); 1.896 + 1.897 +inline JSObject * 1.898 +NewObjectWithClassProto(ExclusiveContext *cx, const js::Class *clasp, JSObject *proto, JSObject *parent, 1.899 + gc::AllocKind allocKind, NewObjectKind newKind = GenericObject) 1.900 +{ 1.901 + return NewObjectWithClassProtoCommon(cx, clasp, proto, parent, allocKind, newKind); 1.902 +} 1.903 + 1.904 +inline JSObject * 1.905 +NewObjectWithClassProto(ExclusiveContext *cx, const js::Class *clasp, JSObject *proto, JSObject *parent, 1.906 + NewObjectKind newKind = GenericObject) 1.907 +{ 1.908 + gc::AllocKind allocKind = gc::GetGCObjectKind(clasp); 1.909 + return NewObjectWithClassProto(cx, clasp, proto, parent, allocKind, newKind); 1.910 +} 1.911 + 1.912 +template<typename T> 1.913 +inline T * 1.914 +NewObjectWithProto(ExclusiveContext *cx, JSObject *proto, JSObject *parent, 1.915 + NewObjectKind newKind = GenericObject) 1.916 +{ 1.917 + JSObject *obj = NewObjectWithClassProto(cx, &T::class_, proto, parent, newKind); 1.918 + if (!obj) 1.919 + return nullptr; 1.920 + 1.921 + return &obj->as<T>(); 1.922 +} 1.923 + 1.924 +/* 1.925 + * Create a native instance of the given class with parent and proto set 1.926 + * according to the context's active global. 1.927 + */ 1.928 +inline JSObject * 1.929 +NewBuiltinClassInstance(ExclusiveContext *cx, const Class *clasp, gc::AllocKind allocKind, 1.930 + NewObjectKind newKind = GenericObject) 1.931 +{ 1.932 + return NewObjectWithClassProto(cx, clasp, nullptr, nullptr, allocKind, newKind); 1.933 +} 1.934 + 1.935 +inline JSObject * 1.936 +NewBuiltinClassInstance(ExclusiveContext *cx, const Class *clasp, NewObjectKind newKind = GenericObject) 1.937 +{ 1.938 + gc::AllocKind allocKind = gc::GetGCObjectKind(clasp); 1.939 + return NewBuiltinClassInstance(cx, clasp, allocKind, newKind); 1.940 +} 1.941 + 1.942 +template<typename T> 1.943 +inline T * 1.944 +NewBuiltinClassInstance(ExclusiveContext *cx, NewObjectKind newKind = GenericObject) 1.945 +{ 1.946 + JSObject *obj = NewBuiltinClassInstance(cx, &T::class_, newKind); 1.947 + if (!obj) 1.948 + return nullptr; 1.949 + 1.950 + return &obj->as<T>(); 1.951 +} 1.952 + 1.953 +template<typename T> 1.954 +inline T * 1.955 +NewBuiltinClassInstance(ExclusiveContext *cx, gc::AllocKind allocKind, NewObjectKind newKind = GenericObject) 1.956 +{ 1.957 + JSObject *obj = NewBuiltinClassInstance(cx, &T::class_, allocKind, newKind); 1.958 + if (!obj) 1.959 + return nullptr; 1.960 + 1.961 + return &obj->as<T>(); 1.962 +} 1.963 + 1.964 +// Used to optimize calls to (new Object()) 1.965 +bool 1.966 +NewObjectScriptedCall(JSContext *cx, MutableHandleObject obj); 1.967 + 1.968 +/* Make an object with pregenerated shape from a NEWOBJECT bytecode. */ 1.969 +static inline JSObject * 1.970 +CopyInitializerObject(JSContext *cx, HandleObject baseobj, NewObjectKind newKind = GenericObject) 1.971 +{ 1.972 + JS_ASSERT(baseobj->getClass() == &JSObject::class_); 1.973 + JS_ASSERT(!baseobj->inDictionaryMode()); 1.974 + 1.975 + gc::AllocKind allocKind = gc::GetGCObjectFixedSlotsKind(baseobj->numFixedSlots()); 1.976 + allocKind = gc::GetBackgroundAllocKind(allocKind); 1.977 + JS_ASSERT_IF(baseobj->isTenured(), allocKind == baseobj->tenuredGetAllocKind()); 1.978 + RootedObject obj(cx); 1.979 + obj = NewBuiltinClassInstance(cx, &JSObject::class_, allocKind, newKind); 1.980 + if (!obj) 1.981 + return nullptr; 1.982 + 1.983 + RootedObject metadata(cx, obj->getMetadata()); 1.984 + RootedShape lastProp(cx, baseobj->lastProperty()); 1.985 + if (!JSObject::setLastProperty(cx, obj, lastProp)) 1.986 + return nullptr; 1.987 + if (metadata && !JSObject::setMetadata(cx, obj, metadata)) 1.988 + return nullptr; 1.989 + 1.990 + return obj; 1.991 +} 1.992 + 1.993 +JSObject * 1.994 +NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, gc::AllocKind allocKind, 1.995 + NewObjectKind newKind = GenericObject); 1.996 + 1.997 +inline JSObject * 1.998 +NewObjectWithType(JSContext *cx, HandleTypeObject type, JSObject *parent, 1.999 + NewObjectKind newKind = GenericObject) 1.1000 +{ 1.1001 + gc::AllocKind allocKind = gc::GetGCObjectKind(type->clasp()); 1.1002 + return NewObjectWithType(cx, type, parent, allocKind, newKind); 1.1003 +} 1.1004 + 1.1005 +JSObject * 1.1006 +NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent, 1.1007 + gc::AllocKind allocKind, HandleShape shape, 1.1008 + NewObjectKind newKind = GenericObject); 1.1009 + 1.1010 +/* 1.1011 + * As for gc::GetGCObjectKind, where numSlots is a guess at the final size of 1.1012 + * the object, zero if the final size is unknown. This should only be used for 1.1013 + * objects that do not require any fixed slots. 1.1014 + */ 1.1015 +static inline gc::AllocKind 1.1016 +GuessObjectGCKind(size_t numSlots) 1.1017 +{ 1.1018 + if (numSlots) 1.1019 + return gc::GetGCObjectKind(numSlots); 1.1020 + return gc::FINALIZE_OBJECT4; 1.1021 +} 1.1022 + 1.1023 +static inline gc::AllocKind 1.1024 +GuessArrayGCKind(size_t numSlots) 1.1025 +{ 1.1026 + if (numSlots) 1.1027 + return gc::GetGCArrayKind(numSlots); 1.1028 + return gc::FINALIZE_OBJECT8; 1.1029 +} 1.1030 + 1.1031 +inline bool 1.1032 +ObjectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) 1.1033 +{ 1.1034 + if (MOZ_UNLIKELY(obj->is<ProxyObject>())) 1.1035 + return Proxy::objectClassIs(obj, classValue, cx); 1.1036 + 1.1037 + switch (classValue) { 1.1038 + case ESClass_Array: return obj->is<ArrayObject>(); 1.1039 + case ESClass_Number: return obj->is<NumberObject>(); 1.1040 + case ESClass_String: return obj->is<StringObject>(); 1.1041 + case ESClass_Boolean: return obj->is<BooleanObject>(); 1.1042 + case ESClass_RegExp: return obj->is<RegExpObject>(); 1.1043 + case ESClass_ArrayBuffer: 1.1044 + return obj->is<ArrayBufferObject>() || obj->is<SharedArrayBufferObject>(); 1.1045 + case ESClass_Date: return obj->is<DateObject>(); 1.1046 + } 1.1047 + MOZ_ASSUME_UNREACHABLE("bad classValue"); 1.1048 +} 1.1049 + 1.1050 +inline bool 1.1051 +IsObjectWithClass(const Value &v, ESClassValue classValue, JSContext *cx) 1.1052 +{ 1.1053 + if (!v.isObject()) 1.1054 + return false; 1.1055 + RootedObject obj(cx, &v.toObject()); 1.1056 + return ObjectClassIs(obj, classValue, cx); 1.1057 +} 1.1058 + 1.1059 +static MOZ_ALWAYS_INLINE bool 1.1060 +NewObjectMetadata(ExclusiveContext *cxArg, JSObject **pmetadata) 1.1061 +{ 1.1062 + // The metadata callback is invoked before each created object, except when 1.1063 + // analysis/compilation is active, to avoid recursion. 1.1064 + JS_ASSERT(!*pmetadata); 1.1065 + if (JSContext *cx = cxArg->maybeJSContext()) { 1.1066 + if (MOZ_UNLIKELY((size_t)cx->compartment()->hasObjectMetadataCallback()) && 1.1067 + !cx->compartment()->activeAnalysis) 1.1068 + { 1.1069 + // Use AutoEnterAnalysis to prohibit both any GC activity under the 1.1070 + // callback, and any reentering of JS via Invoke() etc. 1.1071 + types::AutoEnterAnalysis enter(cx); 1.1072 + 1.1073 + if (!cx->compartment()->callObjectMetadataCallback(cx, pmetadata)) 1.1074 + return false; 1.1075 + } 1.1076 + } 1.1077 + return true; 1.1078 +} 1.1079 + 1.1080 +inline bool 1.1081 +DefineNativeProperty(ExclusiveContext *cx, HandleObject obj, PropertyName *name, HandleValue value, 1.1082 + PropertyOp getter, StrictPropertyOp setter, unsigned attrs) 1.1083 +{ 1.1084 + Rooted<jsid> id(cx, NameToId(name)); 1.1085 + return DefineNativeProperty(cx, obj, id, value, getter, setter, attrs); 1.1086 +} 1.1087 + 1.1088 +namespace baseops { 1.1089 + 1.1090 +inline bool 1.1091 +LookupProperty(ExclusiveContext *cx, HandleObject obj, PropertyName *name, 1.1092 + MutableHandleObject objp, MutableHandleShape propp) 1.1093 +{ 1.1094 + Rooted<jsid> id(cx, NameToId(name)); 1.1095 + return LookupProperty<CanGC>(cx, obj, id, objp, propp); 1.1096 +} 1.1097 + 1.1098 +inline bool 1.1099 +DefineProperty(ExclusiveContext *cx, HandleObject obj, PropertyName *name, HandleValue value, 1.1100 + JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) 1.1101 +{ 1.1102 + Rooted<jsid> id(cx, NameToId(name)); 1.1103 + return DefineGeneric(cx, obj, id, value, getter, setter, attrs); 1.1104 +} 1.1105 + 1.1106 +} /* namespace baseops */ 1.1107 + 1.1108 +} /* namespace js */ 1.1109 + 1.1110 +extern JSObject * 1.1111 +js_InitClass(JSContext *cx, js::HandleObject obj, JSObject *parent_proto, 1.1112 + const js::Class *clasp, JSNative constructor, unsigned nargs, 1.1113 + const JSPropertySpec *ps, const JSFunctionSpec *fs, 1.1114 + const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs, 1.1115 + JSObject **ctorp = nullptr, 1.1116 + js::gc::AllocKind ctorKind = JSFunction::FinalizeKind); 1.1117 + 1.1118 +#endif /* jsobjinlines_h */