1 /*
   2  * Copyright (c) 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.core.test;
  24 
  25 import java.util.ArrayList;
  26 import java.util.List;
  27 import jdk.vm.ci.meta.JavaKind;
  28 import jdk.vm.ci.meta.ResolvedJavaMethod;
  29 import org.junit.Test;
  30 import org.junit.runner.RunWith;
  31 import org.junit.runners.Parameterized;
  32 import org.junit.runners.Parameterized.Parameters;
  33 import org.objectweb.asm.ClassWriter;
  34 import org.objectweb.asm.FieldVisitor;
  35 import org.objectweb.asm.MethodVisitor;
  36 import org.objectweb.asm.Opcodes;
  37 
  38 @RunWith(Parameterized.class)
  39 public class SubWordReturnTest extends GraalCompilerTest {
  40 
  41     private final JavaKind kind;
  42     private final int value;
  43 
  44     private final String generatedClassName;
  45     private final String generatedClassNameInternal;
  46 
  47     private final String testMethodName;
  48 
  49     /**
  50      * The {@link AsmLoader} generates a class looking like this for the types byte, short, int and
  51      * char.
  52      */
  53     static class ByteGetter {
  54 
  55         // private static int intField = 1000000;
  56 
  57         private static byte get() {
  58             // GETSTATIC intField
  59             // IRETURN
  60             return 0;
  61         }
  62 
  63         public static int testByteSnippet() {
  64             return get();
  65         }
  66     }
  67 
  68     @Parameters(name = "{0}, {1}")
  69     public static List<Object[]> data() {
  70         ArrayList<Object[]> ret = new ArrayList<>();
  71         for (int i : new int[]{1000000, 1000001, -1000000, -1}) {
  72             ret.add(new Object[]{JavaKind.Boolean, i});
  73             ret.add(new Object[]{JavaKind.Byte, i});
  74             ret.add(new Object[]{JavaKind.Short, i});
  75             ret.add(new Object[]{JavaKind.Char, i});
  76         }
  77         return ret;
  78     }
  79 
  80     public SubWordReturnTest(JavaKind kind, int value) {
  81         this.kind = kind;
  82         this.value = value;
  83 
  84         this.generatedClassName = SubWordReturnTest.class.getName() + "$" + kind.toString() + "Getter";
  85         this.generatedClassNameInternal = generatedClassName.replace('.', '/');
  86         this.testMethodName = "test" + kind.name() + "Snippet";
  87     }
  88 
  89     @Test
  90     public void test() throws ClassNotFoundException {
  91         Class<?> testClass = new AsmLoader(SubWordReturnTest.class.getClassLoader()).findClass(generatedClassName);
  92         ResolvedJavaMethod method = getResolvedJavaMethod(testClass, testMethodName);
  93         test(method, null);
  94     }
  95 
  96     class AsmLoader extends ClassLoader implements Opcodes {
  97 
  98         Class<?> loaded;
  99 
 100         AsmLoader(ClassLoader parent) {
 101             super(parent);
 102         }
 103 
 104         @Override
 105         protected Class<?> findClass(String name) throws ClassNotFoundException {
 106             if (name.equals(generatedClassName)) {
 107                 if (loaded == null) {
 108                     byte[] gen = generateClass();
 109                     loaded = defineClass(name, gen, 0, gen.length);
 110                 }
 111                 return loaded;
 112             } else {
 113                 return super.findClass(name);
 114             }
 115         }
 116 
 117         private byte[] generateClass() {
 118             ClassWriter cw = new ClassWriter(0);
 119             cw.visit(52, ACC_SUPER | ACC_PUBLIC, generatedClassNameInternal, null, "java/lang/Object", null);
 120 
 121             FieldVisitor intField = cw.visitField(ACC_PRIVATE | ACC_STATIC, "intField", "I", null, value);
 122             intField.visitEnd();
 123 
 124             MethodVisitor get = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, "get", "()" + kind.getTypeChar(), null, null);
 125             get.visitCode();
 126             get.visitFieldInsn(GETSTATIC, generatedClassNameInternal, "intField", "I");
 127             get.visitInsn(IRETURN);
 128             get.visitMaxs(1, 0);
 129             get.visitEnd();
 130 
 131             MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, testMethodName, "()I", null, null);
 132             snippet.visitCode();
 133             snippet.visitMethodInsn(INVOKESTATIC, generatedClassNameInternal, "get", "()" + kind.getTypeChar(), false);
 134             snippet.visitInsn(IRETURN);
 135             snippet.visitMaxs(1, 0);
 136             snippet.visitEnd();
 137 
 138             cw.visitEnd();
 139             return cw.toByteArray();
 140         }
 141     }
 142 
 143 }