mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1022356 Part 01 -- Move from TypedProtoSet to TypedObjectPrediction r=shu
This commit is contained in:
parent
c1e4a09735
commit
e7fb87053d
@ -168,6 +168,8 @@ class TypedProto : public JSObject
|
|||||||
TypeDescr &typeDescr() const {
|
TypeDescr &typeDescr() const {
|
||||||
return getReservedSlot(JS_TYPROTO_SLOT_DESCR).toObject().as<TypeDescr>();
|
return getReservedSlot(JS_TYPROTO_SLOT_DESCR).toObject().as<TypeDescr>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline type::Kind kind() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TypeDescr : public JSObject
|
class TypeDescr : public JSObject
|
||||||
@ -1055,4 +1057,11 @@ js::TypedProto::initTypeDescrSlot(TypeDescr &descr)
|
|||||||
initReservedSlot(JS_TYPROTO_SLOT_DESCR, ObjectValue(descr));
|
initReservedSlot(JS_TYPROTO_SLOT_DESCR, ObjectValue(descr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline js::type::Kind
|
||||||
|
js::TypedProto::kind() const {
|
||||||
|
// Defined out of line because it depends on def'n of both
|
||||||
|
// TypedProto and TypeDescr
|
||||||
|
return typeDescr().kind();
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* builtin_TypedObject_h */
|
#endif /* builtin_TypedObject_h */
|
||||||
|
@ -30,7 +30,7 @@ function foo() {
|
|||||||
var s;
|
var s;
|
||||||
|
|
||||||
for (var i = 0; i < N; i++) {
|
for (var i = 0; i < N; i++) {
|
||||||
if ((i % 2) == 0 || true)
|
if ((i % 2) == 0)
|
||||||
obj = new PointType2({x: i, y: i+1});
|
obj = new PointType2({x: i, y: i+1});
|
||||||
else
|
else
|
||||||
obj = new PointType3({x: i, y: i+1, z: i+2});
|
obj = new PointType3({x: i, y: i+1, z: i+2});
|
||||||
|
@ -117,7 +117,6 @@ IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp,
|
|||||||
backgroundCodegen_(nullptr),
|
backgroundCodegen_(nullptr),
|
||||||
analysisContext(analysisContext),
|
analysisContext(analysisContext),
|
||||||
baselineFrame_(baselineFrame),
|
baselineFrame_(baselineFrame),
|
||||||
descrSetHash_(nullptr),
|
|
||||||
constraints_(constraints),
|
constraints_(constraints),
|
||||||
analysis_(*temp, info->script()),
|
analysis_(*temp, info->script()),
|
||||||
thisTypes(nullptr),
|
thisTypes(nullptr),
|
||||||
@ -6750,26 +6749,24 @@ IonBuilder::getElemTryTypedObject(bool *emitted, MDefinition *obj, MDefinition *
|
|||||||
{
|
{
|
||||||
JS_ASSERT(*emitted == false);
|
JS_ASSERT(*emitted == false);
|
||||||
|
|
||||||
TypeDescrSet objDescrs;
|
TypedObjectPrediction objPrediction = typedObjectPrediction(obj);
|
||||||
if (!lookupTypeDescrSet(obj, &objDescrs))
|
if (objPrediction.isUseless())
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!objDescrs.allOfArrayKind())
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
TypeDescrSet elemDescrs;
|
if (!objPrediction.ofArrayKind())
|
||||||
if (!objDescrs.arrayElementType(*this, &elemDescrs))
|
|
||||||
return false;
|
|
||||||
if (elemDescrs.empty())
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
JS_ASSERT(TypeDescr::isSized(elemDescrs.kind()));
|
TypedObjectPrediction elemPrediction = objPrediction.arrayElementType();
|
||||||
|
if (elemPrediction.isUseless())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
JS_ASSERT(TypeDescr::isSized(elemPrediction.kind()));
|
||||||
|
|
||||||
int32_t elemSize;
|
int32_t elemSize;
|
||||||
if (!elemDescrs.allHaveSameSize(&elemSize))
|
if (!elemPrediction.hasKnownSize(&elemSize))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
switch (elemDescrs.kind()) {
|
switch (elemPrediction.kind()) {
|
||||||
case type::X4:
|
case type::X4:
|
||||||
// FIXME (bug 894105): load into a MIRType_float32x4 etc
|
// FIXME (bug 894105): load into a MIRType_float32x4 etc
|
||||||
return true;
|
return true;
|
||||||
@ -6779,15 +6776,15 @@ IonBuilder::getElemTryTypedObject(bool *emitted, MDefinition *obj, MDefinition *
|
|||||||
return getElemTryComplexElemOfTypedObject(emitted,
|
return getElemTryComplexElemOfTypedObject(emitted,
|
||||||
obj,
|
obj,
|
||||||
index,
|
index,
|
||||||
objDescrs,
|
objPrediction,
|
||||||
elemDescrs,
|
elemPrediction,
|
||||||
elemSize);
|
elemSize);
|
||||||
case type::Scalar:
|
case type::Scalar:
|
||||||
return getElemTryScalarElemOfTypedObject(emitted,
|
return getElemTryScalarElemOfTypedObject(emitted,
|
||||||
obj,
|
obj,
|
||||||
index,
|
index,
|
||||||
objDescrs,
|
objPrediction,
|
||||||
elemDescrs,
|
elemPrediction,
|
||||||
elemSize);
|
elemSize);
|
||||||
|
|
||||||
case type::Reference:
|
case type::Reference:
|
||||||
@ -6808,7 +6805,7 @@ bool
|
|||||||
IonBuilder::checkTypedObjectIndexInBounds(int32_t elemSize,
|
IonBuilder::checkTypedObjectIndexInBounds(int32_t elemSize,
|
||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
MDefinition *index,
|
MDefinition *index,
|
||||||
TypeDescrSet objDescrs,
|
TypedObjectPrediction objPrediction,
|
||||||
MDefinition **indexAsByteOffset,
|
MDefinition **indexAsByteOffset,
|
||||||
bool *canBeNeutered)
|
bool *canBeNeutered)
|
||||||
{
|
{
|
||||||
@ -6822,7 +6819,7 @@ IonBuilder::checkTypedObjectIndexInBounds(int32_t elemSize,
|
|||||||
// Value to int32 using truncation.
|
// Value to int32 using truncation.
|
||||||
int32_t lenOfAll;
|
int32_t lenOfAll;
|
||||||
MDefinition *length;
|
MDefinition *length;
|
||||||
if (objDescrs.hasKnownArrayLength(&lenOfAll)) {
|
if (objPrediction.hasKnownArrayLength(&lenOfAll)) {
|
||||||
length = constantInt(lenOfAll);
|
length = constantInt(lenOfAll);
|
||||||
|
|
||||||
// If we are not loading the length from the object itself,
|
// If we are not loading the length from the object itself,
|
||||||
@ -6859,21 +6856,19 @@ bool
|
|||||||
IonBuilder::getElemTryScalarElemOfTypedObject(bool *emitted,
|
IonBuilder::getElemTryScalarElemOfTypedObject(bool *emitted,
|
||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
MDefinition *index,
|
MDefinition *index,
|
||||||
TypeDescrSet objDescrs,
|
TypedObjectPrediction objPrediction,
|
||||||
TypeDescrSet elemDescrs,
|
TypedObjectPrediction elemPrediction,
|
||||||
int32_t elemSize)
|
int32_t elemSize)
|
||||||
{
|
{
|
||||||
JS_ASSERT(objDescrs.allOfArrayKind());
|
JS_ASSERT(objPrediction.ofArrayKind());
|
||||||
|
|
||||||
// Must always be loading the same scalar type
|
// Must always be loading the same scalar type
|
||||||
ScalarTypeDescr::Type elemType;
|
ScalarTypeDescr::Type elemType = elemPrediction.scalarType();
|
||||||
if (!elemDescrs.scalarType(&elemType))
|
|
||||||
return true;
|
|
||||||
JS_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
|
JS_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
|
||||||
|
|
||||||
bool canBeNeutered;
|
bool canBeNeutered;
|
||||||
MDefinition *indexAsByteOffset;
|
MDefinition *indexAsByteOffset;
|
||||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objDescrs,
|
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction,
|
||||||
&indexAsByteOffset, &canBeNeutered))
|
&indexAsByteOffset, &canBeNeutered))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -6927,32 +6922,32 @@ bool
|
|||||||
IonBuilder::getElemTryComplexElemOfTypedObject(bool *emitted,
|
IonBuilder::getElemTryComplexElemOfTypedObject(bool *emitted,
|
||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
MDefinition *index,
|
MDefinition *index,
|
||||||
TypeDescrSet objDescrs,
|
TypedObjectPrediction objPrediction,
|
||||||
TypeDescrSet elemDescrs,
|
TypedObjectPrediction elemPrediction,
|
||||||
int32_t elemSize)
|
int32_t elemSize)
|
||||||
{
|
{
|
||||||
JS_ASSERT(objDescrs.allOfArrayKind());
|
JS_ASSERT(objPrediction.ofArrayKind());
|
||||||
|
|
||||||
MDefinition *type = loadTypedObjectType(obj);
|
MDefinition *type = loadTypedObjectType(obj);
|
||||||
MDefinition *elemTypeObj = typeObjectForElementFromArrayStructType(type);
|
MDefinition *elemTypeObj = typeObjectForElementFromArrayStructType(type);
|
||||||
|
|
||||||
bool canBeNeutered;
|
bool canBeNeutered;
|
||||||
MDefinition *indexAsByteOffset;
|
MDefinition *indexAsByteOffset;
|
||||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objDescrs,
|
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction,
|
||||||
&indexAsByteOffset, &canBeNeutered))
|
&indexAsByteOffset, &canBeNeutered))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pushDerivedTypedObject(emitted, obj, indexAsByteOffset,
|
return pushDerivedTypedObject(emitted, obj, indexAsByteOffset,
|
||||||
elemDescrs, elemTypeObj, canBeNeutered);
|
elemPrediction, elemTypeObj, canBeNeutered);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IonBuilder::pushDerivedTypedObject(bool *emitted,
|
IonBuilder::pushDerivedTypedObject(bool *emitted,
|
||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
MDefinition *offset,
|
MDefinition *offset,
|
||||||
TypeDescrSet derivedTypeDescrs,
|
TypedObjectPrediction derivedPrediction,
|
||||||
MDefinition *derivedTypeObj,
|
MDefinition *derivedTypeObj,
|
||||||
bool canBeNeutered)
|
bool canBeNeutered)
|
||||||
{
|
{
|
||||||
@ -6962,7 +6957,7 @@ IonBuilder::pushDerivedTypedObject(bool *emitted,
|
|||||||
|
|
||||||
// Create the derived typed object.
|
// Create the derived typed object.
|
||||||
MInstruction *derivedTypedObj = MNewDerivedTypedObject::New(alloc(),
|
MInstruction *derivedTypedObj = MNewDerivedTypedObject::New(alloc(),
|
||||||
derivedTypeDescrs,
|
derivedPrediction,
|
||||||
derivedTypeObj,
|
derivedTypeObj,
|
||||||
owner,
|
owner,
|
||||||
ownerOffset);
|
ownerOffset);
|
||||||
@ -6976,7 +6971,7 @@ IonBuilder::pushDerivedTypedObject(bool *emitted,
|
|||||||
// determined based on the type descriptor (and is immutable).
|
// determined based on the type descriptor (and is immutable).
|
||||||
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
||||||
const Class *expectedClass = objTypes ? objTypes->getKnownClass() : nullptr;
|
const Class *expectedClass = objTypes ? objTypes->getKnownClass() : nullptr;
|
||||||
JSObject *expectedProto = derivedTypeDescrs.knownPrototype();
|
const TypedProto *expectedProto = derivedPrediction.getKnownPrototype();
|
||||||
JS_ASSERT_IF(expectedClass, IsTypedObjectClass(expectedClass));
|
JS_ASSERT_IF(expectedClass, IsTypedObjectClass(expectedClass));
|
||||||
|
|
||||||
// Determine (if possible) the class/proto that the observed type set
|
// Determine (if possible) the class/proto that the observed type set
|
||||||
@ -7663,26 +7658,24 @@ IonBuilder::setElemTryTypedObject(bool *emitted, MDefinition *obj,
|
|||||||
{
|
{
|
||||||
JS_ASSERT(*emitted == false);
|
JS_ASSERT(*emitted == false);
|
||||||
|
|
||||||
TypeDescrSet objTypeDescrs;
|
TypedObjectPrediction objPrediction = typedObjectPrediction(obj);
|
||||||
if (!lookupTypeDescrSet(obj, &objTypeDescrs))
|
if (objPrediction.isUseless())
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!objTypeDescrs.allOfArrayKind())
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
TypeDescrSet elemTypeDescrs;
|
if (!objPrediction.ofArrayKind())
|
||||||
if (!objTypeDescrs.arrayElementType(*this, &elemTypeDescrs))
|
|
||||||
return false;
|
|
||||||
if (elemTypeDescrs.empty())
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
JS_ASSERT(TypeDescr::isSized(elemTypeDescrs.kind()));
|
TypedObjectPrediction elemPrediction = objPrediction.arrayElementType();
|
||||||
|
if (elemPrediction.isUseless())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
JS_ASSERT(TypeDescr::isSized(elemPrediction.kind()));
|
||||||
|
|
||||||
int32_t elemSize;
|
int32_t elemSize;
|
||||||
if (!elemTypeDescrs.allHaveSameSize(&elemSize))
|
if (!elemPrediction.hasKnownSize(&elemSize))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
switch (elemTypeDescrs.kind()) {
|
switch (elemPrediction.kind()) {
|
||||||
case type::X4:
|
case type::X4:
|
||||||
// FIXME (bug 894105): store a MIRType_float32x4 etc
|
// FIXME (bug 894105): store a MIRType_float32x4 etc
|
||||||
return true;
|
return true;
|
||||||
@ -7698,9 +7691,9 @@ IonBuilder::setElemTryTypedObject(bool *emitted, MDefinition *obj,
|
|||||||
return setElemTryScalarElemOfTypedObject(emitted,
|
return setElemTryScalarElemOfTypedObject(emitted,
|
||||||
obj,
|
obj,
|
||||||
index,
|
index,
|
||||||
objTypeDescrs,
|
objPrediction,
|
||||||
value,
|
value,
|
||||||
elemTypeDescrs,
|
elemPrediction,
|
||||||
elemSize);
|
elemSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7711,20 +7704,18 @@ bool
|
|||||||
IonBuilder::setElemTryScalarElemOfTypedObject(bool *emitted,
|
IonBuilder::setElemTryScalarElemOfTypedObject(bool *emitted,
|
||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
MDefinition *index,
|
MDefinition *index,
|
||||||
TypeDescrSet objTypeDescrs,
|
TypedObjectPrediction objPrediction,
|
||||||
MDefinition *value,
|
MDefinition *value,
|
||||||
TypeDescrSet elemTypeDescrs,
|
TypedObjectPrediction elemPrediction,
|
||||||
int32_t elemSize)
|
int32_t elemSize)
|
||||||
{
|
{
|
||||||
// Must always be loading the same scalar type
|
// Must always be loading the same scalar type
|
||||||
ScalarTypeDescr::Type elemType;
|
ScalarTypeDescr::Type elemType = elemPrediction.scalarType();
|
||||||
if (!elemTypeDescrs.scalarType(&elemType))
|
|
||||||
return true;
|
|
||||||
JS_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
|
JS_ASSERT(elemSize == ScalarTypeDescr::alignment(elemType));
|
||||||
|
|
||||||
bool canBeNeutered;
|
bool canBeNeutered;
|
||||||
MDefinition *indexAsByteOffset;
|
MDefinition *indexAsByteOffset;
|
||||||
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objTypeDescrs,
|
if (!checkTypedObjectIndexInBounds(elemSize, obj, index, objPrediction,
|
||||||
&indexAsByteOffset, &canBeNeutered))
|
&indexAsByteOffset, &canBeNeutered))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -8696,18 +8687,18 @@ IonBuilder::getPropTryConstant(bool *emitted, MDefinition *obj, PropertyName *na
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IonBuilder::getPropTryTypedObject(bool *emitted, MDefinition *obj, PropertyName *name,
|
IonBuilder::getPropTryTypedObject(bool *emitted,
|
||||||
|
MDefinition *obj,
|
||||||
|
PropertyName *name,
|
||||||
types::TemporaryTypeSet *resultTypes)
|
types::TemporaryTypeSet *resultTypes)
|
||||||
{
|
{
|
||||||
TypeDescrSet fieldDescrs;
|
TypedObjectPrediction fieldPrediction;
|
||||||
int32_t fieldOffset;
|
int32_t fieldOffset;
|
||||||
size_t fieldIndex;
|
size_t fieldIndex;
|
||||||
if (!lookupTypedObjectField(obj, name, &fieldOffset, &fieldDescrs, &fieldIndex))
|
if (!typedObjectHasField(obj, name, &fieldOffset, &fieldPrediction, &fieldIndex))
|
||||||
return false;
|
|
||||||
if (fieldDescrs.empty())
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
switch (fieldDescrs.kind()) {
|
switch (fieldPrediction.kind()) {
|
||||||
case type::Reference:
|
case type::Reference:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -8720,7 +8711,7 @@ IonBuilder::getPropTryTypedObject(bool *emitted, MDefinition *obj, PropertyName
|
|||||||
return getPropTryComplexPropOfTypedObject(emitted,
|
return getPropTryComplexPropOfTypedObject(emitted,
|
||||||
obj,
|
obj,
|
||||||
fieldOffset,
|
fieldOffset,
|
||||||
fieldDescrs,
|
fieldPrediction,
|
||||||
fieldIndex,
|
fieldIndex,
|
||||||
resultTypes);
|
resultTypes);
|
||||||
|
|
||||||
@ -8728,7 +8719,7 @@ IonBuilder::getPropTryTypedObject(bool *emitted, MDefinition *obj, PropertyName
|
|||||||
return getPropTryScalarPropOfTypedObject(emitted,
|
return getPropTryScalarPropOfTypedObject(emitted,
|
||||||
obj,
|
obj,
|
||||||
fieldOffset,
|
fieldOffset,
|
||||||
fieldDescrs,
|
fieldPrediction,
|
||||||
resultTypes);
|
resultTypes);
|
||||||
|
|
||||||
case type::UnsizedArray:
|
case type::UnsizedArray:
|
||||||
@ -8741,13 +8732,11 @@ IonBuilder::getPropTryTypedObject(bool *emitted, MDefinition *obj, PropertyName
|
|||||||
bool
|
bool
|
||||||
IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted, MDefinition *typedObj,
|
IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted, MDefinition *typedObj,
|
||||||
int32_t fieldOffset,
|
int32_t fieldOffset,
|
||||||
TypeDescrSet fieldDescrs,
|
TypedObjectPrediction fieldPrediction,
|
||||||
types::TemporaryTypeSet *resultTypes)
|
types::TemporaryTypeSet *resultTypes)
|
||||||
{
|
{
|
||||||
// Must always be loading the same scalar type.
|
// Must always be loading the same scalar type
|
||||||
ScalarTypeDescr::Type fieldType;
|
ScalarTypeDescr::Type fieldType = fieldPrediction.scalarType();
|
||||||
if (!fieldDescrs.scalarType(&fieldType))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// OK, perform the optimization.
|
// OK, perform the optimization.
|
||||||
return pushScalarLoadFromTypedObject(emitted, typedObj, constantInt(fieldOffset),
|
return pushScalarLoadFromTypedObject(emitted, typedObj, constantInt(fieldOffset),
|
||||||
@ -8755,17 +8744,13 @@ IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted, MDefinition *typedO
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted, MDefinition *typedObj,
|
IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
|
||||||
|
MDefinition *typedObj,
|
||||||
int32_t fieldOffset,
|
int32_t fieldOffset,
|
||||||
TypeDescrSet fieldDescrs,
|
TypedObjectPrediction fieldPrediction,
|
||||||
size_t fieldIndex,
|
size_t fieldIndex,
|
||||||
types::TemporaryTypeSet *resultTypes)
|
types::TemporaryTypeSet *resultTypes)
|
||||||
{
|
{
|
||||||
// Must know the field index so that we can load the new type
|
|
||||||
// object for the derived value
|
|
||||||
if (fieldIndex == SIZE_MAX)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// OK, perform the optimization
|
// OK, perform the optimization
|
||||||
|
|
||||||
// Identify the type object for the field.
|
// Identify the type object for the field.
|
||||||
@ -8773,7 +8758,7 @@ IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted, MDefinition *typed
|
|||||||
MDefinition *fieldTypeObj = typeObjectForFieldFromStructType(type, fieldIndex);
|
MDefinition *fieldTypeObj = typeObjectForFieldFromStructType(type, fieldIndex);
|
||||||
|
|
||||||
return pushDerivedTypedObject(emitted, typedObj, constantInt(fieldOffset),
|
return pushDerivedTypedObject(emitted, typedObj, constantInt(fieldOffset),
|
||||||
fieldDescrs, fieldTypeObj, true);
|
fieldPrediction, fieldTypeObj, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -9352,16 +9337,13 @@ bool
|
|||||||
IonBuilder::setPropTryTypedObject(bool *emitted, MDefinition *obj,
|
IonBuilder::setPropTryTypedObject(bool *emitted, MDefinition *obj,
|
||||||
PropertyName *name, MDefinition *value)
|
PropertyName *name, MDefinition *value)
|
||||||
{
|
{
|
||||||
TypeDescrSet fieldDescrs;
|
TypedObjectPrediction fieldPrediction;
|
||||||
int32_t fieldOffset;
|
int32_t fieldOffset;
|
||||||
size_t fieldIndex;
|
size_t fieldIndex;
|
||||||
if (!lookupTypedObjectField(obj, name, &fieldOffset, &fieldDescrs,
|
if (!typedObjectHasField(obj, name, &fieldOffset, &fieldPrediction, &fieldIndex))
|
||||||
&fieldIndex))
|
|
||||||
return false;
|
|
||||||
if (fieldDescrs.empty())
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
switch (fieldDescrs.kind()) {
|
switch (fieldPrediction.kind()) {
|
||||||
case type::X4:
|
case type::X4:
|
||||||
// FIXME (bug 894104): store into a MIRType_float32x4 etc
|
// FIXME (bug 894104): store into a MIRType_float32x4 etc
|
||||||
return true;
|
return true;
|
||||||
@ -9375,7 +9357,7 @@ IonBuilder::setPropTryTypedObject(bool *emitted, MDefinition *obj,
|
|||||||
|
|
||||||
case type::Scalar:
|
case type::Scalar:
|
||||||
return setPropTryScalarPropOfTypedObject(emitted, obj, fieldOffset,
|
return setPropTryScalarPropOfTypedObject(emitted, obj, fieldOffset,
|
||||||
value, fieldDescrs);
|
value, fieldPrediction);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_ASSUME_UNREACHABLE("Unknown kind");
|
MOZ_ASSUME_UNREACHABLE("Unknown kind");
|
||||||
@ -9386,12 +9368,10 @@ IonBuilder::setPropTryScalarPropOfTypedObject(bool *emitted,
|
|||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
int32_t fieldOffset,
|
int32_t fieldOffset,
|
||||||
MDefinition *value,
|
MDefinition *value,
|
||||||
TypeDescrSet fieldDescrs)
|
TypedObjectPrediction fieldPrediction)
|
||||||
{
|
{
|
||||||
// Must always be loading the same scalar type
|
// Must always be loading the same scalar type
|
||||||
ScalarTypeDescr::Type fieldType;
|
ScalarTypeDescr::Type fieldType = fieldPrediction.scalarType();
|
||||||
if (!fieldDescrs.scalarType(&fieldType))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// OK! Perform the optimization.
|
// OK! Perform the optimization.
|
||||||
|
|
||||||
@ -10220,56 +10200,37 @@ IonBuilder::bytecodeTypes(jsbytecode *pc)
|
|||||||
return types::TypeScript::BytecodeTypes(script(), pc, bytecodeTypeMap, &typeArrayHint, typeArray);
|
return types::TypeScript::BytecodeTypes(script(), pc, bytecodeTypeMap, &typeArrayHint, typeArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDescrSetHash *
|
TypedObjectPrediction
|
||||||
IonBuilder::getOrCreateDescrSetHash()
|
IonBuilder::typedObjectPrediction(MDefinition *typedObj)
|
||||||
{
|
{
|
||||||
if (!descrSetHash_) {
|
// Extract TypedObjectPrediction directly if we can
|
||||||
TypeDescrSetHash *hash =
|
|
||||||
alloc_->lifoAlloc()->new_<TypeDescrSetHash>(alloc());
|
|
||||||
if (!hash || !hash->init())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
descrSetHash_ = hash;
|
|
||||||
}
|
|
||||||
return descrSetHash_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
IonBuilder::lookupTypeDescrSet(MDefinition *typedObj,
|
|
||||||
TypeDescrSet *out)
|
|
||||||
{
|
|
||||||
*out = TypeDescrSet(); // default to unknown
|
|
||||||
|
|
||||||
// Extract TypeDescrSet directly if we can
|
|
||||||
if (typedObj->isNewDerivedTypedObject()) {
|
if (typedObj->isNewDerivedTypedObject()) {
|
||||||
*out = typedObj->toNewDerivedTypedObject()->set();
|
return typedObj->toNewDerivedTypedObject()->prediction();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
types::TemporaryTypeSet *types = typedObj->resultTypeSet();
|
types::TemporaryTypeSet *types = typedObj->resultTypeSet();
|
||||||
return typeSetToTypeDescrSet(types, out);
|
return typedObjectPrediction(types);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
TypedObjectPrediction
|
||||||
IonBuilder::typeSetToTypeDescrSet(types::TemporaryTypeSet *types,
|
IonBuilder::typedObjectPrediction(types::TemporaryTypeSet *types)
|
||||||
TypeDescrSet *out)
|
|
||||||
{
|
{
|
||||||
// Extract TypeDescrSet directly if we can
|
// Type set must be known to be an object.
|
||||||
if (!types || types->getKnownMIRType() != MIRType_Object)
|
if (!types || types->getKnownMIRType() != MIRType_Object)
|
||||||
return true;
|
return TypedObjectPrediction();
|
||||||
|
|
||||||
// And only known objects.
|
// And only known objects.
|
||||||
if (types->unknownObject())
|
if (types->unknownObject())
|
||||||
return true;
|
return TypedObjectPrediction();
|
||||||
|
|
||||||
TypeDescrSetBuilder set;
|
TypedObjectPrediction out;
|
||||||
for (uint32_t i = 0; i < types->getObjectCount(); i++) {
|
for (uint32_t i = 0; i < types->getObjectCount(); i++) {
|
||||||
types::TypeObject *type = types->getTypeObject(i);
|
types::TypeObject *type = types->getTypeObject(i);
|
||||||
if (!type)
|
if (!type || type->unknownProperties())
|
||||||
return true;
|
return TypedObjectPrediction();
|
||||||
|
|
||||||
if (!IsTypedObjectClass(type->clasp()))
|
if (!IsTypedObjectClass(type->clasp()))
|
||||||
return true;
|
return TypedObjectPrediction();
|
||||||
|
|
||||||
TaggedProto proto = type->proto();
|
TaggedProto proto = type->proto();
|
||||||
|
|
||||||
@ -10278,11 +10239,10 @@ IonBuilder::typeSetToTypeDescrSet(types::TemporaryTypeSet *types,
|
|||||||
JS_ASSERT(proto.isObject() && proto.toObject()->is<TypedProto>());
|
JS_ASSERT(proto.isObject() && proto.toObject()->is<TypedProto>());
|
||||||
|
|
||||||
TypedProto &typedProto = proto.toObject()->as<TypedProto>();
|
TypedProto &typedProto = proto.toObject()->as<TypedProto>();
|
||||||
if (!set.insert(&typedProto.typeDescr()))
|
out.addProto(typedProto);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return set.build(*this, out);
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
MDefinition *
|
MDefinition *
|
||||||
@ -10388,36 +10348,27 @@ IonBuilder::loadTypedObjectElements(MDefinition *typedObj,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Looks up the offset/type-repr-set of the field `id`, given the type
|
// Looks up the offset/type-repr-set of the field `id`, given the type
|
||||||
// set `objTypes` of the field owner. Note that even when true is
|
// set `objTypes` of the field owner. If a field is found, returns true
|
||||||
// returned, `*fieldDescrs` might be empty if no useful type/offset
|
// and sets *fieldOffset, *fieldPrediction, and *fieldIndex. Returns false
|
||||||
// pair could be determined.
|
// otherwise. Infallible.
|
||||||
bool
|
bool
|
||||||
IonBuilder::lookupTypedObjectField(MDefinition *typedObj,
|
IonBuilder::typedObjectHasField(MDefinition *typedObj,
|
||||||
PropertyName *name,
|
PropertyName *name,
|
||||||
int32_t *fieldOffset,
|
int32_t *fieldOffset,
|
||||||
TypeDescrSet *fieldDescrs,
|
TypedObjectPrediction *fieldPrediction,
|
||||||
size_t *fieldIndex)
|
size_t *fieldIndex)
|
||||||
{
|
{
|
||||||
TypeDescrSet objDescrs;
|
TypedObjectPrediction objPrediction = typedObjectPrediction(typedObj);
|
||||||
if (!lookupTypeDescrSet(typedObj, &objDescrs))
|
if (objPrediction.isUseless())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Must be accessing a struct.
|
// Must be accessing a struct.
|
||||||
if (!objDescrs.allOfKind(type::Struct))
|
if (objPrediction.kind() != type::Struct)
|
||||||
return true;
|
return false;
|
||||||
|
|
||||||
// Determine the type/offset of the field `name`, if any.
|
// Determine the type/offset of the field `name`, if any.
|
||||||
int32_t offset;
|
return objPrediction.hasFieldNamed(NameToId(name), fieldOffset,
|
||||||
if (!objDescrs.fieldNamed(*this, NameToId(name), &offset,
|
fieldPrediction, fieldIndex);
|
||||||
fieldDescrs, fieldIndex))
|
|
||||||
return false;
|
|
||||||
if (fieldDescrs->empty())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
JS_ASSERT(offset >= 0);
|
|
||||||
*fieldOffset = offset;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MDefinition *
|
MDefinition *
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#include "jit/MIR.h"
|
#include "jit/MIR.h"
|
||||||
#include "jit/MIRGenerator.h"
|
#include "jit/MIRGenerator.h"
|
||||||
#include "jit/MIRGraph.h"
|
#include "jit/MIRGraph.h"
|
||||||
#include "jit/TypeDescrSet.h"
|
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
namespace jit {
|
namespace jit {
|
||||||
@ -413,11 +412,11 @@ class IonBuilder : public MIRGenerator
|
|||||||
types::TemporaryTypeSet *resultTypes);
|
types::TemporaryTypeSet *resultTypes);
|
||||||
bool getPropTryScalarPropOfTypedObject(bool *emitted, MDefinition *typedObj,
|
bool getPropTryScalarPropOfTypedObject(bool *emitted, MDefinition *typedObj,
|
||||||
int32_t fieldOffset,
|
int32_t fieldOffset,
|
||||||
TypeDescrSet fieldTypeReprs,
|
TypedObjectPrediction fieldTypeReprs,
|
||||||
types::TemporaryTypeSet *resultTypes);
|
types::TemporaryTypeSet *resultTypes);
|
||||||
bool getPropTryComplexPropOfTypedObject(bool *emitted, MDefinition *typedObj,
|
bool getPropTryComplexPropOfTypedObject(bool *emitted, MDefinition *typedObj,
|
||||||
int32_t fieldOffset,
|
int32_t fieldOffset,
|
||||||
TypeDescrSet fieldTypeReprs,
|
TypedObjectPrediction fieldTypeReprs,
|
||||||
size_t fieldIndex,
|
size_t fieldIndex,
|
||||||
types::TemporaryTypeSet *resultTypes);
|
types::TemporaryTypeSet *resultTypes);
|
||||||
bool getPropTryInnerize(bool *emitted, MDefinition *obj, PropertyName *name,
|
bool getPropTryInnerize(bool *emitted, MDefinition *obj, PropertyName *name,
|
||||||
@ -444,21 +443,19 @@ class IonBuilder : public MIRGenerator
|
|||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
int32_t fieldOffset,
|
int32_t fieldOffset,
|
||||||
MDefinition *value,
|
MDefinition *value,
|
||||||
TypeDescrSet fieldTypeReprs);
|
TypedObjectPrediction fieldTypeReprs);
|
||||||
bool setPropTryCache(bool *emitted, MDefinition *obj,
|
bool setPropTryCache(bool *emitted, MDefinition *obj,
|
||||||
PropertyName *name, MDefinition *value,
|
PropertyName *name, MDefinition *value,
|
||||||
bool barrier, types::TemporaryTypeSet *objTypes);
|
bool barrier, types::TemporaryTypeSet *objTypes);
|
||||||
|
|
||||||
// binary data lookup helpers.
|
// binary data lookup helpers.
|
||||||
bool lookupTypeDescrSet(MDefinition *typedObj,
|
TypedObjectPrediction typedObjectPrediction(MDefinition *typedObj);
|
||||||
TypeDescrSet *out);
|
TypedObjectPrediction typedObjectPrediction(types::TemporaryTypeSet *types);
|
||||||
bool typeSetToTypeDescrSet(types::TemporaryTypeSet *types,
|
bool typedObjectHasField(MDefinition *typedObj,
|
||||||
TypeDescrSet *out);
|
PropertyName *name,
|
||||||
bool lookupTypedObjectField(MDefinition *typedObj,
|
int32_t *fieldOffset,
|
||||||
PropertyName *name,
|
TypedObjectPrediction *fieldTypeReprs,
|
||||||
int32_t *fieldOffset,
|
size_t *fieldIndex);
|
||||||
TypeDescrSet *fieldTypeReprs,
|
|
||||||
size_t *fieldIndex);
|
|
||||||
MDefinition *loadTypedObjectType(MDefinition *value);
|
MDefinition *loadTypedObjectType(MDefinition *value);
|
||||||
void loadTypedObjectData(MDefinition *typedObj,
|
void loadTypedObjectData(MDefinition *typedObj,
|
||||||
MDefinition *offset,
|
MDefinition *offset,
|
||||||
@ -483,13 +480,13 @@ class IonBuilder : public MIRGenerator
|
|||||||
bool checkTypedObjectIndexInBounds(int32_t elemSize,
|
bool checkTypedObjectIndexInBounds(int32_t elemSize,
|
||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
MDefinition *index,
|
MDefinition *index,
|
||||||
TypeDescrSet objTypeDescrs,
|
TypedObjectPrediction objTypeDescrs,
|
||||||
MDefinition **indexAsByteOffset,
|
MDefinition **indexAsByteOffset,
|
||||||
bool *canBeNeutered);
|
bool *canBeNeutered);
|
||||||
bool pushDerivedTypedObject(bool *emitted,
|
bool pushDerivedTypedObject(bool *emitted,
|
||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
MDefinition *offset,
|
MDefinition *offset,
|
||||||
TypeDescrSet derivedTypeDescrs,
|
TypedObjectPrediction derivedTypeDescrs,
|
||||||
MDefinition *derivedTypeObj,
|
MDefinition *derivedTypeObj,
|
||||||
bool canBeNeutered);
|
bool canBeNeutered);
|
||||||
bool pushScalarLoadFromTypedObject(bool *emitted,
|
bool pushScalarLoadFromTypedObject(bool *emitted,
|
||||||
@ -515,9 +512,9 @@ class IonBuilder : public MIRGenerator
|
|||||||
bool setElemTryScalarElemOfTypedObject(bool *emitted,
|
bool setElemTryScalarElemOfTypedObject(bool *emitted,
|
||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
MDefinition *index,
|
MDefinition *index,
|
||||||
TypeDescrSet objTypeReprs,
|
TypedObjectPrediction objTypeReprs,
|
||||||
MDefinition *value,
|
MDefinition *value,
|
||||||
TypeDescrSet elemTypeReprs,
|
TypedObjectPrediction elemTypeReprs,
|
||||||
int32_t elemSize);
|
int32_t elemSize);
|
||||||
|
|
||||||
// jsop_getelem() helpers.
|
// jsop_getelem() helpers.
|
||||||
@ -532,14 +529,14 @@ class IonBuilder : public MIRGenerator
|
|||||||
bool getElemTryScalarElemOfTypedObject(bool *emitted,
|
bool getElemTryScalarElemOfTypedObject(bool *emitted,
|
||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
MDefinition *index,
|
MDefinition *index,
|
||||||
TypeDescrSet objTypeReprs,
|
TypedObjectPrediction objTypeReprs,
|
||||||
TypeDescrSet elemTypeReprs,
|
TypedObjectPrediction elemTypeReprs,
|
||||||
int32_t elemSize);
|
int32_t elemSize);
|
||||||
bool getElemTryComplexElemOfTypedObject(bool *emitted,
|
bool getElemTryComplexElemOfTypedObject(bool *emitted,
|
||||||
MDefinition *obj,
|
MDefinition *obj,
|
||||||
MDefinition *index,
|
MDefinition *index,
|
||||||
TypeDescrSet objTypeReprs,
|
TypedObjectPrediction objTypeReprs,
|
||||||
TypeDescrSet elemTypeReprs,
|
TypedObjectPrediction elemTypeReprs,
|
||||||
int32_t elemSize);
|
int32_t elemSize);
|
||||||
|
|
||||||
enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck };
|
enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck };
|
||||||
@ -839,8 +836,6 @@ class IonBuilder : public MIRGenerator
|
|||||||
CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; }
|
CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; }
|
||||||
void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; }
|
void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; }
|
||||||
|
|
||||||
TypeDescrSetHash *getOrCreateDescrSetHash(); // fallible
|
|
||||||
|
|
||||||
types::CompilerConstraintList *constraints() {
|
types::CompilerConstraintList *constraints() {
|
||||||
return constraints_;
|
return constraints_;
|
||||||
}
|
}
|
||||||
@ -856,7 +851,6 @@ class IonBuilder : public MIRGenerator
|
|||||||
|
|
||||||
JSContext *analysisContext;
|
JSContext *analysisContext;
|
||||||
BaselineFrameInspector *baselineFrame_;
|
BaselineFrameInspector *baselineFrame_;
|
||||||
TypeDescrSetHash *descrSetHash_;
|
|
||||||
|
|
||||||
// Constraints for recording dependencies on type information.
|
// Constraints for recording dependencies on type information.
|
||||||
types::CompilerConstraintList *constraints_;
|
types::CompilerConstraintList *constraints_;
|
||||||
|
@ -1449,23 +1449,17 @@ IonBuilder::elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefin
|
|||||||
if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
|
if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
TypeDescrSet objDescrs;
|
TypedObjectPrediction prediction = typedObjectPrediction(obj);
|
||||||
if (!lookupTypeDescrSet(obj, &objDescrs))
|
if (prediction.isUseless() || !prediction.ofArrayKind())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!objDescrs.allOfArrayKind())
|
TypedObjectPrediction elemPrediction = prediction.arrayElementType();
|
||||||
|
if (elemPrediction.isUseless() || elemPrediction.kind() != type::Scalar)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
TypeDescrSet elemDescrs;
|
JS_ASSERT(type::isSized(elemPrediction.kind()));
|
||||||
if (!objDescrs.arrayElementType(*this, &elemDescrs))
|
*arrayType = elemPrediction.scalarType();
|
||||||
return false;
|
return true;
|
||||||
|
|
||||||
if (elemDescrs.empty() || elemDescrs.kind() != type::Scalar)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
JS_ASSERT(TypeDescr::isSized(elemDescrs.kind()));
|
|
||||||
|
|
||||||
return elemDescrs.scalarType(arrayType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include "jit/IonAllocPolicy.h"
|
#include "jit/IonAllocPolicy.h"
|
||||||
#include "jit/IonMacroAssembler.h"
|
#include "jit/IonMacroAssembler.h"
|
||||||
#include "jit/MOpcodes.h"
|
#include "jit/MOpcodes.h"
|
||||||
#include "jit/TypeDescrSet.h"
|
#include "jit/TypedObjectPrediction.h"
|
||||||
#include "jit/TypePolicy.h"
|
#include "jit/TypePolicy.h"
|
||||||
#include "vm/ScopeObject.h"
|
#include "vm/ScopeObject.h"
|
||||||
#include "vm/TypedArrayObject.h"
|
#include "vm/TypedArrayObject.h"
|
||||||
@ -1769,14 +1769,14 @@ class MNewDerivedTypedObject
|
|||||||
IntPolicy<2> >
|
IntPolicy<2> >
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
TypeDescrSet set_;
|
TypedObjectPrediction prediction_;
|
||||||
|
|
||||||
MNewDerivedTypedObject(TypeDescrSet set,
|
MNewDerivedTypedObject(TypedObjectPrediction prediction,
|
||||||
MDefinition *type,
|
MDefinition *type,
|
||||||
MDefinition *owner,
|
MDefinition *owner,
|
||||||
MDefinition *offset)
|
MDefinition *offset)
|
||||||
: MTernaryInstruction(type, owner, offset),
|
: MTernaryInstruction(type, owner, offset),
|
||||||
set_(set)
|
prediction_(prediction)
|
||||||
{
|
{
|
||||||
setMovable();
|
setMovable();
|
||||||
setResultType(MIRType_Object);
|
setResultType(MIRType_Object);
|
||||||
@ -1785,14 +1785,14 @@ class MNewDerivedTypedObject
|
|||||||
public:
|
public:
|
||||||
INSTRUCTION_HEADER(NewDerivedTypedObject);
|
INSTRUCTION_HEADER(NewDerivedTypedObject);
|
||||||
|
|
||||||
static MNewDerivedTypedObject *New(TempAllocator &alloc, TypeDescrSet set,
|
static MNewDerivedTypedObject *New(TempAllocator &alloc, TypedObjectPrediction prediction,
|
||||||
MDefinition *type, MDefinition *owner, MDefinition *offset)
|
MDefinition *type, MDefinition *owner, MDefinition *offset)
|
||||||
{
|
{
|
||||||
return new(alloc) MNewDerivedTypedObject(set, type, owner, offset);
|
return new(alloc) MNewDerivedTypedObject(prediction, type, owner, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDescrSet set() const {
|
TypedObjectPrediction prediction() const {
|
||||||
return set_;
|
return prediction_;
|
||||||
}
|
}
|
||||||
|
|
||||||
MDefinition *type() const {
|
MDefinition *type() const {
|
||||||
|
@ -1,373 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
||||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#include "jit/TypeDescrSet.h"
|
|
||||||
|
|
||||||
#include "mozilla/HashFunctions.h"
|
|
||||||
|
|
||||||
#include "builtin/TypedObject.h"
|
|
||||||
#include "jit/IonBuilder.h"
|
|
||||||
|
|
||||||
using namespace js;
|
|
||||||
using namespace jit;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// TypeDescrSet hasher
|
|
||||||
|
|
||||||
HashNumber
|
|
||||||
TypeDescrSetHasher::hash(TypeDescrSet key)
|
|
||||||
{
|
|
||||||
HashNumber hn = mozilla::HashGeneric(key.length());
|
|
||||||
for (size_t i = 0; i < key.length(); i++)
|
|
||||||
hn = mozilla::AddToHash(hn, uintptr_t(key.get(i)));
|
|
||||||
return hn;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSetHasher::match(TypeDescrSet key1, TypeDescrSet key2)
|
|
||||||
{
|
|
||||||
if (key1.length() != key2.length())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Note: entries are always sorted
|
|
||||||
for (size_t i = 0; i < key1.length(); i++) {
|
|
||||||
if (key1.get(i) != key2.get(i))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// TypeDescrSetBuilder
|
|
||||||
|
|
||||||
TypeDescrSetBuilder::TypeDescrSetBuilder()
|
|
||||||
: invalid_(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSetBuilder::insert(TypeDescr *descr)
|
|
||||||
{
|
|
||||||
// All type descriptors should be tenured, so it is safe to assume
|
|
||||||
// that the pointers do not change during compilation, since no
|
|
||||||
// major GC can overlap with compilation.
|
|
||||||
JS_ASSERT(!GetIonContext()->runtime->isInsideNursery(descr));
|
|
||||||
|
|
||||||
if (invalid_)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (entries_.empty())
|
|
||||||
return entries_.append(descr);
|
|
||||||
|
|
||||||
// Check that this new type repr is of the same basic kind as the
|
|
||||||
// ones we have seen thus far. If not, for example if we have an
|
|
||||||
// `int` and a `struct`, then convert this set to the invalid set.
|
|
||||||
TypeDescr *entry0 = entries_[0];
|
|
||||||
if (descr->kind() != entry0->kind()) {
|
|
||||||
invalid_ = true;
|
|
||||||
entries_.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, use binary search to find the right place to insert
|
|
||||||
// the TypeDescr. We keep the list sorted by the *address* of
|
|
||||||
// the TypeDescrs within.
|
|
||||||
uintptr_t descrAddr = (uintptr_t) descr;
|
|
||||||
size_t min = 0;
|
|
||||||
size_t max = entries_.length();
|
|
||||||
while (min != max) {
|
|
||||||
size_t i = min + ((max - min) >> 1); // average w/o fear of overflow
|
|
||||||
|
|
||||||
uintptr_t entryiaddr = (uintptr_t) entries_[i];
|
|
||||||
if (entryiaddr == descrAddr)
|
|
||||||
return true; // descr already present in the set
|
|
||||||
|
|
||||||
if (entryiaddr < descrAddr) {
|
|
||||||
// descr lies to the right of entry i
|
|
||||||
min = i + 1;
|
|
||||||
} else {
|
|
||||||
// descr lies to the left of entry i
|
|
||||||
max = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// As a sanity check, give up if the TypeDescrSet grows too large.
|
|
||||||
if (entries_.length() >= 512) {
|
|
||||||
invalid_ = true;
|
|
||||||
entries_.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not present. Insert at position `min`.
|
|
||||||
if (min == entries_.length())
|
|
||||||
return entries_.append(descr);
|
|
||||||
TypeDescr **insertLoc = &entries_[min];
|
|
||||||
return entries_.insert(insertLoc, descr) != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSetBuilder::build(IonBuilder &builder, TypeDescrSet *out)
|
|
||||||
{
|
|
||||||
if (invalid_) {
|
|
||||||
*out = TypeDescrSet();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeDescrSetHash *table = builder.getOrCreateDescrSetHash();
|
|
||||||
if (!table)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check if there is already a copy in the hashtable.
|
|
||||||
size_t length = entries_.length();
|
|
||||||
TypeDescrSet tempSet(length, entries_.begin());
|
|
||||||
TypeDescrSetHash::AddPtr p = table->lookupForAdd(tempSet);
|
|
||||||
if (p) {
|
|
||||||
*out = *p;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not, allocate a permanent copy in Ion temp memory and add it.
|
|
||||||
size_t space = sizeof(TypeDescr*) * length;
|
|
||||||
TypeDescr **array = (TypeDescr**)
|
|
||||||
GetIonContext()->temp->allocate(space);
|
|
||||||
if (!array)
|
|
||||||
return false;
|
|
||||||
memcpy(array, entries_.begin(), space);
|
|
||||||
TypeDescrSet permSet(length, array);
|
|
||||||
if (!table->add(p, permSet))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*out = permSet;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// TypeDescrSet
|
|
||||||
|
|
||||||
TypeDescrSet::TypeDescrSet(const TypeDescrSet &c)
|
|
||||||
: length_(c.length_),
|
|
||||||
entries_(c.entries_)
|
|
||||||
{}
|
|
||||||
|
|
||||||
TypeDescrSet::TypeDescrSet(size_t length,
|
|
||||||
TypeDescr **entries)
|
|
||||||
: length_(length),
|
|
||||||
entries_(entries)
|
|
||||||
{}
|
|
||||||
|
|
||||||
TypeDescrSet::TypeDescrSet()
|
|
||||||
: length_(0),
|
|
||||||
entries_(nullptr)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSet::empty() const
|
|
||||||
{
|
|
||||||
return length_ == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSet::allOfArrayKind()
|
|
||||||
{
|
|
||||||
if (empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
switch (kind()) {
|
|
||||||
case type::SizedArray:
|
|
||||||
case type::UnsizedArray:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case type::X4:
|
|
||||||
case type::Reference:
|
|
||||||
case type::Scalar:
|
|
||||||
case type::Struct:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSUME_UNREACHABLE("Invalid kind() in TypeDescrSet");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSet::allOfKind(type::Kind aKind)
|
|
||||||
{
|
|
||||||
if (empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return kind() == aKind;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSet::allHaveSameSize(int32_t *out)
|
|
||||||
{
|
|
||||||
if (empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
JS_ASSERT(TypeDescr::isSized(kind()));
|
|
||||||
|
|
||||||
int32_t size = get(0)->as<SizedTypeDescr>().size();
|
|
||||||
for (size_t i = 1; i < length(); i++) {
|
|
||||||
if (get(i)->as<SizedTypeDescr>().size() != size)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out = size;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
JSObject *
|
|
||||||
TypeDescrSet::knownPrototype() const
|
|
||||||
{
|
|
||||||
JS_ASSERT(!empty());
|
|
||||||
if (length() > 1 || !get(0)->is<ComplexTypeDescr>())
|
|
||||||
return nullptr;
|
|
||||||
return &get(0)->as<ComplexTypeDescr>().instancePrototype();
|
|
||||||
}
|
|
||||||
|
|
||||||
type::Kind
|
|
||||||
TypeDescrSet::kind()
|
|
||||||
{
|
|
||||||
JS_ASSERT(!empty());
|
|
||||||
return get(0)->kind();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool
|
|
||||||
TypeDescrSet::genericType(typename T::Type *out)
|
|
||||||
{
|
|
||||||
JS_ASSERT(allOfKind(type::Scalar));
|
|
||||||
|
|
||||||
typename T::Type type = get(0)->as<T>().type();
|
|
||||||
for (size_t i = 1; i < length(); i++) {
|
|
||||||
if (get(i)->as<T>().type() != type)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out = type;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSet::scalarType(ScalarTypeDescr::Type *out)
|
|
||||||
{
|
|
||||||
return genericType<ScalarTypeDescr>(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSet::referenceType(ReferenceTypeDescr::Type *out)
|
|
||||||
{
|
|
||||||
return genericType<ReferenceTypeDescr>(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSet::x4Type(X4TypeDescr::Type *out)
|
|
||||||
{
|
|
||||||
return genericType<X4TypeDescr>(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSet::hasKnownArrayLength(int32_t *l)
|
|
||||||
{
|
|
||||||
switch (kind()) {
|
|
||||||
case type::UnsizedArray:
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case type::SizedArray:
|
|
||||||
{
|
|
||||||
const size_t result = get(0)->as<SizedArrayTypeDescr>().length();
|
|
||||||
for (size_t i = 1; i < length(); i++) {
|
|
||||||
size_t l = get(i)->as<SizedArrayTypeDescr>().length();
|
|
||||||
if (l != result)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*l = result;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
MOZ_ASSUME_UNREACHABLE("Invalid array size for call to arrayLength()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSet::arrayElementType(IonBuilder &builder, TypeDescrSet *out)
|
|
||||||
{
|
|
||||||
TypeDescrSetBuilder elementTypes;
|
|
||||||
for (size_t i = 0; i < length(); i++) {
|
|
||||||
switch (kind()) {
|
|
||||||
case type::UnsizedArray:
|
|
||||||
if (!elementTypes.insert(&get(i)->as<UnsizedArrayTypeDescr>().elementType()))
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case type::SizedArray:
|
|
||||||
if (!elementTypes.insert(&get(i)->as<SizedArrayTypeDescr>().elementType()))
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
MOZ_ASSUME_UNREACHABLE("Invalid kind for arrayElementType()");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return elementTypes.build(builder, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
TypeDescrSet::fieldNamed(IonBuilder &builder,
|
|
||||||
jsid id,
|
|
||||||
int32_t *offset,
|
|
||||||
TypeDescrSet *out,
|
|
||||||
size_t *index)
|
|
||||||
{
|
|
||||||
JS_ASSERT(kind() == type::Struct);
|
|
||||||
|
|
||||||
// Initialize `*offset` and `*out` for the case where incompatible
|
|
||||||
// or absent fields are found.
|
|
||||||
*offset = -1;
|
|
||||||
*index = SIZE_MAX;
|
|
||||||
*out = TypeDescrSet();
|
|
||||||
|
|
||||||
// Remember offset of the first field.
|
|
||||||
int32_t offset0;
|
|
||||||
size_t index0;
|
|
||||||
TypeDescrSetBuilder fieldTypes;
|
|
||||||
{
|
|
||||||
StructTypeDescr &descr0 = get(0)->as<StructTypeDescr>();
|
|
||||||
if (!descr0.fieldIndex(id, &index0))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
offset0 = descr0.fieldOffset(index0);
|
|
||||||
if (!fieldTypes.insert(&descr0.fieldDescr(index0)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that all subsequent fields are at the same offset
|
|
||||||
// and compute the union of their types.
|
|
||||||
for (size_t i = 1; i < length(); i++) {
|
|
||||||
StructTypeDescr &descri = get(i)->as<StructTypeDescr>();
|
|
||||||
|
|
||||||
size_t indexi;
|
|
||||||
if (!descri.fieldIndex(id, &indexi))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Track whether all indices agree, but do not require it to be true
|
|
||||||
if (indexi != index0)
|
|
||||||
index0 = SIZE_MAX;
|
|
||||||
|
|
||||||
// Require that all offsets agree
|
|
||||||
if (descri.fieldOffset(indexi) != offset0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!fieldTypes.insert(&descri.fieldDescr(indexi)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All struct types had a field named `id` at the same offset
|
|
||||||
// (though it's still possible that the types are incompatible and
|
|
||||||
// that the indices disagree).
|
|
||||||
*offset = offset0;
|
|
||||||
*index = index0;
|
|
||||||
return fieldTypes.build(builder, out);
|
|
||||||
}
|
|
@ -1,204 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
||||||
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
#ifndef jit_TypeRepresentationSet_h
|
|
||||||
#define jit_TypeRepresentationSet_h
|
|
||||||
|
|
||||||
#include "builtin/TypedObject.h"
|
|
||||||
#include "jit/IonAllocPolicy.h"
|
|
||||||
#include "js/HashTable.h"
|
|
||||||
|
|
||||||
// TypeRepresentationSet stores a set of TypeRepresentation* objects,
|
|
||||||
// representing the possible types of the binary data associated with
|
|
||||||
// a typed object value. Often TypeRepresentationSets will be
|
|
||||||
// singleton sets, but it is also possible to have cases where many
|
|
||||||
// type representations flow into a single point. In such cases, the
|
|
||||||
// various type representations may differ in their details but often
|
|
||||||
// have a common prefix. We try to optimize this case as well.
|
|
||||||
//
|
|
||||||
// So, for example, consider some code like:
|
|
||||||
//
|
|
||||||
// var Point2Type = new StructType({x: uint8, y: uint8});
|
|
||||||
// var Point3Type = new StructType({x: uint8, y: uint8, z: uint8});
|
|
||||||
//
|
|
||||||
// function distance2d(pnt) {
|
|
||||||
// return Math.sqrt(pnt.x * pnt.x + pnt.y * pnt.y);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Even if the function `distance2d()` were used with instances of
|
|
||||||
// both Point2Type and Point3Type, we can still generate optimal code,
|
|
||||||
// because both of those types contain fields named `x` and `y` with
|
|
||||||
// the same types at the same offset.
|
|
||||||
|
|
||||||
namespace js {
|
|
||||||
namespace jit {
|
|
||||||
|
|
||||||
class IonBuilder;
|
|
||||||
class TypeDescrSet;
|
|
||||||
|
|
||||||
class TypeDescrSetBuilder {
|
|
||||||
private:
|
|
||||||
Vector<TypeDescr *, 4, SystemAllocPolicy> entries_;
|
|
||||||
bool invalid_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
TypeDescrSetBuilder();
|
|
||||||
|
|
||||||
bool insert(TypeDescr *typeRepr);
|
|
||||||
bool build(IonBuilder &builder, TypeDescrSet *out);
|
|
||||||
};
|
|
||||||
|
|
||||||
class TypeDescrSet {
|
|
||||||
private:
|
|
||||||
friend struct TypeDescrSetHasher;
|
|
||||||
friend class TypeDescrSetBuilder;
|
|
||||||
|
|
||||||
size_t length_;
|
|
||||||
TypeDescr **entries_; // Allocated using temp policy
|
|
||||||
|
|
||||||
TypeDescrSet(size_t length, TypeDescr **entries);
|
|
||||||
|
|
||||||
size_t length() const {
|
|
||||||
return length_;
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeDescr *get(uint32_t i) const {
|
|
||||||
return entries_[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
bool genericType(typename T::Type *out);
|
|
||||||
|
|
||||||
public:
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors
|
|
||||||
//
|
|
||||||
// For more flexible constructors, see
|
|
||||||
// TypeDescrSetBuilder above.
|
|
||||||
|
|
||||||
TypeDescrSet(const TypeDescrSet &c);
|
|
||||||
TypeDescrSet(); // empty set
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// Query the set
|
|
||||||
|
|
||||||
bool empty() const;
|
|
||||||
bool allOfKind(type::Kind kind);
|
|
||||||
|
|
||||||
// Returns true only when non-empty and `kind()` is
|
|
||||||
// `TypeDescr::Array`
|
|
||||||
bool allOfArrayKind();
|
|
||||||
|
|
||||||
// Returns true only if (1) non-empty, (2) for all types t in this
|
|
||||||
// set, t is sized, and (3) there is some size S such that for all
|
|
||||||
// types t in this set, `t.size() == S`. When the above holds,
|
|
||||||
// then also sets `*out` to S; otherwise leaves `*out` unchanged
|
|
||||||
// and returns false.
|
|
||||||
//
|
|
||||||
// At the moment condition (2) trivially holds. When Bug 922115
|
|
||||||
// lands, some array types will be unsized.
|
|
||||||
bool allHaveSameSize(int32_t *out);
|
|
||||||
|
|
||||||
types::TemporaryTypeSet *suitableTypeSet(IonBuilder &builder,
|
|
||||||
const Class *knownClass);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// The following operations are only valid on a non-empty set:
|
|
||||||
|
|
||||||
type::Kind kind();
|
|
||||||
|
|
||||||
// Returns the prototype that a typed object whose type is within
|
|
||||||
// this TypeDescrSet would have. Returns `null` if this cannot be
|
|
||||||
// predicted or instances of the type are not objects (e.g., uint8).
|
|
||||||
JSObject *knownPrototype() const;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// Scalar operations
|
|
||||||
//
|
|
||||||
// Only valid when `kind() == type::Scalar`
|
|
||||||
|
|
||||||
// If all type descrs in this set have a single type, returns true
|
|
||||||
// and sets *out. Else returns false.
|
|
||||||
bool scalarType(ScalarTypeDescr::Type *out);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// Reference operations
|
|
||||||
//
|
|
||||||
// Only valid when `kind() == type::Reference`
|
|
||||||
|
|
||||||
// If all type descrs in this set have a single type, returns true
|
|
||||||
// and sets *out. Else returns false.
|
|
||||||
bool referenceType(ReferenceTypeDescr::Type *out);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// Reference operations
|
|
||||||
//
|
|
||||||
// Only valid when `kind() == type::X4`
|
|
||||||
|
|
||||||
// If all type descrs in this set have a single type, returns true
|
|
||||||
// and sets *out. Else returns false.
|
|
||||||
bool x4Type(X4TypeDescr::Type *out);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// SizedArray operations
|
|
||||||
//
|
|
||||||
// Only valid when `kind() == type::SizedArray`
|
|
||||||
|
|
||||||
// Determines whether all arrays in this set have the same,
|
|
||||||
// statically known, array length and return that length
|
|
||||||
// (via `*length`) if so. Otherwise returns false.
|
|
||||||
bool hasKnownArrayLength(int32_t *length);
|
|
||||||
|
|
||||||
// Returns a `TypeDescrSet` representing the element
|
|
||||||
// types of the various array types in this set. The returned set
|
|
||||||
// may be the empty set.
|
|
||||||
bool arrayElementType(IonBuilder &builder, TypeDescrSet *out);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
// Struct operations
|
|
||||||
//
|
|
||||||
// Only valid when `kind() == type::Struct`
|
|
||||||
|
|
||||||
// Searches the type in the set for a field named `id`. All
|
|
||||||
// possible types must agree on the offset of the field within the
|
|
||||||
// structure and the possible types of the field must be
|
|
||||||
// compatible. If any pair of types disagree on the offset or have
|
|
||||||
// incompatible types for the field, then `*out` will be set to
|
|
||||||
// the empty set.
|
|
||||||
//
|
|
||||||
// Upon success, `out` will be set to the set of possible types of
|
|
||||||
// the field and `offset` will be set to the field's offset within
|
|
||||||
// the struct (measured in bytes).
|
|
||||||
//
|
|
||||||
// The parameter `*index` is special. If all types agree on the
|
|
||||||
// index of the field, then `*index` is set to the field index.
|
|
||||||
// Otherwise, it is set to SIZE_MAX. Note that two types may agree
|
|
||||||
// on the type and offset of a field but disagree about its index,
|
|
||||||
// e.g. the field `c` in `new StructType({a: uint8, b: uint8, c:
|
|
||||||
// uint16})` and `new StructType({a: uint16, c: uint16})`.
|
|
||||||
bool fieldNamed(IonBuilder &builder,
|
|
||||||
jsid id,
|
|
||||||
int32_t *offset,
|
|
||||||
TypeDescrSet *out,
|
|
||||||
size_t *index);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TypeDescrSetHasher
|
|
||||||
{
|
|
||||||
typedef TypeDescrSet Lookup;
|
|
||||||
static HashNumber hash(TypeDescrSet key);
|
|
||||||
static bool match(TypeDescrSet key1,
|
|
||||||
TypeDescrSet key2);
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef js::HashSet<TypeDescrSet,
|
|
||||||
TypeDescrSetHasher,
|
|
||||||
IonAllocPolicy> TypeDescrSetHash;
|
|
||||||
|
|
||||||
} // namespace jit
|
|
||||||
} // namespace js
|
|
||||||
|
|
||||||
#endif
|
|
379
js/src/jit/TypedObjectPrediction.cpp
Normal file
379
js/src/jit/TypedObjectPrediction.cpp
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "jit/TypedObjectPrediction.h"
|
||||||
|
|
||||||
|
using namespace js;
|
||||||
|
using namespace jit;
|
||||||
|
|
||||||
|
static const size_t ALL_FIELDS = SIZE_MAX;
|
||||||
|
|
||||||
|
// Sets the prediction to be the common prefix of descrA and descrB,
|
||||||
|
// considering at most the first max fields.
|
||||||
|
//
|
||||||
|
// In the case where the current prediction is a specific struct,
|
||||||
|
// and we are now seeing a second struct, then descrA and descrB will be
|
||||||
|
// the current and new struct and max will be ALL_FIELDS.
|
||||||
|
//
|
||||||
|
// In the case where the current prediction is already a prefix, and
|
||||||
|
// we are now seeing an additional struct, then descrA will be the
|
||||||
|
// current struct and max will be the current prefix length, and
|
||||||
|
// descrB will be the new struct.
|
||||||
|
//
|
||||||
|
// (Note that in general it is not important which struct is passed as
|
||||||
|
// descrA and which struct is passed as descrB, as the operation is
|
||||||
|
// symmetric.)
|
||||||
|
void
|
||||||
|
TypedObjectPrediction::markAsCommonPrefix(const StructTypeDescr &descrA,
|
||||||
|
const StructTypeDescr &descrB,
|
||||||
|
size_t max)
|
||||||
|
{
|
||||||
|
// count is the number of fields in common. It begins as the min
|
||||||
|
// of the number of fields from descrA, descrB, and max, and then
|
||||||
|
// is decremented as we find uncommon fields.
|
||||||
|
if (max > descrA.fieldCount())
|
||||||
|
max = descrA.fieldCount();
|
||||||
|
if (max > descrB.fieldCount())
|
||||||
|
max = descrB.fieldCount();
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
for (; i < max; i++) {
|
||||||
|
if (&descrA.fieldName(i) != &descrB.fieldName(i))
|
||||||
|
break;
|
||||||
|
if (&descrA.fieldDescr(i) != &descrB.fieldDescr(i))
|
||||||
|
break;
|
||||||
|
JS_ASSERT(descrA.fieldOffset(i) == descrB.fieldOffset(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
// empty prefix is not particularly useful.
|
||||||
|
markInconsistent();
|
||||||
|
} else {
|
||||||
|
setPrefix(descrA, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TypedObjectPrediction::addProto(const TypedProto &proto)
|
||||||
|
{
|
||||||
|
switch (predictionKind()) {
|
||||||
|
case Empty:
|
||||||
|
return setProto(proto);
|
||||||
|
|
||||||
|
case Inconsistent:
|
||||||
|
return; // keep same state
|
||||||
|
|
||||||
|
case Proto: {
|
||||||
|
if (&proto == data_.proto)
|
||||||
|
return; // keep same state
|
||||||
|
|
||||||
|
if (proto.kind() != data_.proto->kind())
|
||||||
|
return markInconsistent();
|
||||||
|
|
||||||
|
if (proto.kind() != type::Struct)
|
||||||
|
return markInconsistent();
|
||||||
|
|
||||||
|
const StructTypeDescr &structDescr = proto.typeDescr().as<StructTypeDescr>();
|
||||||
|
const StructTypeDescr ¤tDescr = data_.proto->typeDescr().as<StructTypeDescr>();
|
||||||
|
markAsCommonPrefix(structDescr, currentDescr, ALL_FIELDS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Descr:
|
||||||
|
// First downgrade from descr to proto, which is less precise,
|
||||||
|
// and then recurse.
|
||||||
|
setProto(data_.descr->typedProto());
|
||||||
|
return addProto(proto);
|
||||||
|
|
||||||
|
case Prefix:
|
||||||
|
if (proto.kind() != type::Struct)
|
||||||
|
return markInconsistent();
|
||||||
|
|
||||||
|
markAsCommonPrefix(*data_.prefix.descr,
|
||||||
|
proto.typeDescr().as<StructTypeDescr>(),
|
||||||
|
data_.prefix.fields);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Bad predictionKind");
|
||||||
|
}
|
||||||
|
|
||||||
|
type::Kind
|
||||||
|
TypedObjectPrediction::kind() const
|
||||||
|
{
|
||||||
|
switch (predictionKind()) {
|
||||||
|
case TypedObjectPrediction::Empty:
|
||||||
|
case TypedObjectPrediction::Inconsistent:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Proto:
|
||||||
|
return proto().kind();
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Descr:
|
||||||
|
return descr().kind();
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Prefix:
|
||||||
|
return prefix().descr->kind();
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Bad prediction kind");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TypedObjectPrediction::ofArrayKind() const
|
||||||
|
{
|
||||||
|
switch (kind()) {
|
||||||
|
case type::Scalar:
|
||||||
|
case type::Reference:
|
||||||
|
case type::X4:
|
||||||
|
case type::Struct:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case type::SizedArray:
|
||||||
|
case type::UnsizedArray:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Bad kind");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
DescrHasKnownSize(const TypeDescr &descr, int32_t *out)
|
||||||
|
{
|
||||||
|
if (!descr.is<SizedTypeDescr>())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*out = descr.as<SizedTypeDescr>().size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TypedObjectPrediction::hasKnownSize(int32_t *out) const
|
||||||
|
{
|
||||||
|
switch (predictionKind()) {
|
||||||
|
case TypedObjectPrediction::Empty:
|
||||||
|
case TypedObjectPrediction::Inconsistent:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Proto:
|
||||||
|
switch (kind()) {
|
||||||
|
case type::Scalar:
|
||||||
|
case type::Reference:
|
||||||
|
case type::X4:
|
||||||
|
case type::Struct:
|
||||||
|
*out = proto().typeDescr().as<SizedTypeDescr>().size();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case type::SizedArray:
|
||||||
|
case type::UnsizedArray:
|
||||||
|
// The prototype does not track the precise dimensions of arrays.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Unknown kind");
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Descr:
|
||||||
|
return DescrHasKnownSize(descr(), out);
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Prefix:
|
||||||
|
// We only know a prefix of the struct fields, hence we do not
|
||||||
|
// know its complete size.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Bad prediction kind");
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypedProto *
|
||||||
|
TypedObjectPrediction::getKnownPrototype() const
|
||||||
|
{
|
||||||
|
switch (predictionKind()) {
|
||||||
|
case TypedObjectPrediction::Empty:
|
||||||
|
case TypedObjectPrediction::Inconsistent:
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Proto:
|
||||||
|
switch (proto().kind()) {
|
||||||
|
case type::Scalar:
|
||||||
|
case type::Reference:
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
case type::X4:
|
||||||
|
case type::Struct:
|
||||||
|
case type::SizedArray:
|
||||||
|
case type::UnsizedArray:
|
||||||
|
return &proto();
|
||||||
|
}
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Invalid proto().kind()");
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Descr:
|
||||||
|
if (descr().is<ComplexTypeDescr>())
|
||||||
|
return &descr().as<ComplexTypeDescr>().instancePrototype();
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Prefix:
|
||||||
|
// We only know a prefix of the struct fields, hence we cannot
|
||||||
|
// say for certain what its prototype will be.
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Bad prediction kind");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
typename T::Type
|
||||||
|
TypedObjectPrediction::extractType() const
|
||||||
|
{
|
||||||
|
JS_ASSERT(kind() == T::Kind);
|
||||||
|
switch (predictionKind()) {
|
||||||
|
case TypedObjectPrediction::Empty:
|
||||||
|
case TypedObjectPrediction::Inconsistent:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Proto:
|
||||||
|
return proto().typeDescr().as<T>().type();
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Descr:
|
||||||
|
return descr().as<T>().type();
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Prefix:
|
||||||
|
break; // Prefixes are always structs, never scalars etc
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Bad prediction kind");
|
||||||
|
}
|
||||||
|
|
||||||
|
ScalarTypeDescr::Type
|
||||||
|
TypedObjectPrediction::scalarType() const
|
||||||
|
{
|
||||||
|
return extractType<ScalarTypeDescr>();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReferenceTypeDescr::Type
|
||||||
|
TypedObjectPrediction::referenceType() const
|
||||||
|
{
|
||||||
|
return extractType<ReferenceTypeDescr>();
|
||||||
|
}
|
||||||
|
|
||||||
|
X4TypeDescr::Type
|
||||||
|
TypedObjectPrediction::x4Type() const
|
||||||
|
{
|
||||||
|
return extractType<X4TypeDescr>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TypedObjectPrediction::hasKnownArrayLength(int32_t *length) const
|
||||||
|
{
|
||||||
|
JS_ASSERT(ofArrayKind());
|
||||||
|
switch (predictionKind()) {
|
||||||
|
case TypedObjectPrediction::Empty:
|
||||||
|
case TypedObjectPrediction::Inconsistent:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Proto:
|
||||||
|
// The prototype does not track the lengths of arrays.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Descr:
|
||||||
|
// In later patches, this condition will always be true
|
||||||
|
// so long as this represents an array
|
||||||
|
if (descr().is<SizedArrayTypeDescr>()) {
|
||||||
|
*length = descr().as<SizedArrayTypeDescr>().length();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Prefix:
|
||||||
|
break; // Prefixes are always structs, never arrays
|
||||||
|
}
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Bad prediction kind");
|
||||||
|
}
|
||||||
|
|
||||||
|
static TypeDescr &
|
||||||
|
DescrArrayElementType(const TypeDescr &descr) {
|
||||||
|
return (descr.is<SizedArrayTypeDescr>()
|
||||||
|
? descr.as<SizedArrayTypeDescr>().elementType()
|
||||||
|
: descr.as<UnsizedArrayTypeDescr>().elementType());
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedObjectPrediction
|
||||||
|
TypedObjectPrediction::arrayElementType() const
|
||||||
|
{
|
||||||
|
JS_ASSERT(ofArrayKind());
|
||||||
|
switch (predictionKind()) {
|
||||||
|
case TypedObjectPrediction::Empty:
|
||||||
|
case TypedObjectPrediction::Inconsistent:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Proto:
|
||||||
|
return TypedObjectPrediction(DescrArrayElementType(proto().typeDescr()));
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Descr:
|
||||||
|
return TypedObjectPrediction(DescrArrayElementType(descr()));
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Prefix:
|
||||||
|
break; // Prefixes are always structs, never arrays
|
||||||
|
}
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Bad prediction kind");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TypedObjectPrediction::hasFieldNamedPrefix(const StructTypeDescr &descr,
|
||||||
|
size_t fieldCount,
|
||||||
|
jsid id,
|
||||||
|
int32_t *offset,
|
||||||
|
TypedObjectPrediction *out,
|
||||||
|
size_t *index) const
|
||||||
|
{
|
||||||
|
// Initialize |*offset| and |*out| for the case where incompatible
|
||||||
|
// or absent fields are found.
|
||||||
|
*offset = SIZE_MAX;
|
||||||
|
*index = SIZE_MAX;
|
||||||
|
*out = TypedObjectPrediction();
|
||||||
|
|
||||||
|
// Find the index of the field |id| if any.
|
||||||
|
if (!descr.fieldIndex(id, index))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check whether the index falls within our known safe prefix.
|
||||||
|
if (*index >= fieldCount)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Load the offset and type.
|
||||||
|
*offset = descr.fieldOffset(*index);
|
||||||
|
*out = TypedObjectPrediction(descr.fieldDescr(*index));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TypedObjectPrediction::hasFieldNamed(jsid id,
|
||||||
|
int32_t *fieldOffset,
|
||||||
|
TypedObjectPrediction *fieldType,
|
||||||
|
size_t *fieldIndex) const
|
||||||
|
{
|
||||||
|
JS_ASSERT(kind() == type::Struct);
|
||||||
|
|
||||||
|
switch (predictionKind()) {
|
||||||
|
case TypedObjectPrediction::Empty:
|
||||||
|
case TypedObjectPrediction::Inconsistent:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Proto:
|
||||||
|
return hasFieldNamedPrefix(
|
||||||
|
proto().typeDescr().as<StructTypeDescr>(), ALL_FIELDS,
|
||||||
|
id, fieldOffset, fieldType, fieldIndex);
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Descr:
|
||||||
|
return hasFieldNamedPrefix(
|
||||||
|
descr().as<StructTypeDescr>(), ALL_FIELDS,
|
||||||
|
id, fieldOffset, fieldType, fieldIndex);
|
||||||
|
|
||||||
|
case TypedObjectPrediction::Prefix:
|
||||||
|
return hasFieldNamedPrefix(
|
||||||
|
*prefix().descr, prefix().fields,
|
||||||
|
id, fieldOffset, fieldType, fieldIndex);
|
||||||
|
}
|
||||||
|
MOZ_ASSUME_UNREACHABLE("Bad prediction kind");
|
||||||
|
}
|
233
js/src/jit/TypedObjectPrediction.h
Normal file
233
js/src/jit/TypedObjectPrediction.h
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||||
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef jit_TypedObjectPrediction_h
|
||||||
|
#define jit_TypedObjectPrediction_h
|
||||||
|
|
||||||
|
#include "builtin/TypedObject.h"
|
||||||
|
#include "jit/IonAllocPolicy.h"
|
||||||
|
|
||||||
|
namespace js {
|
||||||
|
namespace jit {
|
||||||
|
|
||||||
|
// A TypedObjectPrediction summarizes what we know about the type of a
|
||||||
|
// typed object at a given point (if anything). The prediction will
|
||||||
|
// begin as precise as possible and degrade to less precise as more
|
||||||
|
// typed object types are merged using |addProto()|.
|
||||||
|
//
|
||||||
|
// - Precise type descriptor: the precise TypeDescr is known, which gives
|
||||||
|
// us all possible information, including precise dimensons in the case
|
||||||
|
// of an array.
|
||||||
|
// - Proto: precise TypedProto is known. This is almost as precise as the
|
||||||
|
// type descriptor, but does not include array dimensions.
|
||||||
|
// - Prefix: the type is known to be a struct and we can track a prefix
|
||||||
|
// of its fields. This doesn't tell us how big the struct is etc but
|
||||||
|
// can give us fast access to those fields we know about. Useful when
|
||||||
|
// modeling inheritance.
|
||||||
|
// - Empty/Inconsistent: nothing useful is known.
|
||||||
|
//
|
||||||
|
// To create a TypedObjectPrediction from TI, one initially creates an
|
||||||
|
// empty prediction using the |TypedObjectPrediction()| constructor,
|
||||||
|
// and then invokes |addProto()| with the prototype of each typed
|
||||||
|
// object. The prediction will automatically downgrade to less and
|
||||||
|
// less specific settings as needed. Note that creating a prediction
|
||||||
|
// in this way can never yield precise array dimensions, since TI only
|
||||||
|
// tracks the prototype.
|
||||||
|
//
|
||||||
|
// TypedObjectPredictions can also result from other predictions using
|
||||||
|
// the query methods (e.g., |arrayElementType()|). In those cases, the
|
||||||
|
// precise array dimensions may be known.
|
||||||
|
//
|
||||||
|
// To query a prediction, you must first check whether it is "useless"
|
||||||
|
// using |isUseless()|. If this is true, there is no usable
|
||||||
|
// information to be extracted. Otherwise, you can inquire after the
|
||||||
|
// |kind()| of the data (struct, array, etc) and from there make more
|
||||||
|
// specific queries.
|
||||||
|
class TypedObjectPrediction {
|
||||||
|
public:
|
||||||
|
enum PredictionKind {
|
||||||
|
// No data.
|
||||||
|
Empty,
|
||||||
|
|
||||||
|
// Inconsistent data.
|
||||||
|
Inconsistent,
|
||||||
|
|
||||||
|
// Multiple different struct types flow into the same location,
|
||||||
|
// but they share fields in common. Prefix indicates that the first
|
||||||
|
// N fields of some struct type are known to be valid. This occurs
|
||||||
|
// in a subtyping scenario.
|
||||||
|
Prefix,
|
||||||
|
|
||||||
|
// The TypedProto of the value is known. This is generally
|
||||||
|
// less precise than the type descriptor because typed protos
|
||||||
|
// do not track array bounds.
|
||||||
|
Proto,
|
||||||
|
|
||||||
|
// The TypeDescr of the value is known. This is the most specific
|
||||||
|
// possible value and includes precise array bounds. Generally
|
||||||
|
// this only happens if we access the field of a struct.
|
||||||
|
Descr
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PrefixData {
|
||||||
|
const StructTypeDescr *descr;
|
||||||
|
size_t fields;
|
||||||
|
};
|
||||||
|
|
||||||
|
union Data {
|
||||||
|
const TypedProto *proto;
|
||||||
|
const TypeDescr *descr;
|
||||||
|
PrefixData prefix;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
PredictionKind kind_;
|
||||||
|
Data data_;
|
||||||
|
|
||||||
|
PredictionKind predictionKind() const {
|
||||||
|
return kind_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void markInconsistent() {
|
||||||
|
kind_ = Inconsistent;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypedProto &proto() const {
|
||||||
|
JS_ASSERT(predictionKind() == Proto);
|
||||||
|
return *data_.proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypeDescr &descr() const {
|
||||||
|
JS_ASSERT(predictionKind() == Descr);
|
||||||
|
return *data_.descr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PrefixData &prefix() const {
|
||||||
|
JS_ASSERT(predictionKind() == Prefix);
|
||||||
|
return data_.prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setProto(const TypedProto &proto) {
|
||||||
|
kind_ = Proto;
|
||||||
|
data_.proto = &proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDescr(const TypeDescr &descr) {
|
||||||
|
kind_ = Descr;
|
||||||
|
data_.descr = &descr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPrefix(const StructTypeDescr &descr, size_t fields) {
|
||||||
|
kind_ = Prefix;
|
||||||
|
data_.prefix.descr = &descr;
|
||||||
|
data_.prefix.fields = fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
void markAsCommonPrefix(const StructTypeDescr &descrA,
|
||||||
|
const StructTypeDescr &descrB,
|
||||||
|
size_t max);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
typename T::Type extractType() const;
|
||||||
|
|
||||||
|
bool hasFieldNamedPrefix(const StructTypeDescr &descr,
|
||||||
|
size_t fieldCount,
|
||||||
|
jsid id,
|
||||||
|
int32_t *offset,
|
||||||
|
TypedObjectPrediction *out,
|
||||||
|
size_t *index) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructing a prediction. Generally, you start with an empty
|
||||||
|
// prediction and invoke addProto() repeatedly.
|
||||||
|
|
||||||
|
TypedObjectPrediction() {
|
||||||
|
kind_ = Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedObjectPrediction(const TypedProto &proto) {
|
||||||
|
setProto(proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedObjectPrediction(const TypeDescr &descr) {
|
||||||
|
setDescr(descr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedObjectPrediction(const StructTypeDescr &descr, size_t fields) {
|
||||||
|
setPrefix(descr, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addProto(const TypedProto &proto);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Queries that are always valid.
|
||||||
|
|
||||||
|
bool isUseless() const {
|
||||||
|
return predictionKind() == Empty || predictionKind() == Inconsistent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determines whether we can predict the prototype for the typed
|
||||||
|
// object instance. Returns null if we cannot or if the typed
|
||||||
|
// object is of scalar/reference kind, in which case instances are
|
||||||
|
// not objects and hence do not have a (publicly available)
|
||||||
|
// prototype.
|
||||||
|
const TypedProto *getKnownPrototype() const;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Queries that are valid if not useless.
|
||||||
|
|
||||||
|
type::Kind kind() const;
|
||||||
|
|
||||||
|
bool ofArrayKind() const;
|
||||||
|
|
||||||
|
// Returns true if the size of this typed object is statically
|
||||||
|
// known and sets |*out| to that size. Otherwise returns false.
|
||||||
|
//
|
||||||
|
// The size may not be statically known if (1) the object is
|
||||||
|
// an array whose dimensions are unknown or (2) only a prefix
|
||||||
|
// of its type is known.
|
||||||
|
bool hasKnownSize(int32_t *out) const;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// Simple operations
|
||||||
|
//
|
||||||
|
// Only valid when |kind()| is Scalar, Reference, or x4 (as appropriate).
|
||||||
|
|
||||||
|
ScalarTypeDescr::Type scalarType() const;
|
||||||
|
ReferenceTypeDescr::Type referenceType() const;
|
||||||
|
X4TypeDescr::Type x4Type() const;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Queries valid only for arrays.
|
||||||
|
|
||||||
|
// Returns true if the length of the array is statically known,
|
||||||
|
// and sets |*length| appropriately. Otherwise returns false.
|
||||||
|
bool hasKnownArrayLength(int32_t *length) const;
|
||||||
|
|
||||||
|
// Returns a prediction for the array element type, if any.
|
||||||
|
TypedObjectPrediction arrayElementType() const;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// Struct operations
|
||||||
|
//
|
||||||
|
// Only valid when |kind() == TypeDescr::Struct|
|
||||||
|
|
||||||
|
// Returns true if the predicted type includes a field named |id|
|
||||||
|
// and sets |*fieldOffset|, |*fieldType|, and |*fieldIndex| with
|
||||||
|
// the offset (in bytes), type, and index of the field
|
||||||
|
// respectively. Otherwise returns false.
|
||||||
|
bool hasFieldNamed(jsid id,
|
||||||
|
int32_t *fieldOffset,
|
||||||
|
TypedObjectPrediction *fieldType,
|
||||||
|
size_t *fieldIndex) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace jit
|
||||||
|
} // namespace js
|
||||||
|
|
||||||
|
#endif
|
@ -297,7 +297,7 @@ if CONFIG['ENABLE_ION']:
|
|||||||
'jit/shared/Lowering-shared.cpp',
|
'jit/shared/Lowering-shared.cpp',
|
||||||
'jit/Snapshots.cpp',
|
'jit/Snapshots.cpp',
|
||||||
'jit/StupidAllocator.cpp',
|
'jit/StupidAllocator.cpp',
|
||||||
'jit/TypeDescrSet.cpp',
|
'jit/TypedObjectPrediction.cpp',
|
||||||
'jit/TypePolicy.cpp',
|
'jit/TypePolicy.cpp',
|
||||||
'jit/UnreachableCodeElimination.cpp',
|
'jit/UnreachableCodeElimination.cpp',
|
||||||
'jit/ValueNumbering.cpp',
|
'jit/ValueNumbering.cpp',
|
||||||
|
Loading…
Reference in New Issue
Block a user