001/* 002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.compiler.test; 024 025import java.io.*; 026import java.lang.reflect.*; 027import java.util.*; 028 029import com.oracle.graal.debug.*; 030import jdk.internal.jvmci.meta.*; 031import jdk.internal.jvmci.meta.Assumptions.*; 032 033import org.junit.*; 034 035import com.oracle.graal.graphbuilderconf.*; 036import com.oracle.graal.java.*; 037import com.oracle.graal.nodes.*; 038import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; 039import com.oracle.graal.nodes.java.*; 040import com.oracle.graal.phases.*; 041import com.oracle.graal.phases.common.*; 042import com.oracle.graal.phases.common.inlining.*; 043import com.oracle.graal.phases.tiers.*; 044 045public class FinalizableSubclassTest extends GraalCompilerTest { 046 047 /** 048 * used as template to generate class files at runtime. 049 */ 050 public static class NoFinalizerEverAAAA { 051 } 052 053 public static class NoFinalizerYetAAAA { 054 } 055 056 public static class WithFinalizerAAAA extends NoFinalizerYetAAAA { 057 058 @Override 059 protected void finalize() throws Throwable { 060 super.finalize(); 061 } 062 } 063 064 private StructuredGraph parseAndProcess(Class<?> cl, AllowAssumptions allowAssumptions) { 065 Constructor<?>[] constructors = cl.getConstructors(); 066 Assert.assertTrue(constructors.length == 1); 067 final ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(constructors[0]); 068 StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions); 069 070 GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins()); 071 new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL, null).apply(graph); 072 HighTierContext context = new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); 073 new InliningPhase(new CanonicalizerPhase()).apply(graph, context); 074 new CanonicalizerPhase().apply(graph, context); 075 return graph; 076 } 077 078 private void checkForRegisterFinalizeNode(Class<?> cl, boolean shouldContainFinalizer, AllowAssumptions allowAssumptions) { 079 StructuredGraph graph = parseAndProcess(cl, allowAssumptions); 080 Assert.assertTrue(graph.getNodes().filter(RegisterFinalizerNode.class).count() == (shouldContainFinalizer ? 1 : 0)); 081 int noFinalizerAssumption = 0; 082 Assumptions assumptions = graph.getAssumptions(); 083 if (assumptions != null) { 084 for (Assumption a : assumptions) { 085 if (a instanceof NoFinalizableSubclass) { 086 noFinalizerAssumption++; 087 } 088 } 089 } 090 Assert.assertTrue(noFinalizerAssumption == (shouldContainFinalizer ? 0 : 1)); 091 } 092 093 /** 094 * Use a custom class loader to generate classes, to make sure the given classes are loaded in 095 * correct order. 096 */ 097 @Test 098 public void test1() throws ClassNotFoundException { 099 for (int i = 0; i < 2; i++) { 100 ClassTemplateLoader loader = new ClassTemplateLoader(); 101 checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), true, AllowAssumptions.NO); 102 checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), false, AllowAssumptions.YES); 103 104 checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), false, AllowAssumptions.YES); 105 106 checkForRegisterFinalizeNode(loader.findClass("WithFinalizerAAAA"), true, AllowAssumptions.YES); 107 checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), true, AllowAssumptions.YES); 108 } 109 } 110 111 private static class ClassTemplateLoader extends ClassLoader { 112 113 private static int loaderInstance = 0; 114 115 private final String replaceTo; 116 private HashMap<String, Class<?>> cache = new HashMap<>(); 117 118 public ClassTemplateLoader() { 119 loaderInstance++; 120 replaceTo = String.format("%04d", loaderInstance); 121 } 122 123 @Override 124 protected Class<?> findClass(final String name) throws ClassNotFoundException { 125 String nameReplaced = name.replaceAll("AAAA", replaceTo); 126 if (cache.containsKey(nameReplaced)) { 127 return cache.get(nameReplaced); 128 } 129 130 // copy classfile to byte array 131 byte[] classData = null; 132 try { 133 InputStream is = FinalizableSubclassTest.class.getResourceAsStream("FinalizableSubclassTest$" + name + ".class"); 134 assert is != null; 135 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 136 137 byte[] buf = new byte[1024]; 138 int size; 139 while ((size = is.read(buf, 0, buf.length)) != -1) { 140 baos.write(buf, 0, size); 141 } 142 baos.flush(); 143 classData = baos.toByteArray(); 144 } catch (IOException e) { 145 Assert.fail("can't access class: " + name); 146 } 147 dumpStringsInByteArray(classData); 148 149 // replace all occurrences of "AAAA" in classfile 150 int index = -1; 151 while ((index = indexOfAAAA(classData, index + 1)) != -1) { 152 replaceAAAA(classData, index, replaceTo); 153 } 154 dumpStringsInByteArray(classData); 155 156 Class<?> c = defineClass(null, classData, 0, classData.length); 157 cache.put(nameReplaced, c); 158 return c; 159 } 160 161 private static int indexOfAAAA(byte[] b, int index) { 162 for (int i = index; i < b.length; i++) { 163 boolean match = true; 164 for (int j = i; j < i + 4; j++) { 165 if (b[j] != (byte) 'A') { 166 match = false; 167 break; 168 } 169 } 170 if (match) { 171 return i; 172 } 173 } 174 return -1; 175 } 176 177 private static void replaceAAAA(byte[] b, int index, String replacer) { 178 assert replacer.length() == 4; 179 for (int i = index; i < index + 4; i++) { 180 b[i] = (byte) replacer.charAt(i - index); 181 } 182 } 183 184 private static void dumpStringsInByteArray(byte[] b) { 185 boolean wasChar = true; 186 StringBuilder sb = new StringBuilder(); 187 for (Byte x : b) { 188 // check for [a-zA-Z0-9] 189 if ((x >= 0x41 && x <= 0x7a) || (x >= 0x30 && x <= 0x39)) { 190 if (!wasChar) { 191 Debug.log(sb + ""); 192 sb.setLength(0); 193 } 194 sb.append(String.format("%c", x)); 195 wasChar = true; 196 } else { 197 wasChar = false; 198 } 199 } 200 Debug.log(sb + ""); 201 } 202 } 203}