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 }