24 EXPECT(target_instr->IsBlockEntry());
25 EXPECT(!target_instr->IsDefinition());
54 operator []=(var index, var value) {
55 return data[index] = value;
58 List<T%s> data = List<T%s>.filled(10, null);
61 Container<int> x = Container<int>();
64 for (int i = 0; i < 10; ++i) {
68 )", nullable_tag, nullable_tag), std::free);
74 Invoke(root_library,
"foo");
84 ILMatcher cursor(flow_graph, entry,
true);
87 kMatchAndMoveBranchTrue,
89 {kMatchStoreIndexed, &store_indexed},
92 EXPECT(!store_indexed->value()->NeedsWriteBarrier());
96 const std::vector<const char*>& expected_stores) {
97 size_t next_expected_store = 0;
99 !block_it.Done(); block_it.Advance()) {
102 if (
auto store = it.Current()->AsStoreField()) {
103 EXPECT_LT(next_expected_store, expected_stores.size());
104 EXPECT_STREQ(expected_stores[next_expected_store],
105 store->slot().Name());
106 next_expected_store++;
114 const char* function_name,
116 const std::vector<const char*>& expected_stores) {
121 CompilerPass::kComputeSSA,
122 CompilerPass::kTypePropagation,
123 CompilerPass::kApplyICData,
124 CompilerPass::kInlining,
125 CompilerPass::kTypePropagation,
126 CompilerPass::kSelectRepresentations,
127 CompilerPass::kCanonicalize,
128 CompilerPass::kConstantPropagation,
130 ASSERT(flow_graph !=
nullptr);
141 Bar({this.f, this.g});
143 Bar f1() => Bar(f: 10);
144 Bar f2() => Bar(g: 10);
149 return () { return value; };
158 TestCase::NullableTag()), std::free);
161 const auto& root_library = Library::Handle(
LoadTestScript(kScript.get()));
162 Invoke(root_library,
"main");
170 {
"Closure.function",
"Closure.entry_point"});
176 std::vector<const char*> expected_stores_jit;
177 std::vector<const char*> expected_stores_aot;
179 expected_stores_jit.insert(
180 expected_stores_jit.end(),
181 {
"value",
"Context.parent",
"Context.parent",
"value",
182 "Closure.function_type_arguments",
"Closure.context"});
183 expected_stores_aot.insert(
184 expected_stores_aot.end(),
185 {
"value",
"Closure.function_type_arguments",
"Closure.context"});
188 expected_stores_jit);
190 expected_stores_aot);
207 H.AddVariable(
"v0", AbstractType::ZoneHandle(Type::IntType()));
209 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
216 v0 = builder.AddParameter(0, initial);
218 RangeBoundary::FromConstant(max_value)));
220 initial, intermediate,
new Value(v0), S.GetNextDeoptId()));
222 intermediate, initial,
new Value(conv1), S.GetNextDeoptId()));
223 ret = builder.AddReturn(
new Value(conv2));
228 H.flow_graph()->Canonicalize();
229 H.flow_graph()->Canonicalize();
236 kUnboxedInt64, kUnboxedInt32,
239 kUnboxedInt64, kUnboxedInt32,
243 kUnboxedInt32, kUnboxedInt64));
245 thread, 0,
kMaxInt16, kUnboxedInt64, kUnboxedUint32, kUnboxedInt64));
247 thread, 0,
kMaxInt32, kUnboxedInt64, kUnboxedUint32, kUnboxedInt64));
249 thread, 0,
kMaxUint32, kUnboxedInt64, kUnboxedUint32, kUnboxedInt64));
251 thread, 0,
static_cast<int64_t
>(
kMaxUint32) + 1, kUnboxedInt64,
252 kUnboxedUint32, kUnboxedInt64));
254 thread, -1,
kMaxInt16, kUnboxedInt64, kUnboxedUint32, kUnboxedInt64));
258 kUnboxedInt32, kUnboxedUint32,
261 kUnboxedInt32, kUnboxedUint32,
264 thread, 0,
kMaxInt32, kUnboxedInt32, kUnboxedUint32, kUnboxedInt64));
266 thread, 0,
kMaxInt32, kUnboxedInt32, kUnboxedUint32, kUnboxedInt32));
275 H.AddVariable(
"v0", AbstractType::ZoneHandle(Type::DynamicType()));
277 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
278 auto b2 =
H.JoinEntry();
279 auto b3 =
H.TargetEntry();
280 auto b4 =
H.TargetEntry();
288 v0 = builder.AddParameter(0, kTagged);
289 builder.AddInstruction(
new GotoInstr(b2, S.GetNextDeoptId()));
301 false, S.GetNextDeoptId()),
307 builder.AddInstruction(
new GotoInstr(b2, S.GetNextDeoptId()));
312 ret = builder.AddReturn(
new Value(phi));
317 H.flow_graph()->Canonicalize();
329 H.AddVariable(
"v0", AbstractType::ZoneHandle(Type::DynamicType()));
330 H.AddVariable(
"v1", AbstractType::ZoneHandle(Type::DynamicType()));
332 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
339 H.flow_graph()->GetConstant(Type::Handle(Type::IntType()));
341 Definition* float64_array = builder.AddParameter(0, kTagged);
342 Definition* int64_array = builder.AddParameter(1, kTagged);
350 BoxInstr::Create(kUnboxedDouble,
new Value(load_indexed)));
354 new Value(
H.flow_graph()->constant_null()),
356 new Value(
H.flow_graph()->constant_null()),
357 String::Handle(String::New(
"not-null")),
358 S.GetNextDeoptId()));
360 new Value(
cast), S.GetNextDeoptId(), BoxInstr::kGuardInputs));
368 builder.AddReturn(
new Value(index));
373 FlowGraphTypePropagator::Propagate(
H.flow_graph());
376 H.flow_graph()->Canonicalize();
379 H.flow_graph()->RemoveRedefinitions();
384 ClassTable*
const class_table = IsolateGroup::Current()->class_table();
387 const auto& cls = Class::Handle(class_table->
At(
cid));
388 buffer->Printf(
" (%s", cls.ScrubbedNameCString());
389 if (cls.is_abstract()) {
390 buffer->AddString(
", abstract");
398 bool allow_representation_change) {
404 H.AddVariable(
"v0", AbstractType::ZoneHandle(Type::IntType()));
405 H.AddVariable(
"v1", AbstractType::ZoneHandle(Type::IntType()));
407 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
412 Definition* v0 = builder.AddParameter(0, kUnboxedInt64);
413 Definition* v1 = builder.AddParameter(1, kUnboxedInt64);
419 kMintCid, S.GetNextDeoptId(),
true));
425 if (!allow_representation_change) {
426 H.flow_graph()->disallow_unmatched_representations();
429 H.flow_graph()->Canonicalize();
431 EXPECT(
compare->is_null_aware() == !allow_representation_change);
442 buffer->AddString(
"empty CidRangeVector");
445 buffer->AddString(
"non-empty CidRangeVector:\n");
446 for (
const auto& range : ranges) {
447 for (intptr_t
cid = range.cid_start;
cid <= range.cid_end;
cid++) {
458 for (
const auto& range : ranges) {
459 for (intptr_t
cid = range.cid_start;
cid <= range.cid_end;
cid++) {
460 if (expected ==
cid)
return true;
464 buffer.AddString(
"Expected CidRangeVector to include cid ");
477 buffer.AddString(
"Checking that ");
479 buffer.AddString(
"includes cids:\n");
480 for (
const intptr_t
cid : expected) {
487 bool all_found =
true;
488 for (
const intptr_t
cid : expected) {
494 THR_Print(
"All expected cids included.\n\n");
498#define RANGES_CONTAIN_EXPECTED_CIDS(ranges, cids) \
499 RangesContainExpectedCids(dart::Expect(__FILE__, __LINE__), ranges, cids)
504 Type::Handle(IsolateGroup::Current()->object_store()->object_type());
505 const bool is_nullable = Instance::NullIsAssignableTo(
type);
507 const auto& cls = Class::Handle(
type.type_class());
509 ClassTable*
const class_table = thread->isolate_group()->class_table();
510 const intptr_t num_cids = class_table->
NumCids();
511 auto& to_check = Class::Handle(thread->zone());
512 auto& rare_type = AbstractType::Handle(thread->zone());
516 for (intptr_t
cid = kInstanceCid;
cid < num_cids;
cid++) {
522 to_check = class_table->
At(
cid);
524 if (to_check.is_abstract()) {
525 expected_abstract_cids.
Add(
cid);
527 expected_concrete_cids.
Add(
cid);
529 if (
cid != kTypeArgumentsCid) {
530 rare_type = to_check.RareType();
531 EXPECT(rare_type.IsSubtypeOf(
type, Heap::kNew));
536 cls,
false, !is_nullable);
540 expected_cids.
AddArray(expected_concrete_cids);
541 expected_cids.
AddArray(expected_abstract_cids);
543 cls,
true, !is_nullable);
550 Type::Handle(IsolateGroup::Current()->object_store()->function_type());
552 const auto& cls = Class::Handle(
type.type_class());
555 expected_concrete_cids.
Add(kClosureCid);
558 expected_abstract_cids.
Add(
type.type_class_id());
565 expected_cids.
AddArray(expected_concrete_cids);
566 expected_cids.
AddArray(expected_abstract_cids);
574 const auto& num_type = Type::Handle(Type::Number());
575 const auto& int_type = Type::Handle(Type::IntType());
576 const auto& double_type = Type::Handle(Type::Double());
578 const auto& cls = Class::Handle(num_type.type_class());
581 expected_concrete_cids.
Add(kSmiCid);
582 expected_concrete_cids.
Add(kMintCid);
583 expected_concrete_cids.
Add(kDoubleCid);
586 expected_abstract_cids.
Add(num_type.type_class_id());
587 expected_abstract_cids.
Add(int_type.type_class_id());
588 expected_abstract_cids.
Add(double_type.type_class_id());
595 expected_cids.
AddArray(expected_concrete_cids);
596 expected_cids.
AddArray(expected_abstract_cids);
604 const auto&
type = Type::Handle(Type::IntType());
606 const auto& cls = Class::Handle(
type.type_class());
609 expected_concrete_cids.
Add(kSmiCid);
610 expected_concrete_cids.
Add(kMintCid);
613 expected_abstract_cids.
Add(
type.type_class_id());
620 expected_cids.
AddArray(expected_concrete_cids);
621 expected_cids.
AddArray(expected_abstract_cids);
629 const auto&
type = Type::Handle(Type::StringType());
631 const auto& cls = Class::Handle(
type.type_class());
634 expected_concrete_cids.
Add(kOneByteStringCid);
635 expected_concrete_cids.
Add(kTwoByteStringCid);
638 expected_abstract_cids.
Add(
type.type_class_id());
642 THR_Print(
"Checking concrete subtype ranges for String\n");
646 expected_cids.
AddArray(expected_concrete_cids);
647 expected_cids.
AddArray(expected_abstract_cids);
650 THR_Print(
"Checking concrete and abstract subtype ranges for String\n");
658 const char* kScript = R
"(
659 bool foo(double x) => (x + 0.5) == 0;
665 const auto& root_library = Library::Handle(
LoadTestScript(kScript));
672 ILMatcher cursor(flow_graph, entry,
true,
673 ParallelMovesHandling::kSkip);
677 kMatchAndMoveBinaryDoubleOp,
678 kMatchAndMoveEqualityCompare,
692 void anotherFunction() {}
696 const auto& root_library = Library::Handle(
LoadTestScript(kScript));
697 Zone*
const zone = Thread::Current()->zone();
698 auto& invoke_result = Instance::Handle(zone);
699 invoke_result ^=
Invoke(root_library,
"myFunction");
700 EXPECT_EQ(Smi::New(100), invoke_result.ptr());
702 const auto& my_function =
703 Function::Handle(
GetFunction(root_library,
"myFunction"));
707 CompilerPass::kComputeSSA,
716 {kMatchDartReturn, &return_instr},
720 auto*
const load_thread_instr =
new (zone) LoadThreadInstr();
721 flow_graph->InsertBefore(return_instr, load_thread_instr,
nullptr,
723 auto load_thread_value =
Value(load_thread_instr);
725 auto*
const convert_instr =
new (zone) IntConverterInstr(
726 kUntagged, kUnboxedAddress, &load_thread_value, DeoptId::kNone);
727 flow_graph->InsertBefore(return_instr, convert_instr,
nullptr,
729 auto convert_value =
Value(convert_instr);
731 auto*
const box_instr = BoxInstr::Create(kUnboxedAddress, &convert_value);
732 flow_graph->InsertBefore(return_instr, box_instr,
nullptr, FlowGraph::kValue);
734 return_instr->InputAt(0)->definition()->ReplaceUsesWith(box_instr);
738 ILMatcher cursor(flow_graph, flow_graph->graph_entry()->normal_entry());
741 kMatchAndMoveLoadThread,
742 kMatchAndMoveIntConverter,
748 pipeline.RunForcedOptimizedAfterSSAPasses();
751#if !defined(PRODUCT) && !defined(USING_THREAD_SANITIZER)
752 SetFlagScope<bool> sfs(&FLAG_disassemble_optimized,
true);
754 pipeline.CompileGraphAndAttachFunction();
758 invoke_result ^=
Invoke(root_library,
"myFunction");
759 intptr_t result_int = Integer::Cast(invoke_result).AsInt64Value();
760 EXPECT_EQ(
reinterpret_cast<intptr_t
>(thread), result_int);
763#if !defined(TARGET_ARCH_IA32)
767 int globalCounter = 0;
769 int increment() => ++globalCounter;
771 int cachedIncrement() {
772 // We will replace this call with a cacheable call,
773 // which will lead to the counter no longer being incremented.
774 // Make sure to return the value, so we can see that the boxing and
775 // unboxing works as expected.
779 int multipleIncrement() {
781 for(int i = 0; i < 10; i++) {
782 // Save the last returned value.
783 returnValue = cachedIncrement();
790 const auto& root_library = Library::Handle(
LoadTestScript(kScript.get()));
791 const auto& first_result =
792 Object::Handle(
Invoke(root_library,
"multipleIncrement"));
793 EXPECT(first_result.IsSmi());
794 if (first_result.IsSmi()) {
795 const intptr_t int_value = Smi::Cast(first_result).Value();
796 EXPECT_EQ(10, int_value);
799 const auto& cached_increment_function =
800 Function::Handle(
GetFunction(root_library,
"cachedIncrement"));
802 const auto& increment_function =
803 Function::ZoneHandle(
GetFunction(root_library,
"increment"));
805 TestPipeline pipeline(cached_increment_function, CompilerPass::kJIT);
807 CompilerPass::kComputeSSA,
816 {kMatchAndMoveStaticCall, &static_call},
823 CachableIdempotentCallInstr* call =
new CachableIdempotentCallInstr(
824 InstructionSource(), kUnboxedAddress, increment_function,
825 static_call->type_args_len(), Array::empty_array(), std::move(
args),
827 static_call->ReplaceWith(call,
nullptr);
829 pipeline.RunForcedOptimizedAfterSSAPasses();
832 ILMatcher cursor(flow_graph, flow_graph->graph_entry()->normal_entry());
836 kMatchAndMoveCachableIdempotentCall,
848 SetFlagScope<bool> sfs(&FLAG_disassemble_optimized,
true);
850 pipeline.CompileGraphAndAttachFunction();
853 const auto& second_result =
854 Object::Handle(
Invoke(root_library,
"multipleIncrement"));
855 EXPECT(second_result.IsSmi());
856 if (second_result.IsSmi()) {
857 const intptr_t int_value = Smi::Cast(second_result).Value();
858 EXPECT_EQ(11, int_value);
884 kUnboxedIntPtr, kUntagged,
886 Integer::Handle(
Z, Integer::NewCanonical(native_entry)),
889 flow_graph->
InsertBefore(static_call, load_entry_point,
nullptr,
893 const intptr_t num_arguments =
894 FfiCallInstr::InputCountForMarshaller(marshaller);
897 arguments.
Add(
new (
Z)
Value(load_entry_point));
898 auto*
const ffi_call =
new (
Z)
899 FfiCallInstr(DeoptId::kNone, marshaller, is_leaf, std::move(arguments));
901 ffi_call->InputAt(ffi_call->TargetAddressIndex())->definition() ==
903 flow_graph->
InsertBefore(static_call, ffi_call,
nullptr,
912 CompilerPass::kApplyICData,
913 CompilerPass::kTryOptimizePatterns,
914 CompilerPass::kSetOuterInliningId,
915 CompilerPass::kTypePropagation,
917 CompilerPass::kWidenSmiToInt32,
918 CompilerPass::kSelectRepresentations,
920 CompilerPass::kTypePropagation,
921 CompilerPass::kRangeAnalysis,
923 CompilerPass::kFinalizeGraph,
924 CompilerPass::kCanonicalize,
925 CompilerPass::kAllocateRegisters,
926 CompilerPass::kReorderBlocks,
937 const char* kScript = R
"(
940 // This is purely a placeholder and is never called.
941 void placeholder() {}
943 // Will call the "doFfiCall" and exercise its code.
944 bool invokeDoFfiCall() {
945 final double result = doFfiCall(1, 2, 3, 1.0, 2.0, 3.0);
946 if (result != (2 + 3 + 4 + 2.0 + 3.0 + 4.0)) {
947 throw 'Failed. Result was $result.';
952 // Will perform a "C" call while having live values in registers
953 // across the FfiCall.
954 double doFfiCall(int a, int b, int c, double x, double y, double z) {
955 // Ensure there is at least one live value in a register.
962 // We'll replace this StaticCall with an FfiCall.
964 // Use the live value.
965 return (a + b + c + x + y + z);
968 // FFI trampoline function.
969 typedef NT = Void Function();
970 typedef DT = void Function();
971 Pointer<NativeFunction<NT>> ptr = Pointer.fromAddress(0);
972 DT getFfiTrampolineClosure() => ptr.asFunction(isLeaf:true);
975 const auto& root_library = Library::Handle(
LoadTestScript(kScript));
978 auto& c_function = Instructions::Handle(
984#if defined(TARGET_ARCH_ARM)
999 uword native_entry = c_function.EntryPoint();
1002 Invoke(root_library,
"invokeDoFfiCall");
1005 Function::Handle(
GetFunction(root_library,
"doFfiCall"));
1008 const auto&
value = Closure::Handle(
1009 Closure::RawCast(
Invoke(root_library,
"getFfiTrampolineClosure")));
1011 const auto& ffi_trampoline =
1017 const char*
error =
nullptr;
1018 auto*
const zone = thread->zone();
1019 const auto& c_signature =
1020 FunctionType::ZoneHandle(zone, ffi_trampoline.FfiCSignature());
1021 const auto marshaller_ptr = compiler::ffi::CallMarshaller::FromFunction(
1022 zone, ffi_trampoline, 1, c_signature,
1026 const auto& marshaller = *marshaller_ptr;
1028 const auto& compile_and_run =
1031 TestPipeline pipeline(do_ffi_call, CompilerPass::kJIT);
1041 {kMoveGlob, {kMatchAndMoveParallelMove, ¶llel_move}})) {
1042 verify(parallel_move);
1047 pipeline.CompileGraphAndAttachFunction();
1050 auto&
result = Object::Handle(
Invoke(root_library,
"invokeDoFfiCall"));
1055 intptr_t num_cpu_reg_to_stack_nonleaf = 0;
1056 intptr_t num_cpu_reg_to_stack_leaf = 0;
1057 intptr_t num_fpu_reg_to_stack_nonleaf = 0;
1058 intptr_t num_fpu_reg_to_stack_leaf = 0;
1061 compile_and_run(
false, [&](ParallelMoveInstr* parallel_move) {
1063 for (
int i = 0; i < parallel_move->NumMoves(); i++) {
1064 auto move = parallel_move->moves()[i];
1065 if (move->src_slot()->IsRegister() && move->dest_slot()->IsStackSlot()) {
1066 num_cpu_reg_to_stack_nonleaf++;
1067 }
else if (move->src_slot()->IsFpuRegister() &&
1068 move->dest_slot()->IsDoubleStackSlot()) {
1069 num_fpu_reg_to_stack_nonleaf++;
1075 compile_and_run(
true, [&](ParallelMoveInstr* parallel_move) {
1078 for (
int i = 0; i < parallel_move->NumMoves(); i++) {
1079 auto move = parallel_move->moves()[i];
1080 if (move->src_slot()->IsRegister() && move->dest_slot()->IsStackSlot()) {
1081 num_cpu_reg_to_stack_leaf++;
1082 }
else if (move->src_slot()->IsFpuRegister() &&
1083 move->dest_slot()->IsDoubleStackSlot()) {
1084 num_fpu_reg_to_stack_leaf++;
1090 EXPECT_LT(num_cpu_reg_to_stack_leaf, num_cpu_reg_to_stack_nonleaf);
1092 const bool has_callee_save_fpu_regs =
1093 Utils::CountOneBitsWord(kAbiVolatileFpuRegs) <
1094 Utils::CountOneBitsWord(kAllFpuRegistersList);
1095 EXPECT(!has_callee_save_fpu_regs ||
1096 num_fpu_reg_to_stack_leaf < num_fpu_reg_to_stack_nonleaf);
1100 const char* function_name,
1110 EXPECT(entry !=
nullptr);
1114 ILMatcher cursor(flow_graph, entry,
true, ParallelMovesHandling::kSkip);
1117 {kMatchDartReturn, &ret},
1120 ConstantInstr* constant = ret->value()->definition()->AsConstant();
1121 EXPECT(constant !=
nullptr);
1122 if (constant !=
nullptr) {
1123 const Object&
value = constant->value();
1125 if (
value.IsSmi()) {
1126 const intptr_t int_value = Smi::Cast(value).Value();
1135 b0() => 0. bitLength; // 0...00000
1136 b1() => 1. bitLength; // 0...00001
1137 b100() => 100. bitLength;
1138 b200() => 200. bitLength;
1139 bffff() => 0xffff. bitLength;
1140 m1() => (-1).bitLength; // 1...11111
1141 m2() => (-2).bitLength; // 1...11110
1155 const auto& root_library = Library::Handle(
LoadTestScript(kScript));
1156 Invoke(root_library,
"main");
1158 auto test = [&](
const char*
function, intptr_t expected) {
1174 bool allow_representation_change) {
1177 const auto& lib = Library::Handle(Library::CoreLibrary());
1178 const Class& list_class =
1179 Class::Handle(lib.LookupClassAllowPrivate(Symbols::_List()));
1183 const Function& list_filled = Function::ZoneHandle(
1190 H.AddVariable(
"param", AbstractType::ZoneHandle(Type::IntType()));
1192 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
1200 param = builder.AddParameter(0, kUnboxedInt64);
1208 std::move(
args), DeoptId::kNone, 0, ICData::kNoRebind));
1209 array->
UpdateType(CompileType::FromCid(kArrayCid));
1217 new Value(
load), DeoptId::kNone, Instruction::kNotSpeculative));
1220 Token::kADD,
new Value(unbox),
new Value(
H.IntConstant(1)),
1221 S.GetNextDeoptId(), Instruction::kNotSpeculative));
1225 builder.AddReturn(
new Value(box));
1230 if (!allow_representation_change) {
1231 H.flow_graph()->disallow_unmatched_representations();
1234 H.flow_graph()->Canonicalize();
1236 if (allow_representation_change) {
1258 const auto& typed_data_lib = Library::Handle(Library::TypedDataLibrary());
1259 const auto& view_cls = Class::Handle(
1260 typed_data_lib.LookupClassAllowPrivate(Symbols::_Float32ArrayView()));
1261 const Error& err = Error::Handle(view_cls.EnsureIsFinalized(thread));
1263 const auto& factory =
1264 Function::ZoneHandle(view_cls.LookupFactoryAllowPrivate(String::Handle(
1265 String::Concat(Symbols::_Float32ArrayView(), Symbols::DotUnder()))));
1266 EXPECT(!factory.IsNull());
1272 const Slot* field =
nullptr;
1273 switch (field_kind) {
1275 field = &Slot::TypedDataBase_length();
1278 field = &Slot::TypedDataView_offset_in_bytes();
1281 field = &Slot::TypedDataView_typed_data();
1285 auto b1 =
H.flow_graph()->graph_entry()->normal_entry();
1287 const auto constant_4 =
H.IntConstant(4);
1288 const auto constant_1 =
H.IntConstant(1);
1303 {
new Value(
H.flow_graph()->constant_null()),
new Value(array),
1304 new Value(constant_4),
new Value(constant_1)},
1305 DeoptId::kNone, 1, ICData::RebindRule::kStatic));
1307 load = builder.AddDefinition(
1310 ret = builder.AddReturn(
new Value(
load));
1313 H.flow_graph()->Canonicalize();
1315 switch (field_kind) {
1339 const auto& typed_data_lib = Library::Handle(Library::TypedDataLibrary());
1340 const auto& view_cls = Class::Handle(typed_data_lib.LookupClassAllowPrivate(
1341 String::Handle(Symbols::New(thread,
"_TypedListBase"))));
1342 const Error& err = Error::Handle(view_cls.EnsureIsFinalized(thread));
1344 const auto& getter = Function::Handle(
1345 view_cls.LookupFunctionAllowPrivate(Symbols::GetLength()));
1346 EXPECT(!getter.IsNull());
1352 auto b1 =
H.flow_graph()->graph_entry()->normal_entry();
1362 new Value(
H.IntConstant(1)), DeoptId::kNone));
1366 {
new Value(array)}, 0, Array::empty_array(), 1,
1370 ret = builder.AddReturn(
new Value(length_call));
1373 H.flow_graph()->Canonicalize();
1378 it.function().ptr() == getter.ptr());
1388 H.AddVariable(
"v0",
type);
1390 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
1395 Definition* param = builder.AddParameter(0, kTagged);
1403 H.flow_graph()->Canonicalize();
1413 kOneByteStringCid, kTwoByteStringCid,
false);
1421 kClassIdTagMax,
true);
1425 const Class& test_cls,
1427 intptr_t num_stores,
1428 bool expected_to_forward) {
1435 auto b1 =
H.flow_graph()->graph_entry()->normal_entry();
1437 const auto constant_42 =
H.IntConstant(42);
1438 const auto constant_24 =
H.IntConstant(24);
1445 const auto obj = builder.AddDefinition(
1448 if (num_stores >= 1) {
1451 field,
new Value(obj),
new Value(constant_42),
1453 &
H.flow_graph()->parsed_function(),
1454 StoreFieldInstr::Kind::kInitializing));
1457 if (num_stores >= 2) {
1460 field,
new Value(obj),
new Value(constant_24),
1462 &
H.flow_graph()->parsed_function()));
1467 new Value(obj), Slot::Get(field, &
H.flow_graph()->parsed_function()),
1471 ret = builder.AddReturn(
new Value(
load));
1474 H.flow_graph()->Canonicalize();
1476 if (expected_to_forward) {
1484 const char* script_chars = R
"(
1485 import 'dart:typed_data';
1488 final dynamic finalField;
1489 late final dynamic lateFinalField;
1490 dynamic normalField;
1492 TestClass(this.finalField, this.lateFinalField, this.normalField);
1497 const auto& test_cls = Class::ZoneHandle(
1498 lib.LookupClass(String::Handle(Symbols::New(thread,
"TestClass"))));
1499 const auto& err = Error::Handle(test_cls.EnsureIsFinalized(thread));
1502 const auto lookup_field = [&](
const char*
name) ->
const Field& {
1503 const auto& original_field = Field::Handle(
1504 test_cls.LookupField(String::Handle(Symbols::New(thread,
name))));
1505 EXPECT(!original_field.IsNull());
1506 return Field::Handle(original_field.CloneFromOriginal());
1509 const auto& final_field = lookup_field(
"finalField");
1510 const auto& late_final_field = lookup_field(
"lateFinalField");
1511 const auto& normal_field = lookup_field(
"normalField");
static bool compare(const SkBitmap &ref, const SkIRect &iref, const SkBitmap &test, const SkIRect &itest)
static void test_range(skiatest::Reporter *reporter)
#define RELEASE_ASSERT(cond)
void AddArray(const BaseGrowableArray< T, B, Allocator > &src)
static const Bool & True()
ClassPtr At(intptr_t cid) const
bool HasValidClassAt(intptr_t cid) const
ErrorPtr EnsureIsFinalized(Thread *thread) const
FunctionPtr LookupFactoryAllowPrivate(const String &name) const
PRINT_OPERANDS_TO_SUPPORT PRINT_TO_SUPPORT bool UpdateType(CompileType new_type)
void set_range(const Range &)
static constexpr intptr_t kNone
void Fail(const char *format,...) const PRINTF_ATTRIBUTE(2
GraphEntryInstr * graph_entry() const
ConstantInstr * GetConstant(const Object &object, Representation representation=kTagged)
BlockIterator reverse_postorder_iterator() const
void InsertBefore(Instruction *next, Instruction *instr, Environment *env, UseKind use_kind)
FunctionEntryInstr * normal_entry() const
const CidRangeVector & SubtypeRangesForClass(const Class &klass, bool include_abstract, bool exclude_null)
bool CanUseSubtypeRangeCheckFor(const AbstractType &type)
bool TryMatch(std::initializer_list< MatchCode > match_codes, MatchOpCode insert_before=kInvalidMatchOpCode)
void EnsureICData(FlowGraph *graph)
virtual Value * InputAt(intptr_t i) const =0
virtual bool ComputeCanDeoptimize() const =0
void SetInputAt(intptr_t i, Value *value)
Instruction * RemoveFromGraph(bool return_previous=true)
Instruction * previous() const
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
static Object & ZoneHandle()
void SetResultType(Zone *zone, CompileType new_type)
void set_is_known_list_constructor(bool value)
static const char * NullableTag()
void RunAdditionalPasses(std::initializer_list< CompilerPass::Id > passes)
FlowGraph * RunPasses(std::initializer_list< CompilerPass::Id > passes)
std::unique_ptr< char, decltype(std::free) * > CStringUniquePtr
bool BindsToConstant() const
bool Equals(const Value &other) const
const Object & BoundConstant() const
Definition * definition() const
void LoadDImmediate(DRegister dd, double value, Register scratch, Condition cond=AL)
void Ret(Condition cond=AL)
void LoadImmediate(Register rd, Immediate value, Condition cond=AL)
#define THR_Print(format,...)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const char * expected_value
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
Dart_NativeFunction function
#define RANGES_CONTAIN_EXPECTED_CIDS(ranges, cids)
#define EXPECT_PROPERTY(entity, property)
constexpr int16_t kMaxInt16
LibraryPtr LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri)
static void WriteCidRangeVectorTo(const CidRangeVector &ranges, BaseTextBuffer *buffer)
@ TypedDataView_offset_in_bytes
@ TypedDataView_typed_data
constexpr int32_t kMinInt32
static void TestTestRangeCanonicalize(const AbstractType &type, uword lower, uword upper, bool result)
static void TestRepresentationChangeDuringCanonicalization(Thread *thread, bool allow_representation_change)
constexpr uint32_t kMaxUint32
static void TestCanonicalizationOfTypedDataViewFieldLoads(Thread *thread, TypeDataField field_kind)
ObjectPtr Invoke(const Library &lib, const char *name)
FunctionPtr GetFunction(const Library &lib, const char *name)
static void RunInitializingStoresTest(const Library &root_library, const char *function_name, CompilerPass::PipelineMode mode, const std::vector< const char * > &expected_stores)
bool TestIntConverterCanonicalizationRule(Thread *thread, int64_t min_value, int64_t max_value, Representation initial, Representation intermediate, Representation final)
static void TestNullAwareEqualityCompareCanonicalization(Thread *thread, bool allow_representation_change)
const int kNumberOfFpuRegisters
static void TestConstantFoldToSmi(const Library &root_library, const char *function_name, CompilerPass::PipelineMode mode, intptr_t expected_value)
static void ExpectStores(FlowGraph *flow_graph, const std::vector< const char * > &expected_stores)
const RegList kDartVolatileCpuRegs
static void RangesContainExpectedCids(const Expect &expect, const CidRangeVector &ranges, const GrowableArray< intptr_t > &expected)
constexpr int32_t kMaxInt32
static void WriteCidTo(intptr_t cid, BaseTextBuffer *buffer)
constexpr int16_t kMinInt16
static bool ExpectRangesContainCid(const Expect &expect, const CidRangeVector &ranges, intptr_t expected)
const char *const function_name
void TestStaticFieldForwarding(Thread *thread, const Class &test_cls, const Field &field, intptr_t num_stores, bool expected_to_forward)
InstructionsPtr BuildInstructions(std::function< void(compiler::Assembler *assembler)> fun)
const RegList kAbiVolatileFpuRegs
static constexpr intptr_t kInvalidTryIndex
FlowGraph * SetupFfiFlowgraph(TestPipeline *pipeline, const compiler::ffi::CallMarshaller &marshaller, uword native_entry, bool is_leaf)
#define ISOLATE_UNIT_TEST_CASE(name)