mirror of
https://github.com/dart-lang/sdk
synced 2024-10-04 19:29:35 +00:00
[vm/compiler] handle non-nullable null situation better
Rationale: Previously, we avoided introducing redefinitions that introduced the empty non-nullable null type. This situation arises when we do a null check on an actual null value (making all subsequent uses effectively dead code). This is too simple, however, since it still allows hoisting the uses before the check. This CL gives a better solution by introducing redefinitions without a constraining type (which are not removed and avoid the type). In the long run perhaps the best solution would be to simply remove all subsequent uses as dead. https://github.com/dart-lang/sdk/issues/32167 https://github.com/dart-lang/sdk/issues/34473 https://github.com/dart-lang/sdk/issues/35335 Change-Id: Ib5dd072a9e546f6b91faa52ea08e8c0f6350d7e0 Reviewed-on: https://dart-review.googlesource.com/c/89922 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Aart Bik <ajcbik@google.com>
This commit is contained in:
parent
b692a6d183
commit
c701e76506
|
@ -80,7 +80,13 @@ class CompileType : public ZoneAllocated {
|
|||
// abstract type. The pair is assumed to be coherent.
|
||||
static CompileType Create(intptr_t cid, const AbstractType& type);
|
||||
|
||||
CompileType CopyNonNullable() const {
|
||||
// Return the non-nullable version of this type.
|
||||
CompileType CopyNonNullable() {
|
||||
if (IsNull()) {
|
||||
// Represent a non-nullable null type (typically arising for
|
||||
// unreachable values) as None.
|
||||
return None();
|
||||
}
|
||||
return CompileType(kNonNullable, kIllegalCid, type_);
|
||||
}
|
||||
|
||||
|
|
|
@ -1559,7 +1559,13 @@ RedefinitionInstr* FlowGraph::EnsureRedefinition(Instruction* prev,
|
|||
}
|
||||
}
|
||||
RedefinitionInstr* redef = new RedefinitionInstr(new Value(original));
|
||||
redef->set_constrained_type(new CompileType(compile_type));
|
||||
|
||||
// Don't set the constrained type when the type is None(), which denotes an
|
||||
// unreachable value (e.g. using value null after an explicit null check).
|
||||
if (!compile_type.IsNone()) {
|
||||
redef->set_constrained_type(new CompileType(compile_type));
|
||||
}
|
||||
|
||||
InsertAfter(prev, redef, NULL, FlowGraph::kValue);
|
||||
RenameDominatedUses(original, redef, redef);
|
||||
return redef;
|
||||
|
|
|
@ -283,7 +283,7 @@ void FlowGraphTypePropagator::VisitCheckClassId(CheckClassIdInstr* check) {
|
|||
void FlowGraphTypePropagator::VisitCheckNull(CheckNullInstr* check) {
|
||||
Definition* receiver = check->value()->definition();
|
||||
CompileType* type = TypeOf(receiver);
|
||||
if (type->is_nullable() && !type->IsNull()) {
|
||||
if (type->is_nullable()) {
|
||||
// Insert redefinition for the receiver to guard against invalid
|
||||
// code motion.
|
||||
EnsureMoreAccurateRedefinition(check, receiver, type->CopyNonNullable());
|
||||
|
@ -305,7 +305,7 @@ void FlowGraphTypePropagator::CheckNonNullSelector(
|
|||
if (target.IsNull()) {
|
||||
// If the selector is not defined on Null, we can propagate non-nullness.
|
||||
CompileType* type = TypeOf(receiver);
|
||||
if (type->is_nullable() && !type->IsNull()) {
|
||||
if (type->is_nullable()) {
|
||||
// Insert redefinition for the receiver to guard against invalid
|
||||
// code motion.
|
||||
EnsureMoreAccurateRedefinition(call, receiver, type->CopyNonNullable());
|
||||
|
|
Loading…
Reference in a new issue