Bug 987807 - Split a NewSingletonCallObject out of NewCallObject. This produces slightly leaner code and creates all call objects with the correct type initial type from birth. r=terrence

--HG--
extra : rebase_source : 6b27082de6e5c05e0bf672d56a8701a39c8c7090
This commit is contained in:
Jeff Walden 2014-01-15 17:55:39 -05:00
parent 640a8498c2
commit e2d24041ab
14 changed files with 221 additions and 60 deletions

View File

@ -3537,8 +3537,7 @@ CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
return true;
}
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape,
HandleTypeObject, HeapSlot *);
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleShape, HandleTypeObject, HeapSlot *);
static const VMFunction NewCallObjectInfo =
FunctionInfo<NewCallObjectFn>(NewCallObject);
@ -3550,48 +3549,78 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
JSObject *templateObj = lir->mir()->templateObject();
// If we have a template object, we can inline call object creation.
OutOfLineCode *ool;
if (lir->slots()->isRegister()) {
ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->type()),
ToRegister(lir->slots())),
StoreRegisterTo(objReg));
} else {
ool = oolCallVM(NewCallObjectInfo, lir,
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
ImmGCPtr(templateObj->type()),
ImmPtr(nullptr)),
StoreRegisterTo(objReg));
}
if (!ool)
return false;
if (lir->mir()->needsSingletonType()
#ifdef JSGC_GENERATIONAL
// Slot initialization is not barriered in this case, so we must either
if (ins->templateObject()->hasDynamicSlots()) {
// Slot initialization is unbarriered in this case, so we must either
// allocate in the nursery or bail if that is not possible.
|| lir->mir()->templateObject()->hasDynamicSlots()
#endif
)
{
// Objects can only be given singleton types in VM calls.
masm.jump(ool->entry());
} else {
} else
#endif
{
// Inline call object creation, using the OOL path only for tricky cases.
masm.newGCThing(objReg, tempReg, templateObj, ool->entry(), gc::DefaultHeap);
masm.initGCThing(objReg, tempReg, templateObj);
if (lir->slots()->isRegister())
masm.storePtr(ToRegister(lir->slots()), Address(objReg, JSObject::offsetOfSlots()));
}
if (lir->slots()->isRegister())
masm.storePtr(ToRegister(lir->slots()), Address(objReg, JSObject::offsetOfSlots()));
masm.bind(ool->rejoin());
return true;
}
typedef JSObject *(*NewSingletonCallObjectFn)(JSContext *, HandleShape, HeapSlot *);
static const VMFunction NewSingletonCallObjectInfo =
FunctionInfo<NewSingletonCallObjectFn>(NewSingletonCallObject);
bool
CodeGenerator::visitNewSingletonCallObject(LNewSingletonCallObject *lir)
{
Register objReg = ToRegister(lir->output());
JSObject *templateObj = lir->mir()->templateObject();
OutOfLineCode *ool;
if (lir->slots()->isRegister()) {
ool = oolCallVM(NewSingletonCallObjectInfo, lir,
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
ToRegister(lir->slots())),
StoreRegisterTo(objReg));
} else {
ool = oolCallVM(NewSingletonCallObjectInfo, lir,
(ArgList(), ImmGCPtr(templateObj->lastProperty()),
ImmPtr(nullptr)),
StoreRegisterTo(objReg));
}
if (!ool)
return false;
// Objects can only be given singleton types in VM calls. We make the call
// out of line to not bloat inline code, even if (naively) this seems like
// extra work.
masm.jump(ool->entry());
masm.bind(ool->rejoin());
return true;
}
bool
CodeGenerator::visitNewCallObjectPar(LNewCallObjectPar *lir)
{

View File

@ -140,6 +140,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitOutOfLineNewObject(OutOfLineNewObject *ool);
bool visitNewDeclEnvObject(LNewDeclEnvObject *lir);
bool visitNewCallObject(LNewCallObject *lir);
bool visitNewSingletonCallObject(LNewSingletonCallObject *lir);
bool visitNewCallObjectPar(LNewCallObjectPar *lir);
bool visitNewStringObject(LNewStringObject *lir);
bool visitNewPar(LNewPar *lir);

View File

@ -4682,7 +4682,11 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
// instructions could potentially bailout, thus leaking the dynamic slots
// pointer. Run-once scripts need a singleton type, so always do a VM call
// in such cases.
MNewCallObject *callObj = MNewCallObject::New(alloc(), templateObj, script()->treatAsRunOnce(), slots);
MUnaryInstruction *callObj;
if (script()->treatAsRunOnce())
callObj = MNewRunOnceCallObject::New(alloc(), templateObj, slots);
else
callObj = MNewCallObject::New(alloc(), templateObj, slots);
current->add(callObj);
// Initialize the object's reserved slots. No post barrier is needed here,

View File

@ -490,11 +490,36 @@ class LNewCallObject : public LInstructionHelper<1, 1, 1>
const LAllocation *slots() {
return getOperand(0);
}
MNewCallObject *mir() const {
return mir_->toNewCallObject();
}
};
// Allocates a new CallObject with singleton type through an out-of-line VM
// call. The inputs are:
// slots: either a reg representing a HeapSlot *, or a placeholder
// meaning that no slots pointer is needed.
//
class LNewSingletonCallObject : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(NewSingletonCallObject)
LNewSingletonCallObject(const LAllocation &slots) {
setOperand(0, slots);
}
const LAllocation *slots() {
return getOperand(0);
}
MNewCallObjectBase * mir() const {
MOZ_ASSERT(mir_->isNewCallObject() || mir_->isNewRunOnceCallObject());
return static_cast<MNewCallObjectBase *>(mir_);
}
};
class LNewCallObjectPar : public LInstructionHelper<1, 2, 2>
{
LNewCallObjectPar(const LAllocation &cx, const LAllocation &slots,
@ -2410,7 +2435,7 @@ class LMinMaxD : public LInstructionHelper<1, 2, 0>
{
public:
LIR_HEADER(MinMaxD)
LMinMaxD(const LAllocation &first, const LAllocation &second)
LMinMaxD(const LAllocation &first, const LAllocation &second)
{
setOperand(0, first);
setOperand(1, second);

View File

@ -28,6 +28,7 @@
_(NewSlots) \
_(NewDeclEnvObject) \
_(NewCallObject) \
_(NewSingletonCallObject) \
_(NewStringObject) \
_(NewPar) \
_(NewDenseArrayPar) \

View File

@ -201,7 +201,35 @@ LIRGenerator::visitNewCallObject(MNewCallObject *ins)
else
slots = LConstantIndex::Bogus();
LNewCallObject *lir = new(alloc()) LNewCallObject(slots, temp());
LInstruction *lir;
if (ins->templateObject()->hasSingletonType()) {
LNewSingletonCallObject *singletonLir = new(alloc()) LNewSingletonCallObject(slots);
if (!define(singletonLir, ins))
return false;
lir = singletonLir;
} else {
LNewCallObject *normalLir = new(alloc()) LNewCallObject(slots, temp());
if (!define(normalLir, ins))
return false;
lir = normalLir;
}
if (!assignSafepoint(lir, ins))
return false;
return true;
}
bool
LIRGenerator::visitNewRunOnceCallObject(MNewRunOnceCallObject *ins)
{
LAllocation slots;
if (ins->slots()->type() == MIRType_Slots)
slots = useRegister(ins->slots());
else
slots = LConstantIndex::Bogus();
LNewSingletonCallObject *lir = new(alloc()) LNewSingletonCallObject(slots);
if (!define(lir, ins))
return false;

View File

@ -71,6 +71,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitNewObject(MNewObject *ins);
bool visitNewDeclEnvObject(MNewDeclEnvObject *ins);
bool visitNewCallObject(MNewCallObject *ins);
bool visitNewRunOnceCallObject(MNewRunOnceCallObject *ins);
bool visitNewStringObject(MNewStringObject *ins);
bool visitNewDerivedTypedObject(MNewDerivedTypedObject *ins);
bool visitNewPar(MNewPar *ins);

View File

@ -9018,42 +9018,62 @@ class MNewDeclEnvObject : public MNullaryInstruction
}
};
class MNewCallObject : public MUnaryInstruction
class MNewCallObjectBase : public MUnaryInstruction
{
CompilerRootObject templateObj_;
bool needsSingletonType_;
MNewCallObject(JSObject *templateObj, bool needsSingletonType, MDefinition *slots)
protected:
MNewCallObjectBase(JSObject *templateObj, MDefinition *slots)
: MUnaryInstruction(slots),
templateObj_(templateObj),
needsSingletonType_(needsSingletonType)
templateObj_(templateObj)
{
setResultType(MIRType_Object);
}
public:
INSTRUCTION_HEADER(NewCallObject)
static MNewCallObject *New(TempAllocator &alloc, JSObject *templateObj, bool needsSingletonType,
MDefinition *slots)
{
return new(alloc) MNewCallObject(templateObj, needsSingletonType, slots);
}
MDefinition *slots() {
return getOperand(0);
}
JSObject *templateObject() {
return templateObj_;
}
bool needsSingletonType() const {
return needsSingletonType_;
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
};
class MNewCallObject : public MNewCallObjectBase
{
public:
INSTRUCTION_HEADER(NewCallObject)
MNewCallObject(JSObject *templateObj, MDefinition *slots)
: MNewCallObjectBase(templateObj, slots)
{}
static MNewCallObject *
New(TempAllocator &alloc, JSObject *templateObj, MDefinition *slots)
{
return new(alloc) MNewCallObject(templateObj, slots);
}
};
class MNewRunOnceCallObject : public MNewCallObjectBase
{
public:
INSTRUCTION_HEADER(NewRunOnceCallObject)
MNewRunOnceCallObject(JSObject *templateObj, MDefinition *slots)
: MNewCallObjectBase(templateObj, slots)
{}
static MNewRunOnceCallObject *
New(TempAllocator &alloc, JSObject *templateObj, MDefinition *slots)
{
return new(alloc) MNewRunOnceCallObject(templateObj, slots);
}
};
class MNewCallObjectPar : public MBinaryInstruction
{
CompilerRootObject templateObj_;
@ -9068,7 +9088,7 @@ class MNewCallObjectPar : public MBinaryInstruction
public:
INSTRUCTION_HEADER(NewCallObjectPar);
static MNewCallObjectPar *New(TempAllocator &alloc, MDefinition *cx, MNewCallObject *callObj) {
static MNewCallObjectPar *New(TempAllocator &alloc, MDefinition *cx, MNewCallObjectBase *callObj) {
return new(alloc) MNewCallObjectPar(cx, callObj->templateObject(), callObj->slots());
}

View File

@ -90,6 +90,7 @@ namespace jit {
_(NewObject) \
_(NewDeclEnvObject) \
_(NewCallObject) \
_(NewRunOnceCallObject) \
_(NewStringObject) \
_(InitElem) \
_(InitElemGetterSetter) \

View File

@ -183,6 +183,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
CUSTOM_OP(NewArray)
CUSTOM_OP(NewObject)
CUSTOM_OP(NewCallObject)
CUSTOM_OP(NewRunOnceCallObject)
CUSTOM_OP(NewDerivedTypedObject)
UNSAFE_OP(InitElem)
UNSAFE_OP(InitElemGetterSetter)
@ -531,6 +532,13 @@ ParallelSafetyVisitor::visitNewCallObject(MNewCallObject *ins)
return true;
}
bool
ParallelSafetyVisitor::visitNewRunOnceCallObject(MNewRunOnceCallObject *ins)
{
replace(ins, MNewCallObjectPar::New(alloc(), ForkJoinContext(), ins));
return true;
}
bool
ParallelSafetyVisitor::visitLambda(MLambda *ins)
{

View File

@ -525,10 +525,9 @@ NewSlots(JSRuntime *rt, unsigned nslots)
}
JSObject *
NewCallObject(JSContext *cx, HandleScript script,
HandleShape shape, HandleTypeObject type, HeapSlot *slots)
NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
{
JSObject *obj = CallObject::create(cx, script, shape, type, slots);
JSObject *obj = CallObject::create(cx, shape, type, slots);
if (!obj)
return nullptr;
@ -543,6 +542,25 @@ NewCallObject(JSContext *cx, HandleScript script,
return obj;
}
JSObject *
NewSingletonCallObject(JSContext *cx, HandleShape shape, HeapSlot *slots)
{
JSObject *obj = CallObject::createSingleton(cx, shape, slots);
if (!obj)
return nullptr;
#ifdef JSGC_GENERATIONAL
// The JIT creates call objects in the nursery, so elides barriers for
// the initializing writes. The interpreter, however, may have allocated
// the call object tenured, so barrier as needed before re-entering.
MOZ_ASSERT(!IsInsideNursery(cx->runtime(), obj),
"singletons are created in the tenured heap");
cx->runtime()->gcStoreBuffer.putWholeCell(obj);
#endif
return obj;
}
JSObject *
NewStringObject(JSContext *cx, HandleString str)
{

View File

@ -618,8 +618,8 @@ bool SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, Handl
bool InterruptCheck(JSContext *cx);
HeapSlot *NewSlots(JSRuntime *rt, unsigned nslots);
JSObject *NewCallObject(JSContext *cx, HandleScript script,
HandleShape shape, HandleTypeObject type, HeapSlot *slots);
JSObject *NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
JSObject *NewSingletonCallObject(JSContext *cx, HandleShape shape, HeapSlot *slots);
JSObject *NewStringObject(JSContext *cx, HandleString str);
bool SPSEnter(JSContext *cx, HandleScript script);

View File

@ -136,28 +136,39 @@ ScopeObject::setEnclosingScope(HandleObject obj)
setFixedSlot(SCOPE_CHAIN_SLOT, ObjectValue(*obj));
}
/*
* Construct a bare-bones call object given a shape, type, and slots pointer.
* The call object must be further initialized to be usable.
*/
CallObject *
CallObject::create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
CallObject::create(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
{
MOZ_ASSERT(!type->singleton(),
"passed a singleton type to create() (use createSingleton() "
"instead)");
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
JS_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
kind = gc::GetBackgroundAllocKind(kind);
gc::InitialHeap heap = script->treatAsRunOnce() ? gc::TenuredHeap : gc::DefaultHeap;
JSObject *obj = JSObject::create(cx, kind, heap, shape, type, slots);
JSObject *obj = JSObject::create(cx, kind, gc::DefaultHeap, shape, type, slots);
if (!obj)
return nullptr;
if (script->treatAsRunOnce()) {
RootedObject nobj(cx, obj);
if (!JSObject::setSingletonType(cx, nobj))
return nullptr;
return &nobj->as<CallObject>();
}
return &obj->as<CallObject>();
}
CallObject *
CallObject::createSingleton(JSContext *cx, HandleShape shape, HeapSlot *slots)
{
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
kind = gc::GetBackgroundAllocKind(kind);
RootedTypeObject type(cx, cx->getSingletonType(&class_, nullptr));
if (!type)
return nullptr;
RootedObject obj(cx, JSObject::create(cx, kind, gc::TenuredHeap, shape, type, slots));
if (!obj)
return nullptr;
MOZ_ASSERT(obj->hasSingletonType(),
"type created inline above must be a singleton");
return &obj->as<CallObject>();
}

View File

@ -236,8 +236,22 @@ class CallObject : public ScopeObject
static const Class class_;
/* These functions are internal and are exposed only for JITs. */
/*
* Construct a bare-bones call object given a shape, a non-singleton type,
* and slots pointer. The call object must be further initialized to be
* usable.
*/
static CallObject *
create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
create(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
/*
* Construct a bare-bones call object given a shape and slots pointer, and
* make it have singleton type. The call object must be initialized to be
* usable.
*/
static CallObject *
createSingleton(JSContext *cx, HandleShape shape, HeapSlot *slots);
static CallObject *
createTemplateObject(JSContext *cx, HandleScript script, gc::InitialHeap heap);