688 auto zone =
H.flow_graph()->zone();
706 const auto& lib = Library::Handle(zone, Library::TypedDataLibrary());
708 const Class& view_cls = Class::ZoneHandle(
709 zone, lib.LookupClassAllowPrivate(Symbols::_Uint8ArrayView()));
714 auto vc42 =
H.flow_graph()->GetConstant(Integer::Handle(Integer::New(42)));
715 auto b1 =
H.flow_graph()->graph_entry()->normal_entry();
727 array = builder.AddDefinition(
729 new (zone)
Value(vc42), DeoptId::kNone));
732 view = builder.AddDefinition(
737 new (zone)
Value(array), Slot::PointerBase_data(),
743 Slot::PointerBase_data(),
new (zone)
Value(view),
new (zone)
Value(v1),
753 DominatorBasedCSE::Optimize(
H.flow_graph());
762 kMatchAndMoveFunctionEntry,
763 {kMatchAndMoveAllocateTypedData, &alloc_array},
764 {kMatchAndMoveAllocateObject, &alloc_view},
765 {kMatchAndMoveLoadField, &lf},
766 {kMatchAndMoveStoreField, &sf},
767 {kMatchDartReturn, &r},
769 EXPECT(array == alloc_array);
770 EXPECT(view == alloc_view);
781 const char* script_chars = R
"(
782 import 'dart:typed_data';
785 final Float64List data;
792 const Class& view_cls = Class::ZoneHandle(
793 lib.
LookupClass(String::Handle(Symbols::New(thread,
"View"))));
797 const Field& original_field = Field::Handle(
798 view_cls.
LookupField(String::Handle(Symbols::New(thread,
"data"))));
806 auto b1 =
H.flow_graph()->graph_entry()->normal_entry();
816 new Value(
H.IntConstant(1)), DeoptId::kNone));
818 const auto view = builder.AddDefinition(
824 &
H.flow_graph()->parsed_function()));
828 new Value(
H.DoubleConstant(1.0)), StoreBarrierType::kNoStoreBarrier,
830 Instance::ElementSizeFor(kTypedDataFloat64ArrayCid),
831 kTypedDataFloat64ArrayCid, AlignmentType::kAlignedAccess,
834 const auto array_alias = builder.AddDefinition(
new LoadFieldInstr(
835 new Value(view), Slot::Get(field, &
H.flow_graph()->parsed_function()),
839 new Value(array_alias),
new Value(
H.IntConstant(1)),
840 new Value(
H.DoubleConstant(2.0)), StoreBarrierType::kNoStoreBarrier,
842 Instance::ElementSizeFor(kTypedDataFloat32ArrayCid),
843 kTypedDataFloat32ArrayCid, AlignmentType::kAlignedAccess,
847 new Value(array),
new Value(
H.IntConstant(0)),
false,
848 Instance::ElementSizeFor(kTypedDataFloat64ArrayCid),
849 kTypedDataFloat64ArrayCid, AlignmentType::kAlignedAccess,
852 ret = builder.AddReturn(
new Value(
load));
855 DominatorBasedCSE::Optimize(
H.flow_graph());
1209 const char* kScript = R
"(
1210import 'dart:typed_data';
1213 final Float64List _v2storage;
1215 @pragma('vm:prefer-inline')
1216 Vector2.zero() : _v2storage = Float64List(2);
1218 @pragma('vm:prefer-inline')
1219 factory Vector2(double x, double y) => Vector2.zero()..setValues(x, y);
1221 @pragma('vm:prefer-inline')
1222 factory Vector2.copy(Vector2 other) => Vector2.zero()..setFrom(other);
1224 @pragma('vm:prefer-inline')
1225 Vector2 clone() => Vector2.copy(this);
1227 @pragma('vm:prefer-inline')
1228 void setValues(double x_, double y_) {
1233 @pragma('vm:prefer-inline')
1234 void setFrom(Vector2 other) {
1235 final otherStorage = other._v2storage;
1236 _v2storage[1] = otherStorage[1];
1237 _v2storage[0] = otherStorage[0];
1240 @pragma('vm:prefer-inline')
1241 Vector2 operator +(Vector2 other) => clone()..add(other);
1243 @pragma('vm:prefer-inline')
1244 void add(Vector2 arg) {
1245 final argStorage = arg._v2storage;
1246 _v2storage[0] = _v2storage[0] + argStorage[0];
1247 _v2storage[1] = _v2storage[1] + argStorage[1];
1250 @pragma('vm:prefer-inline')
1251 double get x => _v2storage[0];
1253 @pragma('vm:prefer-inline')
1254 double get y => _v2storage[1];
1257@pragma('vm:never-inline')
1258String foo(double x) {
1259 // All allocations in this function are eliminated by the compiler,
1260 // except array allocation for string interpolation at the end.
1261 List v1 = List.filled(2, null);
1264 Vector2 v2 = new Vector2(1.0, 2.0);
1265 Vector2 v3 = v2 + Vector2(x, x);
1266 double sum = v3.x + v3.y;
1267 return "v1: [${v1[0]},${v1[1]}], v2: [${v2.x},${v2.y}], v3: [${v3.x},${v3.y}], sum: $sum";
1275 const auto& root_library = Library::Handle(
LoadTestScript(kScript));
1276 Invoke(root_library,
"main");
1280 ASSERT(flow_graph !=
nullptr);
1283 EXPECT(entry !=
nullptr);
1334 ILMatcher cursor(flow_graph, entry,
true,
1335 ParallelMovesHandling::kSkip);
1337 kMatchAndMoveFunctionEntry,
1338 kMatchAndMoveCheckStackOverflow,
1342 kMatchAndMoveBinaryDoubleOp,
1343 kMatchAndMoveBinaryDoubleOp,
1346 kMatchAndMoveBinaryDoubleOp,
1347 {kMatchAndMoveCreateArray, &create_array},
1348 kMatchAndMoveStoreIndexed,
1349 kMatchAndMoveStoreIndexed,
1350 kMatchAndMoveStoreIndexed,
1351 kMatchAndMoveStoreIndexed,
1352 kMatchAndMoveStoreIndexed,
1353 kMatchAndMoveStoreIndexed,
1354 kMatchAndMoveStoreIndexed,
1355 kMatchAndMoveStoreIndexed,
1356 kMatchAndMoveStoreIndexed,
1357 kMatchAndMoveStoreIndexed,
1358 kMatchAndMoveStoreIndexed,
1359 kMatchAndMoveStoreIndexed,
1360 kMatchAndMoveStoreIndexed,
1362 kMatchAndMoveStoreIndexed,
1363 kMatchAndMoveMoveArgument,
1364 {kMatchAndMoveStaticCall, &string_interpolate},
1368 EXPECT(string_interpolate->ArgumentAt(0) == create_array);
1372 const char* kScript = R
"(
1374@pragma('vm:prefer-inline')
1375({int field1, String field2}) getRecord(int x, String y) =>
1376 (field1: x, field2: y);
1378@pragma('vm:never-inline')
1379String foo(int x, String y) {
1380 // All allocations in this function are eliminated by the compiler,
1381 // except array allocation for string interpolation at the end.
1382 (int, bool) r1 = (x, true);
1383 final r2 = getRecord(x, y);
1384 int sum = r1.$1 + r2.field1;
1385 return "r1: (${r1.$1}, ${r1.$2}), "
1386 "r2: (field1: ${r2.field1}, field2: ${r2.field2}), sum: $sum";
1391 // Deoptimize on the 2nd run.
1392 return foo(count++ == 0 ? 42 : 9223372036854775807, 'hey');
1396 const auto& root_library = Library::Handle(
LoadTestScript(kScript));
1397 const auto& result1 = Object::Handle(
Invoke(root_library,
"main"));
1398 EXPECT(result1.IsString());
1399 EXPECT_STREQ(result1.ToCString(),
1400 "r1: (42, true), r2: (field1: 42, field2: hey), sum: 84");
1404 ASSERT(flow_graph !=
nullptr);
1407 EXPECT(entry !=
nullptr);
1442 ILMatcher cursor(flow_graph, entry,
true,
1443 ParallelMovesHandling::kSkip);
1445 kMatchAndMoveFunctionEntry,
1446 kMatchAndMoveCheckStackOverflow,
1447 kMatchAndMoveCheckSmi,
1448 kMatchAndMoveBinarySmiOp,
1449 kMatchAndMoveCreateArray,
1450 kMatchAndMoveStoreIndexed,
1451 kMatchAndMoveStoreIndexed,
1452 kMatchAndMoveStoreIndexed,
1453 kMatchAndMoveStoreIndexed,
1454 kMatchAndMoveStoreIndexed,
1455 kMatchAndMoveStoreIndexed,
1456 kMatchAndMoveStoreIndexed,
1457 kMatchAndMoveStoreIndexed,
1458 kMatchAndMoveStoreIndexed,
1459 kMatchAndMoveStoreIndexed,
1460 kMatchAndMoveMoveArgument,
1461 kMatchAndMoveStaticCall,
1465 Compiler::CompileOptimizedFunction(thread,
function);
1466 const auto& result2 = Object::Handle(
Invoke(root_library,
"main"));
1467 EXPECT(result2.IsString());
1468 EXPECT_STREQ(result2.ToCString(),
1469 "r1: (9223372036854775807, true), r2: (field1: "
1470 "9223372036854775807, field2: hey), sum: -2");
1635 const char* script_chars = R
"(
1636 @pragma("vm:external-name", "BlackholeNative")
1637 external dynamic blackhole([a, b, c, d, e, f]);
1646 const Class& cls = Class::ZoneHandle(
1647 lib.
LookupClass(String::Handle(Symbols::New(thread,
"K"))));
1651 const Field& original_field = Field::Handle(
1652 cls.
LookupField(String::Handle(Symbols::New(thread,
"field"))));
1657 Function::ZoneHandle(
GetFunction(lib,
"blackhole"));
1662 H.AddVariable(
"v0", AbstractType::ZoneHandle(Type::DynamicType()));
1663 H.AddVariable(
"v1", AbstractType::ZoneHandle(Type::DynamicType()));
1665 auto b1 =
H.flow_graph()->graph_entry()->normal_entry();
1677 auto& slot = Slot::Get(field, &
H.flow_graph()->parsed_function());
1678 auto param0 = builder.AddParameter(0, kUnboxedDouble);
1679 auto param1 = builder.AddParameter(1, kTagged);
1684 box0 = builder.AddDefinition(
1685 BoxInstr::Create(kUnboxedDouble,
new Value(redef0)));
1686 box1 = builder.AddDefinition(
1687 BoxInstr::Create(kUnboxedDouble,
new Value(redef1)));
1693 load0 = builder.AddDefinition(
1695 load1 = builder.AddDefinition(
1697 load2 = builder.AddDefinition(
1706 std::move(
args), S.GetNextDeoptId(), 0, ICData::RebindRule::kStatic));
1708 ret = builder.AddReturn(
new Value(box1));
1714 DominatorBasedCSE::Optimize(
H.flow_graph(),
false);
1730 DominatorBasedCSE::Optimize(
H.flow_graph(),
true);
1738 it.ArgumentAt(1)->OriginalDefinition() == load0);
1740 it.ArgumentAt(2)->OriginalDefinition() == load0);
1744 auto*
const kFunctionName =
"unalignedUint16";
1745 auto*
const kInvokeNoDeoptName =
"no_deopt";
1746 auto*
const kInvokeDeoptName =
"deopt";
1748 OS::SCreate(
nullptr, R
"(
1749 import 'dart:_internal';
1750 import 'dart:typed_data';
1752 @pragma("vm:never-inline")
1753 void check(int x, int y) {
1755 throw "Doesn't match";
1759 @pragma("vm:never-inline")
1761 var bytes = new ByteData(64);
1763 for (var i = 2; i < 4; i++) {
1764 bytes.setUint16(i, x + 1, Endian.host);
1765 check(x + 1, bytes.getUint16(i, Endian.host));
1768 // Force a garbage collection after deoptimization. In DEBUG mode,
1769 // the scavenger tests that the view's data field was set correctly
1770 // during deoptimization before recomputing it.
1771 VMInternalsForTesting.collectAllGarbage();
1773 // Make sure the array is also used on the non-int path.
1774 check(0, bytes.getUint16(0, Endian.host));
1786 kFunctionName, kInvokeNoDeoptName, kFunctionName,
1787 kInvokeDeoptName, kFunctionName),
1793 if (lib.IsNull())
return;
1800 auto&
result = Object::Handle(
Invoke(lib, kInvokeNoDeoptName));
1805 CompilerPass::kComputeSSA,
1806 CompilerPass::kApplyICData,
1807 CompilerPass::kTryOptimizePatterns,
1808 CompilerPass::kSetOuterInliningId,
1809 CompilerPass::kTypePropagation,
1810 CompilerPass::kApplyClassIds,
1811 CompilerPass::kInlining,
1812 CompilerPass::kTypePropagation,
1813 CompilerPass::kApplyClassIds,
1814 CompilerPass::kTypePropagation,
1815 CompilerPass::kApplyICData,
1816 CompilerPass::kCanonicalize,
1817 CompilerPass::kBranchSimplify,
1818 CompilerPass::kIfConvert,
1819 CompilerPass::kCanonicalize,
1820 CompilerPass::kConstantPropagation,
1821 CompilerPass::kOptimisticallySpecializeSmiPhis,
1822 CompilerPass::kTypePropagation,
1823 CompilerPass::kWidenSmiToInt32,
1824 CompilerPass::kSelectRepresentations,
1826 CompilerPass::kCanonicalize,
1827 CompilerPass::kLICM,
1828 CompilerPass::kTryOptimizePatterns,
1829 CompilerPass::kSelectRepresentations,
1831 CompilerPass::kTypePropagation,
1832 CompilerPass::kSelectRepresentations,
1833 CompilerPass::kEliminateEnvironments,
1834 CompilerPass::kEliminateDeadPhis,
1836 CompilerPass::kCanonicalize,
1837 CompilerPass::kOptimizeBranches,
1843 EXPECT(entry !=
nullptr);
1853 ILMatcher cursor(flow_graph, entry,
true, ParallelMovesHandling::kSkip);
1856 {kMatchAndMoveAllocateTypedData, &alloc_typed_data},
1857 {kMatchAndMoveAllocateObject, &alloc_view},
1858 {kMatchAndMoveStoreField, &store_view_typed_data},
1859 {kMatchAndMoveStoreField, &store_view_offset_in_bytes},
1860 {kMatchAndMoveStoreField, &store_view_length},
1861 {kMatchAndMoveLoadField, &load_typed_data_payload},
1862 {kMatchAndMoveStoreField, &store_view_payload},
1864 if (store_view_payload ==
nullptr)
return;
1866 EXPECT_EQ(alloc_view, store_view_typed_data->instance()->definition());
1867 EXPECT(Slot::TypedDataView_typed_data().IsIdentical(
1868 store_view_typed_data->slot()));
1869 EXPECT_EQ(alloc_typed_data, store_view_typed_data->value()->definition());
1871 EXPECT_EQ(alloc_view, store_view_length->instance()->definition());
1872 EXPECT(Slot::TypedDataBase_length().IsIdentical(store_view_length->slot()));
1873 EXPECT_EQ(alloc_typed_data->num_elements()->definition(),
1874 store_view_length->value()->definition());
1876 EXPECT_EQ(alloc_view, store_view_offset_in_bytes->instance()->definition());
1877 EXPECT(Slot::TypedDataView_offset_in_bytes().IsIdentical(
1878 store_view_offset_in_bytes->slot()));
1879 EXPECT(store_view_offset_in_bytes->value()->BindsToSmiConstant());
1880 EXPECT_EQ(0, store_view_offset_in_bytes->value()->BoundSmiConstant());
1882 EXPECT_EQ(alloc_typed_data,
1883 load_typed_data_payload->instance()->definition());
1884 EXPECT(Slot::PointerBase_data().IsIdentical(load_typed_data_payload->slot()));
1886 EXPECT_EQ(alloc_view, store_view_payload->instance()->definition());
1887 EXPECT(Slot::PointerBase_data().IsIdentical(store_view_payload->slot()));
1888 EXPECT_EQ(load_typed_data_payload, store_view_payload->value()->definition());
1891 EXPECT(load_typed_data_payload->HasOnlyUse(store_view_payload->value()));
1893 pipeline.RunAdditionalPasses({
1894 CompilerPass::kAllocationSinking_Sink,
1898 EXPECT_EQ(
nullptr, alloc_view->previous());
1899 EXPECT_EQ(
nullptr, alloc_view->next());
1901 intptr_t mat_count = 0;
1902 for (
auto block_it = flow_graph->reverse_postorder_iterator();
1903 !block_it.Done(); block_it.Advance()) {
1904 for (ForwardInstructionIterator it(block_it.Current()); !it.Done();
1906 auto*
const mat = it.Current()->AsMaterializeObject();
1907 if (mat ==
nullptr)
continue;
1908 if (mat->allocation() == alloc_view) {
1910 for (intptr_t i = 0; i < mat->InputCount(); i++) {
1912 EXPECT(mat->FieldOffsetAt(i) !=
1913 Slot::PointerBase_data().offset_in_bytes());
1916 if (
auto*
const load = mat->InputAt(i)->definition()->AsLoadField()) {
1917 if (
load->instance()->definition() == alloc_typed_data) {
1918 EXPECT(!
load->slot().IsIdentical(Slot::PointerBase_data()));
1928 EXPECT(!load_typed_data_payload->HasUses());
1930 pipeline.RunAdditionalPasses({
1931 CompilerPass::kEliminateDeadPhis,
1933 CompilerPass::kCanonicalize,
1934 CompilerPass::kTypePropagation,
1935 CompilerPass::kSelectRepresentations_Final,
1936 CompilerPass::kUseTableDispatch,
1937 CompilerPass::kEliminateStackOverflowChecks,
1938 CompilerPass::kCanonicalize,
1939 CompilerPass::kAllocationSinking_DetachMaterializations,
1940 CompilerPass::kEliminateWriteBarriers,
1941 CompilerPass::kLoweringAfterCodeMotionDisabled,
1942 CompilerPass::kFinalizeGraph,
1943 CompilerPass::kCanonicalize,
1944 CompilerPass::kReorderBlocks,
1945 CompilerPass::kAllocateRegisters,
1946 CompilerPass::kTestILSerialization,
1950 pipeline.CompileGraphAndAttachFunction();