/*
 * 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 static long run(long a) { switch(a) { case 1: return 0xF0F0F0F0F0L + 1; case 2: return 0xF0F0F0F0F0L + 2; .... default: return 0; } }
/** * 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(); } }