Clone type sets to avoid races when compiling off thread, bug 815258. r=dvander

This commit is contained in:
Brian Hackett 2012-11-26 16:32:45 -05:00
parent 43949a5222
commit 4a40134208
10 changed files with 84 additions and 32 deletions

View File

@ -1271,7 +1271,7 @@ CodeGenerator::generateArgumentsChecks()
for (uint32 i = START_SLOT; i < CountArgSlots(info.fun()); i++) {
// All initial parameters are guaranteed to be MParameters.
MParameter *param = rp->getOperand(i)->toParameter();
types::TypeSet *types = param->typeSet();
const types::TypeSet *types = param->typeSet();
if (!types || types->unknown())
continue;

View File

@ -500,7 +500,14 @@ IonBuilder::rewriteParameters()
for (uint32 i = START_SLOT; i < CountArgSlots(info().fun()); i++) {
MParameter *param = current->getSlot(i)->toParameter();
types::StackTypeSet *types = param->typeSet();
// Find the original (not cloned) type set for the MParameter, as we
// will be adding constraints to it.
types::StackTypeSet *types;
if (param->index() == MParameter::THIS_SLOT)
types = oracle->thisTypeSet(script_);
else
types = oracle->parameterTypeSet(script_, param->index());
if (!types)
continue;
@ -544,7 +551,7 @@ IonBuilder::initParameters()
return true;
MParameter *param = MParameter::New(MParameter::THIS_SLOT,
oracle->thisTypeSet(script_));
cloneTypeSet(oracle->thisTypeSet(script_)));
current->add(param);
current->initSlot(info().thisSlot(), param);
@ -4536,7 +4543,7 @@ IonBuilder::pushTypeBarrier(MInstruction *ins, types::StackTypeSet *actual,
case JSVAL_TYPE_UNKNOWN:
case JSVAL_TYPE_UNDEFINED:
case JSVAL_TYPE_NULL:
barrier = MTypeBarrier::New(ins, observed);
barrier = MTypeBarrier::New(ins, cloneTypeSet(observed));
current->add(barrier);
if (type == JSVAL_TYPE_UNDEFINED)
@ -4569,7 +4576,7 @@ IonBuilder::monitorResult(MInstruction *ins, types::TypeSet *barrier, types::Typ
if (!types || types->unknown())
return;
MInstruction *monitor = MMonitorTypes::New(ins, types);
MInstruction *monitor = MMonitorTypes::New(ins, cloneTypeSet(types));
current->add(monitor);
}
@ -6561,3 +6568,16 @@ IonBuilder::addShapeGuard(MDefinition *obj, const Shape *shape, BailoutKind bail
return guard;
}
const types::TypeSet *
IonBuilder::cloneTypeSet(const types::TypeSet *types)
{
if (!js_IonOptions.parallelCompilation)
return types;
// Clone a type set so that it can be stored into the MIR and accessed
// during off thread compilation. This is necessary because main thread
// updates to type sets can race with reads in the compiler backend, and
// after bug 804676 this code can be removed.
return types->clone(GetIonContext()->temp->lifoAlloc());
}

View File

@ -437,6 +437,8 @@ class IonBuilder : public MIRGenerator
MBasicBlock *bottom,
Vector<MDefinition *, 8, IonAllocPolicy> &retvalDefns);
const types::TypeSet *cloneTypeSet(const types::TypeSet *types);
// A builder is inextricably tied to a particular script.
HeapPtrScript script_;

View File

@ -15,7 +15,7 @@ using namespace js;
using namespace js::ion;
template <typename T> void
MacroAssembler::guardTypeSet(const T &address, types::TypeSet *types,
MacroAssembler::guardTypeSet(const T &address, const types::TypeSet *types,
Register scratch, Label *mismatched)
{
JS_ASSERT(!types->unknown());
@ -64,9 +64,9 @@ MacroAssembler::guardTypeSet(const T &address, types::TypeSet *types,
bind(&matched);
}
template void MacroAssembler::guardTypeSet(const Address &address, types::TypeSet *types,
template void MacroAssembler::guardTypeSet(const Address &address, const types::TypeSet *types,
Register scratch, Label *mismatched);
template void MacroAssembler::guardTypeSet(const ValueOperand &value, types::TypeSet *types,
template void MacroAssembler::guardTypeSet(const ValueOperand &value, const types::TypeSet *types,
Register scratch, Label *mismatched);
void

View File

@ -119,7 +119,7 @@ class MacroAssembler : public MacroAssemblerSpecific
// Emits a test of a value against all types in a TypeSet. A scratch
// register is required.
template <typename T>
void guardTypeSet(const T &address, types::TypeSet *types, Register scratch,
void guardTypeSet(const T &address, const types::TypeSet *types, Register scratch,
Label *mismatched);
void loadObjShape(Register objReg, Register dest) {

View File

@ -347,7 +347,7 @@ MConstantElements::printOpcode(FILE *fp)
}
MParameter *
MParameter::New(int32 index, types::StackTypeSet *types)
MParameter::New(int32 index, const types::TypeSet *types)
{
return new MParameter(index, types);
}

View File

@ -632,12 +632,12 @@ class MConstant : public MNullaryInstruction
class MParameter : public MNullaryInstruction
{
int32 index_;
types::StackTypeSet *typeSet_;
const types::TypeSet *typeSet_;
public:
static const int32 THIS_SLOT = -1;
MParameter(int32 index, types::StackTypeSet *types)
MParameter(int32 index, const types::TypeSet *types)
: index_(index),
typeSet_(types)
{
@ -646,12 +646,12 @@ class MParameter : public MNullaryInstruction
public:
INSTRUCTION_HEADER(Parameter);
static MParameter *New(int32 index, types::StackTypeSet *types);
static MParameter *New(int32 index, const types::TypeSet *types);
int32 index() const {
return index_;
}
types::StackTypeSet *typeSet() const {
const types::TypeSet *typeSet() const {
return typeSet_;
}
void printOpcode(FILE *fp);
@ -5353,9 +5353,9 @@ class MGetArgument
class MTypeBarrier : public MUnaryInstruction
{
BailoutKind bailoutKind_;
types::TypeSet *typeSet_;
const types::TypeSet *typeSet_;
MTypeBarrier(MDefinition *def, types::TypeSet *types)
MTypeBarrier(MDefinition *def, const types::TypeSet *types)
: MUnaryInstruction(def),
typeSet_(types)
{
@ -5370,7 +5370,7 @@ class MTypeBarrier : public MUnaryInstruction
public:
INSTRUCTION_HEADER(TypeBarrier);
static MTypeBarrier *New(MDefinition *def, types::TypeSet *types) {
static MTypeBarrier *New(MDefinition *def, const types::TypeSet *types) {
return new MTypeBarrier(def, types);
}
bool congruentTo(MDefinition * const &def) const {
@ -5382,7 +5382,7 @@ class MTypeBarrier : public MUnaryInstruction
BailoutKind bailoutKind() const {
return bailoutKind_;
}
types::TypeSet *typeSet() const {
const types::TypeSet *typeSet() const {
return typeSet_;
}
AliasSet getAliasSet() const {
@ -5395,9 +5395,9 @@ class MTypeBarrier : public MUnaryInstruction
// TypeScript::Monitor inside these stubs.
class MMonitorTypes : public MUnaryInstruction
{
types::TypeSet *typeSet_;
const types::TypeSet *typeSet_;
MMonitorTypes(MDefinition *def, types::TypeSet *types)
MMonitorTypes(MDefinition *def, const types::TypeSet *types)
: MUnaryInstruction(def),
typeSet_(types)
{
@ -5409,13 +5409,13 @@ class MMonitorTypes : public MUnaryInstruction
public:
INSTRUCTION_HEADER(MonitorTypes);
static MMonitorTypes *New(MDefinition *def, types::TypeSet *types) {
static MMonitorTypes *New(MDefinition *def, const types::TypeSet *types) {
return new MMonitorTypes(def, types);
}
MDefinition *input() const {
return getOperand(0);
}
types::TypeSet *typeSet() const {
const types::TypeSet *typeSet() const {
return typeSet_;
}
AliasSet getAliasSet() const {

View File

@ -456,6 +456,30 @@ StackTypeSet::make(JSContext *cx, const char *name)
return res;
}
const TypeSet *
TypeSet::clone(LifoAlloc *alloc) const
{
unsigned objectCount = baseObjectCount();
unsigned capacity = (objectCount >= 2) ? HashSetCapacity(objectCount) : 0;
TypeSet *res = alloc->new_<TypeSet>();
if (!res)
return NULL;
TypeObjectKey **newSet;
if (capacity) {
newSet = alloc->newArray<TypeObjectKey*>(capacity);
if (!newSet)
return NULL;
PodCopy(newSet, objectSet, capacity);
}
res->flags = this->flags;
res->objectSet = capacity ? newSet : this->objectSet;
return res;
}
/////////////////////////////////////////////////////////////////////
// TypeSet constraints
/////////////////////////////////////////////////////////////////////

View File

@ -444,7 +444,7 @@ class TypeSet
inline void sweep(JSCompartment *compartment);
/* Whether this set contains a specific type. */
inline bool hasType(Type type);
inline bool hasType(Type type) const;
TypeFlags baseFlags() const { return flags & TYPE_FLAG_BASE_MASK; }
bool unknown() const { return !!(flags & TYPE_FLAG_UNKNOWN); }
@ -466,6 +466,12 @@ class TypeSet
return flags >> TYPE_FLAG_DEFINITE_SHIFT;
}
/*
* Clone a type set into an arbitrary allocator. The result should not be
* modified further.
*/
const TypeSet *clone(LifoAlloc *alloc) const;
/*
* Add a type to this set, calling any constraint handlers if this is a new
* possible type.
@ -480,10 +486,10 @@ class TypeSet
* in the hash case (see SET_ARRAY_SIZE in jsinferinlines.h), and getObject
* may return NULL.
*/
inline unsigned getObjectCount();
inline TypeObjectKey *getObject(unsigned i);
inline RawObject getSingleObject(unsigned i);
inline TypeObject *getTypeObject(unsigned i);
inline unsigned getObjectCount() const;
inline TypeObjectKey *getObject(unsigned i) const;
inline RawObject getSingleObject(unsigned i) const;
inline TypeObject *getTypeObject(unsigned i) const;
void setOwnProperty(bool configurable) {
flags |= TYPE_FLAG_OWN_PROPERTY;

View File

@ -1294,7 +1294,7 @@ Type::typeObject() const
}
inline bool
TypeSet::hasType(Type type)
TypeSet::hasType(Type type) const
{
if (unknown())
return true;
@ -1431,7 +1431,7 @@ TypeSet::setOwnProperty(JSContext *cx, bool configured)
}
inline unsigned
TypeSet::getObjectCount()
TypeSet::getObjectCount() const
{
JS_ASSERT(!unknownObject());
uint32_t count = baseObjectCount();
@ -1441,7 +1441,7 @@ TypeSet::getObjectCount()
}
inline TypeObjectKey *
TypeSet::getObject(unsigned i)
TypeSet::getObject(unsigned i) const
{
JS_ASSERT(i < getObjectCount());
if (baseObjectCount() == 1) {
@ -1452,14 +1452,14 @@ TypeSet::getObject(unsigned i)
}
inline RawObject
TypeSet::getSingleObject(unsigned i)
TypeSet::getSingleObject(unsigned i) const
{
TypeObjectKey *key = getObject(i);
return (uintptr_t(key) & 1) ? (JSObject *)(uintptr_t(key) ^ 1) : NULL;
}
inline TypeObject *
TypeSet::getTypeObject(unsigned i)
TypeSet::getTypeObject(unsigned i) const
{
TypeObjectKey *key = getObject(i);
return (key && !(uintptr_t(key) & 1)) ? (TypeObject *) key : NULL;