Bug 787856 - Initial support for lazy prototypes (r=bhackett)

This commit is contained in:
Bill McCloskey 2012-09-26 09:49:20 -07:00
Родитель 800264a100
Коммит 7f9b2c5ac7
34 изменённых файлов: 531 добавлений и 281 удалений

Просмотреть файл

@ -889,7 +889,7 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
}
}
if (type->proto)
if (TaggedProto(type->proto).isObject())
PushMarkStack(gcmarker, type->proto);
if (type->singleton && !type->lazy())
@ -914,7 +914,7 @@ MarkChildren(JSTracer *trc, types::TypeObject *type)
MarkId(trc, &prop->id, "type_prop");
}
if (type->proto)
if (TaggedProto(type->proto).isObject())
MarkObject(trc, &type->proto, "type_proto");
if (type->singleton && !type->lazy())

Просмотреть файл

@ -12,6 +12,8 @@
#include "jsobj.h"
#include "jswrapper.h"
#include "jsobjinlines.h"
struct OuterWrapper : js::DirectWrapper
{
OuterWrapper() : DirectWrapper(0) {}

Просмотреть файл

@ -6,6 +6,8 @@
#include "jsobj.h"
#include "vm/String.h"
#include "jsobjinlines.h"
BEGIN_TEST(testConservativeGC)
{
#ifndef JSGC_USE_EXACT_ROOTING

Просмотреть файл

@ -1931,7 +1931,10 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *objArg, jsid id, JSBool *resolv
}
}
if (!stdnm && !obj->getProto()) {
RootedObject proto(cx);
if (!JSObject::getProto(cx, obj, &proto))
return false;
if (!stdnm && !proto) {
/*
* Try even less frequently used names delegated from the global
* object to Object.prototype, but only if the Object class hasn't
@ -3268,6 +3271,7 @@ JS_GetInstancePrivate(JSContext *cx, JSObject *objArg, JSClass *clasp, jsval *ar
JS_PUBLIC_API(JSObject *)
JS_GetPrototype(RawObject obj)
{
/* FIXME! */
return obj->getProto();
}

Просмотреть файл

@ -504,14 +504,16 @@ js::SetLengthProperty(JSContext *cx, HandleObject obj, double length)
static JSBool
array_length_getter(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValue vp)
{
JSObject *obj = obj_;
RootedObject obj(cx, obj_);
do {
if (obj->isArray()) {
vp.setNumber(obj->getArrayLength());
return JS_TRUE;
return true;
}
} while ((obj = obj->getProto()) != NULL);
return JS_TRUE;
if (!JSObject::getProto(cx, obj, &obj))
return false;
} while (obj);
return true;
}
static JSBool
@ -899,6 +901,8 @@ array_setSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
JSBool
js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
{
JS_ASSERT(obj->isDenseArray());
/*
* Walk up the prototype chain and see if this indexed element already
* exists. If we hit the end of the prototype chain, it's safe to set the
@ -3640,7 +3644,7 @@ NewArray(JSContext *cx, uint32_t length, RawObject protoArg)
* Get a shape with zero fixed slots, regardless of the size class.
* See JSObject::createDenseArray.
*/
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &ArrayClass, proto,
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &ArrayClass, TaggedProto(proto),
cx->global(), gc::FINALIZE_OBJECT0));
if (!shape)
return NULL;

Просмотреть файл

@ -312,7 +312,7 @@ class NewObjectCache
inline JSObject *newObjectFromHit(JSContext *cx, EntryIndex entry);
/* Fill an entry after a cache miss. */
inline void fillProto(EntryIndex entry, Class *clasp, JSObject *proto, gc::AllocKind kind, JSObject *obj);
inline void fillProto(EntryIndex entry, Class *clasp, js::TaggedProto proto, gc::AllocKind kind, JSObject *obj);
inline void fillGlobal(EntryIndex entry, Class *clasp, js::GlobalObject *global, gc::AllocKind kind, JSObject *obj);
inline void fillType(EntryIndex entry, Class *clasp, js::types::TypeObject *type, gc::AllocKind kind, JSObject *obj);

Просмотреть файл

@ -78,11 +78,11 @@ NewObjectCache::fill(EntryIndex entry_, Class *clasp, gc::Cell *key, gc::AllocKi
}
inline void
NewObjectCache::fillProto(EntryIndex entry, Class *clasp, JSObject *proto, gc::AllocKind kind, JSObject *obj)
NewObjectCache::fillProto(EntryIndex entry, Class *clasp, js::TaggedProto proto, gc::AllocKind kind, JSObject *obj)
{
JS_ASSERT(!proto->isGlobal());
JS_ASSERT(obj->getProto() == proto);
return fill(entry, clasp, proto, kind, obj);
JS_ASSERT_IF(proto.isObject(), !proto.toObject()->isGlobal());
JS_ASSERT(obj->getTaggedProto() == proto);
return fill(entry, clasp, proto.raw(), kind, obj);
}
inline void

Просмотреть файл

@ -64,7 +64,6 @@ JSCompartment::JSCompartment(JSRuntime *rt)
lastAnimationTime(0),
regExps(rt),
propertyTree(thisForCtor()),
emptyTypeObject(NULL),
gcMallocAndFreeBytes(0),
gcTriggerMallocAndFreeBytes(0),
gcMallocBytes(0),
@ -271,13 +270,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
if (vp->isObject()) {
RootedObject obj(cx, &vp->toObject());
JS_ASSERT(obj->isCrossCompartmentWrapper());
if (obj->getParent() != global) {
do {
if (!JSObject::setParent(cx, obj, global))
return false;
obj = obj->getProto();
} while (obj && obj->isCrossCompartmentWrapper());
}
JS_ASSERT(obj->getParent() == global);
}
return true;
}
@ -306,7 +299,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
* here (since Object.prototype->parent->proto leads to Object.prototype
* itself).
*/
RootedObject proto(cx, obj->getProto());
RootedObject proto(cx, obj->getTaggedProto().raw());
if (!wrap(cx, proto.address()))
return false;
@ -558,9 +551,6 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
sweepNewTypeObjectTable(newTypeObjects);
sweepNewTypeObjectTable(lazyTypeObjects);
if (emptyTypeObject && !IsTypeObjectMarked(emptyTypeObject.unsafeGet()))
emptyTypeObject = NULL;
sweepBreakpoints(fop);
if (global_ && !IsObjectMarked(&global_))

Просмотреть файл

@ -299,12 +299,10 @@ struct JSCompartment
js::types::TypeObjectSet lazyTypeObjects;
void sweepNewTypeObjectTable(js::types::TypeObjectSet &table);
js::ReadBarriered<js::types::TypeObject> emptyTypeObject;
js::types::TypeObject *getNewType(JSContext *cx, js::TaggedProto proto,
JSFunction *fun = NULL, bool isDOM = false);
/* Get the default 'new' type for objects with a NULL prototype. */
inline js::types::TypeObject *getEmptyType(JSContext *cx);
js::types::TypeObject *getLazyType(JSContext *cx, js::HandleObject proto);
js::types::TypeObject *getLazyType(JSContext *cx, js::Handle<js::TaggedProto> proto);
/*
* Keeps track of the total number of malloc bytes connected to a

Просмотреть файл

@ -97,7 +97,8 @@ JS_SplicePrototype(JSContext *cx, JSObject *objArg, JSObject *protoArg)
return JS_SetPrototype(cx, obj, proto);
}
return obj->splicePrototype(cx, proto);
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
return obj->splicePrototype(cx, tagged);
}
JS_FRIEND_API(JSObject *)
@ -538,6 +539,15 @@ JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallba
rt->telemetryCallback = callback;
}
JS_FRIEND_API(JSObject *)
JS_CloneObject(JSContext *cx, JSObject *obj_, JSObject *proto_, JSObject *parent_)
{
RootedObject obj(cx, obj_);
Rooted<js::TaggedProto> proto(cx, proto_);
RootedObject parent(cx, parent_);
return CloneObject(cx, obj, proto, parent);
}
#ifdef DEBUG
JS_FRIEND_API(void)
js_DumpString(JSString *str)

Просмотреть файл

@ -400,6 +400,7 @@ SetFunctionNativeReserved(RawObject fun, size_t which, const Value &val);
inline JSObject *
GetObjectProto(RawObject obj)
{
/* FIXME */
return reinterpret_cast<const shadow::Object*>(obj)->type->proto;
}

Просмотреть файл

