org.jetbrains.kotlin.preloading.Preloader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-preloader Show documentation
Show all versions of kotlin-preloader Show documentation
Since there is no official artifact on Central Reporitory, this is a howebrew preloader artifact of the Kotlin compiler
The newest version!
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.preloading;
import org.jetbrains.kotlin.preloading.instrumentation.Instrumenter;
import java.io.File;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
@SuppressWarnings("UseOfSystemOutOrSystemErr")
public class Preloader {
public static final int DEFAULT_CLASS_NUMBER_ESTIMATE = 4096;
public static void main(String[] args) throws Exception {
try {
run(args);
}
catch (PreloaderException e) {
System.err.println("error: " + e.toString());
System.err.println();
printUsage(System.err);
System.exit(1);
}
}
private static void run(String[] args) throws Exception {
final long startTime = System.nanoTime();
final Options options = parseOptions(args);
ClassLoader classLoader = createClassLoader(options);
final Handler handler = getHandler(options, classLoader);
ClassLoader preloaded = ClassPreloadingUtils.preloadClasses(options.classpath, options.estimate, classLoader, null, handler);
Class> mainClass = preloaded.loadClass(options.mainClass);
Method mainMethod = mainClass.getMethod("main", String[].class);
Runtime.getRuntime().addShutdownHook(
new Thread(new Runnable() {
@Override
public void run() {
if (options.measure) {
System.out.println();
System.out.println("=== Preloader's measurements: ");
System.out.format("Total time: %.3fs\n", (System.nanoTime() - startTime) / 1e9);
}
handler.done();
}
})
);
//noinspection SSBasedInspection
mainMethod.invoke(0, (Object) options.arguments.toArray(new String[options.arguments.size()]));
}
private static ClassLoader createClassLoader(Options options) throws MalformedURLException {
ClassLoader parent = Preloader.class.getClassLoader();
List instrumenters = options.instrumenters;
if (instrumenters.isEmpty()) return parent;
URL[] classpath = new URL[instrumenters.size()];
for (int i = 0; i < instrumenters.size(); i++) {
classpath[i] = instrumenters.get(i).toURI().toURL();
}
return new URLClassLoader(classpath, parent);
}
@SuppressWarnings("AssignmentToForLoopParameter")
private static Options parseOptions(String[] args) throws Exception {
List classpath = Collections.emptyList();
boolean measure = false;
List instrumenters = Collections.emptyList();
int estimate = DEFAULT_CLASS_NUMBER_ESTIMATE;
String mainClass = null;
List arguments = new ArrayList();
for (int i = 0; i < args.length; i++) {
String arg = args[i];
boolean end = i == args.length - 1;
if ("-help".equals(arg) || "-h".equals(arg)) {
printUsage(System.out);
System.exit(0);
}
else if ("-cp".equals(arg) || "-classpath".equals(arg)) {
if (end) throw new PreloaderException("no argument provided to " + arg);
classpath = parseClassPath(args[++i]);
}
else if ("-estimate".equals(arg)) {
if (end) throw new PreloaderException("no argument provided to " + arg);
estimate = Integer.parseInt(args[++i]);
}
else if ("-instrument".equals(arg)) {
if (end) throw new PreloaderException("no argument provided to " + arg);
instrumenters = parseClassPath(args[++i]);
}
else if ("-measure".equals(arg)) {
measure = true;
}
else {
mainClass = arg;
arguments.addAll(Arrays.asList(args).subList(i + 1, args.length));
break;
}
}
if (mainClass == null) throw new PreloaderException("no main class name provided");
return new Options(classpath, measure, instrumenters, estimate, mainClass, arguments);
}
private static List parseClassPath(String classpath) {
String[] paths = classpath.split(File.pathSeparator);
List files = new ArrayList(paths.length);
for (String path : paths) {
File file = new File(path);
if (!file.exists()) {
throw new PreloaderException("file does not exist: " + file);
}
files.add(file);
}
return files;
}
private static Handler getHandler(Options options, ClassLoader withInstrumenter) {
if (!options.measure) return new Handler();
final Instrumenter instrumenter = options.instrumenters.isEmpty() ? Instrumenter.DO_NOTHING : loadInstrumenter(withInstrumenter);
final int[] counter = new int[1];
final int[] size = new int[1];
return new Handler() {
@Override
public void beforeDefineClass(String name, int sizeInBytes) {
counter[0]++;
size[0] += sizeInBytes;
}
@Override
public void done() {
System.out.println();
System.out.println("Loaded classes: " + counter[0]);
System.out.println("Loaded classes size: " + size[0]);
System.out.println();
instrumenter.dump(System.out);
}
@Override
public byte[] instrument(String resourceName, byte[] data) {
return instrumenter.instrument(resourceName, data);
}
};
}
private static Instrumenter loadInstrumenter(ClassLoader withInstrumenter) {
ServiceLoader loader = ServiceLoader.load(Instrumenter.class, withInstrumenter);
Iterator instrumenters = loader.iterator();
if (instrumenters.hasNext()) {
Instrumenter instrumenter = instrumenters.next();
if (instrumenters.hasNext()) {
System.err.println("warning: only the first preloader instrumenter is used: " + instrumenter.getClass());
}
return instrumenter;
}
else {
System.err.println("warning: no preloader instrumenters found");
return Instrumenter.DO_NOTHING;
}
}
private static void printUsage(PrintStream out) {
out.println("usage: java -jar kotlin-preloader.jar [] []");
out.println("where possible options include:");
out.println(" -classpath (-cp) Paths where to find class files");
out.println(" -measure Record and output the total time taken by the program and number of loaded classes");
out.println(" -instrument Paths where the instrumenter will be looked up by java.util.ServiceLoader");
out.println(" (the class must implement " + Instrumenter.class.getCanonicalName() + " interface)");
out.println(" -estimate Class number estimate (" + DEFAULT_CLASS_NUMBER_ESTIMATE + " by default)");
out.println(" -help (-h) Output this help message");
}
private static class Options {
public final List classpath;
public final boolean measure;
public final List instrumenters;
public final int estimate;
public final String mainClass;
public final List arguments;
private Options(
List classpath,
boolean measure,
List instrumenters,
int estimate,
String mainClass,
List arguments
) {
this.classpath = classpath;
this.measure = measure;
this.instrumenters = instrumenters;
this.estimate = estimate;
this.mainClass = mainClass;
this.arguments = arguments;
}
}
private static class PreloaderException extends RuntimeException {
public PreloaderException(String message) {
super(message);
}
}
private static class Handler extends ClassHandler {
public void done() {}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy