Backed out changeset c2659bf5793d (bug 1107145) for bustage.

DONTBUILD CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2014-12-11 13:00:07 -05:00
parent ed48b245f1
commit 34b779d2f4
26 changed files with 273 additions and 220 deletions

View File

@ -278,6 +278,7 @@ CreateSimdClass(JSContext *cx,
proto = NewObjectWithProto<TypedProto>(cx, objProto, nullptr, TenuredObject);
if (!proto)
return nullptr;
proto->initTypeDescrSlot(*typeDescr);
typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto));
// Link constructor to prototype and install properties.

View File

@ -478,10 +478,16 @@ CreatePrototypeObjectForComplexTypeInstance(JSContext *cx,
if (!ctorPrototypePrototype)
return nullptr;
return NewObjectWithProto<TypedProto>(cx,
Rooted<TypedProto*> result(cx);
result = NewObjectWithProto<TypedProto>(cx,
&*ctorPrototypePrototype,
nullptr,
TenuredObject);
if (!result)
return nullptr;
result->initTypeDescrSlot(*descr);
return result;
}
const Class ArrayTypeDescr::class_ = {
@ -1166,6 +1172,7 @@ DefineSimpleTypeDescr(JSContext *cx,
proto = NewObjectWithProto<TypedProto>(cx, objProto, nullptr, TenuredObject);
if (!proto)
return false;
proto->initTypeDescrSlot(*descr);
descr->initReservedSlot(JS_DESCR_SLOT_TYPROTO, ObjectValue(*proto));
RootedValue descrValue(cx, ObjectValue(*descr));
@ -1461,6 +1468,24 @@ OutlineTypedObject::createUnattached(JSContext *cx,
return createUnattachedWithClass(cx, &OutlineTransparentTypedObject::class_, descr, length, heap);
}
static JSObject *
PrototypeForTypeDescr(JSContext *cx, HandleTypeDescr descr)
{
if (descr->is<SimpleTypeDescr>()) {
// FIXME Bug 929651 -- What prototype to use?
return cx->global()->getOrCreateObjectPrototype(cx);
}
RootedValue protoVal(cx);
if (!JSObject::getProperty(cx, descr, descr,
cx->names().prototype, &protoVal))
{
return nullptr;
}
return &protoVal.toObject();
}
void
OutlineTypedObject::setOwnerAndData(JSObject *owner, uint8_t *data)
{
@ -1483,25 +1508,26 @@ OutlineTypedObject::setOwnerAndData(JSObject *owner, uint8_t *data)
/*static*/ OutlineTypedObject *
OutlineTypedObject::createUnattachedWithClass(JSContext *cx,
const Class *clasp,
HandleTypeDescr descr,
HandleTypeDescr type,
int32_t length,
gc::InitialHeap heap)
{
MOZ_ASSERT(clasp == &OutlineTransparentTypedObject::class_ ||
clasp == &OutlineOpaqueTypedObject::class_);
RootedTypeObject type(cx, cx->getNewType(clasp, TaggedProto(&descr->typedProto()), descr));
if (!type)
RootedObject proto(cx, PrototypeForTypeDescr(cx, type));
if (!proto)
return nullptr;
NewObjectKind newKind = (heap == gc::TenuredHeap) ? MaybeSingletonObject : GenericObject;
OutlineTypedObject *obj = NewObjectWithType<OutlineTypedObject>(cx, type, cx->global(),
gc::FINALIZE_OBJECT0, newKind);
JSObject *obj = NewObjectWithClassProto(cx, clasp, proto, nullptr, gc::FINALIZE_OBJECT0, newKind);
if (!obj)
return nullptr;
obj->setOwnerAndData(nullptr, nullptr);
return obj;
OutlineTypedObject *typedObj = &obj->as<OutlineTypedObject>();
typedObj->setOwnerAndData(nullptr, nullptr);
return typedObj;
}
void
@ -2191,16 +2217,20 @@ InlineTypedObject::create(JSContext *cx, HandleTypeDescr descr, gc::InitialHeap
{
gc::AllocKind allocKind = allocKindForTypeDescriptor(descr);
RootedObject proto(cx, PrototypeForTypeDescr(cx, descr));
if (!proto)
return nullptr;
const Class *clasp = descr->opaque()
? &InlineOpaqueTypedObject::class_
: &InlineTransparentTypedObject::class_;
RootedTypeObject type(cx, cx->getNewType(clasp, TaggedProto(&descr->typedProto()), descr));
if (!type)
NewObjectKind newKind = (heap == gc::TenuredHeap) ? MaybeSingletonObject : GenericObject;
RootedObject obj(cx, NewObjectWithClassProto(cx, clasp, proto, nullptr, allocKind, newKind));
if (!obj)
return nullptr;
NewObjectKind newKind = (heap == gc::TenuredHeap) ? MaybeSingletonObject : GenericObject;
return NewObjectWithType<InlineTypedObject>(cx, type, cx->global(), allocKind, newKind);
return &obj->as<InlineTypedObject>();
}
/* static */ InlineTypedObject *
@ -2748,19 +2778,6 @@ JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::TypedObjectIsAttachedJitInfo,
TypedObjectIsAttachedJitInfo,
js::TypedObjectIsAttached);
bool
js::TypedObjectTypeDescr(ThreadSafeContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
TypedObject &typedObj = args[0].toObject().as<TypedObject>();
args.rval().setObject(typedObj.typeDescr());
return true;
}
JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(js::TypedObjectTypeDescrJitInfo,
TypedObjectTypeDescrJitInfo,
js::TypedObjectTypeDescr);
bool
js::ClampToUint8(ThreadSafeContext *, unsigned argc, Value *vp)
{

View File

@ -134,12 +134,30 @@ class StructTypeDescr;
class TypedProto;
/*
* The prototype for a typed object.
* The prototype for a typed object. Currently, carries a link to the
* type descriptor. Eventually will carry most of the type information
* we want.
*/
class TypedProto : public NativeObject
{
public:
static const Class class_;
inline void initTypeDescrSlot(TypeDescr &descr);
TypeDescr &typeDescr() const {
return getReservedSlot(JS_TYPROTO_SLOT_DESCR).toObject().as<TypeDescr>();
}
TypeDescr &maybeForwardedTypeDescr() const {
return MaybeForwarded(&getReservedSlot(JS_TYPROTO_SLOT_DESCR).toObject())->as<TypeDescr>();
}
inline type::Kind kind() const;
static int32_t offsetOfTypeDescr() {
return getFixedSlotOffset(JS_TYPROTO_SLOT_DESCR);
}
};
class TypeDescr : public NativeObject
@ -576,11 +594,11 @@ class TypedObject : public JSObject
}
TypeDescr &typeDescr() const {
return type()->typeDescr();
return typedProto().typeDescr();
}
TypeDescr &maybeForwardedTypeDescr() const {
return MaybeForwarded(&typeDescr())->as<TypeDescr>();
return maybeForwardedTypedProto().maybeForwardedTypeDescr();
}
int32_t offset() const;
@ -853,14 +871,6 @@ extern const JSJitInfo TypeDescrIsArrayTypeJitInfo;
bool TypedObjectIsAttached(ThreadSafeContext *cx, unsigned argc, Value *vp);
extern const JSJitInfo TypedObjectIsAttachedJitInfo;
/*
* Usage: TypedObjectTypeDescr(obj)
*
* Given a TypedObject `obj`, returns the object's type descriptor.
*/
bool TypedObjectTypeDescr(ThreadSafeContext *cx, unsigned argc, Value *vp);
extern const JSJitInfo TypedObjectTypeDescrJitInfo;
/*
* Usage: ClampToUint8(v)
*
@ -1120,4 +1130,17 @@ JSObject::is<js::InlineTypedObject>() const
getClass() == &js::InlineOpaqueTypedObject::class_;
}
inline void
js::TypedProto::initTypeDescrSlot(TypeDescr &descr)
{
initReservedSlot(JS_TYPROTO_SLOT_DESCR, ObjectValue(descr));
}
inline js::type::Kind
js::TypedProto::kind() const {
// Defined out of line because it depends on def'n of both
// TypedProto and TypeDescr
return typeDescr().kind();
}
#endif /* builtin_TypedObject_h */

View File

@ -28,11 +28,20 @@
#define DESCR_STRUCT_FIELD_OFFSETS(obj) \
UnsafeGetReservedSlot(obj, JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS)
// Typed prototype slots
#define TYPROTO_DESCR(obj) \
UnsafeGetReservedSlot(obj, JS_TYPROTO_SLOT_DESCR)
// Other
#define HAS_PROPERTY(obj, prop) \
callFunction(std_Object_hasOwnProperty, obj, prop)
function TypedObjectTypeDescr(typedObj) {
return TYPROTO_DESCR(std_Object_getPrototypeOf(typedObj));
}
///////////////////////////////////////////////////////////////////////////
// Getting values
//

View File

@ -12,7 +12,8 @@
///////////////////////////////////////////////////////////////////////////
// Slots for typed prototypes
#define JS_TYPROTO_SLOTS 0
#define JS_TYPROTO_SLOT_DESCR 0
#define JS_TYPROTO_SLOTS 1
///////////////////////////////////////////////////////////////////////////
// Slots for type objects

View File

@ -778,6 +778,10 @@ class UnownedBaseShape;
namespace jit {
class JitCode;
}
namespace types {
struct TypeObject;
class TypeNewScript;
}
typedef PreBarriered<JSObject*> PreBarrieredObject;
typedef PreBarriered<JSScript*> PreBarrieredScript;
@ -807,6 +811,7 @@ typedef HeapPtr<Shape*> HeapPtrShape;
typedef HeapPtr<UnownedBaseShape*> HeapPtrUnownedBaseShape;
typedef HeapPtr<jit::JitCode*> HeapPtrJitCode;
typedef HeapPtr<types::TypeObject*> HeapPtrTypeObject;
typedef HeapPtr<types::TypeNewScript*> HeapPtrTypeNewScript;
typedef PreBarriered<Value> PreBarrieredValue;
typedef RelocatablePtr<Value> RelocatableValue;

View File

@ -4677,8 +4677,8 @@ LoadTypedThingLength(MacroAssembler &masm, TypedThingLayout layout, Register obj
break;
case Layout_OutlineTypedObject:
case Layout_InlineTypedObject:
masm.loadPtr(Address(obj, JSObject::offsetOfType()), result);
masm.loadPtr(Address(result, types::TypeObject::offsetOfAddendum()), result);
masm.loadObjProto(obj, result);
masm.unboxObject(Address(result, TypedProto::offsetOfTypeDescr()), result);
masm.unboxInt32(Address(result, ArrayTypeDescr::offsetOfLength()), result);
break;
default:
@ -8516,7 +8516,7 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
// Check if the old type still has a newScript.
masm.loadPtr(Address(objReg, JSObject::offsetOfType()), scratch);
masm.branchPtr(Assembler::Equal,
Address(scratch, types::TypeObject::offsetOfAddendum()),
Address(scratch, types::TypeObject::offsetOfNewScript()),
ImmWord(0),
&noTypeChange);

View File

@ -4884,13 +4884,19 @@ CodeGenerator::visitTypedArrayElements(LTypedArrayElements *lir)
}
void
CodeGenerator::visitTypedObjectDescr(LTypedObjectDescr *lir)
CodeGenerator::visitTypedObjectProto(LTypedObjectProto *lir)
{
Register obj = ToRegister(lir->object());
Register out = ToRegister(lir->output());
MOZ_ASSERT(ToRegister(lir->output()) == ReturnReg);
masm.loadPtr(Address(obj, JSObject::offsetOfType()), out);
masm.loadPtr(Address(out, types::TypeObject::offsetOfAddendum()), out);
// Eventually we ought to inline this helper function for
// efficiency, but it's mildly non-trivial since we must reach
// into the type object and so on.
const Register tempReg = ToRegister(lir->temp());
masm.setupUnalignedABICall(1, tempReg);
masm.passABIArg(obj);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, TypedObjectProto));
}
void

View File

@ -186,7 +186,7 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitTypedArrayElements(LTypedArrayElements *lir);
void visitTypedObjectElements(LTypedObjectElements *lir);
void visitSetTypedObjectOffset(LSetTypedObjectOffset *lir);
void visitTypedObjectDescr(LTypedObjectDescr *ins);
void visitTypedObjectProto(LTypedObjectProto *ins);
void visitStringLength(LStringLength *lir);
void visitSubstr(LSubstr *lir);
void visitInitializedLength(LInitializedLength *lir);

View File

@ -11271,7 +11271,14 @@ IonBuilder::typedObjectPrediction(types::TemporaryTypeSet *types)
if (!IsTypedObjectClass(type->clasp()))
return TypedObjectPrediction();
out.addDescr(type->typeDescr());
TaggedProto proto = type->proto();
// typed objects have immutable prototypes, and they are
// always instances of TypedProto
MOZ_ASSERT(proto.isObject() && proto.toObject()->is<TypedProto>());
TypedProto &typedProto = proto.toObject()->as<TypedProto>();
out.addDescr(typedProto.typeDescr());
}
return out;
@ -11287,10 +11294,16 @@ IonBuilder::loadTypedObjectType(MDefinition *typedObj)
if (typedObj->isNewDerivedTypedObject())
return typedObj->toNewDerivedTypedObject()->type();
MInstruction *descr = MTypedObjectDescr::New(alloc(), typedObj);
current->add(descr);
MInstruction *proto = MTypedObjectProto::New(alloc(), typedObj);
current->add(proto);
return descr;
MInstruction *load = MLoadFixedSlot::New(alloc(), proto, JS_TYPROTO_SLOT_DESCR);
current->add(load);
MInstruction *unbox = MUnbox::New(alloc(), load, MIRType_Object, MUnbox::Infallible);
current->add(unbox);
return unbox;
}
// Given a typed object `typedObj` and an offset `offset` into that