@ -74,9 +74,10 @@ using namespace js::frontend;
static JSBool
fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValue vp)
{
JSObject *obj = obj_;
RootedObject obj(cx, obj_);
while (!obj->isFunction()) {
obj = obj->getProto();
if (!JSObject::getProto(cx, obj, &obj))
return false;
if (!obj)
return true;
}
@ -483,7 +484,7 @@ fun_hasInstance(JSContext *cx, HandleObject objArg, MutableHandleValue v, JSBool
RootedValue pval(cx);
if (!JSObject::getProperty(cx, obj, obj, cx->names().classPrototype, &pval))
return JS_FALSE;
return false;
if (pval.isPrimitive()) {
/*
@ -492,11 +493,15 @@ fun_hasInstance(JSContext *cx, HandleObject objArg, MutableHandleValue v, JSBool
*/
RootedValue val(cx, ObjectValue(*obj));
js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, NullPtr());
return JS_FALSE;
return false;
}
*bp = js_IsDelegate(cx, &pval.toObject(), v);
return JS_TRUE;
RootedObject pobj(cx, &pval.toObject());
bool isDelegate;
if (!IsDelegate(cx, pobj, v, &isDelegate))
return false;
*bp = isDelegate;
return true;
}
inline void
@ -1587,6 +1592,7 @@ js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
#ifdef DEBUG
if (thisv.isObject()) {
JS_ASSERT(thisv.toObject().getClass() != clasp ||
!thisv.toObject().isNative() ||
!thisv.toObject().getProto() ||
thisv.toObject().getProto()->getClass() != clasp);
} else if (thisv.isString()) {

Просмотреть файл

@ -154,6 +154,7 @@ IsNativeFunction(const js::Value &v, JSNative native)
static JS_ALWAYS_INLINE bool
ClassMethodIsNative(JSContext *cx, HandleObject obj, Class *clasp, HandleId methodid, JSNative native)
{
JS_ASSERT(!obj->isProxy());
JS_ASSERT(obj->getClass() == clasp);
Value v;

Просмотреть файл

@ -1848,17 +1848,17 @@ StackTypeSet::getTypedArrayType()
unsigned count = getObjectCount();
for (unsigned i = 0; i < count; i++) {
RawObject proto = NULL;
TaggedProto proto;
if (RawObject object = getSingleObject(i)) {
proto = object->getProto();
proto = object->getTaggedProto();
} else if (TypeObject *object = getTypeObject(i)) {
JS_ASSERT(!object->hasAnyFlags(OBJECT_FLAG_NON_TYPED_ARRAY));
proto = object->proto;
proto = TaggedProto(object->proto);
}
if (!proto)
if (!proto.isObject())
continue;
int objArrayType = proto->getClass() - TypedArray::protoClasses;
int objArrayType = proto.toObject()->getClass() - TypedArray::protoClasses;
JS_ASSERT(objArrayType >= 0 && objArrayType < TypedArray::TYPE_MAX);
/*
@ -2063,10 +2063,10 @@ TypeCompartment::init(JSContext *cx)
}
TypeObject *
TypeCompartment::newTypeObject(JSContext *cx, JSProtoKey key, HandleObject proto,
TypeCompartment::newTypeObject(JSContext *cx, JSProtoKey key, Handle<TaggedProto> proto,
bool unknown, bool isDOM)
{
JS_ASSERT_IF(proto, cx->compartment == proto->compartment());
JS_ASSERT_IF(proto.isObject(), cx->compartment == proto.toObject()->compartment());
TypeObject *object = gc::NewGCThing<TypeObject>(cx, gc::FINALIZE_TYPE_OBJECT, sizeof(TypeObject));
if (!object)
@ -2219,7 +2219,8 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
return NULL;
RootedScript keyScript(cx, key.script);
res = newTypeObject(cx, key.kind, proto);
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
res = newTypeObject(cx, key.kind, tagged);
if (!res) {
cx->compartment->types.setPendingNukeTypes(cx);
return NULL;
@ -2891,20 +2892,20 @@ struct types::ObjectTableKey
jsid *ids;
uint32_t nslots;
uint32_t nfixed;
JSObject *proto;
TaggedProto proto;
typedef JSObject * Lookup;
static inline uint32_t hash(JSObject *obj) {
return (uint32_t) (JSID_BITS(obj->lastProperty()->propid().get()) ^
obj->slotSpan() ^ obj->numFixedSlots() ^
((uint32_t)(size_t)obj->getProto() >> 2));
((uint32_t)obj->getTaggedProto().toWord() >> 2));
}
static inline bool match(const ObjectTableKey &v, JSObject *obj) {
if (obj->slotSpan() != v.nslots ||
obj->numFixedSlots() != v.nfixed ||
obj->getProto() != v.proto) {
obj->getTaggedProto() != v.proto) {
return false;
}
Shape *shape = obj->lastProperty();
@ -2982,7 +2983,7 @@ TypeCompartment::fixObjectType(JSContext *cx, HandleObject obj)
obj->setType(p->value.object);
} else {
/* Make a new type to use for the object and similar future ones. */
RootedObject objProto(cx, obj->getProto());
Rooted<TaggedProto> objProto(cx, obj->getTaggedProto());
TypeObject *objType = newTypeObject(cx, JSProto_Object, objProto);
if (!objType || !objType->addDefiniteProperties(cx, obj)) {
cx->compartment->types.setPendingNukeTypes(cx);
@ -3016,7 +3017,7 @@ TypeCompartment::fixObjectType(JSContext *cx, HandleObject obj)
key.ids = ids;
key.nslots = obj->slotSpan();
key.nfixed = obj->numFixedSlots();
key.proto = obj->getProto();
key.proto = obj->getTaggedProto();
JS_ASSERT(ObjectTableKey::match(key, obj.get()));
ObjectTableEntry entry;
@ -3048,6 +3049,11 @@ TypeObject::getFromPrototypes(JSContext *cx, jsid id, TypeSet *types, bool force
if (!proto)
return;
if (proto == Proxy::LazyProto) {
JS_ASSERT(unknownProperties());
return;
}
if (proto->getType(cx)->unknownProperties()) {
types->addType(cx, Type::UnknownType());
return;
@ -5585,7 +5591,7 @@ JSObject::shouldSplicePrototype(JSContext *cx)
}
bool
JSObject::splicePrototype(JSContext *cx, HandleObject proto)
JSObject::splicePrototype(JSContext *cx, Handle<TaggedProto> proto)
{
JS_ASSERT(cx->compartment == compartment());
@ -5600,7 +5606,7 @@ JSObject::splicePrototype(JSContext *cx, HandleObject proto)
JS_ASSERT_IF(cx->typeInferenceEnabled(), self->hasSingletonType());
/* Inner objects may not appear on prototype chains. */
JS_ASSERT_IF(proto, !proto->getClass()->ext.outerObject);
JS_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject);
/*
* Force type instantiation when splicing lazy types. This may fail,
@ -5608,21 +5614,21 @@ JSObject::splicePrototype(JSContext *cx, HandleObject proto)
*/
Rooted<TypeObject*> type(cx, self->getType(cx));
Rooted<TypeObject*> protoType(cx, NULL);
if (proto) {
protoType = proto->getType(cx);
if (!proto->getNewType(cx))
if (proto.isObject()) {
protoType = proto.toObject()->getType(cx);
if (!proto.toObject()->getNewType(cx))
return false;
}
if (!cx->typeInferenceEnabled()) {
TypeObject *type = proto ? proto->getNewType(cx) : cx->compartment->getEmptyType(cx);
TypeObject *type = cx->compartment->getNewType(cx, proto);
if (!type)
return false;
self->type_ = type;
return true;
}
type->proto = proto;
type->proto = proto.raw();
AutoEnterTypeInference enter(cx);
@ -5652,7 +5658,7 @@ JSObject::makeLazyType(JSContext *cx)
RootedObject self(cx, this);
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(getClass());
RootedObject proto(cx, getProto());
Rooted<TaggedProto> proto(cx, getTaggedProto());
TypeObject *type = cx->compartment->types.newTypeObject(cx, key, proto);
AutoAssertNoGC nogc;
if (!type) {
@ -5712,15 +5718,15 @@ JSObject::makeLazyType(JSContext *cx)
}
/* static */ inline HashNumber
TypeObjectEntry::hash(RawObject proto)
TypeObjectEntry::hash(TaggedProto proto)
{
return PointerHasher<JSObject *, 3>::hash(proto);
return PointerHasher<JSObject *, 3>::hash(proto.raw());
}
/* static */ inline bool
TypeObjectEntry::match(TypeObject *key, RawObject lookup)
TypeObjectEntry::match(TypeObject *key, TaggedProto lookup)
{
return key->proto == lookup;
return key->proto == lookup.raw();
}
#ifdef DEBUG
@ -5758,16 +5764,15 @@ JSObject::setNewTypeUnknown(JSContext *cx)
}
TypeObject *
JSObject::getNewType(JSContext *cx, JSFunction *fun_, bool isDOM)
JSCompartment::getNewType(JSContext *cx, TaggedProto proto_, JSFunction *fun_, bool isDOM)
{
JS_ASSERT(cx->compartment == compartment());
JS_ASSERT_IF(fun_, proto_.isObject());
JS_ASSERT_IF(proto_.isObject(), cx->compartment == proto_.toObject()->compartment());
TypeObjectSet &table = cx->compartment->newTypeObjects;
if (!table.initialized() && !table.init())
if (!newTypeObjects.initialized() && !newTypeObjects.init())
return NULL;
TypeObjectSet::AddPtr p = table.lookupForAdd(this);
TypeObjectSet::AddPtr p = newTypeObjects.lookupForAdd(proto_);
if (p) {
TypeObject *type = *p;
@ -5791,20 +5796,23 @@ JSObject::getNewType(JSContext *cx, JSFunction *fun_, bool isDOM)
return type;
}
RootedObject self(cx, this);
RootedFunction fun(cx, fun_);
Rooted<TaggedProto> proto(cx, proto_);
if (!setDelegate(cx))
if (proto.isObject() && !proto.toObject()->setDelegate(cx))
return NULL;
bool markUnknown = self->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN);
bool markUnknown =
proto.isObject()
? proto.toObject()->lastProperty()->hasObjectFlag(BaseShape::NEW_TYPE_UNKNOWN)
: true;
RootedTypeObject type(cx);
type = cx->compartment->types.newTypeObject(cx, JSProto_Object, self, markUnknown, isDOM);
type = types.newTypeObject(cx, JSProto_Object, proto, markUnknown, isDOM);
if (!type)
return NULL;
if (!table.relookupOrAdd(p, self, type.get()))
if (!newTypeObjects.relookupOrAdd(p, proto, type.get()))
return NULL;
if (!cx->typeInferenceEnabled())
@ -5817,20 +5825,21 @@ JSObject::getNewType(JSContext *cx, JSFunction *fun_, bool isDOM)
* flag set. This is a hack, :XXX: need a real correspondence between
* types and the possible js::Class of objects with that type.
*/
if (self->hasSpecialEquality())
type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
if (proto.isObject()) {
JSObject *obj = proto.toObject();
if (fun)
CheckNewScriptProperties(cx, type, fun);
if (obj->hasSpecialEquality())
type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
if (fun)
CheckNewScriptProperties(cx, type, fun);
#if JS_HAS_XML_SUPPORT
/* Special case for XML object equality, see makeLazyType(). */
if (self->isXML() && !type->unknownProperties())
type->flags |= OBJECT_FLAG_UNKNOWN_MASK;
/* Special case for XML object equality, see makeLazyType(). */
if (obj->isXML() && !type->unknownProperties())
type->flags |= OBJECT_FLAG_UNKNOWN_MASK;
#endif
if (self->getClass()->ext.equality)
type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
}
/*
* The new type is not present in any type sets, so mark the object as
@ -5847,10 +5856,16 @@ JSObject::getNewType(JSContext *cx, JSFunction *fun_, bool isDOM)
}
TypeObject *
JSCompartment::getLazyType(JSContext *cx, HandleObject proto)
JSObject::getNewType(JSContext *cx, JSFunction *fun_, bool isDOM)
{
return cx->compartment->getNewType(cx, this, fun_, isDOM);
}
TypeObject *
JSCompartment::getLazyType(JSContext *cx, Handle<TaggedProto> proto)
{
JS_ASSERT(cx->compartment == this);
JS_ASSERT_IF(proto, cx->compartment == proto->compartment());
JS_ASSERT_IF(proto.isObject(), cx->compartment == proto.toObject()->compartment());
MaybeCheckStackRoots(cx);
@ -6087,7 +6102,7 @@ TypeCompartment::sweep(FreeOp *fop)
for (ObjectTypeTable::Enum e(*objectTypeTable); !e.empty(); e.popFront()) {
const ObjectTableKey &key = e.front().key;
ObjectTableEntry &entry = e.front().value;
JS_ASSERT(entry.object->proto == key.proto);
JS_ASSERT(uintptr_t(entry.object->proto.get()) == key.proto.toWord());
bool remove = false;
if (!IsTypeObjectMarked(entry.object.unsafeGet()))

Просмотреть файл

@ -27,6 +27,89 @@ struct TypeInferenceSizes;
namespace js {
class TaggedProto
{
public:
TaggedProto() : proto(NULL) {}
TaggedProto(JSObject *proto) : proto(proto) {}
uintptr_t toWord() const { return uintptr_t(proto); }
inline bool isLazy() const;
inline bool isObject() const;
inline JSObject *toObject() const;
inline JSObject *toObjectOrNull() const;
JSObject *raw() const { return proto; }
bool operator ==(const TaggedProto &other) { return proto == other.proto; }
bool operator !=(const TaggedProto &other) { return proto != other.proto; }
private:
JSObject *proto;
};
} /* namespace js */
namespace JS {
template <>
struct RootKind<js::TaggedProto>
{
static ThingRootKind rootKind() { return THING_ROOT_OBJECT; };
};
template <> struct RootMethods<const js::TaggedProto>
{
static js::TaggedProto initial() { return js::TaggedProto(); }
static ThingRootKind kind() { return THING_ROOT_OBJECT; }
static bool poisoned(const js::TaggedProto &v) { return IsPoisonedPtr(v.raw()); }
};
template <> struct RootMethods<js::TaggedProto>
{
static js::TaggedProto initial() { return js::TaggedProto(); }
static ThingRootKind kind() { return THING_ROOT_OBJECT; }
static bool poisoned(const js::TaggedProto &v) { return IsPoisonedPtr(v.raw()); }
};
template<class Outer>
class TaggedProtoOperations
{
const js::TaggedProto *value() const {
return static_cast<const Outer*>(this)->extract();
}
public:
uintptr_t toWord() const { return value()->toWord(); }
inline bool isLazy() const;
inline bool isObject() const;
inline JSObject *toObject() const;
inline JSObject *toObjectOrNull() const;
JSObject *raw() const { return value()->raw(); }
};
template <>
class HandleBase<js::TaggedProto> : public TaggedProtoOperations<Handle<js::TaggedProto> >
{
friend class TaggedProtoOperations<Handle<js::TaggedProto> >;
const js::TaggedProto * extract() const {
return static_cast<const Handle<js::TaggedProto>*>(this)->address();
}
};
template <>
class RootedBase<js::TaggedProto> : public TaggedProtoOperations<Rooted<js::TaggedProto> >
{
friend class TaggedProtoOperations<Rooted<js::TaggedProto> >;
const js::TaggedProto *extract() const {
return static_cast<const Rooted<js::TaggedProto> *>(this)->address();
}
};
} /* namespace JS */
namespace js {
class CallObject;
namespace mjit {
@ -874,7 +957,7 @@ struct TypeObject : gc::Cell
void *padding;
#endif
inline TypeObject(RawObject proto, bool isFunction, bool unknown);
inline TypeObject(TaggedProto proto, bool isFunction, bool unknown);
bool isFunction() { return !!(flags & OBJECT_FLAG_FUNCTION); }
@ -970,10 +1053,10 @@ struct TypeObject : gc::Cell
*/
struct TypeObjectEntry
{
typedef JSObject *Lookup;
typedef TaggedProto Lookup;
static inline HashNumber hash(RawObject base);
static inline bool match(TypeObject *key, RawObject lookup);
static inline HashNumber hash(TaggedProto base);
static inline bool match(TypeObject *key, TaggedProto lookup);
};
typedef HashSet<ReadBarriered<TypeObject>, TypeObjectEntry, SystemAllocPolicy> TypeObjectSet;
@ -1258,7 +1341,7 @@ struct TypeCompartment
* or JSProto_Object to indicate a type whose class is unknown (not just
* js_ObjectClass).
*/
TypeObject *newTypeObject(JSContext *cx, JSProtoKey kind, HandleObject proto,
TypeObject *newTypeObject(JSContext *cx, JSProtoKey kind, Handle<TaggedProto> proto,
bool unknown = false, bool isDOM = false);
/* Get or make an object for an allocation site, and add to the allocation site table. */

Просмотреть файл

@ -21,6 +21,61 @@
#ifndef jsinferinlines_h___
#define jsinferinlines_h___
inline bool
js::TaggedProto::isObject() const
{
/* Skip NULL and Proxy::LazyProto. */
return uintptr_t(proto) > uintptr_t(Proxy::LazyProto);
}
inline bool
js::TaggedProto::isLazy() const
{
return proto == Proxy::LazyProto;
}
inline JSObject *
js::TaggedProto::toObject() const
{
JS_ASSERT(isObject());
return proto;
}
inline JSObject *
js::TaggedProto::toObjectOrNull() const
{
JS_ASSERT(!proto || isObject());
return proto;
}
template<class Outer>
inline bool
JS::TaggedProtoOperations<Outer>::isLazy() const
{
return value()->isLazy();
}
template<class Outer>
inline bool
JS::TaggedProtoOperations<Outer>::isObject() const
{
return value()->isObject();
}
template<class Outer>
inline JSObject *
JS::TaggedProtoOperations<Outer>::toObject() const
{
return value()->toObject();
}
template<class Outer>
inline JSObject *
JS::TaggedProtoOperations<Outer>::toObjectOrNull() const
{
return value()->toObjectOrNull();
}
namespace js {
namespace types {
@ -1400,14 +1455,14 @@ TypeCallsite::TypeCallsite(JSContext *cx, JSScript *script, jsbytecode *pc,
// TypeObject
/////////////////////////////////////////////////////////////////////
inline TypeObject::TypeObject(RawObject proto, bool function, bool unknown)
inline TypeObject::TypeObject(TaggedProto proto, bool function, bool unknown)
{
PodZero(this);
/* Inner objects may not appear on prototype chains. */
JS_ASSERT_IF(proto, !proto->getClass()->ext.outerObject);
JS_ASSERT_IF(proto.isObject(), !proto.toObject()->getClass()->ext.outerObject);
this->proto = proto;
this->proto = proto.raw();
if (function)
flags |= OBJECT_FLAG_FUNCTION;
@ -1686,17 +1741,6 @@ js::analyze::ScriptAnalysis::addPushedType(JSContext *cx, uint32_t offset, uint3
pushed->addType(cx, type);
}
inline js::types::TypeObject *
JSCompartment::getEmptyType(JSContext *cx)
{
JS::MaybeCheckStackRoots(cx);
if (!emptyTypeObject) {
JS::RootedObject nullproto(cx, NULL);
emptyTypeObject = types.newTypeObject(cx, JSProto_Object, nullproto, true);
}
return emptyTypeObject;
}
namespace JS {

Просмотреть файл

@ -102,7 +102,7 @@ Enumerate(JSContext *cx, HandleObject pobj, jsid id,
* the built-in prototypes). So exclude __proto__ if the object where the
* property was found has no [[Prototype]] and might be |Object.prototype|.
*/
if (JS_UNLIKELY(!pobj->getProto() && JSID_IS_ATOM(id, cx->names().proto)))
if (JS_UNLIKELY(!pobj->getTaggedProto().isObject() && JSID_IS_ATOM(id, cx->names().proto)))
return true;
if (!(flags & JSITER_OWNONLY) || pobj->isProxy() || pobj->getOps()->enumerate) {
@ -116,7 +116,7 @@ Enumerate(JSContext *cx, HandleObject pobj, jsid id,
* the prototype chain, but custom enumeration behaviors might return
* duplicated properties, so always add in such cases.
*/
if ((pobj->getProto() || pobj->isProxy() || pobj->getOps()->enumerate) && !ht.add(p, id))
if ((pobj->isProxy() || pobj->getProto() || pobj->getOps()->enumerate) && !ht.add(p, id))
return false;
}
@ -404,7 +404,7 @@ static inline PropertyIteratorObject *
NewPropertyIteratorObject(JSContext *cx, unsigned flags)
{
if (flags & JSITER_ENUMERATE) {
RootedTypeObject type(cx, cx->compartment->getEmptyType(cx));
RootedTypeObject type(cx, cx->compartment->getNewType(cx, NULL));
if (!type)
return NULL;
@ -627,18 +627,21 @@ GetIterator(JSContext *cx, HandleObject obj, unsigned flags, MutableHandleValue
*/
PropertyIteratorObject *last = cx->runtime->nativeIterCache.last;
if (last) {
RawObject proto = obj->getProto();
NativeIterator *lastni = last->getNativeIterator();
if (!(lastni->flags & (JSITER_ACTIVE|JSITER_UNREUSABLE)) &&
obj->isNative() &&
obj->lastProperty() == lastni->shapes_array[0] &&
proto && proto->isNative() &&
proto->lastProperty() == lastni->shapes_array[1] &&
!proto->getProto()) {
vp.setObject(*last);
UpdateNativeIterator(lastni, obj);
RegisterEnumerator(cx, last, lastni);
return true;
obj->lastProperty() == lastni->shapes_array[0])
{
JSObject *proto = obj->getProto();
if (proto->isNative() &&
proto->lastProperty() == lastni->shapes_array[1] &&
!proto->getProto())
{
vp.setObject(*last);
UpdateNativeIterator(lastni, obj);
RegisterEnumerator(cx, last, lastni);
return true;
}
}
}
@ -1093,8 +1096,11 @@ SuppressDeletedPropertyHelper(JSContext *cx, HandleObject obj, StringPredicate p
* Check whether another property along the prototype chain
* became visible as a result of this deletion.
*/
if (obj->getProto()) {
RootedObject proto(cx, obj->getProto()), obj2(cx);
RootedObject proto(cx);
if (!JSObject::getProto(cx, obj, &proto))
return false;
if (proto) {
RootedObject obj2(cx);
RootedShape prop(cx);
RootedId id(cx);
if (!ValueToId(cx, StringValue(*idp), id.address()))

Просмотреть файл

@ -565,7 +565,10 @@ obj_isPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
return false;
/* Step 3. */
args.rval().setBoolean(js_IsDelegate(cx, obj, args[0]));
bool isDelegate;
if (!IsDelegate(cx, obj, args[0], &isDelegate))
return false;
args.rval().setBoolean(isDelegate);
return true;
}
@ -1895,7 +1898,7 @@ JSObject::sealOrFreeze(JSContext *cx, HandleObject obj, ImmutabilityType it)
* dictionary mode.
*/
Shape *last = EmptyShape::getInitialShape(cx, obj->getClass(),
obj->getProto(),
obj->getTaggedProto(),
obj->getParent(),
obj->getAllocKind(),
obj->lastProperty()->getObjectFlags());
@ -2120,7 +2123,8 @@ NewObject(JSContext *cx, Class *clasp, types::TypeObject *type_, JSObject *paren
RootedTypeObject type(cx, type_);
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, type->proto, parent, kind));
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(type->proto),
parent, kind));
if (!shape)
return NULL;
@ -2146,10 +2150,12 @@ NewObject(JSContext *cx, Class *clasp, types::TypeObject *type_, JSObject *paren
}
JSObject *
js::NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto_, JSObject *parent_,
js::NewObjectWithGivenProto(JSContext *cx, js::Class *clasp,
js::TaggedProto proto_, JSObject *parent_,
gc::AllocKind kind)
{
RootedObject proto(cx, proto_), parent(cx, parent_);
Rooted<TaggedProto> proto(cx, proto_);
RootedObject parent(cx, parent_);
if (CanBeFinalizedInBackground(kind, clasp))
kind = GetBackgroundAllocKind(kind);
@ -2157,8 +2163,10 @@ js::NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto_, J
NewObjectCache &cache = cx->runtime->newObjectCache;
NewObjectCache::EntryIndex entry = -1;
if (proto && (!parent || parent == proto->getParent()) && !proto->isGlobal()) {
if (cache.lookupProto(clasp, proto, kind, &entry)) {
if (proto.isObject() &&
(!parent || parent == proto.toObject()->getParent()) && !proto.toObject()->isGlobal())
{
if (cache.lookupProto(clasp, proto.toObject(), kind, &entry)) {
JSObject *obj = cache.newObjectFromHit(cx, entry);
if (obj)
return obj;
@ -2166,8 +2174,7 @@ js::NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto_, J
}
bool isDOM = (clasp->flags & JSCLASS_IS_DOMJSCLASS);
types::TypeObject *type = proto ? proto->getNewType(cx, NULL, isDOM)
: cx->compartment->getEmptyType(cx);
types::TypeObject *type = cx->compartment->getNewType(cx, proto, NULL, isDOM);
if (!type)
return NULL;
@ -2175,8 +2182,8 @@ js::NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto_, J
* Default parent to the parent of the prototype, which was set from
* the parent of the prototype's constructor.
*/
if (!parent && proto)
parent = proto->getParent();
if (!parent && proto.isObject())
parent = proto.toObject()->getParent();
JSObject *obj = NewObject(cx, clasp, type, parent, kind);
if (!obj)
@ -2590,13 +2597,9 @@ CopySlots(JSContext *cx, JSObject *from, JSObject *to)
return true;
}
JS_FRIEND_API(JSObject *)
JS_CloneObject(JSContext *cx, JSObject *obj_, JSObject *proto_, JSObject *parent_)
JSObject *
js::CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto, HandleObject parent)
{
RootedObject obj(cx, obj_);
RootedObject proto(cx, proto_);
RootedObject parent(cx, parent_);
/*
* We can only clone native objects and proxies. Dense arrays are slowified if
* we try to clone them.
@ -2611,7 +2614,8 @@ JS_CloneObject(JSContext *cx, JSObject *obj_, JSObject *proto_, JSObject *parent
return NULL;
}
}
JSObject *clone = NewObjectWithGivenProto(cx, obj->getClass(), proto, parent, obj->getAllocKind());
JSObject *clone = NewObjectWithGivenProto(cx, obj->getClass(),
proto, parent, obj->getAllocKind());
if (!clone)
return NULL;
if (obj->isNative()) {
@ -2676,7 +2680,10 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
* Swap prototypes on the two objects, so that TradeGuts can preserve
* the types of the two objects.
*/
RootedObject na(cx, a), aProto(cx, a->getProto()), nb(cx, b), bProto(cx, b->getProto());
RootedObject na(cx, a);
RootedObject nb(cx, b);
Rooted<TaggedProto> aProto(cx, a->getTaggedProto());
Rooted<TaggedProto> bProto(cx, b->getTaggedProto());
if (!SetProto(cx, na, bProto, false) || !SetProto(cx, nb, aProto, false))
return false;
@ -2694,7 +2701,7 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
return false;
} else {
reserved.newbshape = EmptyShape::getInitialShape(cx, a->getClass(),
a->getProto(), a->getParent(),
a->getTaggedProto(), a->getParent(),
b->getAllocKind());
if (!reserved.newbshape)
return false;
@ -2704,7 +2711,7 @@ JSObject::ReserveForTradeGuts(JSContext *cx, JSObject *a, JSObject *b,
return false;
} else {
reserved.newashape = EmptyShape::getInitialShape(cx, b->getClass(),
b->getProto(), b->getParent(),
b->getTaggedProto(), b->getParent(),
a->getAllocKind());
if (!reserved.newashape)
return false;
@ -2906,8 +2913,11 @@ JSObject::TradeGuts(JSContext *cx, JSObject *a, JSObject *b, TradeGutsReserved &
/* Use this method with extreme caution. It trades the guts of two objects. */
bool
JSObject::swap(JSContext *cx, JSObject *other)
JSObject::swap(JSContext *cx, JSObject *other_)
{
RootedObject self(cx, this);
RootedObject other(cx, other_);
// Ensure swap doesn't cause a finalizer to not be run.
JS_ASSERT(IsBackgroundFinalized(getAllocKind()) ==
IsBackgroundFinalized(other->getAllocKind()));
@ -3082,7 +3092,8 @@ DefineConstructorAndPrototype(JSContext *cx, HandleObject obj, JSProtoKey key, H
goto bad;
/* Bootstrap Function.prototype (see also JS_InitStandardClasses). */
if (ctor->getClass() == clasp && !ctor->splicePrototype(cx, proto))
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
if (ctor->getClass() == clasp && !ctor->splicePrototype(cx, tagged))
goto bad;
}
@ -3488,12 +3499,12 @@ static JSClassInitializerOp lazy_prototype_init[JSProto_LIMIT] = {
namespace js {
bool
SetProto(JSContext *cx, HandleObject obj, HandleObject proto, bool checkForCycles)
SetProto(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto, bool checkForCycles)
{
JS_ASSERT_IF(!checkForCycles, obj != proto);
JS_ASSERT_IF(!checkForCycles, obj.get() != proto.raw());
#if JS_HAS_XML_SUPPORT
if (proto && proto->isXML()) {
if (proto.isObject() && proto.toObject()->isXML()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_XML_PROTO_FORBIDDEN);
return false;
}
@ -3531,12 +3542,17 @@ SetProto(JSContext *cx, HandleObject obj, HandleObject proto, bool checkForCycle
}
if (checkForCycles) {
for (JSObject *obj2 = proto; obj2; obj2 = obj2->getProto()) {
JS_ASSERT(!proto.isLazy());
RootedObject obj2(cx);
for (obj2 = proto.toObjectOrNull(); obj2; ) {
if (obj2 == obj) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CYCLIC_VALUE,
js_proto_str);
return false;
}
if (!JSObject::getProto(cx, obj2, &obj2))
return false;
}
}
@ -3551,12 +3567,10 @@ SetProto(JSContext *cx, HandleObject obj, HandleObject proto, bool checkForCycle
return true;
}
if (proto && !proto->setNewTypeUnknown(cx))
if (proto.isObject() && !proto.toObject()->setNewTypeUnknown(cx))
return false;
TypeObject *type = proto
? proto->getNewType(cx, NULL)
: cx->compartment->getEmptyType(cx);
TypeObject *type = cx->compartment->getNewType(cx, proto);
if (!type)
return false;
@ -3753,10 +3767,10 @@ PurgeProtoChain(JSContext *cx, JSObject *obj_, jsid id_)
RootedId id(cx, id_);
while (obj) {
if (!obj->isNative()) {
obj = obj->getProto();
continue;
}
/* Lookups will not be cached through non-native protos. */
if (!obj->isNative())
break;
shape = obj->nativeLookup(cx, id);
if (shape) {
if (!obj->shadowingShapeChange(cx, *shape))
@ -3777,6 +3791,7 @@ js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj_, jsid id_)
RootedObject obj(cx, obj_);
RootedId id(cx, id_);
JS_ASSERT(obj->isNative());
JS_ASSERT(obj->isDelegate());
PurgeProtoChain(cx, obj->getProto(), id);
@ -4080,27 +4095,14 @@ LookupPropertyWithFlagsInline(JSContext *cx, HandleObject obj, HandleId id, unsi
}
}
RootedObject proto(cx, current->getProto());
RootedObject proto(cx);
if (!JSObject::getProto(cx, current, &proto))
return false;
if (!proto)
break;
if (!proto->isNative()) {
if (!JSObject::lookupGeneric(cx, proto, id, objp, propp))
return false;
#ifdef DEBUG
/*
* Non-native objects must have either non-native lookup results,
* or else native results from the non-native's prototype chain.
*
* See StackFrame::getValidCalleeObject, where we depend on this
* fact to force a prototype-delegated joined method accessed via
* arguments.callee through the delegating |this| object's method
* read barrier.
*/
if (propp && objp->isNative()) {
while ((proto = proto->getProto()) != objp)
JS_ASSERT(proto);
}
#endif
return true;
}
@ -4965,8 +4967,12 @@ CheckAccess(JSContext *cx, JSObject *obj_, HandleId id, JSAccessMode mode,
switch (mode & JSACC_TYPEMASK) {
case JSACC_PROTO:
pobj = obj;
if (!writing)
vp.setObjectOrNull(obj->getProto());
if (!writing) {
RootedObject proto(cx);
if (!JSObject::getProto(cx, obj, &proto))
return JS_FALSE;
vp.setObjectOrNull(proto);
}
*attrsp = JSPROP_PERMANENT;
break;
@ -5028,16 +5034,25 @@ baseops::TypeOf(JSContext *cx, HandleObject obj)
}
bool
js_IsDelegate(JSContext *cx, JSObject *obj, const Value &v)
js::IsDelegate(JSContext *cx, HandleObject obj, const js::Value &v, bool *result)
{
if (v.isPrimitive())
return false;
JSObject *obj2 = &v.toObject();
while ((obj2 = obj2->getProto()) != NULL) {
if (obj2 == obj)
return true;
if (v.isPrimitive()) {
*result = false;
return true;
}
RootedObject obj2(cx, &v.toObject());
for (;;) {
if (!JSObject::getProto(cx, obj2, &obj2))
return false;
if (!obj2) {
*result = false;
return true;
}
if (obj2 == obj) {
*result = true;
return true;
}
}
return false;
}
/*
@ -5365,7 +5380,11 @@ JSObject::dump()
}
fprintf(stderr, "proto ");
dumpValue(ObjectOrNullValue(obj->getProto()));
TaggedProto proto = obj->getTaggedProto();
if (proto.isLazy())
fprintf(stderr, "<lazy>");
else
dumpValue(ObjectOrNullValue(proto.toObjectOrNull()));
fputc('\n', stderr);
fprintf(stderr, "parent ");

Просмотреть файл

@ -437,6 +437,23 @@ struct JSObject : public js::ObjectImpl
return type_;
}
/*
* We allow the prototype of an object to be lazily computed if the object
* is a proxy. In the lazy case, we store (JSObject *)0x1 in the proto field
* of the object's TypeObject. We offer three ways of getting the prototype:
*
* 1. obj->getProto() returns the prototype, but asserts if obj is a proxy.
* 2. obj->getTaggedProto() returns a TaggedProto, which can be tested to
* check if the proto is an object, NULL, or lazily computed.
* 3. JSObject::getProto(cx, obj, &proto) computes the proto of an object.
* If obj is a proxy and the proto is lazy, this code may allocate or
* GC in order to compute the proto. Currently, it will not run JS code.
*/
inline JSObject *getProto() const;
inline js::TaggedProto getTaggedProto() const;
static inline bool getProto(JSContext *cx, js::HandleObject obj,
js::MutableHandleObject protop);
inline void setType(js::types::TypeObject *newType);
js::types::TypeObject *getNewType(JSContext *cx, JSFunction *fun = NULL,
@ -460,7 +477,7 @@ struct JSObject : public js::ObjectImpl
bool setNewTypeUnknown(JSContext *cx);
/* Set a new prototype for an object with a singleton type. */
bool splicePrototype(JSContext *cx, js::HandleObject proto);
bool splicePrototype(JSContext *cx, js::Handle<js::TaggedProto> proto);
/*
* For bootstrapping, whether to splice a prototype for Function.prototype
@ -1167,6 +1184,9 @@ js_DefineOwnProperty(JSContext *cx, js::HandleObject obj, js::HandleId id,
namespace js {
JSObject *
CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto, HandleObject parent);
/*
* Flags for the defineHow parameter of js_DefineNativeProperty.
*/
@ -1324,10 +1344,10 @@ extern JSBool
CheckAccess(JSContext *cx, JSObject *obj, HandleId id, JSAccessMode mode,
MutableHandleValue v, unsigned *attrsp);
} /* namespace js */
extern bool
js_IsDelegate(JSContext *cx, JSObject *obj, const js::Value &v);
IsDelegate(JSContext *cx, HandleObject obj, const Value &v, bool *result);
} /* namespace js */
/*
* Wrap boolean, number or string as Boolean, Number or String object.
@ -1400,7 +1420,7 @@ js_GetClassPrototype(JSContext *cx, JSProtoKey protoKey, js::MutableHandleObject
namespace js {
extern bool
SetProto(JSContext *cx, HandleObject obj, HandleObject proto, bool checkForCycles);
SetProto(JSContext *cx, HandleObject obj, Handle<TaggedProto> proto, bool checkForCycles);
extern JSString *
obj_toStringHelper(JSContext *cx, JSObject *obj);

Просмотреть файл

@ -651,9 +651,10 @@ JSObject::setSingletonType(JSContext *cx, js::HandleObject obj)
return true;
JS_ASSERT(!obj->hasLazyType());
JS_ASSERT_IF(obj->getProto(), obj->type() == obj->getProto()->getNewType(cx, NULL));
JS_ASSERT_IF(obj->getTaggedProto().isObject(),
obj->type() == obj->getTaggedProto().toObject()->getNewType(cx, NULL));
js::RootedObject objProto(cx, obj->getProto());
js::Rooted<js::TaggedProto> objProto(cx, obj->getTaggedProto());
js::types::TypeObject *type = cx->compartment->getLazyType(cx, objProto);
if (!type)
return false;
@ -677,7 +678,7 @@ JSObject::clearType(JSContext *cx, js::HandleObject obj)
JS_ASSERT(!obj->hasSingletonType());
JS_ASSERT(cx->compartment == obj->compartment());
js::types::TypeObject *type = cx->compartment->getEmptyType(cx);
js::types::TypeObject *type = cx->compartment->getNewType(cx, NULL);
if (!type)
return false;
@ -688,11 +689,7 @@ JSObject::clearType(JSContext *cx, js::HandleObject obj)
inline void
JSObject::setType(js::types::TypeObject *newType)
{
#ifdef DEBUG
JS_ASSERT(newType);
for (JSObject *obj = newType->proto; obj; obj = obj->getProto())
JS_ASSERT(obj != this);
#endif
JS_ASSERT_IF(hasSpecialEquality(),
newType->hasAnyFlags(js::types::OBJECT_FLAG_SPECIAL_EQUALITY));
JS_ASSERT(!hasSingletonType());
@ -700,6 +697,31 @@ JSObject::setType(js::types::TypeObject *newType)
type_ = newType;
}
inline js::TaggedProto
JSObject::getTaggedProto() const
{
return js::TaggedProto(js::ObjectImpl::getProto());
}
inline JSObject *
JSObject::getProto() const
{
JS_ASSERT(!isProxy());
return js::ObjectImpl::getProto();
}
/* static */ inline bool
JSObject::getProto(JSContext *cx, js::HandleObject obj, js::MutableHandleObject protop)
{
if (obj->getTaggedProto().isLazy()) {
JS_ASSERT(obj->isProxy());
return js::Proxy::getPrototypeOf(cx, obj, protop.address());
} else {
protop.set(obj->js::ObjectImpl::getProto());
return true;
}
}
inline bool JSObject::setIteratedSingleton(JSContext *cx)
{
return setFlag(cx, js::BaseShape::ITERATED_SINGLETON);
@ -1378,14 +1400,20 @@ CanBeFinalizedInBackground(gc::AllocKind kind, Class *clasp)
* default to the prototype's global if the prototype is non-null.
*/
JSObject *
NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, TaggedProto proto, JSObject *parent,
gc::AllocKind kind);
inline JSObject *
NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, TaggedProto proto, JSObject *parent)
{
gc::AllocKind kind = gc::GetGCObjectKind(clasp);
return NewObjectWithGivenProto(cx, clasp, proto, parent, kind);
}
inline JSObject *
NewObjectWithGivenProto(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
{
gc::AllocKind kind = gc::GetGCObjectKind(clasp);
return NewObjectWithGivenProto(cx, clasp, proto, parent, kind);
return NewObjectWithGivenProto(cx, clasp, TaggedProto(proto), parent);
}
inline JSProtoKey

Просмотреть файл

@ -357,8 +357,7 @@ bool
BaseProxyHandler::getPrototypeOf(JSContext *cx, JSObject *proxy, JSObject **proto)
{
// The default implementation here just uses proto of the proxy object.
JS_ASSERT(hasPrototype());
*proto = proxy->getProto();
*proto = proxy->getTaggedProto().toObjectOrNull();
return true;
}
@ -2388,7 +2387,7 @@ Proxy::getElementIfPresent(JSContext *cx, HandleObject proxy_, HandleObject rece
RootedId id(cx);
if (!handler->hasPrototype()) {
return GetProxyHandler(proxy)->getElementIfPresent(cx, proxy, receiver, index, vp.address(), present);
} else if (status = IndexToId(cx, index, id.address()) &&
} else if ((status = IndexToId(cx, index, id.address())) &&
(status = handler->hasOwn(cx, proxy, id, &hasOwn)) && hasOwn)
{
*present = true;
@ -2539,6 +2538,15 @@ Proxy::iteratorNext(JSContext *cx, JSObject *proxy_, Value *vp)
return GetProxyHandler(proxy)->iteratorNext(cx, proxy, vp);
}
bool
Proxy::getPrototypeOf(JSContext *cx, JSObject *proxy, JSObject **proto)
{
JS_CHECK_RECURSION(cx, return false);
return GetProxyHandler(proxy)->getPrototypeOf(cx, proxy, proto);
}
JSObject * const Proxy::LazyProto = reinterpret_cast<JSObject *>(0x1);
static JSObject *
proxy_innerObject(JSContext *cx, HandleObject obj)
{
@ -3052,14 +3060,15 @@ JS_FRIEND_DATA(Class) js::FunctionProxyClass = {
}
};
JS_FRIEND_API(JSObject *)
js::NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv_, JSObject *proto_,
static JSObject *
NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv_, TaggedProto proto_,
JSObject *parent_, JSObject *call_, JSObject *construct_)
{
RootedValue priv(cx, priv_);
RootedObject proto(cx, proto_), parent(cx, parent_), call(cx, call_), construct(cx, construct_);
Rooted<TaggedProto> proto(cx, proto_);
RootedObject parent(cx, parent_), call(cx, call_), construct(cx, construct_);
JS_ASSERT_IF(proto, cx->compartment == proto->compartment());
JS_ASSERT_IF(proto.isObject(), cx->compartment == proto.toObject()->compartment());
JS_ASSERT_IF(parent, cx->compartment == parent->compartment());
JS_ASSERT_IF(construct, cx->compartment == construct->compartment());
JS_ASSERT_IF(call && cx->compartment != call->compartment(), priv.get() == ObjectValue(*call));
@ -3075,7 +3084,7 @@ js::NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv_,
* their properties and so that we don't need to walk the compartment if
* their prototype changes later.
*/
if (proto && !proto->setNewTypeUnknown(cx))
if (proto.isObject() && !proto.toObject()->setNewTypeUnknown(cx))
return NULL;
RootedObject obj(cx, NewObjectWithGivenProto(cx, clasp, proto, parent));
@ -3100,6 +3109,13 @@ js::NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv_,
return obj;
}
JS_FRIEND_API(JSObject *)
js::NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv_, JSObject *proto_,
JSObject *parent_, JSObject *call_, JSObject *construct_)
{
return NewProxyObject(cx, handler, priv_, TaggedProto(proto_), parent_, call_, construct_);
}
static JSBool
proxy(JSContext *cx, unsigned argc, jsval *vp)
{

Просмотреть файл

@ -123,7 +123,7 @@ class JS_FRIEND_API(BaseProxyHandler) {
virtual void finalize(JSFreeOp *fop, JSObject *proxy);
virtual bool getElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver,
uint32_t index, Value *vp, bool *present);
virtual bool getPrototypeOf(JSContext *cx, JSObject *proxy, JSObject **proto);
virtual bool getPrototypeOf(JSContext *cx, JSObject *proxy, JSObject **protop);
};
/*
@ -245,6 +245,9 @@ class Proxy {
static bool regexp_toShared(JSContext *cx, JSObject *proxy, RegExpGuard *g);
static bool defaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp);
static bool iteratorNext(JSContext *cx, JSObject *proxy, Value *vp);
static bool getPrototypeOf(JSContext *cx, JSObject *proxy, JSObject **protop);
static JSObject * const LazyProto;
};
inline bool IsObjectProxyClass(const Class *clasp)

Просмотреть файл

@ -287,7 +287,8 @@ Shape::getChildBinding(JSContext *cx, const StackShape &child)
}
/* static */ Shape *
Shape::replaceLastProperty(JSContext *cx, const StackBaseShape &base, JSObject *proto, Shape *shape_)
Shape::replaceLastProperty(JSContext *cx, const StackBaseShape &base,
TaggedProto proto, Shape *shape_)
{
RootedShape shape(cx, shape_);
@ -1007,7 +1008,7 @@ JSObject::setParent(JSContext *cx, HandleObject obj, HandleObject parent)
return true;
}
Shape *newShape = Shape::setObjectParent(cx, parent, obj->getProto(), obj->shape_);
Shape *newShape = Shape::setObjectParent(cx, parent, obj->getTaggedProto(), obj->shape_);
if (!newShape)
return false;
@ -1016,7 +1017,7 @@ JSObject::setParent(JSContext *cx, HandleObject obj, HandleObject parent)
}
/* static */ Shape *
Shape::setObjectParent(JSContext *cx, JSObject *parent, JSObject *proto, Shape *last)
Shape::setObjectParent(JSContext *cx, JSObject *parent, TaggedProto proto, Shape *last)
{
if (last->getObjectParent() == parent)
return last;
@ -1071,7 +1072,7 @@ JSObject::setFlag(JSContext *cx, /*BaseShape::Flag*/ uint32_t flag_, GenerateSha
return true;
}
Shape *newShape = Shape::setObjectFlag(cx, flag, getProto(), lastProperty());
Shape *newShape = Shape::setObjectFlag(cx, flag, getTaggedProto(), lastProperty());
if (!newShape)
return false;
@ -1080,7 +1081,7 @@ JSObject::setFlag(JSContext *cx, /*BaseShape::Flag*/ uint32_t flag_, GenerateSha
}
/* static */ Shape *
Shape::setObjectFlag(JSContext *cx, BaseShape::Flag flag, JSObject *proto, Shape *last)
Shape::setObjectFlag(JSContext *cx, BaseShape::Flag flag, TaggedProto proto, Shape *last)
{
if (last->getObjectFlags() & flag)
return last;
@ -1167,7 +1168,7 @@ InitialShapeEntry::InitialShapeEntry() : shape(NULL), proto(NULL)
}
inline
InitialShapeEntry::InitialShapeEntry(const ReadBarriered<Shape> &shape, JSObject *proto)
InitialShapeEntry::InitialShapeEntry(const ReadBarriered<Shape> &shape, TaggedProto proto)
: shape(shape), proto(proto)
{
}
@ -1183,7 +1184,7 @@ InitialShapeEntry::getLookup()
InitialShapeEntry::hash(const Lookup &lookup)
{
HashNumber hash = uintptr_t(lookup.clasp) >> 3;
hash = JS_ROTATE_LEFT32(hash, 4) ^ (uintptr_t(lookup.proto) >> 3);
hash = JS_ROTATE_LEFT32(hash, 4) ^ (uintptr_t(lookup.proto.toWord()) >> 3);
hash = JS_ROTATE_LEFT32(hash, 4) ^ (uintptr_t(lookup.parent) >> 3);
return hash + lookup.nfixed;
}
@ -1192,17 +1193,17 @@ InitialShapeEntry::hash(const Lookup &lookup)
InitialShapeEntry::match(const InitialShapeEntry &key, const Lookup &lookup)
{
return lookup.clasp == key.shape->getObjectClass()
&& lookup.proto == key.proto
&& lookup.proto.toWord() == key.proto.toWord()
&& lookup.parent == key.shape->getObjectParent()
&& lookup.nfixed == key.shape->numFixedSlots()
&& lookup.baseFlags == key.shape->getObjectFlags();
}
/* static */ Shape *
EmptyShape::getInitialShape(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent,
EmptyShape::getInitialShape(JSContext *cx, Class *clasp, TaggedProto proto, JSObject *parent,
AllocKind kind, uint32_t objectFlags)
{
JS_ASSERT_IF(proto, cx->compartment == proto->compartment());
JS_ASSERT_IF(proto.isObject(), cx->compartment == proto.toObject()->compartment());
JS_ASSERT_IF(parent, cx->compartment == parent->compartment());
InitialShapeSet &table = cx->compartment->initialShapes;
@ -1218,7 +1219,7 @@ EmptyShape::getInitialShape(JSContext *cx, Class *clasp, JSObject *proto, JSObje
if (p)
return p->shape;
RootedObject protoRoot(cx, lookup.proto);
Rooted<TaggedProto> protoRoot(cx, lookup.proto);
RootedObject parentRoot(cx, lookup.parent);
StackBaseShape base(clasp, parent, objectFlags);
@ -1302,8 +1303,8 @@ JSCompartment::sweepInitialShapeTable()
for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) {
const InitialShapeEntry &entry = e.front();
Shape *shape = entry.shape;
JSObject *proto = entry.proto;
if (!IsShapeMarked(&shape) || (proto && !IsObjectMarked(&proto))) {
JSObject *proto = entry.proto.raw();
if (!IsShapeMarked(&shape) || (entry.proto.isObject() && !IsObjectMarked(&proto))) {
e.removeFront();
} else {
#ifdef DEBUG
@ -1311,7 +1312,7 @@ JSCompartment::sweepInitialShapeTable()
JS_ASSERT(!parent || IsObjectMarked(&parent));
JS_ASSERT(parent == shape->getObjectParent());
#endif
if (shape != entry.shape || proto != entry.proto) {
if (shape != entry.shape || proto != entry.proto.raw()) {
InitialShapeEntry newKey(shape, proto);
e.rekeyFront(newKey.getLookup(), newKey);
}

Просмотреть файл

@ -515,7 +515,7 @@ struct Shape : public js::gc::Cell
/* Replace the base shape of the last shape in a non-dictionary lineage with base. */
static Shape *replaceLastProperty(JSContext *cx, const StackBaseShape &base,
JSObject *proto, Shape *shape);
TaggedProto proto, Shape *shape);
bool hashify(JSContext *cx);
void handoffTableTo(Shape *newShape);
@ -600,8 +600,8 @@ struct Shape : public js::gc::Cell
Class *getObjectClass() const { return base()->clasp; }
JSObject *getObjectParent() const { return base()->parent; }
static Shape *setObjectParent(JSContext *cx, JSObject *obj, JSObject *proto, Shape *last);
static Shape *setObjectFlag(JSContext *cx, BaseShape::Flag flag, JSObject *proto, Shape *last);
static Shape *setObjectParent(JSContext *cx, JSObject *obj, TaggedProto proto, Shape *last);
static Shape *setObjectFlag(JSContext *cx, BaseShape::Flag flag, TaggedProto proto, Shape *last);
uint32_t getObjectFlags() const { return base()->getObjectFlags(); }
bool hasObjectFlag(BaseShape::Flag flag) const {
@ -906,7 +906,7 @@ struct EmptyShape : public js::Shape
* Lookup an initial shape matching the given parameters, creating an empty
* shape if none was found.
*/
static Shape *getInitialShape(JSContext *cx, Class *clasp, JSObject *proto,
static Shape *getInitialShape(JSContext *cx, Class *clasp, TaggedProto proto,
JSObject *parent, gc::AllocKind kind, uint32_t objectFlags = 0);
/*
@ -934,16 +934,16 @@ struct InitialShapeEntry
* Matching prototype for the entry. The shape of an object determines its
* prototype, but the prototype cannot be determined from the shape itself.
*/
JSObject *proto;
TaggedProto proto;
/* State used to determine a match on an initial shape. */
struct Lookup {
Class *clasp;
JSObject *proto;
TaggedProto proto;
JSObject *parent;
uint32_t nfixed;
uint32_t baseFlags;
Lookup(Class *clasp, JSObject *proto, JSObject *parent, uint32_t nfixed,
Lookup(Class *clasp, TaggedProto proto, JSObject *parent, uint32_t nfixed,
uint32_t baseFlags)
: clasp(clasp), proto(proto), parent(parent),
nfixed(nfixed), baseFlags(baseFlags)
@ -951,7 +951,7 @@ struct InitialShapeEntry
};
inline InitialShapeEntry();
inline InitialShapeEntry(const ReadBarriered<Shape> &shape, JSObject *proto);
inline InitialShapeEntry(const ReadBarriered<Shape> &shape, TaggedProto proto);
inline Lookup getLookup();

Просмотреть файл

@ -109,17 +109,6 @@ ToClampedIndex(JSContext *cx, const Value &v, uint32_t length, uint32_t *out)
* can be created implicitly by constructing a TypedArray with a size.
*/
/**
* Walks up the prototype chain to find the actual ArrayBuffer data, if any.
*/
static ArrayBufferObject *
getArrayBuffer(JSObject *obj)
{
while (obj && !obj->isArrayBuffer())
obj = obj->getProto();
return obj ? &obj->asArrayBuffer() : NULL;
}
JS_ALWAYS_INLINE bool
IsArrayBuffer(const Value &v)
{
@ -711,43 +700,31 @@ JSBool
ArrayBufferObject::obj_getGeneric(JSContext *cx, HandleObject obj, HandleObject receiver,
HandleId id, MutableHandleValue vp)
{
RootedObject nobj(cx, getArrayBuffer(obj));
JS_ASSERT(nobj);
nobj = ArrayBufferDelegate(cx, nobj);
if (!nobj)
JS_ASSERT(obj->isArrayBuffer());
RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
if (!delegate)
return false;
return baseops::GetProperty(cx, nobj, receiver, id, vp);
return baseops::GetProperty(cx, delegate, receiver, id, vp);
}
JSBool
ArrayBufferObject::obj_getProperty(JSContext *cx, HandleObject obj,
HandleObject receiver, HandlePropertyName name, MutableHandleValue vp)
{
RootedObject nobj(cx, getArrayBuffer(obj));
if (!nobj) {
JSAutoByteString bs(cx, name);
if (!bs)
return false;
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, "ArrayBuffer", bs.ptr(), "object");
return false;
}
nobj = ArrayBufferDelegate(cx, nobj);
if (!nobj)
JS_ASSERT(obj->isArrayBuffer());
RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
if (!delegate)
return false;
Rooted<jsid> id(cx, NameToId(name));
return baseops::GetProperty(cx, nobj, receiver, id, vp);
return baseops::GetProperty(cx, delegate, receiver, id, vp);
}
JSBool
ArrayBufferObject::obj_getElement(JSContext *cx, HandleObject obj,
HandleObject receiver, uint32_t index, MutableHandleValue vp)
{
RootedObject buffer(cx, getArrayBuffer(obj));
RootedObject delegate(cx, ArrayBufferDelegate(cx, buffer));
JS_ASSERT(obj->isArrayBuffer());
RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
if (!delegate)
return false;
return baseops::GetElement(cx, delegate, receiver, index, vp);
@ -757,8 +734,8 @@ JSBool
ArrayBufferObject::obj_getElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver,
uint32_t index, MutableHandleValue vp, bool *present)
{
RootedObject buffer(cx, getArrayBuffer(obj));
RootedObject delegate(cx, ArrayBufferDelegate(cx, buffer));
JS_ASSERT(obj->isArrayBuffer());
RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
if (!delegate)
return false;
return JSObject::getElementIfPresent(cx, delegate, receiver, index, vp, present);

Просмотреть файл

@ -6814,9 +6814,11 @@ mjit::Compiler::jsop_instanceof()
Label loop = masm.label();
/* Walk prototype chain, break out on NULL or hit. */
/* Walk prototype chain, break out on NULL, a lazy proto (0x1), or a hit. */
masm.loadPtr(Address(obj, JSObject::offsetOfType()), obj);
masm.loadPtr(Address(obj, offsetof(types::TypeObject, proto)), obj);
Jump isLazy = masm.branch32(Assembler::Equal, obj, Imm32(1));
stubcc.linkExit(isLazy, Uses(2));
Jump isFalse2 = masm.branchTestPtr(Assembler::Zero, obj, obj);
Jump isTrue = masm.branchPtr(Assembler::NotEqual, obj, proto);
isTrue.linkTo(loop, &masm);

Просмотреть файл

@ -1049,7 +1049,11 @@ js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VM
js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, NullPtr());
return js_InternalThrow(f);
}
nextsp[-1].setBoolean(js_IsDelegate(cx, &f.regs.sp[0].toObject(), f.regs.sp[-2]));
bool isDelegate;
RootedObject obj(cx, &f.regs.sp[0].toObject());
if (!IsDelegate(cx, obj, f.regs.sp[-2], &isDelegate))
return js_InternalThrow(f);
nextsp[-1].setBoolean(isDelegate);
f.regs.pc = nextpc;
break;
}

Просмотреть файл

@ -132,12 +132,12 @@ GeneratePrototypeGuards(JSContext *cx, Vector<JSC::MacroAssembler::Jump,8> &mism
masm.loadPtr(Address(objReg, JSObject::offsetOfType()), scratchReg);
Jump j = masm.branchPtr(Assembler::NotEqual,
Address(scratchReg, offsetof(types::TypeObject, proto)),
ImmPtr(obj->getProto()));
ImmPtr(obj->getTaggedProto().toObjectOrNull()));
if (!mismatches.append(j))
return false;
}
JSObject *pobj = obj->getProto();
JSObject *pobj = obj->getTaggedProto().toObjectOrNull();
while (pobj != holder) {
if (pobj->hasUncacheableProto()) {
Jump j;
@ -606,10 +606,10 @@ IsCacheableProtoChain(JSObject *obj, JSObject *holder)
* chain and must check for null proto. The prototype chain can be
* altered during the lookupProperty call.
*/
JSObject *proto = obj->getProto();
if (!proto || !proto->isNative())
TaggedProto proto = obj->getTaggedProto();
if (!proto.isObject() || !proto.toObject()->isNative())
return false;
obj = proto;
obj = proto.toObject();
}
return true;
}
@ -678,7 +678,7 @@ struct GetPropHelper {
if (obj->isDenseArray())
aobj = obj->getProto();
else if (IsCacheableListBase(obj))
aobj = obj->getProto();
aobj = obj->getTaggedProto().toObjectOrNull();
if (!aobj->isNative())
return ic.disable(f, "non-native");
@ -1362,7 +1362,7 @@ class GetPropCompiler : public PICStubCompiler
} else {
// Like when we add a property, we need to guard on the shape of
// everything on the prototype chain.
JSObject *proto = obj->getProto();
JSObject *proto = obj->getTaggedProto().toObjectOrNull();
RegisterID lastReg = pic.objReg;
while (proto) {
masm.loadPtr(Address(lastReg, JSObject::offsetOfType()), pic.shapeReg);

Просмотреть файл

@ -1218,7 +1218,11 @@ stubs::FastInstanceOf(VMFrame &f)
THROW();
}
f.regs.sp[-3].setBoolean(js_IsDelegate(f.cx, &lref.toObject(), f.regs.sp[-3]));
bool isDelegate;
RootedObject obj(f.cx, &lref.toObject());
if (!IsDelegate(f.cx, obj, f.regs.sp[-3], &isDelegate))
THROW();
f.regs.sp[-3].setBoolean(isDelegate);
}
void JS_FASTCALL

Просмотреть файл

@ -3247,8 +3247,11 @@ Wrap(JSContext *cx, unsigned argc, jsval *vp)
return true;
}
JSObject *obj = JSVAL_TO_OBJECT(v);
JSObject *wrapped = Wrapper::New(cx, obj, obj->getProto(), &obj->global(),
RootedObject obj(cx, JSVAL_TO_OBJECT(v));
RootedObject proto(cx);
if (!JSObject::getProto(cx, obj, &proto))
return false;
JSObject *wrapped = Wrapper::New(cx, obj, proto, &obj->global(),
&DirectWrapper::singleton);
if (!wrapped)
return false;

Просмотреть файл

@ -35,7 +35,7 @@ ArgumentsObject::create(JSContext *cx, StackFrame *fp)
bool strict = fp->callee().inStrictMode();
Class *clasp = strict ? &StrictArgumentsObjectClass : &NormalArgumentsObjectClass;
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, proto,
RootedShape shape(cx, EmptyShape::getInitialShape(cx, clasp, TaggedProto(proto),
proto->getParent(), FINALIZE_KIND,
BaseShape::INDEXED));
if (!shape)

Просмотреть файл

@ -3644,7 +3644,13 @@ static JSBool
DebuggerObject_getProto(JSContext *cx, unsigned argc, Value *vp)
{
THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "get proto", args, dbg, refobj);
Value protov = ObjectOrNullValue(refobj->getProto());
RootedObject proto(cx);
{
AutoCompartment ac(cx, refobj);
if (!JSObject::getProto(cx, refobj, &proto))
return false;
}
Value protov = ObjectOrNullValue(proto);
if (!dbg->wrapDebuggeeValue(cx, &protov))
return false;
args.rval().set(protov);

Просмотреть файл

@ -463,7 +463,8 @@ GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
* [[Prototype]] before standard classes have been initialized. For now,
* only set the [[Prototype]] if it hasn't already been set.
*/
if (self->shouldSplicePrototype(cx) && !self->splicePrototype(cx, objectProto))
Rooted<TaggedProto> tagged(cx, TaggedProto(objectProto));
if (self->shouldSplicePrototype(cx) && !self->splicePrototype(cx, tagged))
return NULL;
/*

Просмотреть файл

@ -160,7 +160,7 @@ CallObject::createTemplateObject(JSContext *cx, JSScript *script)
{
RootedShape shape(cx, script->bindings.callObjShape());
RootedTypeObject type(cx, cx->compartment->getEmptyType(cx));
RootedTypeObject type(cx, cx->compartment->getNewType(cx, NULL));
if (!type)
return NULL;
@ -268,7 +268,7 @@ DeclEnvObject::create(JSContext *cx, StackFrame *fp)
{
assertSameCompartment(cx, fp);
RootedTypeObject type(cx, cx->compartment->getEmptyType(cx));
RootedTypeObject type(cx, cx->compartment->getNewType(cx, NULL));
if (!type)
return NULL;
@ -302,7 +302,7 @@ WithObject::create(JSContext *cx, HandleObject proto, HandleObject enclosing, ui
if (!type)
return NULL;
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &WithClass, proto,
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &WithClass, TaggedProto(proto),
&enclosing->global(), FINALIZE_KIND));
if (!shape)
return NULL;
@ -641,7 +641,7 @@ ClonedBlockObject::copyUnaliasedValues(StackFrame *fp)
StaticBlockObject *
StaticBlockObject::create(JSContext *cx)
{
RootedTypeObject type(cx, cx->compartment->getEmptyType(cx));
RootedTypeObject type(cx, cx->compartment->getNewType(cx, NULL));
if (!type)
return NULL;