Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Namespaces | Macros | Functions | Variables
object_test.cc File Reference
#include <limits>
#include <memory>
#include "include/dart_api.h"
#include "bin/builtin.h"
#include "bin/vmservice_impl.h"
#include "platform/globals.h"
#include "vm/class_finalizer.h"
#include "vm/closure_functions_cache.h"
#include "vm/code_descriptors.h"
#include "vm/compiler/assembler/assembler.h"
#include "vm/compiler/backend/il_test_helper.h"
#include "vm/compiler/compiler_state.h"
#include "vm/compiler/runtime_api.h"
#include "vm/dart_api_impl.h"
#include "vm/dart_entry.h"
#include "vm/debugger.h"
#include "vm/debugger_api_impl_test.h"
#include "vm/flags.h"
#include "vm/isolate.h"
#include "vm/message_handler.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/resolver.h"
#include "vm/simulator.h"
#include "vm/symbols.h"
#include "vm/tagged_pointer.h"
#include "vm/unit_test.h"
#include "vm/zone_text_buffer.h"

Go to the source code of this file.

Classes

class  dart::CodeTestHelper
 
class  dart::ToggleBreakpointTask
 
class  dart::ObjectAccumulator
 
struct  dart::TestResult
 

Namespaces

namespace  dart
 

Macros

#define Z   (thread->zone())
 
#define FINALIZER_CROSS_GEN_TEST_CASE(n)
 
#define REPEAT_512(V)
 
#define FINALIZER_NATIVE_CROSS_GEN_TEST_CASE(n)
 
#define EXPECT_SUBTYPE(sub, super)    CheckSubtypeRelation(Expect(__FILE__, __LINE__), sub, super, true);
 
#define EXPECT_NOT_SUBTYPE(sub, super)    CheckSubtypeRelation(Expect(__FILE__, __LINE__), sub, super, false);
 
#define EXPECT_TYPES_EQUAL(expected, got)
 
#define EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(expected, got)
 
#define __   assembler->
 
#define USED_INPUT_CASE(Input, ExpectedCids)
 

Functions

 dart::DECLARE_FLAG (bool, write_protect_code)
 
static ClassPtr dart::CreateDummyClass (const String &class_name, const Script &script)
 
 dart::ISOLATE_UNIT_TEST_CASE (Class)
 
 dart::ISOLATE_UNIT_TEST_CASE (SixtyThousandDartClasses)
 
 dart::ISOLATE_UNIT_TEST_CASE (TypeArguments)
 
 dart::TEST_CASE (Class_EndTokenPos)
 
 dart::ISOLATE_UNIT_TEST_CASE (InstanceClass)
 
 dart::ISOLATE_UNIT_TEST_CASE (Smi)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringCompareTo)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringEncodeIRI)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringDecodeIRI)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringDecodeIRIInvalid)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringIRITwoByte)
 
 dart::ISOLATE_UNIT_TEST_CASE (Mint)
 
 dart::ISOLATE_UNIT_TEST_CASE (Double)
 
 dart::ISOLATE_UNIT_TEST_CASE (Integer)
 
 dart::ISOLATE_UNIT_TEST_CASE (String)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringFormat)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringConcat)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringHashConcat)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringSubStringDifferentWidth)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringFromUtf8Literal)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringEqualsUtf8)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringEqualsUTF32)
 
 dart::ISOLATE_UNIT_TEST_CASE (EscapeSpecialCharactersOneByteString)
 
 dart::ISOLATE_UNIT_TEST_CASE (EscapeSpecialCharactersTwoByteString)
 
 dart::ISOLATE_UNIT_TEST_CASE (Symbol)
 
 dart::ISOLATE_UNIT_TEST_CASE (SymbolUnicode)
 
 dart::ISOLATE_UNIT_TEST_CASE (Bool)
 
 dart::ISOLATE_UNIT_TEST_CASE (Array)
 
 dart::ISOLATE_UNIT_TEST_CASE (Array_Grow)
 
 dart::ISOLATE_UNIT_TEST_CASE (EmptyInstantiationsCacheArray)
 
static void dart::TestIllegalArrayLength (intptr_t length)
 
 dart::TEST_CASE (ArrayLengthNegativeOne)
 
 dart::TEST_CASE (ArrayLengthSmiMin)
 
 dart::TEST_CASE (ArrayLengthOneTooMany)
 
 dart::TEST_CASE (ArrayLengthMaxElements)
 
static void dart::TestIllegalTypedDataLength (const char *class_name, intptr_t length)
 
 dart::TEST_CASE (Int8ListLengthNegativeOne)
 
 dart::TEST_CASE (Int8ListLengthSmiMin)
 
 dart::TEST_CASE (Int8ListLengthOneTooMany)
 
 dart::TEST_CASE (Int8ListLengthMaxElements)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringCodePointIterator)
 
 dart::ISOLATE_UNIT_TEST_CASE (StringCodePointIteratorRange)
 
 dart::ISOLATE_UNIT_TEST_CASE (GrowableObjectArray)
 
 dart::ISOLATE_UNIT_TEST_CASE (TypedData_Grow)
 
 dart::ISOLATE_UNIT_TEST_CASE (InternalTypedData)
 
 dart::ISOLATE_UNIT_TEST_CASE (ExternalTypedData)
 
 dart::ISOLATE_UNIT_TEST_CASE (Script)
 
 dart::ISOLATE_UNIT_TEST_CASE (Context)
 
 dart::ISOLATE_UNIT_TEST_CASE (ContextScope)
 
 dart::ISOLATE_UNIT_TEST_CASE (Closure)
 
 dart::ISOLATE_UNIT_TEST_CASE (ObjectPrinting)
 
 dart::ISOLATE_UNIT_TEST_CASE (CheckedHandle)
 
