mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-21 17:59:34 +00:00
Bug 918584 - Part 4: Add SetElementParIC. (r=jandem)
This commit is contained in:
parent
ace6f49a57
commit
790c9846bd
135
js/src/jit-test/tests/parallel/ic-setelement.js
Normal file
135
js/src/jit-test/tests/parallel/ic-setelement.js
Normal file
@ -0,0 +1,135 @@
|
||||
load(libdir + "parallelarray-helpers.js");
|
||||
|
||||
function set(a, n) {
|
||||
// Padding to prevent inlining.
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
for (var i = 0; i < n; i++)
|
||||
a[i] = i;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
var foo = 0;
|
||||
}
|
||||
set({}, 1024);
|
||||
set({}, 1024);
|
||||
function Foo() { }
|
||||
set(new Foo, 1024);
|
||||
|
||||
function testSetDense() {
|
||||
assertArraySeqParResultsEq(
|
||||
range(0, minItemsTestingThreshold),
|
||||
"map",
|
||||
function (i) {
|
||||
var a1 = [];
|
||||
// Defines .foo
|
||||
set(a1, i+1);
|
||||
return a1[i];
|
||||
});
|
||||
}
|
||||
|
||||
if (getBuildConfiguration().parallelJS) {
|
||||
testSetDense();
|
||||
}
|
@ -6057,6 +6057,25 @@ CodeGenerator::addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Regi
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex,
|
||||
Register temp, FloatRegister tempFloat, ValueOperand index,
|
||||
ConstantOrRegister value, bool strict)
|
||||
{
|
||||
switch (gen->info().executionMode()) {
|
||||
case SequentialExecution: {
|
||||
SetElementIC cache(obj, unboxIndex, temp, tempFloat, index, value, strict);
|
||||
return addCache(ins, allocateCache(cache));
|
||||
}
|
||||
case ParallelExecution: {
|
||||
SetElementParIC cache(obj, unboxIndex, temp, tempFloat, index, value, strict);
|
||||
return addCache(ins, allocateCache(cache));
|
||||
}
|
||||
default:
|
||||
MOZ_ASSUME_UNREACHABLE("Bad execution mode");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV *ins)
|
||||
{
|
||||
@ -6202,9 +6221,8 @@ CodeGenerator::visitSetElementCacheV(LSetElementCacheV *ins)
|
||||
ValueOperand index = ToValue(ins, LSetElementCacheV::Index);
|
||||
ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetElementCacheV::Value));
|
||||
|
||||
SetElementIC cache(obj, unboxIndex, temp, tempFloat, index, value, ins->mir()->strict());
|
||||
|
||||
return addCache(ins, allocateCache(cache));
|
||||
return addSetElementCache(ins, obj, unboxIndex, temp, tempFloat, index, value,
|
||||
ins->mir()->strict());
|
||||
}
|
||||
|
||||
bool
|
||||
@ -6222,9 +6240,8 @@ CodeGenerator::visitSetElementCacheT(LSetElementCacheT *ins)
|
||||
else
|
||||
value = TypedOrValueRegister(ins->mir()->value()->type(), ToAnyRegister(tmp));
|
||||
|
||||
SetElementIC cache(obj, unboxIndex, temp, tempFloat, index, value, ins->mir()->strict());
|
||||
|
||||
return addCache(ins, allocateCache(cache));
|
||||
return addSetElementCache(ins, obj, unboxIndex, temp, tempFloat, index, value,
|
||||
ins->mir()->strict());
|
||||
}
|
||||
|
||||
typedef bool (*SetElementICFn)(JSContext *, size_t, HandleObject, HandleValue, HandleValue);
|
||||
@ -6249,6 +6266,29 @@ CodeGenerator::visitSetElementIC(OutOfLineUpdateCache *ool, DataPtr<SetElementIC
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef ParallelResult (*SetElementParICFn)(ForkJoinSlice *, size_t, HandleObject,
|
||||
HandleValue, HandleValue);
|
||||
const VMFunction SetElementParIC::UpdateInfo =
|
||||
FunctionInfo<SetElementParICFn>(SetElementParIC::update);
|
||||
|
||||
bool
|
||||
CodeGenerator::visitSetElementParIC(OutOfLineUpdateCache *ool, DataPtr<SetElementParIC> &ic)
|
||||
{
|
||||
LInstruction *lir = ool->lir();
|
||||
saveLive(lir);
|
||||
|
||||
pushArg(ic->value());
|
||||
pushArg(ic->index());
|
||||
pushArg(ic->object());
|
||||
pushArg(Imm32(ool->getCacheIndex()));
|
||||
if (!callVM(SetElementParIC::UpdateInfo, lir))
|
||||
return false;
|
||||
restoreLive(lir);
|
||||
|
||||
masm.jump(ool->rejoin());
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef ParallelResult (*GetElementParICFn)(ForkJoinSlice *, size_t, HandleObject,
|
||||
HandleValue, MutableHandleValue);
|
||||
const VMFunction GetElementParIC::UpdateInfo =
|
||||
|
@ -316,6 +316,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
bool visitGetElementIC(OutOfLineUpdateCache *ool, DataPtr<GetElementIC> &ic);
|
||||
bool visitGetElementParIC(OutOfLineUpdateCache *ool, DataPtr<GetElementParIC> &ic);
|
||||
bool visitSetElementIC(OutOfLineUpdateCache *ool, DataPtr<SetElementIC> &ic);
|
||||
bool visitSetElementParIC(OutOfLineUpdateCache *ool, DataPtr<SetElementParIC> &ic);
|
||||
bool visitBindNameIC(OutOfLineUpdateCache *ool, DataPtr<BindNameIC> &ic);
|
||||
bool visitNameIC(OutOfLineUpdateCache *ool, DataPtr<NameIC> &ic);
|
||||
bool visitCallsiteCloneIC(OutOfLineUpdateCache *ool, DataPtr<CallsiteCloneIC> &ic);
|
||||
@ -340,6 +341,9 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
bool addSetPropertyCache(LInstruction *ins, RegisterSet liveRegs, Register objReg,
|
||||
PropertyName *name, ConstantOrRegister value, bool strict,
|
||||
bool needsTypeBarrier);
|
||||
bool addSetElementCache(LInstruction *ins, Register obj, Register unboxIndex, Register temp,
|
||||
FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
|
||||
bool strict);
|
||||
bool checkForAbortPar(LInstruction *lir);
|
||||
|
||||
bool generateBranchV(const ValueOperand &value, Label *ifTrue, Label *ifFalse, FloatRegister fr);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#ifdef JS_ION_PERF
|
||||
# include "jit/PerfSpewer.h"
|
||||
#endif
|
||||
#include "jit/ParallelFunctions.h"
|
||||
#include "jit/VMFunctions.h"
|
||||
#include "vm/Shape.h"
|
||||
|
||||
@ -3660,6 +3661,76 @@ SetElementIC::reset()
|
||||
hasDenseStub_ = false;
|
||||
}
|
||||
|
||||
bool
|
||||
SetElementParIC::attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj,
|
||||
const Value &idval)
|
||||
{
|
||||
MacroAssembler masm(cx);
|
||||
DispatchStubPrepender attacher(*this);
|
||||
if (!GenerateSetDenseElement(cx, masm, attacher, obj, idval,
|
||||
object(), index(), value(),
|
||||
tempToUnboxIndex(), temp()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "parallel dense array");
|
||||
}
|
||||
|
||||
bool
|
||||
SetElementParIC::attachTypedArrayElement(LockedJSContext &cx, IonScript *ion,
|
||||
TypedArrayObject *tarr)
|
||||
{
|
||||
MacroAssembler masm(cx);
|
||||
DispatchStubPrepender attacher(*this);
|
||||
if (!GenerateSetTypedArrayElement(cx, masm, attacher, tarr,
|
||||
object(), index(), value(),
|
||||
tempToUnboxIndex(), temp(), tempFloat()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "parallel typed array");
|
||||
}
|
||||
|
||||
ParallelResult
|
||||
SetElementParIC::update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
|
||||
HandleValue idval, HandleValue value)
|
||||
{
|
||||
IonScript *ion = GetTopIonJSScript(slice)->parallelIonScript();
|
||||
SetElementParIC &cache = ion->getCache(cacheIndex).toSetElementPar();
|
||||
|
||||
// Avoid unnecessary locking if cannot attach stubs.
|
||||
if (!cache.canAttachStub())
|
||||
return SetElementPar(slice, obj, idval, value, cache.strict());
|
||||
|
||||
{
|
||||
LockedJSContext cx(slice);
|
||||
|
||||
if (cache.canAttachStub()) {
|
||||
bool alreadyStubbed;
|
||||
if (!cache.hasOrAddStubbedShape(cx, obj->lastProperty(), &alreadyStubbed))
|
||||
return TP_FATAL;
|
||||
if (alreadyStubbed)
|
||||
return SetElementPar(slice, obj, idval, value, cache.strict());
|
||||
|
||||
bool attachedStub = false;
|
||||
if (IsDenseElementSetInlineable(obj, idval)) {
|
||||
if (!cache.attachDenseElement(cx, ion, obj, idval))
|
||||
return TP_FATAL;
|
||||
attachedStub = true;
|
||||
}
|
||||
if (!attachedStub && IsTypedArrayElementSetInlineable(obj, idval, value)) {
|
||||
TypedArrayObject *tarr = &obj->as<TypedArrayObject>();
|
||||
if (!cache.attachTypedArrayElement(cx, ion, tarr))
|
||||
return TP_FATAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SetElementPar(slice, obj, idval, value, cache.strict());
|
||||
}
|
||||
|
||||
bool
|
||||
GetElementParIC::attachReadSlot(LockedJSContext &cx, IonScript *ion, JSObject *obj,
|
||||
const Value &idval, PropertyName *name, JSObject *holder,
|
||||
@ -3734,7 +3805,6 @@ GetElementParIC::update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject ob
|
||||
return TP_FATAL;
|
||||
|
||||
bool attachedStub = false;
|
||||
|
||||
if (cache.monitoredResult() &&
|
||||
GetElementIC::canAttachGetProp(obj, idval, id))
|
||||
{
|
||||
|
@ -30,7 +30,8 @@ namespace jit {
|
||||
_(CallsiteClone) \
|
||||
_(GetPropertyPar) \
|
||||
_(GetElementPar) \
|
||||
_(SetPropertyPar)
|
||||
_(SetPropertyPar) \
|
||||
_(SetElementPar)
|
||||
|
||||
// Forward declarations of Cache kinds.
|
||||
#define FORWARD_DECLARE(kind) class kind##IC;
|
||||
@ -1167,6 +1168,68 @@ class SetPropertyParIC : public ParallelIonCache
|
||||
HandleValue value);
|
||||
};
|
||||
|
||||
class SetElementParIC : public ParallelIonCache
|
||||
{
|
||||
protected:
|
||||
Register object_;
|
||||
Register tempToUnboxIndex_;
|
||||
Register temp_;
|
||||
FloatRegister tempFloat_;
|
||||
ValueOperand index_;
|
||||
ConstantOrRegister value_;
|
||||
bool strict_;
|
||||
|
||||
public:
|
||||
SetElementParIC(Register object, Register tempToUnboxIndex, Register temp,
|
||||
FloatRegister tempFloat, ValueOperand index, ConstantOrRegister value,
|
||||
bool strict)
|
||||
: object_(object),
|
||||
tempToUnboxIndex_(tempToUnboxIndex),
|
||||
temp_(temp),
|
||||
tempFloat_(tempFloat),
|
||||
index_(index),
|
||||
value_(value),
|
||||
strict_(strict)
|
||||
{
|
||||
}
|
||||
|
||||
CACHE_HEADER(SetElementPar)
|
||||
|
||||
#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_;
|
||||
}
|
||||
Register tempToUnboxIndex() const {
|
||||
return tempToUnboxIndex_;
|
||||
}
|
||||
Register temp() const {
|
||||
return temp_;
|
||||
}
|
||||
FloatRegister tempFloat() const {
|
||||
return tempFloat_;
|
||||
}
|
||||
ValueOperand index() const {
|
||||
return index_;
|
||||
}
|
||||
ConstantOrRegister value() const {
|
||||
return value_;
|
||||
}
|
||||
bool strict() const {
|
||||
return strict_;
|
||||
}
|
||||
|
||||
bool attachDenseElement(LockedJSContext &cx, IonScript *ion, JSObject *obj, const Value &idval);
|
||||
bool attachTypedArrayElement(LockedJSContext &cx, IonScript *ion, TypedArrayObject *tarr);
|
||||
|
||||
static ParallelResult update(ForkJoinSlice *slice, size_t cacheIndex, HandleObject obj,
|
||||
HandleValue idval, HandleValue value);
|
||||
};
|
||||
|
||||
#undef CACHE_HEADER
|
||||
|
||||
// Implement cache casts now that the compiler can see the inheritance.
|
||||
|
@ -201,7 +201,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
|
||||
SAFE_OP(GetPropertyPolymorphic)
|
||||
UNSAFE_OP(SetPropertyPolymorphic)
|
||||
SAFE_OP(GetElementCache)
|
||||
UNSAFE_OP(SetElementCache)
|
||||
WRITE_GUARDED_OP(SetElementCache, object)
|
||||
UNSAFE_OP(BindNameCache)
|
||||
SAFE_OP(GuardShape)
|
||||
SAFE_OP(GuardObjectType)
|
||||
@ -236,7 +236,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
|
||||
UNSAFE_OP(CallGetIntrinsicValue)
|
||||
UNSAFE_OP(CallsiteCloneCache)
|
||||
UNSAFE_OP(CallGetElement)
|
||||
UNSAFE_OP(CallSetElement)
|
||||
WRITE_GUARDED_OP(CallSetElement, object)
|
||||
UNSAFE_OP(CallInitElementArray)
|
||||
WRITE_GUARDED_OP(CallSetProperty, object)
|
||||
UNSAFE_OP(DeleteProperty)
|
||||
|
@ -758,6 +758,18 @@ SetPropertyParIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addS
|
||||
addState->dispatchScratch = ToRegister(ins->toSetPropertyCacheT()->tempForDispatchCache());
|
||||
}
|
||||
|
||||
void
|
||||
SetElementParIC::initializeAddCacheState(LInstruction *ins, AddCacheState *addState)
|
||||
{
|
||||
// We don't have an output register to reuse, but luckily SetElementCache
|
||||
// already needs a temp.
|
||||
JS_ASSERT(ins->isSetElementCacheV() || ins->isSetElementCacheT());
|
||||
if (ins->isSetElementCacheV())
|
||||
addState->dispatchScratch = ToRegister(ins->toSetElementCacheV()->temp());
|
||||
else
|
||||
addState->dispatchScratch = ToRegister(ins->toSetElementCacheT()->temp());
|
||||
}
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user