diff -r 000000000000 -r 6474c204b198 js/src/jit/TypeDescrSet.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/src/jit/TypeDescrSet.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,204 @@ +/* -*- 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 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 + 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(TypeDescr::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: + + 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 + // + // Only valid when `kind() == TypeDescr::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() == TypeDescr::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() == TypeDescr::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() == TypeDescr::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() == TypeDescr::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 TypeDescrSetHash; + +} // namespace jit +} // namespace js + +#endif