static LibraryPtr dart::CreateDummyLibrary (const String &library_name)
 
static FunctionPtr dart::CreateFunction (const char *name)
 
 dart::ISOLATE_UNIT_TEST_CASE (Code)
 
 dart::ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION (CodeImmutability, "Crash")
 
 dart::ISOLATE_UNIT_TEST_CASE (EmbedStringInCode)
 
 dart::ISOLATE_UNIT_TEST_CASE (EmbedSmiInCode)
 
 dart::ISOLATE_UNIT_TEST_CASE (ExceptionHandlers)
 
 dart::ISOLATE_UNIT_TEST_CASE (PcDescriptors)
 
 dart::ISOLATE_UNIT_TEST_CASE (PcDescriptorsLargeDeltas)
 
static ClassPtr dart::CreateTestClass (const char *name)
 
static FieldPtr dart::CreateTestField (const char *name)
 
 dart::ISOLATE_UNIT_TEST_CASE (ClassDictionaryIterator)
 
static FunctionPtr dart::GetDummyTarget (const char *name)
 
 dart::ISOLATE_UNIT_TEST_CASE (ICData)
 
 dart::ISOLATE_UNIT_TEST_CASE (SubtypeTestCache)
 
 dart::ISOLATE_UNIT_TEST_CASE (MegamorphicCache)
 
 dart::ISOLATE_UNIT_TEST_CASE (FieldTests)
 
bool dart::EqualsIgnoringPrivate (const String &name, const String &private_name)
 
 dart::ISOLATE_UNIT_TEST_CASE (EqualsIgnoringPrivate)
 
 dart::ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION (ArrayNew_Overflow_Crash, "Crash")
 
 dart::TEST_CASE (StackTraceFormat)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakProperty_PreserveRecurse)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakProperty_PreserveOne_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakProperty_PreserveTwo_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakProperty_PreserveTwoShared_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakProperty_PreserveOne_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakProperty_PreserveTwo_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakProperty_PreserveTwoShared_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakProperty_ClearOne_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakProperty_ClearTwoShared_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakProperty_ClearOne_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakProperty_ClearTwoShared_OldSpace)
 
static void dart::WeakReference_PreserveOne (Thread *thread, Heap::Space space)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakReference_PreserveOne_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakReference_PreserveOne_OldSpace)
 
static void dart::WeakReference_ClearOne (Thread *thread, Heap::Space space)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakReference_ClearOne_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakReference_ClearOne_OldSpace)
 
static void dart::WeakReference_Clear_ReachableThroughWeakProperty (Thread *thread, Heap::Space space)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakReference_Clear_ReachableThroughWeakProperty_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakReference_Clear_ReachableThroughWeakProperty_OldSpace)
 
static void dart::WeakReference_Preserve_ReachableThroughWeakProperty (Thread *thread, Heap::Space space)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakReference_Preserve_ReachableThroughWeakProperty_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakReference_Preserve_ReachableThroughWeakProperty_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakArray_New)
 
 dart::ISOLATE_UNIT_TEST_CASE (WeakArray_Old)
 
static int dart::NumEntries (const FinalizerEntry &entry, intptr_t acc=0)
 
static void dart::Finalizer_PreserveOne (Thread *thread, Heap::Space space, bool with_detach)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_PreserveNoDetachOne_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_PreserveNoDetachOne_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_PreserveWithDetachOne_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_PreserveWithDetachOne_OldSpace)
 
static void dart::Finalizer_ClearDetachOne (Thread *thread, Heap::Space space)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearDetachOne_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearDetachOne_OldSpace)
 
static void dart::Finalizer_ClearValueOne (Thread *thread, Heap::Space space, bool null_token)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearValueOne_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearValueOne_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearValueNullTokenOne_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearValueNullTokenOne_OldSpace)
 
static void dart::Finalizer_DetachOne (Thread *thread, Heap::Space space, bool clear_value)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_DetachOne_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_DetachOne_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_DetachAndClearValueOne_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_DetachAndClearValueOne_OldSpace)
 
static void dart::Finalizer_GcFinalizer (Thread *thread, Heap::Space space)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_GcFinalizer_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_GcFinalizer_OldSpace)
 
static void dart::Finalizer_TwoEntriesCrossGen (Thread *thread, Heap::Space *spaces, bool collect_old_space, bool collect_new_space, bool evacuate_new_space_and_collect_old_space, bool clear_value_1, bool clear_value_2, bool clear_detach_1, bool clear_detach_2)
 
static void dart::Finalizer_TwoEntries (Thread *thread, Heap::Space space, bool clear_value_1, bool clear_value_2, bool clear_detach_1, bool clear_detach_2)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearValueTwo_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearValueTwo_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearFirstValue_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearFirstValue_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearSecondValue_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearSecondValue_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_PreserveTwo_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_PreserveTwo_OldSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearDetachTwo_NewSpace)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_ClearDetachTwo_OldSpace)
 
static void dart::Finalizer_TwoEntriesCrossGen (Thread *thread, intptr_t test_i)
 
 dart::ISOLATE_UNIT_TEST_CASE (Finalizer_Regress_48843)
 
void dart::NativeFinalizer_TwoEntriesCrossGen_Finalizer (void *peer)
 
