27 EXPECT(target_instr->IsBlockEntry());
28 EXPECT(!target_instr->IsDefinition());
54 const char* kScript = R
"(
56 operator []=(var index, var value) {
57 return data[index] = value;
60 List<T?> data = List<T?>.filled(10, null);
63 Container<int> x = Container<int>();
66 for (int i = 0; i < 10; ++i) {
76 Invoke(root_library,
"foo");
86 ILMatcher cursor(flow_graph, entry,
true);
89 kMatchAndMoveBranchTrue,
91 {kMatchStoreIndexed, &store_indexed},
94 EXPECT(!store_indexed->value()->NeedsWriteBarrier());
98 const std::vector<const char*>& expected_stores) {
99 size_t next_expected_store = 0;
101 !block_it.
Done(); block_it.Advance()) {
104 if (
auto store = it.Current()->AsStoreField()) {
105 EXPECT_LT(next_expected_store, expected_stores.size());
106 EXPECT_STREQ(expected_stores[next_expected_store],
107 store->slot().Name());
108 next_expected_store++;
118 const std::vector<const char*>& expected_stores) {
123 CompilerPass::kComputeSSA,
124 CompilerPass::kTypePropagation,
125 CompilerPass::kApplyICData,
126 CompilerPass::kInlining,
127 CompilerPass::kTypePropagation,
128 CompilerPass::kSelectRepresentations,
129 CompilerPass::kCanonicalize,
130 CompilerPass::kConstantPropagation,
132 ASSERT(flow_graph !=
nullptr);
138 const char* kScript = R
"(
143 Bar({this.f, this.g});
145 Bar f1() => Bar(f: 10);
146 Bar f2() => Bar(g: 10);
151 return () { return value; };
162 const auto& root_library = Library::Handle(
LoadTestScript(kScript));
163 Invoke(root_library,
"main");
171 {
"Closure.function",
"Closure.entry_point"});
177 std::vector<const char*> expected_stores_jit;
178 std::vector<const char*> expected_stores_aot;
180 expected_stores_jit.insert(
181 expected_stores_jit.end(),
182 {
"value",
"Context.parent",
"Context.parent",
"value",
183 "Closure.function_type_arguments",
"Closure.context"});
184 expected_stores_aot.insert(
185 expected_stores_aot.end(),
186 {
"value",
"Closure.function_type_arguments",
"Closure.context"});
189 expected_stores_jit);
191 expected_stores_aot);
210 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
217 v0 =
builder.AddParameter(0, initial);
219 RangeBoundary::FromConstant(max_value)));
221 initial, intermediate,
new Value(v0),
S.GetNextDeoptId()));
223 intermediate, initial,
new Value(conv1),
S.GetNextDeoptId()));
229 H.flow_graph()->Canonicalize();
230 H.flow_graph()->Canonicalize();
237 kUnboxedInt64, kUnboxedInt32,
240 kUnboxedInt64, kUnboxedInt32,
244 kUnboxedInt32, kUnboxedInt64));
246 thread, 0,
kMaxInt16, kUnboxedInt64, kUnboxedUint32, kUnboxedInt64));
248 thread, 0,
kMaxInt32, kUnboxedInt64, kUnboxedUint32, kUnboxedInt64));
250 thread, 0,
kMaxUint32, kUnboxedInt64, kUnboxedUint32, kUnboxedInt64));
252 thread, 0,
static_cast<int64_t
>(
kMaxUint32) + 1, kUnboxedInt64,
253 kUnboxedUint32, kUnboxedInt64));
255 thread, -1,
kMaxInt16, kUnboxedInt64, kUnboxedUint32, kUnboxedInt64));
259 kUnboxedInt32, kUnboxedUint32,
262 kUnboxedInt32, kUnboxedUint32,
265 thread, 0,
kMaxInt32, kUnboxedInt32, kUnboxedUint32, kUnboxedInt64));
267 thread, 0,
kMaxInt32, kUnboxedInt32, kUnboxedUint32, kUnboxedInt32));
278 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
279 auto b2 =
H.JoinEntry();
280 auto b3 =
H.TargetEntry();
281 auto b4 =
H.TargetEntry();
289 v0 =
builder.AddParameter(0, kTagged);
302 false,
S.GetNextDeoptId()),
318 H.flow_graph()->Canonicalize();
333 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
355 new Value(
H.flow_graph()->constant_null()),
357 new Value(
H.flow_graph()->constant_null()),
358 String::Handle(String::New(
"not-null")),
359 S.GetNextDeoptId()));
361 new Value(
cast),
S.GetNextDeoptId(), BoxInstr::kGuardInputs));
374 FlowGraphTypePropagator::Propagate(
H.flow_graph());
377 H.flow_graph()->Canonicalize();
380 H.flow_graph()->RemoveRedefinitions();
385 ClassTable*
const class_table = IsolateGroup::Current()->class_table();
388 const auto& cls = Class::Handle(class_table->
At(
cid));
389 buffer->Printf(
" (%s", cls.ScrubbedNameCString());
390 if (cls.is_abstract()) {
391 buffer->AddString(
", abstract");
399 bool allow_representation_change) {
408 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
420 kMintCid,
S.GetNextDeoptId(),
true));
426 if (!allow_representation_change) {
427 H.flow_graph()->disallow_unmatched_representations();
430 H.flow_graph()->Canonicalize();
432 EXPECT(
compare->is_null_aware() == !allow_representation_change);
443 buffer->AddString(
"empty CidRangeVector");
446 buffer->AddString(
"non-empty CidRangeVector:\n");
447 for (
const auto& range : ranges) {
448 for (intptr_t
cid = range.cid_start;
cid <= range.cid_end;
cid++) {
459 for (
const auto& range : ranges) {
460 for (intptr_t
cid = range.cid_start;
cid <= range.cid_end;
cid++) {
461 if (expected ==
cid)
return true;
465 buffer.AddString(
"Expected CidRangeVector to include cid ");
478 buffer.AddString(
"Checking that ");
480 buffer.AddString(
"includes cids:\n");
481 for (
const intptr_t
cid : expected) {
488 bool all_found =
true;
489 for (
const intptr_t
cid : expected) {
495 THR_Print(
"All expected cids included.\n\n");
499#define RANGES_CONTAIN_EXPECTED_CIDS(ranges, cids) \
500 RangesContainExpectedCids(dart::Expect(__FILE__, __LINE__), ranges, cids)
505 Type::Handle(IsolateGroup::Current()->object_store()->object_type());
506 const bool is_nullable = Instance::NullIsAssignableTo(
type);
508 const auto& cls = Class::Handle(
type.type_class());
510 ClassTable*
const class_table = thread->isolate_group()->class_table();
511 const intptr_t num_cids = class_table->
NumCids();
512 auto& to_check = Class::Handle(thread->zone());
513 auto& rare_type = AbstractType::Handle(thread->zone());
517 for (intptr_t
cid = kInstanceCid;
cid < num_cids;
cid++) {
523 to_check = class_table->
At(
cid);
525 if (to_check.is_abstract()) {
526 expected_abstract_cids.
Add(
cid);
528 expected_concrete_cids.
Add(
cid);
530 if (
cid != kTypeArgumentsCid) {
531 rare_type = to_check.RareType();
537 cls,
false, !is_nullable);
541 expected_cids.
AddArray(expected_concrete_cids);
542 expected_cids.
AddArray(expected_abstract_cids);
544 cls,
true, !is_nullable);
551 Type::Handle(IsolateGroup::Current()->object_store()->function_type());
553 const auto& cls = Class::Handle(
type.type_class());
556 expected_concrete_cids.
Add(kClosureCid);
559 expected_abstract_cids.
Add(
type.type_class_id());
566 expected_cids.
AddArray(expected_concrete_cids);
567 expected_cids.
AddArray(expected_abstract_cids);
575 const auto& num_type = Type::Handle(Type::Number());
577 const auto& double_type = Type::Handle(Type::Double());
579 const auto& cls = Class::Handle(num_type.type_class());
582 expected_concrete_cids.
Add(kSmiCid);
583 expected_concrete_cids.
Add(kMintCid);
584 expected_concrete_cids.
Add(kDoubleCid);
587 expected_abstract_cids.
Add(num_type.type_class_id());
588 expected_abstract_cids.
Add(int_type.type_class_id());
589 expected_abstract_cids.
Add(double_type.type_class_id());
596 expected_cids.
AddArray(expected_concrete_cids);
597 expected_cids.
AddArray(expected_abstract_cids);
607 const auto& cls = Class::Handle(
type.type_class());
610 expected_concrete_cids.
Add(kSmiCid);
611 expected_concrete_cids.
Add(kMintCid);
614 expected_abstract_cids.
Add(
type.type_class_id());
621 expected_cids.
AddArray(expected_concrete_cids);
622 expected_cids.
AddArray(expected_abstract_cids);
630 const auto&
type = Type::Handle(Type::StringType());
632 const auto& cls = Class::Handle(
type.type_class());
635 expected_concrete_cids.
Add(kOneByteStringCid);
636 expected_concrete_cids.
Add(kTwoByteStringCid);
639 expected_abstract_cids.
Add(
type.type_class_id());
643 THR_Print(
"Checking concrete subtype ranges for String\n");
647 expected_cids.
AddArray(expected_concrete_cids);
648 expected_cids.
AddArray(expected_abstract_cids);
651 THR_Print(
"Checking concrete and abstract subtype ranges for String\n");
659 const char* kScript = R
"(
660 bool foo(double x) => (x + 0.5) == 0;
666 const auto& root_library = Library::Handle(
LoadTestScript(kScript));
673 ILMatcher cursor(flow_graph, entry,
true,
674 ParallelMovesHandling::kSkip);
678 kMatchAndMoveBinaryDoubleOp,
679 kMatchAndMoveEqualityCompare,
693 void anotherFunction() {}
697 const auto& root_library = Library::Handle(
LoadTestScript(kScript));
698 Zone*
const zone = Thread::Current()->zone();
699 auto& invoke_result = Instance::Handle(zone);
700 invoke_result ^=
Invoke(root_library,
"myFunction");
701 EXPECT_EQ(Smi::New(100), invoke_result.ptr());
703 const auto& my_function =
704 Function::Handle(
GetFunction(root_library,
"myFunction"));
708 CompilerPass::kComputeSSA,
717 {kMatchDartReturn, &return_instr},
721 auto*
const load_thread_instr =
new (zone) LoadThreadInstr();
722 flow_graph->InsertBefore(return_instr, load_thread_instr,
nullptr,
724 auto load_thread_value =
Value(load_thread_instr);
726 auto*
const convert_instr =
new (zone) IntConverterInstr(
728 flow_graph->InsertBefore(return_instr, convert_instr,
nullptr,
730 auto convert_value =
Value(convert_instr);
733 flow_graph->InsertBefore(return_instr, box_instr,
nullptr, FlowGraph::kValue);
735 return_instr->InputAt(0)->definition()->ReplaceUsesWith(box_instr);
739 ILMatcher cursor(flow_graph, flow_graph->graph_entry()->normal_entry());
742 kMatchAndMoveLoadThread,
743 kMatchAndMoveIntConverter,
749 pipeline.RunForcedOptimizedAfterSSAPasses();
752#if !defined(PRODUCT) && !defined(USING_THREAD_SANITIZER)
753 SetFlagScope<bool> sfs(&FLAG_disassemble_optimized,
true);
755 pipeline.CompileGraphAndAttachFunction();
759 invoke_result ^=
Invoke(root_library,
"myFunction");
760 intptr_t result_int = Integer::Cast(invoke_result).AsInt64Value();
761 EXPECT_EQ(
reinterpret_cast<intptr_t
>(thread), result_int);
764#if !defined(TARGET_ARCH_IA32)
768 int globalCounter = 0;
770 int increment() => ++globalCounter;
772 int cachedIncrement() {
773 // We will replace this call with a cacheable call,
774 // which will lead to the counter no longer being incremented.
775 // Make sure to return the value, so we can see that the boxing and
776 // unboxing works as expected.
780 int multipleIncrement() {
782 for(int i = 0; i < 10; i++) {
783 // Save the last returned value.
784 returnValue = cachedIncrement();
791 const auto& root_library = Library::Handle(
LoadTestScript(kScript.get()));
792 const auto& first_result =
793 Object::Handle(
Invoke(root_library,
"multipleIncrement"));
794 EXPECT(first_result.IsSmi());
795 if (first_result.IsSmi()) {
796 const intptr_t int_value = Smi::Cast(first_result).Value();
797 EXPECT_EQ(10, int_value);
800 const auto& cached_increment_function =
801 Function::Handle(
GetFunction(root_library,
"cachedIncrement"));
803 const auto& increment_function =
804 Function::ZoneHandle(
GetFunction(root_library,
"increment"));
806 TestPipeline pipeline(cached_increment_function, CompilerPass::kJIT);
808 CompilerPass::kComputeSSA,
817 {kMatchAndMoveStaticCall, &static_call},
824 CachableIdempotentCallInstr*
call =
new CachableIdempotentCallInstr(
826 static_call->type_args_len(), Array::empty_array(), std::move(
args),
828 static_call->ReplaceWith(
call,
nullptr);
830 pipeline.RunForcedOptimizedAfterSSAPasses();
833 ILMatcher cursor(flow_graph, flow_graph->graph_entry()->normal_entry());
837 kMatchAndMoveCachableIdempotentCall,
849 SetFlagScope<bool> sfs(&FLAG_disassemble_optimized,
true);
851 pipeline.CompileGraphAndAttachFunction();
854 const auto& second_result =
855 Object::Handle(
Invoke(root_library,
"multipleIncrement"));
856 EXPECT(second_result.IsSmi());
857 if (second_result.IsSmi()) {
858 const intptr_t int_value = Smi::Cast(second_result).Value();
859 EXPECT_EQ(11, int_value);
887 Integer::Handle(
Z, Integer::NewCanonical(native_entry)),
890 flow_graph->
InsertBefore(static_call, load_entry_point,
nullptr,
894 const intptr_t num_arguments =
895 FfiCallInstr::InputCountForMarshaller(marshaller);
898 arguments.
Add(
new (
Z)
Value(load_entry_point));
899 auto*
const ffi_call =
new (
Z)
902 ffi_call->InputAt(ffi_call->TargetAddressIndex())->definition() ==
904 flow_graph->
InsertBefore(static_call, ffi_call,
nullptr,
913 CompilerPass::kApplyICData,
914 CompilerPass::kTryOptimizePatterns,
915 CompilerPass::kSetOuterInliningId,
916 CompilerPass::kTypePropagation,
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 =
1095 EXPECT(!has_callee_save_fpu_regs ||
1096 num_fpu_reg_to_stack_leaf < num_fpu_reg_to_stack_nonleaf);
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);
1203 args.Add(
new Value(
H.flow_graph()->constant_null()));
1209 array->
UpdateType(CompileType::FromCid(kArrayCid));
1220 Token::kADD,
new Value(unbox),
new Value(
H.IntConstant(1)),
1221 S.GetNextDeoptId(), Instruction::kNotSpeculative));
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) {
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)},
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();
1366 {
new Value(array)}, 0, Array::empty_array(), 1,
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();
1403 H.flow_graph()->Canonicalize();
1413 kOneByteStringCid, kTwoByteStringCid,
false);
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()));
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");
1535template <
typename... Args>
1537 const Array& args_array = Array::Handle(Array::New(
sizeof...(Args)));
1544 intptr_t num_parameters,
1552 return H.flow_graph();
1555 CompilerPass::kFinalizeGraph,
1556 CompilerPass::kReorderBlocks,
1557 CompilerPass::kAllocateRegisters,
1559 pipeline.CompileGraphAndAttachFunction();
1573 std::optional<int64_t> immediate_mask) {
1576 1 + (!immediate_mask.has_value() ? 1 : 0),
1578 H.AddVariable(
"lhs", AbstractType::ZoneHandle(Type::IntType()),
1579 new CompileType(CompileType::Int()));
1580 if (!immediate_mask.has_value()) {
1581 H.AddVariable(
"rhs", AbstractType::ZoneHandle(Type::IntType()),
1582 new CompileType(CompileType::Int()));
1585 auto normal_entry =
H.flow_graph()->graph_entry()->normal_entry();
1586 auto true_successor =
H.TargetEntry();
1587 auto false_successor =
H.TargetEntry();
1590 BlockBuilder builder(H.flow_graph(), normal_entry);
1591 Definition* lhs = builder.AddParameter(0);
1592 Definition* rhs = immediate_mask.has_value()
1593 ? H.IntConstant(immediate_mask.value(), rep)
1594 : builder.AddParameter(1);
1595 if (rep != lhs->representation()) {
1597 builder.AddUnboxInstr(kUnboxedInt64, lhs, false);
1599 if (rep != rhs->representation()) {
1601 builder.AddUnboxInstr(kUnboxedInt64, rhs, false);
1608 if (test_variant == TestIntVariant::kTestValue) {
1609 auto v2 =
builder.AddDefinition(comparison);
1612 builder.AddBranch(comparison, true_successor, false_successor);
1616 if (test_variant == TestIntVariant::kTestBranch) {
1618 BlockBuilder
builder(
H.flow_graph(), true_successor);
1620 new Value(
H.flow_graph()->GetConstant(Bool::True())));
1624 BlockBuilder
builder(
H.flow_graph(), false_successor);
1636 const std::vector<int64_t>&
inputs,
1640 auto invoke = [&](int64_t v) ->
bool {
1641 const auto& input = Integer::Handle(Integer::New(v));
1642 EXPECT(rep == kUnboxedInt64 || input.IsSmi());
1647 for (
auto& input :
inputs) {
1648 const auto expected = ((input & mask) == 0) == eq_zero;
1649 const auto got = invoke(input);
1650 if (expected != got) {
1652 " %s 0: expected %s but got %s\n",
1653 test_variant == TestIntVariant::kTestBranch ?
"branch" :
"value",
1654 RepresentationUtils::ToCString(rep), input, mask,
1655 eq_zero ?
"==" :
"!=", expected ?
"true" :
"false",
1656 got ?
"true" :
"false");
1665 const std::vector<int64_t>&
inputs,
1666 const std::vector<int64_t>& masks) {
1672 auto invoke = [&](int64_t lhs, int64_t mask) ->
bool {
1673 const auto& arg0 = Integer::Handle(Integer::New(lhs));
1674 const auto& arg1 = Integer::Handle(Integer::New(mask));
1675 EXPECT(rep == kUnboxedInt64 || arg0.IsSmi());
1676 EXPECT(rep == kUnboxedInt64 || arg1.IsSmi());
1682 for (
auto& mask : masks) {
1686 if (rep == kTagged && !Smi::IsValid(mask)) {
1690 for (
auto& input :
inputs) {
1691 const auto expected = ((input & mask) == 0) == eq_zero;
1692 const auto got = invoke(input, mask);
1693 if (expected != got) {
1695 " %s 0: expected %s but got %s\n",
1696 test_variant == TestIntVariant::kTestBranch ?
"branch" :
"value",
1697 RepresentationUtils::ToCString(rep), input, mask,
1698 eq_zero ?
"==" :
"!=", expected ?
"true" :
"false",
1699 got ?
"true" :
"false");
1706 const int64_t msb =
static_cast<int64_t
>(0x8000000000000000L);
1707 const int64_t kSmiSignBit =
kSmiMax + 1;
1709 const std::initializer_list<int64_t> kMasks = {
1710 1, 2, kSmiSignBit, kSmiSignBit | 1, msb, msb | 1};
1712 const std::vector<std::pair<Representation, std::vector<int64_t>>> kValues = {
1718 kSmiMin | 1, msb, msb | 1, msb | 2}},
1721 for (
auto test_variant :
1722 {TestIntVariant::kTestBranch, TestIntVariant::kTestValue}) {
1723 for (
auto eq_zero : {
true,
false}) {
1724 for (
auto& [rep,
values] : kValues) {
1742 H.flow_graph()->graph_entry()->normal_entry());
1743 const auto& coverage_array = Array::Handle(Array::New(1));
1744 coverage_array.SetAt(0, Smi::Handle(Smi::New(0)));
1747 builder.AddReturn(
new Value(
H.flow_graph()->constant_null()));
1751 return H.flow_graph();
1754 auto flow_graph = pipeline.
RunPasses({});
1757 EXPECT(flow_graph->graph_entry()->normal_entry()->next()->IsRecordCoverage());
static void test_range(skiatest::Reporter *reporter)
static sk_sp< Effect > Create()
#define RELEASE_ASSERT(cond)
void SetAt(intptr_t index, const Object &value) const
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)
const Function & function() const
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
bool Equals(const Instruction &other) const
void SetInputAt(intptr_t i, Value *value)
Instruction * RemoveFromGraph(bool return_previous=true)
Instruction * previous() const
static Object & ZoneHandle()
void SetResultType(Zone *zone, CompileType new_type)
void set_is_known_list_constructor(bool value)
void RunAdditionalPasses(std::initializer_list< CompilerPass::Id > passes)
FlowGraph * RunPasses(std::initializer_list< CompilerPass::Id > passes)
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,...)
#define FAIL(name, result)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const char * expected_value
const uint8_t uint32_t uint32_t GError ** error
Dart_NativeFunction function
#define RANGES_CONTAIN_EXPECTED_CIDS(ranges, cids)
#define EXPECT_PROPERTY(entity, property)
const GrXPFactory * Get(SkBlendMode mode)
bool IsSupported(const SkMaskFilter *maskfilter)
const Type & ObjectType()
const Type & DynamicType()
constexpr int16_t kMaxInt16
LibraryPtr LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri)
static void WriteCidRangeVectorTo(const CidRangeVector &ranges, BaseTextBuffer *buffer)
static const Function & BuildTestIntFunction(Zone *zone, TestIntVariant test_variant, bool eq_zero, Representation rep, std::optional< int64_t > immediate_mask)
@ TypedDataView_offset_in_bytes
@ TypedDataView_typed_data
const RegList kAllFpuRegistersList
constexpr int32_t kMinInt32
static void TestIntTest(Zone *zone, TestIntVariant test_variant, bool eq_zero, Representation rep, const std::vector< int64_t > &inputs, const std::vector< int64_t > &masks)
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
GrowableArray< Value * > InputsArray
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)
static ObjectPtr InvokeFunction(const Function &function, Args &... args)
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 const char * Concat(const char *a, const char *b)
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)
ISOLATE_UNIT_TEST_CASE(StackAllocatedDestruction)
static void TestIntTestWithImmediate(Zone *zone, TestIntVariant test_variant, bool eq_zero, Representation rep, const std::vector< int64_t > &inputs, int64_t mask)
const RegList kDartVolatileCpuRegs
static void RangesContainExpectedCids(const Expect &expect, const CidRangeVector &ranges, const GrowableArray< intptr_t > &expected)
static constexpr Representation kUnboxedAddress
constexpr int32_t kMaxInt32
static void WriteCidTo(intptr_t cid, BaseTextBuffer *buffer)
static constexpr Representation kUnboxedIntPtr
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
static const Function & BuildTestFunction(intptr_t num_parameters, std::function< void(FlowGraphBuilderHelper &)> build_graph)
static constexpr intptr_t kClassIdTagMax
FlowGraph * SetupFfiFlowgraph(TestPipeline *pipeline, const compiler::ffi::CallMarshaller &marshaller, uword native_entry, bool is_leaf)
DEF_SWITCHES_START aot vmservice shared library name
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 buffer
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
int compare(const void *untyped_lhs, const void *untyped_rhs)
static SkString join(const CommandLineFlags::StringArray &)
#define ISOLATE_UNIT_TEST_CASE(name)