blob: d03e9f8643e582951322eb27b3bb25efdc94eb06 [file] [log] [blame]
/*
* 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();
}
}