static void dart::NativeFinalizer_TwoEntriesCrossGen (Thread *thread, Heap::Space *spaces, bool collect_new_space, bool evacuate_new_space_and_collect_old_space, bool clear_value_1, bool clear_value_2, bool clear_detach_1, bool clear_detach_2)
 
static void dart::NativeFinalizer_TwoEntriesCrossGen (Thread *thread, intptr_t test_i)
 
 dart::TEST_CASE (IsIsolateUnsendable)
 
 dart::TEST_CASE (ImplementorCid)
 
 dart::ISOLATE_UNIT_TEST_CASE (MirrorReference)
 
static FunctionPtr dart::GetFunction (const Class &cls, const char *name)
 
static FunctionPtr dart::GetStaticFunction (const Class &cls, const char *name)
 
static FieldPtr dart::GetField (const Class &cls, const char *name)
 
 dart::ISOLATE_UNIT_TEST_CASE (FindClosureIndex)
 
 dart::ISOLATE_UNIT_TEST_CASE (FindInvocationDispatcherFunctionIndex)
 
static void dart::PrintMetadata (const char *name, const Object &data)
 
 dart::TEST_CASE (Metadata)
 
 dart::TEST_CASE (FunctionSourceFingerprint)
 
 dart::TEST_CASE (FunctionWithBreakpointNotInlined)
 
void dart::SetBreakpoint (Dart_NativeArguments args)
 
static Dart_NativeFunction dart::SetBreakpointResolver (Dart_Handle name, int argument_count, bool *auto_setup_scope)
 
 dart::TEST_CASE (DeoptimizeFramesWhenSettingBreakpoint)
 
 dart::TEST_CASE (DartAPI_BreakpointLockRace)
 
 dart::ISOLATE_UNIT_TEST_CASE (SpecialClassesHaveEmptyArrays)
 
 dart::ISOLATE_UNIT_TEST_CASE (ToCString)
 
 dart::ISOLATE_UNIT_TEST_CASE (PrintJSON)
 
 dart::ISOLATE_UNIT_TEST_CASE (PrintJSONPrimitives)
 
 dart::TEST_CASE (InstanceEquality)
 
 dart::TEST_CASE (HashCode)
 
static bool dart::HashCodeEqualsCanonicalizeHash (const char *value_script, uint32_t hashcode_canonicalize_vm=kCalculateCanonicalizeHash, bool check_identity=true, bool check_hashcode=true)
 
 dart::TEST_CASE (HashCode_Double)
 
 dart::TEST_CASE (HashCode_Mint)
 
 dart::TEST_CASE (HashCode_Null)
 
 dart::TEST_CASE (HashCode_Smi)
 
 dart::TEST_CASE (HashCode_String)
 
 dart::TEST_CASE (HashCode_Symbol)
 
 dart::TEST_CASE (HashCode_True)
 
 dart::TEST_CASE (HashCode_Type_Dynamic)
 
 dart::TEST_CASE (HashCode_Type_Int)
 
 dart::TEST_CASE (Map_iteration)
 
template<class LinkedHashBase >
static bool dart::LinkedHashBaseEqual (const LinkedHashBase &map1, const LinkedHashBase &map2, bool print_diff, bool check_data=true)
 
static MapPtr dart::ConstructImmutableMap (const Array &input_data, intptr_t used_data, const TypeArguments &type_arguments)
 
 dart::TEST_CASE (ConstMap_vm)
 
static bool dart::IsLinkedHashBase (const Object &object)
 
template<class LinkedHashBase , int kMutableCid, int kImmutableCid>
static void dart::HashBaseNonConstEqualsConst (const char *script, bool check_data=true)
 
static void dart::HashMapNonConstEqualsConst (const char *script, bool check_data=true)
 
static void dart::HashSetNonConstEqualsConst (const char *script, bool check_data=true)
 
 dart::TEST_CASE (ConstMap_small)
 
 dart::TEST_CASE (ConstMap_null)
 
 dart::TEST_CASE (ConstMap_larger)
 
 dart::TEST_CASE (ConstMap_nested)
 
 dart::TEST_CASE (Set_iteration)
 
static SetPtr dart::ConstructImmutableSet (const Array &input_data, intptr_t used_data, const TypeArguments &type_arguments)
 
 dart::TEST_CASE (ConstSet_vm)
 
 dart::TEST_CASE (ConstSet_small)
 
 dart::TEST_CASE (ConstSet_larger)
 
static void dart::CheckConcatAll (const String *data[], intptr_t n)
 
 dart::ISOLATE_UNIT_TEST_CASE (Symbols_FromConcatAll)
 
 dart::ISOLATE_UNIT_TEST_CASE (String_ScrubName)
 
 dart::ISOLATE_UNIT_TEST_CASE (String_EqualsUTF32)
 
 dart::TEST_CASE (TypeParameterTypeRef)
 
static void dart::FinalizeAndCanonicalize (AbstractType *type)
 
static void dart::CheckSubtypeRelation (const Expect &expect, const AbstractType &sub, const AbstractType &super, bool is_subtype)
 
 dart::ISOLATE_UNIT_TEST_CASE (ClosureType_SubtypeOfFunctionType)
 
 dart::ISOLATE_UNIT_TEST_CASE (FunctionType_IsSubtypeOfNonNullableObject)
 
static void dart::ExpectTypesEquivalent (const Expect &expect, const AbstractType &expected, const AbstractType &got, TypeEquality kind)
 
 dart::TEST_CASE (Class_GetInstantiationOf)
 
static TypePtr dart::CreateFutureOrType (const AbstractType &param, Nullability nullability)
 
