Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/classload/GeneratingClassLoader.java
41161 views
/*1* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package nsk.share.classload;2425import java.io.*;26import java.util.*;27import nsk.share.*;2829/**30* Classloader that generates classes on the fly.31*32* This classloader can load classes with name starting with 'Class'.33* It will use nsk.share.classload.TemplateClass as template and will34* replace class name in the bytecode of template class. It can be used35* for example to detect memory leaks in class loading or to quickly36* fill PermGen.37*/38public class GeneratingClassLoader extends ClassLoader {39public static final String DEFAULT_CLASSNAME = TemplateClass.class.getName();40public static final String PREFIX = "Class";4142private final String [] classPath;43private byte[] bytecode;44private int[] offsets;45private final String encoding = "UTF8";46private final String templateClassName;47private final byte[] templateClassNameBytes;4849/**50* Create generating class loader that will use class file51* for given class from classpath as template.52*/53public GeneratingClassLoader(String templateClassName) {54this.templateClassName = templateClassName;55classPath = System.getProperty("java.class.path").split(File.pathSeparator);56try {57templateClassNameBytes = templateClassName.getBytes(encoding);58} catch (UnsupportedEncodingException e) {59throw new TestBug(e);60}61}6263/**64* Create generating class loader that will use class file65* for nsk.share.classload.TemplateClass as template.66*/67public GeneratingClassLoader() {68this("nsk.share.classload.TemplateClass");69}7071public int getNameLength() {72return templateClassName.length();73}7475public String getPrefix() {76return PREFIX;77}7879public String getClassName(int number) {80StringBuffer sb = new StringBuffer();81sb.append(PREFIX);82sb.append(number);83int n = templateClassName.length() - sb.length();84for (int i = 0; i < n; ++i)85sb.append("_");86return sb.toString();87}8889public synchronized Class loadClass(String name) throws ClassNotFoundException {90return loadClass(name, false);91}9293public synchronized Class loadClass(String name, boolean resolve)94throws ClassNotFoundException {95Class c = findLoadedClass(name);96if (c != null)97return c;98if (!name.startsWith(PREFIX))99return super.loadClass(name, resolve);100if (name.length() != templateClassName.length())101throw new ClassNotFoundException("Only can load classes with name.length() = " + getNameLength() + " got: '" + name + "' length: " + name.length());102byte[] bytecode = getPatchedByteCode(name);103c = defineClass(name, bytecode, 0, bytecode.length);104if (resolve)105resolveClass(c);106return c;107}108109private byte[] getPatchedByteCode(String name) throws ClassNotFoundException {110try {111byte[] bytecode = getByteCode();112String fname = name.replace(".", File.separator);113byte[] replaceBytes = fname.getBytes(encoding);114for (int offset : offsets) {115for (int i = 0; i < replaceBytes.length; ++i)116bytecode[offset + i] = replaceBytes[i];117}118return bytecode;119} catch (UnsupportedEncodingException e) {120throw new TestBug(e);121}122}123124private byte[] getByteCode() throws ClassNotFoundException {125if (bytecode == null)126readByteCode();127if (offsets == null) {128getOffsets(bytecode);129if (offsets == null)130throw new TestBug("Class name not found in template class file");131}132return (byte[]) bytecode.clone();133}134135private void readByteCode() throws ClassNotFoundException {136String fname = templateClassName.replace(".", File.separator) + ".class";137File target = null;138for (int i = 0; i < classPath.length; ++i) {139target = new File(classPath[i] + File.separator + fname);140if (target.exists())141break;142}143144if (target == null || !target.exists())145throw new ClassNotFoundException("File not found: " + target);146try {147bytecode = FileUtils.readFile(target);148} catch (IOException e) {149throw new ClassNotFoundException(templateClassName, e);150}151}152153private void getOffsets(byte[] bytecode) {154List<Integer> offsets = new ArrayList<Integer>();155if (this.offsets == null) {156String pname = templateClassName.replace(".", "/");157try {158byte[] pnameb = pname.getBytes(encoding);159int i = 0;160while (true) {161while (i < bytecode.length) {162int j = 0;163while (j < pnameb.length && bytecode[i + j] == pnameb[j])164++j;165if (j == pnameb.length)166break;167i++;168}169if (i == bytecode.length)170break;171offsets.add(Integer.valueOf(i));172i++;173}174} catch (UnsupportedEncodingException e) {175throw new TestBug(e);176}177this.offsets = new int[offsets.size()];178for (int i = 0; i < offsets.size(); ++i)179this.offsets[i] = offsets.get(i).intValue();180}181}182}183184185