View File

@ -2596,7 +2596,7 @@ GenerateAddSlot(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &att
masm.push(object);
masm.loadPtr(Address(object, JSObject::offsetOfType()), object);
masm.branchPtr(Assembler::Equal,
Address(object, types::TypeObject::offsetOfAddendum()),
Address(object, types::TypeObject::offsetOfNewScript()),
ImmWord(0),
&noTypeChange);
masm.pop(object);

View File

@ -4295,18 +4295,23 @@ class LTypedArrayElements : public LInstructionHelper<1, 1, 0>
}
};
// Load a typed object's descriptor.
class LTypedObjectDescr : public LInstructionHelper<1, 1, 0>
// Load a typed object's prototype, which is guaranteed to be a
// TypedProto object.
class LTypedObjectProto : public LCallInstructionHelper<1, 1, 1>
{
public:
LIR_HEADER(TypedObjectDescr)
LIR_HEADER(TypedObjectProto)
LTypedObjectDescr(const LAllocation &object) {
LTypedObjectProto(const LAllocation &object, const LDefinition &temp1) {
setOperand(0, object);
setTemp(0, temp1);
}
const LAllocation *object() {
return getOperand(0);
}
const LDefinition *temp() {
return getTemp(0);
}
};
// Load a typed object's elements vector.

View File

@ -285,7 +285,7 @@
_(SetArrayLength) \
_(TypedArrayLength) \
_(TypedArrayElements) \
_(TypedObjectDescr) \
_(TypedObjectProto) \
_(TypedObjectElements) \
_(SetTypedObjectOffset) \
_(StringLength) \

View File

@ -2496,10 +2496,12 @@ LIRGenerator::visitTypedArrayElements(MTypedArrayElements *ins)
}
void
LIRGenerator::visitTypedObjectDescr(MTypedObjectDescr *ins)
LIRGenerator::visitTypedObjectProto(MTypedObjectProto *ins)
{
MOZ_ASSERT(ins->type() == MIRType_Object);
define(new(alloc()) LTypedObjectDescr(useRegisterAtStart(ins->object())), ins);
defineReturn(new(alloc()) LTypedObjectProto(useFixed(ins->object(), CallTempReg0),
tempFixed(CallTempReg1)),
ins);
}
void