static TypePtr dart::CreateFutureType (const AbstractType &param, Nullability nullability)
 
 dart::ISOLATE_UNIT_TEST_CASE (AbstractType_NormalizeFutureOrType)
 
 dart::TEST_CASE (AbstractType_InstantiatedFutureOrIsNormalized)
 
static void dart::GenerateInvokeInstantiateTAVStub (compiler::Assembler *assembler)
 
static CodePtr dart::CreateInvokeInstantiateTypeArgumentsStub (Thread *thread)
 
static void dart::TypeArgumentsHashCacheTest (Thread *thread, intptr_t num_classes)
 
 dart::TEST_CASE (TypeArguments_Cache_SomeInstantiations)
 
 dart::TEST_CASE (TypeArguments_Cache_ManyInstantiations)
 
static void dart::SubtypeTestCacheCheckContents (Zone *zone, const SubtypeTestCache &cache)
 
static void dart::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 dart::SubtypeTestCacheTest (Thread *thread, intptr_t num_classes, bool expect_hash)
 
 dart::TEST_CASE (STC_LinearLookup)
 
 dart::TEST_CASE (STC_HashLookup)
 

Variables

const intptr_t dart::kFinalizerTwoEntriesNumObjects = 9
 
const uint32_t dart::kCalculateCanonicalizeHash = 0
 

Macro Definition Documentation

◆ __

#define __   assembler->

Definition at line 7945 of file object_test.cc.

◆ EXPECT_NOT_SUBTYPE

#define EXPECT_NOT_SUBTYPE (   sub,
  super 
)     CheckSubtypeRelation(Expect(__FILE__, __LINE__), sub, super, false);

