Bug 918584 - Part 4: Add SetElementParIC. (r=jandem)

This commit is contained in:
Shu-yu Guo 2013-10-10 20:02:31 -07:00
parent ace6f49a57
commit 790c9846bd
7 changed files with 334 additions and 10 deletions

View 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();
}

View File

@ -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 =

View File

@ -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);

View File

@ -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))
{

View File

@ -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.

View File

@ -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)

View File

@ -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 {