js/src/vm/ObjectImpl.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef vm_ObjectImpl_h
michael@0 8 #define vm_ObjectImpl_h
michael@0 9
michael@0 10 #include "mozilla/Assertions.h"
michael@0 11 #include "mozilla/Attributes.h"
michael@0 12
michael@0 13 #include <stdint.h>
michael@0 14
michael@0 15 #include "jsfriendapi.h"
michael@0 16 #include "jsinfer.h"
michael@0 17 #include "NamespaceImports.h"
michael@0 18
michael@0 19 #include "gc/Barrier.h"
michael@0 20 #include "gc/Heap.h"
michael@0 21 #include "gc/Marking.h"
michael@0 22 #include "js/Value.h"
michael@0 23 #include "vm/NumericConversions.h"
michael@0 24 #include "vm/Shape.h"
michael@0 25 #include "vm/String.h"
michael@0 26
michael@0 27 namespace js {
michael@0 28
michael@0 29 class ObjectImpl;
michael@0 30 class Nursery;
michael@0 31 class Shape;
michael@0 32
michael@0 33 /*
michael@0 34 * To really poison a set of values, using 'magic' or 'undefined' isn't good
michael@0 35 * enough since often these will just be ignored by buggy code (see bug 629974)
michael@0 36 * in debug builds and crash in release builds. Instead, we use a safe-for-crash
michael@0 37 * pointer.
michael@0 38 */
michael@0 39 static MOZ_ALWAYS_INLINE void
michael@0 40 Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end)
michael@0 41 {
michael@0 42 #ifdef DEBUG
michael@0 43 for (Value *v = beg; v != end; ++v)
michael@0 44 v->setObject(*reinterpret_cast<JSObject *>(0x42));
michael@0 45 #endif
michael@0 46 }
michael@0 47
michael@0 48 static MOZ_ALWAYS_INLINE void
michael@0 49 Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len)
michael@0 50 {
michael@0 51 #ifdef DEBUG
michael@0 52 Debug_SetValueRangeToCrashOnTouch(vec, vec + len);
michael@0 53 #endif
michael@0 54 }
michael@0 55
michael@0 56 static MOZ_ALWAYS_INLINE void
michael@0 57 Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len)
michael@0 58 {
michael@0 59 #ifdef DEBUG
michael@0 60 Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
michael@0 61 #endif
michael@0 62 }
michael@0 63
michael@0 64 static MOZ_ALWAYS_INLINE void
michael@0 65 Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, uint32_t len)
michael@0 66 {
michael@0 67 #ifdef DEBUG
michael@0 68 Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
michael@0 69 #endif
michael@0 70 }
michael@0 71
michael@0 72 static MOZ_ALWAYS_INLINE void
michael@0 73 Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end)
michael@0 74 {
michael@0 75 #ifdef DEBUG
michael@0 76 Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin);
michael@0 77 #endif
michael@0 78 }
michael@0 79
michael@0 80 class ArrayObject;
michael@0 81
michael@0 82 /*
michael@0 83 * ES6 20130308 draft 8.4.2.4 ArraySetLength.
michael@0 84 *
michael@0 85 * |id| must be "length", |attrs| are the attributes to be used for the newly-
michael@0 86 * changed length property, |value| is the value for the new length, and
michael@0 87 * |setterIsStrict| indicates whether invalid changes will cause a TypeError
michael@0 88 * to be thrown.
michael@0 89 */
michael@0 90 template <ExecutionMode mode>
michael@0 91 extern bool
michael@0 92 ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
michael@0 93 Handle<ArrayObject*> obj, HandleId id,
michael@0 94 unsigned attrs, HandleValue value, bool setterIsStrict);
michael@0 95
michael@0 96 /*
michael@0 97 * Elements header used for all objects. The elements component of such objects
michael@0 98 * offers an efficient representation for all or some of the indexed properties
michael@0 99 * of the object, using a flat array of Values rather than a shape hierarchy
michael@0 100 * stored in the object's slots. This structure is immediately followed by an
michael@0 101 * array of elements, with the elements member in an object pointing to the
michael@0 102 * beginning of that array (the end of this structure).
michael@0 103 * See below for usage of this structure.
michael@0 104 *
michael@0 105 * The sets of properties represented by an object's elements and slots
michael@0 106 * are disjoint. The elements contain only indexed properties, while the slots
michael@0 107 * can contain both named and indexed properties; any indexes in the slots are
michael@0 108 * distinct from those in the elements. If isIndexed() is false for an object,
michael@0 109 * all indexed properties (if any) are stored in the dense elements.
michael@0 110 *
michael@0 111 * Indexes will be stored in the object's slots instead of its elements in
michael@0 112 * the following case:
michael@0 113 * - there are more than MIN_SPARSE_INDEX slots total and the load factor
michael@0 114 * (COUNT / capacity) is less than 0.25
michael@0 115 * - a property is defined that has non-default property attributes.
michael@0 116 *
michael@0 117 * We track these pieces of metadata for dense elements:
michael@0 118 * - The length property as a uint32_t, accessible for array objects with
michael@0 119 * ArrayObject::{length,setLength}(). This is unused for non-arrays.
michael@0 120 * - The number of element slots (capacity), gettable with
michael@0 121 * getDenseElementsCapacity().
michael@0 122 * - The array's initialized length, accessible with
michael@0 123 * getDenseElementsInitializedLength().
michael@0 124 *
michael@0 125 * Holes in the array are represented by MagicValue(JS_ELEMENTS_HOLE) values.
michael@0 126 * These indicate indexes which are not dense properties of the array. The
michael@0 127 * property may, however, be held by the object's properties.
michael@0 128 *
michael@0 129 * The capacity and length of an object's elements are almost entirely
michael@0 130 * unrelated! In general the length may be greater than, less than, or equal
michael@0 131 * to the capacity. The first case occurs with |new Array(100)|. The length
michael@0 132 * is 100, but the capacity remains 0 (indices below length and above capacity
michael@0 133 * must be treated as holes) until elements between capacity and length are
michael@0 134 * set. The other two cases are common, depending upon the number of elements
michael@0 135 * in an array and the underlying allocator used for element storage.
michael@0 136 *
michael@0 137 * The only case in which the capacity and length of an object's elements are
michael@0 138 * related is when the object is an array with non-writable length. In this
michael@0 139 * case the capacity is always less than or equal to the length. This permits
michael@0 140 * JIT code to optimize away the check for non-writable length when assigning
michael@0 141 * to possibly out-of-range elements: such code already has to check for
michael@0 142 * |index < capacity|, and fallback code checks for non-writable length.
michael@0 143 *
michael@0 144 * The initialized length of an object specifies the number of elements that
michael@0 145 * have been initialized. All elements above the initialized length are
michael@0 146 * holes in the object, and the memory for all elements between the initialized
michael@0 147 * length and capacity is left uninitialized. The initialized length is some
michael@0 148 * value less than or equal to both the object's length and the object's
michael@0 149 * capacity.
michael@0 150 *
michael@0 151 * There is flexibility in exactly the value the initialized length must hold,
michael@0 152 * e.g. if an array has length 5, capacity 10, completely empty, it is valid
michael@0 153 * for the initialized length to be any value between zero and 5, as long as
michael@0 154 * the in memory values below the initialized length have been initialized with
michael@0 155 * a hole value. However, in such cases we want to keep the initialized length
michael@0 156 * as small as possible: if the object is known to have no hole values below
michael@0 157 * its initialized length, then it is "packed" and can be accessed much faster
michael@0 158 * by JIT code.
michael@0 159 *
michael@0 160 * Elements do not track property creation order, so enumerating the elements
michael@0 161 * of an object does not necessarily visit indexes in the order they were
michael@0 162 * created.
michael@0 163 */
michael@0 164 class ObjectElements
michael@0 165 {
michael@0 166 public:
michael@0 167 enum Flags {
michael@0 168 CONVERT_DOUBLE_ELEMENTS = 0x1,
michael@0 169
michael@0 170 // Present only if these elements correspond to an array with
michael@0 171 // non-writable length; never present for non-arrays.
michael@0 172 NONWRITABLE_ARRAY_LENGTH = 0x2
michael@0 173 };
michael@0 174
michael@0 175 private:
michael@0 176 friend class ::JSObject;
michael@0 177 friend class ObjectImpl;
michael@0 178 friend class ArrayObject;
michael@0 179 friend class Nursery;
michael@0 180
michael@0 181 template <ExecutionMode mode>
michael@0 182 friend bool
michael@0 183 ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
michael@0 184 Handle<ArrayObject*> obj, HandleId id,
michael@0 185 unsigned attrs, HandleValue value, bool setterIsStrict);
michael@0 186
michael@0 187 /* See Flags enum above. */
michael@0 188 uint32_t flags;
michael@0 189
michael@0 190 /*
michael@0 191 * Number of initialized elements. This is <= the capacity, and for arrays
michael@0 192 * is <= the length. Memory for elements above the initialized length is
michael@0 193 * uninitialized, but values between the initialized length and the proper
michael@0 194 * length are conceptually holes.
michael@0 195 */
michael@0 196 uint32_t initializedLength;
michael@0 197
michael@0 198 /* Number of allocated slots. */
michael@0 199 uint32_t capacity;
michael@0 200
michael@0 201 /* 'length' property of array objects, unused for other objects. */
michael@0 202 uint32_t length;
michael@0 203
michael@0 204 void staticAsserts() {
michael@0 205 static_assert(sizeof(ObjectElements) == VALUES_PER_HEADER * sizeof(Value),
michael@0 206 "Elements size and values-per-Elements mismatch");
michael@0 207 }
michael@0 208
michael@0 209 bool shouldConvertDoubleElements() const {
michael@0 210 return flags & CONVERT_DOUBLE_ELEMENTS;
michael@0 211 }
michael@0 212 void setShouldConvertDoubleElements() {
michael@0 213 flags |= CONVERT_DOUBLE_ELEMENTS;
michael@0 214 }
michael@0 215 void clearShouldConvertDoubleElements() {
michael@0 216 flags &= ~CONVERT_DOUBLE_ELEMENTS;
michael@0 217 }
michael@0 218 bool hasNonwritableArrayLength() const {
michael@0 219 return flags & NONWRITABLE_ARRAY_LENGTH;
michael@0 220 }
michael@0 221 void setNonwritableArrayLength() {
michael@0 222 flags |= NONWRITABLE_ARRAY_LENGTH;
michael@0 223 }
michael@0 224
michael@0 225 public:
michael@0 226 MOZ_CONSTEXPR ObjectElements(uint32_t capacity, uint32_t length)
michael@0 227 : flags(0), initializedLength(0), capacity(capacity), length(length)
michael@0 228 {}
michael@0 229
michael@0 230 HeapSlot *elements() {
michael@0 231 return reinterpret_cast<HeapSlot*>(uintptr_t(this) + sizeof(ObjectElements));
michael@0 232 }
michael@0 233 static ObjectElements * fromElements(HeapSlot *elems) {
michael@0 234 return reinterpret_cast<ObjectElements*>(uintptr_t(elems) - sizeof(ObjectElements));
michael@0 235 }
michael@0 236
michael@0 237 static int offsetOfFlags() {
michael@0 238 return int(offsetof(ObjectElements, flags)) - int(sizeof(ObjectElements));
michael@0 239 }
michael@0 240 static int offsetOfInitializedLength() {
michael@0 241 return int(offsetof(ObjectElements, initializedLength)) - int(sizeof(ObjectElements));
michael@0 242 }
michael@0 243 static int offsetOfCapacity() {
michael@0 244 return int(offsetof(ObjectElements, capacity)) - int(sizeof(ObjectElements));
michael@0 245 }
michael@0 246 static int offsetOfLength() {
michael@0 247 return int(offsetof(ObjectElements, length)) - int(sizeof(ObjectElements));
michael@0 248 }
michael@0 249
michael@0 250 static bool ConvertElementsToDoubles(JSContext *cx, uintptr_t elements);
michael@0 251
michael@0 252 static const size_t VALUES_PER_HEADER = 2;
michael@0 253 };
michael@0 254
michael@0 255 /* Shared singleton for objects with no elements. */
michael@0 256 extern HeapSlot *const emptyObjectElements;
michael@0 257
michael@0 258 struct Class;
michael@0 259 struct GCMarker;
michael@0 260 struct ObjectOps;
michael@0 261 class Shape;
michael@0 262
michael@0 263 class NewObjectCache;
michael@0 264 class TaggedProto;
michael@0 265
michael@0 266 inline Value
michael@0 267 ObjectValue(ObjectImpl &obj);
michael@0 268
michael@0 269 #ifdef DEBUG
michael@0 270 static inline bool
michael@0 271 IsObjectValueInCompartment(js::Value v, JSCompartment *comp);
michael@0 272 #endif
michael@0 273
michael@0 274 /*
michael@0 275 * ObjectImpl specifies the internal implementation of an object. (In contrast
michael@0 276 * JSObject specifies an "external" interface, at the conceptual level of that
michael@0 277 * exposed in ECMAScript.)
michael@0 278 *
michael@0 279 * The |shape_| member stores the shape of the object, which includes the
michael@0 280 * object's class and the layout of all its properties.
michael@0 281 *
michael@0 282 * The |type_| member stores the type of the object, which contains its
michael@0 283 * prototype object and the possible types of its properties.
michael@0 284 *
michael@0 285 * The rest of the object stores its named properties and indexed elements.
michael@0 286 * These are stored separately from one another. Objects are followed by a
michael@0 287 * variable-sized array of values for inline storage, which may be used by
michael@0 288 * either properties of native objects (fixed slots), by elements (fixed
michael@0 289 * elements), or by other data for certain kinds of objects, such as
michael@0 290 * ArrayBufferObjects and TypedArrayObjects.
michael@0 291 *
michael@0 292 * Two native objects with the same shape are guaranteed to have the same
michael@0 293 * number of fixed slots.
michael@0 294 *
michael@0 295 * Named property storage can be split between fixed slots and a dynamically
michael@0 296 * allocated array (the slots member). For an object with N fixed slots, shapes
michael@0 297 * with slots [0..N-1] are stored in the fixed slots, and the remainder are
michael@0 298 * stored in the dynamic array. If all properties fit in the fixed slots, the
michael@0 299 * 'slots' member is nullptr.
michael@0 300 *
michael@0 301 * Elements are indexed via the 'elements' member. This member can point to
michael@0 302 * either the shared emptyObjectElements singleton, into the inline value array
michael@0 303 * (the address of the third value, to leave room for a ObjectElements header;
michael@0 304 * in this case numFixedSlots() is zero) or to a dynamically allocated array.
michael@0 305 *
michael@0 306 * Only certain combinations of slots and elements storage are possible.
michael@0 307 *
michael@0 308 * - For native objects, slots and elements may both be non-empty. The
michael@0 309 * slots may be either names or indexes; no indexed property will be in both
michael@0 310 * the slots and elements.
michael@0 311 *
michael@0 312 * - For non-native objects, slots and elements are both empty.
michael@0 313 *
michael@0 314 * The members of this class are currently protected; in the long run this will
michael@0 315 * will change so that some members are private, and only certain methods that
michael@0 316 * act upon them will be protected.
michael@0 317 */
michael@0 318 class ObjectImpl : public gc::BarrieredCell<ObjectImpl>
michael@0 319 {
michael@0 320 friend Zone *js::gc::BarrieredCell<ObjectImpl>::zone() const;
michael@0 321 friend Zone *js::gc::BarrieredCell<ObjectImpl>::zoneFromAnyThread() const;
michael@0 322
michael@0 323 protected:
michael@0 324 /*
michael@0 325 * Shape of the object, encodes the layout of the object's properties and
michael@0 326 * all other information about its structure. See vm/Shape.h.
michael@0 327 */
michael@0 328 HeapPtrShape shape_;
michael@0 329
michael@0 330 /*
michael@0 331 * The object's type and prototype. For objects with the LAZY_TYPE flag
michael@0 332 * set, this is the prototype's default 'new' type and can only be used
michael@0 333 * to get that prototype.
michael@0 334 */
michael@0 335 HeapPtrTypeObject type_;
michael@0 336
michael@0 337 HeapSlot *slots; /* Slots for object properties. */
michael@0 338 HeapSlot *elements; /* Slots for object elements. */
michael@0 339
michael@0 340 friend bool
michael@0 341 ArraySetLength(JSContext *cx, Handle<ArrayObject*> obj, HandleId id, unsigned attrs,
michael@0 342 HandleValue value, bool setterIsStrict);
michael@0 343
michael@0 344 private:
michael@0 345 static void staticAsserts() {
michael@0 346 static_assert(sizeof(ObjectImpl) == sizeof(shadow::Object),
michael@0 347 "shadow interface must match actual implementation");
michael@0 348 static_assert(sizeof(ObjectImpl) % sizeof(Value) == 0,
michael@0 349 "fixed slots after an object must be aligned");
michael@0 350
michael@0 351 static_assert(offsetof(ObjectImpl, shape_) == offsetof(shadow::Object, shape),
michael@0 352 "shadow shape must match actual shape");
michael@0 353 static_assert(offsetof(ObjectImpl, type_) == offsetof(shadow::Object, type),
michael@0 354 "shadow type must match actual type");
michael@0 355 static_assert(offsetof(ObjectImpl, slots) == offsetof(shadow::Object, slots),
michael@0 356 "shadow slots must match actual slots");
michael@0 357 static_assert(offsetof(ObjectImpl, elements) == offsetof(shadow::Object, _1),
michael@0 358 "shadow placeholder must match actual elements");
michael@0 359 }
michael@0 360
michael@0 361 JSObject * asObjectPtr() { return reinterpret_cast<JSObject *>(this); }
michael@0 362 const JSObject * asObjectPtr() const { return reinterpret_cast<const JSObject *>(this); }
michael@0 363
michael@0 364 friend inline Value ObjectValue(ObjectImpl &obj);
michael@0 365
michael@0 366 /* These functions are public, and they should remain public. */
michael@0 367
michael@0 368 public:
michael@0 369 TaggedProto getTaggedProto() const {
michael@0 370 return type_->proto();
michael@0 371 }
michael@0 372
michael@0 373 bool hasTenuredProto() const;
michael@0 374
michael@0 375 const Class *getClass() const {
michael@0 376 return type_->clasp();
michael@0 377 }
michael@0 378
michael@0 379 static inline bool
michael@0 380 isExtensible(ExclusiveContext *cx, Handle<ObjectImpl*> obj, bool *extensible);
michael@0 381
michael@0 382 // Indicates whether a non-proxy is extensible. Don't call on proxies!
michael@0 383 // This method really shouldn't exist -- but there are a few internal
michael@0 384 // places that want it (JITs and the like), and it'd be a pain to mark them
michael@0 385 // all as friends.
michael@0 386 bool nonProxyIsExtensible() const {
michael@0 387 MOZ_ASSERT(!isProxy());
michael@0 388
michael@0 389 // [[Extensible]] for ordinary non-proxy objects is an object flag.
michael@0 390 return !lastProperty()->hasObjectFlag(BaseShape::NOT_EXTENSIBLE);
michael@0 391 }
michael@0 392
michael@0 393 #ifdef DEBUG
michael@0 394 bool isProxy() const;
michael@0 395 #endif
michael@0 396
michael@0 397 // Attempt to change the [[Extensible]] bit on |obj| to false. Callers
michael@0 398 // must ensure that |obj| is currently extensible before calling this!
michael@0 399 static bool
michael@0 400 preventExtensions(JSContext *cx, Handle<ObjectImpl*> obj);
michael@0 401
michael@0 402 HeapSlotArray getDenseElements() {
michael@0 403 JS_ASSERT(isNative());
michael@0 404 return HeapSlotArray(elements);
michael@0 405 }
michael@0 406 const Value &getDenseElement(uint32_t idx) {
michael@0 407 JS_ASSERT(isNative());
michael@0 408 MOZ_ASSERT(idx < getDenseInitializedLength());
michael@0 409 return elements[idx];
michael@0 410 }
michael@0 411 bool containsDenseElement(uint32_t idx) {
michael@0 412 JS_ASSERT(isNative());
michael@0 413 return idx < getDenseInitializedLength() && !elements[idx].isMagic(JS_ELEMENTS_HOLE);
michael@0 414 }
michael@0 415 uint32_t getDenseInitializedLength() {
michael@0 416 JS_ASSERT(getClass()->isNative());
michael@0 417 return getElementsHeader()->initializedLength;
michael@0 418 }
michael@0 419 uint32_t getDenseCapacity() {
michael@0 420 JS_ASSERT(getClass()->isNative());
michael@0 421 return getElementsHeader()->capacity;
michael@0 422 }
michael@0 423
michael@0 424 protected:
michael@0 425 #ifdef DEBUG
michael@0 426 void checkShapeConsistency();
michael@0 427 #else
michael@0 428 void checkShapeConsistency() { }
michael@0 429 #endif
michael@0 430
michael@0 431 Shape *
michael@0 432 replaceWithNewEquivalentShape(ThreadSafeContext *cx,
michael@0 433 Shape *existingShape, Shape *newShape = nullptr);
michael@0 434
michael@0 435 enum GenerateShape {
michael@0 436 GENERATE_NONE,
michael@0 437 GENERATE_SHAPE
michael@0 438 };
michael@0 439
michael@0 440 bool setFlag(ExclusiveContext *cx, /*BaseShape::Flag*/ uint32_t flag,
michael@0 441 GenerateShape generateShape = GENERATE_NONE);
michael@0 442 bool clearFlag(ExclusiveContext *cx, /*BaseShape::Flag*/ uint32_t flag);
michael@0 443
michael@0 444 bool toDictionaryMode(ThreadSafeContext *cx);
michael@0 445
michael@0 446 private:
michael@0 447 friend class Nursery;
michael@0 448
michael@0 449 /*
michael@0 450 * Get internal pointers to the range of values starting at start and
michael@0 451 * running for length.
michael@0 452 */
michael@0 453 void getSlotRangeUnchecked(uint32_t start, uint32_t length,
michael@0 454 HeapSlot **fixedStart, HeapSlot **fixedEnd,
michael@0 455 HeapSlot **slotsStart, HeapSlot **slotsEnd)
michael@0 456 {
michael@0 457 MOZ_ASSERT(start + length >= start);
michael@0 458
michael@0 459 uint32_t fixed = numFixedSlots();
michael@0 460 if (start < fixed) {
michael@0 461 if (start + length < fixed) {
michael@0 462 *fixedStart = &fixedSlots()[start];
michael@0 463 *fixedEnd = &fixedSlots()[start + length];
michael@0 464 *slotsStart = *slotsEnd = nullptr;
michael@0 465 } else {
michael@0 466 uint32_t localCopy = fixed - start;
michael@0 467 *fixedStart = &fixedSlots()[start];
michael@0 468 *fixedEnd = &fixedSlots()[start + localCopy];
michael@0 469 *slotsStart = &slots[0];
michael@0 470 *slotsEnd = &slots[length - localCopy];
michael@0 471 }
michael@0 472 } else {
michael@0 473 *fixedStart = *fixedEnd = nullptr;
michael@0 474 *slotsStart = &slots[start - fixed];
michael@0 475 *slotsEnd = &slots[start - fixed + length];
michael@0 476 }
michael@0 477 }
michael@0 478
michael@0 479 void getSlotRange(uint32_t start, uint32_t length,
michael@0 480 HeapSlot **fixedStart, HeapSlot **fixedEnd,
michael@0 481 HeapSlot **slotsStart, HeapSlot **slotsEnd)
michael@0 482 {
michael@0 483 MOZ_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED));
michael@0 484 getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd);
michael@0 485 }
michael@0 486
michael@0 487 protected:
michael@0 488 friend struct GCMarker;
michael@0 489 friend class Shape;
michael@0 490 friend class NewObjectCache;
michael@0 491
michael@0 492 void invalidateSlotRange(uint32_t start, uint32_t length) {
michael@0 493 #ifdef DEBUG
michael@0 494 HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
michael@0 495 getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
michael@0 496 Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd);
michael@0 497 Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd);
michael@0 498 #endif /* DEBUG */
michael@0 499 }
michael@0 500
michael@0 501 void initializeSlotRange(uint32_t start, uint32_t count);
michael@0 502
michael@0 503 /*
michael@0 504 * Initialize a flat array of slots to this object at a start slot. The
michael@0 505 * caller must ensure that are enough slots.
michael@0 506 */
michael@0 507 void initSlotRange(uint32_t start, const Value *vector, uint32_t length);
michael@0 508
michael@0 509 /*
michael@0 510 * Copy a flat array of slots to this object at a start slot. Caller must
michael@0 511 * ensure there are enough slots in this object.
michael@0 512 */
michael@0 513 void copySlotRange(uint32_t start, const Value *vector, uint32_t length);
michael@0 514
michael@0 515 #ifdef DEBUG
michael@0 516 enum SentinelAllowed {
michael@0 517 SENTINEL_NOT_ALLOWED,
michael@0 518 SENTINEL_ALLOWED
michael@0 519 };
michael@0 520
michael@0 521 /*
michael@0 522 * Check that slot is in range for the object's allocated slots.
michael@0 523 * If sentinelAllowed then slot may equal the slot capacity.
michael@0 524 */
michael@0 525 bool slotInRange(uint32_t slot, SentinelAllowed sentinel = SENTINEL_NOT_ALLOWED) const;
michael@0 526 #endif
michael@0 527
michael@0 528 /*
michael@0 529 * Minimum size for dynamically allocated slots in normal Objects.
michael@0 530 * ArrayObjects don't use this limit and can have a lower slot capacity,
michael@0 531 * since they normally don't have a lot of slots.
michael@0 532 */
michael@0 533 static const uint32_t SLOT_CAPACITY_MIN = 8;
michael@0 534
michael@0 535 HeapSlot *fixedSlots() const {
michael@0 536 return reinterpret_cast<HeapSlot *>(uintptr_t(this) + sizeof(ObjectImpl));
michael@0 537 }
michael@0 538
michael@0 539 /*
michael@0 540 * These functions are currently public for simplicity; in the long run
michael@0 541 * it may make sense to make at least some of them private.
michael@0 542 */
michael@0 543
michael@0 544 public:
michael@0 545 Shape * lastProperty() const {
michael@0 546 MOZ_ASSERT(shape_);
michael@0 547 return shape_;
michael@0 548 }
michael@0 549
michael@0 550 bool generateOwnShape(ThreadSafeContext *cx, js::Shape *newShape = nullptr) {
michael@0 551 return replaceWithNewEquivalentShape(cx, lastProperty(), newShape);
michael@0 552 }
michael@0 553
michael@0 554 JSCompartment *compartment() const {
michael@0 555 return lastProperty()->base()->compartment();
michael@0 556 }
michael@0 557
michael@0 558 bool isNative() const {
michael@0 559 return lastProperty()->isNative();
michael@0 560 }
michael@0 561
michael@0 562 types::TypeObject *type() const {
michael@0 563 MOZ_ASSERT(!hasLazyType());
michael@0 564 return typeRaw();
michael@0 565 }
michael@0 566
michael@0 567 types::TypeObject *typeRaw() const {
michael@0 568 return type_;
michael@0 569 }
michael@0 570
michael@0 571 uint32_t numFixedSlots() const {
michael@0 572 return reinterpret_cast<const shadow::Object *>(this)->numFixedSlots();
michael@0 573 }
michael@0 574
michael@0 575 /*
michael@0 576 * Whether this is the only object which has its specified type. This
michael@0 577 * object will have its type constructed lazily as needed by analysis.
michael@0 578 */
michael@0 579 bool hasSingletonType() const {
michael@0 580 return !!type_->singleton();
michael@0 581 }
michael@0 582
michael@0 583 /*
michael@0 584 * Whether the object's type has not been constructed yet. If an object
michael@0 585 * might have a lazy type, use getType() below, otherwise type().
michael@0 586 */
michael@0 587 bool hasLazyType() const {
michael@0 588 return type_->lazy();
michael@0 589 }
michael@0 590
michael@0 591 uint32_t slotSpan() const {
michael@0 592 if (inDictionaryMode())
michael@0 593 return lastProperty()->base()->slotSpan();
michael@0 594 return lastProperty()->slotSpan();
michael@0 595 }
michael@0 596
michael@0 597 /* Compute dynamicSlotsCount() for this object. */
michael@0 598 uint32_t numDynamicSlots() const {
michael@0 599 return dynamicSlotsCount(numFixedSlots(), slotSpan(), getClass());
michael@0 600 }
michael@0 601
michael@0 602
michael@0 603 Shape *nativeLookup(ExclusiveContext *cx, jsid id);
michael@0 604 Shape *nativeLookup(ExclusiveContext *cx, PropertyName *name) {
michael@0 605 return nativeLookup(cx, NameToId(name));
michael@0 606 }
michael@0 607
michael@0 608 bool nativeContains(ExclusiveContext *cx, jsid id) {
michael@0 609 return nativeLookup(cx, id) != nullptr;
michael@0 610 }
michael@0 611 bool nativeContains(ExclusiveContext *cx, PropertyName* name) {
michael@0 612 return nativeLookup(cx, name) != nullptr;
michael@0 613 }
michael@0 614 bool nativeContains(ExclusiveContext *cx, Shape* shape) {
michael@0 615 return nativeLookup(cx, shape->propid()) == shape;
michael@0 616 }
michael@0 617
michael@0 618 /* Contextless; can be called from parallel code. */
michael@0 619 Shape *nativeLookupPure(jsid id);
michael@0 620 Shape *nativeLookupPure(PropertyName *name) {
michael@0 621 return nativeLookupPure(NameToId(name));
michael@0 622 }
michael@0 623
michael@0 624 bool nativeContainsPure(jsid id) {
michael@0 625 return nativeLookupPure(id) != nullptr;
michael@0 626 }
michael@0 627 bool nativeContainsPure(PropertyName* name) {
michael@0 628 return nativeContainsPure(NameToId(name));
michael@0 629 }
michael@0 630 bool nativeContainsPure(Shape* shape) {
michael@0 631 return nativeLookupPure(shape->propid()) == shape;
michael@0 632 }
michael@0 633
michael@0 634 const JSClass *getJSClass() const {
michael@0 635 return Jsvalify(getClass());
michael@0 636 }
michael@0 637 bool hasClass(const Class *c) const {
michael@0 638 return getClass() == c;
michael@0 639 }
michael@0 640 const ObjectOps *getOps() const {
michael@0 641 return &getClass()->ops;
michael@0 642 }
michael@0 643
michael@0 644 /*
michael@0 645 * An object is a delegate if it is on another object's prototype or scope
michael@0 646 * chain, and therefore the delegate might be asked implicitly to get or
michael@0 647 * set a property on behalf of another object. Delegates may be accessed
michael@0 648 * directly too, as may any object, but only those objects linked after the
michael@0 649 * head of any prototype or scope chain are flagged as delegates. This
michael@0 650 * definition helps to optimize shape-based property cache invalidation
michael@0 651 * (see Purge{Scope,Proto}Chain in jsobj.cpp).
michael@0 652 */
michael@0 653 bool isDelegate() const {
michael@0 654 return lastProperty()->hasObjectFlag(BaseShape::DELEGATE);
michael@0 655 }
michael@0 656
michael@0 657 /*
michael@0 658 * Return true if this object is a native one that has been converted from
michael@0 659 * shared-immutable prototype-rooted shape storage to dictionary-shapes in
michael@0 660 * a doubly-linked list.
michael@0 661 */
michael@0 662 bool inDictionaryMode() const {
michael@0 663 return lastProperty()->inDictionary();
michael@0 664 }
michael@0 665
michael@0 666 const Value &getSlot(uint32_t slot) const {
michael@0 667 MOZ_ASSERT(slotInRange(slot));
michael@0 668 uint32_t fixed = numFixedSlots();
michael@0 669 if (slot < fixed)
michael@0 670 return fixedSlots()[slot];
michael@0 671 return slots[slot - fixed];
michael@0 672 }
michael@0 673
michael@0 674 const HeapSlot *getSlotAddressUnchecked(uint32_t slot) const {
michael@0 675 uint32_t fixed = numFixedSlots();
michael@0 676 if (slot < fixed)
michael@0 677 return fixedSlots() + slot;
michael@0 678 return slots + (slot - fixed);
michael@0 679 }
michael@0 680
michael@0 681 HeapSlot *getSlotAddressUnchecked(uint32_t slot) {
michael@0 682 const ObjectImpl *obj = static_cast<const ObjectImpl*>(this);
michael@0 683 return const_cast<HeapSlot*>(obj->getSlotAddressUnchecked(slot));
michael@0 684 }
michael@0 685
michael@0 686 HeapSlot *getSlotAddress(uint32_t slot) {
michael@0 687 /*
michael@0 688 * This can be used to get the address of the end of the slots for the
michael@0 689 * object, which may be necessary when fetching zero-length arrays of
michael@0 690 * slots (e.g. for callObjVarArray).
michael@0 691 */
michael@0 692 MOZ_ASSERT(slotInRange(slot, SENTINEL_ALLOWED));
michael@0 693 return getSlotAddressUnchecked(slot);
michael@0 694 }
michael@0 695
michael@0 696 const HeapSlot *getSlotAddress(uint32_t slot) const {
michael@0 697 /*
michael@0 698 * This can be used to get the address of the end of the slots for the
michael@0 699 * object, which may be necessary when fetching zero-length arrays of
michael@0 700 * slots (e.g. for callObjVarArray).
michael@0 701 */
michael@0 702 MOZ_ASSERT(slotInRange(slot, SENTINEL_ALLOWED));
michael@0 703 return getSlotAddressUnchecked(slot);
michael@0 704 }
michael@0 705
michael@0 706 HeapSlot &getSlotRef(uint32_t slot) {
michael@0 707 MOZ_ASSERT(slotInRange(slot));
michael@0 708 return *getSlotAddress(slot);
michael@0 709 }
michael@0 710
michael@0 711 const HeapSlot &getSlotRef(uint32_t slot) const {
michael@0 712 MOZ_ASSERT(slotInRange(slot));
michael@0 713 return *getSlotAddress(slot);
michael@0 714 }
michael@0 715
michael@0 716 HeapSlot &nativeGetSlotRef(uint32_t slot) {
michael@0 717 JS_ASSERT(isNative() && slot < slotSpan());
michael@0 718 return getSlotRef(slot);
michael@0 719 }
michael@0 720 const Value &nativeGetSlot(uint32_t slot) const {
michael@0 721 JS_ASSERT(isNative() && slot < slotSpan());
michael@0 722 return getSlot(slot);
michael@0 723 }
michael@0 724
michael@0 725 void setSlot(uint32_t slot, const Value &value) {
michael@0 726 MOZ_ASSERT(slotInRange(slot));
michael@0 727 MOZ_ASSERT(IsObjectValueInCompartment(value, compartment()));
michael@0 728 getSlotRef(slot).set(this->asObjectPtr(), HeapSlot::Slot, slot, value);
michael@0 729 }
michael@0 730
michael@0 731 inline void setCrossCompartmentSlot(uint32_t slot, const Value &value) {
michael@0 732 MOZ_ASSERT(slotInRange(slot));
michael@0 733 getSlotRef(slot).set(this->asObjectPtr(), HeapSlot::Slot, slot, value);
michael@0 734 }
michael@0 735
michael@0 736 void initSlot(uint32_t slot, const Value &value) {
michael@0 737 MOZ_ASSERT(getSlot(slot).isUndefined());
michael@0 738 MOZ_ASSERT(slotInRange(slot));
michael@0 739 MOZ_ASSERT(IsObjectValueInCompartment(value, compartment()));
michael@0 740 initSlotUnchecked(slot, value);
michael@0 741 }
michael@0 742
michael@0 743 void initCrossCompartmentSlot(uint32_t slot, const Value &value) {
michael@0 744 MOZ_ASSERT(getSlot(slot).isUndefined());
michael@0 745 MOZ_ASSERT(slotInRange(slot));
michael@0 746 initSlotUnchecked(slot, value);
michael@0 747 }
michael@0 748
michael@0 749 void initSlotUnchecked(uint32_t slot, const Value &value) {
michael@0 750 getSlotAddressUnchecked(slot)->init(this->asObjectPtr(), HeapSlot::Slot, slot, value);
michael@0 751 }
michael@0 752
michael@0 753 /* For slots which are known to always be fixed, due to the way they are allocated. */
michael@0 754
michael@0 755 HeapSlot &getFixedSlotRef(uint32_t slot) {
michael@0 756 MOZ_ASSERT(slot < numFixedSlots());
michael@0 757 return fixedSlots()[slot];
michael@0 758 }
michael@0 759
michael@0 760 const Value &getFixedSlot(uint32_t slot) const {
michael@0 761 MOZ_ASSERT(slot < numFixedSlots());
michael@0 762 return fixedSlots()[slot];
michael@0 763 }
michael@0 764
michael@0 765 void setFixedSlot(uint32_t slot, const Value &value) {
michael@0 766 MOZ_ASSERT(slot < numFixedSlots());
michael@0 767 fixedSlots()[slot].set(this->asObjectPtr(), HeapSlot::Slot, slot, value);
michael@0 768 }
michael@0 769
michael@0 770 void initFixedSlot(uint32_t slot, const Value &value) {
michael@0 771 MOZ_ASSERT(slot < numFixedSlots());
michael@0 772 fixedSlots()[slot].init(this->asObjectPtr(), HeapSlot::Slot, slot, value);
michael@0 773 }
michael@0 774
michael@0 775 /*
michael@0 776 * Get the number of dynamic slots to allocate to cover the properties in
michael@0 777 * an object with the given number of fixed slots and slot span. The slot
michael@0 778 * capacity is not stored explicitly, and the allocated size of the slot
michael@0 779 * array is kept in sync with this count.
michael@0 780 */
michael@0 781 static uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class *clasp);
michael@0 782
michael@0 783 /* Memory usage functions. */
michael@0 784 size_t tenuredSizeOfThis() const {
michael@0 785 return js::gc::Arena::thingSize(tenuredGetAllocKind());
michael@0 786 }
michael@0 787
michael@0 788 /* Elements accessors. */
michael@0 789
michael@0 790 ObjectElements * getElementsHeader() const {
michael@0 791 return ObjectElements::fromElements(elements);
michael@0 792 }
michael@0 793
michael@0 794 inline HeapSlot *fixedElements() const {
michael@0 795 static_assert(2 * sizeof(Value) == sizeof(ObjectElements),
michael@0 796 "when elements are stored inline, the first two "
michael@0 797 "slots will hold the ObjectElements header");
michael@0 798 return &fixedSlots()[2];
michael@0 799 }
michael@0 800
michael@0 801 #ifdef DEBUG
michael@0 802 bool canHaveNonEmptyElements();
michael@0 803 #endif
michael@0 804
michael@0 805 void setFixedElements() {
michael@0 806 JS_ASSERT(canHaveNonEmptyElements());
michael@0 807 this->elements = fixedElements();
michael@0 808 }
michael@0 809
michael@0 810 inline bool hasDynamicElements() const {
michael@0 811 /*
michael@0 812 * Note: for objects with zero fixed slots this could potentially give
michael@0 813 * a spurious 'true' result, if the end of this object is exactly
michael@0 814 * aligned with the end of its arena and dynamic slots are allocated
michael@0 815 * immediately afterwards. Such cases cannot occur for dense arrays
michael@0 816 * (which have at least two fixed slots) and can only result in a leak.
michael@0 817 */
michael@0 818 return !hasEmptyElements() && elements != fixedElements();
michael@0 819 }
michael@0 820
michael@0 821 inline bool hasFixedElements() const {
michael@0 822 return elements == fixedElements();
michael@0 823 }
michael@0 824
michael@0 825 inline bool hasEmptyElements() const {
michael@0 826 return elements == emptyObjectElements;
michael@0 827 }
michael@0 828
michael@0 829 /*
michael@0 830 * Get a pointer to the unused data in the object's allocation immediately
michael@0 831 * following this object, for use with objects which allocate a larger size
michael@0 832 * class than they need and store non-elements data inline.
michael@0 833 */
michael@0 834 inline void *fixedData(size_t nslots) const;
michael@0 835
michael@0 836 /* GC support. */
michael@0 837 static ThingRootKind rootKind() { return THING_ROOT_OBJECT; }
michael@0 838
michael@0 839 inline void privateWriteBarrierPre(void **oldval);
michael@0 840
michael@0 841 void privateWriteBarrierPost(void **pprivate) {
michael@0 842 #ifdef JSGC_GENERATIONAL
michael@0 843 shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putCell(reinterpret_cast<js::gc::Cell **>(pprivate));
michael@0 844 #endif
michael@0 845 }
michael@0 846
michael@0 847 void markChildren(JSTracer *trc);
michael@0 848
michael@0 849 /* Private data accessors. */
michael@0 850
michael@0 851 inline void *&privateRef(uint32_t nfixed) const { /* XXX should be private, not protected! */
michael@0 852 /*
michael@0 853 * The private pointer of an object can hold any word sized value.
michael@0 854 * Private pointers are stored immediately after the last fixed slot of
michael@0 855 * the object.
michael@0 856 */
michael@0 857 MOZ_ASSERT(nfixed == numFixedSlots());
michael@0 858 MOZ_ASSERT(hasPrivate());
michael@0 859 HeapSlot *end = &fixedSlots()[nfixed];
michael@0 860 return *reinterpret_cast<void**>(end);
michael@0 861 }
michael@0 862
michael@0 863 bool hasPrivate() const {
michael@0 864 return getClass()->hasPrivate();
michael@0 865 }
michael@0 866 void *getPrivate() const {
michael@0 867 return privateRef(numFixedSlots());
michael@0 868 }
michael@0 869 void setPrivate(void *data) {
michael@0 870 void **pprivate = &privateRef(numFixedSlots());
michael@0 871 privateWriteBarrierPre(pprivate);
michael@0 872 *pprivate = data;
michael@0 873 }
michael@0 874
michael@0 875 void setPrivateGCThing(gc::Cell *cell) {
michael@0 876 void **pprivate = &privateRef(numFixedSlots());
michael@0 877 privateWriteBarrierPre(pprivate);
michael@0 878 *pprivate = reinterpret_cast<void *>(cell);
michael@0 879 privateWriteBarrierPost(pprivate);
michael@0 880 }
michael@0 881
michael@0 882 void setPrivateUnbarriered(void *data) {
michael@0 883 void **pprivate = &privateRef(numFixedSlots());
michael@0 884 *pprivate = data;
michael@0 885 }
michael@0 886 void initPrivate(void *data) {
michael@0 887 privateRef(numFixedSlots()) = data;
michael@0 888 }
michael@0 889
michael@0 890 /* Access private data for an object with a known number of fixed slots. */
michael@0 891 inline void *getPrivate(uint32_t nfixed) const {
michael@0 892 return privateRef(nfixed);
michael@0 893 }
michael@0 894
michael@0 895 /* GC Accessors */
michael@0 896 void setInitialSlots(HeapSlot *newSlots) { slots = newSlots; }
michael@0 897
michael@0 898 /* JIT Accessors */
michael@0 899 static size_t offsetOfShape() { return offsetof(ObjectImpl, shape_); }
michael@0 900 HeapPtrShape *addressOfShape() { return &shape_; }
michael@0 901
michael@0 902 static size_t offsetOfType() { return offsetof(ObjectImpl, type_); }
michael@0 903 HeapPtrTypeObject *addressOfType() { return &type_; }
michael@0 904
michael@0 905 static size_t offsetOfElements() { return offsetof(ObjectImpl, elements); }
michael@0 906 static size_t offsetOfFixedElements() {
michael@0 907 return sizeof(ObjectImpl) + sizeof(ObjectElements);
michael@0 908 }
michael@0 909
michael@0 910 static size_t getFixedSlotOffset(size_t slot) {
michael@0 911 return sizeof(ObjectImpl) + slot * sizeof(Value);
michael@0 912 }
michael@0 913 static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); }
michael@0 914 static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); }
michael@0 915 };
michael@0 916
michael@0 917 namespace gc {
michael@0 918
michael@0 919 template <>
michael@0 920 MOZ_ALWAYS_INLINE Zone *
michael@0 921 BarrieredCell<ObjectImpl>::zone() const
michael@0 922 {
michael@0 923 const ObjectImpl* obj = static_cast<const ObjectImpl*>(this);
michael@0 924 JS::Zone *zone = obj->shape_->zone();
michael@0 925 JS_ASSERT(CurrentThreadCanAccessZone(zone));
michael@0 926 return zone;
michael@0 927 }
michael@0 928
michael@0 929 template <>
michael@0 930 MOZ_ALWAYS_INLINE Zone *
michael@0 931 BarrieredCell<ObjectImpl>::zoneFromAnyThread() const
michael@0 932 {
michael@0 933 const ObjectImpl* obj = static_cast<const ObjectImpl*>(this);
michael@0 934 return obj->shape_->zoneFromAnyThread();
michael@0 935 }
michael@0 936
michael@0 937 // TypeScript::global uses 0x1 as a special value.
michael@0 938 template<>
michael@0 939 /* static */ inline bool
michael@0 940 BarrieredCell<ObjectImpl>::isNullLike(ObjectImpl *obj)
michael@0 941 {
michael@0 942 return IsNullTaggedPointer(obj);
michael@0 943 }
michael@0 944
michael@0 945 template<>
michael@0 946 /* static */ inline void
michael@0 947 BarrieredCell<ObjectImpl>::writeBarrierPost(ObjectImpl *obj, void *addr)
michael@0 948 {
michael@0 949 #ifdef JSGC_GENERATIONAL
michael@0 950 if (IsNullTaggedPointer(obj))
michael@0 951 return;
michael@0 952 obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putCell((Cell **)addr);
michael@0 953 #endif
michael@0 954 }
michael@0 955
michael@0 956 template<>
michael@0 957 /* static */ inline void
michael@0 958 BarrieredCell<ObjectImpl>::writeBarrierPostRelocate(ObjectImpl *obj, void *addr)
michael@0 959 {
michael@0 960 #ifdef JSGC_GENERATIONAL
michael@0 961 obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->putRelocatableCell((Cell **)addr);
michael@0 962 #endif
michael@0 963 }
michael@0 964
michael@0 965 template<>
michael@0 966 /* static */ inline void
michael@0 967 BarrieredCell<ObjectImpl>::writeBarrierPostRemove(ObjectImpl *obj, void *addr)
michael@0 968 {
michael@0 969 #ifdef JSGC_GENERATIONAL
michael@0 970 obj->shadowRuntimeFromAnyThread()->gcStoreBufferPtr()->removeRelocatableCell((Cell **)addr);
michael@0 971 #endif
michael@0 972 }
michael@0 973
michael@0 974 } // namespace gc
michael@0 975
michael@0 976 inline void
michael@0 977 ObjectImpl::privateWriteBarrierPre(void **oldval)
michael@0 978 {
michael@0 979 #ifdef JSGC_INCREMENTAL
michael@0 980 JS::shadow::Zone *shadowZone = this->shadowZoneFromAnyThread();
michael@0 981 if (shadowZone->needsBarrier()) {
michael@0 982 if (*oldval && getClass()->trace)
michael@0 983 getClass()->trace(shadowZone->barrierTracer(), this->asObjectPtr());
michael@0 984 }
michael@0 985 #endif
michael@0 986 }
michael@0 987
michael@0 988 inline Value
michael@0 989 ObjectValue(ObjectImpl &obj)
michael@0 990 {
michael@0 991 Value v;
michael@0 992 v.setObject(*obj.asObjectPtr());
michael@0 993 return v;
michael@0 994 }
michael@0 995
michael@0 996 inline Handle<JSObject*>
michael@0 997 Downcast(Handle<ObjectImpl*> obj)
michael@0 998 {
michael@0 999 return Handle<JSObject*>::fromMarkedLocation(reinterpret_cast<JSObject* const*>(obj.address()));
michael@0 1000 }
michael@0 1001
michael@0 1002 #ifdef DEBUG
michael@0 1003 static inline bool
michael@0 1004 IsObjectValueInCompartment(js::Value v, JSCompartment *comp)
michael@0 1005 {
michael@0 1006 if (!v.isObject())
michael@0 1007 return true;
michael@0 1008 return reinterpret_cast<ObjectImpl*>(&v.toObject())->compartment() == comp;
michael@0 1009 }
michael@0 1010 #endif
michael@0 1011
michael@0 1012 } /* namespace js */
michael@0 1013
michael@0 1014 #endif /* vm_ObjectImpl_h */

mercurial