Definition at line 7419 of file object_test.cc.

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
7433ISOLATE_UNIT_TEST_CASE(ClosureType_SubtypeOfFunctionType) {
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));
7439 FinalizeAndCanonicalize(&closure_type_nullable);
7440 auto& closure_type_legacy = Type::Handle(
7441 closure_type.ToNullability(Nullability::kLegacy, Heap::kNew));
7442 FinalizeAndCanonicalize(&closure_type_legacy);
7443 auto& closure_type_nonnullable = Type::Handle(
7444 closure_type.ToNullability(Nullability::kNonNullable, Heap::kNew));
7445 FinalizeAndCanonicalize(&closure_type_nonnullable);
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));
7451 FinalizeAndCanonicalize(&function_type_nullable);
7452 auto& function_type_legacy = Type::Handle(
7453 function_type.ToNullability(Nullability::kLegacy, Heap::kNew));
7454 FinalizeAndCanonicalize(&function_type_legacy);
7455 auto& function_type_nonnullable = Type::Handle(
7456 function_type.ToNullability(Nullability::kNonNullable, Heap::kNew));
7457 FinalizeAndCanonicalize(&function_type_nonnullable);
7458
7459 EXPECT_SUBTYPE(closure_type_nonnullable, function_type_nullable);
7460 EXPECT_SUBTYPE(closure_type_nonnullable, function_type_legacy);
7461 EXPECT_SUBTYPE(closure_type_nonnullable, function_type_nonnullable);
7462 EXPECT_SUBTYPE(closure_type_legacy, function_type_nullable);
7463 EXPECT_SUBTYPE(closure_type_legacy, function_type_legacy);
7464 EXPECT_SUBTYPE(closure_type_legacy, function_type_nonnullable);
7465 EXPECT_SUBTYPE(closure_type_nullable, function_type_nullable);
7466 EXPECT_SUBTYPE(closure_type_nullable, function_type_legacy);
7467 EXPECT_NOT_SUBTYPE(closure_type_nullable, 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));
7484 FinalizeAndCanonicalize(&future_or_function_type_nullable);
7485 auto& future_or_function_type_legacy =
7486 Type::Handle(Type::New(future_or_class, tav_function_legacy));
7487 FinalizeAndCanonicalize(&future_or_function_type_legacy);
7488 auto& future_or_function_type_nonnullable =
7489 Type::Handle(Type::New(future_or_class, tav_function_nonnullable));
7490 FinalizeAndCanonicalize(&future_or_function_type_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);
7500 EXPECT_NOT_SUBTYPE(closure_type_nullable,
7501 future_or_function_type_nonnullable);
7502}
7503
7504ISOLATE_UNIT_TEST_CASE(FunctionType_IsSubtypeOfNonNullableObject) {
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()));
7511 FinalizeAndCanonicalize(&type_function_int_nullary);
7512
7513 auto& type_nullable_function_int_nullary =
7514 FunctionType::Handle(type_function_int_nullary.ToNullability(
7515 Nullability::kNullable, Heap::kOld));
7516 FinalizeAndCanonicalize(&type_nullable_function_int_nullary);
7517
7518 EXPECT_SUBTYPE(type_function_int_nullary, type_object);
7519 EXPECT_NOT_SUBTYPE(type_nullable_function_int_nullary, type_object);
7520}
7521
7522#undef EXPECT_NOT_SUBTYPE
7523#undef EXPECT_SUBTYPE
7524
7525static void ExpectTypesEquivalent(const Expect& expect,
7526 const AbstractType& expected,
7527 const AbstractType& got,
7528 TypeEquality kind) {
7529 if (got.IsEquivalent(expected, kind)) return;
7530 TextBuffer buffer(128);
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
7542TEST_CASE(Class_GetInstantiationOf) {
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);
7549 EXPECT_VALID(api_lib);
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 // Test that A1.GetInstantiationOf(B) returns B<List<A1::Y>>.
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());
7592 EXPECT_TYPES_EQUAL(type_b_list_a1_y, inst_b_a1);
7593 }
7594
7595 // Test that A2.GetInstantiationOf(B) returns B<List<A2::X>>.
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());
7620 EXPECT_TYPES_EQUAL(type_b_list_a2_x, inst_b_a2);
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
7630static TypePtr CreateFutureOrType(const AbstractType& param,
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);
7637 const auto& type =
7638 AbstractType::Handle(Type::New(future_or_class, tav, nullability));
7639 return Type::RawCast(
7640 ClassFinalizer::FinalizeType(type, ClassFinalizer::kFinalize));
7641}
7642
7643static TypePtr CreateFutureType(const AbstractType& param,
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
7654ISOLATE_UNIT_TEST_CASE(AbstractType_NormalizeFutureOrType) {
7655 // This should be kept up to date with any changes in
7656 // https://github.com/dart-lang/language/blob/master/resources/type-system/normalization.md
7657
7658 ObjectStore* const object_store = IsolateGroup::Current()->object_store();
7659
7660 auto normalized_future_or = [&](const AbstractType& param,
7661 Nullability nullability) -> AbstractTypePtr {
7662 const auto& type = Type::Handle(CreateFutureOrType(param, nullability));
7663 return type.NormalizeFutureOrType(Heap::kNew);
7664 };
7665
7666 // NORM(FutureOr<T>) =
7667 // let S be NORM(T)
7668 // if S is a top type then S
7669 {
7670 const auto& type = AbstractType::Handle(normalized_future_or(
7671 Object::dynamic_type(), Nullability::kNonNullable));
7672 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::dynamic_type(), type);
7673 }
7674
7675 {
7676 const auto& type = AbstractType::Handle(
7677 normalized_future_or(Object::void_type(), Nullability::kNonNullable));
7678 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::void_type(), type);
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));
7686 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, type);
7687 }
7688
7689 // if S is Object then S
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));
7696 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_non_nullable_object, type);
7697 }
7698
7699 // if S is Object* then S
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));
7706 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_legacy_object, type);
7707 }
7708
7709 // if S is Never then Future<Never>
7710
7711 {
7712 const auto& type_never = Type::Handle(object_store->never_type());
7713 const auto& expected =
7714 Type::Handle(CreateFutureType(type_never, Nullability::kNonNullable));
7715 const auto& got = AbstractType::Handle(
7716 normalized_future_or(type_never, Nullability::kNonNullable));
7718 }
7719
7720 // if S is Null then Future<Null>?
7721
7722 {
7723 const auto& type_null = Type::Handle(object_store->null_type());
7724 const auto& expected =
7725 Type::Handle(CreateFutureType(type_null, Nullability::kNullable));
7726 const auto& got = AbstractType::Handle(
7727 normalized_future_or(type_null, Nullability::kNonNullable));
7729 }
7730
7731 // else FutureOr<S>
7732
7733 // NORM(T?) =
7734 // let S be NORM(T)
7735 // ...
7736 // if S is FutureOr<R> and R is nullable then S
7737
7738 {
7739 const auto& type_nullable_int =
7740 Type::Handle(object_store->nullable_int_type());
7741 const auto& expected = Type::Handle(
7742 CreateFutureOrType(type_nullable_int, Nullability::kNonNullable));
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);
7758 EXPECT_VALID(api_lib);
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 // Testing same cases as AbstractType_NormalizeFutureOrType.
7794
7795 // FutureOr<T>?[top type] = top type
7796
7797 {
7798 const auto& got = AbstractType::Handle(
7799 instantiate_future_or(nullable_future_or_T, Object::dynamic_type()));
7800 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::dynamic_type(), got);
7801 }
7802
7803 {
7804 const auto& got = AbstractType::Handle(
7805 instantiate_future_or(nullable_future_or_T, Object::void_type()));
7806 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::void_type(), got);
7807 }
7808
7809 {
7810 const auto& got = AbstractType::Handle(
7811 instantiate_future_or(nullable_future_or_T, type_nullable_object));
7812 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
7813 }
7814
7815 // FutureOr<T?>[top type] = top type
7816
7817 {
7818 const auto& got = AbstractType::Handle(
7819 instantiate_future_or(future_or_nullable_T, Object::dynamic_type()));
7820 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::dynamic_type(), got);
7821 }
7822
7823 {
7824 const auto& got = AbstractType::Handle(
7825 instantiate_future_or(future_or_nullable_T, Object::void_type()));
7826 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::void_type(), got);
7827 }
7828
7829 {
7830 const auto& got = AbstractType::Handle(
7831 instantiate_future_or(future_or_nullable_T, type_nullable_object));
7832 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
7833 }
7834
7835 // FutureOr<T?>[Object] = Object?
7836
7837 {
7838 const auto& got = AbstractType::Handle(
7839 instantiate_future_or(future_or_nullable_T, type_non_nullable_object));
7840 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
7841 }
7842
7843 // FutureOr<T?>[Object*] = Object?
7844
7845 {
7846 const auto& got = AbstractType::Handle(
7847 instantiate_future_or(future_or_nullable_T, type_legacy_object));
7848 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
7849 }
7850
7851 // FutureOr<T>?[Object] = Object?
7852
7853 {
7854 const auto& got = AbstractType::Handle(
7855 instantiate_future_or(nullable_future_or_T, type_non_nullable_object));
7856 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
7857 }
7858
7859 // FutureOr<T>?[Object*] = Object?
7860
7861 {
7862 const auto& got = AbstractType::Handle(
7863 instantiate_future_or(nullable_future_or_T, type_legacy_object));
7864 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
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 // FutureOr<T?>[Never] = Future<Null>?
7871
7872 {
7873 const auto& expected =
7874 Type::Handle(CreateFutureType(type_null, Nullability::kNullable));
7875 const auto& got = AbstractType::Handle(
7876 instantiate_future_or(future_or_nullable_T, type_never));
7878 }
7879
7880 // FutureOr<T>?[Never] = Future<Never>?
7881
7882 {
7883 const auto& expected =
7884 Type::Handle(CreateFutureType(type_never, Nullability::kNullable));
7885 const auto& got = AbstractType::Handle(
7886 instantiate_future_or(nullable_future_or_T, type_never));
7888 }
7889
7890 // FutureOr<T?>[Null] = Future<Null>?
7891
7892 {
7893 const auto& expected =
7894 Type::Handle(CreateFutureType(type_null, Nullability::kNullable));
7895 const auto& got = AbstractType::Handle(
7896 instantiate_future_or(future_or_nullable_T, type_null));
7898 }
7899
7900 // FutureOr<T>?[Null] = Future<Null>?
7901
7902 {
7903 const auto& expected =
7904 Type::Handle(CreateFutureType(type_null, Nullability::kNullable));
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 // FutureOr<T?>[int] = FutureOr<int?>
7916
7917 {
7918 const auto& expected = Type::Handle(
7919 CreateFutureOrType(type_nullable_int, Nullability::kNonNullable));
7920 const auto& got = AbstractType::Handle(
7921 instantiate_future_or(future_or_nullable_T, type_non_nullable_int));
7923 }
7924
7925 // FutureOr<T?>[int?] = FutureOr<int?>
7926
7927 {
7928 const auto& expected = Type::Handle(
7929 CreateFutureOrType(type_nullable_int, Nullability::kNonNullable));
7930 const auto& got = AbstractType::Handle(
7931 instantiate_future_or(future_or_nullable_T, type_nullable_int));
7933 }
7934
7935 // FutureOr<T>?[int?] = FutureOr<int?>
7936
7937 {
7938 const auto& expected = Type::Handle(
7939 CreateFutureOrType(type_nullable_int, Nullability::kNonNullable));
7940 const auto& got = AbstractType::Handle(
7941 instantiate_future_or(nullable_future_or_T, type_nullable_int));
7943 }
7944
7945 // FutureOr<T>?[int] = FutureOr<int>?
7946
7947 {
7948 const auto& expected = Type::Handle(
7949 CreateFutureOrType(type_non_nullable_int, Nullability::kNullable));
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
7958static void GenerateInvokeInstantiateTAVStub(compiler::Assembler* assembler) {
7959 __ EnterDartFrame(0);
7960
7961 // Load the arguments into the right stub calling convention registers.
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 // Set the return from the stub.
7979 __ MoveRegister(CallingConventions::kReturnReg,
7980 InstantiationABI::kResultTypeArgumentsReg);
7981 __ LeaveDartFrame();
7982 __ Ret();
7983}
7984
7985#undef __
7986
7987static CodePtr CreateInvokeInstantiateTypeArgumentsStub(Thread* thread) {
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 /*optimized=*/false));
8007
8008 const auto& pool =
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()); // The InstantiateTypeArguments stub.
8018#endif
8019 return invoke_instantiate_tav.ptr();
8020}
8021
8022#if !defined(PRODUCT)
8023// Defined before TypeArguments::InstantiateAndCanonicalizeFrom in object.cc.
8025#endif
8026
8027static void TypeArgumentsHashCacheTest(Thread* thread, intptr_t num_classes) {
8028 TextBuffer buffer(MB);
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 }
8038 buffer.AddString("}\n");
8039
8040 Dart_Handle api_lib = TestCase::LoadTestScript(buffer.buffer(), nullptr);
8041 EXPECT_VALID(api_lib);
8042 Dart_Handle result = Dart_Invoke(api_lib, NewString("main"), 0, nullptr);
8044
8045 // D + C0...CN, where N = kNumClasses - 1
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 // Cache the first computed set of instantiator type arguments to check that
8070 // no entries from the cache have been lost when the cache grows.
8071 auto& first_instantiator_type_args = TypeArguments::Handle(zone);
8072 // Used for the cache hit in stub check.
8073 const auto& invoke_instantiate_tav =
8074 Code::Handle(zone, CreateInvokeInstantiateTypeArgumentsStub(thread));
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);
8083 class_c = GetClass(root_lib, name);
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 // The first call to InstantiateAndCanonicalizeFrom shouldn't have a cache
8092 // hit since the instantiator type arguments should be unique for each
8093 // iteration, and after that we do a check that the InstantiateTypeArguments
8094 // stub finds the entry (unless the cache is hash-based on IA32).
8096#endif
8097
8098 // Check that the key does not currently exist in the cache.
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);
8107 EXPECT(!loc.present);
8108 old_capacity = cache.NumEntries();
8109 }
8110
8111 decl_type_d_type_args.InstantiateAndCanonicalizeFrom(instantiator_type_args,
8112 function_type_args);
8113
8114 // Check that the key now does exist in the cache.
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 // Double-check that we got the expected type of cache.
8123 EXPECT(updated_cache_is_linear ? cache.IsLinear() : cache.IsHash());
8124 loc = cache.FindKeyOrUnused(instantiator_type_args, function_type_args);
8125 EXPECT(loc.present);
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 // Now check that we get the expected result from calling the stub if it
8135 // checks the cache (e.g., in all cases but hash-based caches on IA32).
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);
8145 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(decl_type_c, result_type);
8146 }
8147
8148#if !defined(PRODUCT)
8149 // Setting to false prior to re-calling InstantiateAndCanonicalizeFrom with
8150 // the same keys, as now we want a runtime check of an existing cache entry.
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);
8157 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(decl_type_c, result_type);
8158
8159 // Check that no new entries were added to the cache.
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);
8167 EXPECT(loc2.present);
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 // Check that the first instantiator TAV still exists in the new cache.
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 // Double-check that we got the expected type of cache.
8180 EXPECT(i < TypeArguments::Cache::kMaxLinearCacheEntries ? cache.IsLinear()
8181 : cache.IsHash());
8182 auto const loc =
8183 cache.FindKeyOrUnused(instantiator_type_args, function_type_args);
8184 EXPECT(loc.present);
8185 }
8186 }
8187}
8188
8189// A smaller version of the following test case, just to ensure some coverage
8190// on slower builds.
8191TEST_CASE(TypeArguments_Cache_SomeInstantiations) {
8193 2 * TypeArguments::Cache::kMaxLinearCacheEntries);
8194}
8195
8196// Too slow in debug mode. Also avoid the sanitizers and simulators for similar
8197// reasons. Any core issues will likely be found by SomeInstantiations.
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");
8205 TypeArgumentsHashCacheTest(thread, kNumClasses);
8206}
8207#endif
8208
8209#undef EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT
8210
8211static void SubtypeTestCacheCheckContents(Zone* zone,
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 // Used to make sure all the cases are in the correct order below.
8230 int check_ordering = used_inputs;
8231 // Input: the value of SubtypeTestCache::Entries for this input
8232 // ExpectedCids is an expression where [cid] is bound to the contents cid.
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) {
8245 USED_INPUT_CASE(SubtypeTestCache::kDestinationType,
8248 USED_INPUT_CASE(SubtypeTestCache::kInstanceDelayedFunctionTypeArguments,
8249 cid == kNullCid || cid == kTypeArgumentsCid);
8251 USED_INPUT_CASE(SubtypeTestCache::kInstanceParentFunctionTypeArguments,
8252 cid == kNullCid || cid == kTypeArgumentsCid);
8254 USED_INPUT_CASE(SubtypeTestCache::kFunctionTypeArguments,
8255 cid == kNullCid || cid == kTypeArgumentsCid);
8257 USED_INPUT_CASE(SubtypeTestCache::kInstantiatorTypeArguments,
8258 cid == kNullCid || cid == kTypeArgumentsCid);
8260 USED_INPUT_CASE(SubtypeTestCache::kInstanceTypeArguments,
8261 cid == kNullCid || cid == kTypeArgumentsCid);
8263 USED_INPUT_CASE(SubtypeTestCache::kInstanceCidOrSignature,
8264 cid == kSmiCid || cid == kFunctionTypeCid);
8265 break;
8266 default:
8267 UNREACHABLE();
8268 }
8269
8270#undef USED_INPUT_CASE
8271 RELEASE_ASSERT(0 == check_ordering);
8272
8273 // Check that unused inputs have never been set.
8274 for (intptr_t i = used_inputs; i < SubtypeTestCache::kMaxInputs; i++) {
8275 // Since we sometimes use Array::NewUninitialized() for allocations of
8276 // STCs and never set unused inputs, the only thing we know is that the
8277 // entry is GC-safe. Since we don't expect valid values for unused inputs,
8278 // we just check if it's either a Smi or null.
8279 const intptr_t cid = array.At(entry_start + i)->GetClassIdMayBeSmi();
8280 EXPECT(cid == kSmiCid || cid == kNullCid);
8281 }
8282 }
8283}
8284
8285static void SubtypeTestCacheEntryTest(
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
8303 EXPECT(!cache.HasCheck(
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, /*index=*/nullptr,
8307 /*result=*/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 // Match replacing unused instance type arguments with null.
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 // No match replacing used instance type arguments with null.
8336 EXPECT(!cache.HasCheck(
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 /*index=*/nullptr, /*result=*/nullptr));
8341 }
8342 if (num_inputs < (SubtypeTestCache::kInstantiatorTypeArguments + 1)) {
8343 // Match replacing unused instantiator type arguments with null.
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 // No match replacing used instantiator type arguments with null.
8353 EXPECT(!cache.HasCheck(
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 /*index=*/nullptr, /*result=*/nullptr));
8358 }
8359 if (num_inputs < (SubtypeTestCache::kFunctionTypeArguments + 1)) {
8360 // Match replacing unused function type arguments with null.
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 // No match replacing used function type arguments with null.
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 /*index=*/nullptr, /*result=*/nullptr));
8374 }
8375 if (num_inputs <
8376 (SubtypeTestCache::kInstanceParentFunctionTypeArguments + 1)) {
8377 // Match replacing unused parent function type arguments with null.
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 // No match replacing used parent function type arguments with null.
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, /*index=*/nullptr,
8390 /*result=*/nullptr));
8391 }
8392 if (num_inputs <
8393 (SubtypeTestCache::kInstanceDelayedFunctionTypeArguments + 1)) {
8394 // Match replacing unused delayed type arguments with null.
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 // No match replacing used delayed type arguments with null.
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 /*index=*/nullptr, /*result=*/nullptr));
8409 }
8410 // Make sure we're not accidentally using the same type as the input below.
8411 RELEASE_ASSERT(destination_type.ptr() != Type::VoidType());
8412 if (num_inputs < (SubtypeTestCache::kDestinationType + 1)) {
8413 // Match replacing unused destination type argument with the null type.
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 // No match replacing used destination type argument with the null type.
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 /*index=*/nullptr, /*result=*/nullptr));
8429 }
8430 // Once hash-based, should stay a hash-based cache.
8431 EXPECT(!was_hash || cache.IsHash());
8432}
8433
8434static void SubtypeTestCacheTest(Thread* thread,
8435 intptr_t num_classes,
8436 bool expect_hash) {
8437 TextBuffer buffer(MB);
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
8454 Dart_Handle api_lib = TestCase::LoadTestScript(buffer.buffer(), nullptr);
8455 EXPECT_VALID(api_lib);
8456
8457 // D + C0...CN, where N = kNumClasses - 1
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 // Test all the possible input values.
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 // Set up unique tavs for each of the TAV inputs.
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 // Just so we're testing both true and false values, as we're not actually
8520 // using the results to determine subtype/assignability.
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++) {
8560 SubtypeTestCacheCheckContents(zone, *stcs[i]);
8561 EXPECT_EQ(expect_hash, stcs[i]->IsHash());
8562 }
8563}
8564
8565TEST_CASE(STC_LinearLookup) {
8566 SubtypeTestCacheTest(thread, SubtypeTestCache::kMaxLinearCacheEntries,
8567 /*expect_hash=*/false);
8568}
8569
8570TEST_CASE(STC_HashLookup) {
8571 SubtypeTestCacheTest(thread, 2 * SubtypeTestCache::kMaxLinearCacheEntries,
8572 /*expect_hash=*/true);
8573}
8574
8575} // namespace dart
AutoreleasePool pool
#define EXPECT(type, expectedAlignment, expectedSize)
#define UNREACHABLE()
Definition assert.h:248
#define RELEASE_ASSERT(cond)
Definition assert.h:327
struct _Dart_Handle * Dart_Handle
Definition dart_api.h:258
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)
#define ASSERT(E)
static const uint8_t buffer[]
GAsyncResult * result
const char * name
Definition fuchsia.cc:50
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)
Definition class_id.h:325
Nullability
Definition object.h:1112
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)
const intptr_t cid
bool TESTING_runtime_fail_on_existing_cache_entry
Definition object.cc:7675
const char *const function_name
static TypePtr CreateFutureOrType(const AbstractType &param, Nullability nullability)
static TypePtr CreateFutureType(const AbstractType &param, 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
Definition switches.h:191
#define __
#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 FALL_THROUGH
Definition globals.h:15
#define Pd
Definition globals.h:408
#define ISOLATE_UNIT_TEST_CASE(name)
Definition unit_test.h:64
Dart_Handle NewString(const char *str)
Definition unit_test.h:229
#define TEST_CASE(name)
Definition unit_test.h:85
#define EXPECT_VALID(handle)
Definition unit_test.h:650

◆ EXPECT_SUBTYPE

#define EXPECT_SUBTYPE (   sub,
  super 
)     CheckSubtypeRelation(Expect(__FILE__, __LINE__), sub, super, true);

