/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.max.graal.hotspot;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.*;
import com.oracle.max.criutils.*;
import com.oracle.max.graal.compiler.*;
import com.oracle.max.graal.hotspot.server.*;
import com.sun.cri.ci.CiCompiler.DebugInfoLevel;
import com.sun.cri.ci.*;
import com.sun.cri.ri.*;
/**
* Exits from the HotSpot VM into Java code.
*/
public class VMExitsNative implements VMExits, Remote {
private boolean installedIntrinsics;
private final Compiler compiler;
public final HotSpotTypePrimitive typeBoolean;
public final HotSpotTypePrimitive typeChar;
public final HotSpotTypePrimitive typeFloat;
public final HotSpotTypePrimitive typeDouble;
public final HotSpotTypePrimitive typeByte;
public final HotSpotTypePrimitive typeShort;
public final HotSpotTypePrimitive typeInt;
public final HotSpotTypePrimitive typeLong;
public final HotSpotTypePrimitive typeVoid;
ThreadFactory daemonThreadFactory = new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new CompilerThread(r);
t.setDaemon(true);
return t;
}
};
private static final class CompilerThread extends Thread {
public CompilerThread(Runnable r) {
super(r);
this.setName("CompilerThread-" + this.getId());
}
}
private ThreadPoolExecutor compileQueue;
public VMExitsNative(Compiler compiler) {
this.compiler = compiler;
typeBoolean = new HotSpotTypePrimitive(compiler, CiKind.Boolean);
typeChar = new HotSpotTypePrimitive(compiler, CiKind.Char);
typeFloat = new HotSpotTypePrimitive(compiler, CiKind.Float);
typeDouble = new HotSpotTypePrimitive(compiler, CiKind.Double);
typeByte = new HotSpotTypePrimitive(compiler, CiKind.Byte);
typeShort = new HotSpotTypePrimitive(compiler, CiKind.Short);
typeInt = new HotSpotTypePrimitive(compiler, CiKind.Int);
typeLong = new HotSpotTypePrimitive(compiler, CiKind.Long);
typeVoid = new HotSpotTypePrimitive(compiler, CiKind.Void);
}
private static Set<String> compiledMethods = new HashSet<String>();
public void startCompiler() throws Throwable {
// Make sure TTY is initialized here such that the correct System.out is used for TTY.
TTY.initialize();
// Install intrinsics.
HotSpotIntrinsic.installIntrinsics((HotSpotRuntime) compiler.getCompiler().runtime);
// Create compilation queue.
compileQueue = new ThreadPoolExecutor(GraalOptions.Threads, GraalOptions.Threads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), daemonThreadFactory);
// Create queue status printing thread.
if (GraalOptions.PrintQueue) {
Thread t = new Thread() {
@Override
public void run() {
while (true) {
TTY.println(compileQueue.toString());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
};
t.setDaemon(true);
t.start();
}
}
public void bootstrap() throws Throwable {
TTY.print("Bootstrapping Graal");
TTY.flush();
// Initialize compile queue with a selected set of methods.
Class<Object> objectKlass = Object.class;
enqueue(objectKlass.getDeclaredMethod("equals", Object.class));
enqueue(objectKlass.getDeclaredMethod("toString"));
// Compile until the queue is empty.
long startTime = System.currentTimeMillis();
int z = 0;
while (compileQueue.getCompletedTaskCount() < compileQueue.getTaskCount()) {
Thread.sleep(100);
while (z < compileQueue.getCompletedTaskCount() / 100) {
++z;
TTY.print(".");
TTY.flush();
}
}
TTY.println(" in %d ms", System.currentTimeMillis() - startTime);
System.gc();
}
private void enqueue(Method m) throws Throwable {
RiMethod riMethod = compiler.getRuntime().getRiMethod(m);
assert !Modifier.isAbstract(((HotSpotMethodResolved) riMethod).accessFlags()) && !Modifier.isNative(((HotSpotMethodResolved) riMethod).accessFlags()) : riMethod;
compileMethod((HotSpotMethodResolved) riMethod, 0, true);
}
public void shutdownCompiler() throws Throwable {
compiler.getCompiler().context.print();
compileQueue.shutdown();
}
@Override
public void compileMethod(final HotSpotMethodResolved method, final int entryBCI, boolean blocking) throws Throwable {
try {
if (Thread.currentThread() instanceof CompilerThread && method.holder().name().contains("java/util/concurrent")) {
return;
}
Runnable runnable = new Runnable() {
public void run() {
try {
CiTargetMethod result = compiler.getCompiler().compileMethod(method, -1, null, DebugInfoLevel.FULL);
HotSpotTargetMethod.installMethod(compiler, method, result, true);
} catch (CiBailout bailout) {
if (GraalOptions.ExitVMOnBailout) {
bailout.printStackTrace(TTY.cachedOut);
System.exit(-1);
}
} catch (Throwable t) {
if (GraalOptions.ExitVMOnException) {
t.printStackTrace(TTY.cachedOut);
System.exit(-1);
}
}
}
};
if (blocking) {
runnable.run();
} else {
compileQueue.execute(runnable);
}
} catch (RejectedExecutionException e) {
// The compile queue was already shut down.
return;
}
}
@Override
public RiMethod createRiMethodUnresolved(String name, String signature, RiType holder) {
return new HotSpotMethodUnresolved(compiler, name, signature, holder);
}
@Override
public RiSignature createRiSignature(String signature) {
return new HotSpotSignature(compiler, signature);
}
@Override
public RiField createRiField(RiType holder, String name, RiType type, int offset, int flags) {
if (offset != -1) {
HotSpotTypeResolved resolved = (HotSpotTypeResolved) holder;
return resolved.createRiField(name, type, offset, flags);
}
return new BaseUnresolvedField(holder, name, type);
}
@Override
public RiType createRiType(HotSpotConstantPool pool, String name) {
throw new RuntimeException("not implemented");
}
@Override
public RiType createRiTypePrimitive(int basicType) {
switch (basicType) {
case 4:
return typeBoolean;
case 5:
return typeChar;
case 6:
return typeFloat;
case 7:
return typeDouble;
case 8:
return typeByte;
case 9:
return typeShort;
case 10:
return typeInt;
case 11:
return typeLong;
case 14:
return typeVoid;
default:
throw new IllegalArgumentException("Unknown basic type: " + basicType);
}
}
@Override
public RiType createRiTypeUnresolved(String name) {
return new HotSpotTypeUnresolved(compiler, name);
}
@Override
public CiConstant createCiConstant(CiKind kind, long value) {
if (kind == CiKind.Long) {
return CiConstant.forLong(value);
} else if (kind == CiKind.Int) {
return CiConstant.forInt((int) value);
} else if (kind == CiKind.Short) {
return CiConstant.forShort((short) value);
} else if (kind == CiKind.Char) {
return CiConstant.forChar((char) value);
} else if (kind == CiKind.Byte) {
return CiConstant.forByte((byte) value);
} else if (kind == CiKind.Boolean) {
return (value == 0) ? CiConstant.FALSE : CiConstant.TRUE;
} else {
throw new IllegalArgumentException();
}
}
@Override
public CiConstant createCiConstantFloat(float value) {
return CiConstant.forFloat(value);
}
@Override
public CiConstant createCiConstantDouble(double value) {
return CiConstant.forDouble(value);
}
@Override
public CiConstant createCiConstantObject(Object object) {
return CiConstant.forObject(object);
}
@Override
public void pollJavaQueue() {
((HotSpotRuntime) compiler.getRuntime()).pollJavaQueue();
}
}