1 /*
   2  * Copyright (c) 2018, 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 
  24 /*
  25  * @test
  26  * @bug 8194246
  27  * @summary JVM crashes on stack trace for large number of methods.
  28  * @library /test/lib
  29  * @modules java.base/jdk.internal.org.objectweb.asm
  30  *          java.base/jdk.internal.misc
  31  *          java.management
  32  * @compile -XDignore.symbol.file LargeClassTest.java
  33  * @run main LargeClassTest
  34  */
  35 
  36 import java.io.File;
  37 import java.io.FileOutputStream;
  38 import jdk.internal.org.objectweb.asm.ClassWriter;
  39 import jdk.internal.org.objectweb.asm.MethodVisitor;
  40 import jdk.internal.org.objectweb.asm.FieldVisitor;
  41 import jdk.internal.org.objectweb.asm.Label;
  42 import jdk.internal.org.objectweb.asm.AnnotationVisitor;
  43 import jdk.internal.org.objectweb.asm.Opcodes;
  44 import jdk.test.lib.process.ProcessTools;
  45 import jdk.test.lib.process.OutputAnalyzer;
  46 
  47 public class LargeClassTest implements Opcodes {
  48     public static void main(String... args) throws Exception {
  49         writeClassFile();
  50         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, "-cp", ".",  "Large");
  51         OutputAnalyzer output = new OutputAnalyzer(pb.start());
  52         output.shouldHaveExitValue(0);
  53     }
  54 
  55     // Writes a Large class with > signed 16 bit int methods
  56     public static void writeClassFile() throws Exception {
  57 
  58         ClassWriter cw = new ClassWriter(0);
  59         FieldVisitor fv;
  60         MethodVisitor mv;
  61         AnnotationVisitor av0;
  62 
  63         cw.visit(55, ACC_PUBLIC + ACC_SUPER, "Large", null, "java/lang/Object", null);
  64 
  65         {
  66           mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
  67           mv.visitCode();
  68           mv.visitVarInsn(ALOAD, 0);
  69           mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
  70           mv.visitInsn(RETURN);
  71           mv.visitMaxs(1, 1);
  72           mv.visitEnd();
  73         }
  74         {
  75           // public static void main(String[] args) {
  76           //     Large large = new Large();
  77           //     large.f_1(55);
  78           // }
  79           mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
  80           mv.visitCode();
  81           mv.visitTypeInsn(NEW, "Large");
  82           mv.visitInsn(DUP);
  83           mv.visitMethodInsn(INVOKESPECIAL, "Large", "<init>", "()V", false);
  84           mv.visitVarInsn(ASTORE, 1);
  85           mv.visitVarInsn(ALOAD, 1);
  86           mv.visitIntInsn(BIPUSH, 55);
  87           mv.visitMethodInsn(INVOKEVIRTUAL, "Large", "f_1", "(I)I", false);
  88           mv.visitInsn(POP);
  89           mv.visitInsn(RETURN);
  90           mv.visitMaxs(2, 2);
  91           mv.visitEnd();
  92         }
  93 
  94         // Write 33560 methods called f_$i
  95         for (int i = 1000; i < 34560; i++)
  96         {
  97           mv = cw.visitMethod(ACC_PUBLIC, "f_" + i, "()V", null, null);
  98           mv.visitCode();
  99           mv.visitInsn(RETURN);
 100           mv.visitMaxs(0, 1);
 101           mv.visitEnd();
 102         }
 103         {
 104           // public int f_1(int prior) {
 105           //   int total = prior + new java.util.Random(1).nextInt();
 106           //   return total + f_2(total);
 107           // }
 108           mv = cw.visitMethod(ACC_PUBLIC, "f_1", "(I)I", null, null);
 109           mv.visitCode();
 110           mv.visitVarInsn(ILOAD, 1);
 111           mv.visitTypeInsn(NEW, "java/util/Random");
 112           mv.visitInsn(DUP);
 113           mv.visitInsn(LCONST_1);
 114           mv.visitMethodInsn(INVOKESPECIAL, "java/util/Random", "<init>", "(J)V", false);
 115           mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Random", "nextInt", "()I", false);
 116           mv.visitInsn(IADD);
 117           mv.visitVarInsn(ISTORE, 2);
 118           mv.visitVarInsn(ILOAD, 2);
 119           mv.visitVarInsn(ALOAD, 0);
 120           mv.visitVarInsn(ILOAD, 2);
 121           mv.visitMethodInsn(INVOKEVIRTUAL, "Large", "f_2", "(I)I", false);
 122           mv.visitInsn(IADD);
 123           mv.visitInsn(IRETURN);
 124           mv.visitMaxs(5, 3);
 125           mv.visitEnd();
 126         }
 127         {
 128           // public int f_2(int total) {
 129           //   System.out.println(java.util.Arrays.toString(Thread.currentThread().getStackTrace()));
 130           //   return 10;
 131           // }
 132           mv = cw.visitMethod(ACC_PUBLIC, "f_2", "(I)I", null, null);
 133           mv.visitCode();
 134           mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
 135           mv.visitMethodInsn(INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
 136           mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Thread", "getStackTrace", "()[Ljava/lang/StackTraceElement;", false);
 137           mv.visitMethodInsn(INVOKESTATIC, "java/util/Arrays", "toString", "([Ljava/lang/Object;)Ljava/lang/String;", false);
 138           mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
 139           mv.visitIntInsn(BIPUSH, 10);
 140           mv.visitInsn(IRETURN);
 141           mv.visitMaxs(2, 2);
 142           mv.visitEnd();
 143         }
 144         cw.visitEnd();
 145 
 146         try (FileOutputStream fos = new FileOutputStream(new File("Large.class"))) {
 147           fos.write(cw.toByteArray());
 148         }
 149     }
 150 }