| // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| // Test allocation sinking optimization. |
| // VMOptions=--optimization-counter-threshold=10 --no-use-osr --no-background-compilation |
| |
| // @dart = 2.9 |
| |
| import 'dart:typed_data'; |
| import 'package:expect/expect.dart'; |
| |
| class Point { |
| var x, y; |
| |
| Point(this.x, this.y); |
| |
| operator *(other) { |
| return x * other.x + y * other.y; |
| } |
| } |
| |
| class C { |
| var p; |
| C(this.p); |
| } |
| |
| class Pointx4 { |
| var x, y; |
| |
| Pointx4(this.x, this.y); |
| |
| operator *(other) { |
| return x * other.x + y * other.y; |
| } |
| } |
| |
| class Cx4 { |
| var p; |
| Cx4(this.p); |
| } |
| |
| class D { |
| var p; |
| D(this.p); |
| } |
| |
| // Class that is used to capture materialized Point object with * operator. |
| class F { |
| var p; |
| var val; |
| |
| F(this.p); |
| |
| operator *(other) { |
| Expect.isTrue(other is Point); |
| Expect.equals(42.0, other.x); |
| Expect.equals(0.5, other.y); |
| |
| if (val == null) { |
| val = other; |
| } else { |
| Expect.isTrue(identical(val, other)); |
| } |
| |
| return this.p * other; |
| } |
| } |
| |
| test1(c, x, y) { |
| var a = new Point(x - 0.5, y + 0.5); |
| var b = new Point(x + 0.5, y + 0.8); |
| var d = new Point(c.p * a, c.p * b); |
| return d * d; |
| } |
| |
| test1x4(c, x, y, z, w) { |
| var a = new Pointx4(x - z, y + w); |
| var b = new Pointx4(x + w, y + z); |
| var d = new Pointx4(c.p * a, c.p * b); |
| return d * d; |
| } |
| |
| effects() { |
| // This function should not be inlinable. |
| try {} catch (e) {} |
| } |
| |
| testForwardingThroughEffects(c, x, y) { |
| var a = new Point(x - 0.5, y + 0.5); |
| var b = new Point(x - 0.5, y - 0.8); |
| var d = new Point(c.p * a, c.p * b); |
| // Effects can't affect neither a, b, nor d because they do not escape. |
| effects(); |
| effects(); |
| return ((a == null) ? 0.0 : 0.1) + (d * d); |
| } |
| |
| testIdentity(x) { |
| var y = new Point(42.0, 0.5); |
| var z = y; |
| return x * y + x * z; |
| } |
| |
| class PointP<T> { |
| var x, y; |
| |
| PointP(this.x, this.y); |
| |
| operator *(other) { |
| return x * other.x + y * other.y; |
| } |
| } |
| |
| foo2() => new PointP<int>(1, 3) * new PointP<num>(5, 6); |
| |
| class A<T> { |
| var x, y; |
| } |
| |
| foo3(x) { |
| // Test materialization of type arguments. |
| var a = new A<int>(); |
| a.x = x; |
| a.y = x; |
| if (x is int) return a.x + a.y; |
| Expect.isFalse(a is A<double>); |
| Expect.isTrue(a is A<int>); |
| Expect.isTrue(a is A); |
| return a.x - a.y; |
| } |
| |
| class WithFinal { |
| final _x; |
| WithFinal(this._x); |
| } |
| |
| testInitialValueForFinalField(x) { |
| new WithFinal(x); |
| } |
| |
| testFinalField() { |
| for (var i = 0; i < 100; i++) { |
| testInitialValueForFinalField(1); |
| } |
| } |
| |
| class V { |
| var x = 0; |
| } |
| |
| test_vm_field() { |
| var obj; |
| inner() => obj.x = 42; |
| var a = new V(); |
| obj = a; |
| var t1 = a.x; |
| var t2 = inner(); |
| return a.x + t1 + t2; |
| } |
| |
| testVMField() { |
| Expect.equals(84, test_vm_field()); |
| for (var i = 0; i < 100; i++) test_vm_field(); |
| Expect.equals(84, test_vm_field()); |
| } |
| |
| class CompoundA { |
| var b; |
| CompoundA(this.b); |
| } |
| |
| class CompoundB { |
| var c; |
| CompoundB(this.c); |
| } |
| |
| class CompoundC { |
| var d; |
| var root; |
| CompoundC(this.d); |
| } |
| |
| class NoopSink { |
| const NoopSink(); |
| call(val) {} |
| } |
| |
| testCompound1() { |
| f(d, [sink = const NoopSink()]) { |
| var c = new CompoundC(d); |
| var a = new CompoundA(new CompoundB(c)); |
| sink(a); |
| return c.d; |
| } |
| |
| Expect.equals(0.1, f(0.1)); |
| for (var i = 0; i < 100; i++) f(0.1); |
| Expect.equals(0.1, f(0.1)); |
| Expect.equals( |
| 0.1, |
| f(0.1, (val) { |
| Expect.isTrue(val is CompoundA); |
| Expect.isTrue(val.b is CompoundB); |
| Expect.isTrue(val.b.c is CompoundC); |
| Expect.isNull(val.b.c.root); |
| Expect.equals(0.1, val.b.c.d); |
| })); |
| } |
| |
| testCompound2() { |
| f(d, [sink = const NoopSink()]) { |
| var c = new CompoundC(d); |
| var a = new CompoundA(new CompoundB(c)); |
| c.root = a; |
| sink(a); |
| return c.d; |
| } |
| |
| Expect.equals(0.1, f(0.1)); |
| for (var i = 0; i < 100; i++) f(0.1); |
| Expect.equals(0.1, f(0.1)); |
| Expect.equals( |
| 0.1, |
| f(0.1, (val) { |
| Expect.isTrue(val is CompoundA); |
| Expect.isTrue(val.b is CompoundB); |
| Expect.isTrue(val.b.c is CompoundC); |
| Expect.equals(val, val.b.c.root); |
| Expect.equals(0.1, val.b.c.d); |
| })); |
| } |
| |
| testCompound3() { |
| f(d, [sink = const NoopSink()]) { |
| var c = new CompoundC(d); |
| c.root = c; |
| sink(c); |
| return c.d; |
| } |
| |
| Expect.equals(0.1, f(0.1)); |
| for (var i = 0; i < 100; i++) f(0.1); |
| Expect.equals(0.1, f(0.1)); |
| Expect.equals( |
| 0.1, |
| f(0.1, (val) { |
| Expect.isTrue(val is CompoundC); |
| Expect.equals(val, val.root); |
| Expect.equals(0.1, val.d); |
| })); |
| } |
| |
| testCompound4() { |
| f(d, [sink = const NoopSink()]) { |
| var c = new CompoundC(d); |
| c.root = c; |
| for (var i = 0; i < 10; i++) { |
| c.d += 1.0; |
| } |
| sink(c); |
| return c.d - 1.0 * 10; |
| } |
| |
| Expect.equals(1.0, f(1.0)); |
| for (var i = 0; i < 100; i++) f(1.0); |
| Expect.equals(1.0, f(1.0)); |
| Expect.equals( |
| 1.0, |
| f(1.0, (val) { |
| Expect.isTrue(val is CompoundC); |
| Expect.equals(val, val.root); |
| Expect.equals(11.0, val.d); |
| })); |
| } |
| |
| main() { |
| var c = new C(new Point(0.1, 0.2)); |
| |
| // Compute initial values. |
| final x0 = test1(c, 11.11, 22.22); |
| var fc = new Cx4(new Pointx4( |
| new Float32x4(1.0, 1.0, 1.0, 1.0), new Float32x4(1.0, 1.0, 1.0, 1.0))); |
| final fx0 = test1x4( |
| fc, |
| new Float32x4(1.0, 1.0, 1.0, 1.0), |
| new Float32x4(1.0, 1.0, 1.0, 1.0), |
| new Float32x4(1.0, 1.0, 1.0, 1.0), |
| new Float32x4(1.0, 1.0, 1.0, 1.0)); |
| final y0 = testForwardingThroughEffects(c, 11.11, 22.22); |
| final z0 = testIdentity(c.p); |
| |
| // Force optimization. |
| for (var i = 0; i < 100; i++) { |
| test1(c, i.toDouble(), i.toDouble()); |
| test1x4( |
| fc, |
| new Float32x4(1.0, 1.0, 1.0, 1.0), |
| new Float32x4(1.0, 1.0, 1.0, 1.0), |
| new Float32x4(1.0, 1.0, 1.0, 1.0), |
| new Float32x4(1.0, 1.0, 1.0, 1.0)); |
| testForwardingThroughEffects(c, i.toDouble(), i.toDouble()); |
| testIdentity(c.p); |
| foo2(); |
| Expect.equals(10, foo3(5)); |
| } |
| Expect.equals(0.0, foo3(0.5)); |
| |
| // Test returned value after optimization. |
| final x1 = test1(c, 11.11, 22.22); |
| final y1 = testForwardingThroughEffects(c, 11.11, 22.22); |
| |
| // Test returned value after deopt. |
| final x2 = test1(new D(c.p), 11.11, 22.22); |
| final y2 = testForwardingThroughEffects(new D(c.p), 11.11, 22.22); |
| |
| Expect.equals(6465, (x0 * 100).floor()); |
| Expect.equals(6465, (x1 * 100).floor()); |
| Expect.equals(6465, (x2 * 100).floor()); |
| Expect.equals(x0, x1); |
| Expect.equals(x0, x2); |
| |
| Expect.equals(6008, (y0 * 100).floor()); |
| Expect.equals(6008, (y1 * 100).floor()); |
| Expect.equals(6008, (y2 * 100).floor()); |
| Expect.equals(y0, y1); |
| Expect.equals(y0, y2); |
| |
| // Test that identity of materialized objects is preserved correctly and |
| // no copies are materialized. |
| final z1 = testIdentity(c.p); |
| final z2 = testIdentity(new F(c.p)); |
| Expect.equals(z0, z1); |
| Expect.equals(z0, z2); |
| |
| testFinalField(); |
| testVMField(); |
| testCompound1(); |
| testCompound2(); |
| testCompound3(); |
| testCompound4(); |
| } |