mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 983977 - Omit type barriers where possible r=jandem
This commit is contained in:
parent
8186a5dafa
commit
4e7c85fecb
@ -211,6 +211,7 @@ CreateX4Class(JSContext *cx, Handle<GlobalObject*> global)
|
||||
return nullptr;
|
||||
x4->initReservedSlot(JS_DESCR_SLOT_TYPE_REPR, ObjectValue(*typeReprObj));
|
||||
x4->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
|
||||
x4->initReservedSlot(JS_DESCR_SLOT_PROTO, ObjectValue(*proto));
|
||||
|
||||
// Link constructor to prototype and install properties.
|
||||
|
||||
|
@ -608,6 +608,8 @@ ArrayMetaTypeDescr::create(JSContext *cx,
|
||||
if (!prototypeObj)
|
||||
return nullptr;
|
||||
|
||||
obj->initReservedSlot(JS_DESCR_SLOT_PROTO, ObjectValue(*prototypeObj));
|
||||
|
||||
if (!LinkConstructorAndPrototype(cx, obj, prototypeObj))
|
||||
return nullptr;
|
||||
|
||||
@ -979,6 +981,8 @@ StructMetaTypeDescr::create(JSContext *cx,
|
||||
if (!prototypeObj)
|
||||
return nullptr;
|
||||
|
||||
descr->initReservedSlot(JS_DESCR_SLOT_PROTO, ObjectValue(*prototypeObj));
|
||||
|
||||
if (!LinkConstructorAndPrototype(cx, descr, prototypeObj))
|
||||
return nullptr;
|
||||
|
||||
|
@ -135,6 +135,14 @@ static T ConvertScalar(double d)
|
||||
class TypeDescr : public JSObject
|
||||
{
|
||||
public:
|
||||
// This is *intentionally* not defined so as to produce link
|
||||
// errors if a is<FooTypeDescr>() etc goes wrong. Otherwise, the
|
||||
// default implementation resolves this to a reference to
|
||||
// FooTypeDescr::class_ which resolves to
|
||||
// JSObject::class_. Debugging the resulting errors leads to much
|
||||
// fun and rejoicing.
|
||||
static const Class class_;
|
||||
|
||||
enum Kind {
|
||||
Scalar = JS_TYPEREPR_SCALAR_KIND,
|
||||
Reference = JS_TYPEREPR_REFERENCE_KIND,
|
||||
@ -269,10 +277,22 @@ class ReferenceTypeDescr : public SimpleTypeDescr
|
||||
macro_(ReferenceTypeDescr::TYPE_OBJECT, HeapPtrObject, Object) \
|
||||
macro_(ReferenceTypeDescr::TYPE_STRING, HeapPtrString, string)
|
||||
|
||||
// Type descriptors whose instances are objects and hence which have
|
||||
// an associated `prototype` property.
|
||||
class ComplexTypeDescr : public SizedTypeDescr
|
||||
{
|
||||
public:
|
||||
// Returns the prototype that instances of this type descriptor
|
||||
// will have.
|
||||
JSObject &instancePrototype() const {
|
||||
return getReservedSlot(JS_DESCR_SLOT_PROTO).toObject();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Type descriptors `float32x4` and `int32x4`
|
||||
*/
|
||||
class X4TypeDescr : public SizedTypeDescr
|
||||
class X4TypeDescr : public ComplexTypeDescr
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
@ -346,6 +366,11 @@ class ArrayMetaTypeDescr : public JSObject
|
||||
|
||||
/*
|
||||
* Type descriptor created by `new ArrayType(typeObj)`
|
||||
*
|
||||
* These have a prototype, and hence *could* be a subclass of
|
||||
* `ComplexTypeDescr`, but it would require some reshuffling of the
|
||||
* hierarchy, and it's not worth the trouble since they will be going
|
||||
* away as part of bug 973238.
|
||||
*/
|
||||
class UnsizedArrayTypeDescr : public TypeDescr
|
||||
{
|
||||
@ -364,7 +389,7 @@ class UnsizedArrayTypeDescr : public TypeDescr
|
||||
/*
|
||||
* Type descriptor created by `unsizedArrayTypeObj.dimension()`
|
||||
*/
|
||||
class SizedArrayTypeDescr : public SizedTypeDescr
|
||||
class SizedArrayTypeDescr : public ComplexTypeDescr
|
||||
{
|
||||
public:
|
||||
static const Class class_;
|
||||
@ -413,7 +438,8 @@ class StructMetaTypeDescr : public JSObject
|
||||
static bool construct(JSContext *cx, unsigned argc, Value *vp);
|
||||
};
|
||||
|
||||
class StructTypeDescr : public SizedTypeDescr {
|
||||
class StructTypeDescr : public ComplexTypeDescr
|
||||
{
|
||||
public:
|
||||
static const Class class_;
|
||||
|
||||
@ -873,13 +899,19 @@ IsSimpleTypeDescrClass(const Class* clasp)
|
||||
clasp == &ReferenceTypeDescr::class_;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsComplexTypeDescrClass(const Class* clasp)
|
||||
{
|
||||
return clasp == &StructTypeDescr::class_ ||
|
||||
clasp == &SizedArrayTypeDescr::class_ ||
|
||||
clasp == &X4TypeDescr::class_;
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsSizedTypeDescrClass(const Class* clasp)
|
||||
{
|
||||
return IsSimpleTypeDescrClass(clasp) ||
|
||||
clasp == &StructTypeDescr::class_ ||
|
||||
clasp == &SizedArrayTypeDescr::class_ ||
|
||||
clasp == &X4TypeDescr::class_;
|
||||
IsComplexTypeDescrClass(clasp);
|
||||
}
|
||||
|
||||
inline bool
|
||||
@ -908,6 +940,13 @@ JSObject::is<js::SizedTypeDescr>() const
|
||||
return IsSizedTypeDescrClass(getClass());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool
|
||||
JSObject::is<js::ComplexTypeDescr>() const
|
||||
{
|
||||
return IsComplexTypeDescrClass(getClass());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool
|
||||
JSObject::is<js::TypeDescr>() const
|
||||
|
@ -21,23 +21,24 @@
|
||||
#define JS_DESCR_SLOT_TYPE_REPR 0 // Associated Type Representation
|
||||
#define JS_DESCR_SLOT_ALIGNMENT 1 // Alignment in bytes
|
||||
#define JS_DESCR_SLOT_SIZE 2 // Size in bytes, if sized, else 0
|
||||
#define JS_DESCR_SLOT_PROTO 3 // Prototype for instances, if any
|
||||
|
||||
// Slots on scalars, references, and x4s
|
||||
#define JS_DESCR_SLOT_TYPE 3 // Type code
|
||||
#define JS_DESCR_SLOT_TYPE 4 // Type code
|
||||
|
||||
// Slots on all array descriptors
|
||||
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 3
|
||||
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 4
|
||||
|
||||
// Slots on sized array descriptors
|
||||
#define JS_DESCR_SLOT_SIZED_ARRAY_LENGTH 4
|
||||
#define JS_DESCR_SLOT_SIZED_ARRAY_LENGTH 5
|
||||
|
||||
// Slots on struct type objects
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 3
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 4
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 5
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_NAMES 4
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_TYPES 5
|
||||
#define JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS 6
|
||||
|
||||
// Maximum number of slots for any descriptor
|
||||
#define JS_DESCR_SLOTS 6
|
||||
#define JS_DESCR_SLOTS 7
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Slots for type representation objects
|
||||
|
23
js/src/jit-test/tests/TypedObject/prototypes.js
vendored
Normal file
23
js/src/jit-test/tests/TypedObject/prototypes.js
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// API Surface Test: check that mutating prototypes
|
||||
// of type descriptors has no effect.
|
||||
|
||||
if (!this.hasOwnProperty("TypedObject"))
|
||||
quit();
|
||||
|
||||
var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
|
||||
|
||||
function main() { // once a C programmer, always a C programmer.
|
||||
var Uints = new StructType({f: uint32, g: uint32});
|
||||
var p = Uints.prototype;
|
||||
Uints.prototype = {}; // no effect
|
||||
assertEq(p, Uints.prototype);
|
||||
|
||||
var Uintss = Uints.array(2);
|
||||
var p = Uintss.prototype;
|
||||
Uintss.prototype = {}; // no effect
|
||||
assertEq(p, Uintss.prototype);
|
||||
|
||||
print("Tests complete");
|
||||
}
|
||||
|
||||
main();
|
@ -6855,27 +6855,48 @@ IonBuilder::pushDerivedTypedObject(bool *emitted,
|
||||
current->add(derivedTypedObj);
|
||||
current->push(derivedTypedObj);
|
||||
|
||||
// Insert a barrier. This is necessary because, while we know from
|
||||
// the inputs that the result of this access operation will be a
|
||||
// derived typed object, and we know the set of type descriptor(s)
|
||||
// it will be associated with (`derivedDescrs`), we do *not* know
|
||||
// precisely what TI type object the result will have at
|
||||
// runtime. The observed type set could be incomplete for two
|
||||
// reasons:
|
||||
// Determine (if possible) the class/proto that `derivedTypedObj`
|
||||
// will have. For derived typed objects, the class (transparent vs
|
||||
// opaque) will be the same as the incoming object from which the
|
||||
// derived typed object is, well, derived. The prototype will be
|
||||
// determined based on the type descriptor (and is immutable).
|
||||
types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
|
||||
const Class *expectedClass = objTypes ? objTypes->getKnownClass() : nullptr;
|
||||
JSObject *expectedProto = derivedTypeDescrs.knownPrototype();
|
||||
JS_ASSERT_IF(expectedClass, IsTypedObjectClass(expectedClass));
|
||||
|
||||
// Determine (if possible) the class/proto that the observed type set
|
||||
// describes.
|
||||
types::TemporaryTypeSet *observedTypes = bytecodeTypes(pc);
|
||||
const Class *observedClass = observedTypes->getKnownClass();
|
||||
JSObject *observedProto = observedTypes->getCommonPrototype();
|
||||
|
||||
// If expectedClass/expectedProto are both non-null (and hence
|
||||
// known), we can predict precisely what TI type object
|
||||
// derivedTypedObj will have. Therefore, if we observe that this
|
||||
// TI type object is already contained in the set of
|
||||
// observedTypes, we can skip the barrier.
|
||||
//
|
||||
// 1. We may simply not have executed this instruction yet.
|
||||
// This occurs frequently with --ion-eager but can happen
|
||||
// under other scenarios as well.
|
||||
// Barriers still wind up being needed in some relatively
|
||||
// rare cases:
|
||||
//
|
||||
// 2. Users can mutate the prototypes of descriptors,
|
||||
// and hence a single descriptor can be associated with multiple
|
||||
// type objects over the course of the execution. Therefore,
|
||||
// even if we have executed this instruction, the TI type object
|
||||
// of the result might be different this time around from
|
||||
// previous executions.
|
||||
types::TemporaryTypeSet *resultTypes = bytecodeTypes(pc);
|
||||
if (!pushTypeBarrier(derivedTypedObj, resultTypes, true))
|
||||
return false;
|
||||
// - if multiple kinds of typed objects flow into this point,
|
||||
// in which case we will not be able to predict expectedClass
|
||||
// nor expectedProto.
|
||||
//
|
||||
// - if the code has never executed, in which case the set of
|
||||
// observed types will be incomplete.
|
||||
//
|
||||
// Barriers are particularly expensive here because they prevent
|
||||
// us from optimizing the MNewDerivedTypedObject away.
|
||||
if (observedClass && observedProto && observedClass == expectedClass &&
|
||||
observedProto == expectedProto)
|
||||
{
|
||||
derivedTypedObj->setResultTypeSet(observedTypes);
|
||||
} else {
|
||||
if (!pushTypeBarrier(derivedTypedObj, observedTypes, true))
|
||||
return false;
|
||||
}
|
||||
|
||||
*emitted = true;
|
||||
return true;
|
||||
|
@ -164,7 +164,7 @@ TypeDescrSet::TypeDescrSet()
|
||||
{}
|
||||
|
||||
bool
|
||||
TypeDescrSet::empty()
|
||||
TypeDescrSet::empty() const
|
||||
{
|
||||
return length_ == 0;
|
||||
}
|
||||
@ -217,6 +217,15 @@ TypeDescrSet::allHaveSameSize(size_t *out)
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
TypeDescrSet::knownPrototype() const
|
||||
{
|
||||
JS_ASSERT(!empty());
|
||||
if (length() > 1 || !get(0)->is<ComplexTypeDescr>())
|
||||
return nullptr;
|
||||
return &get(0)->as<ComplexTypeDescr>().instancePrototype();
|
||||
}
|
||||
|
||||
TypeDescr::Kind
|
||||
TypeDescrSet::kind()
|
||||
{
|
||||
|
@ -85,7 +85,7 @@ class TypeDescrSet {
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Query the set
|
||||
|
||||
bool empty();
|
||||
bool empty() const;
|
||||
bool allOfKind(TypeDescr::Kind kind);
|
||||
|
||||
// Returns true only when non-empty and `kind()` is
|
||||
@ -102,11 +102,19 @@ class TypeDescrSet {
|
||||
// lands, some array types will be unsized.
|
||||
bool allHaveSameSize(size_t *out);
|
||||
|
||||
types::TemporaryTypeSet *suitableTypeSet(IonBuilder &builder,
|
||||
const Class *knownClass);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// The following operations are only valid on a non-empty set:
|
||||
|
||||
TypeDescr::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
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user