зеркало из https://github.com/mozilla/gecko-dev.git
Bug 787856 - Initial support for lazy prototypes (r=bhackett)
This commit is contained in:
Родитель
800264a100
Коммит
7f9b2c5ac7
|
@ -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()))
|
||||
|
|
143
js/src/jsobj.cpp
143
js/src/jsobj.cpp
|
@ -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;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче