Reland "[vm/compiler] Infer type of LoadIndexed from array type"

This is a reland of 501a7ae7b0

The change is re-landed as is, without any extra changes.
The change was reverted due to timeout on internal test (b/163882044),
but that timeout was actually not related to this particular change.

Original change's description:
> [vm/compiler] Infer type of LoadIndexed from array type
>
> After inlining we may have more accurate information about array being
> accessed. This change adds computation of type of LoadIndexed
> instruction based on the type of array being accessed.
>
> The computation is able to skip loading of GrowableArray.data.
> If array was loaded from a field, it takes static type of a field
> into account.
>
> Benchmarks with null safety in JIT mode on x64:
> ForInLoop +80-106%
> DeltaBlueIterators +15-31%
>
> Change-Id: Ia61aa761f4ccd4692e05fdac043f8a2a46f88f21
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/157823
> Reviewed-by: Ryan Macnak <rmacnak@google.com>
> Commit-Queue: Alexander Markov <alexmarkov@google.com>

Change-Id: Iae4fc5132f62fa2635159cbf9ec47636826e1402
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158526
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov 2020-08-14 17:52:06 +00:00 committed by commit-bot@chromium.org
parent 27b6e1eaf6
commit 9138edd1ad
5 changed files with 73 additions and 2 deletions

View file

@ -5528,6 +5528,7 @@ class LoadIndexedInstr : public TemplateDefinition<2, NoThrow> {
DECLARE_INSTRUCTION(LoadIndexed)
virtual CompileType ComputeType() const;
virtual bool RecomputeType();
virtual Representation RequiredInputRepresentation(intptr_t idx) const {
ASSERT(idx == 0 || idx == 1);

View file

@ -1701,6 +1701,61 @@ CompileType ExtractNthOutputInstr::ComputeType() const {
return CompileType::FromCid(definition_cid_);
}
static AbstractTypePtr ExtractElementTypeFromArrayType(
const AbstractType& array_type) {
if (array_type.IsTypeParameter()) {
return ExtractElementTypeFromArrayType(
AbstractType::Handle(TypeParameter::Cast(array_type).bound()));
}
if (!array_type.IsType()) {
return Object::dynamic_type().raw();
}
const intptr_t cid = array_type.type_class_id();
if (cid == kGrowableObjectArrayCid || cid == kArrayCid ||
cid == kImmutableArrayCid ||
array_type.type_class() ==
Isolate::Current()->object_store()->list_class()) {
const auto& type_args = TypeArguments::Handle(array_type.arguments());
return type_args.TypeAtNullSafe(Array::kElementTypeTypeArgPos);
}
return Object::dynamic_type().raw();
}
static AbstractTypePtr GetElementTypeFromArray(Value* array) {
return ExtractElementTypeFromArrayType(*(array->Type()->ToAbstractType()));
}
static CompileType ComputeArrayElementType(Value* array) {
// 1. Try to extract element type from array value.
auto& elem_type = AbstractType::Handle(GetElementTypeFromArray(array));
if (!elem_type.IsDynamicType()) {
return CompileType::FromAbstractType(elem_type);
}
// 2. Array value may be loaded from GrowableObjectArray.data.
// Unwrap and try again.
if (auto* load_field = array->definition()->AsLoadField()) {
if (load_field->slot().IsIdentical(Slot::GrowableObjectArray_data())) {
array = load_field->instance();
elem_type = GetElementTypeFromArray(array);
if (!elem_type.IsDynamicType()) {
return CompileType::FromAbstractType(elem_type);
}
}
}
// 3. If array was loaded from a Dart field, use field's static type.
// Unlike propagated type (which could be cid), static type may contain
// type arguments which can be used to figure out element type.
if (auto* load_field = array->definition()->AsLoadField()) {
if (load_field->slot().IsDartField()) {
elem_type =
ExtractElementTypeFromArrayType(load_field->slot().static_type());
}
}
return CompileType::FromAbstractType(elem_type);
}
CompileType LoadIndexedInstr::ComputeType() const {
switch (class_id_) {
case kArrayCid:
@ -1709,7 +1764,7 @@ CompileType LoadIndexedInstr::ComputeType() const {
// The original call knew something.
return *result_type_;
}
return CompileType::Dynamic();
return ComputeArrayElementType(array());
case kTypedDataFloat32ArrayCid:
case kTypedDataFloat64ArrayCid:
@ -1751,4 +1806,13 @@ CompileType LoadIndexedInstr::ComputeType() const {
}
}
bool LoadIndexedInstr::RecomputeType() {
if ((class_id_ == kArrayCid) || (class_id_ == kImmutableArrayCid)) {
// Array element type computation depends on computed
// types of other instructions and may change over time.
return UpdateType(ComputeType());
}
return false;
}
} // namespace dart

View file

@ -9572,6 +9572,9 @@ class Array : public Instance {
bool IsImmutable() const { return raw()->GetClassId() == kImmutableArrayCid; }
// Position of element type in type arguments.
static const intptr_t kElementTypeTypeArgPos = 0;
virtual TypeArgumentsPtr GetTypeArguments() const {
return raw_ptr()->type_arguments_;
}

View file

@ -335,13 +335,15 @@ void ObjectStore::InitKnownObjects() {
}
void ObjectStore::LazyInitCoreTypes() {
if (non_nullable_list_rare_type_ == Type::null()) {
if (list_class_ == Type::null()) {
ASSERT(non_nullable_list_rare_type_ == Type::null());
ASSERT(non_nullable_map_rare_type_ == Type::null());
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
Class& cls = Class::Handle(zone, core_lib.LookupClass(Symbols::List()));
ASSERT(!cls.IsNull());
set_list_class(cls);
Type& type = Type::Handle(zone);
type ^= cls.RareType();
set_non_nullable_list_rare_type(type);

View file

@ -82,6 +82,7 @@ class ObjectPointerVisitor;
RW(Type, string_type) \
RW(Type, legacy_string_type) \
RW(Type, non_nullable_string_type) \
CW(Class, list_class) /* maybe be null, lazily built */ \
CW(Type, non_nullable_list_rare_type) /* maybe be null, lazily built */ \
CW(Type, non_nullable_map_rare_type) /* maybe be null, lazily built */ \
FW(Type, non_nullable_future_rare_type) /* maybe be null, lazily built */ \