1 /* 2 * Copyright (c) 2013, 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 * 27 * @summary converted from VM Testbase metaspace/stressDictionary. 28 * VM Testbase keywords: [nonconcurrent, javac] 29 * 30 * @library /vmTestbase /test/lib 31 * @run driver jdk.test.lib.FileInstaller . . 32 * @run main/othervm metaspace.stressDictionary.StressDictionary -stressTime 30 33 */ 34 35 package metaspace.stressDictionary; 36 37 import java.util.*; 38 import java.lang.management.ManagementFactory; 39 import java.lang.reflect.InvocationTargetException; 40 import java.lang.reflect.Method; 41 import java.util.concurrent.*; 42 import java.util.concurrent.atomic.AtomicLong; 43 44 import nsk.share.gc.GCTestBase; 45 import nsk.share.test.*; 46 import vm.share.InMemoryJavaCompiler; 47 48 /** 49 * There is a data structure named "dictionary" in class BlockFreelist. It stores 50 * information about free memory blocks for further reusing. Allocation of new block goes 51 * from dictionary only if dictionary is fat enough. (At the moment of test creation this limit is 64K.) 52 * So to stress dictionary we should fill it permanently. The easiest way to fill the dictionary 53 * is to fail class loading. This failed action will return allocated blocks to dictionary. 54 * 55 * There are two type of threads in this test: threads, failing classloading and threads, 56 * loading regular classes and checking they work properly. 57 */ 58 public class StressDictionary extends GCTestBase { 59 60 private static byte[] bytecode; 61 62 private class FillingDictionaryWorker implements Callable<Object> { 63 @Override 64 public Object call() throws Exception { 65 while (stresser.continueExecution()) { 66 try { 67 byte[] badBytecode = bytecode.clone(); 68 badBytecode[random.nextInt(badBytecode.length)] = (byte) 42; 69 classloader.define(badBytecode); 70 } catch (Throwable e) { 71 // We can get ClassFormatError, ClassNotFoundException or anything else here 72 } 73 } 74 return null; 75 } 76 } 77 78 private class RegularWorker implements Callable<Object> { 79 @Override 80 public Object call() throws Exception { 81 while (stresser.continueExecution()) { 82 Class<?> c = classloader.define(bytecode); 83 testClass(c); 84 } 85 return null; 86 } 87 } 88 89 private static String[] args; 90 91 private static final String methodName = "myMethod"; 92 93 private static final int NUMBER_OF_CORRUPTING_THREADS = 10; 94 95 private static final int NUMBER_OF_METHOD_CALLS = 50; 96 97 private static final int NUMBER_OF_NOT_CORRUPTING_THREADS = 10; 98 99 private AtomicLong classesCounter = new AtomicLong(0); 100 101 private volatile ClassloaderUnderTest classloader = new ClassloaderUnderTest(); 102 103 private Random random; 104 105 private ExecutionController stresser; 106 107 public static void main(String[] args) { 108 StressDictionary.args = args; 109 Tests.runTest(new StressDictionary(), args); 110 } 111 112 public void run() { 113 random = new Random(runParams.getSeed()); 114 stresser = new Stresser(args); 115 stresser.start(1); 116 // Generate some bytecodes. 117 bytecode = generateAndCompile(); 118 List<Callable<Object>> tasks = new LinkedList<Callable<Object>>(); 119 for (int i = 0; i < NUMBER_OF_CORRUPTING_THREADS; i++) { 120 tasks.add(this.new FillingDictionaryWorker()); 121 } 122 for (int i = 0; i < NUMBER_OF_NOT_CORRUPTING_THREADS; i++) { 123 tasks.add(this.new RegularWorker()); 124 } 125 ExecutorService executorService = Executors.newCachedThreadPool(); 126 try { 127 executorService.invokeAll(tasks); 128 } catch (InterruptedException e) { 129 e.printStackTrace(); 130 } 131 } 132 133 private byte[] generateAndCompile() { 134 Map<String, CharSequence> sources = new HashMap<String, CharSequence>(); 135 String className = "MyClass" + classesCounter.incrementAndGet(); 136 sources.put(className, generateSource(className)); 137 return InMemoryJavaCompiler.compile(sources).values().iterator().next(); 138 } 139 140 private CharSequence generateSource(String className) { 141 return "public class " + className + " { " + 142 "public static String s1 = \"s1" + random.nextInt() + "\"; " + 143 "public String s2 = \"s2" + random.nextInt() + "\"; " + 144 "public String " + methodName + "() {return s1 + s2; } " + 145 "}"; 146 } 147 148 private void testClass(Class<?> clazz) { 149 try { 150 for (Method m : clazz.getMethods()) { 151 if (m.getName().equals(methodName)) { 152 for (int j = 0; j < NUMBER_OF_METHOD_CALLS; j++) { 153 m.invoke(clazz.newInstance()); 154 } 155 } 156 } 157 } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { 158 log.error("Class check failed: " + e.getMessage()); 159 e.printStackTrace(); 160 setFailed(true); 161 } 162 163 } 164 165 }