diff --git a/agent/doc/c2replay.html b/agent/doc/c2replay.html
new file mode 100644
index 0000000000000000000000000000000000000000..cf90e0e8f62f4cce26316c8b9f842d5729677f4b
--- /dev/null
+++ b/agent/doc/c2replay.html
@@ -0,0 +1,41 @@
+
+
+
+C2 Replay
+
+
+
+
+C2 compiler replay
+
+The C2 compiler replay is a function to repeat the compiling process from a crashed java process in compiled method
+This function only exists in debug version of VM
+
+Usage
+
+First, use SA to attach to the core file, if suceeded, do
+ clhsdb>dumpreplaydata | -a | [> 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= -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 "" 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//proc/
+
+ Use this tool to dump VM type library:
+ vmstructsdump libjvm.so > .db
+
+ set env SA_TYPEDB=.db (refer different shell for set envs)
diff --git a/agent/doc/clhsdb.html b/agent/doc/clhsdb.html
index 838ad556c9c4c39b67860012ab9aa2725c8ff437..f1c43fd1e5f28d01530f0ce1615fd4ef995d44d7 100644
--- a/agent/doc/clhsdb.html
+++ b/agent/doc/clhsdb.html
@@ -37,12 +37,19 @@ Each CLHSDB command can have zero or more arguments and optionally end with outp
Available commands:
assert true | false turn on/off asserts in SA code
attach pid | exec core attach SA to a process or core
+ buildreplayjars [all | boot | app] build jars for replay, boot.jar for bootclasses, app.jar for application classes
class name find a Java class from debuggee and print oop
classes print all loaded Java classes with Klass*
detach detach SA from current target
dis address [ length ] disassemble (sparc/x86) specified number of instructions from given address
+ dissemble address disassemble nmethod
+ dumpcfg -a | id Dump the PhaseCFG for every compiler thread that has one live
dumpclass { address | name } [ directory ] dump .class file for given Klass* or class name
+ dumpcodecache dump codecache contents
dumpheap [ file ] dump heap in hprof binary format
+ dumpideal -a | id dump ideal graph like debug flag -XX:+PrintIdeal
+ dumpilt -a | id dump inline tree for C2 compilation
+ dumpreplaydata | -a | [>replay.txt] dump replay data into a file
echo [ true | false ] turn on/off command echo mode
examine [ address/count ] | [ address,address] show contents of memory from given address
field [ type [ name fieldtype isStatic offset address ] ] print info about a field of HotSpot type
@@ -51,29 +58,35 @@ Available commands:
help [ command ] print help message for all commands or just given command
history show command history. usual !command-number syntax works.
inspect expression inspect a given oop
+ intConstant [ name [ value ] ] print out hotspot integer constant(s)
jdis address show bytecode disassembly of a given Method*
jhisto show Java heap histogram
jseval script evaluate a given string as JavaScript code
jsload file load and evaluate a JavaScript file
jstack [-v] show Java stack trace of all Java threads. -v is verbose mode
livenmethods show all live nmethods
+ longConstant [ name [ value ] ] print out hotspot long constant(s)s
mem address [ length ] show contents of memory -- also shows closest ELF/COFF symbol if found
pmap show Solaris pmap-like output
print expression print given Klass*, Method* or arbitrary address
printas type expression print given address as given HotSpot type. eg. print JavaThread <address>
+ printmdo -a | expression print method data oop
printstatics [ type ] print static fields of given HotSpot type (or all types if none specified)
pstack [-v] show mixed mode stack trace for all Java, non-Java threads. -v is verbose mode
quit quit CLHSDB tool
reattach detach and re-attach SA to current target
+ revptrs find liveness of oops
scanoops start end [ type ] scan a Oop from given start to end address
search [ heap | codecache | threads ] value search a value in heap or codecache or threads
source filename load and execute CLHSDB commands from given file
symbol name show address of a given ELF/COFF symbol
sysprops show all Java System properties
+ thread id show thread of id
threads show all Java threads
tokenize ...
type [ type [ name super isOop isInteger isUnsigned size ] ] show info. on HotSpot type
universe print gc universe
+ vmstructsdump dump hotspot type library in text
verbose true | false turn on/off verbose mode
versioncheck [ true | false ] turn on/off debuggee VM version check
whatis address print info about any arbitrary address
@@ -114,5 +127,11 @@ hsdb> jsload test.js
+C2 Compilation Replay
+
+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.
+c2replay.html
+
diff --git a/agent/doc/index.html b/agent/doc/index.html
index 987e5f9c6597421f21862c30a25fa124df966a4c..395f10ef6c8c197b3ab72000b5a702a6b18b20fe 100644
--- a/agent/doc/index.html
+++ b/agent/doc/index.html
@@ -220,6 +220,12 @@ These scripts are used to run SA remotely.
+
C2 Compilation Replay
+
+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.
+c2replay.html
+
Debugging transported core dumps
When a core dump is moved from the machine where it was produced to a
diff --git a/agent/make/Makefile b/agent/make/Makefile
index c0183f17bc7d1e5985159711512f5ff938e2cd7c..a30a999828623d96eb593424fff2aacce82096d3 100644
--- a/agent/make/Makefile
+++ b/agent/make/Makefile
@@ -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)/*
diff --git a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java
index c640e4ecc726e9660d11034c352425d94e3ce83d..23058f428585ac3f89a2e9f8a7f81624890a7f25 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java
@@ -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 {
| -a | }", 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) {
diff --git a/agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java b/agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java
index fc8826e8d23c4075fdb04f75575dd24e933191be..e69be922fe08472bafd323e4bab6b99051d70a99 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java
@@ -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));
+ }
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java b/agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java
index ab69f43984ddde0f869b5e5eb20b87caf0fc2b26..0b75eac3e29281d897109350a8fdf8e271327f92 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java
@@ -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
+ }
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java b/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java
index eb48eedb330fcc7077e014be7a6c39b35413f2bc..871ee414a44a0709fe4a41de32b9c60101a69b16 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java
@@ -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 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);
+ }
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java b/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java
index 4798977ab1aa63530c18ba4b6b324c98039b38d8..0d0a0f637407f4ae135326009529d11686ba7081 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java
@@ -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);
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java b/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java
index 45d43cd0d16cdac7adf34b3e59a5353b19db6844..3468b0d65142c2ba2635c39531b2976815d612d8 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java
@@ -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());
+ }
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java b/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java
index 0399e275151c85ae4a1f47195b4aca10feee013b..117a9488cf760cdca44e7ed4e947d5aba293e032 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java
@@ -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();
+ }
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java b/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java
index 839ad00aafbbca21d21f081c9b001bc15472c12d..b0b370cef3c74f34a21197549186fba3d7bdfcaa 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java
@@ -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
//
diff --git a/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java b/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java
index deca63123dfe8dbdd9ed68aca439a9dfbf1948ba..45ef0a2d27accfb761ca340b8dea23d009f3ee75 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java
@@ -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);
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java
index 7b7d0c3ad1dbea1513a6c73d81a80489d2f0a019..b238cd3099249f5350ad1a67370354174e6fd572 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java
@@ -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() {
diff --git a/agent/src/share/classes/sun/jvm/hotspot/oops/Field.java b/agent/src/share/classes/sun/jvm/hotspot/oops/Field.java
index 665315361c8f4a712d02a33fa33d374e5510bfd3..621c8cf4b9af0415f58219824049d9e498fbd34f 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Field.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Field.java
@@ -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
//
diff --git a/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
index a2c7afb60275c6be8833ac01ad5abb07151776fb..ba07fa348006b3c4a40d1c80331e8afea0e9f0f1 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
@@ -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);
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java b/agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java
index 35ce375b52e3982009fbcf93383de9a354bc03af..4fc2ed8c6a8e08123798665d067378ca21997745 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java
@@ -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");
+ }
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java b/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java
index 449c0695bd1188547ef3ee97055e53ff2db6d848..2fd57fd9728255a26da9f4e8c13e293028b97e0a 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java
@@ -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);
}
diff --git a/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java b/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java
index e6d233f1471e2458cee55e6521b31d8add6b499d..40ede727708c66314435f22a5100393ea4715126 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java
@@ -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();
+ }
}
diff --git a/src/share/vm/ci/ciClassList.hpp b/src/share/vm/ci/ciClassList.hpp
index 7272ea8758630c3177152a54a41c6120a21441ca..71e5dd18c7f3a1978bdbec5c856bc6ebf244cf45 100644
--- a/src/share/vm/ci/ciClassList.hpp
+++ b/src/share/vm/ci/ciClassList.hpp
@@ -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; \
diff --git a/src/share/vm/ci/ciEnv.cpp b/src/share/vm/ci/ciEnv.cpp
index 0465b9cf9c14a3ff2e93a89478641c886fd1f47e..878313d11103e63d6151606eb7e77ed43ddc014f 100644
--- a/src/share/vm/ci/ciEnv.cpp
+++ b/src/share/vm/ci/ciEnv.cpp
@@ -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* 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();
+}
diff --git a/src/share/vm/ci/ciEnv.hpp b/src/share/vm/ci/ciEnv.hpp
index f252dc7c0f45e3edf89d13f71524bef7beffac58..042bc32fa00e3cdc77538542c2045aeb79af8d4d 100644
--- a/src/share/vm/ci/ciEnv.hpp
+++ b/src/share/vm/ci/ciEnv.hpp
@@ -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
diff --git a/src/share/vm/ci/ciInstanceKlass.cpp b/src/share/vm/ci/ciInstanceKlass.cpp
index 7a3eb328f57176619455507c7dbb4e2afec0dfec..de5e973bfbfe26219a7389fd3769bec9ff10b387 100644
--- a/src/share/vm/ci/ciInstanceKlass.cpp
+++ b/src/share/vm/ci/ciInstanceKlass.cpp
@@ -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);
+ }
+}
diff --git a/src/share/vm/ci/ciInstanceKlass.hpp b/src/share/vm/ci/ciInstanceKlass.hpp
index 205ee493d5587169b38efc8f7759547c4ec693c7..f7aeba2df3b5d199b724b45bff4d6f001a2c98db 100644
--- a/src/share/vm/ci/ciInstanceKlass.hpp
+++ b/src/share/vm/ci/ciInstanceKlass.hpp
@@ -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
diff --git a/src/share/vm/ci/ciMetadata.hpp b/src/share/vm/ci/ciMetadata.hpp
index cbd0bc0287ed0943c48d18223de51d5fa0d5435a..e0baea9666d9b6967610a3a3fbda3e3259d14742 100644
--- a/src/share/vm/ci/ciMetadata.hpp
+++ b/src/share/vm/ci/ciMetadata.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");
diff --git a/src/share/vm/ci/ciMethod.cpp b/src/share/vm/ci/ciMethod.cpp
index 7071f54d0af67483c896c2cf2d7f54f4e4afa6f3..951183d60bd74466ad918acbdef6d0db1e449972 100644
--- a/src/share/vm/ci/ciMethod.cpp
+++ b/src/share/vm/ci/ciMethod.cpp
@@ -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
@@ -1000,8 +1008,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 +1046,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 +1177,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
diff --git a/src/share/vm/ci/ciMethod.hpp b/src/share/vm/ci/ciMethod.hpp
index 15f65213374c4d96fd77ab6e1d7032bd7b2a947d..ecbaacc45d3ed3b150216e179d65541d70504539 100644
--- a/src/share/vm/ci/ciMethod.hpp
+++ b/src/share/vm/ci/ciMethod.hpp
@@ -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;
@@ -252,7 +254,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 +261,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 +293,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);
diff --git a/src/share/vm/ci/ciMethodData.cpp b/src/share/vm/ci/ciMethodData.cpp
index aef1c03c7bc9613a042b5db23e7b70d8a61c4a8e..ee5490be8772641682d456810724bd258bcf7f86 100644
--- a/src/share/vm/ci/ciMethodData.cpp
+++ b/src/share/vm/ci/ciMethodData.cpp
@@ -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);
diff --git a/src/share/vm/ci/ciMethodData.hpp b/src/share/vm/ci/ciMethodData.hpp
index bca5d1cd1e184d9e36c897ba3841b59d91101995..ea650cbd7210eff6eacf26bac48825b81cd6e123 100644
--- a/src/share/vm/ci/ciMethodData.hpp
+++ b/src/share/vm/ci/ciMethodData.hpp
@@ -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
diff --git a/src/share/vm/ci/ciObject.hpp b/src/share/vm/ci/ciObject.hpp
index 6246e173e9c1bb8d237811cf777e649093d9d600..c33b79ed5edbf3f6989a4172b21a632a8702552d 100644
--- a/src/share/vm/ci/ciObject.hpp
+++ b/src/share/vm/ci/ciObject.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
diff --git a/src/share/vm/ci/ciObjectFactory.hpp b/src/share/vm/ci/ciObjectFactory.hpp
index 10870b904712fd5a7391a5f3029a74f4b5172212..29de514b2eacb20e575c1464f72ad1f81bbc24bc 100644
--- a/src/share/vm/ci/ciObjectFactory.hpp
+++ b/src/share/vm/ci/ciObjectFactory.hpp
@@ -137,6 +137,7 @@ public:
ciReturnAddress* get_return_address(int bci);
+ GrowableArray* get_ci_metadata() const { return _ci_metadata; }
// RedefineClasses support
void metadata_do(void f(Metadata*));
diff --git a/src/share/vm/ci/ciReplay.cpp b/src/share/vm/ci/ciReplay.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..726d84b1b5d45f99d355e060465b97f3c3a09c71
--- /dev/null
+++ b/src/share/vm/ci/ciReplay.cpp
@@ -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 ci_method_records;
+ GrowableArray 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' # # ...
+ // 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
+ 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
+ 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
+ //
+ //
+ 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 orig # # ... data # # ... oops
+ 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
+ //
+ // 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 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
diff --git a/src/share/vm/ci/ciReplay.hpp b/src/share/vm/ci/ciReplay.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5966d3ece760a47abd55b98f8b2859acfbc4959a
--- /dev/null
+++ b/src/share/vm/ci/ciReplay.hpp
@@ -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
diff --git a/src/share/vm/ci/ciSymbol.cpp b/src/share/vm/ci/ciSymbol.cpp
index 26b3e4d565dd09a61cb49bc98203db70b001c5ea..1a89adf5dd397ad6fcd2483464aedca1535b7f48 100644
--- a/src/share/vm/ci/ciSymbol.cpp
+++ b/src/share/vm/ci/ciSymbol.cpp
@@ -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() {
diff --git a/src/share/vm/ci/ciSymbol.hpp b/src/share/vm/ci/ciSymbol.hpp
index 642be46252b96c15c6d492c3dc30d9a896d51f9f..d54b54009be71fc3a2420d41256382253c31d303 100644
--- a/src/share/vm/ci/ciSymbol.hpp
+++ b/src/share/vm/ci/ciSymbol.hpp
@@ -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);
diff --git a/src/share/vm/ci/ciUtilities.hpp b/src/share/vm/ci/ciUtilities.hpp
index 9788f77a734aee656ace6a19bb6e35fda0a0f22c..1a075bf6e98f792d7dc8d0ba7fb6c67dafb0e93d 100644
--- a/src/share/vm/ci/ciUtilities.hpp
+++ b/src/share/vm/ci/ciUtilities.hpp
@@ -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); \
diff --git a/src/share/vm/classfile/javaClasses.cpp b/src/share/vm/classfile/javaClasses.cpp
index c414079e9ed2296e73d0a3bcd6264e685ec6b655..5662fabad277a58b1c517b29770b454ae48768b0 100644
--- a/src/share/vm/classfile/javaClasses.cpp
+++ b/src/share/vm/classfile/javaClasses.cpp
@@ -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.
diff --git a/src/share/vm/classfile/javaClasses.hpp b/src/share/vm/classfile/javaClasses.hpp
index 902099f1953c73fe1394a29e25c900f04bad1a87..04e0214d204c40de26dea56cdb061e230febb2bf 100644
--- a/src/share/vm/classfile/javaClasses.hpp
+++ b/src/share/vm/classfile/javaClasses.hpp
@@ -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.
diff --git a/src/share/vm/code/dependencies.cpp b/src/share/vm/code/dependencies.cpp
index 93db50afe07ec63567eb0f531535a2ef5d447103..d81fb3f3fb374441d4c62f4181a0cc552995a3f8 100644
--- a/src/share/vm/code/dependencies.cpp
+++ b/src/share/vm/code/dependencies.cpp
@@ -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++) {
diff --git a/src/share/vm/interpreter/invocationCounter.hpp b/src/share/vm/interpreter/invocationCounter.hpp
index 38725907ead1b5a16061c106bfb94173882624a6..db896d8ade6cc91834655addeca8935a3404b76a 100644
--- a/src/share/vm/interpreter/invocationCounter.hpp
+++ b/src/share/vm/interpreter/invocationCounter.hpp
@@ -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; }
diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp
index c5b20d8ffd091e2e9f5402efb2e508dc0047ad48..2f1ef700624a7402312b8ea9152321e981a60e4f 100644
--- a/src/share/vm/oops/instanceKlass.cpp
+++ b/src/share/vm/oops/instanceKlass.cpp
@@ -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) {
diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp
index f427f338c0258d2326acc8316eaebc121ed86417..ad59ab0632fd32386e40b48c9bdffc9d97db21df 100644
--- a/src/share/vm/oops/instanceKlass.hpp
+++ b/src/share/vm/oops/instanceKlass.hpp
@@ -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
diff --git a/src/share/vm/oops/symbol.cpp b/src/share/vm/oops/symbol.cpp
index 6a8191cbe4f624aa2bc711cfa85412a4ffebbcb0..f2253dbcce0ef0c36acad30767d99bd735f4e09f 100644
--- a/src/share/vm/oops/symbol.cpp
+++ b/src/share/vm/oops/symbol.cpp
@@ -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 {
diff --git a/src/share/vm/oops/symbol.hpp b/src/share/vm/oops/symbol.hpp
index 90ec5c176000421d9cdb17d294bbf8a874d63c2f..55867d2b00753fcc77a741c555cf85b99d3eb097 100644
--- a/src/share/vm/oops/symbol.hpp
+++ b/src/share/vm/oops/symbol.hpp
@@ -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(); }
diff --git a/src/share/vm/opto/bytecodeInfo.cpp b/src/share/vm/opto/bytecodeInfo.cpp
index 1c08a6ebf3b08bb53fdbc567807e4710c824e7c8..80117960dc58cccbe16f66701123200e9c15cda7 100644
--- a/src/share/vm/opto/bytecodeInfo.cpp
+++ b/src/share/vm/opto/bytecodeInfo.cpp
@@ -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() &&
diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp
index aeb62798ba15f312efdde4abd983ce813d5ebc2c..1678053c656a81d3cf4b8caf10cc8e4022e653e3 100644
--- a/src/share/vm/prims/jni.cpp
+++ b/src/share/vm/prims/jni.cpp
@@ -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 {
diff --git a/src/share/vm/prims/jvmtiExport.hpp b/src/share/vm/prims/jvmtiExport.hpp
index 7dcab683149d640423be9a45b2a931a9cb1ba520..1100d5269951b88c84b72d0bba9010ef194031c3 100644
--- a/src/share/vm/prims/jvmtiExport.hpp
+++ b/src/share/vm/prims/jvmtiExport.hpp
@@ -64,6 +64,8 @@ class AttachOperation;
//
class JvmtiExport : public AllStatic {
friend class VMStructs;
+ friend class CompileReplay;
+
private:
#if INCLUDE_JVMTI
diff --git a/src/share/vm/runtime/compilationPolicy.cpp b/src/share/vm/runtime/compilationPolicy.cpp
index 73b8f8393f76197276afd8ee9c50447482f6a856..713163a10010a72afd527cf557422808a612bd3e 100644
--- a/src/share/vm/runtime/compilationPolicy.cpp
+++ b/src/share/vm/runtime/compilationPolicy.cpp
@@ -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
diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
index 62ad97f8958796a939f0cd7e7bf379eea8532153..785965ca3f5107f9098f070d4edf780ec06c8af4 100644
--- a/src/share/vm/runtime/globals.hpp
+++ b/src/share/vm/runtime/globals.hpp
@@ -3189,6 +3189,26 @@ class CommandLineFlags {
product(ccstrlist, CompileCommand, "", \
"Prepend to .hotspot_compiler; e.g. log,java/lang/String.") \
\
+ 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)") \
\
diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp
index eb6d3cd78a80318f9465105e73cabdef22225220..484566125bf3828caf0677b6925e3dce27f0a33f 100644
--- a/src/share/vm/runtime/vmStructs.cpp
+++ b/src/share/vm/runtime/vmStructs.cpp
@@ -993,6 +993,7 @@ typedef BinaryTreeDictionary 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) \
diff --git a/src/share/vm/utilities/array.hpp b/src/share/vm/utilities/array.hpp
index 9690529c5d2f77cbbbc13424aca1006963e7deeb..5578ed9b61f1090ec24579d11ade53e55037832d 100644
--- a/src/share/vm/utilities/array.hpp
+++ b/src/share/vm/utilities/array.hpp
@@ -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)); }
diff --git a/src/share/vm/utilities/utf8.cpp b/src/share/vm/utilities/utf8.cpp
index be7d1881546a355408ce9a17b042bdc68ce1d2a0..da470b18cc0a356012c26f76703617dbe1e9cf65 100644
--- a/src/share/vm/utilities/utf8.cpp
+++ b/src/share/vm/utilities/utf8.cpp
@@ -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';
+}
diff --git a/src/share/vm/utilities/utf8.hpp b/src/share/vm/utilities/utf8.hpp
index c56d550ec9d4c86f6eca8fd964772d45520c77e2..69710fccec4d6718008b3a08118729fc7fb469d8 100644
--- a/src/share/vm/utilities/utf8.hpp
+++ b/src/share/vm/utilities/utf8.hpp
@@ -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
diff --git a/src/share/vm/utilities/vmError.cpp b/src/share/vm/utilities/vmError.cpp
index 175fe382fd7d4fef495b3062873f35ecff8295a0..ddb6e1cf882e31d522f0453a94c760a134964f77 100644
--- a/src/share/vm/utilities/vmError.cpp
+++ b/src/share/vm/utilities/vmError.cpp
@@ -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;