Bug 1085029 - Use common-descriptor logic more often in TypedObjectPrediction, r=nmatsakis.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 29 Oct 2014 11:19:51 -0700
changeset 212997 a9cab8a15d2bee231a85f2b30b70afd2ab59b525
parent 212996 4ec33eddc6fcdcab1c8bc9bc5100bc2d699c17e3
child 212998 24241717af63311a2e6202332441aa9403bfdbb6
push id27738
push usercbook@mozilla.com
push dateThu, 30 Oct 2014 13:46:07 +0000
treeherdermozilla-central@1aa1b23d799e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnmatsakis
bugs1085029
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1085029 - Use common-descriptor logic more often in TypedObjectPrediction, r=nmatsakis.
js/src/jit/IonBuilder.cpp
js/src/jit/TypedObjectPrediction.cpp
js/src/jit/TypedObjectPrediction.h
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -10913,17 +10913,17 @@ IonBuilder::typedObjectPrediction(types:
 
         TaggedProto proto = type->proto();
 
         // typed objects have immutable prototypes, and they are
         // always instances of TypedProto
         MOZ_ASSERT(proto.isObject() && proto.toObject()->is<TypedProto>());
 
         TypedProto &typedProto = proto.toObject()->as<TypedProto>();
-        out.addProto(typedProto);
+        out.addDescr(typedProto.typeDescr());
     }
 
     return out;
 }
 
 MDefinition *
 IonBuilder::loadTypedObjectType(MDefinition *typedObj)
 {
--- a/js/src/jit/TypedObjectPrediction.cpp
+++ b/js/src/jit/TypedObjectPrediction.cpp
@@ -52,71 +52,62 @@ TypedObjectPrediction::markAsCommonPrefi
         // empty prefix is not particularly useful.
         markInconsistent();
     } else {
         setPrefix(descrA, i);
     }
 }
 
 void
-TypedObjectPrediction::addProto(const TypedProto &proto)
+TypedObjectPrediction::addDescr(const TypeDescr &descr)
 {
     switch (predictionKind()) {
       case Empty:
-        return setProto(proto);
+        return setDescr(descr);
 
       case Inconsistent:
         return; // keep same state
 
-      case Proto: {
-        if (&proto == data_.proto)
+      case Descr: {
+        if (&descr == data_.descr)
             return; // keep same state
 
-        if (proto.kind() != data_.proto->kind())
+        if (descr.kind() != data_.descr->kind())
             return markInconsistent();
 
-        if (proto.kind() != type::Struct)
+        if (descr.kind() != type::Struct)
             return markInconsistent();
 
-        const StructTypeDescr &structDescr = proto.typeDescr().as<StructTypeDescr>();
-        const StructTypeDescr &currentDescr = data_.proto->typeDescr().as<StructTypeDescr>();
+        const StructTypeDescr &structDescr = descr.as<StructTypeDescr>();
+        const StructTypeDescr &currentDescr = data_.descr->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)
+        if (descr.kind() != type::Struct)
             return markInconsistent();
 
         markAsCommonPrefix(*data_.prefix.descr,
-                           proto.typeDescr().as<StructTypeDescr>(),
+                           descr.as<StructTypeDescr>(),
                            data_.prefix.fields);
         return;
     }
 
     MOZ_CRASH("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_CRASH("Bad prediction kind");
@@ -153,32 +144,16 @@ DescrHasKnownSize(const TypeDescr &descr
 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::Simd:
-          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_CRASH("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;
     }
@@ -189,30 +164,16 @@ TypedObjectPrediction::hasKnownSize(int3
 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::Simd:
-          case type::Struct:
-          case type::SizedArray:
-          case type::UnsizedArray:
-            return &proto();
-        }
-        MOZ_CRASH("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.
@@ -227,19 +188,16 @@ typename T::Type
 TypedObjectPrediction::extractType() const
 {
     MOZ_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_CRASH("Bad prediction kind");
@@ -267,20 +225,16 @@ bool
 TypedObjectPrediction::hasKnownArrayLength(int32_t *length) const
 {
     MOZ_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;
@@ -302,19 +256,16 @@ TypedObjectPrediction
 TypedObjectPrediction::arrayElementType() const
 {
     MOZ_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_CRASH("Bad prediction kind");
 }
@@ -349,21 +300,16 @@ TypedObjectPrediction::hasFieldNamed(jsi
 {
     MOZ_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,
--- a/js/src/jit/TypedObjectPrediction.h
+++ b/js/src/jit/TypedObjectPrediction.h
@@ -11,32 +11,21 @@
 #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.
+// 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 |addProto()| with the prototype of each typed
+// 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.
@@ -56,70 +45,53 @@ class TypedObjectPrediction {
         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.
+        // possible value and includes precise array bounds.
         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 {
-        MOZ_ASSERT(predictionKind() == Proto);
-        return *data_.proto;
-    }
-
     const TypeDescr &descr() const {
         MOZ_ASSERT(predictionKind() == Descr);
         return *data_.descr;
     }
 
     const PrefixData &prefix() const {
         MOZ_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;
@@ -139,35 +111,31 @@ class TypedObjectPrediction {
                              size_t *fieldOffset,
                              TypedObjectPrediction *out,
                              size_t *index) const;
 
   public:
 
     ///////////////////////////////////////////////////////////////////////////
     // Constructing a prediction. Generally, you start with an empty
-    // prediction and invoke addProto() repeatedly.
+    // prediction and invoke addDescr() repeatedly.
 
     TypedObjectPrediction() {
         kind_ = Empty;
     }
 
-    explicit TypedObjectPrediction(const TypedProto &proto) {
-        setProto(proto);
-    }
-
     explicit TypedObjectPrediction(const TypeDescr &descr) {
         setDescr(descr);
     }
 
     TypedObjectPrediction(const StructTypeDescr &descr, size_t fields) {
         setPrefix(descr, fields);
     }
 
-    void addProto(const TypedProto &proto);
+    void addDescr(const TypeDescr &descr);
 
     ///////////////////////////////////////////////////////////////////////////
     // Queries that are always valid.
 
     bool isUseless() const {
         return predictionKind() == Empty || predictionKind() == Inconsistent;
     }