Bug 886102 - Ignore idempotency for parallel ICs. (r=nmatsakis)

This commit is contained in:
Shu-yu Guo 2013-07-03 09:47:28 -07:00
parent 0f800194a1
commit 66ee89e766
3 changed files with 20 additions and 45 deletions

View File

@ -7848,7 +7848,14 @@ IonBuilder::getPropTryCache(bool *emitted, HandlePropertyName name, HandleId id,
// Try to mark the cache as idempotent. We only do this if JM is enabled
// (its ICs are used to mark property reads as likely non-idempotent) or
// if we are compiling eagerly (to improve test coverage).
if (obj->type() == MIRType_Object && !invalidatedIdempotentCache()) {
//
// In parallel execution, idempotency of caches is ignored, since we
// repeat the entire ForkJoin workload if we bail out. Note that it's
// overly restrictive to mark everything as idempotent, because we can
// treat non-idempotent caches in parallel as repeatable.
if (obj->type() == MIRType_Object && !invalidatedIdempotentCache() &&
info().executionMode() != ParallelExecution)
{
if (PropertyReadIsIdempotent(cx, obj, name))
load->setIdempotent();
}

View File

@ -1580,15 +1580,8 @@ bool
ParallelGetPropertyIC::canAttachReadSlot(LockedJSContext &cx, JSObject *obj,
MutableHandleObject holder, MutableHandleShape shape)
{
// Parallel execution should only cache native objects.
if (!obj->isNative())
return false;
if (IsIdempotentAndMaybeHasHooks(*this, obj))
return false;
// Bail if we have hooks.
if (obj->getOps()->lookupProperty || obj->getOps()->lookupGeneric)
// Bail if we have hooks or are not native.
if (!obj->hasIdempotentProtoChain())
return false;
if (!js::LookupPropertyPure(obj, NameToId(name()), holder.address(), shape.address()))
@ -1604,9 +1597,6 @@ ParallelGetPropertyIC::canAttachReadSlot(LockedJSContext &cx, JSObject *obj,
return false;
}
if (IsIdempotentAndHasSingletonHolder(*this, holder, shape))
return false;
return true;
}
@ -1626,11 +1616,7 @@ ParallelGetPropertyIC::attachReadSlot(LockedJSContext &cx, IonScript *ion,
MacroAssembler masm(cx);
GenerateReadSlot(cx, ion, masm, attacher, obj, name(), holder, shape, object(), output());
const char *attachKind = "parallel non-idempotent reading";
if (idempotent())
attachKind = "parallel idempotent reading";
if (!linkAndAttachStub(cx, masm, attacher, ion, attachKind))
if (!linkAndAttachStub(cx, masm, attacher, ion, "parallel reading"))
return false;
*attachedStub = true;
@ -1651,17 +1637,13 @@ ParallelGetPropertyIC::update(ForkJoinSlice *slice, size_t cacheIndex,
ParallelGetPropertyIC &cache = ion->getCache(cacheIndex).toParallelGetProperty();
RootedScript script(pt);
jsbytecode *pc;
cache.getScriptedLocation(&script, &pc);
// Grab the property early, as the pure path is fast anyways and doesn't
// need a lock. If we can't do it purely, bail out of parallel execution.
if (!GetPropertyPure(obj, NameToId(cache.name()), vp.address()))
return TP_RETRY_SEQUENTIALLY;
// Avoid unnecessary locking if cannot attach stubs and idempotent.
if (cache.idempotent() && !cache.canAttachStub())
// Avoid unnecessary locking if cannot attach stubs.
if (!cache.canAttachStub())
return TP_SUCCESS;
{
@ -1687,25 +1669,11 @@ ParallelGetPropertyIC::update(ForkJoinSlice *slice, size_t cacheIndex,
return TP_FATAL;
if (!attachedStub) {
if (cache.idempotent())
topScript->invalidatedIdempotentCache = true;
// ParallelDo will take care of invalidating all bailed out
// scripts, so just bail out now.
return TP_RETRY_SEQUENTIALLY;
}
}
if (!cache.idempotent()) {
#if JS_HAS_NO_SUCH_METHOD
// Straight up bail if there's this __noSuchMethod__ hook.
if (JSOp(*pc) == JSOP_CALLPROP && JS_UNLIKELY(vp.isPrimitive()))
return TP_RETRY_SEQUENTIALLY;
#endif
// Monitor changes to cache entry.
types::TypeScript::Monitor(cx, script, pc, vp);
}
}
return TP_SUCCESS;

View File

@ -46,15 +46,15 @@ using parallel::SpewCompile;
return visitSpecializedInstruction(ins, ins->specialization(), flags); \
}
#define UNSAFE_OP(op) \
virtual bool visit##op(M##op *ins) { \
SpewMIR(ins, "Unsafe"); \
return markUnsafe(); \
#define UNSAFE_OP(op) \
virtual bool visit##op(M##op *ins) { \
SpewMIR(ins, "Unsafe"); \
return markUnsafe(); \
}
#define WRITE_GUARDED_OP(op, obj) \
virtual bool visit##op(M##op *prop) { \
return insertWriteGuard(prop, prop->obj()); \
#define WRITE_GUARDED_OP(op, obj) \
virtual bool visit##op(M##op *prop) { \
return insertWriteGuard(prop, prop->obj()); \
}
#define MAYBE_WRITE_GUARDED_OP(op, obj) \