Bug 728411 - Move slot range operations into ObjectImpl. r=bhackett

--HG--
extra : rebase_source : 704d67267923e019df82de7f77f60b48c6c62128
This commit is contained in:
Jeff Walden 2012-02-23 15:39:32 -08:00
parent e6976ebef4
commit 8b9d875ceb
10 changed files with 265 additions and 239 deletions

View File

@ -37,12 +37,15 @@
*
* ***** END LICENSE BLOCK ***** */
#ifndef jsgc_barrier_inl_h___
#define jsgc_barrier_inl_h___
#include "jsgcmark.h"
#include "gc/Barrier.h"
#ifndef jsgc_barrier_inl_h___
#define jsgc_barrier_inl_h___
#include "vm/ObjectImpl-inl.h"
#include "vm/String-inl.h"
namespace js {

View File

@ -101,6 +101,7 @@
#include "jsscopeinlines.h"
#include "jsscriptinlines.h"
#include "vm/ObjectImpl-inl.h"
#include "vm/RegExpObject-inl.h"
#include "vm/RegExpStatics-inl.h"
#include "vm/Stack-inl.h"

View File

@ -139,6 +139,7 @@
#include "jsstrinlines.h"
#include "vm/ArgumentsObject-inl.h"
#include "vm/ObjectImpl-inl.h"
#include "vm/Stack-inl.h"
using namespace mozilla;

View File

@ -374,22 +374,6 @@ Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len)
#endif
}
static JS_ALWAYS_INLINE void
Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, size_t len)
{
#ifdef DEBUG
Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
#endif
}
static JS_ALWAYS_INLINE void
Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end)
{
#ifdef DEBUG
Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin);
#endif
}
} /* namespace js */
#endif /* jsinterp_h___ */

View File

