Merge
This commit is contained in:
commit
d055fd81db
41
hotspot/agent/doc/c2replay.html
Normal file
41
hotspot/agent/doc/c2replay.html
Normal file
@ -0,0 +1,41 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>
|
||||
C2 Replay
|
||||
</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>C2 compiler replay</h1>
|
||||
<p>
|
||||
The C2 compiler replay is a function to repeat the compiling process from a crashed java process in compiled method<br>
|
||||
This function only exists in debug version of VM
|
||||
</p>
|
||||
<h2>Usage</h2>
|
||||
<pre>
|
||||
First, use SA to attach to the core file, if suceeded, do
|
||||
clhsdb>dumpreplaydata <address> | -a | <thread_id> [> replay.txt]
|
||||
create file replay.txt, address is address of Method, or nmethod(CodeBlob)
|
||||
clhsdb>buildreplayjars [all | boot | app]
|
||||
create files:
|
||||
all:
|
||||
app.jar, boot.jar
|
||||
boot:
|
||||
boot.jar
|
||||
app:
|
||||
app.jar
|
||||
exit SA now.
|
||||
Second, use the obtained replay text file, replay.txt and jar files, app.jar and boot.jar, using debug version of java
|
||||
java -Xbootclasspath/p:boot.jar -cp app.jar -XX:ReplayDataFile=<datafile> -XX:+ReplayCompiles ....
|
||||
This will replay the compiling process.
|
||||
|
||||
With ReplayCompiles, the replay will recompile all the methods in app.jar, and in boot.jar to emulate the process in java app.
|
||||
|
||||
notes:
|
||||
1) Most time, we don't need the boot.jar which is the classes loaded from JDK. It will be only modified when an agent(JVMDI) is running and modifies the classes.
|
||||
2) If encounter error as "<flag>" not found, that means the SA is using a VMStructs which is different from the one with corefile. In this case, SA has a utility tool vmstructsdump which is located at agent/src/os/<os>/proc/<os_platform>
|
||||
|
||||
Use this tool to dump VM type library:
|
||||
vmstructsdump libjvm.so > <type_name>.db
|
||||
|
||||
set env SA_TYPEDB=<type_name>.db (refer different shell for set envs)
|
@ -37,12 +37,19 @@ Each CLHSDB command can have zero or more arguments and optionally end with outp
|
||||
Available commands:
|
||||
assert true | false <font color="red">turn on/off asserts in SA code</font>
|
||||
attach pid | exec core <font color="red">attach SA to a process or core</font>
|
||||
buildreplayjars [all | boot | app] <font color="red">build jars for replay, boot.jar for bootclasses, app.jar for application classes</font>
|
||||
class name <font color="red">find a Java class from debuggee and print oop</font>
|
||||
classes <font color="red">print all loaded Java classes with Klass*</font>
|
||||
detach <font color="red">detach SA from current target</font>
|
||||
dis address [ length ] <font color="red">disassemble (sparc/x86) specified number of instructions from given address</font>
|
||||
dissemble address <font color="red">disassemble nmethod</font>
|
||||
dumpcfg -a | id <font color="red">Dump the PhaseCFG for every compiler thread that has one live</font>
|
||||
dumpclass { address | name } [ directory ] <font color="red">dump .class file for given Klass* or class name</font>
|
||||
dumpcodecache <font color="red">dump codecache contents</font>
|
||||
dumpheap [ file ] <font color="red">dump heap in hprof binary format</font>
|
||||
dumpideal -a | id <font color="red">dump ideal graph like debug flag -XX:+PrintIdeal</font>
|
||||
dumpilt -a | id <font color="red">dump inline tree for C2 compilation</font>
|
||||
dumpreplaydata <address> | -a | <thread_id> [>replay.txt] <font color="red">dump replay data into a file</font>
|
||||
echo [ true | false ] <font color="red">turn on/off command echo mode</font>
|
||||
examine [ address/count ] | [ address,address] <font color="red">show contents of memory from given address</font>
|
||||
field [ type [ name fieldtype isStatic offset address ] ] <font color="red">print info about a field of HotSpot type</font>
|
||||
@ -51,29 +58,35 @@ Available commands:
|
||||
help [ command ] <font color="red">print help message for all commands or just given command</font>
|
||||
history <font color="red">show command history. usual !command-number syntax works.</font>
|
||||
inspect expression <font color="red">inspect a given oop</font>
|
||||
intConstant [ name [ value ] ] <font color="red">print out hotspot integer constant(s)</font>
|
||||
jdis address <font color="red">show bytecode disassembly of a given Method*</font>
|
||||
jhisto <font color="red">show Java heap histogram</font>
|
||||
jseval script <font color="red">evaluate a given string as JavaScript code</font>
|
||||
jsload file <font color="red">load and evaluate a JavaScript file</font>
|
||||
jstack [-v] <font color="red">show Java stack trace of all Java threads. -v is verbose mode</font>
|
||||
livenmethods <font color="red">show all live nmethods</font>
|
||||
longConstant [ name [ value ] ] <font color="red">print out hotspot long constant(s)s</font>
|
||||
mem address [ length ] <font color="red">show contents of memory -- also shows closest ELF/COFF symbol if found</font>
|
||||
pmap <font color="red">show Solaris pmap-like output</font>
|
||||
print expression <font color="red">print given Klass*, Method* or arbitrary address</font>
|
||||
printas type expression <font color="red">print given address as given HotSpot type. eg. print JavaThread <address></font>
|
||||
printmdo -a | expression <font color="red">print method data oop</font>
|
||||
printstatics [ type ] <font color="red">print static fields of given HotSpot type (or all types if none specified)</font>
|
||||
pstack [-v] <font color="red">show mixed mode stack trace for all Java, non-Java threads. -v is verbose mode</font>
|
||||
quit <font color="red">quit CLHSDB tool</font>
|
||||
reattach <font color="red">detach and re-attach SA to current target</font>
|
||||
revptrs <font color="red">find liveness of oops</font>
|
||||
scanoops start end [ type ] <font color="red">scan a Oop from given start to end address</font>
|
||||
search [ heap | codecache | threads ] value <font color="red">search a value in heap or codecache or threads</font>
|
||||
source filename <font color="red">load and execute CLHSDB commands from given file</font>
|
||||
symbol name <font color="red">show address of a given ELF/COFF symbol</font>
|
||||
sysprops <font color="red">show all Java System properties</font>
|
||||
thread id <font color="red">show thread of id</font>
|
||||
threads <font color="red">show all Java threads</font>
|
||||
tokenize ...
|
||||
type [ type [ name super isOop isInteger isUnsigned size ] ] <font color="red">show info. on HotSpot type</font>
|
||||
universe <font color="red">print gc universe</font>
|
||||
vmstructsdump <font color="red">dump hotspot type library in text</font>
|
||||
verbose true | false <font color="red">turn on/off verbose mode</font>
|
||||
versioncheck [ true | false ] <font color="red">turn on/off debuggee VM version check</font>
|
||||
whatis address <font color="red">print info about any arbitrary address</font>
|
||||
@ -114,5 +127,11 @@ hsdb> jsload test.js
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<h3>C2 Compilation Replay</h3>
|
||||
<p>
|
||||
When a java process crashes in compiled method, usually a core file is saved.
|
||||
The C2 replay function can reproduce the compiling process in the core.
|
||||
<a href="c2replay.html">c2replay.html</a>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -220,6 +220,12 @@ These scripts are used to run SA remotely.
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3>C2 Compilation Replay</h3>
|
||||
<p>
|
||||
When a java process crashes in compiled method, usually a core file is saved.
|
||||
The C2 replay function can reproduce the compiling process in the core.
|
||||
<a href="c2replay.html">c2replay.html</a>
|
||||
|
||||
<h3>Debugging transported core dumps</h3>
|
||||
<p>
|
||||
When a core dump is moved from the machine where it was produced to a
|
||||
|
@ -58,10 +58,8 @@ sun.jvm.hotspot.debugger.cdbg.basic \
|
||||
sun.jvm.hotspot.debugger.cdbg.basic.amd64 \
|
||||
sun.jvm.hotspot.debugger.cdbg.basic.x86 \
|
||||
sun.jvm.hotspot.debugger.dummy \
|
||||
sun.jvm.hotspot.debugger.ia64 \
|
||||
sun.jvm.hotspot.debugger.linux \
|
||||
sun.jvm.hotspot.debugger.linux.amd64 \
|
||||
sun.jvm.hotspot.debugger.linux.ia64 \
|
||||
sun.jvm.hotspot.debugger.linux.x86 \
|
||||
sun.jvm.hotspot.debugger.posix \
|
||||
sun.jvm.hotspot.debugger.posix.elf \
|
||||
@ -77,7 +75,6 @@ sun.jvm.hotspot.debugger.sparc \
|
||||
sun.jvm.hotspot.debugger.win32.coff \
|
||||
sun.jvm.hotspot.debugger.windbg \
|
||||
sun.jvm.hotspot.debugger.windbg.amd64 \
|
||||
sun.jvm.hotspot.debugger.windbg.ia64 \
|
||||
sun.jvm.hotspot.debugger.windbg.x86 \
|
||||
sun.jvm.hotspot.debugger.x86 \
|
||||
sun.jvm.hotspot.gc_implementation \
|
||||
@ -97,10 +94,8 @@ sun.jvm.hotspot.runtime.amd64 \
|
||||
sun.jvm.hotspot.runtime.bsd \
|
||||
sun.jvm.hotspot.runtime.bsd_amd64 \
|
||||
sun.jvm.hotspot.runtime.bsd_x86 \
|
||||
sun.jvm.hotspot.runtime.ia64 \
|
||||
sun.jvm.hotspot.runtime.linux \
|
||||
sun.jvm.hotspot.runtime.linux_amd64 \
|
||||
sun.jvm.hotspot.runtime.linux_ia64 \
|
||||
sun.jvm.hotspot.runtime.linux_sparc \
|
||||
sun.jvm.hotspot.runtime.linux_x86 \
|
||||
sun.jvm.hotspot.runtime.posix \
|
||||
@ -109,7 +104,6 @@ sun.jvm.hotspot.runtime.solaris_sparc \
|
||||
sun.jvm.hotspot.runtime.solaris_x86 \
|
||||
sun.jvm.hotspot.runtime.sparc \
|
||||
sun.jvm.hotspot.runtime.win32_amd64 \
|
||||
sun.jvm.hotspot.runtime.win32_ia64 \
|
||||
sun.jvm.hotspot.runtime.win32_x86 \
|
||||
sun.jvm.hotspot.runtime.x86 \
|
||||
sun.jvm.hotspot.tools \
|
||||
@ -152,7 +146,6 @@ sun/jvm/hotspot/debugger/cdbg/basic/*.java \
|
||||
sun/jvm/hotspot/debugger/cdbg/basic/amd64/*.java \
|
||||
sun/jvm/hotspot/debugger/cdbg/basic/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/dummy/*.java \
|
||||
sun/jvm/hotspot/debugger/ia64/*.java \
|
||||
sun/jvm/hotspot/debugger/linux/*.java \
|
||||
sun/jvm/hotspot/debugger/linux/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/posix/*.java \
|
||||
@ -168,7 +161,6 @@ sun/jvm/hotspot/debugger/remote/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/sparc/*.java \
|
||||
sun/jvm/hotspot/debugger/win32/coff/*.java \
|
||||
sun/jvm/hotspot/debugger/windbg/*.java \
|
||||
sun/jvm/hotspot/debugger/windbg/ia64/*.java \
|
||||
sun/jvm/hotspot/debugger/windbg/x86/*.java \
|
||||
sun/jvm/hotspot/debugger/x86/*.java \
|
||||
sun/jvm/hotspot/gc_implementation/g1/*.java \
|
||||
@ -186,10 +178,8 @@ sun/jvm/hotspot/runtime/amd64/*.java \
|
||||
sun/jvm/hotspot/runtime/bsd/*.java \
|
||||
sun/jvm/hotspot/runtime/bsd_amd64/*.java \
|
||||
sun/jvm/hotspot/runtime/bsd_x86/*.java \
|
||||
sun/jvm/hotspot/runtime/ia64/*.java \
|
||||
sun/jvm/hotspot/runtime/linux/*.java \
|
||||
sun/jvm/hotspot/runtime/linux_amd64/*.java \
|
||||
sun/jvm/hotspot/runtime/linux_ia64/*.java \
|
||||
sun/jvm/hotspot/runtime/linux_sparc/*.java \
|
||||
sun/jvm/hotspot/runtime/linux_x86/*.java \
|
||||
sun/jvm/hotspot/runtime/posix/*.java \
|
||||
@ -198,7 +188,6 @@ sun/jvm/hotspot/runtime/solaris_sparc/*.java \
|
||||
sun/jvm/hotspot/runtime/solaris_x86/*.java \
|
||||
sun/jvm/hotspot/runtime/sparc/*.java \
|
||||
sun/jvm/hotspot/runtime/win32_amd64/*.java \
|
||||
sun/jvm/hotspot/runtime/win32_ia64/*.java \
|
||||
sun/jvm/hotspot/runtime/win32_x86/*.java \
|
||||
sun/jvm/hotspot/runtime/x86/*.java \
|
||||
sun/jvm/hotspot/tools/*.java \
|
||||
@ -258,6 +247,7 @@ SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VE
|
||||
|
||||
SA_PROPERTIES = $(OUTPUT_DIR)/sa.properties
|
||||
JAVAC = $(JDK_HOME)/bin/javac
|
||||
JAVA = $(JDK_HOME)/bin/java
|
||||
JAVADOC = $(JDK_HOME)/bin/javadoc
|
||||
RMIC = $(JDK_HOME)/bin/rmic
|
||||
|
||||
@ -298,7 +288,7 @@ filelist: $(ALLFILES)
|
||||
|
||||
.PHONY: natives
|
||||
natives:
|
||||
cd ../src/os/`java -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) all
|
||||
cd ../src/os/`$(JAVA) -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) all
|
||||
|
||||
.PHONY: sa-jdi.jar
|
||||
sa-jdi.jar:
|
||||
@ -323,5 +313,5 @@ sa.jar:
|
||||
|
||||
clean::
|
||||
rm -rf filelist
|
||||
cd ../src/os/`java -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) clean
|
||||
cd ../src/os/`$(JAVA) -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) clean
|
||||
rm -rf $(BUILD_DIR)/*
|
||||
|
@ -33,6 +33,7 @@ import sun.jvm.hotspot.types.Type;
|
||||
import sun.jvm.hotspot.types.Field;
|
||||
import sun.jvm.hotspot.HotSpotTypeDataBase;
|
||||
import sun.jvm.hotspot.types.basic.BasicType;
|
||||
import sun.jvm.hotspot.types.basic.BasicTypeDataBase;
|
||||
import sun.jvm.hotspot.types.CIntegerType;
|
||||
import sun.jvm.hotspot.code.*;
|
||||
import sun.jvm.hotspot.compiler.*;
|
||||
@ -448,6 +449,112 @@ public class CommandProcessor {
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("dumpreplaydata", "dumpreplaydata { <address > | -a | <thread_id> }", false) {
|
||||
// This is used to dump replay data from ciInstanceKlass, ciMethodData etc
|
||||
// default file name is replay.txt, also if java crashes in compiler
|
||||
// thread, this file will be dumped in error processing.
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
String name = t.nextToken();
|
||||
Address a = null;
|
||||
try {
|
||||
a = VM.getVM().getDebugger().parseAddress(name);
|
||||
} catch (NumberFormatException e) { }
|
||||
if (a != null) {
|
||||
// only nmethod, Method, MethodData and InstanceKlass needed to
|
||||
// dump replay data
|
||||
|
||||
CodeBlob cb = VM.getVM().getCodeCache().findBlob(a);
|
||||
if (cb != null && (cb instanceof NMethod)) {
|
||||
((NMethod)cb).dumpReplayData(out);
|
||||
return;
|
||||
}
|
||||
// assume it is Metadata
|
||||
Metadata meta = Metadata.instantiateWrapperFor(a);
|
||||
if (meta != null) {
|
||||
meta.dumpReplayData(out);
|
||||
} else {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Not an address
|
||||
boolean all = name.equals("-a");
|
||||
Threads threads = VM.getVM().getThreads();
|
||||
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
thread.printThreadIDOn(new PrintStream(bos));
|
||||
if (all || bos.toString().equals(name)) {
|
||||
if (thread instanceof CompilerThread) {
|
||||
CompilerThread ct = (CompilerThread)thread;
|
||||
ciEnv env = ct.env();
|
||||
if (env != null) {
|
||||
env.dumpReplayData(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("buildreplayjars", "buildreplayjars [ all | app | boot ] | [ prefix ]", false) {
|
||||
// This is used to dump jar files of all the classes
|
||||
// loaded in the core. Everything on the bootclasspath
|
||||
// will go in boot.jar and everything else will go in
|
||||
// app.jar. Then the classes can be loaded by the replay
|
||||
// jvm using -Xbootclasspath/p:boot.jar -cp app.jar. boot.jar usually
|
||||
// not needed, unless changed by jvmti.
|
||||
public void doit(Tokens t) {
|
||||
int tcount = t.countTokens();
|
||||
if (tcount > 2) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String prefix = "";
|
||||
String option = "all"; // default
|
||||
switch(tcount) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
option = t.nextToken();
|
||||
if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") &&
|
||||
!option.equalsIgnoreCase("root")) {
|
||||
prefix = option;
|
||||
option = "all";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
option = t.nextToken();
|
||||
prefix = t.nextToken();
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") &&
|
||||
!option.equalsIgnoreCase("boot")) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
ClassDump cd = new ClassDump();
|
||||
if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("boot")) {
|
||||
cd.setClassFilter(new BootFilter());
|
||||
cd.setJarOutput(prefix + "boot.jar");
|
||||
cd.run();
|
||||
}
|
||||
if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("app")) {
|
||||
cd.setClassFilter(new NonBootFilter());
|
||||
cd.setJarOutput(prefix + "app.jar");
|
||||
cd.run();
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("findpc", "findpc address", false) {
|
||||
public void doit(Tokens t) {
|
||||
if (t.countTokens() != 1) {
|
||||
|
@ -16,9 +16,9 @@
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@ -50,4 +50,8 @@ public class ciBaseObject extends VMObject {
|
||||
public ciBaseObject(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public void dumpReplayData(PrintStream out) {
|
||||
out.println("# Unknown ci type " + getAddress().getAddressAt(0));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2012, 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
|
||||
@ -16,9 +16,9 @@
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@ -60,4 +60,8 @@ public class ciConstant extends VMObject {
|
||||
public ciConstant(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public void dumpReplayData(PrintStream out) {
|
||||
// Nothing to be done
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2012, 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
|
||||
@ -16,9 +16,9 @@
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@ -74,4 +74,29 @@ public class ciEnv extends VMObject {
|
||||
public CompileTask task() {
|
||||
return new CompileTask(taskField.getValue(this.getAddress()));
|
||||
}
|
||||
|
||||
public void dumpReplayData(PrintStream out) {
|
||||
out.println("JvmtiExport can_access_local_variables " +
|
||||
(JvmtiExport.canAccessLocalVariables() ? '1' : '0'));
|
||||
out.println("JvmtiExport can_hotswap_or_post_breakpoint " +
|
||||
(JvmtiExport.canHotswapOrPostBreakpoint() ? '1' : '0'));
|
||||
out.println("JvmtiExport can_post_on_exceptions " +
|
||||
(JvmtiExport.canPostOnExceptions() ? '1' : '0'));
|
||||
|
||||
GrowableArray<ciMetadata> objects = factory().objects();
|
||||
out.println("# " + objects.length() + " ciObject found");
|
||||
for (int i = 0; i < objects.length(); i++) {
|
||||
ciMetadata o = objects.at(i);
|
||||
out.println("# ciMetadata" + i + " @ " + o);
|
||||
o.dumpReplayData(out);
|
||||
}
|
||||
CompileTask task = task();
|
||||
Method method = task.method();
|
||||
int entryBci = task.osrBci();
|
||||
Klass holder = method.getMethodHolder();
|
||||
out.println("compile " + holder.getName().asString() + " " +
|
||||
OopUtilities.escapeString(method.getName().asString()) + " " +
|
||||
method.getSignature().asString() + " " +
|
||||
entryBci);
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,9 @@
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@ -80,4 +80,84 @@ public class ciInstanceKlass extends ciKlass {
|
||||
public boolean isInitialized() {
|
||||
return initState() == CLASS_STATE_FULLY_INITIALIZED;
|
||||
}
|
||||
|
||||
public void dumpReplayData(PrintStream out) {
|
||||
InstanceKlass ik = (InstanceKlass)getMetadata();
|
||||
ConstantPool cp = ik.getConstants();
|
||||
|
||||
// Try to record related loaded classes
|
||||
Klass sub = ik.getSubklassKlass();
|
||||
while (sub != null) {
|
||||
if (sub instanceof InstanceKlass) {
|
||||
out.println("instanceKlass " + sub.getName().asString());
|
||||
}
|
||||
sub = sub.getNextSiblingKlass();
|
||||
}
|
||||
|
||||
final int length = (int) cp.getLength();
|
||||
out.print("ciInstanceKlass " + name() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
|
||||
for (int index = 1; index < length; index++) {
|
||||
out.print(" " + cp.getTags().at(index));
|
||||
}
|
||||
out.println();
|
||||
if (isInitialized()) {
|
||||
Field[] staticFields = ik.getStaticFields();
|
||||
for (int i = 0; i < staticFields.length; i++) {
|
||||
Field f = staticFields[i];
|
||||
Oop mirror = ik.getJavaMirror();
|
||||
if (f.isFinal() && !f.hasInitialValue()) {
|
||||
out.print("staticfield " + name() + " " +
|
||||
OopUtilities.escapeString(f.getID().getName()) + " " +
|
||||
f.getFieldType().getSignature().asString() + " ");
|
||||
if (f instanceof ByteField) {
|
||||
ByteField bf = (ByteField)f;
|
||||
out.println(bf.getValue(mirror));
|
||||
} else if (f instanceof BooleanField) {
|
||||
BooleanField bf = (BooleanField)f;
|
||||
out.println(bf.getValue(mirror) ? 1 : 0);
|
||||
} else if (f instanceof ShortField) {
|
||||
ShortField bf = (ShortField)f;
|
||||
out.println(bf.getValue(mirror));
|
||||
} else if (f instanceof CharField) {
|
||||
CharField bf = (CharField)f;
|
||||
out.println(bf.getValue(mirror) & 0xffff);
|
||||
} else if (f instanceof IntField) {
|
||||
IntField bf = (IntField)f;
|
||||
out.println(bf.getValue(mirror));
|
||||
} else if (f instanceof LongField) {
|
||||
LongField bf = (LongField)f;
|
||||
out.println(bf.getValue(mirror));
|
||||
} else if (f instanceof FloatField) {
|
||||
FloatField bf = (FloatField)f;
|
||||
out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
|
||||
} else if (f instanceof DoubleField) {
|
||||
DoubleField bf = (DoubleField)f;
|
||||
out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
|
||||
} else if (f instanceof OopField) {
|
||||
OopField bf = (OopField)f;
|
||||
Oop value = bf.getValue(mirror);
|
||||
if (value == null) {
|
||||
out.println("null");
|
||||
} else if (value.isInstance()) {
|
||||
Instance inst = (Instance)value;
|
||||
if (inst.isA(SystemDictionary.getStringKlass())) {
|
||||
out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
|
||||
} else {
|
||||
out.println(inst.getKlass().getName().asString());
|
||||
}
|
||||
} else if (value.isObjArray()) {
|
||||
ObjArray oa = (ObjArray)value;
|
||||
Klass ek = (ObjArrayKlass)oa.getKlass();
|
||||
out.println(oa.getLength() + " " + ek.getName().asString());
|
||||
} else if (value.isTypeArray()) {
|
||||
TypeArray ta = (TypeArray)value;
|
||||
out.println(ta.getLength());
|
||||
} else {
|
||||
out.println(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,9 @@
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@ -88,4 +88,19 @@ public class ciMethod extends ciMetadata {
|
||||
st.printf(" %s::%s", method.getMethodHolder().getName().asString().replace('/', '.'),
|
||||
method.getName().asString());
|
||||
}
|
||||
|
||||
public void dumpReplayData(PrintStream out) {
|
||||
Method method = (Method)getMetadata();
|
||||
NMethod nm = method.getNativeMethod();
|
||||
Klass holder = method.getMethodHolder();
|
||||
out.println("ciMethod " +
|
||||
holder.getName().asString() + " " +
|
||||
OopUtilities.escapeString(method.getName().asString()) + " " +
|
||||
method.getSignature().asString() + " " +
|
||||
method.getInvocationCounter() + " " +
|
||||
method.getBackedgeCounter() + " " +
|
||||
interpreterInvocationCount() + " " +
|
||||
interpreterThrowoutCount() + " " +
|
||||
instructionsSize());
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,9 @@
|
||||
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@ -174,4 +174,52 @@ public class ciMethodData extends ciMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
public void dumpReplayData(PrintStream out) {
|
||||
MethodData mdo = (MethodData)getMetadata();
|
||||
Method method = mdo.getMethod();
|
||||
Klass holder = method.getMethodHolder();
|
||||
out.print("ciMethodData " +
|
||||
holder.getName().asString() + " " +
|
||||
OopUtilities.escapeString(method.getName().asString()) + " " +
|
||||
method.getSignature().asString() + " " +
|
||||
state() + " " + currentMileage());
|
||||
byte[] orig = orig();
|
||||
out.print(" orig " + orig.length);
|
||||
for (int i = 0; i < orig.length; i++) {
|
||||
out.print(" " + (orig[i] & 0xff));
|
||||
}
|
||||
|
||||
long[] data = data();
|
||||
out.print(" data " + data.length);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
out.print(" 0x" + Long.toHexString(data[i]));
|
||||
}
|
||||
int count = 0;
|
||||
for (int round = 0; round < 2; round++) {
|
||||
if (round == 1) out.print(" oops " + count);
|
||||
ProfileData pdata = firstData();
|
||||
for ( ; isValid(pdata); pdata = nextData(pdata)) {
|
||||
if (pdata instanceof ciReceiverTypeData) {
|
||||
ciReceiverTypeData vdata = (ciReceiverTypeData)pdata;
|
||||
for (int i = 0; i < vdata.rowLimit(); i++) {
|
||||
ciKlass k = vdata.receiverAt(i);
|
||||
if (k != null) {
|
||||
if (round == 0) count++;
|
||||
else out.print(" " + ((vdata.dp() + vdata.cellOffset(vdata.receiverCellIndex(i))) / MethodData.cellSize) + " " + k.name());
|
||||
}
|
||||
}
|
||||
} else if (pdata instanceof ciVirtualCallData) {
|
||||
ciVirtualCallData vdata = (ciVirtualCallData)pdata;
|
||||
for (int i = 0; i < vdata.rowLimit(); i++) {
|
||||
ciKlass k = vdata.receiverAt(i);
|
||||
if (k != null) {
|
||||
if (round == 0) count++;
|
||||
else out.print(" " + ((vdata.dp() + vdata.cellOffset(vdata.receiverCellIndex(i))) / MethodData.cellSize + " " + k.name()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
@ -498,6 +498,42 @@ public class NMethod extends CodeBlob {
|
||||
method.getSignature().asString();
|
||||
}
|
||||
|
||||
public void dumpReplayData(PrintStream out) {
|
||||
HashMap h = new HashMap();
|
||||
for (int i = 1; i < getMetadataLength(); i++) {
|
||||
Metadata meta = Metadata.instantiateWrapperFor(getMetadataAt(i));
|
||||
System.err.println(meta);
|
||||
if (h.get(meta) != null) continue;
|
||||
h.put(meta, meta);
|
||||
if (meta instanceof InstanceKlass) {
|
||||
((InstanceKlass)meta).dumpReplayData(out);
|
||||
} else if (meta instanceof Method) {
|
||||
((Method)meta).dumpReplayData(out);
|
||||
MethodData mdo = ((Method)meta).getMethodData();
|
||||
if (mdo != null) {
|
||||
mdo.dumpReplayData(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Method method = getMethod();
|
||||
if (h.get(method) == null) {
|
||||
method.dumpReplayData(out);
|
||||
MethodData mdo = method.getMethodData();
|
||||
if (mdo != null) {
|
||||
mdo.dumpReplayData(out);
|
||||
}
|
||||
}
|
||||
if (h.get(method.getMethodHolder()) == null) {
|
||||
((InstanceKlass)method.getMethodHolder()).dumpReplayData(out);
|
||||
}
|
||||
Klass holder = method.getMethodHolder();
|
||||
out.println("compile " + holder.getName().asString() + " " +
|
||||
OopUtilities.escapeString(method.getName().asString()) + " " +
|
||||
method.getSignature().asString() + " " +
|
||||
getEntryBCI());
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Internals only below this point
|
||||
//
|
||||
|
@ -56,7 +56,7 @@ public class CompileTask extends VMObject {
|
||||
}
|
||||
|
||||
public Method method() {
|
||||
Address oh = methodField.getValue(getAddress()).getAddressAt(0);
|
||||
Address oh = methodField.getValue(getAddress());
|
||||
return (Method)Metadata.instantiateWrapperFor(oh);
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ public class ConstantPoolCache extends Metadata {
|
||||
|
||||
|
||||
public void printValueOn(PrintStream tty) {
|
||||
tty.print("ConstantPoolCache for " + getConstants().getPoolHolder().getName().asString());
|
||||
tty.print("ConstantPoolCache for " + getConstants().getPoolHolder().getName().asString() + " address = " + getAddress() + " offset = " + baseOffset);
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
|
@ -110,6 +110,8 @@ public class Field {
|
||||
public Symbol getSignature() { return signature; }
|
||||
public Symbol getGenericSignature() { return genericSignature; }
|
||||
|
||||
public boolean hasInitialValue() { return holder.getFieldInitialValueIndex(fieldIndex) != 0; }
|
||||
|
||||
//
|
||||
// Following acccessors are for named, non-VM fields only
|
||||
//
|
||||
|
@ -278,7 +278,7 @@ public class InstanceKlass extends Klass {
|
||||
}
|
||||
|
||||
public short getFieldGenericSignatureIndex(int index) {
|
||||
int len = getFields().length();
|
||||
// int len = getFields().length();
|
||||
int allFieldsCount = getAllFieldsCount();
|
||||
int generic_signature_slot = allFieldsCount * FIELD_SLOTS;
|
||||
for (int i = 0; i < allFieldsCount; i++) {
|
||||
@ -325,7 +325,7 @@ public class InstanceKlass extends Klass {
|
||||
public KlassArray getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); }
|
||||
public int getJavaFieldsCount() { return (int) javaFieldsCount.getValue(this); }
|
||||
public int getAllFieldsCount() {
|
||||
int len = getFields().length();
|
||||
int len = getFields().length();
|
||||
int allFieldsCount = 0;
|
||||
for (; allFieldsCount*FIELD_SLOTS < len; allFieldsCount++) {
|
||||
short flags = getFieldAccessFlags(allFieldsCount);
|
||||
@ -581,6 +581,19 @@ public class InstanceKlass extends Klass {
|
||||
}
|
||||
}
|
||||
|
||||
public Field[] getStaticFields() {
|
||||
U2Array fields = getFields();
|
||||
int length = getJavaFieldsCount();
|
||||
ArrayList result = new ArrayList();
|
||||
for (int index = 0; index < length; index++) {
|
||||
Field f = newField(index);
|
||||
if (f.isStatic()) {
|
||||
result.add(f);
|
||||
}
|
||||
}
|
||||
return (Field[])result.toArray(new Field[result.size()]);
|
||||
}
|
||||
|
||||
public void iterateNonStaticFields(OopVisitor visitor, Oop obj) {
|
||||
if (getSuper() != null) {
|
||||
((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj);
|
||||
@ -979,4 +992,84 @@ public class InstanceKlass extends Klass {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void dumpReplayData(PrintStream out) {
|
||||
ConstantPool cp = getConstants();
|
||||
|
||||
// Try to record related loaded classes
|
||||
Klass sub = getSubklassKlass();
|
||||
while (sub != null) {
|
||||
if (sub instanceof InstanceKlass) {
|
||||
out.println("instanceKlass " + sub.getName().asString());
|
||||
}
|
||||
sub = sub.getNextSiblingKlass();
|
||||
}
|
||||
|
||||
final int length = (int) cp.getLength();
|
||||
out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
|
||||
for (int index = 1; index < length; index++) {
|
||||
out.print(" " + cp.getTags().at(index));
|
||||
}
|
||||
out.println();
|
||||
if (isInitialized()) {
|
||||
Field[] staticFields = getStaticFields();
|
||||
for (int i = 0; i < staticFields.length; i++) {
|
||||
Field f = staticFields[i];
|
||||
Oop mirror = getJavaMirror();
|
||||
if (f.isFinal() && !f.hasInitialValue()) {
|
||||
out.print("staticfield " + getName().asString() + " " +
|
||||
OopUtilities.escapeString(f.getID().getName()) + " " +
|
||||
f.getFieldType().getSignature().asString() + " ");
|
||||
if (f instanceof ByteField) {
|
||||
ByteField bf = (ByteField)f;
|
||||
out.println(bf.getValue(mirror));
|
||||
} else if (f instanceof BooleanField) {
|
||||
BooleanField bf = (BooleanField)f;
|
||||
out.println(bf.getValue(mirror) ? 1 : 0);
|
||||
} else if (f instanceof ShortField) {
|
||||
ShortField bf = (ShortField)f;
|
||||
out.println(bf.getValue(mirror));
|
||||
} else if (f instanceof CharField) {
|
||||
CharField bf = (CharField)f;
|
||||
out.println(bf.getValue(mirror) & 0xffff);
|
||||
} else if (f instanceof IntField) {
|
||||
IntField bf = (IntField)f;
|
||||
out.println(bf.getValue(mirror));
|
||||
} else if (f instanceof LongField) {
|
||||
LongField bf = (LongField)f;
|
||||
out.println(bf.getValue(mirror));
|
||||
} else if (f instanceof FloatField) {
|
||||
FloatField bf = (FloatField)f;
|
||||
out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
|
||||
} else if (f instanceof DoubleField) {
|
||||
DoubleField bf = (DoubleField)f;
|
||||
out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
|
||||
} else if (f instanceof OopField) {
|
||||
OopField bf = (OopField)f;
|
||||
|
||||
Oop value = bf.getValue(mirror);
|
||||
if (value == null) {
|
||||
out.println("null");
|
||||
} else if (value.isInstance()) {
|
||||
Instance inst = (Instance)value;
|
||||
if (inst.isA(SystemDictionary.getStringKlass())) {
|
||||
out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
|
||||
} else {
|
||||
out.println(inst.getKlass().getName().asString());
|
||||
}
|
||||
} else if (value.isObjArray()) {
|
||||
ObjArray oa = (ObjArray)value;
|
||||
Klass ek = (ObjArrayKlass)oa.getKlass();
|
||||
out.println(oa.getLength() + " " + ek.getName().asString());
|
||||
} else if (value.isTypeArray()) {
|
||||
TypeArray ta = (TypeArray)value;
|
||||
out.println(ta.getLength());
|
||||
} else {
|
||||
out.println(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,4 +79,7 @@ abstract public class Metadata extends VMObject {
|
||||
}
|
||||
|
||||
abstract public void printValueOn(PrintStream tty);
|
||||
public void dumpReplayData(PrintStream out) {
|
||||
out.println("# Unknown Metadata");
|
||||
}
|
||||
}
|
||||
|
@ -358,6 +358,25 @@ public class Method extends Metadata {
|
||||
buf.append(")");
|
||||
return buf.toString().replace('/', '.');
|
||||
}
|
||||
|
||||
public void dumpReplayData(PrintStream out) {
|
||||
NMethod nm = getNativeMethod();
|
||||
int code_size = 0;
|
||||
if (nm != null) {
|
||||
code_size = (int)nm.codeEnd().minus(nm.getVerifiedEntryPoint());
|
||||
}
|
||||
Klass holder = getMethodHolder();
|
||||
out.println("ciMethod " +
|
||||
holder.getName().asString() + " " +
|
||||
OopUtilities.escapeString(getName().asString()) + " " +
|
||||
getSignature().asString() + " " +
|
||||
getInvocationCounter() + " " +
|
||||
getBackedgeCounter() + " " +
|
||||
interpreterInvocationCount() + " " +
|
||||
interpreterThrowoutCount() + " " +
|
||||
code_size);
|
||||
}
|
||||
|
||||
public int interpreterThrowoutCount() {
|
||||
return (int) interpreterThrowoutCountField.getValue(this);
|
||||
}
|
||||
|
@ -332,4 +332,59 @@ public class MethodData extends Metadata {
|
||||
public int currentMileage() {
|
||||
return 20000;
|
||||
}
|
||||
|
||||
public void dumpReplayData(PrintStream out) {
|
||||
Method method = getMethod();
|
||||
Klass holder = method.getMethodHolder();
|
||||
out.print("ciMethodData " +
|
||||
holder.getName().asString() + " " +
|
||||
OopUtilities.escapeString(method.getName().asString()) + " " +
|
||||
method.getSignature().asString() + " " +
|
||||
"2" + " " +
|
||||
currentMileage());
|
||||
byte[] orig = orig();
|
||||
out.print(" orig " + orig.length);
|
||||
for (int i = 0; i < orig.length; i++) {
|
||||
out.print(" " + (orig[i] & 0xff));
|
||||
}
|
||||
|
||||
long[] data = data();
|
||||
out.print(" data " + data.length);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
out.print(" 0x" + Long.toHexString(data[i]));
|
||||
}
|
||||
int count = 0;
|
||||
for (int round = 0; round < 2; round++) {
|
||||
if (round == 1) out.print(" oops " + count);
|
||||
ProfileData pdata = firstData();
|
||||
for ( ; isValid(pdata); pdata = nextData(pdata)) {
|
||||
if (pdata instanceof ReceiverTypeData) {
|
||||
ReceiverTypeData vdata = (ReceiverTypeData)pdata;
|
||||
for (int i = 0; i < vdata.rowLimit(); i++) {
|
||||
Klass k = vdata.receiver(i);
|
||||
if (k != null) {
|
||||
if (round == 0) count++;
|
||||
else out.print(" " +
|
||||
(dpToDi(vdata.dp() +
|
||||
vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " +
|
||||
k.getName().asString());
|
||||
}
|
||||
}
|
||||
} else if (pdata instanceof VirtualCallData) {
|
||||
VirtualCallData vdata = (VirtualCallData)pdata;
|
||||
for (int i = 0; i < vdata.rowLimit(); i++) {
|
||||
Klass k = vdata.receiver(i);
|
||||
if (k != null) {
|
||||
if (round == 0) count++;
|
||||
else out.print(" " +
|
||||
(dpToDi(vdata.dp() +
|
||||
vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " +
|
||||
k.getName().asString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
@ -1836,7 +1836,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||
// check if we could do inlining
|
||||
if (!PatchALot && Inline && klass->is_loaded() &&
|
||||
(klass->is_initialized() || klass->is_interface() && target->holder()->is_initialized())
|
||||
&& target->will_link(klass, callee_holder, code)) {
|
||||
&& target->is_loaded()) {
|
||||
// callee is known => check if we have static binding
|
||||
assert(target->is_loaded(), "callee must be known");
|
||||
if (code == Bytecodes::_invokestatic ||
|
||||
|
@ -282,7 +282,7 @@ void BCEscapeAnalyzer::invoke(StateInfo &state, Bytecodes::Code code, ciMethod*
|
||||
ciMethod* inline_target = NULL;
|
||||
if (target->is_loaded() && klass->is_loaded()
|
||||
&& (klass->is_initialized() || klass->is_interface() && target->holder()->is_initialized())
|
||||
&& target->will_link(klass, callee_holder, code)) {
|
||||
&& target->is_loaded()) {
|
||||
if (code == Bytecodes::_invokestatic
|
||||
|| code == Bytecodes::_invokespecial
|
||||
|| code == Bytecodes::_invokevirtual && target->is_final_method()) {
|
||||
|
@ -106,6 +106,7 @@ friend class ciSymbol; \
|
||||
friend class ciArray; \
|
||||
friend class ciObjArray; \
|
||||
friend class ciMetadata; \
|
||||
friend class ciReplay; \
|
||||
friend class ciTypeArray; \
|
||||
friend class ciType; \
|
||||
friend class ciReturnAddress; \
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "ci/ciInstanceKlass.hpp"
|
||||
#include "ci/ciMethod.hpp"
|
||||
#include "ci/ciNullObject.hpp"
|
||||
#include "ci/ciReplay.hpp"
|
||||
#include "ci/ciUtilities.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
@ -772,6 +773,11 @@ ciMethod* ciEnv::get_method_by_index_impl(constantPoolHandle cpool,
|
||||
: !m->method_holder()->is_loaded())) {
|
||||
m = NULL;
|
||||
}
|
||||
#ifdef ASSERT
|
||||
if (m != NULL && ReplayCompiles && !ciReplay::is_loaded(m)) {
|
||||
m = NULL;
|
||||
}
|
||||
#endif
|
||||
if (m != NULL) {
|
||||
// We found the method.
|
||||
return get_method(m);
|
||||
@ -1144,3 +1150,43 @@ void ciEnv::record_out_of_memory_failure() {
|
||||
// If memory is low, we stop compiling methods.
|
||||
record_method_not_compilable("out of memory");
|
||||
}
|
||||
|
||||
fileStream* ciEnv::_replay_data_stream = NULL;
|
||||
|
||||
void ciEnv::dump_replay_data() {
|
||||
VM_ENTRY_MARK;
|
||||
MutexLocker ml(Compile_lock);
|
||||
if (_replay_data_stream == NULL) {
|
||||
_replay_data_stream = new (ResourceObj::C_HEAP, mtCompiler) fileStream(ReplayDataFile);
|
||||
if (_replay_data_stream == NULL) {
|
||||
fatal(err_msg("Can't open %s for replay data", ReplayDataFile));
|
||||
}
|
||||
}
|
||||
dump_replay_data(_replay_data_stream);
|
||||
}
|
||||
|
||||
|
||||
void ciEnv::dump_replay_data(outputStream* out) {
|
||||
ASSERT_IN_VM;
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
out->print_cr("JvmtiExport can_access_local_variables %d", _jvmti_can_access_local_variables);
|
||||
out->print_cr("JvmtiExport can_hotswap_or_post_breakpoint %d", _jvmti_can_hotswap_or_post_breakpoint);
|
||||
out->print_cr("JvmtiExport can_post_on_exceptions %d", _jvmti_can_post_on_exceptions);
|
||||
#endif // INCLUDE_JVMTI
|
||||
|
||||
GrowableArray<ciMetadata*>* objects = _factory->get_ci_metadata();
|
||||
out->print_cr("# %d ciObject found", objects->length());
|
||||
for (int i = 0; i < objects->length(); i++) {
|
||||
objects->at(i)->dump_replay_data(out);
|
||||
}
|
||||
Method* method = task()->method();
|
||||
int entry_bci = task()->osr_bci();
|
||||
// Klass holder = method->method_holder();
|
||||
out->print_cr("compile %s %s %s %d",
|
||||
method->klass_name()->as_quoted_ascii(),
|
||||
method->name()->as_quoted_ascii(),
|
||||
method->signature()->as_quoted_ascii(),
|
||||
entry_bci);
|
||||
out->flush();
|
||||
}
|
||||
|
@ -46,6 +46,8 @@ class ciEnv : StackObj {
|
||||
friend class CompileBroker;
|
||||
friend class Dependencies; // for get_object, during logging
|
||||
|
||||
static fileStream* _replay_data_stream;
|
||||
|
||||
private:
|
||||
Arena* _arena; // Alias for _ciEnv_arena except in init_shared_objects()
|
||||
Arena _ciEnv_arena;
|
||||
@ -448,6 +450,13 @@ public:
|
||||
|
||||
// RedefineClasses support
|
||||
void metadata_do(void f(Metadata*)) { _factory->metadata_do(f); }
|
||||
|
||||
// Dump the compilation replay data for this ciEnv to
|
||||
// ReplayDataFile, creating the file if needed.
|
||||
void dump_replay_data();
|
||||
|
||||
// Dump the compilation replay data for the ciEnv to the stream.
|
||||
void dump_replay_data(outputStream* out);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CI_CIENV_HPP
|
||||
|
@ -561,3 +561,114 @@ ciInstanceKlass* ciInstanceKlass::implementor() {
|
||||
}
|
||||
return impl;
|
||||
}
|
||||
|
||||
// Utility class for printing of the contents of the static fields for
|
||||
// use by compilation replay. It only prints out the information that
|
||||
// could be consumed by the compiler, so for primitive types it prints
|
||||
// out the actual value. For Strings it's the actual string value.
|
||||
// For array types it it's first level array size since that's the
|
||||
// only value which statically unchangeable. For all other reference
|
||||
// types it simply prints out the dynamic type.
|
||||
|
||||
class StaticFinalFieldPrinter : public FieldClosure {
|
||||
outputStream* _out;
|
||||
const char* _holder;
|
||||
public:
|
||||
StaticFinalFieldPrinter(outputStream* out, const char* holder) :
|
||||
_out(out),
|
||||
_holder(holder) {
|
||||
}
|
||||
void do_field(fieldDescriptor* fd) {
|
||||
if (fd->is_final() && !fd->has_initial_value()) {
|
||||
oop mirror = fd->field_holder()->java_mirror();
|
||||
_out->print("staticfield %s %s %s ", _holder, fd->name()->as_quoted_ascii(), fd->signature()->as_quoted_ascii());
|
||||
switch (fd->field_type()) {
|
||||
case T_BYTE: _out->print_cr("%d", mirror->byte_field(fd->offset())); break;
|
||||
case T_BOOLEAN: _out->print_cr("%d", mirror->bool_field(fd->offset())); break;
|
||||
case T_SHORT: _out->print_cr("%d", mirror->short_field(fd->offset())); break;
|
||||
case T_CHAR: _out->print_cr("%d", mirror->char_field(fd->offset())); break;
|
||||
case T_INT: _out->print_cr("%d", mirror->int_field(fd->offset())); break;
|
||||
case T_LONG: _out->print_cr(INT64_FORMAT, mirror->long_field(fd->offset())); break;
|
||||
case T_FLOAT: {
|
||||
float f = mirror->float_field(fd->offset());
|
||||
_out->print_cr("%d", *(int*)&f);
|
||||
break;
|
||||
}
|
||||
case T_DOUBLE: {
|
||||
double d = mirror->double_field(fd->offset());
|
||||
_out->print_cr(INT64_FORMAT, *(jlong*)&d);
|
||||
break;
|
||||
}
|
||||
case T_ARRAY: {
|
||||
oop value = mirror->obj_field_acquire(fd->offset());
|
||||
if (value == NULL) {
|
||||
_out->print_cr("null");
|
||||
} else {
|
||||
typeArrayOop ta = (typeArrayOop)value;
|
||||
_out->print("%d", ta->length());
|
||||
if (value->is_objArray()) {
|
||||
objArrayOop oa = (objArrayOop)value;
|
||||
const char* klass_name = value->klass()->name()->as_quoted_ascii();
|
||||
_out->print(" %s", klass_name);
|
||||
}
|
||||
_out->cr();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case T_OBJECT: {
|
||||
oop value = mirror->obj_field_acquire(fd->offset());
|
||||
if (value == NULL) {
|
||||
_out->print_cr("null");
|
||||
} else if (value->is_instance()) {
|
||||
if (value->is_a(SystemDictionary::String_klass())) {
|
||||
_out->print("\"");
|
||||
_out->print_raw(java_lang_String::as_quoted_ascii(value));
|
||||
_out->print_cr("\"");
|
||||
} else {
|
||||
const char* klass_name = value->klass()->name()->as_quoted_ascii();
|
||||
_out->print_cr(klass_name);
|
||||
}
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void ciInstanceKlass::dump_replay_data(outputStream* out) {
|
||||
ASSERT_IN_VM;
|
||||
InstanceKlass* ik = get_instanceKlass();
|
||||
ConstantPool* cp = ik->constants();
|
||||
|
||||
// Try to record related loaded classes
|
||||
Klass* sub = ik->subklass();
|
||||
while (sub != NULL) {
|
||||
if (sub->oop_is_instance()) {
|
||||
out->print_cr("instanceKlass %s", sub->name()->as_quoted_ascii());
|
||||
}
|
||||
sub = sub->next_sibling();
|
||||
}
|
||||
|
||||
// Dump out the state of the constant pool tags. During replay the
|
||||
// tags will be validated for things which shouldn't change and
|
||||
// classes will be resolved if the tags indicate that they were
|
||||
// resolved at compile time.
|
||||
out->print("ciInstanceKlass %s %d %d %d", ik->name()->as_quoted_ascii(),
|
||||
is_linked(), is_initialized(), cp->length());
|
||||
for (int index = 1; index < cp->length(); index++) {
|
||||
out->print(" %d", cp->tags()->at(index));
|
||||
}
|
||||
out->cr();
|
||||
if (is_initialized()) {
|
||||
// Dump out the static final fields in case the compilation relies
|
||||
// on their value for correct replay.
|
||||
StaticFinalFieldPrinter sffp(out, ik->name()->as_quoted_ascii());
|
||||
ik->do_local_static_fields(&sffp);
|
||||
}
|
||||
}
|
||||
|
@ -230,6 +230,9 @@ public:
|
||||
// What kind of ciObject is this?
|
||||
bool is_instance_klass() const { return true; }
|
||||
bool is_java_klass() const { return true; }
|
||||
|
||||
// Dump the current state of this klass for compilation replay.
|
||||
virtual void dump_replay_data(outputStream* out);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CI_CIINSTANCEKLASS_HPP
|
||||
|
@ -61,6 +61,7 @@ class ciMetadata: public ciBaseObject {
|
||||
virtual bool is_array_klass() const { return false; }
|
||||
virtual bool is_obj_array_klass() const { return false; }
|
||||
virtual bool is_type_array_klass() const { return false; }
|
||||
virtual void dump_replay_data(outputStream* st) { /* do nothing */ }
|
||||
|
||||
ciMethod* as_method() {
|
||||
assert(is_method(), "bad cast");
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "ci/ciMethodData.hpp"
|
||||
#include "ci/ciStreams.hpp"
|
||||
#include "ci/ciSymbol.hpp"
|
||||
#include "ci/ciReplay.hpp"
|
||||
#include "ci/ciUtilities.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "compiler/abstractCompiler.hpp"
|
||||
@ -139,6 +140,12 @@ ciMethod::ciMethod(methodHandle h_m) : ciMetadata(h_m()) {
|
||||
}
|
||||
if (_interpreter_invocation_count == 0)
|
||||
_interpreter_invocation_count = 1;
|
||||
_instructions_size = -1;
|
||||
#ifdef ASSERT
|
||||
if (ReplayCompiles) {
|
||||
ciReplay::initialize(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -161,7 +168,8 @@ ciMethod::ciMethod(ciInstanceKlass* holder,
|
||||
#if defined(COMPILER2) || defined(SHARK)
|
||||
,
|
||||
_flow( NULL),
|
||||
_bcea( NULL)
|
||||
_bcea( NULL),
|
||||
_instructions_size(-1)
|
||||
#endif // COMPILER2 || SHARK
|
||||
{
|
||||
// Usually holder and accessor are the same type but in some cases
|
||||
@ -867,25 +875,6 @@ ciMethodData* ciMethod::method_data_or_null() {
|
||||
return md;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethod::will_link
|
||||
//
|
||||
// Will this method link in a specific calling context?
|
||||
bool ciMethod::will_link(ciKlass* accessing_klass,
|
||||
ciKlass* declared_method_holder,
|
||||
Bytecodes::Code bc) {
|
||||
if (!is_loaded()) {
|
||||
// Method lookup failed.
|
||||
return false;
|
||||
}
|
||||
|
||||
// The link checks have been front-loaded into the get_method
|
||||
// call. This method (ciMethod::will_link()) will be removed
|
||||
// in the future.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethod::should_exclude
|
||||
//
|
||||
@ -1000,8 +989,7 @@ bool ciMethod::can_be_osr_compiled(int entry_bci) {
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethod::has_compiled_code
|
||||
bool ciMethod::has_compiled_code() {
|
||||
VM_ENTRY_MARK;
|
||||
return get_Method()->code() != NULL;
|
||||
return instructions_size() > 0;
|
||||
}
|
||||
|
||||
int ciMethod::comp_level() {
|
||||
@ -1039,14 +1027,18 @@ int ciMethod::code_size_for_inlining() {
|
||||
// junk like exception handler, stubs, and constant table, which are
|
||||
// not highly relevant to an inlined method. So we use the more
|
||||
// specific accessor nmethod::insts_size.
|
||||
int ciMethod::instructions_size(int comp_level) {
|
||||
GUARDED_VM_ENTRY(
|
||||
nmethod* code = get_Method()->code();
|
||||
if (code != NULL && (comp_level == CompLevel_any || comp_level == code->comp_level())) {
|
||||
return code->insts_end() - code->verified_entry_point();
|
||||
}
|
||||
return 0;
|
||||
)
|
||||
int ciMethod::instructions_size() {
|
||||
if (_instructions_size == -1) {
|
||||
GUARDED_VM_ENTRY(
|
||||
nmethod* code = get_Method()->code();
|
||||
if (code != NULL && (code->comp_level() == CompLevel_full_optimization)) {
|
||||
_instructions_size = code->insts_end() - code->verified_entry_point();
|
||||
} else {
|
||||
_instructions_size = 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
return _instructions_size;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@ -1166,6 +1158,20 @@ ciMethodBlocks *ciMethod::get_method_blocks() {
|
||||
|
||||
#undef FETCH_FLAG_FROM_VM
|
||||
|
||||
void ciMethod::dump_replay_data(outputStream* st) {
|
||||
ASSERT_IN_VM;
|
||||
Method* method = get_Method();
|
||||
Klass* holder = method->method_holder();
|
||||
st->print_cr("ciMethod %s %s %s %d %d %d %d %d",
|
||||
holder->name()->as_quoted_ascii(),
|
||||
method->name()->as_quoted_ascii(),
|
||||
method->signature()->as_quoted_ascii(),
|
||||
method->invocation_counter()->raw_counter(),
|
||||
method->backedge_counter()->raw_counter(),
|
||||
interpreter_invocation_count(),
|
||||
interpreter_throwout_count(),
|
||||
_instructions_size);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethod::print_codes
|
||||
|
@ -51,6 +51,7 @@ class ciMethod : public ciMetadata {
|
||||
friend class ciExceptionHandlerStream;
|
||||
friend class ciBytecodeStream;
|
||||
friend class ciMethodHandle;
|
||||
friend class ciReplay;
|
||||
|
||||
private:
|
||||
// General method information.
|
||||
@ -69,6 +70,7 @@ class ciMethod : public ciMetadata {
|
||||
int _handler_count;
|
||||
int _interpreter_invocation_count;
|
||||
int _interpreter_throwout_count;
|
||||
int _instructions_size;
|
||||
|
||||
bool _uses_monitors;
|
||||
bool _balanced_monitors;
|
||||
@ -239,9 +241,6 @@ class ciMethod : public ciMetadata {
|
||||
int resolve_vtable_index(ciKlass* caller, ciKlass* receiver);
|
||||
|
||||
// Compilation directives
|
||||
bool will_link(ciKlass* accessing_klass,
|
||||
ciKlass* declared_method_holder,
|
||||
Bytecodes::Code bc);
|
||||
bool should_exclude();
|
||||
bool should_inline();
|
||||
bool should_not_inline();
|
||||
@ -252,7 +251,6 @@ class ciMethod : public ciMetadata {
|
||||
bool can_be_osr_compiled(int entry_bci);
|
||||
void set_not_compilable();
|
||||
bool has_compiled_code();
|
||||
int instructions_size(int comp_level = CompLevel_any);
|
||||
void log_nmethod_identity(xmlStream* log);
|
||||
bool is_not_reached(int bci);
|
||||
bool was_executed_more_than(int times);
|
||||
@ -260,6 +258,7 @@ class ciMethod : public ciMetadata {
|
||||
bool is_klass_loaded(int refinfo_index, bool must_be_resolved) const;
|
||||
bool check_call(int refinfo_index, bool is_static) const;
|
||||
bool ensure_method_data(); // make sure it exists in the VM also
|
||||
int instructions_size();
|
||||
int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC
|
||||
|
||||
// JSR 292 support
|
||||
@ -291,6 +290,7 @@ class ciMethod : public ciMetadata {
|
||||
bool is_accessor () const;
|
||||
bool is_initializer () const;
|
||||
bool can_be_statically_bound() const { return _can_be_statically_bound; }
|
||||
void dump_replay_data(outputStream* st);
|
||||
|
||||
// Print the bytecodes of this method.
|
||||
void print_codes_on(outputStream* st);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "ci/ciMetadata.hpp"
|
||||
#include "ci/ciMethodData.hpp"
|
||||
#include "ci/ciReplay.hpp"
|
||||
#include "ci/ciUtilities.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
@ -115,6 +116,11 @@ void ciMethodData::load_data() {
|
||||
_arg_local = mdo->arg_local();
|
||||
_arg_stack = mdo->arg_stack();
|
||||
_arg_returned = mdo->arg_returned();
|
||||
#ifndef PRODUCT
|
||||
if (ReplayCompiles) {
|
||||
ciReplay::initialize(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ciReceiverTypeData::translate_receiver_data_from(ProfileData* data) {
|
||||
@ -366,6 +372,79 @@ void ciMethodData::print_impl(outputStream* st) {
|
||||
ciMetadata::print_impl(st);
|
||||
}
|
||||
|
||||
void ciMethodData::dump_replay_data(outputStream* out) {
|
||||
ASSERT_IN_VM;
|
||||
MethodData* mdo = get_MethodData();
|
||||
Method* method = mdo->method();
|
||||
Klass* holder = method->method_holder();
|
||||
out->print("ciMethodData %s %s %s %d %d",
|
||||
holder->name()->as_quoted_ascii(),
|
||||
method->name()->as_quoted_ascii(),
|
||||
method->signature()->as_quoted_ascii(),
|
||||
_state,
|
||||
current_mileage());
|
||||
|
||||
// dump the contents of the MDO header as raw data
|
||||
unsigned char* orig = (unsigned char*)&_orig;
|
||||
int length = sizeof(_orig);
|
||||
out->print(" orig %d", length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
out->print(" %d", orig[i]);
|
||||
}
|
||||
|
||||
// dump the MDO data as raw data
|
||||
int elements = data_size() / sizeof(intptr_t);
|
||||
out->print(" data %d", elements);
|
||||
for (int i = 0; i < elements; i++) {
|
||||
// We could use INTPTR_FORMAT here but that's a zero justified
|
||||
// which makes comparing it with the SA version of this output
|
||||
// harder.
|
||||
#ifdef _LP64
|
||||
out->print(" 0x%" FORMAT64_MODIFIER "x", data()[i]);
|
||||
#else
|
||||
out->print(" 0x%x", data()[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
// The MDO contained oop references as ciObjects, so scan for those
|
||||
// and emit pairs of offset and klass name so that they can be
|
||||
// reconstructed at runtime. The first round counts the number of
|
||||
// oop references and the second actually emits them.
|
||||
int count = 0;
|
||||
for (int round = 0; round < 2; round++) {
|
||||
if (round == 1) out->print(" oops %d", count);
|
||||
ProfileData* pdata = first_data();
|
||||
for ( ; is_valid(pdata); pdata = next_data(pdata)) {
|
||||
if (pdata->is_ReceiverTypeData()) {
|
||||
ciReceiverTypeData* vdata = (ciReceiverTypeData*)pdata;
|
||||
for (uint i = 0; i < vdata->row_limit(); i++) {
|
||||
ciKlass* k = vdata->receiver(i);
|
||||
if (k != NULL) {
|
||||
if (round == 0) {
|
||||
count++;
|
||||
} else {
|
||||
out->print(" %d %s", dp_to_di(vdata->dp() + in_bytes(vdata->receiver_offset(i))) / sizeof(intptr_t), k->name()->as_quoted_ascii());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (pdata->is_VirtualCallData()) {
|
||||
ciVirtualCallData* vdata = (ciVirtualCallData*)pdata;
|
||||
for (uint i = 0; i < vdata->row_limit(); i++) {
|
||||
ciKlass* k = vdata->receiver(i);
|
||||
if (k != NULL) {
|
||||
if (round == 0) {
|
||||
count++;
|
||||
} else {
|
||||
out->print(" %d %s", dp_to_di(vdata->dp() + in_bytes(vdata->receiver_offset(i))) / sizeof(intptr_t), k->name()->as_quoted_ascii());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out->cr();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void ciMethodData::print() {
|
||||
print_data_on(tty);
|
||||
|
@ -144,6 +144,7 @@ public:
|
||||
|
||||
class ciMethodData : public ciMetadata {
|
||||
CI_PACKAGE_ACCESS
|
||||
friend class ciReplay;
|
||||
|
||||
private:
|
||||
// Size in bytes
|
||||
@ -320,6 +321,7 @@ public:
|
||||
void print();
|
||||
void print_data_on(outputStream* st);
|
||||
#endif
|
||||
void dump_replay_data(outputStream* out);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CI_CIMETHODDATA_HPP
|
||||
|
@ -131,6 +131,7 @@ public:
|
||||
// Is this a type or value which has no associated class?
|
||||
// It is true of primitive types and null objects.
|
||||
virtual bool is_classless() const { return false; }
|
||||
virtual void dump_replay_data(outputStream* st) { /* do nothing */ }
|
||||
|
||||
// Note: some ciObjects refer to oops which have yet to be created.
|
||||
// We refer to these as "unloaded". Specifically, there are
|
||||
|
@ -137,6 +137,7 @@ public:
|
||||
|
||||
ciReturnAddress* get_return_address(int bci);
|
||||
|
||||
GrowableArray<ciMetadata*>* get_ci_metadata() const { return _ci_metadata; }
|
||||
// RedefineClasses support
|
||||
void metadata_do(void f(Metadata*));
|
||||
|
||||
|
942
hotspot/src/share/vm/ci/ciReplay.cpp
Normal file
942
hotspot/src/share/vm/ci/ciReplay.cpp
Normal file
@ -0,0 +1,942 @@
|
||||
/* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "ci/ciMethodData.hpp"
|
||||
#include "ci/ciReplay.hpp"
|
||||
#include "ci/ciUtilities.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "utilities/copy.hpp"
|
||||
|
||||
#ifdef ASSERT
|
||||
|
||||
// ciReplay
|
||||
|
||||
typedef struct _ciMethodDataRecord {
|
||||
const char* klass;
|
||||
const char* method;
|
||||
const char* signature;
|
||||
int state;
|
||||
int current_mileage;
|
||||
intptr_t* data;
|
||||
int data_length;
|
||||
char* orig_data;
|
||||
int orig_data_length;
|
||||
int oops_length;
|
||||
jobject* oops_handles;
|
||||
int* oops_offsets;
|
||||
} ciMethodDataRecord;
|
||||
|
||||
typedef struct _ciMethodRecord {
|
||||
const char* klass;
|
||||
const char* method;
|
||||
const char* signature;
|
||||
int instructions_size;
|
||||
int interpreter_invocation_count;
|
||||
int interpreter_throwout_count;
|
||||
int invocation_counter;
|
||||
int backedge_counter;
|
||||
} ciMethodRecord;
|
||||
|
||||
class CompileReplay;
|
||||
static CompileReplay* replay_state;
|
||||
|
||||
class CompileReplay : public StackObj {
|
||||
private:
|
||||
FILE* stream;
|
||||
Thread* thread;
|
||||
Handle protection_domain;
|
||||
Handle loader;
|
||||
|
||||
GrowableArray<ciMethodRecord*> ci_method_records;
|
||||
GrowableArray<ciMethodDataRecord*> ci_method_data_records;
|
||||
|
||||
const char* _error_message;
|
||||
|
||||
char* bufptr;
|
||||
char* buffer;
|
||||
int buffer_length;
|
||||
int buffer_end;
|
||||
int line_no;
|
||||
|
||||
public:
|
||||
CompileReplay(const char* filename, TRAPS) {
|
||||
thread = THREAD;
|
||||
loader = Handle(thread, SystemDictionary::java_system_loader());
|
||||
stream = fopen(filename, "rt");
|
||||
if (stream == NULL) {
|
||||
fprintf(stderr, "Can't open replay file %s\n", filename);
|
||||
}
|
||||
buffer_length = 32;
|
||||
buffer = NEW_RESOURCE_ARRAY(char, buffer_length);
|
||||
_error_message = NULL;
|
||||
|
||||
test();
|
||||
}
|
||||
|
||||
~CompileReplay() {
|
||||
if (stream != NULL) fclose(stream);
|
||||
}
|
||||
|
||||
void test() {
|
||||
strcpy(buffer, "1 2 foo 4 bar 0x9 \"this is it\"");
|
||||
bufptr = buffer;
|
||||
assert(parse_int("test") == 1, "what");
|
||||
assert(parse_int("test") == 2, "what");
|
||||
assert(strcmp(parse_string(), "foo") == 0, "what");
|
||||
assert(parse_int("test") == 4, "what");
|
||||
assert(strcmp(parse_string(), "bar") == 0, "what");
|
||||
assert(parse_intptr_t("test") == 9, "what");
|
||||
assert(strcmp(parse_quoted_string(), "this is it") == 0, "what");
|
||||
}
|
||||
|
||||
bool had_error() {
|
||||
return _error_message != NULL || thread->has_pending_exception();
|
||||
}
|
||||
|
||||
bool can_replay() {
|
||||
return !(stream == NULL || had_error());
|
||||
}
|
||||
|
||||
void report_error(const char* msg) {
|
||||
_error_message = msg;
|
||||
// Restore the buffer contents for error reporting
|
||||
for (int i = 0; i < buffer_end; i++) {
|
||||
if (buffer[i] == '\0') buffer[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
int parse_int(const char* label) {
|
||||
if (had_error()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int v = 0;
|
||||
int read;
|
||||
if (sscanf(bufptr, "%i%n", &v, &read) != 1) {
|
||||
report_error(label);
|
||||
} else {
|
||||
bufptr += read;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
intptr_t parse_intptr_t(const char* label) {
|
||||
if (had_error()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
intptr_t v = 0;
|
||||
int read;
|
||||
if (sscanf(bufptr, INTPTR_FORMAT "%n", &v, &read) != 1) {
|
||||
report_error(label);
|
||||
} else {
|
||||
bufptr += read;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
void skip_ws() {
|
||||
// Skip any leading whitespace
|
||||
while (*bufptr == ' ' || *bufptr == '\t') {
|
||||
bufptr++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char* scan_and_terminate(char delim) {
|
||||
char* str = bufptr;
|
||||
while (*bufptr != delim && *bufptr != '\0') {
|
||||
bufptr++;
|
||||
}
|
||||
if (*bufptr != '\0') {
|
||||
*bufptr++ = '\0';
|
||||
}
|
||||
if (bufptr == str) {
|
||||
// nothing here
|
||||
return NULL;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
char* parse_string() {
|
||||
if (had_error()) return NULL;
|
||||
|
||||
skip_ws();
|
||||
return scan_and_terminate(' ');
|
||||
}
|
||||
|
||||
char* parse_quoted_string() {
|
||||
if (had_error()) return NULL;
|
||||
|
||||
skip_ws();
|
||||
|
||||
if (*bufptr == '"') {
|
||||
bufptr++;
|
||||
return scan_and_terminate('"');
|
||||
} else {
|
||||
return scan_and_terminate(' ');
|
||||
}
|
||||
}
|
||||
|
||||
const char* parse_escaped_string() {
|
||||
char* result = parse_quoted_string();
|
||||
if (result != NULL) {
|
||||
unescape_string(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Look for the tag 'tag' followed by an
|
||||
bool parse_tag_and_count(const char* tag, int& length) {
|
||||
const char* t = parse_string();
|
||||
if (t == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(tag, t) != 0) {
|
||||
report_error(tag);
|
||||
return false;
|
||||
}
|
||||
length = parse_int("parse_tag_and_count");
|
||||
return !had_error();
|
||||
}
|
||||
|
||||
// Parse a sequence of raw data encoded as bytes and return the
|
||||
// resulting data.
|
||||
char* parse_data(const char* tag, int& length) {
|
||||
if (!parse_tag_and_count(tag, length)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char * result = NEW_RESOURCE_ARRAY(char, length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
int val = parse_int("data");
|
||||
result[i] = val;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Parse a standard chunk of data emitted as:
|
||||
// 'tag' <length> # # ...
|
||||
// Where each # is an intptr_t item
|
||||
intptr_t* parse_intptr_data(const char* tag, int& length) {
|
||||
if (!parse_tag_and_count(tag, length)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
intptr_t* result = NEW_RESOURCE_ARRAY(intptr_t, length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
skip_ws();
|
||||
intptr_t val = parse_intptr_t("data");
|
||||
result[i] = val;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Parse a possibly quoted version of a symbol into a symbolOop
|
||||
Symbol* parse_symbol(TRAPS) {
|
||||
const char* str = parse_escaped_string();
|
||||
if (str != NULL) {
|
||||
Symbol* sym = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
|
||||
return sym;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Parse a valid klass name and look it up
|
||||
Klass* parse_klass(TRAPS) {
|
||||
const char* str = parse_escaped_string();
|
||||
Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
|
||||
if (klass_name != NULL) {
|
||||
Klass* k = SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
oop throwable = PENDING_EXCEPTION;
|
||||
java_lang_Throwable::print(throwable, tty);
|
||||
tty->cr();
|
||||
report_error(str);
|
||||
return NULL;
|
||||
}
|
||||
return k;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Lookup a klass
|
||||
Klass* resolve_klass(const char* klass, TRAPS) {
|
||||
Symbol* klass_name = SymbolTable::lookup(klass, (int)strlen(klass), CHECK_NULL);
|
||||
return SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, CHECK_NULL);
|
||||
}
|
||||
|
||||
// Parse the standard tuple of <klass> <name> <signature>
|
||||
Method* parse_method(TRAPS) {
|
||||
InstanceKlass* k = (InstanceKlass*)parse_klass(CHECK_NULL);
|
||||
Symbol* method_name = parse_symbol(CHECK_NULL);
|
||||
Symbol* method_signature = parse_symbol(CHECK_NULL);
|
||||
Method* m = k->find_method(method_name, method_signature);
|
||||
if (m == NULL) {
|
||||
report_error("can't find method");
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
// Process each line of the replay file executing each command until
|
||||
// the file ends.
|
||||
void process(TRAPS) {
|
||||
line_no = 1;
|
||||
int pos = 0;
|
||||
int c = getc(stream);
|
||||
while(c != EOF) {
|
||||
if (pos + 1 >= buffer_length) {
|
||||
int newl = buffer_length * 2;
|
||||
char* newb = NEW_RESOURCE_ARRAY(char, newl);
|
||||
memcpy(newb, buffer, pos);
|
||||
buffer = newb;
|
||||
buffer_length = newl;
|
||||
}
|
||||
if (c == '\n') {
|
||||
// null terminate it, reset the pointer and process the line
|
||||
buffer[pos] = '\0';
|
||||
buffer_end = pos++;
|
||||
bufptr = buffer;
|
||||
process_command(CHECK);
|
||||
if (had_error()) {
|
||||
tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message);
|
||||
tty->print_cr("%s", buffer);
|
||||
assert(false, "error");
|
||||
return;
|
||||
}
|
||||
pos = 0;
|
||||
buffer_end = 0;
|
||||
line_no++;
|
||||
} else if (c == '\r') {
|
||||
// skip LF
|
||||
} else {
|
||||
buffer[pos++] = c;
|
||||
}
|
||||
c = getc(stream);
|
||||
}
|
||||
}
|
||||
|
||||
void process_command(TRAPS) {
|
||||
char* cmd = parse_string();
|
||||
if (cmd == NULL) {
|
||||
return;
|
||||
}
|
||||
if (strcmp("#", cmd) == 0) {
|
||||
// ignore
|
||||
} else if (strcmp("compile", cmd) == 0) {
|
||||
process_compile(CHECK);
|
||||
} else if (strcmp("ciMethod", cmd) == 0) {
|
||||
process_ciMethod(CHECK);
|
||||
} else if (strcmp("ciMethodData", cmd) == 0) {
|
||||
process_ciMethodData(CHECK);
|
||||
} else if (strcmp("staticfield", cmd) == 0) {
|
||||
process_staticfield(CHECK);
|
||||
} else if (strcmp("ciInstanceKlass", cmd) == 0) {
|
||||
process_ciInstanceKlass(CHECK);
|
||||
} else if (strcmp("instanceKlass", cmd) == 0) {
|
||||
process_instanceKlass(CHECK);
|
||||
#if INCLUDE_JVMTI
|
||||
} else if (strcmp("JvmtiExport", cmd) == 0) {
|
||||
process_JvmtiExport(CHECK);
|
||||
#endif // INCLUDE_JVMTI
|
||||
} else {
|
||||
report_error("unknown command");
|
||||
}
|
||||
}
|
||||
|
||||
// compile <klass> <name> <signature> <entry_bci>
|
||||
void process_compile(TRAPS) {
|
||||
// methodHandle method;
|
||||
Method* method = parse_method(CHECK);
|
||||
int entry_bci = parse_int("entry_bci");
|
||||
Klass* k = method->method_holder();
|
||||
((InstanceKlass*)k)->initialize(THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
oop throwable = PENDING_EXCEPTION;
|
||||
java_lang_Throwable::print(throwable, tty);
|
||||
tty->cr();
|
||||
if (ReplayIgnoreInitErrors) {
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
((InstanceKlass*)k)->set_init_state(InstanceKlass::fully_initialized);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Make sure the existence of a prior compile doesn't stop this one
|
||||
nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, CompLevel_full_optimization, true) : method->code();
|
||||
if (nm != NULL) {
|
||||
nm->make_not_entrant();
|
||||
}
|
||||
replay_state = this;
|
||||
CompileBroker::compile_method(method, entry_bci, CompLevel_full_optimization,
|
||||
methodHandle(), 0, "replay", THREAD);
|
||||
replay_state = NULL;
|
||||
reset();
|
||||
}
|
||||
|
||||
// ciMethod <klass> <name> <signature> <invocation_counter> <backedge_counter> <interpreter_invocation_count> <interpreter_throwout_count> <instructions_size>
|
||||
//
|
||||
//
|
||||
void process_ciMethod(TRAPS) {
|
||||
Method* method = parse_method(CHECK);
|
||||
ciMethodRecord* rec = new_ciMethod(method);
|
||||
rec->invocation_counter = parse_int("invocation_counter");
|
||||
rec->backedge_counter = parse_int("backedge_counter");
|
||||
rec->interpreter_invocation_count = parse_int("interpreter_invocation_count");
|
||||
rec->interpreter_throwout_count = parse_int("interpreter_throwout_count");
|
||||
rec->instructions_size = parse_int("instructions_size");
|
||||
}
|
||||
|
||||
// ciMethodData <klass> <name> <signature> <state> <current mileage> orig <length> # # ... data <length> # # ... oops <length>
|
||||
void process_ciMethodData(TRAPS) {
|
||||
Method* method = parse_method(CHECK);
|
||||
/* jsut copied from Method, to build interpret data*/
|
||||
if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) {
|
||||
return;
|
||||
}
|
||||
// methodOopDesc::build_interpreter_method_data(method, CHECK);
|
||||
{
|
||||
// Grab a lock here to prevent multiple
|
||||
// MethodData*s from being created.
|
||||
MutexLocker ml(MethodData_lock, THREAD);
|
||||
if (method->method_data() == NULL) {
|
||||
ClassLoaderData* loader_data = method->method_holder()->class_loader_data();
|
||||
MethodData* method_data = MethodData::allocate(loader_data, method, CHECK);
|
||||
method->set_method_data(method_data);
|
||||
}
|
||||
}
|
||||
|
||||
// collect and record all the needed information for later
|
||||
ciMethodDataRecord* rec = new_ciMethodData(method);
|
||||
rec->state = parse_int("state");
|
||||
rec->current_mileage = parse_int("current_mileage");
|
||||
|
||||
rec->orig_data = parse_data("orig", rec->orig_data_length);
|
||||
if (rec->orig_data == NULL) {
|
||||
return;
|
||||
}
|
||||
rec->data = parse_intptr_data("data", rec->data_length);
|
||||
if (rec->data == NULL) {
|
||||
return;
|
||||
}
|
||||
if (!parse_tag_and_count("oops", rec->oops_length)) {
|
||||
return;
|
||||
}
|
||||
rec->oops_handles = NEW_RESOURCE_ARRAY(jobject, rec->oops_length);
|
||||
rec->oops_offsets = NEW_RESOURCE_ARRAY(int, rec->oops_length);
|
||||
for (int i = 0; i < rec->oops_length; i++) {
|
||||
int offset = parse_int("offset");
|
||||
if (had_error()) {
|
||||
return;
|
||||
}
|
||||
Klass* k = parse_klass(CHECK);
|
||||
rec->oops_offsets[i] = offset;
|
||||
rec->oops_handles[i] = (jobject)(new KlassHandle(THREAD, k));
|
||||
}
|
||||
}
|
||||
|
||||
// instanceKlass <name>
|
||||
//
|
||||
// Loads and initializes the klass 'name'. This can be used to
|
||||
// create particular class loading environments
|
||||
void process_instanceKlass(TRAPS) {
|
||||
// just load the referenced class
|
||||
Klass* k = parse_klass(CHECK);
|
||||
}
|
||||
|
||||
// ciInstanceKlass <name> <is_linked> <is_initialized> <length> tag # # # ...
|
||||
//
|
||||
// Load the klass 'name' and link or initialize it. Verify that the
|
||||
// constant pool is the same length as 'length' and make sure the
|
||||
// constant pool tags are in the same state.
|
||||
void process_ciInstanceKlass(TRAPS) {
|
||||
InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK);
|
||||
int is_linked = parse_int("is_linked");
|
||||
int is_initialized = parse_int("is_initialized");
|
||||
int length = parse_int("length");
|
||||
if (is_initialized) {
|
||||
k->initialize(THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
oop throwable = PENDING_EXCEPTION;
|
||||
java_lang_Throwable::print(throwable, tty);
|
||||
tty->cr();
|
||||
if (ReplayIgnoreInitErrors) {
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
k->set_init_state(InstanceKlass::fully_initialized);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (is_linked) {
|
||||
k->link_class(CHECK);
|
||||
}
|
||||
ConstantPool* cp = k->constants();
|
||||
if (length != cp->length()) {
|
||||
report_error("constant pool length mismatch: wrong class files?");
|
||||
return;
|
||||
}
|
||||
|
||||
int parsed_two_word = 0;
|
||||
for (int i = 1; i < length; i++) {
|
||||
int tag = parse_int("tag");
|
||||
if (had_error()) {
|
||||
return;
|
||||
}
|
||||
switch (cp->tag_at(i).value()) {
|
||||
case JVM_CONSTANT_UnresolvedClass: {
|
||||
if (tag == JVM_CONSTANT_Class) {
|
||||
tty->print_cr("Resolving klass %s at %d", cp->unresolved_klass_at(i)->as_utf8(), i);
|
||||
Klass* k = cp->klass_at(i, CHECK);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JVM_CONSTANT_Long:
|
||||
case JVM_CONSTANT_Double:
|
||||
parsed_two_word = i + 1;
|
||||
|
||||
case JVM_CONSTANT_ClassIndex:
|
||||
case JVM_CONSTANT_StringIndex:
|
||||
case JVM_CONSTANT_String:
|
||||
case JVM_CONSTANT_UnresolvedClassInError:
|
||||
case JVM_CONSTANT_Fieldref:
|
||||
case JVM_CONSTANT_Methodref:
|
||||
case JVM_CONSTANT_InterfaceMethodref:
|
||||
case JVM_CONSTANT_NameAndType:
|
||||
case JVM_CONSTANT_Utf8:
|
||||
case JVM_CONSTANT_Integer:
|
||||
case JVM_CONSTANT_Float:
|
||||
if (tag != cp->tag_at(i).value()) {
|
||||
report_error("tag mismatch: wrong class files?");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case JVM_CONSTANT_Class:
|
||||
if (tag == JVM_CONSTANT_Class) {
|
||||
} else if (tag == JVM_CONSTANT_UnresolvedClass) {
|
||||
tty->print_cr("Warning: entry was unresolved in the replay data");
|
||||
} else {
|
||||
report_error("Unexpected tag");
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0:
|
||||
if (parsed_two_word == i) continue;
|
||||
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize a class and fill in the value for a static field.
|
||||
// This is useful when the compile was dependent on the value of
|
||||
// static fields but it's impossible to properly rerun the static
|
||||
// initiailizer.
|
||||
void process_staticfield(TRAPS) {
|
||||
InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK);
|
||||
|
||||
if (ReplaySuppressInitializers == 0 ||
|
||||
ReplaySuppressInitializers == 2 && k->class_loader() == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(k->is_initialized(), "must be");
|
||||
|
||||
const char* field_name = parse_escaped_string();;
|
||||
const char* field_signature = parse_string();
|
||||
fieldDescriptor fd;
|
||||
Symbol* name = SymbolTable::lookup(field_name, (int)strlen(field_name), CHECK);
|
||||
Symbol* sig = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
|
||||
if (!k->find_local_field(name, sig, &fd) ||
|
||||
!fd.is_static() ||
|
||||
fd.has_initial_value()) {
|
||||
report_error(field_name);
|
||||
return;
|
||||
}
|
||||
|
||||
oop java_mirror = k->java_mirror();
|
||||
if (field_signature[0] == '[') {
|
||||
int length = parse_int("array length");
|
||||
oop value = NULL;
|
||||
|
||||
if (field_signature[1] == '[') {
|
||||
// multi dimensional array
|
||||
ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK);
|
||||
int rank = 0;
|
||||
while (field_signature[rank] == '[') {
|
||||
rank++;
|
||||
}
|
||||
int* dims = NEW_RESOURCE_ARRAY(int, rank);
|
||||
dims[0] = length;
|
||||
for (int i = 1; i < rank; i++) {
|
||||
dims[i] = 1; // These aren't relevant to the compiler
|
||||
}
|
||||
value = kelem->multi_allocate(rank, dims, CHECK);
|
||||
} else {
|
||||
if (strcmp(field_signature, "[B") == 0) {
|
||||
value = oopFactory::new_byteArray(length, CHECK);
|
||||
} else if (strcmp(field_signature, "[Z") == 0) {
|
||||
value = oopFactory::new_boolArray(length, CHECK);
|
||||
} else if (strcmp(field_signature, "[C") == 0) {
|
||||
value = oopFactory::new_charArray(length, CHECK);
|
||||
} else if (strcmp(field_signature, "[S") == 0) {
|
||||
value = oopFactory::new_shortArray(length, CHECK);
|
||||
} else if (strcmp(field_signature, "[F") == 0) {
|
||||
value = oopFactory::new_singleArray(length, CHECK);
|
||||
} else if (strcmp(field_signature, "[D") == 0) {
|
||||
value = oopFactory::new_doubleArray(length, CHECK);
|
||||
} else if (strcmp(field_signature, "[I") == 0) {
|
||||
value = oopFactory::new_intArray(length, CHECK);
|
||||
} else if (strcmp(field_signature, "[J") == 0) {
|
||||
value = oopFactory::new_longArray(length, CHECK);
|
||||
} else if (field_signature[0] == '[' && field_signature[1] == 'L') {
|
||||
KlassHandle kelem = resolve_klass(field_signature + 1, CHECK);
|
||||
value = oopFactory::new_objArray(kelem(), length, CHECK);
|
||||
} else {
|
||||
report_error("unhandled array staticfield");
|
||||
}
|
||||
}
|
||||
java_mirror->obj_field_put(fd.offset(), value);
|
||||
} else {
|
||||
const char* string_value = parse_escaped_string();
|
||||
if (strcmp(field_signature, "I") == 0) {
|
||||
int value = atoi(string_value);
|
||||
java_mirror->int_field_put(fd.offset(), value);
|
||||
} else if (strcmp(field_signature, "B") == 0) {
|
||||
int value = atoi(string_value);
|
||||
java_mirror->byte_field_put(fd.offset(), value);
|
||||
} else if (strcmp(field_signature, "C") == 0) {
|
||||
int value = atoi(string_value);
|
||||
java_mirror->char_field_put(fd.offset(), value);
|
||||
} else if (strcmp(field_signature, "S") == 0) {
|
||||
int value = atoi(string_value);
|
||||
java_mirror->short_field_put(fd.offset(), value);
|
||||
} else if (strcmp(field_signature, "Z") == 0) {
|
||||
int value = atol(string_value);
|
||||
java_mirror->bool_field_put(fd.offset(), value);
|
||||
} else if (strcmp(field_signature, "J") == 0) {
|
||||
jlong value;
|
||||
if (sscanf(string_value, INT64_FORMAT, &value) != 1) {
|
||||
fprintf(stderr, "Error parsing long: %s\n", string_value);
|
||||
return;
|
||||
}
|
||||
java_mirror->long_field_put(fd.offset(), value);
|
||||
} else if (strcmp(field_signature, "F") == 0) {
|
||||
float value = atof(string_value);
|
||||
java_mirror->float_field_put(fd.offset(), value);
|
||||
} else if (strcmp(field_signature, "D") == 0) {
|
||||
double value = atof(string_value);
|
||||
java_mirror->double_field_put(fd.offset(), value);
|
||||
} else if (strcmp(field_signature, "Ljava/lang/String;") == 0) {
|
||||
Handle value = java_lang_String::create_from_str(string_value, CHECK);
|
||||
java_mirror->obj_field_put(fd.offset(), value());
|
||||
} else if (field_signature[0] == 'L') {
|
||||
Symbol* klass_name = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
|
||||
KlassHandle kelem = resolve_klass(field_signature, CHECK);
|
||||
oop value = ((InstanceKlass*)kelem())->allocate_instance(CHECK);
|
||||
java_mirror->obj_field_put(fd.offset(), value);
|
||||
} else {
|
||||
report_error("unhandled staticfield");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
void process_JvmtiExport(TRAPS) {
|
||||
const char* field = parse_string();
|
||||
bool value = parse_int("JvmtiExport flag") != 0;
|
||||
if (strcmp(field, "can_access_local_variables") == 0) {
|
||||
JvmtiExport::set_can_access_local_variables(value);
|
||||
} else if (strcmp(field, "can_hotswap_or_post_breakpoint") == 0) {
|
||||
JvmtiExport::set_can_hotswap_or_post_breakpoint(value);
|
||||
} else if (strcmp(field, "can_post_on_exceptions") == 0) {
|
||||
JvmtiExport::set_can_post_on_exceptions(value);
|
||||
} else {
|
||||
report_error("Unrecognized JvmtiExport directive");
|
||||
}
|
||||
}
|
||||
#endif // INCLUDE_JVMTI
|
||||
|
||||
// Create and initialize a record for a ciMethod
|
||||
ciMethodRecord* new_ciMethod(Method* method) {
|
||||
ciMethodRecord* rec = NEW_RESOURCE_OBJ(ciMethodRecord);
|
||||
rec->klass = method->method_holder()->name()->as_utf8();
|
||||
rec->method = method->name()->as_utf8();
|
||||
rec->signature = method->signature()->as_utf8();
|
||||
ci_method_records.append(rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
// Lookup data for a ciMethod
|
||||
ciMethodRecord* find_ciMethodRecord(Method* method) {
|
||||
const char* klass_name = method->method_holder()->name()->as_utf8();
|
||||
const char* method_name = method->name()->as_utf8();
|
||||
const char* signature = method->signature()->as_utf8();
|
||||
for (int i = 0; i < ci_method_records.length(); i++) {
|
||||
ciMethodRecord* rec = ci_method_records.at(i);
|
||||
if (strcmp(rec->klass, klass_name) == 0 &&
|
||||
strcmp(rec->method, method_name) == 0 &&
|
||||
strcmp(rec->signature, signature) == 0) {
|
||||
return rec;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create and initialize a record for a ciMethodData
|
||||
ciMethodDataRecord* new_ciMethodData(Method* method) {
|
||||
ciMethodDataRecord* rec = NEW_RESOURCE_OBJ(ciMethodDataRecord);
|
||||
rec->klass = method->method_holder()->name()->as_utf8();
|
||||
rec->method = method->name()->as_utf8();
|
||||
rec->signature = method->signature()->as_utf8();
|
||||
ci_method_data_records.append(rec);
|
||||
return rec;
|
||||
}
|
||||
|
||||
// Lookup data for a ciMethodData
|
||||
ciMethodDataRecord* find_ciMethodDataRecord(Method* method) {
|
||||
const char* klass_name = method->method_holder()->name()->as_utf8();
|
||||
const char* method_name = method->name()->as_utf8();
|
||||
const char* signature = method->signature()->as_utf8();
|
||||
for (int i = 0; i < ci_method_data_records.length(); i++) {
|
||||
ciMethodDataRecord* rec = ci_method_data_records.at(i);
|
||||
if (strcmp(rec->klass, klass_name) == 0 &&
|
||||
strcmp(rec->method, method_name) == 0 &&
|
||||
strcmp(rec->signature, signature) == 0) {
|
||||
return rec;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* error_message() {
|
||||
return _error_message;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_error_message = NULL;
|
||||
ci_method_records.clear();
|
||||
ci_method_data_records.clear();
|
||||
}
|
||||
|
||||
// Take an ascii string contain \u#### escapes and convert it to utf8
|
||||
// in place.
|
||||
static void unescape_string(char* value) {
|
||||
char* from = value;
|
||||
char* to = value;
|
||||
while (*from != '\0') {
|
||||
if (*from != '\\') {
|
||||
*from++ = *to++;
|
||||
} else {
|
||||
switch (from[1]) {
|
||||
case 'u': {
|
||||
from += 2;
|
||||
jchar value=0;
|
||||
for (int i=0; i<4; i++) {
|
||||
char c = *from++;
|
||||
switch (c) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
value = (value << 4) + c - '0';
|
||||
break;
|
||||
case 'a': case 'b': case 'c':
|
||||
case 'd': case 'e': case 'f':
|
||||
value = (value << 4) + 10 + c - 'a';
|
||||
break;
|
||||
case 'A': case 'B': case 'C':
|
||||
case 'D': case 'E': case 'F':
|
||||
value = (value << 4) + 10 + c - 'A';
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
UNICODE::convert_to_utf8(&value, 1, to);
|
||||
to++;
|
||||
break;
|
||||
}
|
||||
case 't': *to++ = '\t'; from += 2; break;
|
||||
case 'n': *to++ = '\n'; from += 2; break;
|
||||
case 'r': *to++ = '\r'; from += 2; break;
|
||||
case 'f': *to++ = '\f'; from += 2; break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
}
|
||||
*from = *to;
|
||||
}
|
||||
};
|
||||
|
||||
void ciReplay::replay(TRAPS) {
|
||||
int exit_code = replay_impl(THREAD);
|
||||
|
||||
Threads::destroy_vm();
|
||||
|
||||
vm_exit(exit_code);
|
||||
}
|
||||
|
||||
int ciReplay::replay_impl(TRAPS) {
|
||||
HandleMark hm;
|
||||
ResourceMark rm;
|
||||
// Make sure we don't run with background compilation
|
||||
BackgroundCompilation = false;
|
||||
|
||||
if (ReplaySuppressInitializers > 2) {
|
||||
// ReplaySuppressInitializers > 2 means that we want to allow
|
||||
// normal VM bootstrap but once we get into the replay itself
|
||||
// don't allow any intializers to be run.
|
||||
ReplaySuppressInitializers = 1;
|
||||
}
|
||||
|
||||
// Load and parse the replay data
|
||||
CompileReplay rp(ReplayDataFile, THREAD);
|
||||
int exit_code = 0;
|
||||
if (rp.can_replay()) {
|
||||
rp.process(THREAD);
|
||||
} else {
|
||||
exit_code = 1;
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
oop throwable = PENDING_EXCEPTION;
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
java_lang_Throwable::print(throwable, tty);
|
||||
tty->cr();
|
||||
java_lang_Throwable::print_stack_trace(throwable, tty);
|
||||
tty->cr();
|
||||
exit_code = 2;
|
||||
}
|
||||
|
||||
if (rp.had_error()) {
|
||||
tty->print_cr("Failed on %s", rp.error_message());
|
||||
exit_code = 1;
|
||||
}
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
|
||||
void ciReplay::initialize(ciMethodData* m) {
|
||||
if (replay_state == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_IN_VM;
|
||||
ResourceMark rm;
|
||||
|
||||
Method* method = m->get_MethodData()->method();
|
||||
ciMethodDataRecord* rec = replay_state->find_ciMethodDataRecord(method);
|
||||
if (rec == NULL) {
|
||||
// This indicates some mismatch with the original environment and
|
||||
// the replay environment though it's not always enough to
|
||||
// interfere with reproducing a bug
|
||||
tty->print_cr("Warning: requesting ciMethodData record for method with no data: ");
|
||||
method->print_name(tty);
|
||||
tty->cr();
|
||||
} else {
|
||||
m->_state = rec->state;
|
||||
m->_current_mileage = rec->current_mileage;
|
||||
if (rec->data_length != 0) {
|
||||
assert(m->_data_size == rec->data_length * (int)sizeof(rec->data[0]), "must agree");
|
||||
|
||||
// Write the correct ciObjects back into the profile data
|
||||
ciEnv* env = ciEnv::current();
|
||||
for (int i = 0; i < rec->oops_length; i++) {
|
||||
KlassHandle *h = (KlassHandle *)rec->oops_handles[i];
|
||||
*(ciMetadata**)(rec->data + rec->oops_offsets[i]) =
|
||||
env->get_metadata((*h)());
|
||||
}
|
||||
// Copy the updated profile data into place as intptr_ts
|
||||
#ifdef _LP64
|
||||
Copy::conjoint_jlongs_atomic((jlong *)rec->data, (jlong *)m->_data, rec->data_length);
|
||||
#else
|
||||
Copy::conjoint_jints_atomic((jint *)rec->data, (jint *)m->_data, rec->data_length);
|
||||
#endif
|
||||
}
|
||||
|
||||
// copy in the original header
|
||||
Copy::conjoint_jbytes(rec->orig_data, (char*)&m->_orig, rec->orig_data_length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ciReplay::should_not_inline(ciMethod* method) {
|
||||
if (replay_state == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VM_ENTRY_MARK;
|
||||
// ciMethod without a record shouldn't be inlined.
|
||||
return replay_state->find_ciMethodRecord(method->get_Method()) == NULL;
|
||||
}
|
||||
|
||||
|
||||
void ciReplay::initialize(ciMethod* m) {
|
||||
if (replay_state == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_IN_VM;
|
||||
ResourceMark rm;
|
||||
|
||||
Method* method = m->get_Method();
|
||||
ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
|
||||
if (rec == NULL) {
|
||||
// This indicates some mismatch with the original environment and
|
||||
// the replay environment though it's not always enough to
|
||||
// interfere with reproducing a bug
|
||||
tty->print_cr("Warning: requesting ciMethod record for method with no data: ");
|
||||
method->print_name(tty);
|
||||
tty->cr();
|
||||
} else {
|
||||
// m->_instructions_size = rec->instructions_size;
|
||||
m->_instructions_size = -1;
|
||||
m->_interpreter_invocation_count = rec->interpreter_invocation_count;
|
||||
m->_interpreter_throwout_count = rec->interpreter_throwout_count;
|
||||
method->invocation_counter()->_counter = rec->invocation_counter;
|
||||
method->backedge_counter()->_counter = rec->backedge_counter;
|
||||
}
|
||||
}
|
||||
|
||||
bool ciReplay::is_loaded(Method* method) {
|
||||
if (replay_state == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ASSERT_IN_VM;
|
||||
ResourceMark rm;
|
||||
|
||||
ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
|
||||
return rec != NULL;
|
||||
}
|
||||
#endif
|
55
hotspot/src/share/vm/ci/ciReplay.hpp
Normal file
55
hotspot/src/share/vm/ci/ciReplay.hpp
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_CI_CIREPLAY_HPP
|
||||
#define SHARE_VM_CI_CIREPLAY_HPP
|
||||
|
||||
#include "ci/ciMethod.hpp"
|
||||
|
||||
// ciReplay
|
||||
|
||||
class ciReplay {
|
||||
CI_PACKAGE_ACCESS
|
||||
|
||||
#ifdef ASSERT
|
||||
private:
|
||||
static int replay_impl(TRAPS);
|
||||
|
||||
public:
|
||||
static void replay(TRAPS);
|
||||
|
||||
// These are used by the CI to fill in the cached data from the
|
||||
// replay file when replaying compiles.
|
||||
static void initialize(ciMethodData* method);
|
||||
static void initialize(ciMethod* method);
|
||||
|
||||
static bool is_loaded(Method* method);
|
||||
static bool is_loaded(Klass* klass);
|
||||
|
||||
static bool should_not_inline(ciMethod* method);
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CI_CIREPLAY_HPP
|
@ -63,6 +63,11 @@ const char* ciSymbol::as_utf8() {
|
||||
return s->as_utf8();
|
||||
}
|
||||
|
||||
// The text of the symbol as a null-terminated C string.
|
||||
const char* ciSymbol::as_quoted_ascii() {
|
||||
GUARDED_VM_QUICK_ENTRY(return get_symbol()->as_quoted_ascii();)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciSymbol::base
|
||||
const jbyte* ciSymbol::base() {
|
||||
|
@ -73,6 +73,9 @@ public:
|
||||
const char* as_utf8();
|
||||
int utf8_length();
|
||||
|
||||
// The text of the symbol as ascii with all non-printable characters quoted as \u####
|
||||
const char* as_quoted_ascii();
|
||||
|
||||
// Return the i-th utf8 byte, where i < utf8_length
|
||||
int byte_at(int i);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2012, 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
|
||||
@ -80,6 +80,9 @@
|
||||
#define GUARDED_VM_ENTRY(action) \
|
||||
{if (IS_IN_VM) { action } else { VM_ENTRY_MARK; { action }}}
|
||||
|
||||
#define GUARDED_VM_QUICK_ENTRY(action) \
|
||||
{if (IS_IN_VM) { action } else { VM_QUICK_ENTRY_MARK; { action }}}
|
||||
|
||||
// Redefine this later.
|
||||
#define KILL_COMPILE_ON_FATAL_(result) \
|
||||
THREAD); \
|
||||
|
@ -348,6 +348,22 @@ unsigned int java_lang_String::to_hash(oop java_string) {
|
||||
return java_lang_String::to_hash(value->char_at_addr(offset), length);
|
||||
}
|
||||
|
||||
char* java_lang_String::as_quoted_ascii(oop java_string) {
|
||||
typeArrayOop value = java_lang_String::value(java_string);
|
||||
int offset = java_lang_String::offset(java_string);
|
||||
int length = java_lang_String::length(java_string);
|
||||
|
||||
jchar* base = (length == 0) ? NULL : value->char_at_addr(offset);
|
||||
if (base == NULL) return NULL;
|
||||
|
||||
int result_length = UNICODE::quoted_ascii_length(base, length) + 1;
|
||||
char* result = NEW_RESOURCE_ARRAY(char, result_length);
|
||||
UNICODE::as_quoted_ascii(base, length, result, result_length);
|
||||
assert(result_length >= length + 1, "must not be shorter");
|
||||
assert(result_length == (int)strlen(result) + 1, "must match");
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int java_lang_String::hash_string(oop java_string) {
|
||||
int length = java_lang_String::length(java_string);
|
||||
// Zero length string doesn't hash necessarily hash to zero.
|
||||
|
@ -154,6 +154,8 @@ class java_lang_String : AllStatic {
|
||||
static char* as_utf8_string(oop java_string, int start, int len);
|
||||
static char* as_platform_dependent_str(Handle java_string, TRAPS);
|
||||
static jchar* as_unicode_string(oop java_string, int& length);
|
||||
// produce an ascii string with all other values quoted using \u####
|
||||
static char* as_quoted_ascii(oop java_string);
|
||||
|
||||
// Compute the hash value for a java.lang.String object which would
|
||||
// contain the characters passed in.
|
||||
|
@ -569,6 +569,7 @@ void Dependencies::print_dependency(DepType dept, int nargs, DepArgument args[],
|
||||
|
||||
void Dependencies::DepStream::log_dependency(Klass* witness) {
|
||||
if (_deps == NULL && xtty == NULL) return; // fast cutout for runtime
|
||||
ResourceMark rm;
|
||||
int nargs = argument_count();
|
||||
DepArgument args[max_arg_count];
|
||||
for (int j = 0; j < nargs; j++) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2012, 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
|
||||
@ -40,6 +40,7 @@
|
||||
|
||||
class InvocationCounter VALUE_OBJ_CLASS_SPEC {
|
||||
friend class VMStructs;
|
||||
friend class ciReplay;
|
||||
private: // bit no: |31 3| 2 | 1 0 |
|
||||
unsigned int _counter; // format: [count|carry|state]
|
||||
|
||||
@ -85,6 +86,8 @@ class InvocationCounter VALUE_OBJ_CLASS_SPEC {
|
||||
void set_carry(); // set the sticky carry bit
|
||||
void set_carry_flag() { _counter |= carry_mask; }
|
||||
|
||||
int raw_counter() { return _counter; }
|
||||
|
||||
// Accessors
|
||||
State state() const { return (State)(_counter & state_mask); }
|
||||
bool carry() const { return (_counter & carry_mask) != 0; }
|
||||
|
@ -1052,6 +1052,13 @@ Method* InstanceKlass::class_initializer() {
|
||||
}
|
||||
|
||||
void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_oop, TRAPS) {
|
||||
if (ReplayCompiles &&
|
||||
(ReplaySuppressInitializers == 1 ||
|
||||
ReplaySuppressInitializers >= 2 && this_oop->class_loader() != NULL)) {
|
||||
// Hide the existence of the initializer for the purpose of replaying the compile
|
||||
return;
|
||||
}
|
||||
|
||||
methodHandle h_method(THREAD, this_oop->class_initializer());
|
||||
assert(!this_oop->is_initialized(), "we cannot initialize twice");
|
||||
if (TraceClassInitialization) {
|
||||
|
@ -133,6 +133,7 @@ class OopMapBlock VALUE_OBJ_CLASS_SPEC {
|
||||
class InstanceKlass: public Klass {
|
||||
friend class VMStructs;
|
||||
friend class ClassFileParser;
|
||||
friend class CompileReplay;
|
||||
|
||||
protected:
|
||||
// Constructor
|
||||
|
@ -153,17 +153,15 @@ char* Symbol::as_C_string_flexible_buffer(Thread* t,
|
||||
|
||||
void Symbol::print_symbol_on(outputStream* st) const {
|
||||
st = st ? st : tty;
|
||||
int length = UTF8::unicode_length((const char*)bytes(), utf8_length());
|
||||
const char *ptr = (const char *)bytes();
|
||||
jchar value;
|
||||
for (int index = 0; index < length; index++) {
|
||||
ptr = UTF8::next(ptr, &value);
|
||||
if (value >= 32 && value < 127 || value == '\'' || value == '\\') {
|
||||
st->put(value);
|
||||
} else {
|
||||
st->print("\\u%04x", value);
|
||||
}
|
||||
}
|
||||
st->print("%s", as_quoted_ascii());
|
||||
}
|
||||
|
||||
char* Symbol::as_quoted_ascii() const {
|
||||
const char *ptr = (const char *)&_body[0];
|
||||
int quoted_length = UTF8::quoted_ascii_length(ptr, utf8_length());
|
||||
char* result = NEW_RESOURCE_ARRAY(char, quoted_length + 1);
|
||||
UTF8::as_quoted_ascii(ptr, result, quoted_length + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
jchar* Symbol::as_unicode(int& length) const {
|
||||
|
@ -189,6 +189,8 @@ class Symbol : public MetaspaceObj {
|
||||
// Use buf if needed buffer length is <= size.
|
||||
char* as_C_string_flexible_buffer(Thread* t, char* buf, int size) const;
|
||||
|
||||
// Returns an escaped form of a Java string.
|
||||
char* as_quoted_ascii() const;
|
||||
|
||||
// Returns a null terminated utf8 string in a resource array
|
||||
char* as_utf8() const { return as_C_string(); }
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "ci/ciReplay.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
@ -150,7 +151,7 @@ const char* InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_
|
||||
} else {
|
||||
// Not hot. Check for medium-sized pre-existing nmethod at cold sites.
|
||||
if (callee_method->has_compiled_code() &&
|
||||
callee_method->instructions_size(CompLevel_full_optimization) > inline_small_code_size)
|
||||
callee_method->instructions_size() > inline_small_code_size)
|
||||
return "already compiled into a medium method";
|
||||
}
|
||||
if (size > max_inline_size) {
|
||||
@ -192,7 +193,7 @@ const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* cal
|
||||
}
|
||||
|
||||
if (callee_method->has_compiled_code() &&
|
||||
callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode) {
|
||||
callee_method->instructions_size() > InlineSmallCode) {
|
||||
wci_result->set_profit(wci_result->profit() * 0.1);
|
||||
// %%% adjust wci_result->size()?
|
||||
}
|
||||
@ -216,7 +217,7 @@ const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* cal
|
||||
// Now perform checks which are heuristic
|
||||
|
||||
if (callee_method->has_compiled_code() &&
|
||||
callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode) {
|
||||
callee_method->instructions_size() > InlineSmallCode) {
|
||||
return "already compiled into a big method";
|
||||
}
|
||||
|
||||
@ -235,6 +236,12 @@ const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* cal
|
||||
return "disallowed by CompilerOracle";
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (ciReplay::should_not_inline(callee_method)) {
|
||||
return "disallowed by ciReplay";
|
||||
}
|
||||
#endif
|
||||
|
||||
if (UseStringCache) {
|
||||
// Do not inline StringCache::profile() method used only at the beginning.
|
||||
if (callee_method->name() == ciSymbol::profile_name() &&
|
||||
|
@ -334,7 +334,7 @@ bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* kl
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(dest_method->will_link(method()->holder(), klass, bc()), "dest_method: typeflow responsibility");
|
||||
assert(dest_method->is_loaded(), "dest_method: typeflow responsibility");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "ci/ciReplay.hpp"
|
||||
#include "classfile/altHashing.hpp"
|
||||
#include "classfile/classLoader.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
@ -5151,6 +5152,7 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, v
|
||||
|
||||
// Check if we should compile all classes on bootclasspath
|
||||
NOT_PRODUCT(if (CompileTheWorld) ClassLoader::compile_the_world();)
|
||||
NOT_PRODUCT(if (ReplayCompiles) ciReplay::replay(thread);)
|
||||
// Since this is not a JVM_ENTRY we have to set the thread state manually before leaving.
|
||||
ThreadStateTransition::transition_and_fence(thread, _thread_in_vm, _thread_in_native);
|
||||
} else {
|
||||
|
@ -64,6 +64,8 @@ class AttachOperation;
|
||||
//
|
||||
class JvmtiExport : public AllStatic {
|
||||
friend class VMStructs;
|
||||
friend class CompileReplay;
|
||||
|
||||
private:
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
|
@ -97,6 +97,9 @@ void CompilationPolicy::completed_vm_startup() {
|
||||
// This is intended to force compiles for methods (usually for
|
||||
// debugging) that would otherwise be interpreted for some reason.
|
||||
bool CompilationPolicy::must_be_compiled(methodHandle m, int comp_level) {
|
||||
// Don't allow Xcomp to cause compiles in replay mode
|
||||
if (ReplayCompiles) return false;
|
||||
|
||||
if (m->has_compiled_code()) return false; // already compiled
|
||||
if (!can_be_compiled(m, comp_level)) return false;
|
||||
|
||||
@ -322,6 +325,16 @@ nmethod* NonTieredCompPolicy::event(methodHandle method, methodHandle inlinee, i
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (CompileTheWorld || ReplayCompiles) {
|
||||
// Don't trigger other compiles in testing mode
|
||||
if (bci == InvocationEntryBci) {
|
||||
reset_counter_for_invocation_event(method);
|
||||
} else {
|
||||
reset_counter_for_back_branch_event(method);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bci == InvocationEntryBci) {
|
||||
// when code cache is full, compilation gets switched off, UseCompiler
|
||||
// is set to false
|
||||
|
@ -3189,6 +3189,26 @@ class CommandLineFlags {
|
||||
product(ccstrlist, CompileCommand, "", \
|
||||
"Prepend to .hotspot_compiler; e.g. log,java/lang/String.<init>") \
|
||||
\
|
||||
develop(bool, ReplayCompiles, false, \
|
||||
"Enable replay of compilations from ReplayDataFile") \
|
||||
\
|
||||
develop(ccstr, ReplayDataFile, "replay.txt", \
|
||||
"file containing compilation replay information") \
|
||||
\
|
||||
develop(intx, ReplaySuppressInitializers, 2, \
|
||||
"Controls handling of class initialization during replay" \
|
||||
"0 - don't do anything special" \
|
||||
"1 - treat all class initializers as empty" \
|
||||
"2 - treat class initializers for application classes as empty" \
|
||||
"3 - allow all class initializers to run during bootstrap but" \
|
||||
" pretend they are empty after starting replay") \
|
||||
\
|
||||
develop(bool, ReplayIgnoreInitErrors, false, \
|
||||
"Ignore exceptions thrown during initialization for replay") \
|
||||
\
|
||||
develop(bool, DumpReplayDataOnError, true, \
|
||||
"record replay data for crashing compiler threads") \
|
||||
\
|
||||
product(bool, CICompilerCountPerCPU, false, \
|
||||
"1 compiler thread for log(N CPUs)") \
|
||||
\
|
||||
|
@ -993,6 +993,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||
\
|
||||
nonstatic_field(ciMethod, _interpreter_invocation_count, int) \
|
||||
nonstatic_field(ciMethod, _interpreter_throwout_count, int) \
|
||||
nonstatic_field(ciMethod, _instructions_size, int) \
|
||||
\
|
||||
nonstatic_field(ciMethodData, _data_size, int) \
|
||||
nonstatic_field(ciMethodData, _state, u_char) \
|
||||
|
@ -353,9 +353,9 @@ protected:
|
||||
// sort the array.
|
||||
bool contains(const T& x) const { return index_of(x) >= 0; }
|
||||
|
||||
T at(int i) const { return _data[i]; }
|
||||
void at_put(const int i, const T& x) { _data[i] = x; }
|
||||
T* adr_at(const int i) { return &_data[i]; }
|
||||
T at(int i) const { assert(i >= 0 && i< _length, err_msg_res("oob: 0 <= %d < %d", i, _length)); return _data[i]; }
|
||||
void at_put(const int i, const T& x) { assert(i >= 0 && i< _length, err_msg_res("oob: 0 <= %d < %d", i, _length)); _data[i] = x; }
|
||||
T* adr_at(const int i) { assert(i >= 0 && i< _length, err_msg_res("oob: 0 <= %d < %d", i, _length)); return &_data[i]; }
|
||||
int find(const T& x) { return index_of(x); }
|
||||
|
||||
T at_acquire(const int which) { return OrderAccess::load_acquire(adr_at(which)); }
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2012, 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
|
||||
@ -147,7 +147,7 @@ static u_char* utf8_write(u_char* base, jchar ch) {
|
||||
|
||||
void UTF8::convert_to_unicode(const char* utf8_str, jchar* unicode_str, int unicode_length) {
|
||||
unsigned char ch;
|
||||
const char *ptr = (const char *)utf8_str;
|
||||
const char *ptr = utf8_str;
|
||||
int index = 0;
|
||||
|
||||
/* ASCII case loop optimization */
|
||||
@ -162,6 +162,119 @@ void UTF8::convert_to_unicode(const char* utf8_str, jchar* unicode_str, int unic
|
||||
}
|
||||
}
|
||||
|
||||
// returns the quoted ascii length of a 0-terminated utf8 string
|
||||
int UTF8::quoted_ascii_length(const char* utf8_str, int utf8_length) {
|
||||
const char *ptr = utf8_str;
|
||||
const char* end = ptr + utf8_length;
|
||||
int result = 0;
|
||||
while (ptr < end) {
|
||||
jchar c;
|
||||
ptr = UTF8::next(ptr, &c);
|
||||
if (c >= 32 && c < 127) {
|
||||
result++;
|
||||
} else {
|
||||
result += 6;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// converts a utf8 string to quoted ascii
|
||||
void UTF8::as_quoted_ascii(const char* utf8_str, char* buf, int buflen) {
|
||||
const char *ptr = utf8_str;
|
||||
char* p = buf;
|
||||
char* end = buf + buflen;
|
||||
while (*ptr != '\0') {
|
||||
jchar c;
|
||||
ptr = UTF8::next(ptr, &c);
|
||||
if (c >= 32 && c < 127) {
|
||||
if (p + 1 >= end) break; // string is truncated
|
||||
*p++ = (char)c;
|
||||
} else {
|
||||
if (p + 6 >= end) break; // string is truncated
|
||||
sprintf(p, "\\u%04x", c);
|
||||
p += 6;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
|
||||
const char* UTF8::from_quoted_ascii(const char* quoted_ascii_str) {
|
||||
const char *ptr = quoted_ascii_str;
|
||||
char* result = NULL;
|
||||
while (*ptr != '\0') {
|
||||
char c = *ptr;
|
||||
if (c < 32 || c >= 127) break;
|
||||
}
|
||||
if (*ptr == '\0') {
|
||||
// nothing to do so return original string
|
||||
return quoted_ascii_str;
|
||||
}
|
||||
// everything up to this point was ok.
|
||||
int length = ptr - quoted_ascii_str;
|
||||
char* buffer = NULL;
|
||||
for (int round = 0; round < 2; round++) {
|
||||
while (*ptr != '\0') {
|
||||
if (*ptr != '\\') {
|
||||
if (buffer != NULL) {
|
||||
buffer[length] = *ptr;
|
||||
}
|
||||
length++;
|
||||
} else {
|
||||
switch (ptr[1]) {
|
||||
case 'u': {
|
||||
ptr += 2;
|
||||
jchar value=0;
|
||||
for (int i=0; i<4; i++) {
|
||||
char c = *ptr++;
|
||||
switch (c) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
value = (value << 4) + c - '0';
|
||||
break;
|
||||
case 'a': case 'b': case 'c':
|
||||
case 'd': case 'e': case 'f':
|
||||
value = (value << 4) + 10 + c - 'a';
|
||||
break;
|
||||
case 'A': case 'B': case 'C':
|
||||
case 'D': case 'E': case 'F':
|
||||
value = (value << 4) + 10 + c - 'A';
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
if (buffer == NULL) {
|
||||
char utf8_buffer[4];
|
||||
char* next = (char*)utf8_write((u_char*)utf8_buffer, value);
|
||||
length += next - utf8_buffer;
|
||||
} else {
|
||||
char* next = (char*)utf8_write((u_char*)&buffer[length], value);
|
||||
length += next - &buffer[length];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 't': if (buffer != NULL) buffer[length] = '\t'; ptr += 2; length++; break;
|
||||
case 'n': if (buffer != NULL) buffer[length] = '\n'; ptr += 2; length++; break;
|
||||
case 'r': if (buffer != NULL) buffer[length] = '\r'; ptr += 2; length++; break;
|
||||
case 'f': if (buffer != NULL) buffer[length] = '\f'; ptr += 2; length++; break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (round == 0) {
|
||||
buffer = NEW_RESOURCE_ARRAY(char, length + 1);
|
||||
ptr = quoted_ascii_str;
|
||||
} else {
|
||||
buffer[length] = '\0';
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
// Returns NULL if 'c' it not found. This only works as long
|
||||
// as 'c' is an ASCII character
|
||||
const jbyte* UTF8::strrchr(const jbyte* base, int length, jbyte c) {
|
||||
@ -242,3 +355,35 @@ void UNICODE::convert_to_utf8(const jchar* base, int length, char* utf8_buffer)
|
||||
}
|
||||
*utf8_buffer = '\0';
|
||||
}
|
||||
|
||||
// returns the quoted ascii length of a unicode string
|
||||
int UNICODE::quoted_ascii_length(jchar* base, int length) {
|
||||
int result = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
jchar c = base[i];
|
||||
if (c >= 32 && c < 127) {
|
||||
result++;
|
||||
} else {
|
||||
result += 6;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// converts a utf8 string to quoted ascii
|
||||
void UNICODE::as_quoted_ascii(const jchar* base, int length, char* buf, int buflen) {
|
||||
char* p = buf;
|
||||
char* end = buf + buflen;
|
||||
for (int index = 0; index < length; index++) {
|
||||
jchar c = base[index];
|
||||
if (c >= 32 && c < 127) {
|
||||
if (p + 1 >= end) break; // string is truncated
|
||||
*p++ = (char)c;
|
||||
} else {
|
||||
if (p + 6 >= end) break; // string is truncated
|
||||
sprintf(p, "\\u%04x", c);
|
||||
p += 6;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2012, 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
|
||||
@ -32,22 +32,32 @@
|
||||
|
||||
class UTF8 : AllStatic {
|
||||
public:
|
||||
// returns the unicode length of a 0-terminated uft8 string
|
||||
static int unicode_length(const char* uft8_str);
|
||||
// returns the unicode length of a 0-terminated utf8 string
|
||||
static int unicode_length(const char* utf8_str);
|
||||
|
||||
// returns the unicode length of a non-0-terminated uft8 string
|
||||
static int unicode_length(const char* uft8_str, int len);
|
||||
// returns the unicode length of a non-0-terminated utf8 string
|
||||
static int unicode_length(const char* utf8_str, int len);
|
||||
|
||||
// converts a uft8 string to a unicode string
|
||||
// converts a utf8 string to a unicode string
|
||||
static void convert_to_unicode(const char* utf8_str, jchar* unicode_buffer, int unicode_length);
|
||||
|
||||
// returns the quoted ascii length of a utf8 string
|
||||
static int quoted_ascii_length(const char* utf8_str, int utf8_length);
|
||||
|
||||
// converts a utf8 string to quoted ascii
|
||||
static void as_quoted_ascii(const char* utf8_str, char* buf, int buflen);
|
||||
|
||||
// converts a quoted ascii string to utf8 string. returns the original
|
||||
// string unchanged if nothing needs to be done.
|
||||
static const char* from_quoted_ascii(const char* quoted_ascii_string);
|
||||
|
||||
// decodes the current utf8 character, stores the result in value,
|
||||
// and returns the end of the current uft8 chararacter.
|
||||
// and returns the end of the current utf8 chararacter.
|
||||
static char* next(const char* str, jchar* value);
|
||||
|
||||
// decodes the current utf8 character, gets the supplementary character instead of
|
||||
// the surrogate pair when seeing a supplementary character in string,
|
||||
// stores the result in value, and returns the end of the current uft8 chararacter.
|
||||
// stores the result in value, and returns the end of the current utf8 chararacter.
|
||||
static char* next_character(const char* str, jint* value);
|
||||
|
||||
// Utility methods
|
||||
@ -79,6 +89,12 @@ class UNICODE : AllStatic {
|
||||
// in resource area unless a buffer is provided.
|
||||
static char* as_utf8(jchar* base, int length);
|
||||
static char* as_utf8(jchar* base, int length, char* buf, int buflen);
|
||||
|
||||
// returns the quoted ascii length of a unicode string
|
||||
static int quoted_ascii_length(jchar* base, int length);
|
||||
|
||||
// converts a utf8 string to quoted ascii
|
||||
static void as_quoted_ascii(const jchar* base, int length, char* buf, int buflen);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_UTILITIES_UTF8_HPP
|
||||
|
@ -1009,6 +1009,15 @@ void VMError::report_and_die() {
|
||||
OnError = NULL;
|
||||
}
|
||||
|
||||
static bool skip_replay = false;
|
||||
if (DumpReplayDataOnError && _thread && _thread->is_Compiler_thread() && !skip_replay) {
|
||||
skip_replay = true;
|
||||
ciEnv* env = ciEnv::current();
|
||||
if (env != NULL) {
|
||||
env->dump_replay_data();
|
||||
}
|
||||
}
|
||||
|
||||
static bool skip_bug_url = !should_report_bug(first_error->_id);
|
||||
if (!skip_bug_url) {
|
||||
skip_bug_url = true;
|
||||
|
Loading…
Reference in New Issue
Block a user