View File

@ -192,7 +192,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitTypedArrayElements(MTypedArrayElements *ins);
void visitTypedObjectElements(MTypedObjectElements *ins);
void visitSetTypedObjectOffset(MSetTypedObjectOffset *ins);
void visitTypedObjectDescr(MTypedObjectDescr *ins);
void visitTypedObjectProto(MTypedObjectProto *ins);
void visitInitializedLength(MInitializedLength *ins);
void visitSetInitializedLength(MSetInitializedLength *ins);
void visitNot(MNot *ins);

View File

@ -2829,12 +2829,12 @@ class MNewTypedObject : public MNullaryInstruction
}
};
class MTypedObjectDescr
class MTypedObjectProto
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
private:
explicit MTypedObjectDescr(MDefinition *object)
explicit MTypedObjectProto(MDefinition *object)
: MUnaryInstruction(object)
{
setResultType(MIRType_Object);
@ -2842,10 +2842,10 @@ class MTypedObjectDescr
}
public:
INSTRUCTION_HEADER(TypedObjectDescr)
INSTRUCTION_HEADER(TypedObjectProto)
static MTypedObjectDescr *New(TempAllocator &alloc, MDefinition *object) {
return new(alloc) MTypedObjectDescr(object);
static MTypedObjectProto *New(TempAllocator &alloc, MDefinition *object) {
return new(alloc) MTypedObjectProto(object);
}
MDefinition *object() const {

View File

@ -164,7 +164,7 @@ namespace jit {
_(SetArrayLength) \
_(TypedArrayLength) \
_(TypedArrayElements) \
_(TypedObjectDescr) \
_(TypedObjectProto) \
_(TypedObjectElements) \
_(SetTypedObjectOffset) \
_(InitializedLength) \

View File

@ -244,7 +244,7 @@ class ParallelSafetyVisitor : public MDefinitionVisitor
WRITE_GUARDED_OP(SetArrayLength, elements)
SAFE_OP(TypedArrayLength)
SAFE_OP(TypedArrayElements)
SAFE_OP(TypedObjectDescr)
SAFE_OP(TypedObjectProto)
SAFE_OP(TypedObjectElements)
SAFE_OP(SetTypedObjectOffset)
SAFE_OP(InitializedLength)

View File

@ -1291,6 +1291,15 @@ AssertValidValue(JSContext *cx, Value *v)
}
#endif
// Definition of the MTypedObjectProto MIR.
JSObject *
TypedObjectProto(JSObject *obj)
{
MOZ_ASSERT(obj->is<TypedObject>());
TypedObject &typedObj = obj->as<TypedObject>();
return &typedObj.typedProto();
}
bool
ObjectIsCallable(JSObject *obj)
{

View File

@ -791,6 +791,8 @@ void AssertValidSymbolPtr(JSContext *cx, JS::Symbol *sym);
void AssertValidValue(JSContext *cx, Value *v);
#endif
JSObject *TypedObjectProto(JSObject *obj);
void MarkValueFromIon(JSRuntime *rt, Value *vp);
void MarkStringFromIon(JSRuntime *rt, JSString **stringp);
void MarkObjectFromIon(JSRuntime *rt, JSObject **objp);

View File

@ -375,8 +375,7 @@ class ExclusiveContext : public ThreadSafeContext
}
// Zone local methods that can be used freely from an ExclusiveContext.
types::TypeObject *getNewType(const Class *clasp, TaggedProto proto,
JSObject *associated = nullptr);
types::TypeObject *getNewType(const Class *clasp, TaggedProto proto, JSFunction *fun = nullptr);
types::TypeObject *getSingletonType(const Class *clasp, TaggedProto proto);
inline js::LifoAlloc &typeLifoAlloc();

View File

@ -271,13 +271,13 @@ struct JSCompartment
void sweepInitialShapeTable();
/* Set of default 'new' or lazy types in the compartment. */
js::types::NewTypeObjectTable newTypeObjects;
js::types::NewTypeObjectTable lazyTypeObjects;
void sweepNewTypeObjectTable(js::types::NewTypeObjectTable &table);
js::types::TypeObjectWithNewScriptSet newTypeObjects;
js::types::TypeObjectWithNewScriptSet lazyTypeObjects;
void sweepNewTypeObjectTable(js::types::TypeObjectWithNewScriptSet &table);
#ifdef JSGC_HASH_TABLE_CHECKS
void checkTypeObjectTablesAfterMovingGC();
void checkTypeObjectTableAfterMovingGC(js::types::NewTypeObjectTable &table);
void checkTypeObjectTableAfterMovingGC(js::types::TypeObjectWithNewScriptSet &table);
void checkInitialShapesTableAfterMovingGC();
void checkWrapperMapAfterMovingGC();
#endif
@ -394,7 +394,7 @@ struct JSCompartment
#ifdef JSGC_COMPACTING
void fixupInitialShapeTable();
void fixupNewTypeObjectTable(js::types::NewTypeObjectTable &table);
void fixupNewTypeObjectTable(js::types::TypeObjectWithNewScriptSet &table);
void fixupAfterMovingGC();
void fixupGlobal();
#endif

View File

@ -3264,7 +3264,7 @@ TypeObject::maybeClearNewScriptOnOOM()
if (!isMarked())
return;
if (!newScript())
if (!newScript_)
return;
for (unsigned i = 0; i < getPropertyCount(); i++) {
@ -3278,7 +3278,7 @@ TypeObject::maybeClearNewScriptOnOOM()
// This method is called during GC sweeping, so there is no write barrier
// that needs to be triggered.
js_delete(newScript());
addendum_ = nullptr;
newScript_.unsafeSet(nullptr);
}
void
@ -4083,12 +4083,12 @@ TypeNewScript::maybeAnalyze(JSContext *cx, TypeObject *type, bool *regenerate, b
if (!type->addDefiniteProperties(cx, prefixShape))
return false;
NewTypeObjectTable &table = cx->compartment()->newTypeObjects;
NewTypeObjectTable::Lookup lookup(type->clasp(), type->proto(), fun);
TypeObjectWithNewScriptSet &table = cx->compartment()->newTypeObjects;
TypeObjectWithNewScriptSet::Lookup lookup(type->clasp(), type->proto(), fun);
MOZ_ASSERT(table.lookup(lookup)->object == type);
table.remove(lookup);
table.putNew(lookup, NewTypeObjectEntry(initialType, fun));
table.putNew(lookup, TypeObjectWithNewScriptEntry(initialType, fun));
templateObject()->setType(initialType);
@ -4322,32 +4322,31 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj)
}
/* static */ inline HashNumber
NewTypeObjectEntry::hash(const Lookup &lookup)
TypeObjectWithNewScriptEntry::hash(const Lookup &lookup)
{
return PointerHasher<JSObject *, 3>::hash(lookup.hashProto.raw()) ^
PointerHasher<const Class *, 3>::hash(lookup.clasp) ^
PointerHasher<JSObject *, 3>::hash(lookup.associated);
PointerHasher<JSFunction *, 3>::hash(lookup.newFunction);
}
/* static */ inline bool
NewTypeObjectEntry::match(const NewTypeObjectEntry &key, const Lookup &lookup)
TypeObjectWithNewScriptEntry::match(const TypeObjectWithNewScriptEntry &key, const Lookup &lookup)
{
return key.object->proto() == lookup.matchProto &&
key.object->clasp() == lookup.clasp &&
key.associated == lookup.associated;
key.newFunction == lookup.newFunction;
}
#ifdef DEBUG
bool
JSObject::hasNewType(const Class *clasp, TypeObject *type)
{
NewTypeObjectTable &table = compartment()->newTypeObjects;
TypeObjectWithNewScriptSet &table = compartment()->newTypeObjects;
if (!table.initialized())
return false;
NewTypeObjectTable::Ptr p =
table.lookup(NewTypeObjectTable::Lookup(clasp, TaggedProto(this), nullptr));
TypeObjectWithNewScriptSet::Ptr p = table.lookup(TypeObjectWithNewScriptSet::Lookup(clasp, TaggedProto(this), nullptr));
return p && p->object == type;
}
#endif /* DEBUG */
@ -4363,12 +4362,10 @@ JSObject::setNewTypeUnknown(JSContext *cx, const Class *clasp, HandleObject obj)
* not have the SETS_MARKED_UNKNOWN bit set, so may require a type set
* crawl if prototypes of the object change dynamically in the future.
*/
NewTypeObjectTable &table = cx->compartment()->newTypeObjects;
TypeObjectWithNewScriptSet &table = cx->compartment()->newTypeObjects;
if (table.initialized()) {
Rooted<TaggedProto> taggedProto(cx, TaggedProto(obj));
NewTypeObjectTable::Ptr p =
table.lookup(NewTypeObjectTable::Lookup(clasp, taggedProto, nullptr));
if (p)
if (TypeObjectWithNewScriptSet::Ptr p = table.lookup(TypeObjectWithNewScriptSet::Lookup(clasp, taggedProto, nullptr)))
MarkTypeObjectUnknownProperties(cx, p->object);
}
@ -4382,14 +4379,14 @@ JSObject::setNewTypeUnknown(JSContext *cx, const Class *clasp, HandleObject obj)
*/
class NewTypeObjectsSetRef : public BufferableRef
{
NewTypeObjectTable *set;
TypeObjectWithNewScriptSet *set;
const Class *clasp;
JSObject *proto;
JSObject *associated;
JSFunction *newFunction;
public:
NewTypeObjectsSetRef(NewTypeObjectTable *s, const Class *clasp, JSObject *proto, JSObject *associated)
: set(s), clasp(clasp), proto(proto), associated(associated)
NewTypeObjectsSetRef(TypeObjectWithNewScriptSet *s, const Class *clasp, JSObject *proto, JSFunction *newFunction)
: set(s), clasp(clasp), proto(proto), newFunction(newFunction)
{}
void mark(JSTracer *trc) {
@ -4399,21 +4396,19 @@ class NewTypeObjectsSetRef : public BufferableRef
if (prior == proto)
return;
NewTypeObjectTable::Ptr p =
set->lookup(NewTypeObjectTable::Lookup(clasp, TaggedProto(prior), TaggedProto(proto),
associated));
TypeObjectWithNewScriptSet::Ptr p = set->lookup(TypeObjectWithNewScriptSet::Lookup(clasp, TaggedProto(prior), TaggedProto(proto), newFunction));
MOZ_ASSERT(p); // newTypeObjects set must still contain original entry.
set->rekeyAs(NewTypeObjectTable::Lookup(clasp, TaggedProto(prior), TaggedProto(proto), associated),
NewTypeObjectTable::Lookup(clasp, TaggedProto(proto), associated), *p);
set->rekeyAs(TypeObjectWithNewScriptSet::Lookup(clasp, TaggedProto(prior), TaggedProto(proto), newFunction),
TypeObjectWithNewScriptSet::Lookup(clasp, TaggedProto(proto), newFunction), *p);
}
};
static void
TypeObjectTablePostBarrier(ExclusiveContext *cx, NewTypeObjectTable *table,
const Class *clasp, TaggedProto proto, JSObject *associated)
TypeObjectTablePostBarrier(ExclusiveContext *cx, TypeObjectWithNewScriptSet *table,
const Class *clasp, TaggedProto proto, JSFunction *fun)
{
MOZ_ASSERT_IF(associated, !IsInsideNursery(associated));
MOZ_ASSERT_IF(fun, !IsInsideNursery(fun));
if (!proto.isObject())
return;
@ -4425,35 +4420,33 @@ TypeObjectTablePostBarrier(ExclusiveContext *cx, NewTypeObjectTable *table,
if (IsInsideNursery(proto.toObject())) {
StoreBuffer &sb = cx->asJSContext()->runtime()->gc.storeBuffer;
sb.putGeneric(NewTypeObjectsSetRef(table, clasp, proto.toObject(), associated));
sb.putGeneric(NewTypeObjectsSetRef(table, clasp, proto.toObject(), fun));
}
}
TypeObject *
ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSObject *associated)
ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *fun)
{
MOZ_ASSERT_IF(associated, proto.isObject());
MOZ_ASSERT_IF(associated, associated->is<JSFunction>() || associated->is<TypeDescr>());
MOZ_ASSERT_IF(fun, proto.isObject());
MOZ_ASSERT_IF(proto.isObject(), isInsideCurrentCompartment(proto.toObject()));
NewTypeObjectTable &newTypeObjects = compartment()->newTypeObjects;
TypeObjectWithNewScriptSet &newTypeObjects = compartment()->newTypeObjects;
if (!newTypeObjects.initialized() && !newTypeObjects.init())
return nullptr;
// Canonicalize new functions to use the original one associated with its script.
if (associated && associated->is<JSFunction>()) {
JSFunction *fun = &associated->as<JSFunction>();
if (fun) {
if (fun->hasScript())
associated = fun->nonLazyScript()->functionNonDelazifying();
fun = fun->nonLazyScript()->functionNonDelazifying();
else if (fun->isInterpretedLazy() && !fun->isSelfHostedBuiltin())
associated = fun->lazyScript()->functionNonDelazifying();
fun = fun->lazyScript()->functionNonDelazifying();
else
associated = nullptr;
fun = nullptr;
}
NewTypeObjectTable::AddPtr p =
newTypeObjects.lookupForAdd(NewTypeObjectTable::Lookup(clasp, proto, associated));
TypeObjectWithNewScriptSet::AddPtr p =
newTypeObjects.lookupForAdd(TypeObjectWithNewScriptSet::Lookup(clasp, proto, fun));
if (p) {
TypeObject *type = p->object;
MOZ_ASSERT(type->clasp() == clasp);
@ -4482,20 +4475,16 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSObject *as
if (!type)
return nullptr;
if (!newTypeObjects.add(p, NewTypeObjectEntry(type, associated)))
if (!newTypeObjects.add(p, TypeObjectWithNewScriptEntry(type, fun)))
return nullptr;
TypeObjectTablePostBarrier(this, &newTypeObjects, clasp, proto, associated);
TypeObjectTablePostBarrier(this, &newTypeObjects, clasp, proto, fun);
if (proto.isObject()) {
RootedObject obj(this, proto.toObject());
if (associated) {
if (associated->is<JSFunction>())
TypeNewScript::make(asJSContext(), type, &associated->as<JSFunction>());
else
type->setTypeDescr(&associated->as<TypeDescr>());
}
if (fun)
TypeNewScript::make(asJSContext(), type, fun);
/*
* Some builtin objects have slotful native properties baked in at
@ -4534,12 +4523,12 @@ ExclusiveContext::getSingletonType(const Class *clasp, TaggedProto proto)
AutoEnterAnalysis enter(this);
NewTypeObjectTable &table = compartment()->lazyTypeObjects;
TypeObjectWithNewScriptSet &table = compartment()->lazyTypeObjects;
if (!table.initialized() && !table.init())
return nullptr;
NewTypeObjectTable::AddPtr p = table.lookupForAdd(NewTypeObjectTable::Lookup(clasp, proto, nullptr));
TypeObjectWithNewScriptSet::AddPtr p = table.lookupForAdd(TypeObjectWithNewScriptSet::Lookup(clasp, proto, nullptr));
if (p) {
TypeObject *type = p->object;
MOZ_ASSERT(type->lazy());
@ -4552,7 +4541,7 @@ ExclusiveContext::getSingletonType(const Class *clasp, TaggedProto proto)
if (!type)
return nullptr;
if (!table.add(p, NewTypeObjectEntry(type, nullptr)))
if (!table.add(p, TypeObjectWithNewScriptEntry(type, nullptr)))
return nullptr;
TypeObjectTablePostBarrier(this, &table, clasp, proto, nullptr);
@ -4860,20 +4849,20 @@ TypeCompartment::sweep(FreeOp *fop)
}
void
JSCompartment::sweepNewTypeObjectTable(NewTypeObjectTable &table)
JSCompartment::sweepNewTypeObjectTable(TypeObjectWithNewScriptSet &table)
{
MOZ_ASSERT(zone()->runtimeFromAnyThread()->isHeapCollecting());
if (table.initialized()) {
for (NewTypeObjectTable::Enum e(table); !e.empty(); e.popFront()) {
NewTypeObjectEntry entry = e.front();
for (TypeObjectWithNewScriptSet::Enum e(table); !e.empty(); e.popFront()) {
TypeObjectWithNewScriptEntry entry = e.front();
if (IsTypeObjectAboutToBeFinalizedFromAnyThread(entry.object.unsafeGet()) ||
(entry.associated && IsObjectAboutToBeFinalizedFromAnyThread(&entry.associated)))
(entry.newFunction && IsObjectAboutToBeFinalizedFromAnyThread(&entry.newFunction)))
{
e.removeFront();
} else {
/* Any rekeying necessary is handled by fixupNewTypeObjectTable() below. */
MOZ_ASSERT(entry.object.unbarrieredGet() == e.front().object.unbarrieredGet());
MOZ_ASSERT(entry.associated == e.front().associated);
MOZ_ASSERT(entry.newFunction == e.front().newFunction);
}
}
}
@ -4882,7 +4871,7 @@ JSCompartment::sweepNewTypeObjectTable(NewTypeObjectTable &table)
#ifdef JSGC_COMPACTING
void
JSCompartment::fixupNewTypeObjectTable(NewTypeObjectTable &table)
JSCompartment::fixupNewTypeObjectTable(TypeObjectWithNewScriptSet &table)
{
/*
* Each entry's hash depends on the object's prototype and we can't tell
@ -4890,8 +4879,8 @@ JSCompartment::fixupNewTypeObjectTable(NewTypeObjectTable &table)
*/
MOZ_ASSERT(zone()->isCollecting());
if (table.initialized()) {
for (NewTypeObjectTable::Enum e(table); !e.empty(); e.popFront()) {
NewTypeObjectEntry entry = e.front();
for (TypeObjectWithNewScriptSet::Enum e(table); !e.empty(); e.popFront()) {
TypeObjectWithNewScriptEntry entry = e.front();
bool needRekey = false;
if (IsForwarded(entry.object.get())) {
entry.object.set(Forwarded(entry.object.get()));
@ -4907,7 +4896,7 @@ JSCompartment::fixupNewTypeObjectTable(NewTypeObjectTable &table)
needRekey = true;
}
if (needRekey) {
NewTypeObjectTable::Lookup lookup(entry.object->clasp(),
TypeObjectWithNewScriptSet::Lookup lookup(entry.object->clasp(),
proto,
entry.newFunction);
e.rekeyFront(lookup, entry);
@ -4953,7 +4942,7 @@ JSCompartment::checkTypeObjectTablesAfterMovingGC()
}
void
JSCompartment::checkTypeObjectTableAfterMovingGC(NewTypeObjectTable &table)
JSCompartment::checkTypeObjectTableAfterMovingGC(TypeObjectWithNewScriptSet &table)
{
/*
* Assert that nothing points into the nursery or needs to be relocated, and
@ -4962,17 +4951,17 @@ JSCompartment::checkTypeObjectTableAfterMovingGC(NewTypeObjectTable &table)
if (!table.initialized())
return;
for (NewTypeObjectTable::Enum e(table); !e.empty(); e.popFront()) {
NewTypeObjectEntry entry = e.front();
for (TypeObjectWithNewScriptSet::Enum e(table); !e.empty(); e.popFront()) {
TypeObjectWithNewScriptEntry entry = e.front();
CheckGCThingAfterMovingGC(entry.object.get());
TaggedProto proto = entry.object->proto();
if (proto.isObject())
CheckGCThingAfterMovingGC(proto.toObject());
CheckGCThingAfterMovingGC(entry.associated);
CheckGCThingAfterMovingGC(entry.newFunction);
NewTypeObjectTable::Lookup
lookup(entry.object->clasp(), proto, entry.associated);
NewTypeObjectTable::Ptr ptr = table.lookup(lookup);
TypeObjectWithNewScriptEntry::Lookup
lookup(entry.object->clasp(), proto, entry.newFunction);
TypeObjectWithNewScriptSet::Ptr ptr = table.lookup(lookup);
MOZ_ASSERT(ptr.found() && &*ptr == &e.front());
}
}
@ -5083,7 +5072,7 @@ TypeCompartment::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t
TypeObject::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
return mallocSizeOf(newScriptDontCheckGeneration());
return mallocSizeOf(newScript_);
}
TypeZone::TypeZone(Zone *zone)
@ -5248,14 +5237,8 @@ TypeScript::printTypes(JSContext *cx, HandleScript script) const
#endif /* DEBUG */
void
TypeObject::setAddendum(AddendumKind kind, void *addendum)
TypeObject::setNewScript(TypeNewScript *newScript)
{
MOZ_ASSERT(!needsSweep());
MOZ_ASSERT(kind <= (OBJECT_FLAG_ADDENDUM_MASK >> OBJECT_FLAG_ADDENDUM_SHIFT));
MOZ_ASSERT(!(flags_ & OBJECT_FLAG_ADDENDUM_MASK));
writeBarrierPre(this);
flags_ |= kind << OBJECT_FLAG_ADDENDUM_SHIFT;
addendum_ = addendum;
newScript_ = newScript;
}

View File

@ -512,14 +512,10 @@ enum MOZ_ENUM_TYPE(uint32_t) {
OBJECT_FLAG_DYNAMIC_MASK
| OBJECT_FLAG_SETS_MARKED_UNKNOWN,
// Mask/shift for the kind of addendum attached to this type object.
OBJECT_FLAG_ADDENDUM_MASK = 0x04000000,
OBJECT_FLAG_ADDENDUM_SHIFT = 26,
// Mask/shift for this type object's generation. If out of sync with the
// TypeZone's generation, this TypeObject hasn't been swept yet.
OBJECT_FLAG_GENERATION_MASK = 0x08000000,
OBJECT_FLAG_GENERATION_SHIFT = 27,
OBJECT_FLAG_GENERATION_MASK = 0x04000000,
OBJECT_FLAG_GENERATION_SHIFT = 26,
};
typedef uint32_t TypeObjectFlags;
@ -980,6 +976,9 @@ class TypeNewScript
js_free(initializerList);
}
static inline void writeBarrierPre(TypeNewScript *newScript);
static void writeBarrierPost(TypeNewScript *newScript, void *addr) {}
bool analyzed() const {
if (preliminaryObjects) {
MOZ_ASSERT(!templateObject());
@ -1100,27 +1099,12 @@ struct TypeObject : public gc::TenuredCell
/* Flags for this object. */
TypeObjectFlags flags_;
enum AddendumKind {
Addendum_NewScript,
Addendum_TypeDescr
};
// If non-null, holds additional information about this object, whose
// format is indicated by the object's addendum kind.
void *addendum_;
void setAddendum(AddendumKind kind, void *addendum);
AddendumKind addendumKind() const {
return (AddendumKind)
((flags_ & OBJECT_FLAG_ADDENDUM_MASK) >> OBJECT_FLAG_ADDENDUM_SHIFT);
}
TypeNewScript *newScriptDontCheckGeneration() const {
return addendumKind() == Addendum_NewScript
? reinterpret_cast<TypeNewScript *>(addendum_)
: nullptr;
}
/*
* If specified, holds information about properties which are definitely
* added to objects of this type after being constructed by a particular
* script.
*/
HeapPtrTypeNewScript newScript_;
public:
@ -1141,23 +1125,10 @@ struct TypeObject : public gc::TenuredCell
TypeNewScript *newScript() {
maybeSweep(nullptr);
return newScriptDontCheckGeneration();
return newScript_;
}
void setNewScript(TypeNewScript *newScript) {
setAddendum(Addendum_NewScript, newScript);
}
TypeDescr &typeDescr() {
// Note: there is no need to sweep when accessing the type descriptor
// of an object, as it is strongly held and immutable.
MOZ_ASSERT(addendumKind() == Addendum_TypeDescr);
return *reinterpret_cast<TypeDescr *>(addendum_);
}
void setTypeDescr(TypeDescr *descr) {
setAddendum(Addendum_TypeDescr, descr);
}
void setNewScript(TypeNewScript *newScript);
private:
/*
@ -1318,8 +1289,8 @@ struct TypeObject : public gc::TenuredCell
return offsetof(TypeObject, proto_);
}
static inline uint32_t offsetOfAddendum() {
return offsetof(TypeObject, addendum_);
static inline uint32_t offsetOfNewScript() {
return offsetof(TypeObject, newScript_);
}
static inline uint32_t offsetOfFlags() {
@ -1336,50 +1307,49 @@ struct TypeObject : public gc::TenuredCell
};
/*
* Entries for the per-compartment set of type objects which are the default
* types to use for some prototype. An optional associated object is used which
* allows multiple type objects to be created with the same prototype. The
* associated object may be a function (for types constructed with 'new') or a
* type descriptor (for typed objects). These entries are also used for the set
* of lazy type objects in the compartment, which use a null associated object
* (though there are only a few of these per compartment).
* Entries for the per-compartment set of type objects which are 'new' types to
* use for some prototype and constructed with an optional script. This also
* includes entries for the set of lazy type objects in the compartment, which
* use a null script (though there are only a few of these per compartment).
*/
struct NewTypeObjectEntry
struct TypeObjectWithNewScriptEntry
{
ReadBarrieredTypeObject object;
// Note: This pointer is only used for equality and does not need a read barrier.
JSObject *associated;
JSFunction *newFunction;
NewTypeObjectEntry(TypeObject *object, JSObject *associated)
: object(object), associated(associated)
TypeObjectWithNewScriptEntry(TypeObject *object, JSFunction *newFunction)
: object(object), newFunction(newFunction)
{}
struct Lookup {
const Class *clasp;
TaggedProto hashProto;
TaggedProto matchProto;
JSObject *associated;
JSFunction *newFunction;
Lookup(const Class *clasp, TaggedProto proto, JSObject *associated)
: clasp(clasp), hashProto(proto), matchProto(proto), associated(associated)
Lookup(const Class *clasp, TaggedProto proto, JSFunction *newFunction)
: clasp(clasp), hashProto(proto), matchProto(proto), newFunction(newFunction)
{}
/*
* For use by generational post barriers only. Look up an entry whose
* proto has been moved, but was hashed with the original value.
*/
Lookup(const Class *clasp, TaggedProto hashProto, TaggedProto matchProto, JSObject *associated)
: clasp(clasp), hashProto(hashProto), matchProto(matchProto), associated(associated)
Lookup(const Class *clasp, TaggedProto hashProto, TaggedProto matchProto, JSFunction *newFunction)
: clasp(clasp), hashProto(hashProto), matchProto(matchProto), newFunction(newFunction)
{}
};
static inline HashNumber hash(const Lookup &lookup);
static inline bool match(const NewTypeObjectEntry &key, const Lookup &lookup);
static void rekey(NewTypeObjectEntry &k, const NewTypeObjectEntry& newKey) { k = newKey; }
static inline bool match(const TypeObjectWithNewScriptEntry &key, const Lookup &lookup);
static void rekey(TypeObjectWithNewScriptEntry &k, const TypeObjectWithNewScriptEntry& newKey) { k = newKey; }
};
typedef HashSet<NewTypeObjectEntry, NewTypeObjectEntry, SystemAllocPolicy> NewTypeObjectTable;
typedef HashSet<TypeObjectWithNewScriptEntry,
TypeObjectWithNewScriptEntry,
SystemAllocPolicy> TypeObjectWithNewScriptSet;
/* Whether to use a new type object when calling 'new' at script/pc. */
bool

View File

@ -1208,7 +1208,7 @@ inline TypeObject::TypeObject(const Class *clasp, TaggedProto proto, TypeObjectF
inline void
TypeObject::finalize(FreeOp *fop)
{
fop->delete_(newScriptDontCheckGeneration());
fop->delete_(newScript_.get());
}
inline uint32_t
@ -1300,6 +1300,17 @@ TypeObject::getProperty(unsigned i)
return propertySet[i];
}
inline void
TypeNewScript::writeBarrierPre(TypeNewScript *newScript)
{
if (!newScript || !newScript->fun->runtimeFromAnyThread()->needsIncrementalBarrier())
return;
JS::Zone *zone = newScript->fun->zoneFromAnyThread();
if (zone->needsIncrementalBarrier())
newScript->trace(zone->barrierTracer());
}
} } /* namespace js::types */
inline js::types::TypeScript *

View File

@ -1166,9 +1166,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FNINFO("TypedObjectIsAttached",
JSNativeThreadSafeWrapper<js::TypedObjectIsAttached>,
&js::TypedObjectIsAttachedJitInfo, 1, 0),
JS_FNINFO("TypedObjectTypeDescr",
JSNativeThreadSafeWrapper<js::TypedObjectTypeDescr>,
&js::TypedObjectTypeDescrJitInfo, 1, 0),
JS_FNINFO("ObjectIsOpaqueTypedObject",
intrinsic_ObjectIsOpaqueTypedObject,
&js::ObjectIsOpaqueTypedObjectJitInfo, 1, 0),