From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- js/src/jit/TypedObjectPrediction.cpp | 308 +++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100644 js/src/jit/TypedObjectPrediction.cpp (limited to 'js/src/jit/TypedObjectPrediction.cpp') diff --git a/js/src/jit/TypedObjectPrediction.cpp b/js/src/jit/TypedObjectPrediction.cpp new file mode 100644 index 000000000..c01ad5eda --- /dev/null +++ b/js/src/jit/TypedObjectPrediction.cpp @@ -0,0 +1,308 @@ +/* -*- 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/. */ + +#include "jit/TypedObjectPrediction.h" + +using namespace js; +using namespace jit; + +static const size_t ALL_FIELDS = SIZE_MAX; + +// Sets the prediction to be the common prefix of descrA and descrB, +// considering at most the first max fields. +// +// In the case where the current prediction is a specific struct, +// and we are now seeing a second struct, then descrA and descrB will be +// the current and new struct and max will be ALL_FIELDS. +// +// In the case where the current prediction is already a prefix, and +// we are now seeing an additional struct, then descrA will be the +// current struct and max will be the current prefix length, and +// descrB will be the new struct. +// +// (Note that in general it is not important which struct is passed as +// descrA and which struct is passed as descrB, as the operation is +// symmetric.) +void +TypedObjectPrediction::markAsCommonPrefix(const StructTypeDescr& descrA, + const StructTypeDescr& descrB, + size_t max) +{ + // count is the number of fields in common. It begins as the min + // of the number of fields from descrA, descrB, and max, and then + // is decremented as we find uncommon fields. + if (max > descrA.fieldCount()) + max = descrA.fieldCount(); + if (max > descrB.fieldCount()) + max = descrB.fieldCount(); + + size_t i = 0; + for (; i < max; i++) { + if (&descrA.fieldName(i) != &descrB.fieldName(i)) + break; + if (&descrA.fieldDescr(i) != &descrB.fieldDescr(i)) + break; + MOZ_ASSERT(descrA.fieldOffset(i) == descrB.fieldOffset(i)); + } + + if (i == 0) { + // empty prefix is not particularly useful. + markInconsistent(); + } else { + setPrefix(descrA, i); + } +} + +void +TypedObjectPrediction::addDescr(const TypeDescr& descr) +{ + switch (predictionKind()) { + case Empty: + return setDescr(descr); + + case Inconsistent: + return; // keep same state + + case Descr: { + if (&descr == data_.descr) + return; // keep same state + + if (descr.kind() != data_.descr->kind()) + return markInconsistent(); + + if (descr.kind() != type::Struct) + return markInconsistent(); + + const StructTypeDescr& structDescr = descr.as(); + const StructTypeDescr& currentDescr = data_.descr->as(); + markAsCommonPrefix(structDescr, currentDescr, ALL_FIELDS); + return; + } + + case Prefix: + if (descr.kind() != type::Struct) + return markInconsistent(); + + markAsCommonPrefix(*data_.prefix.descr, + descr.as(), + data_.prefix.fields); + return; + } + + MOZ_CRASH("Bad predictionKind"); +} + +type::Kind +TypedObjectPrediction::kind() const +{ + switch (predictionKind()) { + case TypedObjectPrediction::Empty: + case TypedObjectPrediction::Inconsistent: + break; + + case TypedObjectPrediction::Descr: + return descr().kind(); + + case TypedObjectPrediction::Prefix: + return prefix().descr->kind(); + } + + MOZ_CRASH("Bad prediction kind"); +} + +bool +TypedObjectPrediction::ofArrayKind() const +{ + switch (kind()) { + case type::Scalar: + case type::Reference: + case type::Simd: + case type::Struct: + return false; + + case type::Array: + return true; + } + + MOZ_CRASH("Bad kind"); +} + +bool +TypedObjectPrediction::hasKnownSize(uint32_t* out) const +{ + switch (predictionKind()) { + case TypedObjectPrediction::Empty: + case TypedObjectPrediction::Inconsistent: + return false; + + case TypedObjectPrediction::Descr: + *out = descr().size(); + return true; + + case TypedObjectPrediction::Prefix: + // We only know a prefix of the struct fields, hence we do not + // know its complete size. + return false; + + default: + MOZ_CRASH("Bad prediction kind"); + } +} + +const TypedProto* +TypedObjectPrediction::getKnownPrototype() const +{ + switch (predictionKind()) { + case TypedObjectPrediction::Empty: + case TypedObjectPrediction::Inconsistent: + return nullptr; + + case TypedObjectPrediction::Descr: + if (descr().is()) + return &descr().as().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. + return nullptr; + + default: + MOZ_CRASH("Bad prediction kind"); + } +} + +template +typename T::Type +TypedObjectPrediction::extractType() const +{ + MOZ_ASSERT(kind() == T::Kind); + switch (predictionKind()) { + case TypedObjectPrediction::Empty: + case TypedObjectPrediction::Inconsistent: + break; + + case TypedObjectPrediction::Descr: + return descr().as().type(); + + case TypedObjectPrediction::Prefix: + break; // Prefixes are always structs, never scalars etc + } + + MOZ_CRASH("Bad prediction kind"); +} + +ScalarTypeDescr::Type +TypedObjectPrediction::scalarType() const +{ + return extractType(); +} + +ReferenceTypeDescr::Type +TypedObjectPrediction::referenceType() const +{ + return extractType(); +} + +SimdType +TypedObjectPrediction::simdType() const +{ + return descr().as().type(); +} + +bool +TypedObjectPrediction::hasKnownArrayLength(int32_t* length) const +{ + switch (predictionKind()) { + case TypedObjectPrediction::Empty: + case TypedObjectPrediction::Inconsistent: + return false; + + case TypedObjectPrediction::Descr: + // In later patches, this condition will always be true + // so long as this represents an array + if (descr().is()) { + *length = descr().as().length(); + return true; + } + return false; + + case TypedObjectPrediction::Prefix: + // Prefixes are always structs, never arrays + return false; + + default: + MOZ_CRASH("Bad prediction kind"); + } +} + +TypedObjectPrediction +TypedObjectPrediction::arrayElementType() const +{ + MOZ_ASSERT(ofArrayKind()); + switch (predictionKind()) { + case TypedObjectPrediction::Empty: + case TypedObjectPrediction::Inconsistent: + break; + + case TypedObjectPrediction::Descr: + return TypedObjectPrediction(descr().as().elementType()); + + case TypedObjectPrediction::Prefix: + break; // Prefixes are always structs, never arrays + } + MOZ_CRASH("Bad prediction kind"); +} + +bool +TypedObjectPrediction::hasFieldNamedPrefix(const StructTypeDescr& descr, + size_t fieldCount, + jsid id, + size_t* fieldOffset, + TypedObjectPrediction* out, + size_t* index) const +{ + // Find the index of the field |id| if any. + if (!descr.fieldIndex(id, index)) + return false; + + // Check whether the index falls within our known safe prefix. + if (*index >= fieldCount) + return false; + + // Load the offset and type. + *fieldOffset = descr.fieldOffset(*index); + *out = TypedObjectPrediction(descr.fieldDescr(*index)); + return true; +} + +bool +TypedObjectPrediction::hasFieldNamed(jsid id, + size_t* fieldOffset, + TypedObjectPrediction* fieldType, + size_t* fieldIndex) const +{ + MOZ_ASSERT(kind() == type::Struct); + + switch (predictionKind()) { + case TypedObjectPrediction::Empty: + case TypedObjectPrediction::Inconsistent: + return false; + + case TypedObjectPrediction::Descr: + return hasFieldNamedPrefix( + descr().as(), ALL_FIELDS, + id, fieldOffset, fieldType, fieldIndex); + + case TypedObjectPrediction::Prefix: + return hasFieldNamedPrefix( + *prefix().descr, prefix().fields, + id, fieldOffset, fieldType, fieldIndex); + + default: + MOZ_CRASH("Bad prediction kind"); + } +} -- cgit v1.2.3