1 /* 2 * Copyright (c) 2018, 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 */ 23 24 25 package org.graalvm.compiler.core.test; 26 27 import java.io.ByteArrayOutputStream; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.lang.reflect.Constructor; 31 32 import org.graalvm.compiler.java.GraphBuilderPhase; 33 import org.graalvm.compiler.nodes.DeoptimizeNode; 34 import org.graalvm.compiler.nodes.StructuredGraph; 35 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; 36 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; 37 import org.graalvm.compiler.nodes.java.NewInstanceNode; 38 import org.graalvm.compiler.options.OptionValues; 39 import org.graalvm.compiler.phases.OptimisticOptimizations; 40 import org.junit.Assert; 41 import org.junit.Test; 42 43 import jdk.vm.ci.meta.ResolvedJavaMethod; 44 45 public class NewInstanceTest extends GraalCompilerTest { 46 public static class Template { 47 public Object o = new CCCC(); 48 } 49 50 /** 51 * 1. Concrete class, should produce normal {@link NewInstanceNode} 52 */ 53 public static class CCCC { 54 55 } 56 57 /** 58 * 2. The test will replace references to {@link CCCC} in the {@link Template} to {@link AAAA} 59 */ 60 public abstract static class AAAA { 61 62 } 63 64 /** 65 * 3. The test will replace references to {@link CCCC} in the {@link Template} to {@link IIII} 66 */ 67 public interface IIII { 68 69 } 70 71 private StructuredGraph parseAndProcess(Class<?> cl) { 72 Constructor<?>[] constructors = cl.getConstructors(); 73 Assert.assertTrue(constructors.length == 1); 74 final ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(constructors[0]); 75 OptionValues options = getInitialOptions(); 76 StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options, null, javaMethod), AllowAssumptions.YES).method(javaMethod).build(); 77 78 GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins()).withUnresolvedIsError(false); 79 new GraphBuilderPhase.Instance(getProviders(), conf, OptimisticOptimizations.ALL, null).apply(graph); 80 return graph; 81 } 82 83 private void checkGraph(Class<?> cl, int newInstanceNodeCount, int deoptimizeNodeCount) { 84 StructuredGraph graph = parseAndProcess(cl); 85 Assert.assertEquals(newInstanceNodeCount, graph.getNodes().filter(NewInstanceNode.class).count()); 86 Assert.assertEquals(deoptimizeNodeCount, graph.getNodes().filter(DeoptimizeNode.class).count()); 87 } 88 89 /** 90 * Use a custom class loader to generate classes, substitute class names at the allocation site. 91 */ 92 @Test 93 public void test1() throws ClassNotFoundException { 94 checkGraph(Template.class, 1, 0); 95 ClassTemplateLoader loader1 = new ClassTemplateLoader("CCCC", "AAAA"); 96 checkGraph(loader1.findClass("Template"), 0, 1); 97 ClassTemplateLoader loader2 = new ClassTemplateLoader("CCCC", "IIII"); 98 checkGraph(loader2.findClass("Template"), 0, 1); 99 } 100 101 private static class ClassTemplateLoader extends ClassLoader { 102 private final String find; 103 private final String replace; 104 105 ClassTemplateLoader(String find, String replace) { 106 assert find.length() == replace.length(); 107 this.find = find; 108 this.replace = replace; 109 } 110 111 @Override 112 protected Class<?> findClass(final String name) throws ClassNotFoundException { 113 // copy classfile to byte array 114 byte[] classData = null; 115 try { 116 InputStream is = NewInstanceTest.class.getResourceAsStream("NewInstanceTest$" + name + ".class"); 117 assert is != null; 118 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 119 120 byte[] buf = new byte[1024]; 121 int size; 122 while ((size = is.read(buf, 0, buf.length)) != -1) { 123 baos.write(buf, 0, size); 124 } 125 baos.flush(); 126 classData = baos.toByteArray(); 127 } catch (IOException e) { 128 Assert.fail("can't access class: " + name); 129 } 130 131 // replace all occurrences of the template in classfile 132 int index = -1; 133 while ((index = indexOfTemplate(classData, index + 1, find)) != -1) { 134 replaceTemplate(classData, index, replace); 135 } 136 137 Class<?> c = defineClass(null, classData, 0, classData.length); 138 return c; 139 } 140 141 private static int indexOfTemplate(byte[] b, int index, String find) { 142 for (int i = index; i < b.length; i++) { 143 boolean match = true; 144 for (int j = i; j < i + find.length(); j++) { 145 if (b[j] != (byte) find.charAt(j - i)) { 146 match = false; 147 break; 148 } 149 } 150 if (match) { 151 return i; 152 } 153 } 154 return -1; 155 } 156 157 private static void replaceTemplate(byte[] b, int index, String replace) { 158 for (int i = index; i < index + replace.length(); i++) { 159 b[i] = (byte) replace.charAt(i - index); 160 } 161 } 162 } 163 }