// 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 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 { var x, y; PointP(this.x, this.y); operator *(other) { return x * other.x + y * other.y; } } foo2() => new PointP(1, 3) * new PointP(5, 6); class A { var x, y; } foo3(x) { // Test materialization of type arguments. var a = new A(); a.x = x; a.y = x; if (x is int) return a.x + a.y; Expect.isFalse(a is A); Expect.isTrue(a is A); 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(); }