1 /* 2 * Copyright (c) 2015, 2017, 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 package org.graalvm.compiler.jtt.backend; 24 25 import static org.objectweb.asm.Opcodes.ACC_FINAL; 26 import static org.objectweb.asm.Opcodes.ACC_PUBLIC; 27 import static org.objectweb.asm.Opcodes.ACC_STATIC; 28 import static org.objectweb.asm.Opcodes.ACC_SUPER; 29 import static org.objectweb.asm.Opcodes.ILOAD; 30 import static org.objectweb.asm.Opcodes.LRETURN; 31 32 import java.lang.reflect.Method; 33 import java.util.ArrayList; 34 import java.util.Collection; 35 import java.util.List; 36 37 import org.graalvm.compiler.debug.GraalError; 38 import org.graalvm.compiler.jtt.JTTTest; 39 import org.graalvm.compiler.test.ExportingClassLoader; 40 import org.junit.Before; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 import org.junit.runners.Parameterized; 44 import org.junit.runners.Parameterized.Parameter; 45 import org.junit.runners.Parameterized.Parameters; 46 import org.objectweb.asm.ClassWriter; 47 import org.objectweb.asm.Label; 48 import org.objectweb.asm.MethodVisitor; 49 import org.objectweb.asm.Opcodes; 50 51 import jdk.vm.ci.meta.ResolvedJavaMethod; 52 import junit.framework.AssertionFailedError; 53 54 /** 55 * This test let the compiler deal with a large amount of constant data in a method. This data is 56 * stored typically in the constant section of the native method. Especially on the SPARC platform 57 * the backend can address only 8k of memory with an immediate offset. Beyond this barrier, a 58 * different addressing mode must be used. 59 * 60 * In order to do this this test generates a large method containing a large switch statement in 61 * form of 62 * 63 * <code> 64 * static long run(long a) { 65 * switch(a) { 66 * case 1: 67 * return 0xF0F0F0F0F0L + 1; 68 * case 2: 69 * return 0xF0F0F0F0F0L + 2; 70 * .... 71 * default: 72 * return 0; 73 * } 74 * 75 * } 76 * </code> 77 * 78 */ 79 @RunWith(Parameterized.class) 80 public class LargeConstantSectionTest extends JTTTest { 81 private static final String NAME = "LargeConstantSection"; 82 private static final long LARGE_CONSTANT = 0xF0F0F0F0F0L; 83 private static LargeConstantClassLoader LOADER; 84 @Parameter(value = 0) public int numberBlocks; 85 86 @Parameters(name = "{0}") 87 public static Collection<Object[]> data() { 88 List<Object[]> parameters = new ArrayList<>(); 89 for (int i = 4; i < 13; i += 2) { 90 parameters.add(new Object[]{1 << i}); 91 } 92 return parameters; 93 } 94 95 @Before 96 public void before() { 97 LOADER = new LargeConstantClassLoader(LargeConstantSectionTest.class.getClassLoader()); 98 } 99 100 public class LargeConstantClassLoader extends ExportingClassLoader { 101 public LargeConstantClassLoader(ClassLoader parent) { 102 super(parent); 103 } 104 105 @Override 106 protected Class<?> findClass(String name) throws ClassNotFoundException { 107 if (name.equals(NAME)) { 108 ClassWriter cw = new ClassWriter(0); 109 MethodVisitor mv; 110 cw.visit(52, ACC_PUBLIC + ACC_SUPER, NAME, null, "java/lang/Object", null); 111 112 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "run", "(I)J", null, null); 113 mv.visitCode(); 114 Label begin = new Label(); 115 mv.visitLabel(begin); 116 mv.visitVarInsn(ILOAD, 0); 117 Label[] labels = new Label[numberBlocks]; 118 int[] keys = new int[numberBlocks]; 119 for (int i = 0; i < labels.length; i++) { 120 labels[i] = new Label(); 121 keys[i] = i; 122 } 123 Label defaultLabel = new Label(); 124 mv.visitLookupSwitchInsn(defaultLabel, keys, labels); 125 for (int i = 0; i < labels.length; i++) { 126 mv.visitLabel(labels[i]); 127 mv.visitFrame(Opcodes.F_NEW, 1, new Object[]{Opcodes.INTEGER}, 0, new Object[]{}); 128 mv.visitLdcInsn(new Long(LARGE_CONSTANT + i)); 129 mv.visitInsn(LRETURN); 130 } 131 mv.visitLabel(defaultLabel); 132 mv.visitFrame(Opcodes.F_NEW, 1, new Object[]{Opcodes.INTEGER}, 0, new Object[]{}); 133 mv.visitLdcInsn(new Long(3L)); 134 mv.visitInsn(LRETURN); 135 Label end = new Label(); 136 mv.visitLabel(end); 137 mv.visitLocalVariable("a", "I", null, begin, end, 0); 138 mv.visitMaxs(2, 1); 139 mv.visitEnd(); 140 byte[] bytes = cw.toByteArray(); 141 return defineClass(name, bytes, 0, bytes.length); 142 } else { 143 return super.findClass(name); 144 } 145 } 146 } 147 148 @Test 149 @SuppressWarnings("try") 150 public void run0() throws Exception { 151 test("run", numberBlocks - 3); 152 } 153 154 @Override 155 protected ResolvedJavaMethod getResolvedJavaMethod(String methodName) { 156 try { 157 for (Method method : LOADER.findClass(NAME).getDeclaredMethods()) { 158 if (method.getName().equals(methodName)) { 159 return asResolvedJavaMethod(method); 160 } 161 } 162 } catch (ClassNotFoundException e) { 163 throw new AssertionFailedError("Cannot find class " + NAME); 164 } 165 throw GraalError.shouldNotReachHere(); 166 } 167 }