michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_TypeRepresentationSet_h michael@0: #define jit_TypeRepresentationSet_h michael@0: michael@0: #include "builtin/TypedObject.h" michael@0: #include "jit/IonAllocPolicy.h" michael@0: #include "js/HashTable.h" michael@0: michael@0: // TypeRepresentationSet stores a set of TypeRepresentation* objects, michael@0: // representing the possible types of the binary data associated with michael@0: // a typed object value. Often TypeRepresentationSets will be michael@0: // singleton sets, but it is also possible to have cases where many michael@0: // type representations flow into a single point. In such cases, the michael@0: // various type representations may differ in their details but often michael@0: // have a common prefix. We try to optimize this case as well. michael@0: // michael@0: // So, for example, consider some code like: michael@0: // michael@0: // var Point2Type = new StructType({x: uint8, y: uint8}); michael@0: // var Point3Type = new StructType({x: uint8, y: uint8, z: uint8}); michael@0: // michael@0: // function distance2d(pnt) { michael@0: // return Math.sqrt(pnt.x * pnt.x + pnt.y * pnt.y); michael@0: // } michael@0: // michael@0: // Even if the function `distance2d()` were used with instances of michael@0: // both Point2Type and Point3Type, we can still generate optimal code, michael@0: // because both of those types contain fields named `x` and `y` with michael@0: // the same types at the same offset. michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: class IonBuilder; michael@0: class TypeDescrSet; michael@0: michael@0: class TypeDescrSetBuilder { michael@0: private: michael@0: Vector entries_; michael@0: bool invalid_; michael@0: michael@0: public: michael@0: TypeDescrSetBuilder(); michael@0: michael@0: bool insert(TypeDescr *typeRepr); michael@0: bool build(IonBuilder &builder, TypeDescrSet *out); michael@0: }; michael@0: michael@0: class TypeDescrSet { michael@0: private: michael@0: friend struct TypeDescrSetHasher; michael@0: friend class TypeDescrSetBuilder; michael@0: michael@0: size_t length_; michael@0: TypeDescr **entries_; // Allocated using temp policy michael@0: michael@0: TypeDescrSet(size_t length, TypeDescr **entries); michael@0: michael@0: size_t length() const { michael@0: return length_; michael@0: } michael@0: michael@0: TypeDescr *get(uint32_t i) const { michael@0: return entries_[i]; michael@0: } michael@0: michael@0: template michael@0: bool genericType(typename T::Type *out); michael@0: michael@0: public: michael@0: ////////////////////////////////////////////////////////////////////// michael@0: // Constructors michael@0: // michael@0: // For more flexible constructors, see michael@0: // TypeDescrSetBuilder above. michael@0: michael@0: TypeDescrSet(const TypeDescrSet &c); michael@0: TypeDescrSet(); // empty set michael@0: michael@0: ////////////////////////////////////////////////////////////////////// michael@0: // Query the set michael@0: michael@0: bool empty() const; michael@0: bool allOfKind(TypeDescr::Kind kind); michael@0: michael@0: // Returns true only when non-empty and `kind()` is michael@0: // `TypeDescr::Array` michael@0: bool allOfArrayKind(); michael@0: michael@0: // Returns true only if (1) non-empty, (2) for all types t in this michael@0: // set, t is sized, and (3) there is some size S such that for all michael@0: // types t in this set, `t.size() == S`. When the above holds, michael@0: // then also sets `*out` to S; otherwise leaves `*out` unchanged michael@0: // and returns false. michael@0: // michael@0: // At the moment condition (2) trivially holds. When Bug 922115 michael@0: // lands, some array types will be unsized. michael@0: bool allHaveSameSize(int32_t *out); michael@0: michael@0: types::TemporaryTypeSet *suitableTypeSet(IonBuilder &builder, michael@0: const Class *knownClass); michael@0: michael@0: ////////////////////////////////////////////////////////////////////// michael@0: // The following operations are only valid on a non-empty set: michael@0: michael@0: TypeDescr::Kind kind(); michael@0: michael@0: // Returns the prototype that a typed object whose type is within michael@0: // this TypeDescrSet would have. Returns `null` if this cannot be michael@0: // predicted or instances of the type are not objects (e.g., uint8). michael@0: JSObject *knownPrototype() const; michael@0: michael@0: ////////////////////////////////////////////////////////////////////// michael@0: // Scalar operations michael@0: // michael@0: // Only valid when `kind() == TypeDescr::Scalar` michael@0: michael@0: // If all type descrs in this set have a single type, returns true michael@0: // and sets *out. Else returns false. michael@0: bool scalarType(ScalarTypeDescr::Type *out); michael@0: michael@0: ////////////////////////////////////////////////////////////////////// michael@0: // Reference operations michael@0: // michael@0: // Only valid when `kind() == TypeDescr::Reference` michael@0: michael@0: // If all type descrs in this set have a single type, returns true michael@0: // and sets *out. Else returns false. michael@0: bool referenceType(ReferenceTypeDescr::Type *out); michael@0: michael@0: ////////////////////////////////////////////////////////////////////// michael@0: // Reference operations michael@0: // michael@0: // Only valid when `kind() == TypeDescr::X4` michael@0: michael@0: // If all type descrs in this set have a single type, returns true michael@0: // and sets *out. Else returns false. michael@0: bool x4Type(X4TypeDescr::Type *out); michael@0: michael@0: ////////////////////////////////////////////////////////////////////// michael@0: // SizedArray operations michael@0: // michael@0: // Only valid when `kind() == TypeDescr::SizedArray` michael@0: michael@0: // Determines whether all arrays in this set have the same, michael@0: // statically known, array length and return that length michael@0: // (via `*length`) if so. Otherwise returns false. michael@0: bool hasKnownArrayLength(int32_t *length); michael@0: michael@0: // Returns a `TypeDescrSet` representing the element michael@0: // types of the various array types in this set. The returned set michael@0: // may be the empty set. michael@0: bool arrayElementType(IonBuilder &builder, TypeDescrSet *out); michael@0: michael@0: ////////////////////////////////////////////////////////////////////// michael@0: // Struct operations michael@0: // michael@0: // Only valid when `kind() == TypeDescr::Struct` michael@0: michael@0: // Searches the type in the set for a field named `id`. All michael@0: // possible types must agree on the offset of the field within the michael@0: // structure and the possible types of the field must be michael@0: // compatible. If any pair of types disagree on the offset or have michael@0: // incompatible types for the field, then `*out` will be set to michael@0: // the empty set. michael@0: // michael@0: // Upon success, `out` will be set to the set of possible types of michael@0: // the field and `offset` will be set to the field's offset within michael@0: // the struct (measured in bytes). michael@0: // michael@0: // The parameter `*index` is special. If all types agree on the michael@0: // index of the field, then `*index` is set to the field index. michael@0: // Otherwise, it is set to SIZE_MAX. Note that two types may agree michael@0: // on the type and offset of a field but disagree about its index, michael@0: // e.g. the field `c` in `new StructType({a: uint8, b: uint8, c: michael@0: // uint16})` and `new StructType({a: uint16, c: uint16})`. michael@0: bool fieldNamed(IonBuilder &builder, michael@0: jsid id, michael@0: int32_t *offset, michael@0: TypeDescrSet *out, michael@0: size_t *index); michael@0: }; michael@0: michael@0: struct TypeDescrSetHasher michael@0: { michael@0: typedef TypeDescrSet Lookup; michael@0: static HashNumber hash(TypeDescrSet key); michael@0: static bool match(TypeDescrSet key1, michael@0: TypeDescrSet key2); michael@0: }; michael@0: michael@0: typedef js::HashSet TypeDescrSetHash; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif