DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * 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/JitAllocPolicy.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 |addDescr()|.
//
// To create a TypedObjectPrediction from TI, one initially creates an
// empty prediction using the |TypedObjectPrediction()| constructor,
// and then invokes |addDescr()| 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 TypeDescr of the value is known. This is the most specific
    // possible value and includes precise array bounds.
    Descr
  };

  struct PrefixData {
    const StructTypeDescr* descr;
    size_t fields;
  };

  union Data {
    const TypeDescr* descr;
    PrefixData prefix;
  };

 private:
  PredictionKind kind_;
  Data data_;

  PredictionKind predictionKind() const { return kind_; }

  void markInconsistent() { kind_ = Inconsistent; }

  const TypeDescr& descr() const {
    MOZ_ASSERT(predictionKind() == Descr);
    return *data_.descr;
  }

  const PrefixData& prefix() const {
    MOZ_ASSERT(predictionKind() == Prefix);
    return data_.prefix;
  }

  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, size_t* fieldOffset,
                           TypedObjectPrediction* out, size_t* index,
                           bool* isMutable) const;

 public:
  ///////////////////////////////////////////////////////////////////////////
  // Constructing a prediction. Generally, you start with an empty
  // prediction and invoke addDescr() repeatedly.

  TypedObjectPrediction() : data_() { kind_ = Empty; }

  explicit TypedObjectPrediction(const TypeDescr& descr) { setDescr(descr); }

  TypedObjectPrediction(const StructTypeDescr& descr, size_t fields) {
    setPrefix(descr, fields);
  }

  void addDescr(const TypeDescr& descr);

  ///////////////////////////////////////////////////////////////////////////
  // 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(uint32_t* out) const;

  //////////////////////////////////////////////////////////////////////
  // Simple operations
  //
  // Only valid when |kind()| is Scalar or Reference.

  Scalar::Type scalarType() const;
  ReferenceType referenceType() 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, size_t* fieldOffset,
                     TypedObjectPrediction* fieldType, size_t* fieldIndex,
                     bool* fieldMutable) const;
};

}  // namespace jit
}  // namespace js

#endif