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 }