mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 05:07:52 +00:00
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:
parent
27b6e1eaf6
commit
9138edd1ad
|
@ -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
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
|
|
|
@ -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