mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:45:06 +00:00
[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>
This commit is contained in:
parent
287c796412
commit
501a7ae7b0
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -9566,6 +9566,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_;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */ \
|
||||
|
|
Loading…
Reference in a new issue