diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index c4b37bc5215..3f81a1ebf17 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -16,6 +16,7 @@ #include "ion/AsmJS.h" #include "vm/ForkJoin.h" +#include "vm/Interpreter.h" #include "vm/ObjectImpl-inl.h" diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index a16cfe31fd5..6fa0de00116 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -393,37 +393,6 @@ class TryNoteIter /************************************************************************/ -/* - * To really poison a set of values, using 'magic' or 'undefined' isn't good - * enough since often these will just be ignored by buggy code (see bug 629974) - * in debug builds and crash in release builds. Instead, we use a safe-for-crash - * pointer. - */ -static JS_ALWAYS_INLINE void -Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end) -{ -#ifdef DEBUG - for (Value *v = beg; v != end; ++v) - v->setObject(*reinterpret_cast(0x42)); -#endif -} - -static JS_ALWAYS_INLINE void -Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len) -{ -#ifdef DEBUG - Debug_SetValueRangeToCrashOnTouch(vec, vec + len); -#endif -} - -static JS_ALWAYS_INLINE void -Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len) -{ -#ifdef DEBUG - Debug_SetValueRangeToCrashOnTouch((Value *) vec, len); -#endif -} - bool Throw(JSContext *cx, HandleValue v); diff --git a/js/src/vm/ObjectImpl-inl.h b/js/src/vm/ObjectImpl-inl.h index c5a4b4a864f..bca18c168a8 100644 --- a/js/src/vm/ObjectImpl-inl.h +++ b/js/src/vm/ObjectImpl-inl.h @@ -16,97 +16,22 @@ #include "gc/Heap.h" #include "gc/Marking.h" #include "js/TemplateLib.h" -#include "vm/Interpreter.h" #include "vm/ObjectImpl.h" #include "gc/Barrier-inl.h" -namespace js { - -static MOZ_ALWAYS_INLINE void -Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, uint32_t len) -{ -#ifdef DEBUG - Debug_SetValueRangeToCrashOnTouch((Value *) vec, len); -#endif -} - -static MOZ_ALWAYS_INLINE void -Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end) -{ -#ifdef DEBUG - Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin); -#endif -} - -} // namespace js - inline JSCompartment * js::ObjectImpl::compartment() const { return lastProperty()->base()->compartment(); } -inline js::TaggedProto -js::ObjectImpl::getTaggedProto() const -{ - return TaggedProto(getProto()); -} - -inline js::Shape * -js::ObjectImpl::nativeLookup(JSContext *cx, PropertyId pid) -{ - return nativeLookup(cx, pid.asId()); -} - -inline js::Shape * -js::ObjectImpl::nativeLookup(JSContext *cx, PropertyName *name) -{ - return nativeLookup(cx, NameToId(name)); -} - -inline bool -js::ObjectImpl::nativeContains(JSContext *cx, jsid id) -{ - return nativeLookup(cx, id) != NULL; -} - -inline bool -js::ObjectImpl::nativeContains(JSContext *cx, PropertyName *name) -{ - return nativeLookup(cx, name) != NULL; -} - inline bool js::ObjectImpl::nativeContains(JSContext *cx, Shape *shape) { return nativeLookup(cx, shape->propid()) == shape; } -inline js::Shape * -js::ObjectImpl::nativeLookupPure(PropertyId pid) -{ - return nativeLookupPure(pid.asId()); -} - -inline js::Shape * -js::ObjectImpl::nativeLookupPure(PropertyName *name) -{ - return nativeLookupPure(NameToId(name)); -} - -inline bool -js::ObjectImpl::nativeContainsPure(jsid id) -{ - return nativeLookupPure(id) != NULL; -} - -inline bool -js::ObjectImpl::nativeContainsPure(PropertyName *name) -{ - return nativeContainsPure(NameToId(name)); -} - inline bool js::ObjectImpl::nativeContainsPure(Shape *shape) { @@ -123,88 +48,6 @@ js::ObjectImpl::isExtensible() const return !lastProperty()->hasObjectFlag(BaseShape::NOT_EXTENSIBLE); } -inline uint32_t -js::ObjectImpl::getDenseInitializedLength() -{ - MOZ_ASSERT(isNative()); - return getElementsHeader()->initializedLength; -} - -inline uint32_t -js::ObjectImpl::getDenseCapacity() -{ - MOZ_ASSERT(isNative()); - return getElementsHeader()->capacity; -} - -inline js::HeapSlotArray -js::ObjectImpl::getDenseElements() -{ - MOZ_ASSERT(isNative()); - return HeapSlotArray(elements); -} - -inline const js::Value & -js::ObjectImpl::getDenseElement(uint32_t idx) -{ - MOZ_ASSERT(isNative() && idx < getDenseInitializedLength()); - return elements[idx]; -} - -inline bool -js::ObjectImpl::containsDenseElement(uint32_t idx) -{ - MOZ_ASSERT(isNative()); - return idx < getDenseInitializedLength() && !elements[idx].isMagic(JS_ELEMENTS_HOLE); -} - -inline void -js::ObjectImpl::getSlotRangeUnchecked(uint32_t start, uint32_t length, - HeapSlot **fixedStart, HeapSlot **fixedEnd, - HeapSlot **slotsStart, HeapSlot **slotsEnd) -{ - MOZ_ASSERT(start + length >= start); - - uint32_t fixed = numFixedSlots(); - if (start < fixed) { - if (start + length < fixed) { - *fixedStart = &fixedSlots()[start]; - *fixedEnd = &fixedSlots()[start + length]; - *slotsStart = *slotsEnd = NULL; - } else { - uint32_t localCopy = fixed - start; - *fixedStart = &fixedSlots()[start]; - *fixedEnd = &fixedSlots()[start + localCopy]; - *slotsStart = &slots[0]; - *slotsEnd = &slots[length - localCopy]; - } - } else { - *fixedStart = *fixedEnd = NULL; - *slotsStart = &slots[start - fixed]; - *slotsEnd = &slots[start - fixed + length]; - } -} - -inline void -js::ObjectImpl::getSlotRange(uint32_t start, uint32_t length, - HeapSlot **fixedStart, HeapSlot **fixedEnd, - HeapSlot **slotsStart, HeapSlot **slotsEnd) -{ - MOZ_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED)); - getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd); -} - -inline void -js::ObjectImpl::invalidateSlotRange(uint32_t start, uint32_t length) -{ -#ifdef DEBUG - HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; - getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd); - Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd); - Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd); -#endif /* DEBUG */ -} - inline bool js::ObjectImpl::isNative() const { @@ -217,22 +60,6 @@ js::ObjectImpl::isProxy() const return js::IsProxy(const_cast(this->asObjectPtr())); } -inline js::HeapSlot & -js::ObjectImpl::nativeGetSlotRef(uint32_t slot) -{ - MOZ_ASSERT(isNative()); - MOZ_ASSERT(slot < slotSpan()); - return getSlotRef(slot); -} - -inline const js::Value & -js::ObjectImpl::nativeGetSlot(uint32_t slot) const -{ - MOZ_ASSERT(isNative()); - MOZ_ASSERT(slot < slotSpan()); - return getSlot(slot); -} - #ifdef DEBUG inline bool IsObjectValueInCompartment(js::Value v, JSCompartment *comp) @@ -309,18 +136,6 @@ js::ObjectImpl::numDynamicSlots() const return dynamicSlotsCount(numFixedSlots(), slotSpan()); } -inline JSClass * -js::ObjectImpl::getJSClass() const -{ - return Jsvalify(getClass()); -} - -inline const js::ObjectOps * -js::ObjectImpl::getOps() const -{ - return &getClass()->ops; -} - inline bool js::ObjectImpl::isDelegate() const { @@ -333,26 +148,6 @@ js::ObjectImpl::inDictionaryMode() const return lastProperty()->inDictionary(); } -/* static */ inline uint32_t -js::ObjectImpl::dynamicSlotsCount(uint32_t nfixed, uint32_t span) -{ - if (span <= nfixed) - return 0; - span -= nfixed; - if (span <= SLOT_CAPACITY_MIN) - return SLOT_CAPACITY_MIN; - - uint32_t slots = RoundUpPow2(span); - MOZ_ASSERT(slots >= span); - return slots; -} - -inline size_t -js::ObjectImpl::tenuredSizeOfThis() const -{ - return js::gc::Arena::thingSize(tenuredGetAllocKind()); -} - JS_ALWAYS_INLINE JS::Zone * js::ObjectImpl::zone() const { @@ -442,17 +237,4 @@ js::ObjectImpl::setPrivateGCThing(js::gc::Cell *cell) privateWriteBarrierPost(pprivate); } -inline void -js::ObjectImpl::setPrivateUnbarriered(void *data) -{ - void **pprivate = &privateRef(numFixedSlots()); - *pprivate = data; -} - -inline void -js::ObjectImpl::initPrivate(void *data) -{ - privateRef(numFixedSlots()) = data; -} - #endif /* vm_ObjectImpl_inl_h */ diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index b1ce27530b4..f369f1b9c33 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -16,6 +16,18 @@ using namespace js; +void +js::ObjectImpl::assertIsNative() const +{ + MOZ_ASSERT(isNative()); +} + +void +js::ObjectImpl::assertSlotIsWithinSpan(uint32_t slot) const +{ + MOZ_ASSERT(slot < slotSpan()); +} + PropDesc::PropDesc() : pd_(UndefinedValue()), value_(UndefinedValue()), diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h index 980f935bdba..f1d4d2cae9d 100644 --- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -27,6 +27,53 @@ class ObjectImpl; class Nursery; class Shape; +/* + * To really poison a set of values, using 'magic' or 'undefined' isn't good + * enough since often these will just be ignored by buggy code (see bug 629974) + * in debug builds and crash in release builds. Instead, we use a safe-for-crash + * pointer. + */ +static JS_ALWAYS_INLINE void +Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end) +{ +#ifdef DEBUG + for (Value *v = beg; v != end; ++v) + v->setObject(*reinterpret_cast(0x42)); +#endif +} + +static JS_ALWAYS_INLINE void +Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len) +{ +#ifdef DEBUG + Debug_SetValueRangeToCrashOnTouch(vec, vec + len); +#endif +} + +static JS_ALWAYS_INLINE void +Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len) +{ +#ifdef DEBUG + Debug_SetValueRangeToCrashOnTouch((Value *) vec, len); +#endif +} + +static MOZ_ALWAYS_INLINE void +Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, uint32_t len) +{ +#ifdef DEBUG + Debug_SetValueRangeToCrashOnTouch((Value *) vec, len); +#endif +} + +static MOZ_ALWAYS_INLINE void +Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end) +{ +#ifdef DEBUG + Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin); +#endif +} + static inline PropertyOp CastAsPropertyOp(JSObject *object) { @@ -1197,11 +1244,27 @@ class ObjectImpl : public gc::Cell static bool preventExtensions(JSContext *cx, Handle obj); - inline HeapSlotArray getDenseElements(); - inline const Value & getDenseElement(uint32_t idx); - inline bool containsDenseElement(uint32_t idx); - inline uint32_t getDenseInitializedLength(); - inline uint32_t getDenseCapacity(); + HeapSlotArray getDenseElements() { + assertIsNative(); + return HeapSlotArray(elements); + } + const Value &getDenseElement(uint32_t idx) { + assertIsNative(); + MOZ_ASSERT(idx < getDenseInitializedLength()); + return elements[idx]; + } + bool containsDenseElement(uint32_t idx) { + assertIsNative(); + return idx < getDenseInitializedLength() && !elements[idx].isMagic(JS_ELEMENTS_HOLE); + } + uint32_t getDenseInitializedLength() { + assertIsNative(); + return getElementsHeader()->initializedLength; + } + uint32_t getDenseCapacity() { + assertIsNative(); + return getElementsHeader()->capacity; + } bool makeElementsSparse(JSContext *cx) { NEW_OBJECT_REPRESENTATION_ONLY(); @@ -1238,19 +1301,54 @@ class ObjectImpl : public gc::Cell * Get internal pointers to the range of values starting at start and * running for length. */ - inline void getSlotRangeUnchecked(uint32_t start, uint32_t length, - HeapSlot **fixedStart, HeapSlot **fixedEnd, - HeapSlot **slotsStart, HeapSlot **slotsEnd); - inline void getSlotRange(uint32_t start, uint32_t length, - HeapSlot **fixedStart, HeapSlot **fixedEnd, - HeapSlot **slotsStart, HeapSlot **slotsEnd); + void getSlotRangeUnchecked(uint32_t start, uint32_t length, + HeapSlot **fixedStart, HeapSlot **fixedEnd, + HeapSlot **slotsStart, HeapSlot **slotsEnd) + { + MOZ_ASSERT(start + length >= start); + + uint32_t fixed = numFixedSlots(); + if (start < fixed) { + if (start + length < fixed) { + *fixedStart = &fixedSlots()[start]; + *fixedEnd = &fixedSlots()[start + length]; + *slotsStart = *slotsEnd = NULL; + } else { + uint32_t localCopy = fixed - start; + *fixedStart = &fixedSlots()[start]; + *fixedEnd = &fixedSlots()[start + localCopy]; + *slotsStart = &slots[0]; + *slotsEnd = &slots[length - localCopy]; + } + } else { + *fixedStart = *fixedEnd = NULL; + *slotsStart = &slots[start - fixed]; + *slotsEnd = &slots[start - fixed + length]; + } + } + + void getSlotRange(uint32_t start, uint32_t length, + HeapSlot **fixedStart, HeapSlot **fixedEnd, + HeapSlot **slotsStart, HeapSlot **slotsEnd) + { + MOZ_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED)); + getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd); + } protected: friend struct GCMarker; friend class Shape; friend class NewObjectCache; - inline void invalidateSlotRange(uint32_t start, uint32_t count); + void invalidateSlotRange(uint32_t start, uint32_t length) { +#ifdef DEBUG + HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd; + getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd); + Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd); + Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd); +#endif /* DEBUG */ + } + void initializeSlotRange(uint32_t start, uint32_t count); /* @@ -1310,7 +1408,9 @@ class ObjectImpl : public gc::Cell */ public: - inline js::TaggedProto getTaggedProto() const; + js::TaggedProto getTaggedProto() const { + return TaggedProto(getProto()); + } Shape * lastProperty() const { MOZ_ASSERT(shape_); @@ -1324,6 +1424,7 @@ class ObjectImpl : public gc::Cell inline JSCompartment *compartment() const; inline bool isNative() const; + void assertIsNative() const; types::TypeObject *type() const { MOZ_ASSERT(!hasLazyType()); @@ -1347,16 +1448,25 @@ class ObjectImpl : public gc::Cell bool hasLazyType() const { return type_->lazy(); } inline uint32_t slotSpan() const; + void assertSlotIsWithinSpan(uint32_t slot) const; /* Compute dynamicSlotsCount() for this object. */ inline uint32_t numDynamicSlots() const; Shape *nativeLookup(JSContext *cx, jsid id); - inline Shape *nativeLookup(JSContext *cx, PropertyId pid); - inline Shape *nativeLookup(JSContext *cx, PropertyName *name); + Shape *nativeLookup(JSContext *cx, PropertyId pid) { + return nativeLookup(cx, pid.asId()); + } + Shape *nativeLookup(JSContext *cx, PropertyName *name) { + return nativeLookup(cx, NameToId(name)); + } - inline bool nativeContains(JSContext *cx, jsid id); - inline bool nativeContains(JSContext *cx, PropertyName* name); + bool nativeContains(JSContext *cx, jsid id) { + return nativeLookup(cx, id) != NULL; + } + bool nativeContains(JSContext *cx, PropertyName* name) { + return nativeLookup(cx, name) != NULL; + } inline bool nativeContains(JSContext *cx, Shape* shape); /* @@ -1364,18 +1474,30 @@ class ObjectImpl : public gc::Cell * operation would have been effectful. */ Shape *nativeLookupPure(jsid id); - inline Shape *nativeLookupPure(PropertyId pid); - inline Shape *nativeLookupPure(PropertyName *name); + Shape *nativeLookupPure(PropertyId pid) { + return nativeLookupPure(pid.asId()); + } + Shape *nativeLookupPure(PropertyName *name) { + return nativeLookupPure(NameToId(name)); + } - inline bool nativeContainsPure(jsid id); - inline bool nativeContainsPure(PropertyName* name); - inline bool nativeContainsPure(Shape* shape); + bool nativeContainsPure(jsid id) { + return nativeLookupPure(id) != NULL; + } + bool nativeContainsPure(PropertyName* name) { + return nativeContainsPure(NameToId(name)); + } + bool nativeContainsPure(Shape* shape); - inline JSClass *getJSClass() const; - inline bool hasClass(const Class *c) const { + JSClass *getJSClass() const { + return Jsvalify(getClass()); + } + bool hasClass(const Class *c) const { return getClass() == c; } - inline const ObjectOps *getOps() const; + const ObjectOps *getOps() const { + return &getClass()->ops; + } /* * An object is a delegate if it is on another object's prototype or scope @@ -1425,8 +1547,16 @@ class ObjectImpl : public gc::Cell return *getSlotAddress(slot); } - inline HeapSlot &nativeGetSlotRef(uint32_t slot); - inline const Value &nativeGetSlot(uint32_t slot) const; + HeapSlot &nativeGetSlotRef(uint32_t slot) { + assertIsNative(); + assertSlotIsWithinSpan(slot); + return getSlotRef(slot); + } + const Value &nativeGetSlot(uint32_t slot) const { + assertIsNative(); + assertSlotIsWithinSpan(slot); + return getSlot(slot); + } inline void setSlot(uint32_t slot, const Value &value); inline void setCrossCompartmentSlot(uint32_t slot, const Value &value); @@ -1455,10 +1585,22 @@ class ObjectImpl : public gc::Cell * capacity is not stored explicitly, and the allocated size of the slot * array is kept in sync with this count. */ - static inline uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span); + static uint32_t dynamicSlotsCount(uint32_t nfixed, uint32_t span) { + if (span <= nfixed) + return 0; + span -= nfixed; + if (span <= SLOT_CAPACITY_MIN) + return SLOT_CAPACITY_MIN; + + uint32_t slots = RoundUpPow2(span); + MOZ_ASSERT(slots >= span); + return slots; + } /* Memory usage functions. */ - inline size_t tenuredSizeOfThis() const; + size_t tenuredSizeOfThis() const { + return js::gc::Arena::thingSize(tenuredGetAllocKind()); + } /* Elements accessors. */ @@ -1531,8 +1673,13 @@ class ObjectImpl : public gc::Cell } inline void setPrivate(void *data); inline void setPrivateGCThing(gc::Cell *cell); - inline void setPrivateUnbarriered(void *data); - inline void initPrivate(void *data); + void setPrivateUnbarriered(void *data) { + void **pprivate = &privateRef(numFixedSlots()); + *pprivate = data; + } + void initPrivate(void *data) { + privateRef(numFixedSlots()) = data; + } /* Access private data for an object with a known number of fixed slots. */ inline void *getPrivate(uint32_t nfixed) const {