blob: c5a4b4a864f4a626d714dd92e9d26f044cca6c4f [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef vm_ObjectImpl_inl_h
#define vm_ObjectImpl_inl_h
#include "mozilla/Assertions.h"
#include "jscompartment.h"
#include "jsgc.h"
#include "jsproxy.h"
#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)
{
return nativeLookupPure(shape->propid()) == shape;
}
inline bool
js::ObjectImpl::isExtensible() const
{
if (this->isProxy())
return Proxy::isExtensible(const_cast<JSObject*>(this->asObjectPtr()));
// [[Extensible]] for ordinary non-proxy objects is an object flag.
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
{
return lastProperty()->isNative();
}
inline bool
js::ObjectImpl::isProxy() const
{
return js::IsProxy(const_cast<JSObject*>(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)
{
if (!v.isObject())
return true;
return v.toObject().compartment() == comp;
}
#endif
inline void
js::ObjectImpl::setSlot(uint32_t slot, const js::Value &value)
{
MOZ_ASSERT(slotInRange(slot));
MOZ_ASSERT(IsObjectValueInCompartment(value, asObjectPtr()->compartment()));
getSlotRef(slot).set(this->asObjectPtr(), HeapSlot::Slot, slot, value);
}
inline void
js::ObjectImpl::setCrossCompartmentSlot(uint32_t slot, const js::Value &value)
{
MOZ_ASSERT(slotInRange(slot));
getSlotRef(slot).set(this->asObjectPtr(), HeapSlot::Slot, slot, value);
}
inline void
js::ObjectImpl::initSlot(uint32_t slot, const js::Value &value)
{
MOZ_ASSERT(getSlot(slot).isUndefined());
MOZ_ASSERT(slotInRange(slot));
MOZ_ASSERT(IsObjectValueInCompartment(value, asObjectPtr()->compartment()));
initSlotUnchecked(slot, value);
}
inline void
js::ObjectImpl::initCrossCompartmentSlot(uint32_t slot, const js::Value &value)
{
MOZ_ASSERT(getSlot(slot).isUndefined());
MOZ_ASSERT(slotInRange(slot));
initSlotUnchecked(slot, value);
}
inline void
js::ObjectImpl::initSlotUnchecked(uint32_t slot, const js::Value &value)
{
getSlotAddressUnchecked(slot)->init(this->asObjectPtr(), HeapSlot::Slot, slot, value);
}
inline void
js::ObjectImpl::setFixedSlot(uint32_t slot, const js::Value &value)
{
MOZ_ASSERT(slot < numFixedSlots());
fixedSlots()[slot].set(this->asObjectPtr(), HeapSlot::Slot, slot, value);
}
inline void
js::ObjectImpl::initFixedSlot(uint32_t slot, const js::Value &value)
{
MOZ_ASSERT(slot < numFixedSlots());
fixedSlots()[slot].init(this->asObjectPtr(), HeapSlot::Slot, slot, value);
}
inline uint32_t
js::ObjectImpl::slotSpan() const
{
if (inDictionaryMode())
return lastProperty()->base()->slotSpan();
return lastProperty()->slotSpan();
}
inline uint32_t
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
{
return lastProperty()->hasObjectFlag(BaseShape::DELEGATE);
}
inline bool
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
{
JS_ASSERT(InSequentialOrExclusiveParallelSection());
return shape_->zone();
}
/* static */ inline void
js::ObjectImpl::readBarrier(ObjectImpl *obj)
{
#ifdef JSGC_INCREMENTAL
Zone *zone = obj->zone();
if (zone->needsBarrier()) {
MOZ_ASSERT(!zone->rt->isHeapMajorCollecting());
JSObject *tmp = obj->asObjectPtr();
MarkObjectUnbarriered(zone->barrierTracer(), &tmp, "read barrier");
MOZ_ASSERT(tmp == obj->asObjectPtr());
}
#endif
}
inline void
js::ObjectImpl::privateWriteBarrierPre(void **old)
{
#ifdef JSGC_INCREMENTAL
Zone *zone = this->zone();
if (zone->needsBarrier()) {
if (*old && getClass()->trace)
getClass()->trace(zone->barrierTracer(), this->asObjectPtr());
}
#endif
}
inline void
js::ObjectImpl::privateWriteBarrierPost(void **pprivate)
{
#ifdef JSGC_GENERATIONAL
runtime()->gcStoreBuffer.putCell(reinterpret_cast<js::gc::Cell **>(pprivate));
#endif
}
/* static */ inline void
js::ObjectImpl::writeBarrierPre(ObjectImpl *obj)
{
#ifdef JSGC_INCREMENTAL
/*
* This would normally be a null test, but TypeScript::global uses 0x1 as a
* special value.
*/
if (IsNullTaggedPointer(obj) || !obj->runtime()->needsBarrier())
return;
Zone *zone = obj->zone();
if (zone->needsBarrier()) {
MOZ_ASSERT(!zone->rt->isHeapMajorCollecting());
JSObject *tmp = obj->asObjectPtr();
MarkObjectUnbarriered(zone->barrierTracer(), &tmp, "write barrier");
MOZ_ASSERT(tmp == obj->asObjectPtr());
}
#endif
}
/* static */ inline void
js::ObjectImpl::writeBarrierPost(ObjectImpl *obj, void *addr)
{
#ifdef JSGC_GENERATIONAL
if (IsNullTaggedPointer(obj))
return;
obj->runtime()->gcStoreBuffer.putCell((Cell **)addr);
#endif
}
inline void
js::ObjectImpl::setPrivate(void *data)
{
void **pprivate = &privateRef(numFixedSlots());
privateWriteBarrierPre(pprivate);
*pprivate = data;
}
inline void
js::ObjectImpl::setPrivateGCThing(js::gc::Cell *cell)
{
void **pprivate = &privateRef(numFixedSlots());
privateWriteBarrierPre(pprivate);
*pprivate = reinterpret_cast<void *>(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 */