7422 : "not be");
7423 super.PrintName(Object::kScrubbedName, &
buffer);
7424 expect.Fail(
"%s",
buffer.buffer());
7425 }
7426}
7427
7428#define EXPECT_SUBTYPE(sub, super) \
7429 CheckSubtypeRelation(Expect(__FILE__, __LINE__), sub, super, true);
7430#define EXPECT_NOT_SUBTYPE(sub, super) \
7431 CheckSubtypeRelation(Expect(__FILE__, __LINE__), sub, super, false);
7432
7434 const auto& closure_class =
7435 Class::Handle(IsolateGroup::Current()->object_store()->closure_class());
7436 const auto& closure_type = Type::Handle(closure_class.DeclarationType());
7437 auto& closure_type_nullable = Type::Handle(
7438 closure_type.ToNullability(Nullability::kNullable, Heap::kNew));
7440 auto& closure_type_legacy = Type::Handle(
7441 closure_type.ToNullability(Nullability::kLegacy, Heap::kNew));
7443 auto& closure_type_nonnullable = Type::Handle(
7444 closure_type.ToNullability(Nullability::kNonNullable, Heap::kNew));
7446
7447 const auto& function_type =
7448 Type::Handle(IsolateGroup::Current()->object_store()->function_type());
7449 auto& function_type_nullable = Type::Handle(
7450 function_type.ToNullability(Nullability::kNullable, Heap::kNew));
7452 auto& function_type_legacy = Type::Handle(
7453 function_type.ToNullability(Nullability::kLegacy, Heap::kNew));
7455 auto& function_type_nonnullable = Type::Handle(
7456 function_type.ToNullability(Nullability::kNonNullable, Heap::kNew));
7458
7459 EXPECT_SUBTYPE(closure_type_nonnullable, function_type_nullable);
7461 EXPECT_SUBTYPE(closure_type_nonnullable, function_type_nonnullable);
7468
7469 const auto& async_lib = Library::Handle(Library::AsyncLibrary());
7470 const auto& future_or_class =
7471 Class::Handle(async_lib.LookupClass(Symbols::FutureOr()));
7472 auto& tav_function_nullable = TypeArguments::Handle(TypeArguments::New(1));
7473 tav_function_nullable.SetTypeAt(0, function_type_nullable);
7474 tav_function_nullable = tav_function_nullable.Canonicalize(thread);
7475 auto& tav_function_legacy = TypeArguments::Handle(TypeArguments::New(1));
7476 tav_function_legacy.SetTypeAt(0, function_type_legacy);
7477 tav_function_legacy = tav_function_legacy.Canonicalize(thread);
7478 auto& tav_function_nonnullable = TypeArguments::Handle(TypeArguments::New(1));
7479 tav_function_nonnullable.SetTypeAt(0, function_type_nonnullable);
7480 tav_function_nonnullable = tav_function_nonnullable.Canonicalize(thread);
7481
7482 auto& future_or_function_type_nullable =
7483 Type::Handle(Type::New(future_or_class, tav_function_nullable));
7485 auto& future_or_function_type_legacy =
7486 Type::Handle(Type::New(future_or_class, tav_function_legacy));
7488 auto& future_or_function_type_nonnullable =
7489 Type::Handle(Type::New(future_or_class, tav_function_nonnullable));
7491
7492 EXPECT_SUBTYPE(closure_type_nonnullable, future_or_function_type_nullable);
7493 EXPECT_SUBTYPE(closure_type_nonnullable, future_or_function_type_legacy);
7494 EXPECT_SUBTYPE(closure_type_nonnullable, future_or_function_type_nonnullable);
7495 EXPECT_SUBTYPE(closure_type_legacy, future_or_function_type_nullable);
7496 EXPECT_SUBTYPE(closure_type_legacy, future_or_function_type_legacy);
7497 EXPECT_SUBTYPE(closure_type_legacy, future_or_function_type_nonnullable);
7498 EXPECT_SUBTYPE(closure_type_nullable, future_or_function_type_nullable);
7499 EXPECT_SUBTYPE(closure_type_nullable, future_or_function_type_legacy);
7501 future_or_function_type_nonnullable);
7502}
7503
7505 const auto& type_object = Type::Handle(
7506 IsolateGroup::Current()->object_store()->non_nullable_object_type());
7507
7508 auto& type_function_int_nullary =
7509 FunctionType::Handle(FunctionType::New(0, Nullability::kNonNullable));
7510 type_function_int_nullary.set_result_type(Type::Handle(Type::IntType()));
7512
7513 auto& type_nullable_function_int_nullary =
7514 FunctionType::Handle(type_function_int_nullary.ToNullability(
7515 Nullability::kNullable, Heap::kOld));
7517
7520}
7521
7522#undef EXPECT_NOT_SUBTYPE
7523#undef EXPECT_SUBTYPE
7524
7526 const AbstractType& expected,
7527 const AbstractType& got,
7528 TypeEquality kind) {
7529 if (got.IsEquivalent(expected, kind)) return;
7531 buffer.AddString(
"Expected type ");
7532 expected.PrintName(Object::kScrubbedName, &
buffer);
7533 buffer.AddString(
", got ");
7534 got.PrintName(Object::kScrubbedName, &
buffer);
7535 expect.Fail(
"%s",
buffer.buffer());
7536}
7537
7538#define EXPECT_TYPES_EQUAL(expected, got) \
7539 ExpectTypesEquivalent(Expect(__FILE__, __LINE__), expected, got, \
7540 TypeEquality::kCanonical);
7541
7543 const char* kScript = R"(
7544 class B<T> {}
7545 class A1<X, Y> implements B<List<Y>> {}
7546 class A2<X, Y> extends A1<Y, X> {}
7547 )";
7548 Dart_Handle api_lib = TestCase::LoadTestScript(kScript, nullptr);
7550 TransitionNativeToVM transition(thread);
7551 Zone* const zone = thread->zone();
7552
7553 const auto& root_lib =
7554 Library::CheckedHandle(zone, Api::UnwrapHandle(api_lib));
7555 EXPECT(!root_lib.IsNull());
7556 const auto& class_b = Class::Handle(zone,
GetClass(root_lib,
"B"));
7557 const auto& class_a1 = Class::Handle(zone,
GetClass(root_lib,
"A1"));
7558 const auto& class_a2 = Class::Handle(zone,
GetClass(root_lib,
"A2"));
7559
7560 const auto& core_lib = Library::Handle(zone, Library::CoreLibrary());
7561 const auto& class_list = Class::Handle(zone,
GetClass(core_lib,
"List"));
7562
7563 const auto& decl_type_b = Type::Handle(zone, class_b.DeclarationType());
7564 const auto& decl_type_list = Type::Handle(zone, class_list.DeclarationType());
7565 const auto& null_tav = Object::null_type_arguments();
7566
7567
7568 {
7569 const auto& decl_type_a1 = Type::Handle(zone, class_a1.DeclarationType());
7570 const auto& decl_type_args_a1 =
7571 TypeArguments::Handle(zone, decl_type_a1.arguments());
7572 const auto& type_arg_a1_y =
7573 TypeParameter::CheckedHandle(zone, decl_type_args_a1.TypeAt(1));
7574 auto& tav_a1_y = TypeArguments::Handle(TypeArguments::New(1));
7575 tav_a1_y.SetTypeAt(0, type_arg_a1_y);
7576 tav_a1_y = tav_a1_y.Canonicalize(thread);
7577 auto& type_list_a1_y = Type::CheckedHandle(
7578 zone, decl_type_list.InstantiateFrom(tav_a1_y, null_tav, kAllFree,
7579 Heap::kNew));
7580 type_list_a1_y ^= type_list_a1_y.Canonicalize(thread);
7581 auto& tav_list_a1_y = TypeArguments::Handle(TypeArguments::New(1));
7582 tav_list_a1_y.SetTypeAt(0, type_list_a1_y);
7583 tav_list_a1_y = tav_list_a1_y.Canonicalize(thread);
7584 auto& type_b_list_a1_y = Type::CheckedHandle(
7585 zone, decl_type_b.InstantiateFrom(tav_list_a1_y, null_tav, kAllFree,
7586 Heap::kNew));
7587 type_b_list_a1_y ^= type_b_list_a1_y.Canonicalize(thread);
7588
7589 const auto& inst_b_a1 =
7590 Type::Handle(zone, class_a1.GetInstantiationOf(zone, class_b));
7591 EXPECT(!inst_b_a1.IsNull());
7593 }
7594
7595
7596 {
7597 const auto& decl_type_a2 = Type::Handle(zone, class_a2.DeclarationType());
7598 const auto& decl_type_args_a2 =
7599 TypeArguments::Handle(zone, decl_type_a2.arguments());
7600 const auto& type_arg_a2_x =
7601 TypeParameter::CheckedHandle(zone, decl_type_args_a2.TypeAt(0));
7602 auto& tav_a2_x = TypeArguments::Handle(TypeArguments::New(1));
7603 tav_a2_x.SetTypeAt(0, type_arg_a2_x);
7604 tav_a2_x = tav_a2_x.Canonicalize(thread);
7605 auto& type_list_a2_x = Type::CheckedHandle(
7606 zone, decl_type_list.InstantiateFrom(tav_a2_x, null_tav, kAllFree,
7607 Heap::kNew));
7608 type_list_a2_x ^= type_list_a2_x.Canonicalize(thread);
7609 auto& tav_list_a2_x = TypeArguments::Handle(TypeArguments::New(1));
7610 tav_list_a2_x.SetTypeAt(0, type_list_a2_x);
7611 tav_list_a2_x = tav_list_a2_x.Canonicalize(thread);
7612 auto& type_b_list_a2_x = Type::CheckedHandle(
7613 zone, decl_type_b.InstantiateFrom(tav_list_a2_x, null_tav, kAllFree,
7614 Heap::kNew));
7615 type_b_list_a2_x ^= type_b_list_a2_x.Canonicalize(thread);
7616
7617 const auto& inst_b_a2 =
7618 Type::Handle(zone, class_a2.GetInstantiationOf(zone, class_b));
7619 EXPECT(!inst_b_a2.IsNull());
7621 }
7622}
7623
7624#undef EXPECT_TYPES_EQUAL
7625
7626#define EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(expected, got) \
7627 ExpectTypesEquivalent(Expect(__FILE__, __LINE__), expected, got, \
7628 TypeEquality::kSyntactical);
7629
7631 Nullability nullability) {
7632 const auto& async_lib = Library::Handle(Library::AsyncLibrary());
7633 const auto& future_or_class =
7634 Class::Handle(async_lib.LookupClass(Symbols::FutureOr()));
7635 const auto& tav = TypeArguments::Handle(TypeArguments::New(1));
7636 tav.SetTypeAt(0, param);
7638 AbstractType::Handle(Type::New(future_or_class, tav, nullability));
7639 return Type::RawCast(
7640 ClassFinalizer::FinalizeType(
type, ClassFinalizer::kFinalize));
7641}
7642
7644 Nullability nullability) {
7645 ObjectStore* const object_store = IsolateGroup::Current()->object_store();
7646 const auto& future_class = Class::Handle(object_store->future_class());
7647 const auto& tav = TypeArguments::Handle(TypeArguments::New(1));
7648 tav.SetTypeAt(0, param);
7649 const auto&
type = Type::Handle(Type::New(future_class, tav, nullability));
7650 return Type::RawCast(
7651 ClassFinalizer::FinalizeType(
type, ClassFinalizer::kFinalize));
7652}
7653
7655
7656
7657
7658 ObjectStore* const object_store = IsolateGroup::Current()->object_store();
7659
7660 auto normalized_future_or = [&](const AbstractType& param,
7663 return type.NormalizeFutureOrType(Heap::kNew);
7664 };
7665
7666
7667
7668
7669 {
7670 const auto&
type = AbstractType::Handle(normalized_future_or(
7671 Object::dynamic_type(), Nullability::kNonNullable));
7673 }
7674
7675 {
7676 const auto&
type = AbstractType::Handle(
7677 normalized_future_or(Object::void_type(), Nullability::kNonNullable));
7679 }
7680
7681 {
7682 const auto& type_nullable_object =
7683 Type::Handle(object_store->nullable_object_type());
7684 const auto&
type = AbstractType::Handle(
7685 normalized_future_or(type_nullable_object, Nullability::kNonNullable));
7687 }
7688
7689
7690
7691 {
7692 const auto& type_non_nullable_object =
7693 Type::Handle(object_store->non_nullable_object_type());
7694 const auto&
type = AbstractType::Handle(normalized_future_or(
7695 type_non_nullable_object, Nullability::kNonNullable));
7697 }
7698
7699
7700
7701 {
7702 const auto& type_legacy_object =
7703 Type::Handle(object_store->legacy_object_type());
7704 const auto&
type = AbstractType::Handle(
7705 normalized_future_or(type_legacy_object, Nullability::kNonNullable));
7707 }
7708
7709
7710
7711 {
7712 const auto& type_never = Type::Handle(object_store->never_type());
7713 const auto& expected =
7715 const auto& got = AbstractType::Handle(
7716 normalized_future_or(type_never, Nullability::kNonNullable));
7718 }
7719
7720
7721
7722 {
7723 const auto& type_null = Type::Handle(object_store->null_type());
7724 const auto& expected =
7726 const auto& got = AbstractType::Handle(
7727 normalized_future_or(type_null, Nullability::kNonNullable));
7729 }
7730
7731
7732
7733
7734
7735
7736
7737
7738 {
7739 const auto& type_nullable_int =
7740 Type::Handle(object_store->nullable_int_type());
7741 const auto& expected = Type::Handle(
7743 const auto& got = AbstractType::Handle(
7744 normalized_future_or(type_nullable_int, Nullability::kNullable));
7746 }
7747}
7748
7749TEST_CASE(AbstractType_InstantiatedFutureOrIsNormalized) {
7750 const char* kScript = R"(
7751import 'dart:async';
7752
7753FutureOr<T>? foo<T>() { return null; }
7754FutureOr<T?> bar<T>() { return null; }
7755)";
7756
7757 Dart_Handle api_lib = TestCase::LoadTestScript(kScript, nullptr);
7759 TransitionNativeToVM transition(thread);
7760 Zone* const zone = thread->zone();
7761 ObjectStore* const object_store = IsolateGroup::Current()->object_store();
7762
7763 const auto& null_tav = Object::null_type_arguments();
7764 auto instantiate_future_or =
7765 [&](const AbstractType& generic,
7766 const AbstractType& param) -> AbstractTypePtr {
7767 const auto& tav = TypeArguments::Handle(TypeArguments::New(1));
7768 tav.SetTypeAt(0, param);
7769 return generic.InstantiateFrom(null_tav, tav, kCurrentAndEnclosingFree,
7770 Heap::kNew);
7771 };
7772
7773 const auto& root_lib =
7774 Library::CheckedHandle(zone, Api::UnwrapHandle(api_lib));
7775 EXPECT(!root_lib.IsNull());
7776 const auto& foo = Function::Handle(zone,
GetFunction(root_lib,
"foo"));
7777 const auto& bar = Function::Handle(zone,
GetFunction(root_lib,
"bar"));
7778 const auto& foo_sig = FunctionType::Handle(zone, foo.signature());
7779 const auto& bar_sig = FunctionType::Handle(zone, bar.signature());
7780
7781 const auto& nullable_future_or_T =
7782 AbstractType::Handle(zone, foo_sig.result_type());
7783 const auto& future_or_nullable_T =
7784 AbstractType::Handle(zone, bar_sig.result_type());
7785
7786 const auto& type_nullable_object =
7787 Type::Handle(object_store->nullable_object_type());
7788 const auto& type_non_nullable_object =
7789 Type::Handle(object_store->non_nullable_object_type());
7790 const auto& type_legacy_object =
7791 Type::Handle(object_store->legacy_object_type());
7792
7793
7794
7795
7796
7797 {
7798 const auto& got = AbstractType::Handle(
7799 instantiate_future_or(nullable_future_or_T, Object::dynamic_type()));
7801 }
7802
7803 {
7804 const auto& got = AbstractType::Handle(
7805 instantiate_future_or(nullable_future_or_T, Object::void_type()));
7807 }
7808
7809 {
7810 const auto& got = AbstractType::Handle(
7811 instantiate_future_or(nullable_future_or_T, type_nullable_object));
7813 }
7814
7815
7816
7817 {
7818 const auto& got = AbstractType::Handle(
7819 instantiate_future_or(future_or_nullable_T, Object::dynamic_type()));
7821 }
7822
7823 {
7824 const auto& got = AbstractType::Handle(
7825 instantiate_future_or(future_or_nullable_T, Object::void_type()));
7827 }
7828
7829 {
7830 const auto& got = AbstractType::Handle(
7831 instantiate_future_or(future_or_nullable_T, type_nullable_object));
7833 }
7834
7835
7836
7837 {
7838 const auto& got = AbstractType::Handle(
7839 instantiate_future_or(future_or_nullable_T, type_non_nullable_object));
7841 }
7842
7843
7844
7845 {
7846 const auto& got = AbstractType::Handle(
7847 instantiate_future_or(future_or_nullable_T, type_legacy_object));
7849 }
7850
7851
7852
7853 {
7854 const auto& got = AbstractType::Handle(
7855 instantiate_future_or(nullable_future_or_T, type_non_nullable_object));
7857 }
7858
7859
7860
7861 {
7862 const auto& got = AbstractType::Handle(
7863 instantiate_future_or(nullable_future_or_T, type_legacy_object));
7865 }
7866
7867 const auto& type_never = Type::Handle(object_store->never_type());
7868 const auto& type_null = Type::Handle(object_store->null_type());
7869
7870
7871
7872 {
7873 const auto& expected =
7875 const auto& got = AbstractType::Handle(
7876 instantiate_future_or(future_or_nullable_T, type_never));
7878 }
7879
7880
7881
7882 {
7883 const auto& expected =
7885 const auto& got = AbstractType::Handle(
7886 instantiate_future_or(nullable_future_or_T, type_never));
7888 }
7889
7890
7891
7892 {
7893 const auto& expected =
7895 const auto& got = AbstractType::Handle(
7896 instantiate_future_or(future_or_nullable_T, type_null));
7898 }
7899
7900
7901
7902 {
7903 const auto& expected =
7905 const auto& got = AbstractType::Handle(
7906 instantiate_future_or(nullable_future_or_T, type_null));
7908 }
7909
7910 const auto& type_nullable_int =
7911 Type::Handle(object_store->nullable_int_type());
7912 const auto& type_non_nullable_int =
7913 Type::Handle(object_store->non_nullable_int_type());
7914
7915
7916
7917 {
7918 const auto& expected = Type::Handle(
7920 const auto& got = AbstractType::Handle(
7921 instantiate_future_or(future_or_nullable_T, type_non_nullable_int));
7923 }
7924
7925
7926
7927 {
7928 const auto& expected = Type::Handle(
7930 const auto& got = AbstractType::Handle(
7931 instantiate_future_or(future_or_nullable_T, type_nullable_int));
7933 }
7934
7935
7936
7937 {
7938 const auto& expected = Type::Handle(
7940 const auto& got = AbstractType::Handle(
7941 instantiate_future_or(nullable_future_or_T, type_nullable_int));
7943 }
7944
7945
7946
7947 {
7948 const auto& expected = Type::Handle(
7950 const auto& got = AbstractType::Handle(
7951 instantiate_future_or(nullable_future_or_T, type_non_nullable_int));
7953 }
7954}
7955
7956#define __ assembler->
7957
7959 __ EnterDartFrame(0);
7960
7961
7962 const intptr_t uninstantiated_offset =
7963 (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize;
7964 const intptr_t inst_type_args_offset =
7965 (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize;
7966 const intptr_t fun_type_args_offset =
7967 (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize;
7968
7969 __ LoadMemoryValue(InstantiationABI::kUninstantiatedTypeArgumentsReg, FPREG,
7970 uninstantiated_offset);
7971 __ LoadMemoryValue(InstantiationABI::kInstantiatorTypeArgumentsReg, FPREG,
7972 inst_type_args_offset);
7973 __ LoadMemoryValue(InstantiationABI::kFunctionTypeArgumentsReg, FPREG,
7974 fun_type_args_offset);
7975
7976 __ Call(StubCode::InstantiateTypeArguments());
7977
7978
7979 __ MoveRegister(CallingConventions::kReturnReg,
7980 InstantiationABI::kResultTypeArgumentsReg);
7981 __ LeaveDartFrame();
7983}
7984
7985#undef __
7986
7988 Zone* const zone = thread->zone();
7989 const auto& klass = Class::Handle(
7990 zone, thread->isolate_group()->class_table()->At(kInstanceCid));
7991 const auto& symbol = String::Handle(
7992 zone, Symbols::New(thread, OS::SCreate(zone, "InstantiateTAVTest")));
7993 const auto& signature = FunctionType::Handle(zone, FunctionType::New());
7994 const auto& function = Function::Handle(
7995 zone, Function::New(signature, symbol, UntaggedFunction::kRegularFunction,
7996 false, false, false, false, false, klass,
7997 TokenPosition::kNoSource));
7998
7999 compiler::ObjectPoolBuilder pool_builder;
8000 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
8001 compiler::Assembler assembler(&pool_builder);
8003 const Code& invoke_instantiate_tav = Code::Handle(
8004 Code::FinalizeCodeAndNotify("InstantiateTAV", nullptr, &assembler,
8005 Code::PoolAttachment::kNotAttachPool,
8006 false));
8007
8009 ObjectPool::Handle(zone, ObjectPool::NewFromBuilder(pool_builder));
8010 invoke_instantiate_tav.set_object_pool(
pool.ptr());
8011 invoke_instantiate_tav.set_owner(function);
8012 invoke_instantiate_tav.set_exception_handlers(
8013 ExceptionHandlers::Handle(zone, ExceptionHandlers::New(0)));
8014#if defined(TARGET_ARCH_IA32)
8015 EXPECT_EQ(0,
pool.Length());
8016#else
8017 EXPECT_EQ(1,
pool.Length());
8018#endif
8019 return invoke_instantiate_tav.ptr();
8020}
8021
8022#if !defined(PRODUCT)
8023
8025#endif
8026
8029 buffer.AddString(
"class D<T> {}\n");
8030 for (intptr_t i = 0; i < num_classes; i++) {
8031 buffer.Printf(
"class C%" Pd " { String toString() => 'C%" Pd "'; }\n", i,
8032 i);
8033 }
8034 buffer.AddString(
"main() {\n");
8035 for (intptr_t i = 0; i < num_classes; i++) {
8036 buffer.Printf(
" C%" Pd "().toString();\n", i);
8037 }
8039
8044
8045
8046 EXPECT(IsolateGroup::Current()->class_table()->NumCids() > num_classes);
8047
8048 TransitionNativeToVM transition(thread);
8049 Zone* const zone = thread->zone();
8050
8051 const auto& root_lib =
8052 Library::CheckedHandle(zone, Api::UnwrapHandle(api_lib));
8053 EXPECT(!root_lib.IsNull());
8054
8055 const auto& class_d = Class::Handle(zone,
GetClass(root_lib,
"D"));
8056 ASSERT(!class_d.IsNull());
8057 const auto& decl_type_d = Type::Handle(zone, class_d.DeclarationType());
8058 const auto& decl_type_d_type_args =
8059 TypeArguments::Handle(zone, decl_type_d.arguments());
8060
8061 EXPECT(!decl_type_d_type_args.HasInstantiations());
8062
8063 auto& class_c = Class::Handle(zone);
8064 auto& decl_type_c = Type::Handle(zone);
8065 auto& instantiator_type_args = TypeArguments::Handle(zone);
8066 const auto& function_type_args = Object::null_type_arguments();
8067 auto& result_type_args = TypeArguments::Handle(zone);
8068 auto& result_type = AbstractType::Handle(zone);
8069
8070
8071 auto& first_instantiator_type_args = TypeArguments::Handle(zone);
8072
8073 const auto& invoke_instantiate_tav =
8075 const auto& invoke_instantiate_tav_arguments =
8076 Array::Handle(zone, Array::New(3));
8077 const auto& invoke_instantiate_tav_args_descriptor =
8078 Array::Handle(zone, ArgumentsDescriptor::NewBoxed(0, 3));
8079 for (intptr_t i = 0; i < num_classes; ++i) {
8080 const bool updated_cache_is_linear =
8081 i < TypeArguments::Cache::kMaxLinearCacheEntries;
8082 auto const name = OS::SCreate(zone,
"C%" Pd "", i);
8084 ASSERT(!class_c.IsNull());
8085 decl_type_c = class_c.DeclarationType();
8086 instantiator_type_args = TypeArguments::New(1);
8087 instantiator_type_args.SetTypeAt(0, decl_type_c);
8088 instantiator_type_args = instantiator_type_args.Canonicalize(thread);
8089
8090#if !defined(PRODUCT)
8091
8092
8093
8094
8096#endif
8097
8098
8099 intptr_t old_capacity;
8100 {
8101 SafepointMutexLocker ml(
8102 thread->isolate_group()->type_arguments_canonicalization_mutex());
8103 TypeArguments::Cache
cache(zone, decl_type_d_type_args);
8104 EXPECT_EQ(i,
cache.NumOccupied());
8105 auto loc =
8106 cache.FindKeyOrUnused(instantiator_type_args, function_type_args);
8108 old_capacity =
cache.NumEntries();
8109 }
8110
8111 decl_type_d_type_args.InstantiateAndCanonicalizeFrom(instantiator_type_args,
8112 function_type_args);
8113
8114
8115 TypeArguments::Cache::KeyLocation loc;
8116 bool storage_changed;
8117 {
8118 SafepointMutexLocker ml(
8119 thread->isolate_group()->type_arguments_canonicalization_mutex());
8120 TypeArguments::Cache
cache(zone, decl_type_d_type_args);
8121 EXPECT_EQ(i + 1,
cache.NumOccupied());
8122
8124 loc =
cache.FindKeyOrUnused(instantiator_type_args, function_type_args);
8126 storage_changed =
cache.NumEntries() != old_capacity;
8127 }
8128
8129#if defined(TARGET_ARCH_IA32)
8130 const bool stub_checks_hash_caches = false;
8131#else
8132 const bool stub_checks_hash_caches = true;
8133#endif
8134
8135
8136 if (updated_cache_is_linear || stub_checks_hash_caches) {
8137 invoke_instantiate_tav_arguments.SetAt(0, decl_type_d_type_args);
8138 invoke_instantiate_tav_arguments.SetAt(1, instantiator_type_args);
8139 invoke_instantiate_tav_arguments.SetAt(2, function_type_args);
8140 result_type_args ^= DartEntry::InvokeCode(
8141 invoke_instantiate_tav, invoke_instantiate_tav_args_descriptor,
8142 invoke_instantiate_tav_arguments, thread);
8143 EXPECT_EQ(1, result_type_args.Length());
8144 result_type = result_type_args.TypeAt(0);
8146 }
8147
8148#if !defined(PRODUCT)
8149
8150
8152#endif
8153
8154 result_type_args = decl_type_d_type_args.InstantiateAndCanonicalizeFrom(
8155 instantiator_type_args, function_type_args);
8156 result_type = result_type_args.TypeAt(0);
8158
8159
8160 {
8161 SafepointMutexLocker ml(
8162 thread->isolate_group()->type_arguments_canonicalization_mutex());
8163 TypeArguments::Cache
cache(zone, decl_type_d_type_args);
8164 EXPECT_EQ(i + 1,
cache.NumOccupied());
8165 auto const loc2 =
8166 cache.FindKeyOrUnused(instantiator_type_args, function_type_args);
8168 EXPECT_EQ(loc.entry, loc2.entry);
8169 }
8170
8171 if (i == 0) {
8172 first_instantiator_type_args = instantiator_type_args.ptr();
8173 } else if (storage_changed) {
8174
8175 SafepointMutexLocker ml(
8176 thread->isolate_group()->type_arguments_canonicalization_mutex());
8177 TypeArguments::Cache
cache(zone, decl_type_d_type_args);
8178 EXPECT_EQ(i + 1,
cache.NumOccupied());
8179
8180 EXPECT(i < TypeArguments::Cache::kMaxLinearCacheEntries ?
cache.IsLinear()
8182 auto const loc =
8183 cache.FindKeyOrUnused(instantiator_type_args, function_type_args);
8185 }
8186 }
8187}
8188
8189
8190
8191TEST_CASE(TypeArguments_Cache_SomeInstantiations) {
8193 2 * TypeArguments::Cache::kMaxLinearCacheEntries);
8194}
8195
8196
8197
8198#if !defined(DEBUG) && !defined(USING_MEMORY_SANITIZER) && \
8199 !defined(USING_THREAD_SANITIZER) && !defined(USING_LEAK_SANITIZER) && \
8200 !defined(USING_UNDEFINED_BEHAVIOR_SANITIZER) && !defined(USING_SIMULATOR)
8201TEST_CASE(TypeArguments_Cache_ManyInstantiations) {
8202 const intptr_t kNumClasses = 100000;
8203 static_assert(kNumClasses > TypeArguments::Cache::kMaxLinearCacheEntries,
8204 "too few classes to trigger change to a hash-based cache");
8206}
8207#endif
8208
8209#undef EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT
8210
8212 const SubtypeTestCache& cache) {
8213 const intptr_t used_inputs =
cache.num_inputs();
8214 if (used_inputs < 1 || used_inputs > SubtypeTestCache::kMaxInputs) {
8215 FAIL(
"Invalid number of used inputs: %" Pd "", used_inputs);
8216 return;
8217 }
8218 const auto& array = Array::Handle(zone,
cache.cache());
8219 for (intptr_t i = 0; i <
cache.NumEntries(); i++) {
8220 if (!
cache.IsOccupied(i))
continue;
8221 const intptr_t entry_start = i * SubtypeTestCache::kTestEntryLength;
8222 {
8223 const intptr_t
cid =
8224 array.At(entry_start + SubtypeTestCache::kTestResult)
8225 ->GetClassIdMayBeSmi();
8226 EXPECT(cid == kNullCid || cid == kBoolCid);
8227 }
8228
8229
8230 int check_ordering = used_inputs;
8231
8232
8233#define USED_INPUT_CASE(Input, ExpectedCids) \
8234 case (Input) + 1: { \
8235 RELEASE_ASSERT((Input) + 1 == check_ordering); \
8236 const intptr_t cid = \
8237 array.At(entry_start + (Input))->GetClassIdMayBeSmi(); \
8238 if (!(ExpectedCids)) { \
8239 FAIL("expected: " #ExpectedCids ", got: cid %" Pd "", cid); \
8240 } \
8241 --check_ordering; \
8242 }
8243
8244 switch (used_inputs) {
8248 USED_INPUT_CASE(SubtypeTestCache::kInstanceDelayedFunctionTypeArguments,
8249 cid == kNullCid || cid == kTypeArgumentsCid);
8251 USED_INPUT_CASE(SubtypeTestCache::kInstanceParentFunctionTypeArguments,
8252 cid == kNullCid || cid == kTypeArgumentsCid);
8255 cid == kNullCid || cid == kTypeArgumentsCid);
8258 cid == kNullCid || cid == kTypeArgumentsCid);
8261 cid == kNullCid || cid == kTypeArgumentsCid);
8264 cid == kSmiCid || cid == kFunctionTypeCid);
8265 break;
8266 default:
8268 }
8269
8270#undef USED_INPUT_CASE
8272
8273
8274 for (intptr_t i = used_inputs; i < SubtypeTestCache::kMaxInputs; i++) {
8275
8276
8277
8278
8279 const intptr_t
cid = array.At(entry_start + i)->GetClassIdMayBeSmi();
8280 EXPECT(cid == kSmiCid || cid == kNullCid);
8281 }
8282 }
8283}
8284
8286 Thread* thread,
8287 const SubtypeTestCache& cache,
8288 const Object& instance_class_id_or_signature,
8289 const AbstractType& destination_type,
8290 const TypeArguments& instance_type_arguments,
8291 const TypeArguments& instantiator_type_arguments,
8292 const TypeArguments& function_type_arguments,
8293 const TypeArguments& parent_function_type_arguments,
8294 const TypeArguments& delayed_type_arguments,
8295 const Bool& expected_result,
8296 Bool* got_result) {
8297 const auto& tav_null = TypeArguments::null_type_arguments();
8298 const intptr_t num_inputs =
cache.num_inputs();
8299 const bool was_hash =
cache.IsHash();
8300 const intptr_t old_count =
cache.NumberOfChecks();
8301 intptr_t expected_index, got_index;
8302
8304 instance_class_id_or_signature, destination_type, instance_type_arguments,
8305 instantiator_type_arguments, function_type_arguments,
8306 parent_function_type_arguments, delayed_type_arguments, nullptr,
8307 nullptr));
8308 {
8309 SafepointMutexLocker ml(
8310 thread->isolate_group()->subtype_test_cache_mutex());
8311 expected_index =
8312 cache.AddCheck(instance_class_id_or_signature, destination_type,
8313 instance_type_arguments, instantiator_type_arguments,
8314 function_type_arguments, parent_function_type_arguments,
8315 delayed_type_arguments, expected_result);
8316 EXPECT(expected_index >= 0);
8317 }
8318 EXPECT_EQ(old_count + 1,
cache.NumberOfChecks());
8319 EXPECT(
cache.HasCheck(instance_class_id_or_signature, destination_type,
8320 instance_type_arguments, instantiator_type_arguments,
8321 function_type_arguments, parent_function_type_arguments,
8322 delayed_type_arguments, &got_index, got_result));
8323 EXPECT_EQ(expected_index, got_index);
8324 EXPECT(got_result->ptr() == expected_result.ptr());
8325 if (num_inputs < (SubtypeTestCache::kInstanceTypeArguments + 1)) {
8326
8327 EXPECT(
cache.HasCheck(instance_class_id_or_signature, destination_type,
8328 tav_null, instantiator_type_arguments,
8329 function_type_arguments,
8330 parent_function_type_arguments,
8331 delayed_type_arguments, &got_index, got_result));
8332 EXPECT_EQ(expected_index, got_index);
8333 EXPECT(got_result->ptr() == expected_result.ptr());
8334 } else {
8335
8337 instance_class_id_or_signature, destination_type, tav_null,
8338 instantiator_type_arguments, function_type_arguments,
8339 parent_function_type_arguments, delayed_type_arguments,
8340 nullptr, nullptr));
8341 }
8342 if (num_inputs < (SubtypeTestCache::kInstantiatorTypeArguments + 1)) {
8343
8344 EXPECT(
cache.HasCheck(instance_class_id_or_signature, destination_type,
8345 instance_type_arguments, tav_null,
8346 function_type_arguments,
8347 parent_function_type_arguments,
8348 delayed_type_arguments, &got_index, got_result));
8349 EXPECT_EQ(expected_index, got_index);
8350 EXPECT(got_result->ptr() == expected_result.ptr());
8351 } else {
8352
8354 instance_class_id_or_signature, destination_type,
8355 instance_type_arguments, tav_null, function_type_arguments,
8356 parent_function_type_arguments, delayed_type_arguments,
8357 nullptr, nullptr));
8358 }
8359 if (num_inputs < (SubtypeTestCache::kFunctionTypeArguments + 1)) {
8360
8361 EXPECT(
cache.HasCheck(instance_class_id_or_signature, destination_type,
8362 instance_type_arguments, instantiator_type_arguments,
8363 tav_null, parent_function_type_arguments,
8364 delayed_type_arguments, &got_index, got_result));
8365 EXPECT_EQ(expected_index, got_index);
8366 EXPECT(got_result->ptr() == expected_result.ptr());
8367 } else {
8368
8369 EXPECT(!
cache.HasCheck(instance_class_id_or_signature, destination_type,
8370 instance_type_arguments, instantiator_type_arguments,
8371 tav_null, parent_function_type_arguments,
8372 delayed_type_arguments,
8373 nullptr, nullptr));
8374 }
8375 if (num_inputs <
8376 (SubtypeTestCache::kInstanceParentFunctionTypeArguments + 1)) {
8377
8378 EXPECT(
cache.HasCheck(instance_class_id_or_signature, destination_type,
8379 instance_type_arguments, instantiator_type_arguments,
8380 function_type_arguments, tav_null,
8381 delayed_type_arguments, &got_index, got_result));
8382 EXPECT_EQ(expected_index, got_index);
8383 EXPECT(got_result->ptr() == expected_result.ptr());
8384 } else {
8385
8386 EXPECT(!
cache.HasCheck(instance_class_id_or_signature, destination_type,
8387 instance_type_arguments, instantiator_type_arguments,
8388 function_type_arguments, tav_null,
8389 delayed_type_arguments, nullptr,
8390 nullptr));
8391 }
8392 if (num_inputs <
8393 (SubtypeTestCache::kInstanceDelayedFunctionTypeArguments + 1)) {
8394
8395 EXPECT(
cache.HasCheck(instance_class_id_or_signature, destination_type,
8396 instance_type_arguments, instantiator_type_arguments,
8397 function_type_arguments,
8398 parent_function_type_arguments, tav_null, &got_index,
8399 got_result));
8400 EXPECT_EQ(expected_index, got_index);
8401 EXPECT(got_result->ptr() == expected_result.ptr());
8402 } else {
8403
8404 EXPECT(!
cache.HasCheck(instance_class_id_or_signature, destination_type,
8405 instance_type_arguments, instantiator_type_arguments,
8406 function_type_arguments,
8407 parent_function_type_arguments, tav_null,
8408 nullptr, nullptr));
8409 }
8410
8412 if (num_inputs < (SubtypeTestCache::kDestinationType + 1)) {
8413
8414 EXPECT(
cache.HasCheck(instance_class_id_or_signature, Object::void_type(),
8415 instance_type_arguments, instantiator_type_arguments,
8416 function_type_arguments,
8417 parent_function_type_arguments,
8418 delayed_type_arguments, &got_index, got_result));
8419 EXPECT_EQ(expected_index, got_index);
8420 EXPECT(got_result->ptr() == expected_result.ptr());
8421 } else {
8422
8423 EXPECT(!
cache.HasCheck(instance_class_id_or_signature, Object::void_type(),
8424 instance_type_arguments, instantiator_type_arguments,
8425 function_type_arguments,
8426 parent_function_type_arguments,
8427 delayed_type_arguments,
8428 nullptr, nullptr));
8429 }
8430
8432}
8433
8435 intptr_t num_classes,
8436 bool expect_hash) {
8438 buffer.AddString(
"class D {}\n");
8439 buffer.AddString(
"D createInstanceD() => D();");
8440 buffer.AddString(
"D Function() createClosureD() => () => D();\n");
8441 for (intptr_t i = 0; i < num_classes; i++) {
8442 buffer.Printf(R
"(class C%)" Pd R"( extends D {}
8443)"
8444 R"(C%)" Pd R"( createInstanceC%)" Pd R"(() => C%)" Pd
8445 R"(();
8446)"
8447 R"(C%)" Pd R"( Function() createClosureC%)" Pd
8448 R"(() => () => C%)" Pd
8449 R"(();
8450)",
8451 i, i, i, i, i, i, i);
8452 }
8453
8456
8457
8458 EXPECT(IsolateGroup::Current()->class_table()->NumCids() > num_classes);
8459
8460 TransitionNativeToVM transition(thread);
8461 Zone* const zone = thread->zone();
8462
8463 const auto& root_lib =
8464 Library::CheckedHandle(zone, Api::UnwrapHandle(api_lib));
8465 EXPECT(!root_lib.IsNull());
8466
8467 const auto& class_d = Class::Handle(zone,
GetClass(root_lib,
"D"));
8468 ASSERT(!class_d.IsNull());
8469 {
8470 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
8471 ClassFinalizer::FinalizeClass(class_d);
8472 }
8473 const auto& instance_d =
8474 Instance::CheckedHandle(zone,
Invoke(root_lib,
"createInstanceD"));
8475 auto& type_instance_d_int =
8476 Type::CheckedHandle(zone, instance_d.GetType(Heap::kNew));
8477 const auto& closure_d =
8478 Instance::CheckedHandle(zone,
Invoke(root_lib,
"createClosureD"));
8479 ASSERT(!closure_d.IsNull());
8480 auto& type_closure_d_int =
8481 FunctionType::CheckedHandle(zone, closure_d.GetType(Heap::kNew));
8482
8483
8484 const SubtypeTestCache* stcs[SubtypeTestCache::kMaxInputs];
8485 for (intptr_t i = 0; i < SubtypeTestCache::kMaxInputs; i++) {
8486 stcs[i] = &SubtypeTestCache::Handle(zone, SubtypeTestCache::New(i + 1));
8487 }
8488
8489 auto& class_c = Class::Handle(zone);
8490 auto& instance_c = Instance::Handle(zone);
8491 auto& closure_c = Closure::Handle(zone);
8492 auto& instance_class_id_or_signature = Object::Handle(zone);
8493
8494 auto& instance_type_arguments =
8495 TypeArguments::Handle(zone, TypeArguments::New(1));
8496 instance_type_arguments.SetTypeAt(0, Type::Handle(zone, Type::SmiType()));
8497 instance_type_arguments = instance_type_arguments.Canonicalize(thread);
8498 auto& instantiator_type_arguments =
8499 TypeArguments::Handle(zone, TypeArguments::New(1));
8500 instantiator_type_arguments.SetTypeAt(0, Type::Handle(zone, Type::IntType()));
8501 instantiator_type_arguments =
8502 instantiator_type_arguments.Canonicalize(thread);
8503 auto& function_type_arguments =
8504 TypeArguments::Handle(zone, TypeArguments::New(1));
8505 function_type_arguments.SetTypeAt(0, Type::Handle(zone, Type::Double()));
8506 function_type_arguments = function_type_arguments.Canonicalize(thread);
8507 auto& parent_function_type_arguments =
8508 TypeArguments::Handle(zone, TypeArguments::New(1));
8509 parent_function_type_arguments.SetTypeAt(
8510 0, Type::Handle(zone, Type::StringType()));
8511 parent_function_type_arguments =
8512 parent_function_type_arguments.Canonicalize(thread);
8513 auto& delayed_type_arguments =
8514 TypeArguments::Handle(zone, TypeArguments::New(1));
8515 delayed_type_arguments.SetTypeAt(0, Type::Handle(zone, Type::BoolType()));
8516 delayed_type_arguments = delayed_type_arguments.Canonicalize(thread);
8517 auto& got_result = Bool::Handle(zone);
8518 for (intptr_t i = 0; i < num_classes; ++i) {
8519
8520
8521 const auto& expected_result = (i % 2 == 0) ? Bool::True() : Bool::False();
8522
8523 auto const class_name = OS::SCreate(zone,
"C%" Pd "", i);
8524 class_c =
GetClass(root_lib, class_name);
8525 ASSERT(!class_c.IsNull());
8526 {
8527 SafepointWriteRwLocker ml(thread,
8528 thread->isolate_group()->program_lock());
8529 ClassFinalizer::FinalizeClass(class_c);
8530 }
8531 auto const instance_name = OS::SCreate(zone,
"createInstanceC%" Pd "", i);
8532 instance_c ^=
Invoke(root_lib, instance_name);
8533 EXPECT(!instance_c.IsClosure());
8534 instance_class_id_or_signature = Smi::New(instance_c.GetClassId());
8535
8536 for (intptr_t i = 0; i < 5; i++) {
8538 thread, *stcs[i], instance_class_id_or_signature, type_instance_d_int,
8539 instance_type_arguments, instantiator_type_arguments,
8540 function_type_arguments, parent_function_type_arguments,
8541 delayed_type_arguments, expected_result, &got_result);
8542 }
8543
8544 auto const function_name = OS::SCreate(zone,
"createClosureC%" Pd "", i);
8545 closure_c ^=
Invoke(root_lib, function_name);
8546
8547 instance_class_id_or_signature = closure_c.function();
8548 instance_class_id_or_signature =
8549 Function::Cast(instance_class_id_or_signature).signature();
8550
8551 for (intptr_t i = 5; i < SubtypeTestCache::kMaxInputs; i++) {
8553 thread, *stcs[i], instance_class_id_or_signature, type_closure_d_int,
8554 instance_type_arguments, instantiator_type_arguments,
8555 function_type_arguments, parent_function_type_arguments,
8556 delayed_type_arguments, expected_result, &got_result);
8557 }
8558 }
8559 for (intptr_t i = 0; i < SubtypeTestCache::kMaxInputs; i++) {
8561 EXPECT_EQ(expect_hash, stcs[i]->IsHash());
8562 }
8563}
8564
8567 false);
8568}
8569
8572 true);
8573}
8574
8575}
#define RELEASE_ASSERT(cond)
struct _Dart_Handle * Dart_Handle
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
#define FAIL(name, result)
static const uint8_t buffer[]
static CodePtr CreateInvokeInstantiateTypeArgumentsStub(Thread *thread)
static void GenerateInvokeInstantiateTAVStub(compiler::Assembler *assembler)
static void SubtypeTestCacheEntryTest(Thread *thread, const SubtypeTestCache &cache, const Object &instance_class_id_or_signature, const AbstractType &destination_type, const TypeArguments &instance_type_arguments, const TypeArguments &instantiator_type_arguments, const TypeArguments &function_type_arguments, const TypeArguments &parent_function_type_arguments, const TypeArguments &delayed_type_arguments, const Bool &expected_result, Bool *got_result)
static void ExpectTypesEquivalent(const Expect &expect, const AbstractType &expected, const AbstractType &got, TypeEquality kind)
bool IsConcreteTypeClassId(intptr_t index)
static void FinalizeAndCanonicalize(AbstractType *type)
const char *const class_name
ObjectPtr Invoke(const Library &lib, const char *name)
FunctionPtr GetFunction(const Library &lib, const char *name)
static void TypeArgumentsHashCacheTest(Thread *thread, intptr_t num_classes)
static void SubtypeTestCacheTest(Thread *thread, intptr_t num_classes, bool expect_hash)
static void SubtypeTestCacheCheckContents(Zone *zone, const SubtypeTestCache &cache)
ClassPtr GetClass(const Library &lib, const char *name)
bool TESTING_runtime_fail_on_existing_cache_entry
const char *const function_name
static TypePtr CreateFutureOrType(const AbstractType ¶m, Nullability nullability)
static TypePtr CreateFutureType(const AbstractType ¶m, Nullability nullability)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
#define EXPECT_SUBTYPE(sub, super)
#define USED_INPUT_CASE(Input, ExpectedCids)
#define EXPECT_TYPES_EQUAL(expected, got)
#define EXPECT_NOT_SUBTYPE(sub, super)
#define EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(expected, got)
#define ISOLATE_UNIT_TEST_CASE(name)
Dart_Handle NewString(const char *str)
#define EXPECT_VALID(handle)