зеркало из https://github.com/mozilla/gecko-dev.git
Clone type sets to avoid races when compiling off thread, bug 815258. r=dvander
This commit is contained in:
Родитель
43949a5222
Коммит
4a40134208
|
@ -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;
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче