/* * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package org.graalvm.compiler.jtt.backend; import static org.objectweb.asm.Opcodes.ACC_FINAL; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ACC_SUPER; import static org.objectweb.asm.Opcodes.ILOAD; import static org.objectweb.asm.Opcodes.LRETURN; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.jtt.JTTTest; import org.graalvm.compiler.test.ExportingClassLoader; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import jdk.vm.ci.meta.ResolvedJavaMethod; import junit.framework.AssertionFailedError; /** * This test let the compiler deal with a large amount of constant data in a method. This data is * stored typically in the constant section of the native method. Especially on the SPARC platform * the backend can address only 8k of memory with an immediate offset. Beyond this barrier, a * different addressing mode must be used. * * In order to do this this test generates a large method containing a large switch statement in * form of * * <code> * static long run(long a) { * switch(a) { * case 1: * return 0xF0F0F0F0F0L + 1; * case 2: * return 0xF0F0F0F0F0L + 2; * .... * default: * return 0; * } * * } * </code> * */ @RunWith(Parameterized.class) public class LargeConstantSectionTest extends JTTTest { private static final String NAME = "LargeConstantSection"; private static final long LARGE_CONSTANT = 0xF0F0F0F0F0L; private static LargeConstantClassLoader LOADER; @Parameter(value = 0) public int numberBlocks; @Parameters(name = "{0}") public static Collection<Object[]> data() { List<Object[]> parameters = new ArrayList<>(); for (int i = 4; i < 13; i += 2) { parameters.add(new Object[]{1 << i}); } return parameters; } @Before public void before() { LOADER = new LargeConstantClassLoader(LargeConstantSectionTest.class.getClassLoader()); } public class LargeConstantClassLoader extends ExportingClassLoader { public LargeConstantClassLoader(ClassLoader parent) { super(parent); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { if (name.equals(NAME)) { ClassWriter cw = new ClassWriter(0); MethodVisitor mv; cw.visit(52, ACC_PUBLIC + ACC_SUPER, NAME, null, "java/lang/Object", null); mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "run", "(I)J", null, null); mv.visitCode(); Label begin = new Label(); mv.visitLabel(begin); mv.visitVarInsn(ILOAD, 0); Label[] labels = new Label[numberBlocks]; int[] keys = new int[numberBlocks]; for (int i = 0; i < labels.length; i++) { labels[i] = new Label(); keys[i] = i; } Label defaultLabel = new Label(); mv.visitLookupSwitchInsn(defaultLabel, keys, labels); for (int i = 0; i < labels.length; i++) { mv.visitLabel(labels[i]); mv.visitFrame(Opcodes.F_NEW, 1, new Object[]{Opcodes.INTEGER}, 0, new Object[]{}); mv.visitLdcInsn(new Long(LARGE_CONSTANT + i)); mv.visitInsn(LRETURN); } mv.visitLabel(defaultLabel); mv.visitFrame(Opcodes.F_NEW, 1, new Object[]{Opcodes.INTEGER}, 0, new Object[]{}); mv.visitLdcInsn(new Long(3L)); mv.visitInsn(LRETURN); Label end = new Label(); mv.visitLabel(end); mv.visitLocalVariable("a", "I", null, begin, end, 0); mv.visitMaxs(2, 1); mv.visitEnd(); byte[] bytes = cw.toByteArray(); return defineClass(name, bytes, 0, bytes.length); } else { return super.findClass(name); } } } @Test @SuppressWarnings("try") public void run0() throws Exception { test("run", numberBlocks - 3); } @Override protected ResolvedJavaMethod getResolvedJavaMethod(String methodName) { try { for (Method method : LOADER.findClass(NAME).getDeclaredMethods()) { if (method.getName().equals(methodName)) { return asResolvedJavaMethod(method); } } } catch (ClassNotFoundException e) { throw new AssertionFailedError("Cannot find class " + NAME); } throw GraalError.shouldNotReachHere(); } }