mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 1116855
- Various fixes and VM changes for JIT'ing unboxed objects, r=jandem.
This commit is contained in:
parent
958c00e0fe
commit
1a99000d97
@ -1700,7 +1700,7 @@ TypedObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
|
||||
return obj_lookupElement(cx, obj, index, objp, propp);
|
||||
|
||||
if (JSID_IS_ATOM(id, cx->names().length)) {
|
||||
MarkNonNativePropertyFound(propp);
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
@ -1712,7 +1712,7 @@ TypedObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
|
||||
StructTypeDescr &structDescr = descr->as<StructTypeDescr>();
|
||||
size_t index;
|
||||
if (structDescr.fieldIndex(id, &index)) {
|
||||
MarkNonNativePropertyFound(propp);
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
@ -1746,7 +1746,7 @@ TypedObject::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
{
|
||||
MOZ_ASSERT(obj->is<TypedObject>());
|
||||
MarkNonNativePropertyFound(propp);
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
@ -1177,9 +1177,17 @@ CanAttachNativeGetProp(typename GetPropCache::Context cx, const GetPropCache &ca
|
||||
// of turn. We don't mind doing this even when purity isn't required, because we
|
||||
// only miss out on shape hashification, which is only a temporary perf cost.
|
||||
// The limits were arbitrarily set, anyways.
|
||||
if (!LookupPropertyPure(cx, obj, NameToId(name), holder.address(), shape.address()))
|
||||
JSObject *baseHolder = nullptr;
|
||||
if (!LookupPropertyPure(cx, obj, NameToId(name), &baseHolder, shape.address()))
|
||||
return GetPropertyIC::CanAttachNone;
|
||||
|
||||
MOZ_ASSERT(!holder);
|
||||
if (baseHolder) {
|
||||
if (!baseHolder->isNative())
|
||||
return GetPropertyIC::CanAttachNone;
|
||||
holder.set(&baseHolder->as<NativeObject>());
|
||||
}
|
||||
|
||||
RootedScript script(cx);
|
||||
jsbytecode *pc;
|
||||
cache.getScriptedLocation(&script, &pc);
|
||||
@ -2645,7 +2653,7 @@ IsPropertyAddInlineable(NativeObject *obj, HandleId id, ConstantOrRegister val,
|
||||
|
||||
static SetPropertyIC::NativeSetPropCacheability
|
||||
CanAttachNativeSetProp(JSContext *cx, HandleObject obj, HandleId id, ConstantOrRegister val,
|
||||
bool needsTypeBarrier, MutableHandleNativeObject holder,
|
||||
bool needsTypeBarrier, MutableHandleObject holder,
|
||||
MutableHandleShape shape, bool *checkTypeset)
|
||||
{
|
||||
if (!obj->isNative())
|
||||
@ -2723,7 +2731,7 @@ SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
|
||||
}
|
||||
|
||||
RootedShape shape(cx);
|
||||
RootedNativeObject holder(cx);
|
||||
RootedObject holder(cx);
|
||||
bool checkTypeset;
|
||||
canCache = CanAttachNativeSetProp(cx, obj, id, cache.value(), cache.needsTypeBarrier(),
|
||||
&holder, &shape, &checkTypeset);
|
||||
|
112
js/src/jsobj.cpp
112
js/src/jsobj.cpp
@ -3047,79 +3047,73 @@ js::HasOwnProperty(JSContext *cx, HandleObject obj, HandleId id, bool *result)
|
||||
return true;
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
LookupPropertyPureInline(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
|
||||
Shape **propp)
|
||||
bool
|
||||
js::LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
||||
Shape **propp)
|
||||
{
|
||||
if (!obj->isNative())
|
||||
return false;
|
||||
do {
|
||||
if (obj->isNative()) {
|
||||
/* Search for a native dense element, typed array element, or property. */
|
||||
|
||||
NativeObject *current = &obj->as<NativeObject>();
|
||||
while (true) {
|
||||
/* Search for a native dense element, typed array element, or property. */
|
||||
if (JSID_IS_INT(id) && obj->as<NativeObject>().containsDenseElement(JSID_TO_INT(id))) {
|
||||
*objp = obj;
|
||||
MarkDenseOrTypedArrayElementFound<NoGC>(propp);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (JSID_IS_INT(id) && current->containsDenseElement(JSID_TO_INT(id))) {
|
||||
*objp = current;
|
||||
MarkDenseOrTypedArrayElementFound<NoGC>(propp);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsAnyTypedArray(current)) {
|
||||
uint64_t index;
|
||||
if (IsTypedArrayIndex(id, &index)) {
|
||||
if (index < AnyTypedArrayLength(obj)) {
|
||||
*objp = current;
|
||||
MarkDenseOrTypedArrayElementFound<NoGC>(propp);
|
||||
} else {
|
||||
*objp = nullptr;
|
||||
*propp = nullptr;
|
||||
if (IsAnyTypedArray(obj)) {
|
||||
uint64_t index;
|
||||
if (IsTypedArrayIndex(id, &index)) {
|
||||
if (index < AnyTypedArrayLength(obj)) {
|
||||
*objp = obj;
|
||||
MarkDenseOrTypedArrayElementFound<NoGC>(propp);
|
||||
} else {
|
||||
*objp = nullptr;
|
||||
*propp = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Shape *shape = obj->as<NativeObject>().lookupPure(id)) {
|
||||
*objp = obj;
|
||||
*propp = shape;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fail if there's a resolve hook. We allow the JSFunction resolve hook
|
||||
// if we know it will never add a property with this name or str_resolve
|
||||
// with a non-integer property.
|
||||
do {
|
||||
const Class *clasp = obj->getClass();
|
||||
if (!clasp->resolve)
|
||||
break;
|
||||
if (clasp->resolve == fun_resolve && !FunctionHasResolveHook(cx->names(), id))
|
||||
break;
|
||||
if (clasp->resolve == str_resolve && !JSID_IS_INT(id))
|
||||
break;
|
||||
return false;
|
||||
} while (0);
|
||||
} else {
|
||||
// Search for a property on an unboxed object. Other non-native objects
|
||||
// are not handled here.
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return false;
|
||||
if (obj->as<UnboxedPlainObject>().layout().lookup(id)) {
|
||||
*objp = obj;
|
||||
MarkNonNativePropertyFound<NoGC>(propp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Shape *shape = current->lookupPure(id)) {
|
||||
*objp = current;
|
||||
*propp = shape;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fail if there's a resolve hook. We allow the JSFunction resolve hook
|
||||
// if we know it will never add a property with this name or str_resolve
|
||||
// with a non-integer property.
|
||||
do {
|
||||
const Class *clasp = current->getClass();
|
||||
if (!clasp->resolve)
|
||||
break;
|
||||
if (clasp->resolve == fun_resolve && !FunctionHasResolveHook(cx->names(), id))
|
||||
break;
|
||||
if (clasp->resolve == str_resolve && !JSID_IS_INT(id))
|
||||
break;
|
||||
return false;
|
||||
} while (0);
|
||||
|
||||
JSObject *proto = current->getProto();
|
||||
|
||||
if (!proto)
|
||||
break;
|
||||
if (!proto->isNative())
|
||||
return false;
|
||||
|
||||
current = &proto->as<NativeObject>();
|
||||
}
|
||||
obj = obj->getProto();
|
||||
} while (obj);
|
||||
|
||||
*objp = nullptr;
|
||||
*propp = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
|
||||
Shape **propp)
|
||||
{
|
||||
return LookupPropertyPureInline(cx, obj, id, objp, propp);
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::reportReadOnly(JSContext *cx, jsid id, unsigned report)
|
||||
{
|
||||
|
@ -1226,7 +1226,7 @@ js_FindVariableScope(JSContext *cx, JSFunction **funp);
|
||||
namespace js {
|
||||
|
||||
bool
|
||||
LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
|
||||
LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, JSObject **objp,
|
||||
Shape **propp);
|
||||
|
||||
bool
|
||||
|
@ -559,7 +559,7 @@ js::proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
|
||||
return false;
|
||||
|
||||
if (found) {
|
||||
MarkNonNativePropertyFound(propp);
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
objp.set(obj);
|
||||
} else {
|
||||
objp.set(nullptr);
|
||||
|
@ -332,6 +332,7 @@ NativeObject::setLastProperty(ExclusiveContext *cx, HandleNativeObject obj, Hand
|
||||
MOZ_ASSERT(!shape->inDictionary());
|
||||
MOZ_ASSERT(shape->compartment() == obj->compartment());
|
||||
MOZ_ASSERT(shape->numFixedSlots() == obj->numFixedSlots());
|
||||
MOZ_ASSERT(shape->getObjectClass() == obj->getClass());
|
||||
|
||||
size_t oldSpan = obj->lastProperty()->slotSpan();
|
||||
size_t newSpan = shape->slotSpan();
|
||||
@ -355,6 +356,7 @@ NativeObject::setLastPropertyShrinkFixedSlots(Shape *shape)
|
||||
MOZ_ASSERT(!shape->inDictionary());
|
||||
MOZ_ASSERT(shape->compartment() == compartment());
|
||||
MOZ_ASSERT(lastProperty()->slotSpan() == shape->slotSpan());
|
||||
MOZ_ASSERT(shape->getObjectClass() == getClass());
|
||||
|
||||
DebugOnly<size_t> oldFixed = numFixedSlots();
|
||||
DebugOnly<size_t> newFixed = shape->numFixedSlots();
|
||||
@ -381,6 +383,30 @@ NativeObject::setLastPropertyMakeNonNative(Shape *shape)
|
||||
shape_ = shape;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
NativeObject::setLastPropertyMakeNative(ExclusiveContext *cx, HandleNativeObject obj,
|
||||
HandleShape shape)
|
||||
{
|
||||
MOZ_ASSERT(obj->getClass()->isNative());
|
||||
MOZ_ASSERT(!obj->lastProperty()->isNative());
|
||||
MOZ_ASSERT(shape->isNative());
|
||||
MOZ_ASSERT(!obj->inDictionaryMode());
|
||||
MOZ_ASSERT(!shape->inDictionary());
|
||||
MOZ_ASSERT(shape->compartment() == obj->compartment());
|
||||
|
||||
obj->shape_ = shape;
|
||||
obj->slots_ = nullptr;
|
||||
obj->elements_ = emptyObjectElements;
|
||||
|
||||
size_t oldSpan = shape->numFixedSlots();
|
||||
size_t newSpan = shape->slotSpan();
|
||||
|
||||
// A failures at this point will leave the object as a mutant, and we
|
||||
// can't recover.
|
||||
if (oldSpan != newSpan && !updateSlotsForSpan(cx, obj, oldSpan, newSpan))
|
||||
CrashAtUnhandlableOOM("NativeObject::setLastPropertyMakeNative");
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
NativeObject::setSlotSpan(ExclusiveContext *cx, HandleNativeObject obj, uint32_t span)
|
||||
{
|
||||
|
@ -417,6 +417,12 @@ class NativeObject : public JSObject
|
||||
// that are (temporarily) inconsistent.
|
||||
void setLastPropertyMakeNonNative(Shape *shape);
|
||||
|
||||
// As for setLastProperty(), but changes the class associated with the
|
||||
// object to a native one. The object's type has already been changed, and
|
||||
// this brings the shape into sync with it.
|
||||
static void setLastPropertyMakeNative(ExclusiveContext *cx, HandleNativeObject obj,
|
||||
HandleShape shape);
|
||||
|
||||
protected:
|
||||
#ifdef DEBUG
|
||||
void checkShapeConsistency();
|
||||
|
@ -1495,8 +1495,9 @@ template<> struct RootKind<BaseShape *> : SpecificRootKind<BaseShape *, THING_RO
|
||||
// properties of non-native objects, and dense elements for native objects.
|
||||
// Use separate APIs for these two cases.
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static inline void
|
||||
MarkNonNativePropertyFound(MutableHandleShape propp)
|
||||
MarkNonNativePropertyFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
|
||||
{
|
||||
propp.set(reinterpret_cast<Shape*>(1));
|
||||
}
|
||||
|
@ -196,15 +196,11 @@ UnboxedPlainObject::convertToNative(JSContext *cx)
|
||||
if (!SetClassAndProto(cx, obj, &PlainObject::class_, proto))
|
||||
return false;
|
||||
|
||||
// Any failures after this point will leave the object as a mutant, and we
|
||||
// can't recover.
|
||||
|
||||
RootedPlainObject nobj(cx, &obj->as<PlainObject>());
|
||||
if (!nobj->setLastProperty(cx, nobj, shape))
|
||||
CrashAtUnhandlableOOM("UnboxedPlainObject::convertToNative");
|
||||
RootedNativeObject nobj(cx, &obj->as<PlainObject>());
|
||||
NativeObject::setLastPropertyMakeNative(cx, nobj, shape);
|
||||
|
||||
for (size_t i = 0; i < values.length(); i++)
|
||||
nobj->initSlot(i, values[i]);
|
||||
nobj->initSlotUnchecked(i, values[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -250,7 +246,7 @@ UnboxedPlainObject::obj_lookupGeneric(JSContext *cx, HandleObject obj,
|
||||
MutableHandleShape propp)
|
||||
{
|
||||
if (obj->as<UnboxedPlainObject>().layout().lookup(id)) {
|
||||
MarkNonNativePropertyFound(propp);
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
@ -28,6 +28,12 @@ UnboxedTypeSize(JSValueType type)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
UnboxedTypeNeedsPreBarrier(JSValueType type)
|
||||
{
|
||||
return type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
// Class describing the layout of an UnboxedPlainObject.
|
||||
class UnboxedLayout
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user