@ -3808,43 +3808,6 @@ js_InitClass(JSContext *cx, HandleObject obj, JSObject *protoProto,
ps, fs, static_ps, static_fs, ctorp, ctorKind);
}
void
JSObject::initSlotRange(size_t start, const Value *vector, size_t length)
{
JSCompartment *comp = compartment();
HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
for (HeapSlot *sp = fixedStart; sp != fixedEnd; sp++)
sp->init(comp, this, start++, *vector++);
for (HeapSlot *sp = slotsStart; sp != slotsEnd; sp++)
sp->init(comp, this, start++, *vector++);
}
void
JSObject::copySlotRange(size_t start, const Value *vector, size_t length)
{
JSCompartment *comp = compartment();
HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
for (HeapSlot *sp = fixedStart; sp != fixedEnd; sp++)
sp->set(comp, this, start++, *vector++);
for (HeapSlot *sp = slotsStart; sp != slotsEnd; sp++)
sp->set(comp, this, start++, *vector++);
}
inline void
JSObject::invalidateSlotRange(size_t start, size_t length)
{
#ifdef DEBUG
JS_ASSERT(!isDenseArray());
HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd);
Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd);
#endif /* DEBUG */
}
inline bool
JSObject::updateSlotsForSpan(JSContext *cx, size_t oldSpan, size_t newSpan)
{
@ -4129,17 +4092,6 @@ JSObject::shrinkElements(JSContext *cx, unsigned newcap)
Probes::resizeObject(cx, this, oldSize, computedSizeOfThisSlotsElements());
}
#ifdef DEBUG
bool
JSObject::slotInRange(unsigned slot, SentinelAllowed sentinel) const
{
size_t capacity = numFixedSlots() + numDynamicSlots();
if (sentinel == SENTINEL_ALLOWED)
return slot <= capacity;
return slot < capacity;
}
#endif /* DEBUG */
static JSObject *
js_InitNullClass(JSContext *cx, JSObject *obj)
{

View File

@ -541,17 +541,6 @@ struct JSObject : public js::ObjectImpl
static const uint32_t MAX_FIXED_SLOTS = 16;
private:
/*
* Get internal pointers to the range of values starting at start and
* running for length.
*/
inline void getSlotRangeUnchecked(size_t start, size_t length,
js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd,
js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd);
inline void getSlotRange(size_t start, size_t length,
js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd,
js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd);
public:
/* Accessors for properties. */
@ -575,15 +564,9 @@ struct JSObject : public js::ObjectImpl
bool hasDynamicSlots() const { return slots != NULL; }
/* Compute dynamicSlotsCount() for this object. */
inline size_t numDynamicSlots() const;
protected:
inline bool hasContiguousSlots(size_t start, size_t count) const;
inline void initializeSlotRange(size_t start, size_t count);
inline void invalidateSlotRange(size_t start, size_t count);
inline bool updateSlotsForSpan(JSContext *cx, size_t oldSpan, size_t newSpan);
public:
@ -594,35 +577,8 @@ struct JSObject : public js::ObjectImpl
inline void prepareSlotRangeForOverwrite(size_t start, size_t end);
inline void prepareElementRangeForOverwrite(size_t start, size_t end);
/*
* Initialize a flat array of slots to this object at a start slot. The
* caller must ensure that are enough slots.
*/
void initSlotRange(size_t start, const js::Value *vector, size_t length);
/*
* Copy a flat array of slots to this object at a start slot. Caller must
* ensure there are enough slots in this object.
*/
void copySlotRange(size_t start, const js::Value *vector, size_t length);
inline uint32_t slotSpan() const;
void rollbackProperties(JSContext *cx, uint32_t slotSpan);
#ifdef DEBUG
enum SentinelAllowed {
SENTINEL_NOT_ALLOWED,
SENTINEL_ALLOWED
};
/*
* Check that slot is in range for the object's allocated slots.
* If sentinelAllowed then slot may equal the slot capacity.
*/
bool slotInRange(unsigned slot, SentinelAllowed sentinel = SENTINEL_NOT_ALLOWED) const;
#endif
private:
js::HeapSlot *getSlotAddressUnchecked(unsigned slot) {
size_t fixed = numFixedSlots();
@ -837,12 +793,9 @@ struct JSObject : public js::ObjectImpl
inline void setArrayLength(JSContext *cx, uint32_t length);
inline uint32_t getDenseArrayCapacity();
inline uint32_t getDenseArrayInitializedLength();
inline void setDenseArrayLength(uint32_t length);
inline void setDenseArrayInitializedLength(uint32_t length);
inline void ensureDenseArrayInitializedLength(JSContext *cx, unsigned index, unsigned extra);
inline js::HeapSlotArray getDenseArrayElements();
inline const js::Value &getDenseArrayElement(unsigned idx);
inline void setDenseArrayElement(unsigned idx, const js::Value &val);
inline void initDenseArrayElement(unsigned idx, const js::Value &val);
inline void setDenseArrayElementWithType(JSContext *cx, unsigned idx, const js::Value &val);
@ -1176,9 +1129,7 @@ struct JSObject : public js::ObjectImpl
/* Direct subtypes of JSObject: */
inline bool isArguments() const;
inline bool isArrayBuffer() const;
inline bool isArray() const;
inline bool isDate() const;
inline bool isDenseArray() const;
inline bool isElementIterator() const;
inline bool isError() const;
inline bool isFunction() const;
@ -1194,7 +1145,6 @@ struct JSObject : public js::ObjectImpl
inline bool isRegExpStatics() const;
inline bool isScope() const;
inline bool isScript() const;
inline bool isSlowArray() const;
inline bool isStopIteration() const;
inline bool isWeakMap() const;
inline bool isXML() const;

View File

@ -372,12 +372,6 @@ JSObject::dynamicSlotIndex(size_t slot)
return slot - numFixedSlots();
}
inline size_t
JSObject::numDynamicSlots() const
{
return dynamicSlotsCount(numFixedSlots(), slotSpan());
}
inline void
JSObject::setLastPropertyInfallible(const js::Shape *shape)
{
@ -512,13 +506,6 @@ JSObject::setDenseArrayLength(uint32_t length)
getElementsHeader()->length = length;
}
inline uint32_t
JSObject::getDenseArrayInitializedLength()
{
JS_ASSERT(isDenseArray());
return getElementsHeader()->initializedLength;
}
inline void
JSObject::setDenseArrayInitializedLength(uint32_t length)
{
@ -543,20 +530,6 @@ JSObject::ensureElements(JSContext *cx, uint32_t capacity)
return true;
}
inline js::HeapSlotArray
JSObject::getDenseArrayElements()
{
JS_ASSERT(isDenseArray());
return js::HeapSlotArray(elements);
}
inline const js::Value &
JSObject::getDenseArrayElement(unsigned idx)
{
JS_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength());
return elements[idx];
}
inline void
JSObject::setDenseArrayElement(unsigned idx, const js::Value &val)
{
@ -932,25 +905,6 @@ inline bool JSObject::isWeakMap() const { return hasClass(&js::WeakMapClass); }
inline bool JSObject::isWith() const { return hasClass(&js::WithClass); }
inline bool JSObject::isXML() const { return hasClass(&js::XMLClass); }
inline bool JSObject::isArray() const
{
return isSlowArray() || isDenseArray();
}
inline bool JSObject::isDenseArray() const
{
bool result = hasClass(&js::ArrayClass);
JS_ASSERT_IF(result, elements != js::emptyObjectElements);
return result;
}
inline bool JSObject::isSlowArray() const
{
bool result = hasClass(&js::SlowArrayClass);
JS_ASSERT_IF(result, elements != js::emptyObjectElements);
return result;
}
inline bool
JSObject::isXMLId() const
{
@ -967,60 +921,6 @@ JSObject::isQName() const
|| hasClass(&js::AnyNameClass);
}
inline void
JSObject::getSlotRangeUnchecked(size_t start, size_t length,
js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd,
js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd)
{
JS_ASSERT(!isDenseArray());
size_t fixed = numFixedSlots();
if (start < fixed) {
if (start + length < fixed) {
*fixedStart = &fixedSlots()[start];
*fixedEnd = &fixedSlots()[start + length];
*slotsStart = *slotsEnd = NULL;
} else {
size_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
JSObject::getSlotRange(size_t start, size_t length,
js::HeapSlot **fixedStart, js::HeapSlot **fixedEnd,
js::HeapSlot **slotsStart, js::HeapSlot **slotsEnd)
{
JS_ASSERT(slotInRange(start + length, SENTINEL_ALLOWED));
getSlotRangeUnchecked(start, length, fixedStart, fixedEnd, slotsStart, slotsEnd);
}
inline void
JSObject::initializeSlotRange(size_t start, size_t length)
{
/*
* No bounds check, as this is used when the object's shape does not
* reflect its allocated slots (updateSlotsForSpan).
*/
js::HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
getSlotRangeUnchecked(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
JSCompartment *comp = compartment();
size_t offset = start;
for (js::HeapSlot *sp = fixedStart; sp != fixedEnd; sp++)
sp->init(comp, this, offset++, js::UndefinedValue());
for (js::HeapSlot *sp = slotsStart; sp != slotsEnd; sp++)
sp->init(comp, this, offset++, js::UndefinedValue());
}
/* static */ inline JSObject *
JSObject::create(JSContext *cx, js::gc::AllocKind kind,
js::HandleShape shape, js::HandleTypeObject type, js::HeapSlot *slots)
@ -1124,14 +1024,6 @@ JSObject::principals(JSContext *cx)
return cx->compartment ? cx->compartment->principals : NULL;
}
inline uint32_t
JSObject::slotSpan() const
{
if (inDictionaryMode())
return lastProperty()->base()->slotSpan();
return lastProperty()->slotSpan();
}
inline js::HeapSlot &
JSObject::nativeGetSlotRef(unsigned slot)
{

View File

@ -14,11 +14,163 @@
#include "jscompartment.h"
#include "jsgc.h"
#include "jsgcmark.h"
#include "jsinterp.h"
#include "js/TemplateLib.h"
#include "ObjectImpl.h"
namespace js {
static JS_ALWAYS_INLINE void
Debug_SetSlotRangeToCrashOnTouch(HeapSlot *vec, size_t len)
{
#ifdef DEBUG
Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
#endif
}
static JS_ALWAYS_INLINE void
Debug_SetSlotRangeToCrashOnTouch(HeapSlot *begin, HeapSlot *end)
{
#ifdef DEBUG
Debug_SetValueRangeToCrashOnTouch((Value *) begin, end - begin);
#endif
}
} // namespace js
inline bool
js::ObjectImpl::isExtensible() const
{
return !lastProperty()->hasObjectFlag(BaseShape::NOT_EXTENSIBLE);
}
inline bool
js::ObjectImpl::isDenseArray() const
{
bool result = hasClass(&ArrayClass);
MOZ_ASSERT_IF(result, elements != emptyObjectElements);
return result;
}
inline bool
js::ObjectImpl::isSlowArray() const
{
bool result = hasClass(&SlowArrayClass);
MOZ_ASSERT_IF(result, elements != emptyObjectElements);
return result;
}
inline bool
js::ObjectImpl::isArray() const
{
return isSlowArray() || isDenseArray();
}
inline uint32_t
js::ObjectImpl::getDenseArrayInitializedLength()
{
MOZ_ASSERT(isDenseArray());
return getElementsHeader()->initializedLength;
}
inline js::HeapSlotArray
js::ObjectImpl::getDenseArrayElements()
{
MOZ_ASSERT(isDenseArray());
return HeapSlotArray(elements);
}
inline const js::Value &
js::ObjectImpl::getDenseArrayElement(unsigned idx)
{
MOZ_ASSERT(isDenseArray() && idx < getDenseArrayInitializedLength());
return elements[idx];
}
inline void
js::ObjectImpl::getSlotRangeUnchecked(size_t start, size_t length,
HeapSlot **fixedStart, HeapSlot **fixedEnd,
HeapSlot **slotsStart, HeapSlot **slotsEnd)
{
MOZ_ASSERT(!isDenseArray());
MOZ_ASSERT(start + length >= start);
size_t fixed = numFixedSlots();
if (start < fixed) {
if (start + length < fixed) {
*fixedStart = &fixedSlots()[start];
*fixedEnd = &fixedSlots()[start + length];
*slotsStart = *slotsEnd = NULL;
} else {
size_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(size_t start, size_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(size_t start, size_t length)
{
#ifdef DEBUG
MOZ_ASSERT(!isDenseArray());
HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
Debug_SetSlotRangeToCrashOnTouch(fixedStart, fixedEnd);
Debug_SetSlotRangeToCrashOnTouch(slotsStart, slotsEnd);
#endif /* DEBUG */
}
inline void
js::ObjectImpl::initializeSlotRange(size_t start, size_t length)
{
/*
* No bounds check, as this is used when the object's shape does not
* reflect its allocated slots (updateSlotsForSpan).
*/
HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
getSlotRangeUnchecked(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
JSCompartment *comp = compartment();
size_t offset = start;
for (HeapSlot *sp = fixedStart; sp < fixedEnd; sp++)
sp->init(comp, this->asObjectPtr(), offset++, UndefinedValue());
for (HeapSlot *sp = slotsStart; sp < slotsEnd; sp++)
sp->init(comp, this->asObjectPtr(), offset++, UndefinedValue());
}
inline uint32_t
js::ObjectImpl::slotSpan() const
{
if (inDictionaryMode())
return lastProperty()->base()->slotSpan();
return lastProperty()->slotSpan();
}
inline size_t
js::ObjectImpl::numDynamicSlots() const
{
return dynamicSlotsCount(numFixedSlots(), slotSpan());
}
inline bool
js::ObjectImpl::isNative() const
{
@ -138,10 +290,4 @@ js::ObjectImpl::writeBarrierPost(ObjectImpl *obj, void *addr)
{
}
inline bool
js::ObjectImpl::isExtensible() const
{
return !lastProperty()->hasObjectFlag(BaseShape::NOT_EXTENSIBLE);
}
#endif /* ObjectImpl_inl_h__ */

View File

@ -13,6 +13,8 @@
#include "ObjectImpl.h"
#include "gc/Barrier-inl.h"
#include "ObjectImpl-inl.h"
using namespace js;
@ -23,6 +25,41 @@ static ObjectElements emptyElementsHeader(0, 0);
HeapSlot *js::emptyObjectElements =
reinterpret_cast<HeapSlot *>(uintptr_t(&emptyElementsHeader) + sizeof(ObjectElements));
void
js::ObjectImpl::initSlotRange(size_t start, const Value *vector, size_t length)
{
JSCompartment *comp = compartment();
HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
for (HeapSlot *sp = fixedStart; sp < fixedEnd; sp++)
sp->init(comp, this->asObjectPtr(), start++, *vector++);
for (HeapSlot *sp = slotsStart; sp < slotsEnd; sp++)
sp->init(comp, this->asObjectPtr(), start++, *vector++);
}
void
js::ObjectImpl::copySlotRange(size_t start, const Value *vector, size_t length)
{
JSCompartment *comp = compartment();
HeapSlot *fixedStart, *fixedEnd, *slotsStart, *slotsEnd;
getSlotRange(start, length, &fixedStart, &fixedEnd, &slotsStart, &slotsEnd);
for (HeapSlot *sp = fixedStart; sp < fixedEnd; sp++)
sp->set(comp, this->asObjectPtr(), start++, *vector++);
for (HeapSlot *sp = slotsStart; sp < slotsEnd; sp++)
sp->set(comp, this->asObjectPtr(), start++, *vector++);
}
#ifdef DEBUG
bool
js::ObjectImpl::slotInRange(unsigned slot, SentinelAllowed sentinel) const
{
size_t capacity = numFixedSlots() + numDynamicSlots();
if (sentinel == SENTINEL_ALLOWED)
return slot <= capacity;
return slot < capacity;
}
#endif /* DEBUG */
#if defined(_MSC_VER) && _MSC_VER >= 1500
/*
* Work around a compiler bug in MSVC9 and above, where inlining this function

View File

@ -19,6 +19,8 @@
namespace js {
class ObjectImpl;
/*
* Header structure for object element arrays. This structure is immediately
* followed by an array of elements, with the elements member in an object
@ -28,6 +30,7 @@ namespace js {
class ObjectElements
{
friend struct ::JSObject;
friend class ObjectImpl;
/* Number of allocated slots. */
uint32_t capacity;
@ -171,11 +174,72 @@ class ObjectImpl : public gc::Cell
JSObject * asObjectPtr() { return reinterpret_cast<JSObject *>(this); }
/* These functions are public, and they should remain public. */
public:
JSObject * getProto() const {
return type_->proto;
}
inline bool isExtensible() const;
/*
* XXX Once the property/element split of bug 586842 is complete, these
* methods should move back to JSObject.
*/
inline bool isDenseArray() const;
inline bool isSlowArray() const;
inline bool isArray() const;
inline HeapSlotArray getDenseArrayElements();
inline const Value & getDenseArrayElement(unsigned idx);
inline uint32_t getDenseArrayInitializedLength();
private:
/*
* Get internal pointers to the range of values starting at start and
* running for length.
*/
inline void getSlotRangeUnchecked(size_t start, size_t length,
HeapSlot **fixedStart, HeapSlot **fixedEnd,
HeapSlot **slotsStart, HeapSlot **slotsEnd);
inline void getSlotRange(size_t start, size_t length,
HeapSlot **fixedStart, HeapSlot **fixedEnd,
HeapSlot **slotsStart, HeapSlot **slotsEnd);
protected:
friend struct GCMarker;
friend struct Shape;
friend class NewObjectCache;
inline void invalidateSlotRange(size_t start, size_t count);
inline void initializeSlotRange(size_t start, size_t count);
/*
* Initialize a flat array of slots to this object at a start slot. The
* caller must ensure that are enough slots.
*/
void initSlotRange(size_t start, const Value *vector, size_t length);
/*
* Copy a flat array of slots to this object at a start slot. Caller must
* ensure there are enough slots in this object.
*/
void copySlotRange(size_t start, const Value *vector, size_t length);
#ifdef DEBUG
enum SentinelAllowed {
SENTINEL_NOT_ALLOWED,
SENTINEL_ALLOWED
};
/*
* Check that slot is in range for the object's allocated slots.
* If sentinelAllowed then slot may equal the slot capacity.
*/
bool slotInRange(unsigned slot, SentinelAllowed sentinel = SENTINEL_NOT_ALLOWED) const;
#endif
/* Minimum size for dynamically allocated slots. */
static const uint32_t SLOT_CAPACITY_MIN = 8;
@ -215,6 +279,11 @@ class ObjectImpl : public gc::Cell
*/
bool hasLazyType() const { return type_->lazy(); }
inline uint32_t slotSpan() const;
/* Compute dynamicSlotsCount() for this object. */
inline size_t numDynamicSlots() const;
inline bool isNative() const;
const Shape * nativeLookup(JSContext *cx, jsid id);
@ -304,15 +373,6 @@ class ObjectImpl : public gc::Cell
}
static size_t getPrivateDataOffset(size_t nfixed) { return getFixedSlotOffset(nfixed); }
static size_t offsetOfSlots() { return offsetof(ObjectImpl, slots); }
/* These functions are public, and they should remain public. */
public:
JSObject * getProto() const {
return type_->proto;
}
inline bool isExtensible() const;
};
} /* namespace js */