[vm/nnbd] Fix supertype check in GenerateSubtype1TestCacheLookup

Before calling Subtype1TestCache stub, there was a quick check if
supertype's class id matches tested class id.
Null extends Object, so supertype of Null matches Object.
However, in NNBD strong mode Null is not assignable to Object.

Fixes https://github.com/dart-lang/sdk/issues/41272

Change-Id: Icc3efaf90992b5083cbe086af81db7504724b855
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/142085
Reviewed-by: Régis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov
2020-04-02 01:39:10 +00:00
committed by commit-bot@chromium.org
parent 0e8ee2b668
commit 6e53ac6e4c
6 changed files with 65 additions and 23 deletions
@@ -428,13 +428,17 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
__ LoadClassId(R2, TypeTestABI::kInstanceReg);
__ LoadClassById(R1, R2);
// R1: instance class.
// Check immediate superclass equality.
__ ldr(R2, compiler::FieldAddress(
R1, compiler::target::Class::super_type_offset()));
__ ldr(R2, compiler::FieldAddress(
R2, compiler::target::Type::type_class_id_offset()));
__ CompareImmediate(R2, Smi::RawValue(type_class.id()));
__ b(is_instance_lbl, EQ);
// Check immediate superclass equality. If type_class is Object, then testing
// supertype may yield a wrong result for Null in NNBD strong mode (because
// Null also extends Object).
if (!type_class.IsObjectClass() || !Isolate::Current()->null_safety()) {
__ ldr(R2, compiler::FieldAddress(
R1, compiler::target::Class::super_type_offset()));
__ ldr(R2, compiler::FieldAddress(
R2, compiler::target::Type::type_class_id_offset()));
__ CompareImmediate(R2, Smi::RawValue(type_class.id()));
__ b(is_instance_lbl, EQ);
}
const Register kInstantiatorTypeArgumentsReg = kNoRegister;
const Register kFunctionTypeArgumentsReg = kNoRegister;
@@ -414,11 +414,15 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
__ LoadClassId(TMP, TypeTestABI::kInstanceReg);
__ LoadClassById(R1, TMP);
// R1: instance class.
// Check immediate superclass equality.
__ LoadFieldFromOffset(R2, R1, Class::super_type_offset());
__ LoadFieldFromOffset(R2, R2, Type::type_class_id_offset());
__ CompareImmediate(R2, Smi::RawValue(type_class.id()));
__ b(is_instance_lbl, EQ);
// Check immediate superclass equality. If type_class is Object, then testing
// supertype may yield a wrong result for Null in NNBD strong mode (because
// Null also extends Object).
if (!type_class.IsObjectClass() || !Isolate::Current()->null_safety()) {
__ LoadFieldFromOffset(R2, R1, Class::super_type_offset());
__ LoadFieldFromOffset(R2, R2, Type::type_class_id_offset());
__ CompareImmediate(R2, Smi::RawValue(type_class.id()));
__ b(is_instance_lbl, EQ);
}
const Register kInstantiatorTypeArgumentsReg = kNoRegister;
const Register kFunctionTypeArgumentsReg = kNoRegister;
@@ -401,11 +401,15 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
__ LoadClassId(EDI, TypeTestABI::kInstanceReg);
__ LoadClassById(ECX, EDI);
// ECX: instance class.
// Check immediate superclass equality.
__ movl(EDI, compiler::FieldAddress(ECX, Class::super_type_offset()));
__ movl(EDI, compiler::FieldAddress(EDI, Type::type_class_id_offset()));
__ cmpl(EDI, compiler::Immediate(Smi::RawValue(type_class.id())));
__ j(EQUAL, is_instance_lbl);
// Check immediate superclass equality. If type_class is Object, then testing
// supertype may yield a wrong result for Null in NNBD strong mode (because
// Null also extends Object).
if (!type_class.IsObjectClass() || !Isolate::Current()->null_safety()) {
__ movl(EDI, compiler::FieldAddress(ECX, Class::super_type_offset()));
__ movl(EDI, compiler::FieldAddress(EDI, Type::type_class_id_offset()));
__ cmpl(EDI, compiler::Immediate(Smi::RawValue(type_class.id())));
__ j(EQUAL, is_instance_lbl);
}
const Register kInstantiatorTypeArgumentsReg = kNoRegister;
const Register kFunctionTypeArgumentsReg = kNoRegister;
@@ -433,11 +433,16 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
__ LoadClassId(TMP, TypeTestABI::kInstanceReg);
__ LoadClassById(R10, TMP);
// R10: instance class.
// Check immediate superclass equality.
__ movq(R13, compiler::FieldAddress(R10, Class::super_type_offset()));
__ movq(R13, compiler::FieldAddress(R13, Type::type_class_id_offset()));
__ CompareImmediate(R13, compiler::Immediate(Smi::RawValue(type_class.id())));
__ j(EQUAL, is_instance_lbl);
// Check immediate superclass equality. If type_class is Object, then testing
// supertype may yield a wrong result for Null in NNBD strong mode (because
// Null also extends Object).
if (!type_class.IsObjectClass() || !Isolate::Current()->null_safety()) {
__ movq(R13, compiler::FieldAddress(R10, Class::super_type_offset()));
__ movq(R13, compiler::FieldAddress(R13, Type::type_class_id_offset()));
__ CompareImmediate(R13,
compiler::Immediate(Smi::RawValue(type_class.id())));
__ j(EQUAL, is_instance_lbl);
}
const Register kInstantiatorTypeArgumentsReg = kNoRegister;
const Register kFunctionTypeArgumentsReg = kNoRegister;
+2 -1
View File
@@ -17827,7 +17827,8 @@ bool Instance::RuntimeTypeIsSubtypeOf(
}
const Class& cls = Class::Handle(zone, clazz());
if (cls.IsClosureClass()) {
if (other.IsDartFunctionType() || other.IsDartClosureType()) {
if (other.IsDartFunctionType() || other.IsDartClosureType() ||
other.IsObjectType()) {
return true;
}
AbstractType& instantiated_other = AbstractType::Handle(zone, other.raw());
@@ -0,0 +1,24 @@
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// VMOptions=--optimization_counter_threshold=10 --deterministic
// Requirements=nnbd-strong
// Verifies that null cannot be casted to Object.
// Regression test for https://github.com/dart-lang/sdk/issues/41272.
import 'package:expect/expect.dart';
doTest() {
dynamic x;
Expect.throwsTypeError(() {
x as Object;
});
}
main() {
for (int i = 0; i < 20; ++i) {
doTest();
}
}