mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 881536 - Part 4: Implement ParallelGetElementIC. (r=nbp)
This commit is contained in:
parent
9d5cb5bd4f
commit
b97ad254e9
@ -5809,6 +5809,24 @@ CodeGenerator::visitParallelGetPropertyIC(OutOfLineUpdateCache *ool, ParallelGet
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CodeGenerator::addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
|
||||||
|
TypedOrValueRegister output, bool monitoredResult)
|
||||||
|
{
|
||||||
|
switch (gen->info().executionMode()) {
|
||||||
|
case SequentialExecution: {
|
||||||
|
GetElementIC cache(obj, index, output, monitoredResult);
|
||||||
|
return addCache(ins, allocateCache(cache));
|
||||||
|
}
|
||||||
|
case ParallelExecution: {
|
||||||
|
ParallelGetElementIC cache(obj, index, output, monitoredResult);
|
||||||
|
return addCache(ins, allocateCache(cache));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Bad execution mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CodeGenerator::visitGetElementCacheV(LGetElementCacheV *ins)
|
CodeGenerator::visitGetElementCacheV(LGetElementCacheV *ins)
|
||||||
{
|
{
|
||||||
@ -5816,9 +5834,7 @@ CodeGenerator::visitGetElementCacheV(LGetElementCacheV *ins)
|
|||||||
ConstantOrRegister index = TypedOrValueRegister(ToValue(ins, LGetElementCacheV::Index));
|
ConstantOrRegister index = TypedOrValueRegister(ToValue(ins, LGetElementCacheV::Index));
|
||||||
TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
|
TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
|
||||||
|
|
||||||
GetElementIC cache(obj, index, output, ins->mir()->monitoredResult());
|
return addGetElementCache(ins, obj, index, output, ins->mir()->monitoredResult());
|
||||||
|
|
||||||
return addCache(ins, allocateCache(cache));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -5828,9 +5844,7 @@ CodeGenerator::visitGetElementCacheT(LGetElementCacheT *ins)
|
|||||||
ConstantOrRegister index = TypedOrValueRegister(MIRType_Int32, ToAnyRegister(ins->index()));
|
ConstantOrRegister index = TypedOrValueRegister(MIRType_Int32, ToAnyRegister(ins->index()));
|
||||||
TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->output()));
|
TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->output()));
|
||||||
|
|
||||||
GetElementIC cache(obj, index, output, ins->mir()->monitoredResult());
|
return addGetElementCache(ins, obj, index, output, ins->mir()->monitoredResult());
|
||||||
|
|
||||||
return addCache(ins, allocateCache(cache));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef bool (*GetElementICFn)(JSContext *, size_t, HandleObject, HandleValue, MutableHandleValue);
|
typedef bool (*GetElementICFn)(JSContext *, size_t, HandleObject, HandleValue, MutableHandleValue);
|
||||||
@ -5908,6 +5922,29 @@ CodeGenerator::visitSetElementIC(OutOfLineUpdateCache *ool, SetElementIC *ic)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef ParallelResult (*ParallelGetElementICFn)(ForkJoinSlice *, size_t, HandleObject,
|
||||||
|
HandleValue, MutableHandleValue);
|
||||||
|
const VMFunction ParallelGetElementIC::UpdateInfo =
|
||||||
|
FunctionInfo<ParallelGetElementICFn>(ParallelGetElementIC::update);
|
||||||
|
|
||||||
|
bool
|
||||||
|
CodeGenerator::visitParallelGetElementIC(OutOfLineUpdateCache *ool, ParallelGetElementIC *ic)
|
||||||
|
{
|
||||||
|
LInstruction *lir = ool->lir();
|
||||||
|
saveLive(lir);
|
||||||
|
|
||||||
|
pushArg(ic->index());
|
||||||
|
pushArg(ic->object());
|
||||||
|
pushArg(Imm32(ool->getCacheIndex()));
|
||||||
|
if (!callVM(ParallelGetElementIC::UpdateInfo, lir))
|
||||||
|
return false;
|
||||||
|
StoreValueTo(ic->output()).generate(this);
|
||||||
|
restoreLiveIgnore(lir, StoreValueTo(ic->output()).clobbered());
|
||||||
|
|
||||||
|
masm.jump(ool->rejoin());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CodeGenerator::visitBindNameCache(LBindNameCache *ins)
|
CodeGenerator::visitBindNameCache(LBindNameCache *ins)
|
||||||
{
|
{
|
||||||
|
@ -287,6 +287,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||||||
bool visitParallelGetPropertyIC(OutOfLineUpdateCache *ool, ParallelGetPropertyIC *ic);
|
bool visitParallelGetPropertyIC(OutOfLineUpdateCache *ool, ParallelGetPropertyIC *ic);
|
||||||
bool visitSetPropertyIC(OutOfLineUpdateCache *ool, SetPropertyIC *ic);
|
bool visitSetPropertyIC(OutOfLineUpdateCache *ool, SetPropertyIC *ic);
|
||||||
bool visitGetElementIC(OutOfLineUpdateCache *ool, GetElementIC *ic);
|
bool visitGetElementIC(OutOfLineUpdateCache *ool, GetElementIC *ic);
|
||||||
|
bool visitParallelGetElementIC(OutOfLineUpdateCache *ool, ParallelGetElementIC *ic);
|
||||||
bool visitSetElementIC(OutOfLineUpdateCache *ool, SetElementIC *ic);
|
bool visitSetElementIC(OutOfLineUpdateCache *ool, SetElementIC *ic);
|
||||||
bool visitBindNameIC(OutOfLineUpdateCache *ool, BindNameIC *ic);
|
bool visitBindNameIC(OutOfLineUpdateCache *ool, BindNameIC *ic);
|
||||||
bool visitNameIC(OutOfLineUpdateCache *ool, NameIC *ic);
|
bool visitNameIC(OutOfLineUpdateCache *ool, NameIC *ic);
|
||||||
@ -302,6 +303,8 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||||||
bool addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
|
bool addGetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
|
||||||
PropertyName *name, TypedOrValueRegister output,
|
PropertyName *name, TypedOrValueRegister output,
|
||||||
bool allowGetters);
|
bool allowGetters);
|
||||||
|
bool addGetElementCache(LInstruction *ins, Register obj, ConstantOrRegister index,
|
||||||
|
TypedOrValueRegister output, bool monitoredResult);
|
||||||
bool checkForParallelBailout(LInstruction *lir);
|
bool checkForParallelBailout(LInstruction *lir);
|
||||||
|
|
||||||
bool generateBranchV(const ValueOperand &value, Label *ifTrue, Label *ifFalse, FloatRegister fr);
|
bool generateBranchV(const ValueOperand &value, Label *ifTrue, Label *ifFalse, FloatRegister fr);
|
||||||
|
@ -1057,8 +1057,8 @@ bool
|
|||||||
GetPropertyIC::attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
|
GetPropertyIC::attachReadSlot(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
|
||||||
HandleShape shape)
|
HandleShape shape)
|
||||||
{
|
{
|
||||||
RepatchStubAppender attacher(*this);
|
|
||||||
MacroAssembler masm(cx);
|
MacroAssembler masm(cx);
|
||||||
|
RepatchStubAppender attacher(*this);
|
||||||
GenerateReadSlot(cx, ion, masm, attacher, obj, name(), holder, shape, object(), output());
|
GenerateReadSlot(cx, ion, masm, attacher, obj, name(), holder, shape, object(), output());
|
||||||
const char *attachKind = "non idempotent reading";
|
const char *attachKind = "non idempotent reading";
|
||||||
if (idempotent())
|
if (idempotent())
|
||||||
@ -1600,22 +1600,24 @@ ParallelIonCache::destroy()
|
|||||||
js_delete(stubbedShapes_);
|
js_delete(stubbedShapes_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
/* static */ bool
|
||||||
ParallelGetPropertyIC::canAttachReadSlot(LockedJSContext &cx, JSObject *obj,
|
ParallelGetPropertyIC::canAttachReadSlot(LockedJSContext &cx, IonCache &cache,
|
||||||
MutableHandleObject holder, MutableHandleShape shape)
|
TypedOrValueRegister output, JSObject *obj,
|
||||||
|
PropertyName *name, MutableHandleObject holder,
|
||||||
|
MutableHandleShape shape)
|
||||||
{
|
{
|
||||||
// Bail if we have hooks or are not native.
|
// Bail if we have hooks or are not native.
|
||||||
if (!obj->hasIdempotentProtoChain())
|
if (!obj->hasIdempotentProtoChain())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!js::LookupPropertyPure(obj, NameToId(name()), holder.address(), shape.address()))
|
if (!js::LookupPropertyPure(obj, NameToId(name), holder.address(), shape.address()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// In parallel execution we can't cache getters due to possible
|
// In parallel execution we can't cache getters due to possible
|
||||||
// side-effects, so only check if we can cache slot reads.
|
// side-effects, so only check if we can cache slot reads.
|
||||||
bool readSlot;
|
bool readSlot;
|
||||||
bool callGetter;
|
bool callGetter;
|
||||||
if (!DetermineGetPropKind(cx, *this, obj, obj, holder, shape, output(), false,
|
if (!DetermineGetPropKind(cx, cache, obj, obj, holder, shape, output, false,
|
||||||
&readSlot, &callGetter) || !readSlot)
|
&readSlot, &callGetter) || !readSlot)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -1689,7 +1691,9 @@ ParallelGetPropertyIC::update(ForkJoinSlice *slice, size_t cacheIndex,
|
|||||||
{
|
{
|
||||||
RootedShape shape(cx);
|
RootedShape shape(cx);
|
||||||
RootedObject holder(cx);
|
RootedObject holder(cx);
|
||||||
if (cache.canAttachReadSlot(cx, obj, &holder, &shape)) {
|
if (canAttachReadSlot(cx, cache, cache.output(), obj, cache.name(),
|
||||||
|
&holder, &shape))
|
||||||
|
{
|
||||||
if (!cache.attachReadSlot(cx, ion, obj, holder, shape))
|
if (!cache.attachReadSlot(cx, ion, obj, holder, shape))
|
||||||
return TP_FATAL;
|
return TP_FATAL;
|
||||||
attachedStub = true;
|
attachedStub = true;
|
||||||
@ -2159,6 +2163,16 @@ SetPropertyIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
|
|||||||
|
|
||||||
const size_t GetElementIC::MAX_FAILED_UPDATES = 16;
|
const size_t GetElementIC::MAX_FAILED_UPDATES = 16;
|
||||||
|
|
||||||
|
/* static */ bool
|
||||||
|
GetElementIC::canAttachGetProp(JSObject *obj, const Value &idval, jsid id)
|
||||||
|
{
|
||||||
|
uint32_t dummy;
|
||||||
|
return (obj->isNative() &&
|
||||||
|
idval.isString() &&
|
||||||
|
JSID_IS_ATOM(id) &&
|
||||||
|
!JSID_TO_ATOM(id)->isIndex(&dummy));
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GetElementIC::attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj,
|
GetElementIC::attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj,
|
||||||
const Value &idval, HandlePropertyName name)
|
const Value &idval, HandlePropertyName name)
|
||||||
@ -2196,108 +2210,137 @@ GetElementIC::attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj,
|
|||||||
return linkAndAttachStub(cx, masm, attacher, ion, "property");
|
return linkAndAttachStub(cx, masm, attacher, ion, "property");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
/* static */ bool
|
||||||
GetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval)
|
GetElementIC::canAttachDenseElement(JSObject *obj, const Value &idval)
|
||||||
{
|
{
|
||||||
JS_ASSERT(obj->isNative());
|
return obj->isNative() && idval.isInt32();
|
||||||
JS_ASSERT(idval.isInt32());
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
GenerateDenseElement(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
|
||||||
|
JSObject *obj, const Value &idval, Register object,
|
||||||
|
ConstantOrRegister index, TypedOrValueRegister output)
|
||||||
|
{
|
||||||
|
JS_ASSERT(GetElementIC::canAttachDenseElement(obj, idval));
|
||||||
|
|
||||||
Label failures;
|
Label failures;
|
||||||
MacroAssembler masm(cx);
|
|
||||||
RepatchStubAppender attacher(*this);
|
|
||||||
|
|
||||||
// Guard object's shape.
|
// Guard object's shape.
|
||||||
RootedObject globalObj(cx, &script->global());
|
|
||||||
RootedShape shape(cx, obj->lastProperty());
|
RootedShape shape(cx, obj->lastProperty());
|
||||||
if (!shape)
|
if (!shape)
|
||||||
return false;
|
return false;
|
||||||
masm.branchTestObjShape(Assembler::NotEqual, object(), shape, &failures);
|
masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
|
||||||
|
|
||||||
// Ensure the index is an int32 value.
|
// Ensure the index is an int32 value.
|
||||||
Register indexReg = InvalidReg;
|
Register indexReg = InvalidReg;
|
||||||
|
|
||||||
if (index().reg().hasValue()) {
|
if (index.reg().hasValue()) {
|
||||||
indexReg = output().scratchReg().gpr();
|
indexReg = output.scratchReg().gpr();
|
||||||
JS_ASSERT(indexReg != InvalidReg);
|
JS_ASSERT(indexReg != InvalidReg);
|
||||||
ValueOperand val = index().reg().valueReg();
|
ValueOperand val = index.reg().valueReg();
|
||||||
|
|
||||||
masm.branchTestInt32(Assembler::NotEqual, val, &failures);
|
masm.branchTestInt32(Assembler::NotEqual, val, &failures);
|
||||||
|
|
||||||
// Unbox the index.
|
// Unbox the index.
|
||||||
masm.unboxInt32(val, indexReg);
|
masm.unboxInt32(val, indexReg);
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(!index().reg().typedReg().isFloat());
|
JS_ASSERT(!index.reg().typedReg().isFloat());
|
||||||
indexReg = index().reg().typedReg().gpr();
|
indexReg = index.reg().typedReg().gpr();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load elements vector.
|
// Load elements vector.
|
||||||
masm.push(object());
|
masm.push(object);
|
||||||
masm.loadPtr(Address(object(), JSObject::offsetOfElements()), object());
|
masm.loadPtr(Address(object, JSObject::offsetOfElements()), object);
|
||||||
|
|
||||||
Label hole;
|
Label hole;
|
||||||
|
|
||||||
// Guard on the initialized length.
|
// Guard on the initialized length.
|
||||||
Address initLength(object(), ObjectElements::offsetOfInitializedLength());
|
Address initLength(object, ObjectElements::offsetOfInitializedLength());
|
||||||
masm.branch32(Assembler::BelowOrEqual, initLength, indexReg, &hole);
|
masm.branch32(Assembler::BelowOrEqual, initLength, indexReg, &hole);
|
||||||
|
|
||||||
// Check for holes & load the value.
|
// Check for holes & load the value.
|
||||||
masm.loadElementTypedOrValue(BaseIndex(object(), indexReg, TimesEight),
|
masm.loadElementTypedOrValue(BaseIndex(object, indexReg, TimesEight),
|
||||||
output(), true, &hole);
|
output, true, &hole);
|
||||||
|
|
||||||
masm.pop(object());
|
masm.pop(object);
|
||||||
attacher.jumpRejoin(masm);
|
attacher.jumpRejoin(masm);
|
||||||
|
|
||||||
// All failures flow to here.
|
// All failures flow to here.
|
||||||
masm.bind(&hole);
|
masm.bind(&hole);
|
||||||
masm.pop(object());
|
masm.pop(object);
|
||||||
masm.bind(&failures);
|
masm.bind(&failures);
|
||||||
|
|
||||||
attacher.jumpNextStub(masm);
|
attacher.jumpNextStub(masm);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
GetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval)
|
||||||
|
{
|
||||||
|
MacroAssembler masm(cx);
|
||||||
|
RepatchStubAppender attacher(*this);
|
||||||
|
if (!GenerateDenseElement(cx, masm, attacher, obj, idval, object(), index(), output()))
|
||||||
|
return false;
|
||||||
|
|
||||||
setHasDenseStub();
|
setHasDenseStub();
|
||||||
return linkAndAttachStub(cx, masm, attacher, ion, "dense array");
|
return linkAndAttachStub(cx, masm, attacher, ion, "dense array");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
/* static */ bool
|
||||||
GetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
|
GetElementIC::canAttachTypedArrayElement(JSObject *obj, const Value &idval,
|
||||||
const Value &idval)
|
TypedOrValueRegister output)
|
||||||
{
|
{
|
||||||
|
if (!obj->is<TypedArrayObject>() ||
|
||||||
|
(!(idval.isInt32()) &&
|
||||||
|
!(idval.isString() && GetIndexFromString(idval.toString()) != UINT32_MAX)))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The output register is not yet specialized as a float register, the only
|
||||||
|
// way to accept float typed arrays for now is to return a Value type.
|
||||||
|
int arrayType = obj->as<TypedArrayObject>().type();
|
||||||
|
bool floatOutput = arrayType == TypedArrayObject::TYPE_FLOAT32 ||
|
||||||
|
arrayType == TypedArrayObject::TYPE_FLOAT64;
|
||||||
|
return !floatOutput || output.hasValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
GenerateTypedArrayElement(JSContext *cx, MacroAssembler &masm, IonCache::StubAttacher &attacher,
|
||||||
|
TypedArrayObject *tarr, const Value &idval, Register object,
|
||||||
|
ConstantOrRegister index, TypedOrValueRegister output)
|
||||||
|
{
|
||||||
|
JS_ASSERT(GetElementIC::canAttachTypedArrayElement(tarr, idval, output));
|
||||||
|
|
||||||
Label failures;
|
Label failures;
|
||||||
MacroAssembler masm(cx);
|
|
||||||
RepatchStubAppender attacher(*this);
|
|
||||||
|
|
||||||
// The array type is the object within the table of typed array classes.
|
// The array type is the object within the table of typed array classes.
|
||||||
int arrayType = tarr->type();
|
int arrayType = tarr->type();
|
||||||
|
|
||||||
// The output register is not yet specialized as a float register, the only
|
Register tmpReg = output.scratchReg().gpr();
|
||||||
// way to accept float typed arrays for now is to return a Value type.
|
|
||||||
DebugOnly<bool> floatOutput = arrayType == TypedArrayObject::TYPE_FLOAT32 ||
|
|
||||||
arrayType == TypedArrayObject::TYPE_FLOAT64;
|
|
||||||
JS_ASSERT_IF(!output().hasValue(), !floatOutput);
|
|
||||||
|
|
||||||
Register tmpReg = output().scratchReg().gpr();
|
|
||||||
JS_ASSERT(tmpReg != InvalidReg);
|
JS_ASSERT(tmpReg != InvalidReg);
|
||||||
|
|
||||||
// Check that the typed array is of the same type as the current object
|
// Check that the typed array is of the same type as the current object
|
||||||
// because load size differ in function of the typed array data width.
|
// because load size differ in function of the typed array data width.
|
||||||
masm.branchTestObjClass(Assembler::NotEqual, object(), tmpReg, tarr->getClass(), &failures);
|
masm.branchTestObjClass(Assembler::NotEqual, object, tmpReg, tarr->getClass(), &failures);
|
||||||
|
|
||||||
// Decide to what type index the stub should be optimized
|
// Decide to what type index the stub should be optimized
|
||||||
Register indexReg = tmpReg;
|
Register indexReg = tmpReg;
|
||||||
JS_ASSERT(!index().constant());
|
JS_ASSERT(!index.constant());
|
||||||
if (idval.isString()) {
|
if (idval.isString()) {
|
||||||
JS_ASSERT(GetIndexFromString(idval.toString()) != UINT32_MAX);
|
JS_ASSERT(GetIndexFromString(idval.toString()) != UINT32_MAX);
|
||||||
|
|
||||||
// Part 1: Get the string into a register
|
// Part 1: Get the string into a register
|
||||||
Register str;
|
Register str;
|
||||||
if (index().reg().hasValue()) {
|
if (index.reg().hasValue()) {
|
||||||
ValueOperand val = index().reg().valueReg();
|
ValueOperand val = index.reg().valueReg();
|
||||||
masm.branchTestString(Assembler::NotEqual, val, &failures);
|
masm.branchTestString(Assembler::NotEqual, val, &failures);
|
||||||
|
|
||||||
str = masm.extractString(val, indexReg);
|
str = masm.extractString(val, indexReg);
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(!index().reg().typedReg().isFloat());
|
JS_ASSERT(!index.reg().typedReg().isFloat());
|
||||||
str = index().reg().typedReg().gpr();
|
str = index.reg().typedReg().gpr();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Part 2: Call to translate the str into index
|
// Part 2: Call to translate the str into index
|
||||||
@ -2321,51 +2364,59 @@ GetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayO
|
|||||||
} else {
|
} else {
|
||||||
JS_ASSERT(idval.isInt32());
|
JS_ASSERT(idval.isInt32());
|
||||||
|
|
||||||
if (index().reg().hasValue()) {
|
if (index.reg().hasValue()) {
|
||||||
ValueOperand val = index().reg().valueReg();
|
ValueOperand val = index.reg().valueReg();
|
||||||
masm.branchTestInt32(Assembler::NotEqual, val, &failures);
|
masm.branchTestInt32(Assembler::NotEqual, val, &failures);
|
||||||
|
|
||||||
// Unbox the index.
|
// Unbox the index.
|
||||||
masm.unboxInt32(val, indexReg);
|
masm.unboxInt32(val, indexReg);
|
||||||
} else {
|
} else {
|
||||||
JS_ASSERT(!index().reg().typedReg().isFloat());
|
JS_ASSERT(!index.reg().typedReg().isFloat());
|
||||||
indexReg = index().reg().typedReg().gpr();
|
indexReg = index.reg().typedReg().gpr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guard on the initialized length.
|
// Guard on the initialized length.
|
||||||
Address length(object(), TypedArrayObject::lengthOffset());
|
Address length(object, TypedArrayObject::lengthOffset());
|
||||||
masm.branch32(Assembler::BelowOrEqual, length, indexReg, &failures);
|
masm.branch32(Assembler::BelowOrEqual, length, indexReg, &failures);
|
||||||
|
|
||||||
// Save the object register on the stack in case of failure.
|
// Save the object register on the stack in case of failure.
|
||||||
Label popAndFail;
|
Label popAndFail;
|
||||||
Register elementReg = object();
|
Register elementReg = object;
|
||||||
masm.push(object());
|
masm.push(object);
|
||||||
|
|
||||||
// Load elements vector.
|
// Load elements vector.
|
||||||
masm.loadPtr(Address(object(), TypedArrayObject::dataOffset()), elementReg);
|
masm.loadPtr(Address(object, TypedArrayObject::dataOffset()), elementReg);
|
||||||
|
|
||||||
// Load the value. We use an invalid register because the destination
|
// Load the value. We use an invalid register because the destination
|
||||||
// register is necessary a non double register.
|
// register is necessary a non double register.
|
||||||
int width = TypedArrayObject::slotWidth(arrayType);
|
int width = TypedArrayObject::slotWidth(arrayType);
|
||||||
BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(width));
|
BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(width));
|
||||||
if (output().hasValue())
|
if (output.hasValue())
|
||||||
masm.loadFromTypedArray(arrayType, source, output().valueReg(), true,
|
masm.loadFromTypedArray(arrayType, source, output.valueReg(), true,
|
||||||
elementReg, &popAndFail);
|
elementReg, &popAndFail);
|
||||||
else
|
else
|
||||||
masm.loadFromTypedArray(arrayType, source, output().typedReg(),
|
masm.loadFromTypedArray(arrayType, source, output.typedReg(),
|
||||||
elementReg, &popAndFail);
|
elementReg, &popAndFail);
|
||||||
|
|
||||||
masm.pop(object());
|
masm.pop(object);
|
||||||
attacher.jumpRejoin(masm);
|
attacher.jumpRejoin(masm);
|
||||||
|
|
||||||
// Restore the object before continuing to the next stub.
|
// Restore the object before continuing to the next stub.
|
||||||
masm.bind(&popAndFail);
|
masm.bind(&popAndFail);
|
||||||
masm.pop(object());
|
masm.pop(object);
|
||||||
masm.bind(&failures);
|
masm.bind(&failures);
|
||||||
|
|
||||||
attacher.jumpNextStub(masm);
|
attacher.jumpNextStub(masm);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
GetElementIC::attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
|
||||||
|
const Value &idval)
|
||||||
|
{
|
||||||
|
MacroAssembler masm(cx);
|
||||||
|
RepatchStubAppender attacher(*this);
|
||||||
|
GenerateTypedArrayElement(cx, masm, attacher, tarr, idval, object(), index(), output());
|
||||||
return linkAndAttachStub(cx, masm, attacher, ion, "typed array");
|
return linkAndAttachStub(cx, masm, attacher, ion, "typed array");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2517,34 +2568,22 @@ GetElementIC::update(JSContext *cx, size_t cacheIndex, HandleObject obj,
|
|||||||
return false;
|
return false;
|
||||||
attachedStub = true;
|
attachedStub = true;
|
||||||
}
|
}
|
||||||
if (!attachedStub && obj->isNative() && cache.monitoredResult()) {
|
if (!attachedStub && cache.monitoredResult() && canAttachGetProp(obj, idval, id)) {
|
||||||
uint32_t dummy;
|
RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
|
||||||
if (idval.isString() && JSID_IS_ATOM(id) && !JSID_TO_ATOM(id)->isIndex(&dummy)) {
|
if (!cache.attachGetProp(cx, ion, obj, idval, name))
|
||||||
RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
|
return false;
|
||||||
if (!cache.attachGetProp(cx, ion, obj, idval, name))
|
attachedStub = true;
|
||||||
return false;
|
|
||||||
attachedStub = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!attachedStub && !cache.hasDenseStub() && obj->isNative() && idval.isInt32()) {
|
if (!attachedStub && !cache.hasDenseStub() && canAttachDenseElement(obj, idval)) {
|
||||||
if (!cache.attachDenseElement(cx, ion, obj, idval))
|
if (!cache.attachDenseElement(cx, ion, obj, idval))
|
||||||
return false;
|
return false;
|
||||||
attachedStub = true;
|
attachedStub = true;
|
||||||
}
|
}
|
||||||
if (!attachedStub && obj->is<TypedArrayObject>()) {
|
if (!attachedStub && canAttachTypedArrayElement(obj, idval, cache.output())) {
|
||||||
if ((idval.isInt32()) ||
|
Rooted<TypedArrayObject*> tarr(cx, &obj->as<TypedArrayObject>());
|
||||||
(idval.isString() && GetIndexFromString(idval.toString()) != UINT32_MAX))
|
if (!cache.attachTypedArrayElement(cx, ion, tarr, idval))
|
||||||
{
|
return false;
|
||||||
Rooted<TypedArrayObject*> tarr(cx, &obj->as<TypedArrayObject>());
|
attachedStub = true;
|
||||||
int arrayType = tarr->type();
|
|
||||||
bool floatOutput = arrayType == TypedArrayObject::TYPE_FLOAT32 ||
|
|
||||||
arrayType == TypedArrayObject::TYPE_FLOAT64;
|
|
||||||
if (!floatOutput || cache.output().hasValue()) {
|
|
||||||
if (!cache.attachTypedArrayElement(cx, ion, tarr, idval))
|
|
||||||
return false;
|
|
||||||
attachedStub = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2603,7 +2642,6 @@ SetElementIC::attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, c
|
|||||||
RepatchStubAppender attacher(*this);
|
RepatchStubAppender attacher(*this);
|
||||||
|
|
||||||
// Guard object is a dense array.
|
// Guard object is a dense array.
|
||||||
RootedObject globalObj(cx, &script->global());
|
|
||||||
RootedShape shape(cx, obj->lastProperty());
|
RootedShape shape(cx, obj->lastProperty());
|
||||||
if (!shape)
|
if (!shape)
|
||||||
return false;
|
return false;
|
||||||
@ -2713,6 +2751,120 @@ SetElementIC::reset()
|
|||||||
hasDenseStub_ = false;
|
hasDenseStub_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ParallelGetElementIC::attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj,
|
||||||
|
const Value &idval, PropertyName *name, JSObject *holder,
|
||||||
|
Shape *shape)
|
||||||
|
{
|
||||||
|
MacroAssembler masm(cx);
|
||||||
|
DispatchStubPrepender attacher(*this);
|
||||||
|
|
||||||
|
// Guard on the index value.
|
||||||
|
Label failures;
|
||||||
|
ValueOperand val = index().reg().valueReg();
|
||||||
|
masm.branchTestValue(Assembler::NotEqual, val, idval, &failures);
|
||||||
|
|
||||||
|
GenerateReadSlot(cx, ion, masm, attacher, obj, name, holder, shape, object(), output(),
|
||||||
|
&failures);
|
||||||
|
|
||||||
|
return linkAndAttachStub(cx, masm, attacher, ion, "parallel getelem reading");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ParallelGetElementIC::attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj,
|
||||||
|
const Value &idval)
|
||||||
|
{
|
||||||
|
MacroAssembler masm(cx);
|
||||||
|
DispatchStubPrepender attacher(*this);
|
||||||
|
if (!GenerateDenseElement(cx, masm, attacher, obj, idval, object(), index(), output()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return linkAndAttachStub(cx, masm, attacher, ion, "parallel dense element");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ParallelGetElementIC::attachTypedArrayElement(LockedJSContext &cx, IonScript *ion,
|
||||||
|
TypedArrayObject *tarr, const Value &idval)
|
||||||
|
{
|
||||||
|
MacroAssembler masm(cx);
|
||||||
|
DispatchStubPrepender attacher(*this);
|
||||||
|
GenerateTypedArrayElement(cx, masm, attacher, tarr, idval, object(), index(), output());
|
||||||
|
return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array");
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelResult
|
||||||
|
ParallelGetElementIC::update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
|
||||||
|
HandleValue idval, MutableHandleValue vp)
|
||||||
|
{
|
||||||
|
AutoFlushCache afc("ParallelGetElementCache");
|
||||||
|
PerThreadData *pt = slice->perThreadData;
|
||||||
|
|
||||||
|
const SafepointIndex *safepointIndex;
|
||||||
|
void *returnAddr;
|
||||||
|
RootedScript topScript(pt, GetTopIonJSScript(pt, &safepointIndex, &returnAddr));
|
||||||
|
IonScript *ion = topScript->parallelIonScript();
|
||||||
|
|
||||||
|
ParallelGetElementIC &cache = ion->getCache(cacheIndex).toParallelGetElement();
|
||||||
|
|
||||||
|
// Try to get the element early, as the pure path doesn't need a lock. If
|
||||||
|
// we can't do it purely, bail out of parallel execution.
|
||||||
|
if (!GetObjectElementOperationPure(slice, obj, idval, vp.address()))
|
||||||
|
return TP_RETRY_SEQUENTIALLY;
|
||||||
|
|
||||||
|
// Avoid unnecessary locking if cannot attach stubs.
|
||||||
|
if (!cache.canAttachStub())
|
||||||
|
return TP_SUCCESS;
|
||||||
|
|
||||||
|
{
|
||||||
|
LockedJSContext cx(slice);
|
||||||
|
|
||||||
|
if (cache.canAttachStub()) {
|
||||||
|
bool alreadyStubbed;
|
||||||
|
if (!cache.hasOrAddStubbedShape(cx, obj->lastProperty(), &alreadyStubbed))
|
||||||
|
return TP_FATAL;
|
||||||
|
if (alreadyStubbed)
|
||||||
|
return TP_SUCCESS;
|
||||||
|
|
||||||
|
jsid id;
|
||||||
|
if (!ValueToIdPure(idval, &id))
|
||||||
|
return TP_FATAL;
|
||||||
|
|
||||||
|
bool attachedStub = false;
|
||||||
|
|
||||||
|
if (cache.monitoredResult() &&
|
||||||
|
GetElementIC::canAttachGetProp(obj, idval, id))
|
||||||
|
{
|
||||||
|
RootedShape shape(cx);
|
||||||
|
RootedObject holder(cx);
|
||||||
|
PropertyName *name = JSID_TO_ATOM(id)->asPropertyName();
|
||||||
|
if (ParallelGetPropertyIC::canAttachReadSlot(cx, cache, cache.output(), obj,
|
||||||
|
name, &holder, &shape))
|
||||||
|
{
|
||||||
|
if (!cache.attachReadSlot(cx, ion, obj, idval, name, holder, shape))
|
||||||
|
return TP_FATAL;
|
||||||
|
attachedStub = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!attachedStub &&
|
||||||
|
GetElementIC::canAttachDenseElement(obj, idval))
|
||||||
|
{
|
||||||
|
if (!cache.attachDenseElement(cx, ion, obj, idval))
|
||||||
|
return TP_FATAL;
|
||||||
|
attachedStub = true;
|
||||||
|
}
|
||||||
|
if (!attachedStub &&
|
||||||
|
GetElementIC::canAttachTypedArrayElement(obj, idval, cache.output()))
|
||||||
|
{
|
||||||
|
if (!cache.attachTypedArrayElement(cx, ion, &obj->as<TypedArrayObject>(), idval))
|
||||||
|
return TP_FATAL;
|
||||||
|
attachedStub = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TP_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BindNameIC::attachGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain)
|
BindNameIC::attachGlobal(JSContext *cx, IonScript *ion, JSObject *scopeChain)
|
||||||
{
|
{
|
||||||
|
@ -29,7 +29,8 @@ namespace ion {
|
|||||||
_(BindName) \
|
_(BindName) \
|
||||||
_(Name) \
|
_(Name) \
|
||||||
_(CallsiteClone) \
|
_(CallsiteClone) \
|
||||||
_(ParallelGetProperty)
|
_(ParallelGetProperty) \
|
||||||
|
_(ParallelGetElement)
|
||||||
|
|
||||||
// Forward declarations of Cache kinds.
|
// Forward declarations of Cache kinds.
|
||||||
#define FORWARD_DECLARE(kind) class kind##IC;
|
#define FORWARD_DECLARE(kind) class kind##IC;
|
||||||
@ -669,6 +670,11 @@ class GetElementIC : public RepatchIonCache
|
|||||||
hasDenseStub_ = true;
|
hasDenseStub_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool canAttachGetProp(JSObject *obj, const Value &idval, jsid id);
|
||||||
|
static bool canAttachDenseElement(JSObject *obj, const Value &idval);
|
||||||
|
static bool canAttachTypedArrayElement(JSObject *obj, const Value &idval,
|
||||||
|
TypedOrValueRegister output);
|
||||||
|
|
||||||
bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval, HandlePropertyName name);
|
bool attachGetProp(JSContext *cx, IonScript *ion, HandleObject obj, const Value &idval, HandlePropertyName name);
|
||||||
bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
|
bool attachDenseElement(JSContext *cx, IonScript *ion, JSObject *obj, const Value &idval);
|
||||||
bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
|
bool attachTypedArrayElement(JSContext *cx, IonScript *ion, TypedArrayObject *tarr,
|
||||||
@ -924,8 +930,11 @@ class ParallelGetPropertyIC : public ParallelIonCache
|
|||||||
return output_;
|
return output_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool canAttachReadSlot(LockedJSContext &cx, JSObject *obj, MutableHandleObject holder,
|
static bool canAttachReadSlot(LockedJSContext &cx, IonCache &cache,
|
||||||
MutableHandleShape shape);
|
TypedOrValueRegister output, JSObject *obj,
|
||||||
|
PropertyName *name, MutableHandleObject holder,
|
||||||
|
MutableHandleShape shape);
|
||||||
|
|
||||||
bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, JSObject *holder,
|
bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, JSObject *holder,
|
||||||
Shape *shape);
|
Shape *shape);
|
||||||
bool attachArrayLength(LockedJSContext &cx, IonScript *ion, JSObject *obj);
|
bool attachArrayLength(LockedJSContext &cx, IonScript *ion, JSObject *obj);
|
||||||
@ -934,6 +943,57 @@ class ParallelGetPropertyIC : public ParallelIonCache
|
|||||||
MutableHandleValue vp);
|
MutableHandleValue vp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ParallelGetElementIC : public ParallelIonCache
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
Register object_;
|
||||||
|
ConstantOrRegister index_;
|
||||||
|
TypedOrValueRegister output_;
|
||||||
|
|
||||||
|
bool monitoredResult_ : 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ParallelGetElementIC(Register object, ConstantOrRegister index,
|
||||||
|
TypedOrValueRegister output, bool monitoredResult)
|
||||||
|
: object_(object),
|
||||||
|
index_(index),
|
||||||
|
output_(output),
|
||||||
|
monitoredResult_(monitoredResult)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CACHE_HEADER(ParallelGetElement)
|
||||||
|
|
||||||
|
#ifdef JS_CPU_X86
|
||||||
|
// x86 lacks a general purpose scratch register for dispatch caches and
|
||||||
|
// must be given one manually.
|
||||||
|
void initializeAddCacheState(LInstruction *ins, AddCacheState *addState);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Register object() const {
|
||||||
|
return object_;
|
||||||
|
}
|
||||||
|
ConstantOrRegister index() const {
|
||||||
|
return index_;
|
||||||
|
}
|
||||||
|
TypedOrValueRegister output() const {
|
||||||
|
return output_;
|
||||||
|
}
|
||||||
|
bool monitoredResult() const {
|
||||||
|
return monitoredResult_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval,
|
||||||
|
PropertyName *name, JSObject *holder, Shape *shape);
|
||||||
|
bool attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval);
|
||||||
|
bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, TypedArrayObject *tarr,
|
||||||
|
const Value &idval);
|
||||||
|
|
||||||
|
static ParallelResult update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj, HandleValue idval,
|
||||||
|
MutableHandleValue vp);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
#undef CACHE_HEADER
|
#undef CACHE_HEADER
|
||||||
|
|
||||||
// Implement cache casts now that the compiler can see the inheritance.
|
// Implement cache casts now that the compiler can see the inheritance.
|
||||||
|
@ -3725,14 +3725,16 @@ class LGetElementCacheV : public LInstructionHelper<BOX_PIECES, 1 + BOX_PIECES,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class LGetElementCacheT : public LInstructionHelper<1, 2, 0>
|
class LGetElementCacheT : public LInstructionHelper<1, 2, 1>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LIR_HEADER(GetElementCacheT)
|
LIR_HEADER(GetElementCacheT)
|
||||||
|
|
||||||
LGetElementCacheT(const LAllocation &object, const LAllocation &index) {
|
LGetElementCacheT(const LAllocation &object, const LAllocation &index,
|
||||||
|
const LDefinition &temp) {
|
||||||
setOperand(0, object);
|
setOperand(0, object);
|
||||||
setOperand(1, index);
|
setOperand(1, index);
|
||||||
|
setTemp(0, temp);
|
||||||
}
|
}
|
||||||
const LAllocation *object() {
|
const LAllocation *object() {
|
||||||
return getOperand(0);
|
return getOperand(0);
|
||||||
@ -3743,6 +3745,9 @@ class LGetElementCacheT : public LInstructionHelper<1, 2, 0>
|
|||||||
const LDefinition *output() {
|
const LDefinition *output() {
|
||||||
return getDef(0);
|
return getDef(0);
|
||||||
}
|
}
|
||||||
|
const LDefinition *temp() {
|
||||||
|
return getTemp(0);
|
||||||
|
}
|
||||||
const MGetElementCache *mir() const {
|
const MGetElementCache *mir() const {
|
||||||
return mir_->toGetElementCache();
|
return mir_->toGetElementCache();
|
||||||
}
|
}
|
||||||
|
@ -2331,8 +2331,7 @@ LIRGenerator::visitGetElementCache(MGetElementCache *ins)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JS_ASSERT(ins->index()->type() == MIRType_Int32);
|
JS_ASSERT(ins->index()->type() == MIRType_Int32);
|
||||||
LGetElementCacheT *lir = new LGetElementCacheT(useRegister(ins->object()),
|
LGetElementCacheT *lir = newLGetElementCacheT(ins);
|
||||||
useRegister(ins->index()));
|
|
||||||
return define(lir, ins) && assignSafepoint(lir, ins);
|
return define(lir, ins) && assignSafepoint(lir, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
|
|||||||
SAFE_OP(GetPropertyCache)
|
SAFE_OP(GetPropertyCache)
|
||||||
SAFE_OP(GetPropertyPolymorphic)
|
SAFE_OP(GetPropertyPolymorphic)
|
||||||
UNSAFE_OP(SetPropertyPolymorphic)
|
UNSAFE_OP(SetPropertyPolymorphic)
|
||||||
UNSAFE_OP(GetElementCache)
|
SAFE_OP(GetElementCache)
|
||||||
UNSAFE_OP(SetElementCache)
|
UNSAFE_OP(SetElementCache)
|
||||||
UNSAFE_OP(BindNameCache)
|
UNSAFE_OP(BindNameCache)
|
||||||
SAFE_OP(GuardShape)
|
SAFE_OP(GuardShape)
|
||||||
|
@ -325,6 +325,14 @@ LIRGeneratorARM::newLGetPropertyCacheT(MGetPropertyCache *ins)
|
|||||||
return new LGetPropertyCacheT(useRegister(ins->object()), LDefinition::BogusTemp());
|
return new LGetPropertyCacheT(useRegister(ins->object()), LDefinition::BogusTemp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LGetElementCacheT *
|
||||||
|
LIRGeneratorARM::newLGetElementCacheT(MGetElementCache *ins)
|
||||||
|
{
|
||||||
|
return new LGetElementCacheT(useRegister(ins->object()),
|
||||||
|
useRegister(ins->index()),
|
||||||
|
LDefinition::BogusTemp());
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LIRGeneratorARM::visitGuardShape(MGuardShape *ins)
|
LIRGeneratorARM::visitGuardShape(MGuardShape *ins)
|
||||||
{
|
{
|
||||||
|
@ -61,6 +61,7 @@ class LIRGeneratorARM : public LIRGeneratorShared
|
|||||||
MTableSwitch *ins);
|
MTableSwitch *ins);
|
||||||
LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
|
LTableSwitchV *newLTableSwitchV(MTableSwitch *ins);
|
||||||
LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
|
LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
|
||||||
|
LGetElementCacheT *newLGetElementCacheT(MGetElementCache *ins);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool visitConstant(MConstant *ins);
|
bool visitConstant(MConstant *ins);
|
||||||
|
@ -175,6 +175,14 @@ LIRGeneratorX64::newLGetPropertyCacheT(MGetPropertyCache *ins)
|
|||||||
return new LGetPropertyCacheT(useRegister(ins->object()), LDefinition::BogusTemp());
|
return new LGetPropertyCacheT(useRegister(ins->object()), LDefinition::BogusTemp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LGetElementCacheT *
|
||||||
|
LIRGeneratorX64::newLGetElementCacheT(MGetElementCache *ins)
|
||||||
|
{
|
||||||
|
return new LGetElementCacheT(useRegister(ins->object()),
|
||||||
|
useRegister(ins->index()),
|
||||||
|
LDefinition::BogusTemp());
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LIRGeneratorX64::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
|
LIRGeneratorX64::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic *ins)
|
||||||
{
|
{
|
||||||
|
@ -31,6 +31,7 @@ class LIRGeneratorX64 : public LIRGeneratorX86Shared
|
|||||||
LDefinition tempToUnbox();
|
LDefinition tempToUnbox();
|
||||||
|
|
||||||
LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
|
LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
|
||||||
|
LGetElementCacheT *newLGetElementCacheT(MGetElementCache *ins);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool visitBox(MBox *box);
|
bool visitBox(MBox *box);
|
||||||
|
@ -674,6 +674,18 @@ ParallelGetPropertyIC::initializeAddCacheState(LInstruction *ins, AddCacheState
|
|||||||
addState->dispatchScratch = ToRegister(ins->toGetPropertyCacheT()->temp());
|
addState->dispatchScratch = ToRegister(ins->toGetPropertyCacheT()->temp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ParallelGetElementIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
|
||||||
|
{
|
||||||
|
// We don't have a scratch register, but only use the temp if we needed
|
||||||
|
// one, it's BogusTemp otherwise.
|
||||||
|
JS_ASSERT(ins->isGetElementCacheV() || ins->isGetElementCacheT());
|
||||||
|
if (ins->isGetElementCacheV() || ins->toGetElementCacheT()->temp()->isBogusTemp())
|
||||||
|
addState->dispatchScratch = output_.scratchReg().gpr();
|
||||||
|
else
|
||||||
|
addState->dispatchScratch = ToRegister(ins->toGetElementCacheT()->temp());
|
||||||
|
}
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
namespace ion {
|
namespace ion {
|
||||||
|
|
||||||
|
@ -286,3 +286,16 @@ LIRGeneratorX86::newLGetPropertyCacheT(MGetPropertyCache *ins)
|
|||||||
scratch = LDefinition::BogusTemp();
|
scratch = LDefinition::BogusTemp();
|
||||||
return new LGetPropertyCacheT(useRegister(ins->object()), scratch);
|
return new LGetPropertyCacheT(useRegister(ins->object()), scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LGetElementCacheT *
|
||||||
|
LIRGeneratorX86::newLGetElementCacheT(MGetElementCache *ins)
|
||||||
|
{
|
||||||
|
LDefinition scratch;
|
||||||
|
if (ins->type() == MIRType_Double)
|
||||||
|
scratch = temp();
|
||||||
|
else
|
||||||
|
scratch = LDefinition::BogusTemp();
|
||||||
|
return new LGetElementCacheT(useRegister(ins->object()),
|
||||||
|
useRegister(ins->index()),
|
||||||
|
scratch);
|
||||||
|
}
|
||||||
|
@ -34,6 +34,7 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared
|
|||||||
bool defineUntypedPhi(MPhi *phi, size_t lirIndex);
|
bool defineUntypedPhi(MPhi *phi, size_t lirIndex);
|
||||||
|
|
||||||
LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
|
LGetPropertyCacheT *newLGetPropertyCacheT(MGetPropertyCache *ins);
|
||||||
|
LGetElementCacheT *newLGetElementCacheT(MGetElementCache *ins);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool visitBox(MBox *box);
|
bool visitBox(MBox *box);
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
load(libdir + "parallelarray-helpers.js");
|
||||||
|
|
||||||
|
function f(a) {
|
||||||
|
compareAgainstArray(
|
||||||
|
range(0, minItemsTestingThreshold),
|
||||||
|
"map",
|
||||||
|
function(i) { return a[i]; });
|
||||||
|
}
|
||||||
|
|
||||||
|
function g(a, x) {
|
||||||
|
compareAgainstArray(
|
||||||
|
range(0, minItemsTestingThreshold),
|
||||||
|
"map",
|
||||||
|
function(i) { return a[x]; });
|
||||||
|
}
|
||||||
|
|
||||||
|
function testICDenseElement() {
|
||||||
|
var a1 = [];
|
||||||
|
var a2 = [];
|
||||||
|
var a3 = [];
|
||||||
|
var a4 = [];
|
||||||
|
var len = minItemsTestingThreshold;
|
||||||
|
for (var i = 0; i < len; i++) {
|
||||||
|
a1[i] = Math.random() * 100 | 0;
|
||||||
|
a2[i] = Math.random() * 100 | 0;
|
||||||
|
a3[i] = Math.random() * 100 | 0;
|
||||||
|
a4[i] = Math.random() * 100 | 0;
|
||||||
|
}
|
||||||
|
f(a1); f({}); f(a2); f(a3); f(a4); f(a3); f(a1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function testICTypedArrayElement() {
|
||||||
|
var specs = [Int8Array,
|
||||||
|
Uint8Array,
|
||||||
|
Int16Array,
|
||||||
|
Uint16Array,
|
||||||
|
Int32Array,
|
||||||
|
Uint32Array,
|
||||||
|
Float32Array,
|
||||||
|
Float64Array,
|
||||||
|
Uint8ClampedArray];
|
||||||
|
var len = minItemsTestingThreshold;
|
||||||
|
f({});
|
||||||
|
for (var i = 0; i < specs.length; i++) {
|
||||||
|
var ta = new specs[i](len);
|
||||||
|
for (var j = 0; j < len; j++)
|
||||||
|
ta[j] = Math.random() * 100;
|
||||||
|
f(ta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function testICSlotElement() {
|
||||||
|
var o1 = { foo: 0 };
|
||||||
|
var o2 = { foo: 0, bar: '' };
|
||||||
|
var o3 = { foo: 0, bar: '', baz: function () { } };
|
||||||
|
var o4 = { foo: { } };
|
||||||
|
g(o1, "foo"); g(o2, "foo"); g(o3, "foo"); g(o2, "foo"); g(o1, "foo"); g(o4, "foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getBuildConfiguration().parallelJS) {
|
||||||
|
testICDenseElement();
|
||||||
|
testICTypedArrayElement();
|
||||||
|
testICSlotElement();
|
||||||
|
}
|
@ -594,7 +594,7 @@ js::ParallelDo::apply()
|
|||||||
// compiled scripts were collected.
|
// compiled scripts were collected.
|
||||||
if (ParallelTestsShouldPass(cx_) && worklist_.length() != 0) {
|
if (ParallelTestsShouldPass(cx_) && worklist_.length() != 0) {
|
||||||
JS_ReportError(cx_, "ForkJoin: compilation required in par or bailout mode");
|
JS_ReportError(cx_, "ForkJoin: compilation required in par or bailout mode");
|
||||||
return ExecutionFatal;
|
return SpewEndOp(ExecutionFatal);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user