1 /*
   2  * Copyright (c) 2011, 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.replacements.test;
  24 
  25 import java.util.Random;
  26 
  27 import org.graalvm.compiler.core.test.GraalCompilerTest;
  28 import org.graalvm.compiler.phases.common.AbstractInliningPhase;
  29 import org.graalvm.compiler.test.ExportingClassLoader;
  30 import org.junit.Assert;
  31 import org.junit.Test;
  32 
  33 import org.objectweb.asm.ClassWriter;
  34 import org.objectweb.asm.Label;
  35 import org.objectweb.asm.MethodVisitor;
  36 import org.objectweb.asm.Opcodes;
  37 import jdk.vm.ci.meta.ResolvedJavaMethod;
  38 
  39 /**
  40  * Tests that deoptimization upon exception handling works.
  41  */
  42 public class DeoptimizeOnExceptionTest extends GraalCompilerTest {
  43 
  44     public DeoptimizeOnExceptionTest() {
  45         getSuites().getHighTier().findPhase(AbstractInliningPhase.class).remove();
  46     }
  47 
  48     private static void raiseException(String m1, String m2, String m3, String m4, String m5) {
  49         throw new RuntimeException(m1 + m2 + m3 + m4 + m5);
  50     }
  51 
  52     @Test
  53     public void test1() {
  54         test("test1Snippet", "m1", "m2", "m3", "m4", "m5");
  55     }
  56 
  57     // no local exception handler - will deopt
  58     public static String test1Snippet(String m1, String m2, String m3, String m4, String m5) {
  59         if (m1 != null) {
  60             raiseException(m1, m2, m3, m4, m5);
  61         }
  62         return m1 + m2 + m3 + m4 + m5;
  63     }
  64 
  65     @Test
  66     public void test2() {
  67         test("test2Snippet");
  68     }
  69 
  70     public String test2Snippet() throws Exception {
  71         try {
  72             ClassLoader testCl = new MyClassLoader();
  73             @SuppressWarnings("unchecked")
  74             Class<Runnable> c = (Class<Runnable>) testCl.loadClass(name);
  75             Runnable r = c.newInstance();
  76             ct = Long.MAX_VALUE;
  77             // warmup
  78             for (int i = 0; i < 100; i++) {
  79                 r.run();
  80             }
  81             // compile
  82             ResolvedJavaMethod method = getResolvedJavaMethod(c, "run");
  83             getCode(method);
  84             ct = 0;
  85             r.run();
  86         } catch (Throwable e) {
  87             e.printStackTrace(System.out);
  88             Assert.fail();
  89         }
  90         return "SUCCESS";
  91     }
  92 
  93     public static class MyClassLoader extends ExportingClassLoader {
  94         @Override
  95         protected Class<?> findClass(String className) throws ClassNotFoundException {
  96             return defineClass(name.replace('/', '.'), clazz, 0, clazz.length);
  97         }
  98     }
  99 
 100     public static void methodB() {
 101         Random r = new Random(System.currentTimeMillis());
 102         while (r.nextFloat() > .03f) {
 103             // Empty
 104         }
 105 
 106         return;
 107     }
 108 
 109     public static void methodA() {
 110         Random r = new Random(System.currentTimeMillis());
 111         while (r.nextDouble() > .05) {
 112             // Empty
 113         }
 114         return;
 115     }
 116 
 117     private static Object m = new Object();
 118     static long ct = Long.MAX_VALUE;
 119 
 120     public static Object getM() {
 121         if (ct-- > 0) {
 122             return m;
 123         } else {
 124             return null;
 125         }
 126     }
 127 
 128     private static String name = "t/TestJSR";
 129 
 130     private static final byte[] clazz = makeClazz();
 131 
 132     private static byte[] makeClazz() {
 133         // Code generated the class below using asm.
 134         String clazzName = DeoptimizeOnExceptionTest.class.getName().replace('.', '/');
 135         final ClassWriter w = new ClassWriter(0);
 136         w.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC,
 137                         "t/TestJSR", null, "java/lang/Object",
 138                         new String[]{"java/lang/Runnable"});
 139         MethodVisitor mv = w.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, new String[]{});
 140         mv.visitCode();
 141         mv.visitVarInsn(Opcodes.ALOAD, 0);
 142         mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
 143         mv.visitInsn(Opcodes.RETURN);
 144         mv.visitMaxs(10, 10);
 145         mv.visitEnd();
 146 
 147         mv = w.visitMethod(Opcodes.ACC_PUBLIC, "run", "()V", null, null);
 148         mv.visitCode();
 149         mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "getM", "()Ljava/lang/Object;", false);
 150         Label l1 = new Label();
 151         mv.visitJumpInsn(Opcodes.JSR, l1);
 152         mv.visitInsn(Opcodes.RETURN);
 153 
 154         mv.visitLabel(l1);
 155         mv.visitVarInsn(Opcodes.ASTORE, 1);
 156 
 157         Label lElse = new Label();
 158         Label lEnd = new Label();
 159         mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);
 160         mv.visitInsn(Opcodes.POP2);
 161         mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "getM", "()Ljava/lang/Object;", false);
 162         mv.visitInsn(Opcodes.DUP);
 163         mv.visitJumpInsn(Opcodes.IFNULL, lElse);
 164         mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "methodA", "()V", false);
 165         mv.visitJumpInsn(Opcodes.GOTO, lEnd);
 166         mv.visitLabel(lElse);
 167         mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "methodB", "()V", false);
 168         mv.visitLabel(lEnd);
 169 
 170         mv.visitVarInsn(Opcodes.RET, 1);
 171         mv.visitMaxs(10, 10);
 172         mv.visitEnd();
 173         return w.toByteArray();
 174     }
 175 }