Definition at line 7417 of file object_test.cc.

7417 {
7418 if (sub.IsSubtypeOf(super, Heap::kNew) != is_subtype) {

◆ EXPECT_TYPES_EQUAL

#define EXPECT_TYPES_EQUAL (   expected,
  got 
)
Value:
ExpectTypesEquivalent(Expect(__FILE__, __LINE__), expected, got, \
TypeEquality::kCanonical);

Definition at line 7527 of file object_test.cc.

7528 {
7529 if (got.IsEquivalent(expected, kind)) return;

◆ EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT

#define EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT (   expected,
  got 
)
Value:
ExpectTypesEquivalent(Expect(__FILE__, __LINE__), expected, got, \
TypeEquality::kSyntactical);

Definition at line 7615 of file object_test.cc.

◆ FINALIZER_CROSS_GEN_TEST_CASE

#define FINALIZER_CROSS_GEN_TEST_CASE (   n)
Value:
ISOLATE_UNIT_TEST_CASE(Finalizer_CrossGen_##n) { \
Finalizer_TwoEntriesCrossGen(thread, n); \
}

Definition at line 4353 of file object_test.cc.

4354 { \
4355 Finalizer_TwoEntriesCrossGen(thread, n); \
4356 }

◆ FINALIZER_NATIVE_CROSS_GEN_TEST_CASE

#define FINALIZER_NATIVE_CROSS_GEN_TEST_CASE (   n)
Value:
ISOLATE_UNIT_TEST_CASE(NativeFinalizer_CrossGen_##n) { \
NativeFinalizer_TwoEntriesCrossGen(thread, n); \
}

Definition at line 5134 of file object_test.cc.

5135 { \
5136 NativeFinalizer_TwoEntriesCrossGen(thread, n); \
5137 }

◆ REPEAT_512

#define REPEAT_512 (   V)

Definition at line 4358 of file object_test.cc.

◆ USED_INPUT_CASE

#define USED_INPUT_CASE (   Input,
  ExpectedCids 
)
Value:
case (Input) + 1: { \
RELEASE_ASSERT((Input) + 1 == check_ordering); \
const intptr_t cid = \
array.At(entry_start + (Input))->GetClassIdMayBeSmi(); \
if (!(ExpectedCids)) { \
FAIL("expected: " #ExpectedCids ", got: cid %" Pd "", cid); \
} \
--check_ordering; \
}

◆ Z

#define Z   (thread->zone())

Definition at line 40 of file object_test.cc.