Bug 969012 - Allow inlining out-of-line slot creation in IonMonkey; r=jandem

This commit is contained in:
Terrence Cole 2014-03-06 14:58:22 -08:00
Родитель a0436d61c4
Коммит ef1260f7b2
22 изменённых файлов: 378 добавлений и 362 удалений

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

@ -3,15 +3,6 @@ load(libdir + "parallelarray-helpers.js");
function testClosureCreationAndInvocation() { function testClosureCreationAndInvocation() {
var a = range(0, 64); var a = range(0, 64);
function makeaddv(v) { function makeaddv(v) {
var u = 1;
var t = 2;
var s = 3;
var r = 4;
var q = 5;
var p = 6;
var o = 7;
var n = 8;
var m = 9;
var l = 10; var l = 10;
var k = 11; var k = 11;
var j = 12; var j = 12;
@ -34,11 +25,6 @@ function testClosureCreationAndInvocation() {
case 6: return g; case 7: return h; case 6: return g; case 7: return h;
case 8: return i; case 9: return j; case 8: return i; case 9: return j;
case 10: return k; case 11: return l; case 10: return k; case 11: return l;
case 12: return m; case 13: return n;
case 14: return o; case 15: return p;
case 16: return q; case 17: return r;
case 18: return s; case 19: return t;
case 20: return u;
} }
}); });
} }

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

@ -3,15 +3,6 @@ load(libdir + "parallelarray-helpers.js");
function testClosureCreationAndInvocation() { function testClosureCreationAndInvocation() {
var a = range(0, 64); var a = range(0, 64);
function makeaddv(v) { function makeaddv(v) {
var u = 1;
var t = 2;
var s = 3;
var r = 4;
var q = 5;
var p = 6;
var o = 7;
var n = 8;
var m = 9;
var l = 10; var l = 10;
var k = 11; var k = 11;
var j = 12; var j = 12;
@ -32,11 +23,6 @@ function testClosureCreationAndInvocation() {
case 6: return g; case 7: return h; case 6: return g; case 7: return h;
case 8: return i; case 9: return j; case 8: return i; case 9: return j;
case 10: return k; case 11: return l; case 10: return k; case 11: return l;
case 12: return m; case 13: return n;
case 14: return o; case 15: return p;
case 16: return q; case 17: return r;
case 18: return s; case 19: return t;
case 20: return u;
} }
}; };
}; };

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

