1/*
2 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package org.graalvm.compiler.replacements.test;
24
25import java.util.HashMap;
26
27import org.junit.Assert;
28import org.junit.Test;
29
30import org.graalvm.compiler.core.test.GraalCompilerTest;
31
32/**
33 * Tests the implementation of {@code NEW}.
34 */
35public class NewInstanceTest extends GraalCompilerTest {
36
37    @Override
38    protected void assertDeepEquals(Object expected, Object actual) {
39        Assert.assertTrue(expected != null);
40        Assert.assertTrue(actual != null);
41        super.assertDeepEquals(expected.getClass(), actual.getClass());
42
43        if (expected instanceof Object[]) {
44            Assert.assertTrue(actual instanceof Object[]);
45            Object[] eArr = (Object[]) expected;
46            Object[] aArr = (Object[]) actual;
47            Assert.assertTrue(eArr.length == aArr.length);
48            for (int i = 0; i < eArr.length; i++) {
49                assertDeepEquals(eArr[i], aArr[i]);
50            }
51        } else if (expected.getClass() != Object.class) {
52            try {
53                expected.getClass().getDeclaredMethod("equals", Object.class);
54                super.assertDeepEquals(expected, actual);
55            } catch (Exception e) {
56            }
57        }
58    }
59
60    @Test
61    public void test1() {
62        test("newObject");
63    }
64
65    @Test
66    public void test2() {
67        test("newObjectTwice");
68    }
69
70    public static Object newObject() {
71        return new Object();
72    }
73
74    @Test
75    public void test3() {
76        test("newObjectLoop", 100);
77    }
78
79    @Test
80    public void test4() {
81        test("newBigObject");
82    }
83
84    @Test
85    public void test5() {
86        test("newSomeObject");
87    }
88
89    @Test
90    public void test6() {
91        test("newEmptyString");
92    }
93
94    @Test
95    public void test7() {
96        test("newString", "value");
97    }
98
99    @Test
100    public void test8() {
101        test("newHashMap", 31);
102    }
103
104    @Test
105    public void test9() {
106        test("newRegression", true);
107    }
108
109    public static Object[] newObjectTwice() {
110        Object[] res = {new Object(), new Object()};
111        return res;
112    }
113
114    public static Object[] newObjectLoop(int n) {
115        Object[] res = new Object[n];
116        for (int i = 0; i < n; i++) {
117            res[i] = new Object();
118        }
119        return res;
120    }
121
122    public static BigObject newBigObject() {
123        return new BigObject();
124    }
125
126    public static SomeObject newSomeObject() {
127        return new SomeObject();
128    }
129
130    public static String newEmptyString() {
131        return new String();
132    }
133
134    public static String newString(String value) {
135        return new String(value);
136    }
137
138    public static HashMap<?, ?> newHashMap(int initialCapacity) {
139        return new HashMap<>(initialCapacity);
140    }
141
142    static class SomeObject {
143
144        String name = "o1";
145        HashMap<String, Object> map = new HashMap<>();
146
147        SomeObject() {
148            map.put(name, this.getClass());
149        }
150
151        @Override
152        public boolean equals(Object obj) {
153            if (obj instanceof SomeObject) {
154                SomeObject so = (SomeObject) obj;
155                return so.name.equals(name) && so.map.equals(map);
156            }
157            return false;
158        }
159
160        @Override
161        public int hashCode() {
162            return name.hashCode();
163        }
164    }
165
166    static class BigObject {
167
168        Object f01;
169        Object f02;
170        Object f03;
171        Object f04;
172        Object f05;
173        Object f06;
174        Object f07;
175        Object f08;
176        Object f09;
177        Object f10;
178        Object f12;
179        Object f13;
180        Object f14;
181        Object f15;
182        Object f16;
183        Object f17;
184        Object f18;
185        Object f19;
186        Object f20;
187        Object f21;
188        Object f22;
189        Object f23;
190        Object f24;
191        Object f25;
192        Object f26;
193        Object f27;
194        Object f28;
195        Object f29;
196        Object f30;
197        Object f31;
198        Object f32;
199        Object f33;
200        Object f34;
201        Object f35;
202        Object f36;
203        Object f37;
204        Object f38;
205        Object f39;
206        Object f40;
207        Object f41;
208        Object f42;
209        Object f43;
210        Object f44;
211        Object f45;
212    }
213
214    /**
215     * Tests that an earlier bug does not occur. The issue was that the loading of the TLAB 'top'
216     * and 'end' values was being GVN'ed from each branch of the 'if' statement. This meant that the
217     * allocated B object in the true branch overwrote the allocated array. The cause is that
218     * RegisterNode was a floating node and the reads from it were UnsafeLoads which are also
219     * floating. The fix was to make RegisterNode a fixed node (which it should have been in the
220     * first place).
221     */
222    public static Object newRegression(boolean condition) {
223        Object result;
224        if (condition) {
225            Object[] arr = {0, 1, 2, 3, 4, 5};
226            result = new B();
227            for (int i = 0; i < arr.length; ++i) {
228                // If the bug exists, the values of arr will now be deadbeef values
229                // and the virtual dispatch will cause a segfault. This can result in
230                // either a VM crash or a spurious NullPointerException.
231                if (arr[i].equals(Integer.valueOf(i))) {
232                    return false;
233                }
234            }
235        } else {
236            result = new B();
237        }
238        return result;
239    }
240
241    static class B {
242
243        long f1 = 0xdeadbeefdeadbe01L;
244        long f2 = 0xdeadbeefdeadbe02L;
245        long f3 = 0xdeadbeefdeadbe03L;
246        long f4 = 0xdeadbeefdeadbe04L;
247        long f5 = 0xdeadbeefdeadbe05L;
248    }
249}
250