@ -972,8 +972,7 @@ CodeGenerator::visitLambda(LLambda *lir)
JS_ASSERT(!info.singletonType); JS_ASSERT(!info.singletonType);
masm.newGCThing(output, tempReg, info.fun, ool->entry(), gc::DefaultHeap); masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
masm.initGCThing(output, tempReg, info.fun);
emitLambdaInit(output, scopeChain, info); emitLambdaInit(output, scopeChain, info);
@ -3337,29 +3336,6 @@ CodeGenerator::visitNewDerivedTypedObject(LNewDerivedTypedObject *lir)
return callVM(CreateDerivedTypedObjInfo, lir); return callVM(CreateDerivedTypedObjInfo, lir);
} }
bool
CodeGenerator::visitNewSlots(LNewSlots *lir)
{
Register temp1 = ToRegister(lir->temp1());
Register temp2 = ToRegister(lir->temp2());
Register temp3 = ToRegister(lir->temp3());
Register output = ToRegister(lir->output());
masm.mov(ImmPtr(GetIonContext()->runtime), temp1);
masm.mov(ImmWord(lir->mir()->nslots()), temp2);
masm.setupUnalignedABICall(2, temp3);
masm.passABIArg(temp1);
masm.passABIArg(temp2);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewSlots));
masm.testPtr(output, output);
if (!bailoutIf(Assembler::Zero, lir->snapshot()))
return false;
return true;
}
bool CodeGenerator::visitAtan2D(LAtan2D *lir) bool CodeGenerator::visitAtan2D(LAtan2D *lir)
{ {
Register temp = ToRegister(lir->temp()); Register temp = ToRegister(lir->temp());
@ -3408,8 +3384,7 @@ CodeGenerator::visitNewArray(LNewArray *lir)
if (!addOutOfLineCode(ool)) if (!addOutOfLineCode(ool))
return false; return false;
masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap()); masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
masm.initGCThing(objReg, tempReg, templateObject);
masm.bind(ool->rejoin()); masm.bind(ool->rejoin());
return true; return true;
@ -3495,8 +3470,7 @@ CodeGenerator::visitNewObject(LNewObject *lir)
if (!addOutOfLineCode(ool)) if (!addOutOfLineCode(ool))
return false; return false;
masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap()); masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
masm.initGCThing(objReg, tempReg, templateObject);
masm.bind(ool->rejoin()); masm.bind(ool->rejoin());
return true; return true;
@ -3531,14 +3505,13 @@ CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
if (!ool) if (!ool)
return false; return false;
masm.newGCThing(objReg, tempReg, templateObj, ool->entry(), gc::DefaultHeap); masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry());
masm.initGCThing(objReg, tempReg, templateObj);
masm.bind(ool->rejoin()); masm.bind(ool->rejoin());
return true; return true;
} }
typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape, typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape, HandleTypeObject);
HandleTypeObject, HeapSlot *);
static const VMFunction NewCallObjectInfo = static const VMFunction NewCallObjectInfo =
FunctionInfo<NewCallObjectFn>(NewCallObject); FunctionInfo<NewCallObjectFn>(NewCallObject);
@ -3551,22 +3524,11 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
JSObject *templateObj = lir->mir()->templateObject(); JSObject *templateObj = lir->mir()->templateObject();
// If we have a template object, we can inline call object creation. // If we have a template object, we can inline call object creation.
OutOfLineCode *ool; OutOfLineCode *ool = oolCallVM(NewCallObjectInfo, lir,
if (lir->slots()->isRegister()) { (ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
ool = oolCallVM(NewCallObjectInfo, lir, ImmGCPtr(templateObj->lastProperty()),
(ArgList(), ImmGCPtr(lir->mir()->block()->info().script()), ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type())),
ImmGCPtr(templateObj->lastProperty()), StoreRegisterTo(objReg));
ImmGCPtr(templateObj->hasSingletonType() ? nullptr : 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()),
ImmPtr(nullptr)),
StoreRegisterTo(objReg));
}
if (!ool) if (!ool)
return false; return false;
@ -3574,11 +3536,7 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir)
// Objects can only be given singleton types in VM calls. // Objects can only be given singleton types in VM calls.
masm.jump(ool->entry()); masm.jump(ool->entry());
} else { } else {
masm.newGCThing(objReg, tempReg, templateObj, ool->entry(), gc::DefaultHeap); masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry());
masm.initGCThing(objReg, tempReg, templateObj);
if (lir->slots()->isRegister())
masm.storePtr(ToRegister(lir->slots()), Address(objReg, JSObject::offsetOfSlots()));
} }
masm.bind(ool->rejoin()); masm.bind(ool->rejoin());
@ -3595,17 +3553,6 @@ CodeGenerator::visitNewCallObjectPar(LNewCallObjectPar *lir)
JSObject *templateObj = lir->mir()->templateObj(); JSObject *templateObj = lir->mir()->templateObj();
emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, templateObj); emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, templateObj);
// NB: !lir->slots()->isRegister() implies that there is no slots
// array at all, and the memory is already zeroed when copying
// from the template object
if (lir->slots()->isRegister()) {
Register slotsReg = ToRegister(lir->slots());
JS_ASSERT(slotsReg != resultReg);
masm.storePtr(slotsReg, Address(resultReg, JSObject::offsetOfSlots()));
}
return true; return true;
} }
@ -3664,8 +3611,7 @@ CodeGenerator::visitNewStringObject(LNewStringObject *lir)
if (!ool) if (!ool)
return false; return false;
masm.newGCThing(output, temp, templateObj, ool->entry(), gc::DefaultHeap); masm.createGCObject(output, temp, templateObj, gc::DefaultHeap, ool->entry());
masm.initGCThing(output, temp, templateObj);
masm.loadStringLength(input, temp); masm.loadStringLength(input, temp);
@ -3910,7 +3856,7 @@ CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
return false; return false;
// Allocate. If the FreeList is empty, call to VM, which may GC. // Allocate. If the FreeList is empty, call to VM, which may GC.
masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap()); masm.newGCThing(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
// Initialize based on the templateObject. // Initialize based on the templateObject.
masm.bind(ool->rejoin()); masm.bind(ool->rejoin());
@ -4979,6 +4925,70 @@ JitCompartment::generateStringConcatStub(JSContext *cx, ExecutionMode mode)
return code; return code;
} }
JitCode *
JitRuntime::generateMallocStub(JSContext *cx)
{
const Register regReturn = CallTempReg0;
const Register regNBytes = CallTempReg0;
const Register regRuntime = CallTempReg1;
const Register regTemp = CallTempReg1;
MacroAssembler masm(cx);
RegisterSet regs = RegisterSet::Volatile();
regs.takeUnchecked(regNBytes);
masm.PushRegsInMask(regs);
masm.setupUnalignedABICall(2, regTemp);
masm.movePtr(ImmPtr(cx->runtime()), regRuntime);
masm.passABIArg(regRuntime);
masm.passABIArg(regNBytes);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MallocWrapper));
masm.storeCallResult(regReturn);
masm.PopRegsInMask(regs);
masm.ret();
Linker linker(masm);
JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
#ifdef JS_ION_PERF
writePerfSpewerJitCodeProfile(code, "MallocStub");
#endif
return code;
}
JitCode *
JitRuntime::generateFreeStub(JSContext *cx)
{
const Register regSlots = CallTempReg0;
const Register regTemp = CallTempReg1;
MacroAssembler masm(cx);
RegisterSet regs = RegisterSet::Volatile();
regs.takeUnchecked(regSlots);
masm.PushRegsInMask(regs);
masm.setupUnalignedABICall(1, regTemp);
masm.passABIArg(regSlots);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js_free));
masm.PopRegsInMask(regs);
masm.ret();
Linker linker(masm);
JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
#ifdef JS_ION_PERF
writePerfSpewerJitCodeProfile(code, "FreeStub");
#endif
return code;
}
typedef bool (*CharCodeAtFn)(JSContext *, HandleString, int32_t, uint32_t *); typedef bool (*CharCodeAtFn)(JSContext *, HandleString, int32_t, uint32_t *);
static const VMFunction CharCodeAtInfo = FunctionInfo<CharCodeAtFn>(jit::CharCodeAt); static const VMFunction CharCodeAtInfo = FunctionInfo<CharCodeAtFn>(jit::CharCodeAt);
@ -5632,9 +5642,7 @@ CodeGenerator::visitArrayConcat(LArrayConcat *lir)
masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail); masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
// Try to allocate an object. // Try to allocate an object.
JSObject *templateObj = lir->mir()->templateObj(); masm.createGCObject(temp1, temp2, lir->mir()->templateObj(), lir->mir()->initialHeap(), &fail);
masm.newGCThing(temp1, temp2, templateObj, &fail, lir->mir()->initialHeap());
masm.initGCThing(temp1, temp2, templateObj);
masm.jump(&call); masm.jump(&call);
{ {
masm.bind(&fail); masm.bind(&fail);
@ -6005,8 +6013,7 @@ CodeGenerator::visitRest(LRest *lir)
JSObject *templateObject = lir->mir()->templateObject(); JSObject *templateObject = lir->mir()->templateObject();
Label joinAlloc, failAlloc; Label joinAlloc, failAlloc;
masm.newGCThing(temp2, temp0, templateObject, &failAlloc, gc::DefaultHeap); masm.createGCObject(temp2, temp0, templateObject, gc::DefaultHeap, &failAlloc);
masm.initGCThing(temp2, temp0, templateObject);
masm.jump(&joinAlloc); masm.jump(&joinAlloc);
{ {
masm.bind(&failAlloc); masm.bind(&failAlloc);

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

@ -131,7 +131,6 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitCallDirectEvalV(LCallDirectEvalV *lir); bool visitCallDirectEvalV(LCallDirectEvalV *lir);
bool visitDoubleToInt32(LDoubleToInt32 *lir); bool visitDoubleToInt32(LDoubleToInt32 *lir);
bool visitFloat32ToInt32(LFloat32ToInt32 *lir); bool visitFloat32ToInt32(LFloat32ToInt32 *lir);
bool visitNewSlots(LNewSlots *lir);
bool visitNewArrayCallVM(LNewArray *lir); bool visitNewArrayCallVM(LNewArray *lir);
bool visitNewArray(LNewArray *lir); bool visitNewArray(LNewArray *lir);
bool visitOutOfLineNewArray(OutOfLineNewArray *ool); bool visitOutOfLineNewArray(OutOfLineNewArray *ool);

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

@ -268,6 +268,16 @@ JitRuntime::initialize(JSContext *cx)
if (!shapePreBarrier_) if (!shapePreBarrier_)
return false; return false;
IonSpew(IonSpew_Codegen, "# Emitting malloc stub");
mallocStub_ = generateMallocStub(cx);
if (!mallocStub_)
return false;
IonSpew(IonSpew_Codegen, "# Emitting free stub");
freeStub_ = generateFreeStub(cx);
if (!freeStub_)
return false;
IonSpew(IonSpew_Codegen, "# Emitting VM function wrappers"); IonSpew(IonSpew_Codegen, "# Emitting VM function wrappers");
for (VMFunction *fun = VMFunction::functions; fun; fun = fun->next) { for (VMFunction *fun = VMFunction::functions; fun; fun = fun->next) {
if (!generateVMWrapper(cx, *fun)) if (!generateVMWrapper(cx, *fun))

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

@ -4667,23 +4667,9 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
// creation. // creation.
CallObject *templateObj = inspector->templateCallObject(); CallObject *templateObj = inspector->templateCallObject();
// If the CallObject needs dynamic slots, allocate those now. // Allocate the object. Run-once scripts need a singleton type, so always do
MInstruction *slots; // a VM call in such cases.
if (templateObj->hasDynamicSlots()) { MNewCallObject *callObj = MNewCallObject::New(alloc(), templateObj, script()->treatAsRunOnce());
size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlots(),
templateObj->lastProperty()->slotSpan(templateObj->getClass()),
templateObj->getClass());
slots = MNewSlots::New(alloc(), nslots);
} else {
slots = MConstant::New(alloc(), NullValue());
}
current->add(slots);
// Allocate the actual object. It is important that no intervening
// 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);
current->add(callObj); current->add(callObj);
// Initialize the object's reserved slots. No post barrier is needed here, // Initialize the object's reserved slots. No post barrier is needed here,
@ -4692,14 +4678,20 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::calleeSlot(), callee)); current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::calleeSlot(), callee));
// Initialize argument slots. // Initialize argument slots.
MSlots *slots = nullptr;
for (AliasedFormalIter i(script()); i; i++) { for (AliasedFormalIter i(script()); i; i++) {
unsigned slot = i.scopeSlot(); unsigned slot = i.scopeSlot();
unsigned formal = i.frameIndex(); unsigned formal = i.frameIndex();
MDefinition *param = current->getSlot(info().argSlotUnchecked(formal)); MDefinition *param = current->getSlot(info().argSlotUnchecked(formal));
if (slot >= templateObj->numFixedSlots()) if (slot >= templateObj->numFixedSlots()) {
if (!slots) {
slots = MSlots::New(alloc(), callObj);
current->add(slots);
}
current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlots(), param)); current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlots(), param));
else } else {
current->add(MStoreFixedSlot::New(alloc(), callObj, slot, param)); current->add(MStoreFixedSlot::New(alloc(), callObj, slot, param));
}
} }
return callObj; return callObj;
@ -7612,6 +7604,10 @@ IonBuilder::setElemTryTypedStatic(bool *emitted, MDefinition *object,
return true; return true;
TypedArrayObject *tarr = &tarrObj->as<TypedArrayObject>(); TypedArrayObject *tarr = &tarrObj->as<TypedArrayObject>();
if (gc::IsInsideNursery(tarr->runtimeFromMainThread(), tarr->viewData()))
return true;
ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type(); ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type();
MDefinition *ptr = convertShiftToMaskForStaticTypedArray(index, viewType); MDefinition *ptr = convertShiftToMaskForStaticTypedArray(index, viewType);

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

@ -633,14 +633,11 @@ MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
#endif #endif
} }
// Inlined version of gc::CheckAllocatorState that checks the bare essentials
// and bails for anything that cannot be handled with our jit allocators.
void void
MacroAssembler::newGCThing(Register result, Register temp, gc::AllocKind allocKind, Label *fail, MacroAssembler::checkAllocatorState(Label *fail)
gc::InitialHeap initialHeap /* = gc::DefaultHeap */)
{ {
// Inlined equivalent of js::gc::NewGCThing() without failure case handling.
int thingSize = int(gc::Arena::thingSize(allocKind));
#ifdef JS_GC_ZEAL #ifdef JS_GC_ZEAL
// Don't execute the inline path if gcZeal is active. // Don't execute the inline path if gcZeal is active.
branch32(Assembler::NotEqual, branch32(Assembler::NotEqual,
@ -652,29 +649,66 @@ MacroAssembler::newGCThing(Register result, Register temp, gc::AllocKind allocKi
// as the metadata to use for the object may vary between executions of the op. // as the metadata to use for the object may vary between executions of the op.
if (GetIonContext()->compartment->hasObjectMetadataCallback()) if (GetIonContext()->compartment->hasObjectMetadataCallback())
jump(fail); jump(fail);
}
// Inline version of ShouldNurseryAllocate.
bool
MacroAssembler::shouldNurseryAllocate(gc::AllocKind allocKind, gc::InitialHeap initialHeap)
{
#ifdef JSGC_GENERATIONAL #ifdef JSGC_GENERATIONAL
// Always use nursery allocation if it is possible to do so. The jit // Note that Ion elides barriers on writes to objects know to be in the
// assumes a nursery pointer is returned to avoid barriers. // nursery, so any allocation that can be made into the nursery must be made
if (allocKind <= gc::FINALIZE_OBJECT_LAST && initialHeap != gc::TenuredHeap) { // into the nursery, even if the nursery is disabled. At runtime these will
// Inline Nursery::allocate. No explicit check for nursery.isEnabled() // take the out-of-line path, which is required to insert a barrier for the
// is needed, as the comparison with the nursery's end will always fail // initializing writes.
// in such cases. return IsNurseryAllocable(allocKind) && initialHeap != gc::TenuredHeap;
const Nursery &nursery = GetIonContext()->runtime->gcNursery(); #else
loadPtr(AbsoluteAddress(nursery.addressOfPosition()), result); return false;
computeEffectiveAddress(Address(result, thingSize), temp); #endif
branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(nursery.addressOfCurrentEnd()), temp, fail); }
storePtr(temp, AbsoluteAddress(nursery.addressOfPosition()));
return; // Inline version of Nursery::allocateObject.
} void
MacroAssembler::nurseryAllocate(Register result, Register slots, gc::AllocKind allocKind,
size_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail)
{
#ifdef JSGC_GENERATIONAL
JS_ASSERT(IsNurseryAllocable(allocKind));
JS_ASSERT(initialHeap != gc::TenuredHeap);
// This allocation site is requesting too many dynamic slots. Several
// allocation sites assume that nursery allocation will succeed to
// avoid needing barriers later. Ensure these sites limit their slot
// requests appropriately.
JS_ASSERT(nDynamicSlots < Nursery::MaxNurserySlots);
// No explicit check for nursery.isEnabled() is needed, as the comparison
// with the nursery's end will always fail in such cases.
const Nursery &nursery = GetIonContext()->runtime->gcNursery();
Register temp = slots;
int thingSize = int(gc::Arena::thingSize(allocKind));
int totalSize = thingSize + nDynamicSlots * sizeof(HeapSlot);
loadPtr(AbsoluteAddress(nursery.addressOfPosition()), result);
computeEffectiveAddress(Address(result, totalSize), temp);
branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(nursery.addressOfCurrentEnd()), temp, fail);
storePtr(temp, AbsoluteAddress(nursery.addressOfPosition()));
if (nDynamicSlots)
computeEffectiveAddress(Address(result, thingSize), slots);
#endif // JSGC_GENERATIONAL #endif // JSGC_GENERATIONAL
}
// Inlined version of FreeSpan::allocate.
void
MacroAssembler::freeSpanAllocate(Register result, Register temp, gc::AllocKind allocKind, Label *fail)
{
CompileZone *zone = GetIonContext()->compartment->zone(); CompileZone *zone = GetIonContext()->compartment->zone();
int thingSize = int(gc::Arena::thingSize(allocKind));
// Inline FreeSpan::allocate. // Load FreeSpan::first of |zone|'s freeLists for |allocKind|. If there is
// There is always exactly one FreeSpan per allocKind per JSCompartment. // no room remaining in the span, we bail to finish the allocation. The
// If a FreeSpan is replaced, its members are updated in the freeLists table, // interpreter will call |refillFreeLists|, setting up a new FreeSpan so
// which the code below always re-reads. // that we can continue allocating in the jit.
loadPtr(AbsoluteAddress(zone->addressOfFreeListFirst(allocKind)), result); loadPtr(AbsoluteAddress(zone->addressOfFreeListFirst(allocKind)), result);
branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(zone->addressOfFreeListLast(allocKind)), result, fail); branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(zone->addressOfFreeListLast(allocKind)), result, fail);
computeEffectiveAddress(Address(result, thingSize), temp); computeEffectiveAddress(Address(result, thingSize), temp);
@ -682,25 +716,118 @@ MacroAssembler::newGCThing(Register result, Register temp, gc::AllocKind allocKi
} }
void void
MacroAssembler::newGCThing(Register result, Register temp, JSObject *templateObject, Label *fail, MacroAssembler::callMallocStub(size_t nbytes, Register result, Label *fail)
gc::InitialHeap initialHeap) {
// This register must match the one in JitRuntime::generateMallocStub.
const Register regNBytes = CallTempReg0;
JS_ASSERT(nbytes > 0);
JS_ASSERT(nbytes <= INT32_MAX);
if (regNBytes != result)
push(regNBytes);
move32(Imm32(nbytes), regNBytes);
call(GetIonContext()->runtime->jitRuntime()->mallocStub());
if (regNBytes != result) {
movePtr(regNBytes, result);
pop(regNBytes);
}
branchTest32(Assembler::Zero, result, result, fail);
}
void
MacroAssembler::callFreeStub(Register slots)
{
// This register must match the one in JitRuntime::generateFreeStub.
const Register regSlots = CallTempReg0;
push(regSlots);
movePtr(slots, regSlots);
call(GetIonContext()->runtime->jitRuntime()->freeStub());
pop(regSlots);
}
// Inlined equivalent of gc::AllocateObject, without failure case handling.
void
MacroAssembler::allocateObject(Register result, Register slots, gc::AllocKind allocKind,
uint32_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail)
{ {
gc::AllocKind allocKind = templateObject->tenuredGetAllocKind();
JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST); JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
newGCThing(result, temp, allocKind, fail, initialHeap); checkAllocatorState(fail);
if (shouldNurseryAllocate(allocKind, initialHeap))
return nurseryAllocate(result, slots, allocKind, nDynamicSlots, initialHeap, fail);
if (!nDynamicSlots)
return freeSpanAllocate(result, slots, allocKind, fail);
callMallocStub(nDynamicSlots * sizeof(HeapValue), slots, fail);
Label failAlloc;
Label success;
push(slots);
freeSpanAllocate(result, slots, allocKind, &failAlloc);
pop(slots);
jump(&success);
bind(&failAlloc);
pop(slots);
callFreeStub(slots);
jump(fail);
bind(&success);
}
void
MacroAssembler::newGCThing(Register result, Register temp, JSObject *templateObj,
gc::InitialHeap initialHeap, Label *fail)
{
// This method does not initialize the object: if external slots get
// allocated into |temp|, there is no easy way for us to ensure the caller
// frees them. Instead just assert this case does not happen.
JS_ASSERT(!templateObj->numDynamicSlots());
gc::AllocKind allocKind = templateObj->tenuredGetAllocKind();
JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
allocateObject(result, temp, allocKind, templateObj->numDynamicSlots(), initialHeap, fail);
}
void
MacroAssembler::createGCObject(Register obj, Register temp, JSObject *templateObj,
gc::InitialHeap initialHeap, Label *fail)
{
uint32_t nDynamicSlots = templateObj->numDynamicSlots();
gc::AllocKind allocKind = templateObj->tenuredGetAllocKind();
JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
allocateObject(obj, temp, allocKind, nDynamicSlots, initialHeap, fail);
initGCThing(obj, temp, templateObj);
}
// Inlined equivalent of gc::AllocateNonObject, without failure case handling.
// Non-object allocation does not need to worry about slots, so can take a
// simpler path.
void
MacroAssembler::allocateNonObject(Register result, Register temp, gc::AllocKind allocKind, Label *fail)
{
checkAllocatorState(fail);
freeSpanAllocate(result, temp, allocKind, fail);
} }
void void
MacroAssembler::newGCString(Register result, Register temp, Label *fail) MacroAssembler::newGCString(Register result, Register temp, Label *fail)
{ {
newGCThing(result, temp, js::gc::FINALIZE_STRING, fail); allocateNonObject(result, temp, js::gc::FINALIZE_STRING, fail);
} }
void void
MacroAssembler::newGCShortString(Register result, Register temp, Label *fail) MacroAssembler::newGCShortString(Register result, Register temp, Label *fail)
{ {
newGCThing(result, temp, js::gc::FINALIZE_SHORT_STRING, fail); allocateNonObject(result, temp, js::gc::FINALIZE_SHORT_STRING, fail);
} }
void void
@ -756,6 +883,7 @@ MacroAssembler::newGCThingPar(Register result, Register cx, Register tempReg1, R
{ {
gc::AllocKind allocKind = templateObject->tenuredGetAllocKind(); gc::AllocKind allocKind = templateObject->tenuredGetAllocKind();
JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST); JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
JS_ASSERT(!templateObject->numDynamicSlots());
newGCThingPar(result, cx, tempReg1, tempReg2, allocKind, fail); newGCThingPar(result, cx, tempReg1, tempReg2, allocKind, fail);
} }
@ -775,7 +903,7 @@ MacroAssembler::newGCShortStringPar(Register result, Register cx, Register tempR
} }
void void
MacroAssembler::copySlotsFromTemplate(Register obj, Register temp, const JSObject *templateObj, MacroAssembler::copySlotsFromTemplate(Register obj, const JSObject *templateObj,
uint32_t start, uint32_t end) uint32_t start, uint32_t end)
{ {
uint32_t nfixed = Min(templateObj->numFixedSlots(), end); uint32_t nfixed = Min(templateObj->numFixedSlots(), end);
@ -784,27 +912,26 @@ MacroAssembler::copySlotsFromTemplate(Register obj, Register temp, const JSObjec
} }
void void
MacroAssembler::fillSlotsWithUndefined(Register obj, Register temp, const JSObject *templateObj, MacroAssembler::fillSlotsWithUndefined(Address base, Register temp, uint32_t start, uint32_t end)
uint32_t start, uint32_t end)
{ {
#ifdef JS_NUNBOX32 #ifdef JS_NUNBOX32
// We only have a single spare register, so do the initialization as two // We only have a single spare register, so do the initialization as two
// strided writes of the tag and body. // strided writes of the tag and body.
jsval_layout jv = JSVAL_TO_IMPL(UndefinedValue()); jsval_layout jv = JSVAL_TO_IMPL(UndefinedValue());
uint32_t nfixed = Min(templateObj->numFixedSlots(), end);
mov(ImmWord(jv.s.tag), temp); Address addr = base;
for (unsigned i = start; i < nfixed; i++) move32(Imm32(jv.s.payload.i32), temp);
store32(temp, ToType(Address(obj, JSObject::getFixedSlotOffset(i)))); for (unsigned i = start; i < end; ++i, addr.offset += sizeof(HeapValue))
store32(temp, ToPayload(addr));
mov(ImmWord(jv.s.payload.i32), temp); addr = base;
for (unsigned i = start; i < nfixed; i++) move32(Imm32(jv.s.tag), temp);
store32(temp, ToPayload(Address(obj, JSObject::getFixedSlotOffset(i)))); for (unsigned i = start; i < end; ++i, addr.offset += sizeof(HeapValue))
store32(temp, ToType(addr));
#else #else
moveValue(UndefinedValue(), temp); moveValue(UndefinedValue(), temp);
uint32_t nfixed = Min(templateObj->numFixedSlots(), end); for (uint32_t i = start; i < end; ++i, base.offset += sizeof(HeapValue))
for (unsigned i = start; i < nfixed; i++) storePtr(temp, base);
storePtr(temp, Address(obj, JSObject::getFixedSlotOffset(i)));
#endif #endif
} }
@ -821,7 +948,7 @@ FindStartOfUndefinedSlots(JSObject *templateObj, uint32_t nslots)
} }
void void
MacroAssembler::initGCSlots(Register obj, Register temp, JSObject *templateObj) MacroAssembler::initGCSlots(Register obj, Register slots, JSObject *templateObj)
{ {
// Slots of non-array objects are required to be initialized. // Slots of non-array objects are required to be initialized.
// Use the values currently in the template object. // Use the values currently in the template object.
@ -829,6 +956,9 @@ MacroAssembler::initGCSlots(Register obj, Register temp, JSObject *templateObj)
if (nslots == 0) if (nslots == 0)
return; return;
uint32_t nfixed = templateObj->numFixedSlots();
uint32_t ndynamic = templateObj->numDynamicSlots();
// Attempt to group slot writes such that we minimize the amount of // Attempt to group slot writes such that we minimize the amount of
// duplicated data we need to embed in code and load into registers. In // duplicated data we need to embed in code and load into registers. In
// general, most template object slots will be undefined except for any // general, most template object slots will be undefined except for any
@ -837,22 +967,41 @@ MacroAssembler::initGCSlots(Register obj, Register temp, JSObject *templateObj)
// duplicated writes of UndefinedValue to the tail. For the majority of // duplicated writes of UndefinedValue to the tail. For the majority of
// objects, the "tail" will be the entire slot range. // objects, the "tail" will be the entire slot range.
uint32_t startOfUndefined = FindStartOfUndefinedSlots(templateObj, nslots); uint32_t startOfUndefined = FindStartOfUndefinedSlots(templateObj, nslots);
copySlotsFromTemplate(obj, temp, templateObj, 0, startOfUndefined); JS_ASSERT(startOfUndefined <= nfixed); // Reserved slots must be fixed.
fillSlotsWithUndefined(obj, temp, templateObj, startOfUndefined, nslots);
// Copy over any preserved reserved slots.
copySlotsFromTemplate(obj, templateObj, 0, startOfUndefined);
// Fill the rest of the fixed slots with undefined.
fillSlotsWithUndefined(Address(obj, JSObject::getFixedSlotOffset(startOfUndefined)), slots,
startOfUndefined, nfixed);
if (ndynamic) {
// We are short one register to do this elegantly. Borrow the obj
// register briefly for our slots base address.
push(obj);
loadPtr(Address(obj, JSObject::offsetOfSlots()), obj);
fillSlotsWithUndefined(Address(obj, 0), slots, 0, ndynamic);
pop(obj);
}
} }
void void
MacroAssembler::initGCThing(Register obj, Register temp, JSObject *templateObj) MacroAssembler::initGCThing(Register obj, Register slots, JSObject *templateObj)
{ {
// Fast initialization of an empty object returned by NewGCThing(). // Fast initialization of an empty object returned by allocateObject().
JS_ASSERT(!templateObj->hasDynamicElements()); JS_ASSERT(!templateObj->hasDynamicElements());
storePtr(ImmGCPtr(templateObj->lastProperty()), Address(obj, JSObject::offsetOfShape())); storePtr(ImmGCPtr(templateObj->lastProperty()), Address(obj, JSObject::offsetOfShape()));
storePtr(ImmGCPtr(templateObj->type()), Address(obj, JSObject::offsetOfType())); storePtr(ImmGCPtr(templateObj->type()), Address(obj, JSObject::offsetOfType()));
storePtr(ImmPtr(nullptr), Address(obj, JSObject::offsetOfSlots())); if (templateObj->hasDynamicSlots())
storePtr(slots, Address(obj, JSObject::offsetOfSlots()));
else
storePtr(ImmPtr(nullptr), Address(obj, JSObject::offsetOfSlots()));
if (templateObj->is<ArrayObject>()) { if (templateObj->is<ArrayObject>()) {
Register temp = slots;
JS_ASSERT(!templateObj->getDenseInitializedLength()); JS_ASSERT(!templateObj->getDenseInitializedLength());
int elementsOffset = JSObject::offsetOfFixedElements(); int elementsOffset = JSObject::offsetOfFixedElements();
@ -875,7 +1024,7 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject *templateObj)
} else { } else {
storePtr(ImmPtr(emptyObjectElements), Address(obj, JSObject::offsetOfElements())); storePtr(ImmPtr(emptyObjectElements), Address(obj, JSObject::offsetOfElements()));
initGCSlots(obj, temp, templateObj); initGCSlots(obj, slots, templateObj);
if (templateObj->hasPrivate()) { if (templateObj->hasPrivate()) {
uint32_t nfixed = templateObj->numFixedSlots(); uint32_t nfixed = templateObj->numFixedSlots();

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

@ -786,10 +786,30 @@ class MacroAssembler : public MacroAssemblerSpecific
void branchEqualTypeIfNeeded(MIRType type, MDefinition *maybeDef, Register tag, Label *label); void branchEqualTypeIfNeeded(MIRType type, MDefinition *maybeDef, Register tag, Label *label);
// Inline allocation. // Inline allocation.
void newGCThing(Register result, Register temp, gc::AllocKind allocKind, Label *fail, private:
gc::InitialHeap initialHeap = gc::DefaultHeap); void checkAllocatorState(Label *fail);
void newGCThing(Register result, Register temp, JSObject *templateObject, Label *fail, bool shouldNurseryAllocate(gc::AllocKind allocKind, gc::InitialHeap initialHeap);
gc::InitialHeap initialHeap); void nurseryAllocate(Register result, Register slots, gc::AllocKind allocKind,
size_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail);
void freeSpanAllocate(Register result, Register temp, gc::AllocKind allocKind, Label *fail);
void allocateObject(Register result, Register slots, gc::AllocKind allocKind,
uint32_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail);
void allocateNonObject(Register result, Register temp, gc::AllocKind allocKind, Label *fail);
void copySlotsFromTemplate(Register obj, const JSObject *templateObj,
uint32_t start, uint32_t end);
void fillSlotsWithUndefined(Address addr, Register temp, uint32_t start, uint32_t end);
void initGCSlots(Register obj, Register temp, JSObject *templateObj);
public:
void callMallocStub(size_t nbytes, Register result, Label *fail);
void callFreeStub(Register slots);
void createGCObject(Register result, Register temp, JSObject *templateObj,
gc::InitialHeap initialHeap, Label *fail);
void newGCThing(Register result, Register temp, JSObject *templateObj,
gc::InitialHeap initialHeap, Label *fail);
void initGCThing(Register obj, Register temp, JSObject *templateObj);
void newGCString(Register result, Register temp, Label *fail); void newGCString(Register result, Register temp, Label *fail);
void newGCShortString(Register result, Register temp, Label *fail); void newGCShortString(Register result, Register temp, Label *fail);
@ -802,12 +822,6 @@ class MacroAssembler : public MacroAssemblerSpecific
void newGCShortStringPar(Register result, Register cx, Register tempReg1, Register tempReg2, void newGCShortStringPar(Register result, Register cx, Register tempReg1, Register tempReg2,
Label *fail); Label *fail);
void copySlotsFromTemplate(Register obj, Register temp, const JSObject *templateObj,
uint32_t start, uint32_t end);
void fillSlotsWithUndefined(Register obj, Register temp, const JSObject *templateObj,
uint32_t start, uint32_t end);
void initGCSlots(Register obj, Register temp, JSObject *templateObj);
void initGCThing(Register obj, Register temp, JSObject *templateObj);
// Compares two strings for equality based on the JSOP. // Compares two strings for equality based on the JSOP.
// This checks for identical pointers, atoms and length and fails for everything else. // This checks for identical pointers, atoms and length and fails for everything else.

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

@ -186,6 +186,10 @@ class JitRuntime
JitCode *valuePreBarrier_; JitCode *valuePreBarrier_;
JitCode *shapePreBarrier_; JitCode *shapePreBarrier_;
// Thunk to call malloc/free.
JitCode *mallocStub_;
JitCode *freeStub_;
// Thunk used by the debugger for breakpoint and step mode. // Thunk used by the debugger for breakpoint and step mode.
JitCode *debugTrapHandler_; JitCode *debugTrapHandler_;
@ -221,6 +225,8 @@ class JitRuntime
JitCode *generateBailoutHandler(JSContext *cx); JitCode *generateBailoutHandler(JSContext *cx);
JitCode *generateInvalidator(JSContext *cx); JitCode *generateInvalidator(JSContext *cx);
JitCode *generatePreBarrier(JSContext *cx, MIRType type); JitCode *generatePreBarrier(JSContext *cx, MIRType type);
JitCode *generateMallocStub(JSContext *cx);
JitCode *generateFreeStub(JSContext *cx);
JitCode *generateDebugTrapHandler(JSContext *cx); JitCode *generateDebugTrapHandler(JSContext *cx);
JitCode *generateForkJoinGetSliceStub(JSContext *cx); JitCode *generateForkJoinGetSliceStub(JSContext *cx);
JitCode *generateVMWrapper(JSContext *cx, const VMFunction &f); JitCode *generateVMWrapper(JSContext *cx, const VMFunction &f);
@ -330,6 +336,14 @@ class JitRuntime
return shapePreBarrier_; return shapePreBarrier_;
} }
JitCode *mallocStub() const {
return mallocStub_;
}
JitCode *freeStub() const {
return freeStub_;
}
bool ensureForkJoinGetSliceStubExists(JSContext *cx); bool ensureForkJoinGetSliceStubExists(JSContext *cx);
JitCode *forkJoinGetSliceStub() const { JitCode *forkJoinGetSliceStub() const {
return forkJoinGetSliceStub_; return forkJoinGetSliceStub_;

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

@ -302,32 +302,6 @@ class LGoto : public LControlInstructionHelper<1, 0, 0>
} }
}; };
class LNewSlots : public LCallInstructionHelper<1, 0, 3>
{
public:
LIR_HEADER(NewSlots)
LNewSlots(const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3) {
setTemp(0, temp1);
setTemp(1, temp2);
setTemp(2, temp3);
}
const LDefinition *temp1() {
return getTemp(0);
}
const LDefinition *temp2() {
return getTemp(1);
}
const LDefinition *temp3() {
return getTemp(2);
}
MNewSlots *mir() const {
return mir_->toNewSlots();
}
};
class LNewArray : public LInstructionHelper<1, 0, 1> class LNewArray : public LInstructionHelper<1, 0, 1>
{ {
public: public:
@ -464,22 +438,19 @@ class LNewDeclEnvObject : public LInstructionHelper<1, 0, 1>
} }
}; };
// Allocates a new CallObject. The inputs are: // Allocates a new CallObject.
// slots: either a reg representing a HeapSlot *, or a placeholder
// meaning that no slots pointer is needed.
// //
// This instruction generates two possible instruction sets: // This instruction generates two possible instruction sets:
// (1) If the call object is extensible, this is a callVM to create the // (1) If the call object is extensible, this is a callVM to create the
// call object. // call object.
// (2) Otherwise, an inline allocation of the call object is attempted. // (2) Otherwise, an inline allocation of the call object is attempted.
// //
class LNewCallObject : public LInstructionHelper<1, 1, 1> class LNewCallObject : public LInstructionHelper<1, 0, 1>
{ {
public: public:
LIR_HEADER(NewCallObject) LIR_HEADER(NewCallObject)
LNewCallObject(const LAllocation &slots, const LDefinition &temp) { LNewCallObject(const LDefinition &temp) {
setOperand(0, slots);
setTemp(0, temp); setTemp(0, temp);
} }
@ -487,21 +458,15 @@ class LNewCallObject : public LInstructionHelper<1, 1, 1>
return getTemp(0); return getTemp(0);
} }
const LAllocation *slots() {
return getOperand(0);
}
MNewCallObject *mir() const { MNewCallObject *mir() const {
return mir_->toNewCallObject(); return mir_->toNewCallObject();
} }
}; };
class LNewCallObjectPar : public LInstructionHelper<1, 2, 2> class LNewCallObjectPar : public LInstructionHelper<1, 1, 2>
{ {
LNewCallObjectPar(const LAllocation &cx, const LAllocation &slots, LNewCallObjectPar(const LAllocation &cx, const LDefinition &temp1, const LDefinition &temp2) {
const LDefinition &temp1, const LDefinition &temp2)
{
setOperand(0, cx); setOperand(0, cx);
setOperand(1, slots);
setTemp(0, temp1); setTemp(0, temp1);
setTemp(1, temp2); setTemp(1, temp2);
} }
@ -509,37 +474,16 @@ class LNewCallObjectPar : public LInstructionHelper<1, 2, 2>
public: public:
LIR_HEADER(NewCallObjectPar); LIR_HEADER(NewCallObjectPar);
static LNewCallObjectPar *NewWithSlots(TempAllocator &alloc, static LNewCallObjectPar *New(TempAllocator &alloc, const LAllocation &cx,
const LAllocation &cx, const LAllocation &slots, const LDefinition &temp1, const LDefinition &temp2)
const LDefinition &temp1, const LDefinition &temp2)
{ {
return new(alloc) LNewCallObjectPar(cx, slots, temp1, temp2); return new(alloc) LNewCallObjectPar(cx, temp1, temp2);
}
static LNewCallObjectPar *NewSansSlots(TempAllocator &alloc,
const LAllocation &cx,
const LDefinition &temp1, const LDefinition &temp2)
{
LAllocation slots = LConstantIndex::Bogus();
return new(alloc) LNewCallObjectPar(cx, slots, temp1, temp2);
} }
const LAllocation *forkJoinContext() { const LAllocation *forkJoinContext() {
return getOperand(0); return getOperand(0);
} }
const LAllocation *slots() {
return getOperand(1);
}
const bool hasDynamicSlots() {
// TO INVESTIGATE: Felix tried using isRegister() method here,
// but for useFixed(_, CallTempN), isRegister() is false (and
// isUse() is true). So for now ignore that and try to match
// the LConstantIndex::Bogus() generated above instead.
return slots() && ! slots()->isConstant();
}
const MNewCallObjectPar *mir() const { const MNewCallObjectPar *mir() const {
return mir_->toNewCallObjectPar(); return mir_->toNewCallObjectPar();
} }

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

@ -25,7 +25,6 @@
_(Goto) \ _(Goto) \
_(NewArray) \ _(NewArray) \
_(NewObject) \ _(NewObject) \
_(NewSlots) \
_(NewDeclEnvObject) \ _(NewDeclEnvObject) \
_(NewCallObject) \ _(NewCallObject) \
_(NewStringObject) \ _(NewStringObject) \

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

@ -160,17 +160,6 @@ LIRGenerator::visitDefFun(MDefFun *ins)
return add(lir, ins) && assignSafepoint(lir, ins); return add(lir, ins) && assignSafepoint(lir, ins);
} }
bool
LIRGenerator::visitNewSlots(MNewSlots *ins)
{
// No safepoint needed, since we don't pass a cx.
LNewSlots *lir = new(alloc()) LNewSlots(tempFixed(CallTempReg0), tempFixed(CallTempReg1),
tempFixed(CallTempReg2));
if (!assignSnapshot(lir))
return false;
return defineReturn(lir, ins);
}
bool bool
LIRGenerator::visitNewArray(MNewArray *ins) LIRGenerator::visitNewArray(MNewArray *ins)
{ {
@ -195,13 +184,7 @@ LIRGenerator::visitNewDeclEnvObject(MNewDeclEnvObject *ins)
bool bool
LIRGenerator::visitNewCallObject(MNewCallObject *ins) LIRGenerator::visitNewCallObject(MNewCallObject *ins)
{ {
LAllocation slots; LNewCallObject *lir = new(alloc()) LNewCallObject(temp());
if (ins->slots()->type() == MIRType_Slots)
slots = useRegister(ins->slots());
else
slots = LConstantIndex::Bogus();
LNewCallObject *lir = new(alloc()) LNewCallObject(slots, temp());
if (!define(lir, ins)) if (!define(lir, ins))
return false; return false;
@ -225,17 +208,7 @@ bool
LIRGenerator::visitNewCallObjectPar(MNewCallObjectPar *ins) LIRGenerator::visitNewCallObjectPar(MNewCallObjectPar *ins)
{ {
const LAllocation &parThreadContext = useRegister(ins->forkJoinContext()); const LAllocation &parThreadContext = useRegister(ins->forkJoinContext());
const LDefinition &temp1 = temp(); LNewCallObjectPar *lir = LNewCallObjectPar::New(alloc(), parThreadContext, temp(), temp());
const LDefinition &temp2 = temp();
LNewCallObjectPar *lir;
if (ins->slots()->type() == MIRType_Slots) {
const LAllocation &slots = useRegister(ins->slots());
lir = LNewCallObjectPar::NewWithSlots(alloc(), parThreadContext, slots, temp1, temp2);
} else {
lir = LNewCallObjectPar::NewSansSlots(alloc(), parThreadContext, temp1, temp2);
}
return define(lir, ins); return define(lir, ins);
} }

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

@ -66,7 +66,6 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitCallee(MCallee *callee); bool visitCallee(MCallee *callee);
bool visitGoto(MGoto *ins); bool visitGoto(MGoto *ins);
bool visitTableSwitch(MTableSwitch *tableswitch); bool visitTableSwitch(MTableSwitch *tableswitch);
bool visitNewSlots(MNewSlots *ins);
bool visitNewArray(MNewArray *ins); bool visitNewArray(MNewArray *ins);
bool visitNewObject(MNewObject *ins); bool visitNewObject(MNewObject *ins);
bool visitNewDeclEnvObject(MNewDeclEnvObject *ins); bool visitNewDeclEnvObject(MNewDeclEnvObject *ins);

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

@ -8967,33 +8967,6 @@ class MPostWriteBarrier : public MBinaryInstruction, public ObjectPolicy<0>
#endif #endif
}; };
class MNewSlots : public MNullaryInstruction
{
unsigned nslots_;
MNewSlots(unsigned nslots)
: nslots_(nslots)
{
setResultType(MIRType_Slots);
}
public:
INSTRUCTION_HEADER(NewSlots)
static MNewSlots *New(TempAllocator &alloc, unsigned nslots) {
return new(alloc) MNewSlots(nslots);
}
unsigned nslots() const {
return nslots_;
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
bool possiblyCalls() const {
return true;
}
};
class MNewDeclEnvObject : public MNullaryInstruction class MNewDeclEnvObject : public MNullaryInstruction
{ {
CompilerRootObject templateObj_; CompilerRootObject templateObj_;
@ -9020,13 +8993,13 @@ class MNewDeclEnvObject : public MNullaryInstruction
} }
}; };
class MNewCallObject : public MUnaryInstruction class MNewCallObject : public MNullaryInstruction
{ {
CompilerRootObject templateObj_; CompilerRootObject templateObj_;
bool needsSingletonType_; bool needsSingletonType_;
MNewCallObject(JSObject *templateObj, bool needsSingletonType, MDefinition *slots) MNewCallObject(JSObject *templateObj, bool needsSingletonType)
: MUnaryInstruction(slots), : MNullaryInstruction(),
templateObj_(templateObj), templateObj_(templateObj),
needsSingletonType_(needsSingletonType) needsSingletonType_(needsSingletonType)
{ {
@ -9036,15 +9009,11 @@ class MNewCallObject : public MUnaryInstruction
public: public:
INSTRUCTION_HEADER(NewCallObject) INSTRUCTION_HEADER(NewCallObject)
static MNewCallObject *New(TempAllocator &alloc, JSObject *templateObj, bool needsSingletonType, static MNewCallObject *New(TempAllocator &alloc, JSObject *templateObj, bool needsSingletonType)
MDefinition *slots)
{ {
return new(alloc) MNewCallObject(templateObj, needsSingletonType, slots); return new(alloc) MNewCallObject(templateObj, needsSingletonType);
} }
MDefinition *slots() {
return getOperand(0);
}
JSObject *templateObject() { JSObject *templateObject() {
return templateObj_; return templateObj_;
} }
@ -9056,12 +9025,12 @@ class MNewCallObject : public MUnaryInstruction
} }
}; };
class MNewCallObjectPar : public MBinaryInstruction class MNewCallObjectPar : public MUnaryInstruction
{ {
CompilerRootObject templateObj_; CompilerRootObject templateObj_;
MNewCallObjectPar(MDefinition *cx, JSObject *templateObj, MDefinition *slots) MNewCallObjectPar(MDefinition *cx, JSObject *templateObj)
: MBinaryInstruction(cx, slots), : MUnaryInstruction(cx),
templateObj_(templateObj) templateObj_(templateObj)
{ {
setResultType(MIRType_Object); setResultType(MIRType_Object);
@ -9071,17 +9040,13 @@ class MNewCallObjectPar : public MBinaryInstruction
INSTRUCTION_HEADER(NewCallObjectPar); INSTRUCTION_HEADER(NewCallObjectPar);
static MNewCallObjectPar *New(TempAllocator &alloc, MDefinition *cx, MNewCallObject *callObj) { static MNewCallObjectPar *New(TempAllocator &alloc, MDefinition *cx, MNewCallObject *callObj) {
return new(alloc) MNewCallObjectPar(cx, callObj->templateObject(), callObj->slots()); return new(alloc) MNewCallObjectPar(cx, callObj->templateObject());
} }
MDefinition *forkJoinContext() const { MDefinition *forkJoinContext() const {
return getOperand(0); return getOperand(0);
} }
MDefinition *slots() const {
return getOperand(1);
}
JSObject *templateObj() const { JSObject *templateObj() const {
return templateObj_; return templateObj_;
} }

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

@ -85,7 +85,6 @@ namespace jit {
_(ToInt32) \ _(ToInt32) \
_(TruncateToInt32) \ _(TruncateToInt32) \
_(ToString) \ _(ToString) \
_(NewSlots) \
_(NewArray) \ _(NewArray) \
_(NewObject) \ _(NewObject) \
_(NewDeclEnvObject) \ _(NewDeclEnvObject) \

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

@ -179,7 +179,6 @@ class ParallelSafetyVisitor : public MInstructionVisitor
SAFE_OP(TruncateToInt32) SAFE_OP(TruncateToInt32)
SAFE_OP(MaybeToDoubleElement) SAFE_OP(MaybeToDoubleElement)
CUSTOM_OP(ToString) CUSTOM_OP(ToString)
SAFE_OP(NewSlots)
CUSTOM_OP(NewArray) CUSTOM_OP(NewArray)
CUSTOM_OP(NewObject) CUSTOM_OP(NewObject)
CUSTOM_OP(NewCallObject) CUSTOM_OP(NewCallObject)
@ -527,6 +526,10 @@ ParallelSafetyVisitor::visitCreateThisWithTemplate(MCreateThisWithTemplate *ins)
bool bool
ParallelSafetyVisitor::visitNewCallObject(MNewCallObject *ins) ParallelSafetyVisitor::visitNewCallObject(MNewCallObject *ins)
{ {
if (ins->templateObject()->hasDynamicSlots()) {
SpewMIR(ins, "call with dynamic slots");
return markUnsafe();
}
replace(ins, MNewCallObjectPar::New(alloc(), ForkJoinContext(), ins)); replace(ins, MNewCallObjectPar::New(alloc(), ForkJoinContext(), ins));
return true; return true;
} }
@ -641,11 +644,6 @@ ParallelSafetyVisitor::insertWriteGuard(MInstruction *writeInstruction,
object = valueBeingWritten->toSlots()->object(); object = valueBeingWritten->toSlots()->object();
break; break;
case MDefinition::Op_NewSlots:
// Values produced by new slots will ALWAYS be
// thread-local.
return true;
default: default:
SpewMIR(writeInstruction, "cannot insert write guard for %s", SpewMIR(writeInstruction, "cannot insert write guard for %s",
valueBeingWritten->opName()); valueBeingWritten->opName());

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

@ -509,26 +509,16 @@ InterruptCheck(JSContext *cx)
return CheckForInterrupt(cx); return CheckForInterrupt(cx);
} }
HeapSlot * void *
NewSlots(JSRuntime *rt, unsigned nslots) MallocWrapper(JSRuntime *rt, size_t nbytes)
{ {
JS_STATIC_ASSERT(sizeof(Value) == sizeof(HeapSlot)); return rt->pod_malloc<uint8_t>(nbytes);
Value *slots = reinterpret_cast<Value *>(rt->malloc_(nslots * sizeof(Value)));
if (!slots)
return nullptr;
for (unsigned i = 0; i < nslots; i++)
slots[i] = UndefinedValue();
return reinterpret_cast<HeapSlot *>(slots);
} }
JSObject * JSObject *
NewCallObject(JSContext *cx, HandleScript script, NewCallObject(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type)
HandleShape shape, HandleTypeObject type, HeapSlot *slots)
{ {
JSObject *obj = CallObject::create(cx, script, shape, type, slots); JSObject *obj = CallObject::create(cx, script, shape, type);
if (!obj) if (!obj)
return nullptr; return nullptr;

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

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

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

@ -252,8 +252,7 @@ class JSObject : public js::ObjectImpl
js::gc::AllocKind kind, js::gc::AllocKind kind,
js::gc::InitialHeap heap, js::gc::InitialHeap heap,
js::HandleShape shape, js::HandleShape shape,
js::HandleTypeObject type, js::HandleTypeObject type);
js::HeapSlot *extantSlots = nullptr);
/* Make an array object with the specified initial state. */ /* Make an array object with the specified initial state. */
static inline js::ArrayObject *createArray(js::ExclusiveContext *cx, static inline js::ArrayObject *createArray(js::ExclusiveContext *cx,

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

@ -497,8 +497,7 @@ inline bool JSObject::isVarObj()
/* static */ inline JSObject * /* static */ inline JSObject *
JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::InitialHeap heap, JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
js::HandleShape shape, js::HandleTypeObject type, js::HandleShape shape, js::HandleTypeObject type)
js::HeapSlot *extantSlots /* = nullptr */)
{ {
/* /*
* Callers must use dynamicSlotsCount to size the initial slot array of the * Callers must use dynamicSlotsCount to size the initial slot array of the
@ -511,13 +510,9 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp()) == shape->numFixedSlots()); JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp()) == shape->numFixedSlots());
JS_ASSERT_IF(type->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind)); JS_ASSERT_IF(type->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind));
JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap); JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap);
JS_ASSERT_IF(extantSlots, dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(),
type->clasp()));
const js::Class *clasp = type->clasp(); const js::Class *clasp = type->clasp();
size_t nDynamicSlots = 0; size_t nDynamicSlots = dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp);
if (!extantSlots)
nDynamicSlots = dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp);
JSObject *obj = js::NewGCObject<js::CanGC>(cx, kind, nDynamicSlots, heap); JSObject *obj = js::NewGCObject<js::CanGC>(cx, kind, nDynamicSlots, heap);
if (!obj) if (!obj)
@ -525,13 +520,7 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi
obj->shape_.init(shape); obj->shape_.init(shape);
obj->type_.init(type); obj->type_.init(type);
if (extantSlots) { // Note: slots are created and assigned internally by NewGCObject.
#ifdef JSGC_GENERATIONAL
if (cx->isJSContext())
cx->asJSContext()->runtime()->gcNursery.notifyInitialSlots(obj, extantSlots);
#endif
obj->slots = extantSlots;
}
obj->elements = js::emptyObjectElements; obj->elements = js::emptyObjectElements;
if (clasp->hasPrivate()) if (clasp->hasPrivate())

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

@ -141,14 +141,14 @@ ScopeObject::setEnclosingScope(HandleObject obj)
* The call object must be further initialized to be usable. * The call object must be further initialized to be usable.
*/ */
CallObject * CallObject *
CallObject::create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots) CallObject::create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type)
{ {
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots()); gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
JS_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_)); JS_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
kind = gc::GetBackgroundAllocKind(kind); kind = gc::GetBackgroundAllocKind(kind);
gc::InitialHeap heap = script->treatAsRunOnce() ? gc::TenuredHeap : gc::DefaultHeap; 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, heap, shape, type);
if (!obj) if (!obj)
return nullptr; return nullptr;

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

@ -237,7 +237,7 @@ class CallObject : public ScopeObject
/* These functions are internal and are exposed only for JITs. */ /* These functions are internal and are exposed only for JITs. */
static CallObject * static CallObject *
create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots); create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type);
static CallObject * static CallObject *
createTemplateObject(JSContext *cx, HandleScript script, gc::InitialHeap heap); createTemplateObject(JSContext *cx, HandleScript script, gc::InitialHeap heap);