6830717: replay of compilations would help with debugging
authorminqi
Mon, 12 Nov 2012 14:03:53 -0800
changeset 14477 95e66ea71f71
parent 14470 f6651390f4e7
child 14478 1c4a20806af7
6830717: replay of compilations would help with debugging Summary: When java process crashed in compiler thread, repeat the compilation process will help finding root cause. This is done with using SA dump application class data and replay data from core dump, then use debug version of jvm to recompile the problematic java method. Reviewed-by: kvn, twisti, sspitsyn Contributed-by: yumin.qi@oracle.com
hotspot/agent/doc/c2replay.html
hotspot/agent/doc/clhsdb.html
hotspot/agent/doc/index.html
hotspot/agent/make/Makefile
hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Field.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java
hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java
hotspot/src/share/vm/ci/ciClassList.hpp
hotspot/src/share/vm/ci/ciEnv.cpp
hotspot/src/share/vm/ci/ciEnv.hpp
hotspot/src/share/vm/ci/ciInstanceKlass.cpp
hotspot/src/share/vm/ci/ciInstanceKlass.hpp
hotspot/src/share/vm/ci/ciMetadata.hpp
hotspot/src/share/vm/ci/ciMethod.cpp
hotspot/src/share/vm/ci/ciMethod.hpp
hotspot/src/share/vm/ci/ciMethodData.cpp
hotspot/src/share/vm/ci/ciMethodData.hpp
hotspot/src/share/vm/ci/ciObject.hpp
hotspot/src/share/vm/ci/ciObjectFactory.hpp
hotspot/src/share/vm/ci/ciReplay.cpp
hotspot/src/share/vm/ci/ciReplay.hpp
hotspot/src/share/vm/ci/ciSymbol.cpp
hotspot/src/share/vm/ci/ciSymbol.hpp
hotspot/src/share/vm/ci/ciUtilities.hpp
hotspot/src/share/vm/classfile/javaClasses.cpp
hotspot/src/share/vm/classfile/javaClasses.hpp
hotspot/src/share/vm/code/dependencies.cpp
hotspot/src/share/vm/interpreter/invocationCounter.hpp
hotspot/src/share/vm/oops/instanceKlass.cpp
hotspot/src/share/vm/oops/instanceKlass.hpp
hotspot/src/share/vm/oops/symbol.cpp
hotspot/src/share/vm/oops/symbol.hpp
hotspot/src/share/vm/opto/bytecodeInfo.cpp
hotspot/src/share/vm/prims/jni.cpp
hotspot/src/share/vm/prims/jvmtiExport.hpp
hotspot/src/share/vm/runtime/compilationPolicy.cpp
hotspot/src/share/vm/runtime/globals.hpp
hotspot/src/share/vm/runtime/vmStructs.cpp
hotspot/src/share/vm/utilities/array.hpp
hotspot/src/share/vm/utilities/utf8.cpp
hotspot/src/share/vm/utilities/utf8.hpp
hotspot/src/share/vm/utilities/vmError.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/doc/c2replay.html	Mon Nov 12 14:03:53 2012 -0800
@@ -0,0 +1,41 @@
+<html>
+<head>
+<title>
+C2 Replay
+</title>
+</head>
+<body>
+
+<h1>C2 compiler replay</h1>
+<p>
+The C2 compiler replay is a function to repeat the compiling process from a crashed java process in compiled method<br>
+This function only exists in debug version of VM
+</p>
+<h2>Usage</h2>
+<pre> 
+First, use SA to attach to the core file, if suceeded, do
+       clhsdb>dumpreplaydata <address> | -a | <thread_id> [> replay.txt]
+       create file replay.txt, address is address of Method, or nmethod(CodeBlob)
+       clhsdb>buildreplayjars [all | boot | app]
+       create files:
+         all:
+           app.jar, boot.jar
+         boot:
+           boot.jar
+         app:
+           app.jar
+       exit SA now.
+Second, use the obtained replay text file, replay.txt and jar files, app.jar and boot.jar, using debug version of java
+       java -Xbootclasspath/p:boot.jar -cp app.jar -XX:ReplayDataFile=<datafile> -XX:+ReplayCompiles ....
+       This will replay the compiling process.
+
+       With ReplayCompiles, the replay will recompile all the methods in app.jar, and in boot.jar to emulate the process in java app.
+
+notes:
+       1) Most time, we don't need the boot.jar which is the classes loaded from JDK. It will be only modified when an agent(JVMDI) is running and modifies the classes.
+       2) If encounter error as "<flag>" not found, that means the SA is using a VMStructs which is different from the one with corefile. In this case, SA has a utility tool vmstructsdump which is located at agent/src/os/<os>/proc/<os_platform>
+
+       Use this tool to dump VM type library:
+       vmstructsdump libjvm.so > <type_name>.db
+
+       set env SA_TYPEDB=<type_name>.db (refer different shell for set envs)
--- a/hotspot/agent/doc/clhsdb.html	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/doc/clhsdb.html	Mon Nov 12 14:03:53 2012 -0800
@@ -37,12 +37,19 @@
 Available commands:
   assert true | false <font color="red">turn on/off asserts in SA code</font>
   attach pid | exec core  <font color="red">attach SA to a process or core</font>
+  buildreplayjars [all | boot | app] <font color="red">build jars for replay, boot.jar for bootclasses, app.jar for application classes</font>
   class name <font color="red">find a Java class from debuggee and print oop</font>
   classes <font color="red">print all loaded Java classes with Klass*</font>
   detach <font color="red">detach SA from current target</font>
   dis address [ length ]  <font color="red">disassemble (sparc/x86) specified number of instructions from given address</font>
+  dissemble address <font color="red">disassemble nmethod</font>
+  dumpcfg -a | id <font color="red">Dump the PhaseCFG for every compiler thread that has one live</font>
   dumpclass { address | name } [ directory ] <font color="red">dump .class file for given Klass* or class name</font>
+  dumpcodecache <font color="red">dump codecache contents</font>
   dumpheap [ file ] <font color="red">dump heap in hprof binary format</font>
+  dumpideal -a | id <font color="red">dump ideal graph like debug flag -XX:+PrintIdeal</font>
+  dumpilt -a | id <font color="red">dump inline tree for C2 compilation</font>
+  dumpreplaydata <address> | -a | <thread_id> [>replay.txt] <font color="red">dump replay data into a file</font>
   echo [ true | false ] <font color="red">turn on/off command echo mode</font>
   examine [ address/count ] | [ address,address] <font color="red">show contents of memory from given address</font>
   field [ type [ name fieldtype isStatic offset address ] ] <font color="red">print info about a field of HotSpot type</font>
@@ -51,29 +58,35 @@
   help [ command ] <font color="red">print help message for all commands or just given command</font>
   history <font color="red">show command history. usual !command-number syntax works.</font>
   inspect expression <font color="red">inspect a given oop</font>
+  intConstant [ name [ value ] ] <font color="red">print out hotspot integer constant(s)</font>
   jdis address <font color="red">show bytecode disassembly of a given Method*</font>
   jhisto <font color="red">show Java heap histogram</font>
   jseval script <font color="red">evaluate a given string as JavaScript code</font>
   jsload file <font color="red">load and evaluate a JavaScript file</font>
   jstack [-v] <font color="red">show Java stack trace of all Java threads. -v is verbose mode</font>
   livenmethods <font color="red">show all live nmethods</font>
+  longConstant [ name [ value ] ] <font color="red">print out hotspot long constant(s)s</font>
   mem address [ length ] <font color="red">show contents of memory -- also shows closest ELF/COFF symbol if found</font>
   pmap <font color="red">show Solaris pmap-like output</font>
   print expression <font color="red">print given Klass*, Method* or arbitrary address</font>
   printas type expression <font color="red">print given address as given HotSpot type. eg. print JavaThread &lt;address&gt;</font>
+  printmdo -a | expression <font color="red">print method data oop</font>
   printstatics [ type ] <font color="red">print static fields of given HotSpot type (or all types if none specified)</font>
   pstack [-v] <font color="red">show mixed mode stack trace for all Java, non-Java threads. -v is verbose mode</font>
   quit <font color="red">quit CLHSDB tool</font>
   reattach <font color="red">detach and re-attach SA to current target</font>
+  revptrs  <font color="red">find liveness of oops</font>
   scanoops start end [ type ] <font color="red">scan a Oop from given start to end address</font>
   search [ heap | codecache | threads ] value <font color="red">search a value in heap or codecache or threads</font>
   source filename <font color="red">load and execute CLHSDB commands from given file</font>
   symbol name <font color="red">show address of a given ELF/COFF symbol</font>
   sysprops <font color="red">show all Java System properties</font>
+  thread id <font color="red">show thread of id</font>
   threads <font color="red">show all Java threads</font>
   tokenize ...
   type [ type [ name super isOop isInteger isUnsigned size ] ] <font color="red">show info. on HotSpot type</font>
   universe <font color="red">print gc universe</font>
+  vmstructsdump <font color="red">dump hotspot type library in text</font>
   verbose true | false <font color="red">turn on/off verbose mode</font>
   versioncheck [ true | false ] <font color="red">turn on/off debuggee VM version check</font>
   whatis address <font color="red">print info about any arbitrary address</font>
@@ -114,5 +127,11 @@
 </code>
 </pre>
 
+<h3>C2 Compilation Replay</h3>
+<p>
+When a java process crashes in compiled method, usually a core file is saved.
+The C2 replay function can reproduce the compiling process in the core.
+<a href="c2replay.html">c2replay.html</a>
+
 </body>
 </html>
--- a/hotspot/agent/doc/index.html	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/doc/index.html	Mon Nov 12 14:03:53 2012 -0800
@@ -220,6 +220,12 @@
 </tr>
 </table>
 
+<h3>C2 Compilation Replay</h3>
+<p>
+When a java process crashes in compiled method, usually a core file is saved.
+The C2 replay function can reproduce the compiling process in the core.
+<a href="c2replay.html">c2replay.html</a>
+
 <h3>Debugging transported core dumps</h3>
 <p>
 When a core dump is moved from the machine where it was produced to a
--- a/hotspot/agent/make/Makefile	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/make/Makefile	Mon Nov 12 14:03:53 2012 -0800
@@ -58,10 +58,8 @@
 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.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.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_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/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/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/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_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_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 @@
 
 .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 @@
 
 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)/*
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java	Mon Nov 12 14:03:53 2012 -0800
@@ -33,6 +33,7 @@
 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 @@
                 }
             }
         },
+        new Command("dumpreplaydata", "dumpreplaydata { <address > | -a | <thread_id> }", false) {
+            // This is used to dump replay data from ciInstanceKlass, ciMethodData etc
+            // default file name is replay.txt, also if java crashes in compiler
+            // thread, this file will be dumped in error processing.
+            public void doit(Tokens t) {
+                if (t.countTokens() != 1) {
+                    usage();
+                    return;
+                }
+                String name = t.nextToken();
+                Address a = null;
+                try {
+                    a = VM.getVM().getDebugger().parseAddress(name);
+                } catch (NumberFormatException e) { }
+                if (a != null) {
+                    // only nmethod, Method, MethodData and InstanceKlass needed to
+                    // dump replay data
+
+                    CodeBlob cb = VM.getVM().getCodeCache().findBlob(a);
+                    if (cb != null && (cb instanceof NMethod)) {
+                        ((NMethod)cb).dumpReplayData(out);
+                        return;
+                    }
+                    // assume it is Metadata
+                    Metadata meta = Metadata.instantiateWrapperFor(a);
+                    if (meta != null) {
+                        meta.dumpReplayData(out);
+                    } else {
+                        usage();
+                        return;
+                    }
+                }
+                // Not an address
+                boolean all = name.equals("-a");
+                Threads threads = VM.getVM().getThreads();
+                for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                    thread.printThreadIDOn(new PrintStream(bos));
+                    if (all || bos.toString().equals(name)) {
+                        if (thread instanceof CompilerThread) {
+                            CompilerThread ct = (CompilerThread)thread;
+                            ciEnv env = ct.env();
+                            if (env != null) {
+                               env.dumpReplayData(out);
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        new Command("buildreplayjars", "buildreplayjars [ all | app | boot ]  | [ prefix ]", false) {
+            // This is used to dump jar files of all the classes
+            // loaded in the core.  Everything on the bootclasspath
+            // will go in boot.jar and everything else will go in
+            // app.jar.  Then the classes can be loaded by the replay
+            // jvm using -Xbootclasspath/p:boot.jar -cp app.jar. boot.jar usually
+            // not needed, unless changed by jvmti.
+            public void doit(Tokens t) {
+                int tcount = t.countTokens();
+                if (tcount > 2) {
+                    usage();
+                    return;
+                }
+                try {
+                   String prefix = "";
+                   String option = "all"; // default
+                   switch(tcount) {
+                       case 0:
+                           break;
+                       case 1:
+                           option = t.nextToken();
+                           if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") &&
+                               !option.equalsIgnoreCase("root")) {
+                              prefix = option;
+                              option = "all";
+                           }
+                           break;
+                       case 2:
+                           option = t.nextToken();
+                           prefix = t.nextToken();
+                           break;
+                       default:
+                           usage();
+                           return;
+                   }
+                   if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") &&
+                               !option.equalsIgnoreCase("boot")) {
+                       usage();
+                       return;
+                   }
+                   ClassDump cd = new ClassDump();
+                   if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("boot")) {
+                     cd.setClassFilter(new BootFilter());
+                     cd.setJarOutput(prefix + "boot.jar");
+                     cd.run();
+                   }
+                   if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("app")) {
+                     cd.setClassFilter(new NonBootFilter());
+                     cd.setJarOutput(prefix + "app.jar");
+                     cd.run();
+                   }
+                } catch (IOException ioe) {
+                   ioe.printStackTrace();
+                }
+            }
+        },
         new Command("findpc", "findpc address", false) {
             public void doit(Tokens t) {
                 if (t.countTokens() != 1) {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java	Mon Nov 12 14:03:53 2012 -0800
@@ -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 ciBaseObject(Address addr) {
     super(addr);
   }
+
+  public void dumpReplayData(PrintStream out) {
+    out.println("# Unknown ci type " + getAddress().getAddressAt(0));
+  }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java	Mon Nov 12 14:03:53 2012 -0800
@@ -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 ciConstant(Address addr) {
     super(addr);
   }
+
+  public void dumpReplayData(PrintStream out) {
+    // Nothing to be done
+  }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java	Mon Nov 12 14:03:53 2012 -0800
@@ -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 CompileTask task() {
     return new CompileTask(taskField.getValue(this.getAddress()));
   }
+
+  public void dumpReplayData(PrintStream out) {
+    out.println("JvmtiExport can_access_local_variables " +
+                (JvmtiExport.canAccessLocalVariables() ? '1' : '0'));
+    out.println("JvmtiExport can_hotswap_or_post_breakpoint " +
+                (JvmtiExport.canHotswapOrPostBreakpoint() ? '1' : '0'));
+    out.println("JvmtiExport can_post_on_exceptions " +
+                (JvmtiExport.canPostOnExceptions() ? '1' : '0'));
+
+    GrowableArray<ciMetadata> objects = factory().objects();
+    out.println("# " + objects.length() + " ciObject found");
+    for (int i = 0; i < objects.length(); i++) {
+      ciMetadata o = objects.at(i);
+      out.println("# ciMetadata" + i + " @ " + o);
+      o.dumpReplayData(out);
+    }
+    CompileTask task = task();
+    Method method = task.method();
+    int entryBci = task.osrBci();
+    Klass holder = method.getMethodHolder();
+    out.println("compile " + holder.getName().asString() + " " +
+                OopUtilities.escapeString(method.getName().asString()) + " " +
+                method.getSignature().asString() + " " +
+                entryBci);
+  }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java	Mon Nov 12 14:03:53 2012 -0800
@@ -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 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);
+            }
+          }
+        }
+      }
+    }
+  }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java	Mon Nov 12 14:03:53 2012 -0800
@@ -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 @@
     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());
+  }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java	Mon Nov 12 14:03:53 2012 -0800
@@ -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 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();
+  }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java	Mon Nov 12 14:03:53 2012 -0800
@@ -498,6 +498,42 @@
            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
   //
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java	Mon Nov 12 14:03:53 2012 -0800
@@ -56,7 +56,7 @@
   }
 
   public Method method() {
-    Address oh =  methodField.getValue(getAddress()).getAddressAt(0);
+    Address oh =  methodField.getValue(getAddress());
     return (Method)Metadata.instantiateWrapperFor(oh);
   }
 
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java	Mon Nov 12 14:03:53 2012 -0800
@@ -86,7 +86,7 @@
 
 
   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() {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Field.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Field.java	Mon Nov 12 14:03:53 2012 -0800
@@ -110,6 +110,8 @@
   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
   //
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java	Mon Nov 12 14:03:53 2012 -0800
@@ -278,7 +278,7 @@
   }
 
   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 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 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 @@
     }
     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);
+            }
+          }
+        }
+      }
+    }
+  }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java	Mon Nov 12 14:03:53 2012 -0800
@@ -79,4 +79,7 @@
   }
 
   abstract public void printValueOn(PrintStream tty);
+  public void dumpReplayData(PrintStream out) {
+      out.println("# Unknown Metadata");
+  }
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java	Mon Nov 12 14:03:53 2012 -0800
@@ -358,6 +358,25 @@
     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);
   }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java	Mon Nov 12 14:03:53 2012 -0800
@@ -332,4 +332,59 @@
   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();
+  }
 }
--- a/hotspot/src/share/vm/ci/ciClassList.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciClassList.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -106,6 +106,7 @@
 friend class ciArray;                  \
 friend class ciObjArray;               \
 friend class ciMetadata;               \
+friend class ciReplay;                 \
 friend class ciTypeArray;              \
 friend class ciType;                   \
 friend class ciReturnAddress;          \
--- a/hotspot/src/share/vm/ci/ciEnv.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -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 @@
            : !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 @@
   // If memory is low, we stop compiling methods.
   record_method_not_compilable("out of memory");
 }
+
+fileStream* ciEnv::_replay_data_stream = NULL;
+
+void ciEnv::dump_replay_data() {
+  VM_ENTRY_MARK;
+  MutexLocker ml(Compile_lock);
+  if (_replay_data_stream == NULL) {
+    _replay_data_stream = new (ResourceObj::C_HEAP, mtCompiler) fileStream(ReplayDataFile);
+    if (_replay_data_stream == NULL) {
+      fatal(err_msg("Can't open %s for replay data", ReplayDataFile));
+    }
+  }
+  dump_replay_data(_replay_data_stream);
+}
+
+
+void ciEnv::dump_replay_data(outputStream* out) {
+  ASSERT_IN_VM;
+
+#if INCLUDE_JVMTI
+  out->print_cr("JvmtiExport can_access_local_variables %d",     _jvmti_can_access_local_variables);
+  out->print_cr("JvmtiExport can_hotswap_or_post_breakpoint %d", _jvmti_can_hotswap_or_post_breakpoint);
+  out->print_cr("JvmtiExport can_post_on_exceptions %d",         _jvmti_can_post_on_exceptions);
+#endif // INCLUDE_JVMTI
+
+  GrowableArray<ciMetadata*>* objects = _factory->get_ci_metadata();
+  out->print_cr("# %d ciObject found", objects->length());
+  for (int i = 0; i < objects->length(); i++) {
+    objects->at(i)->dump_replay_data(out);
+  }
+  Method* method = task()->method();
+  int entry_bci = task()->osr_bci();
+  // Klass holder = method->method_holder();
+  out->print_cr("compile %s %s %s %d",
+                method->klass_name()->as_quoted_ascii(),
+                method->name()->as_quoted_ascii(),
+                method->signature()->as_quoted_ascii(),
+                entry_bci);
+  out->flush();
+}
--- a/hotspot/src/share/vm/ci/ciEnv.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciEnv.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -46,6 +46,8 @@
   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 @@
 
   // 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
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -561,3 +561,114 @@
   }
   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);
+  }
+}
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -230,6 +230,9 @@
   // 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
--- a/hotspot/src/share/vm/ci/ciMetadata.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciMetadata.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -61,6 +61,7 @@
   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");
--- a/hotspot/src/share/vm/ci/ciMethod.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -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 @@
   }
   if (_interpreter_invocation_count == 0)
     _interpreter_invocation_count = 1;
+  _instructions_size = -1;
+#ifdef ASSERT
+  if (ReplayCompiles) {
+    ciReplay::initialize(this);
+  }
+#endif
 }
 
 
@@ -161,7 +168,8 @@
 #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 @@
 // ------------------------------------------------------------------
 // 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 @@
 // 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 @@
 
 #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
--- a/hotspot/src/share/vm/ci/ciMethod.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -51,6 +51,7 @@
   friend class ciExceptionHandlerStream;
   friend class ciBytecodeStream;
   friend class ciMethodHandle;
+  friend class ciReplay;
 
  private:
   // General method information.
@@ -69,6 +70,7 @@
   int _handler_count;
   int _interpreter_invocation_count;
   int _interpreter_throwout_count;
+  int _instructions_size;
 
   bool _uses_monitors;
   bool _balanced_monitors;
@@ -252,7 +254,6 @@
   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 @@
   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 @@
   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);
--- a/hotspot/src/share/vm/ci/ciMethodData.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciMethodData.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -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 @@
   _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 @@
   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);
--- a/hotspot/src/share/vm/ci/ciMethodData.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciMethodData.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -144,6 +144,7 @@
 
 class ciMethodData : public ciMetadata {
   CI_PACKAGE_ACCESS
+  friend class ciReplay;
 
 private:
   // Size in bytes
@@ -320,6 +321,7 @@
   void print();
   void print_data_on(outputStream* st);
 #endif
+  void dump_replay_data(outputStream* out);
 };
 
 #endif // SHARE_VM_CI_CIMETHODDATA_HPP
--- a/hotspot/src/share/vm/ci/ciObject.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciObject.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -131,6 +131,7 @@
   // 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
--- a/hotspot/src/share/vm/ci/ciObjectFactory.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciObjectFactory.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -137,6 +137,7 @@
 
   ciReturnAddress* get_return_address(int bci);
 
+  GrowableArray<ciMetadata*>* get_ci_metadata() const { return _ci_metadata; }
   // RedefineClasses support
   void metadata_do(void f(Metadata*));
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/ci/ciReplay.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -0,0 +1,942 @@
+/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "ci/ciMethodData.hpp"
+#include "ci/ciReplay.hpp"
+#include "ci/ciUtilities.hpp"
+#include "compiler/compileBroker.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/oopFactory.hpp"
+#include "memory/resourceArea.hpp"
+#include "utilities/copy.hpp"
+
+#ifdef ASSERT
+
+// ciReplay
+
+typedef struct _ciMethodDataRecord {
+  const char* klass;
+  const char* method;
+  const char* signature;
+  int state;
+  int current_mileage;
+  intptr_t* data;
+  int data_length;
+  char* orig_data;
+  int orig_data_length;
+  int oops_length;
+  jobject* oops_handles;
+  int* oops_offsets;
+} ciMethodDataRecord;
+
+typedef struct _ciMethodRecord {
+  const char* klass;
+  const char* method;
+  const char* signature;
+  int instructions_size;
+  int interpreter_invocation_count;
+  int interpreter_throwout_count;
+  int invocation_counter;
+  int backedge_counter;
+} ciMethodRecord;
+
+class CompileReplay;
+static CompileReplay* replay_state;
+
+class CompileReplay : public StackObj {
+ private:
+  FILE*   stream;
+  Thread* thread;
+  Handle  protection_domain;
+  Handle  loader;
+
+  GrowableArray<ciMethodRecord*>     ci_method_records;
+  GrowableArray<ciMethodDataRecord*> ci_method_data_records;
+
+  const char* _error_message;
+
+  char* bufptr;
+  char* buffer;
+  int   buffer_length;
+  int   buffer_end;
+  int   line_no;
+
+ public:
+  CompileReplay(const char* filename, TRAPS) {
+    thread = THREAD;
+    loader = Handle(thread, SystemDictionary::java_system_loader());
+    stream = fopen(filename, "rt");
+    if (stream == NULL) {
+      fprintf(stderr, "Can't open replay file %s\n", filename);
+    }
+    buffer_length = 32;
+    buffer = NEW_RESOURCE_ARRAY(char, buffer_length);
+    _error_message = NULL;
+
+    test();
+  }
+
+  ~CompileReplay() {
+    if (stream != NULL) fclose(stream);
+  }
+
+  void test() {
+    strcpy(buffer, "1 2 foo 4 bar 0x9 \"this is it\"");
+    bufptr = buffer;
+    assert(parse_int("test") == 1, "what");
+    assert(parse_int("test") == 2, "what");
+    assert(strcmp(parse_string(), "foo") == 0, "what");
+    assert(parse_int("test") == 4, "what");
+    assert(strcmp(parse_string(), "bar") == 0, "what");
+    assert(parse_intptr_t("test") == 9, "what");
+    assert(strcmp(parse_quoted_string(), "this is it") == 0, "what");
+  }
+
+  bool had_error() {
+    return _error_message != NULL || thread->has_pending_exception();
+  }
+
+  bool can_replay() {
+    return !(stream == NULL || had_error());
+  }
+
+  void report_error(const char* msg) {
+    _error_message = msg;
+    // Restore the buffer contents for error reporting
+    for (int i = 0; i < buffer_end; i++) {
+      if (buffer[i] == '\0') buffer[i] = ' ';
+    }
+  }
+
+  int parse_int(const char* label) {
+    if (had_error()) {
+      return 0;
+    }
+
+    int v = 0;
+    int read;
+    if (sscanf(bufptr, "%i%n", &v, &read) != 1) {
+      report_error(label);
+    } else {
+      bufptr += read;
+    }
+    return v;
+  }
+
+  intptr_t parse_intptr_t(const char* label) {
+    if (had_error()) {
+      return 0;
+    }
+
+    intptr_t v = 0;
+    int read;
+    if (sscanf(bufptr, INTPTR_FORMAT "%n", &v, &read) != 1) {
+      report_error(label);
+    } else {
+      bufptr += read;
+    }
+    return v;
+  }
+
+  void skip_ws() {
+    // Skip any leading whitespace
+    while (*bufptr == ' ' || *bufptr == '\t') {
+      bufptr++;
+    }
+  }
+
+
+  char* scan_and_terminate(char delim) {
+    char* str = bufptr;
+    while (*bufptr != delim && *bufptr != '\0') {
+      bufptr++;
+    }
+    if (*bufptr != '\0') {
+      *bufptr++ = '\0';
+    }
+    if (bufptr == str) {
+      // nothing here
+      return NULL;
+    }
+    return str;
+  }
+
+  char* parse_string() {
+    if (had_error()) return NULL;
+
+    skip_ws();
+    return scan_and_terminate(' ');
+  }
+
+  char* parse_quoted_string() {
+    if (had_error()) return NULL;
+
+    skip_ws();
+
+    if (*bufptr == '"') {
+      bufptr++;
+      return scan_and_terminate('"');
+    } else {
+      return scan_and_terminate(' ');
+    }
+  }
+
+  const char* parse_escaped_string() {
+    char* result = parse_quoted_string();
+    if (result != NULL) {
+      unescape_string(result);
+    }
+    return result;
+  }
+
+  // Look for the tag 'tag' followed by an
+  bool parse_tag_and_count(const char* tag, int& length) {
+    const char* t = parse_string();
+    if (t == NULL) {
+      return false;
+    }
+
+    if (strcmp(tag, t) != 0) {
+      report_error(tag);
+      return false;
+    }
+    length = parse_int("parse_tag_and_count");
+    return !had_error();
+  }
+
+  // Parse a sequence of raw data encoded as bytes and return the
+  // resulting data.
+  char* parse_data(const char* tag, int& length) {
+    if (!parse_tag_and_count(tag, length)) {
+      return NULL;
+    }
+
+    char * result = NEW_RESOURCE_ARRAY(char, length);
+    for (int i = 0; i < length; i++) {
+      int val = parse_int("data");
+      result[i] = val;
+    }
+    return result;
+  }
+
+  // Parse a standard chunk of data emitted as:
+  //   'tag' <length> # # ...
+  // Where each # is an intptr_t item
+  intptr_t* parse_intptr_data(const char* tag, int& length) {
+    if (!parse_tag_and_count(tag, length)) {
+      return NULL;
+    }
+
+    intptr_t* result = NEW_RESOURCE_ARRAY(intptr_t, length);
+    for (int i = 0; i < length; i++) {
+      skip_ws();
+      intptr_t val = parse_intptr_t("data");
+      result[i] = val;
+    }
+    return result;
+  }
+
+  // Parse a possibly quoted version of a symbol into a symbolOop
+  Symbol* parse_symbol(TRAPS) {
+    const char* str = parse_escaped_string();
+    if (str != NULL) {
+      Symbol* sym = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
+      return sym;
+    }
+    return NULL;
+  }
+
+  // Parse a valid klass name and look it up
+  Klass* parse_klass(TRAPS) {
+    const char* str = parse_escaped_string();
+    Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
+    if (klass_name != NULL) {
+      Klass* k = SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, THREAD);
+      if (HAS_PENDING_EXCEPTION) {
+        oop throwable = PENDING_EXCEPTION;
+        java_lang_Throwable::print(throwable, tty);
+        tty->cr();
+        report_error(str);
+        return NULL;
+      }
+      return k;
+    }
+    return NULL;
+  }
+
+  // Lookup a klass
+  Klass* resolve_klass(const char* klass, TRAPS) {
+    Symbol* klass_name = SymbolTable::lookup(klass, (int)strlen(klass), CHECK_NULL);
+    return SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, CHECK_NULL);
+  }
+
+  // Parse the standard tuple of <klass> <name> <signature>
+  Method* parse_method(TRAPS) {
+    InstanceKlass* k = (InstanceKlass*)parse_klass(CHECK_NULL);
+    Symbol* method_name = parse_symbol(CHECK_NULL);
+    Symbol* method_signature = parse_symbol(CHECK_NULL);
+    Method* m = k->find_method(method_name, method_signature);
+    if (m == NULL) {
+      report_error("can't find method");
+    }
+    return m;
+  }
+
+  // Process each line of the replay file executing each command until
+  // the file ends.
+  void process(TRAPS) {
+    line_no = 1;
+    int pos = 0;
+    int c = getc(stream);
+    while(c != EOF) {
+      if (pos + 1 >= buffer_length) {
+        int newl = buffer_length * 2;
+        char* newb = NEW_RESOURCE_ARRAY(char, newl);
+        memcpy(newb, buffer, pos);
+        buffer = newb;
+        buffer_length = newl;
+      }
+      if (c == '\n') {
+        // null terminate it, reset the pointer and process the line
+        buffer[pos] = '\0';
+        buffer_end = pos++;
+        bufptr = buffer;
+        process_command(CHECK);
+        if (had_error()) {
+          tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message);
+          tty->print_cr("%s", buffer);
+          assert(false, "error");
+          return;
+        }
+        pos = 0;
+        buffer_end = 0;
+        line_no++;
+      } else if (c == '\r') {
+        // skip LF
+      } else {
+        buffer[pos++] = c;
+      }
+      c = getc(stream);
+    }
+  }
+
+  void process_command(TRAPS) {
+    char* cmd = parse_string();
+    if (cmd == NULL) {
+      return;
+    }
+    if (strcmp("#", cmd) == 0) {
+      // ignore
+    } else if (strcmp("compile", cmd) == 0) {
+      process_compile(CHECK);
+    } else if (strcmp("ciMethod", cmd) == 0) {
+      process_ciMethod(CHECK);
+    } else if (strcmp("ciMethodData", cmd) == 0) {
+      process_ciMethodData(CHECK);
+    } else if (strcmp("staticfield", cmd) == 0) {
+      process_staticfield(CHECK);
+    } else if (strcmp("ciInstanceKlass", cmd) == 0) {
+      process_ciInstanceKlass(CHECK);
+    } else if (strcmp("instanceKlass", cmd) == 0) {
+      process_instanceKlass(CHECK);
+#if INCLUDE_JVMTI
+    } else if (strcmp("JvmtiExport", cmd) == 0) {
+      process_JvmtiExport(CHECK);
+#endif // INCLUDE_JVMTI
+    } else {
+      report_error("unknown command");
+    }
+  }
+
+  // compile <klass> <name> <signature> <entry_bci>
+  void process_compile(TRAPS) {
+    // methodHandle method;
+    Method* method = parse_method(CHECK);
+    int entry_bci = parse_int("entry_bci");
+    Klass* k = method->method_holder();
+    ((InstanceKlass*)k)->initialize(THREAD);
+    if (HAS_PENDING_EXCEPTION) {
+      oop throwable = PENDING_EXCEPTION;
+      java_lang_Throwable::print(throwable, tty);
+      tty->cr();
+      if (ReplayIgnoreInitErrors) {
+        CLEAR_PENDING_EXCEPTION;
+        ((InstanceKlass*)k)->set_init_state(InstanceKlass::fully_initialized);
+      } else {
+        return;
+      }
+    }
+    // Make sure the existence of a prior compile doesn't stop this one
+    nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, CompLevel_full_optimization, true) : method->code();
+    if (nm != NULL) {
+      nm->make_not_entrant();
+    }
+    replay_state = this;
+    CompileBroker::compile_method(method, entry_bci, CompLevel_full_optimization,
+                                  methodHandle(), 0, "replay", THREAD);
+    replay_state = NULL;
+    reset();
+  }
+
+  // ciMethod <klass> <name> <signature> <invocation_counter> <backedge_counter> <interpreter_invocation_count> <interpreter_throwout_count> <instructions_size>
+  //
+  //
+  void process_ciMethod(TRAPS) {
+    Method* method = parse_method(CHECK);
+    ciMethodRecord* rec = new_ciMethod(method);
+    rec->invocation_counter = parse_int("invocation_counter");
+    rec->backedge_counter = parse_int("backedge_counter");
+    rec->interpreter_invocation_count = parse_int("interpreter_invocation_count");
+    rec->interpreter_throwout_count = parse_int("interpreter_throwout_count");
+    rec->instructions_size = parse_int("instructions_size");
+  }
+
+  // ciMethodData <klass> <name> <signature> <state> <current mileage> orig <length> # # ... data <length> # # ... oops <length>
+  void process_ciMethodData(TRAPS) {
+    Method* method = parse_method(CHECK);
+    /* jsut copied from Method, to build interpret data*/
+    if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) {
+      return;
+    }
+    // methodOopDesc::build_interpreter_method_data(method, CHECK);
+    {
+      // Grab a lock here to prevent multiple
+      // MethodData*s from being created.
+      MutexLocker ml(MethodData_lock, THREAD);
+      if (method->method_data() == NULL) {
+        ClassLoaderData* loader_data = method->method_holder()->class_loader_data();
+        MethodData* method_data = MethodData::allocate(loader_data, method, CHECK);
+        method->set_method_data(method_data);
+      }
+    }
+
+    // collect and record all the needed information for later
+    ciMethodDataRecord* rec = new_ciMethodData(method);
+    rec->state = parse_int("state");
+    rec->current_mileage = parse_int("current_mileage");
+
+    rec->orig_data = parse_data("orig", rec->orig_data_length);
+    if (rec->orig_data == NULL) {
+      return;
+    }
+    rec->data = parse_intptr_data("data", rec->data_length);
+    if (rec->data == NULL) {
+      return;
+    }
+    if (!parse_tag_and_count("oops", rec->oops_length)) {
+      return;
+    }
+    rec->oops_handles = NEW_RESOURCE_ARRAY(jobject, rec->oops_length);
+    rec->oops_offsets = NEW_RESOURCE_ARRAY(int, rec->oops_length);
+    for (int i = 0; i < rec->oops_length; i++) {
+      int offset = parse_int("offset");
+      if (had_error()) {
+        return;
+      }
+      Klass* k = parse_klass(CHECK);
+      rec->oops_offsets[i] = offset;
+      rec->oops_handles[i] = (jobject)(new KlassHandle(THREAD, k));
+    }
+  }
+
+  // instanceKlass <name>
+  //
+  // Loads and initializes the klass 'name'.  This can be used to
+  // create particular class loading environments
+  void process_instanceKlass(TRAPS) {
+    // just load the referenced class
+    Klass* k = parse_klass(CHECK);
+  }
+
+  // ciInstanceKlass <name> <is_linked> <is_initialized> <length> tag # # # ...
+  //
+  // Load the klass 'name' and link or initialize it.  Verify that the
+  // constant pool is the same length as 'length' and make sure the
+  // constant pool tags are in the same state.
+  void process_ciInstanceKlass(TRAPS) {
+    InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK);
+    int is_linked = parse_int("is_linked");
+    int is_initialized = parse_int("is_initialized");
+    int length = parse_int("length");
+    if (is_initialized) {
+      k->initialize(THREAD);
+      if (HAS_PENDING_EXCEPTION) {
+        oop throwable = PENDING_EXCEPTION;
+        java_lang_Throwable::print(throwable, tty);
+        tty->cr();
+        if (ReplayIgnoreInitErrors) {
+          CLEAR_PENDING_EXCEPTION;
+          k->set_init_state(InstanceKlass::fully_initialized);
+        } else {
+          return;
+        }
+      }
+    } else if (is_linked) {
+      k->link_class(CHECK);
+    }
+    ConstantPool* cp = k->constants();
+    if (length != cp->length()) {
+      report_error("constant pool length mismatch: wrong class files?");
+      return;
+    }
+
+    int parsed_two_word = 0;
+    for (int i = 1; i < length; i++) {
+      int tag = parse_int("tag");
+      if (had_error()) {
+        return;
+      }
+      switch (cp->tag_at(i).value()) {
+        case JVM_CONSTANT_UnresolvedClass: {
+          if (tag == JVM_CONSTANT_Class) {
+            tty->print_cr("Resolving klass %s at %d", cp->unresolved_klass_at(i)->as_utf8(), i);
+            Klass* k = cp->klass_at(i, CHECK);
+          }
+          break;
+        }
+        case JVM_CONSTANT_Long:
+        case JVM_CONSTANT_Double:
+          parsed_two_word = i + 1;
+
+        case JVM_CONSTANT_ClassIndex:
+        case JVM_CONSTANT_StringIndex:
+        case JVM_CONSTANT_String:
+        case JVM_CONSTANT_UnresolvedClassInError:
+        case JVM_CONSTANT_Fieldref:
+        case JVM_CONSTANT_Methodref:
+        case JVM_CONSTANT_InterfaceMethodref:
+        case JVM_CONSTANT_NameAndType:
+        case JVM_CONSTANT_Utf8:
+        case JVM_CONSTANT_Integer:
+        case JVM_CONSTANT_Float:
+          if (tag != cp->tag_at(i).value()) {
+            report_error("tag mismatch: wrong class files?");
+            return;
+          }
+          break;
+
+        case JVM_CONSTANT_Class:
+          if (tag == JVM_CONSTANT_Class) {
+          } else if (tag == JVM_CONSTANT_UnresolvedClass) {
+            tty->print_cr("Warning: entry was unresolved in the replay data");
+          } else {
+            report_error("Unexpected tag");
+            return;
+          }
+          break;
+
+        case 0:
+          if (parsed_two_word == i) continue;
+
+        default:
+          ShouldNotReachHere();
+          break;
+      }
+
+    }
+  }
+
+  // Initialize a class and fill in the value for a static field.
+  // This is useful when the compile was dependent on the value of
+  // static fields but it's impossible to properly rerun the static
+  // initiailizer.
+  void process_staticfield(TRAPS) {
+    InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK);
+
+    if (ReplaySuppressInitializers == 0 ||
+        ReplaySuppressInitializers == 2 && k->class_loader() == NULL) {
+      return;
+    }
+
+    assert(k->is_initialized(), "must be");
+
+    const char* field_name = parse_escaped_string();;
+    const char* field_signature = parse_string();
+    fieldDescriptor fd;
+    Symbol* name = SymbolTable::lookup(field_name, (int)strlen(field_name), CHECK);
+    Symbol* sig = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
+    if (!k->find_local_field(name, sig, &fd) ||
+        !fd.is_static() ||
+        fd.has_initial_value()) {
+      report_error(field_name);
+      return;
+    }
+
+    oop java_mirror = k->java_mirror();
+    if (field_signature[0] == '[') {
+      int length = parse_int("array length");
+      oop value = NULL;
+
+      if (field_signature[1] == '[') {
+        // multi dimensional array
+        ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK);
+        int rank = 0;
+        while (field_signature[rank] == '[') {
+          rank++;
+        }
+        int* dims = NEW_RESOURCE_ARRAY(int, rank);
+        dims[0] = length;
+        for (int i = 1; i < rank; i++) {
+          dims[i] = 1; // These aren't relevant to the compiler
+        }
+        value = kelem->multi_allocate(rank, dims, CHECK);
+      } else {
+        if (strcmp(field_signature, "[B") == 0) {
+          value = oopFactory::new_byteArray(length, CHECK);
+        } else if (strcmp(field_signature, "[Z") == 0) {
+          value = oopFactory::new_boolArray(length, CHECK);
+        } else if (strcmp(field_signature, "[C") == 0) {
+          value = oopFactory::new_charArray(length, CHECK);
+        } else if (strcmp(field_signature, "[S") == 0) {
+          value = oopFactory::new_shortArray(length, CHECK);
+        } else if (strcmp(field_signature, "[F") == 0) {
+          value = oopFactory::new_singleArray(length, CHECK);
+        } else if (strcmp(field_signature, "[D") == 0) {
+          value = oopFactory::new_doubleArray(length, CHECK);
+        } else if (strcmp(field_signature, "[I") == 0) {
+          value = oopFactory::new_intArray(length, CHECK);
+        } else if (strcmp(field_signature, "[J") == 0) {
+          value = oopFactory::new_longArray(length, CHECK);
+        } else if (field_signature[0] == '[' && field_signature[1] == 'L') {
+          KlassHandle kelem = resolve_klass(field_signature + 1, CHECK);
+          value = oopFactory::new_objArray(kelem(), length, CHECK);
+        } else {
+          report_error("unhandled array staticfield");
+        }
+      }
+      java_mirror->obj_field_put(fd.offset(), value);
+    } else {
+      const char* string_value = parse_escaped_string();
+      if (strcmp(field_signature, "I") == 0) {
+        int value = atoi(string_value);
+        java_mirror->int_field_put(fd.offset(), value);
+      } else if (strcmp(field_signature, "B") == 0) {
+        int value = atoi(string_value);
+        java_mirror->byte_field_put(fd.offset(), value);
+      } else if (strcmp(field_signature, "C") == 0) {
+        int value = atoi(string_value);
+        java_mirror->char_field_put(fd.offset(), value);
+      } else if (strcmp(field_signature, "S") == 0) {
+        int value = atoi(string_value);
+        java_mirror->short_field_put(fd.offset(), value);
+      } else if (strcmp(field_signature, "Z") == 0) {
+        int value = atol(string_value);
+        java_mirror->bool_field_put(fd.offset(), value);
+      } else if (strcmp(field_signature, "J") == 0) {
+        jlong value;
+        if (sscanf(string_value, INT64_FORMAT, &value) != 1) {
+          fprintf(stderr, "Error parsing long: %s\n", string_value);
+          return;
+        }
+        java_mirror->long_field_put(fd.offset(), value);
+      } else if (strcmp(field_signature, "F") == 0) {
+        float value = atof(string_value);
+        java_mirror->float_field_put(fd.offset(), value);
+      } else if (strcmp(field_signature, "D") == 0) {
+        double value = atof(string_value);
+        java_mirror->double_field_put(fd.offset(), value);
+      } else if (strcmp(field_signature, "Ljava/lang/String;") == 0) {
+        Handle value = java_lang_String::create_from_str(string_value, CHECK);
+        java_mirror->obj_field_put(fd.offset(), value());
+      } else if (field_signature[0] == 'L') {
+        Symbol* klass_name = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
+        KlassHandle kelem = resolve_klass(field_signature, CHECK);
+        oop value = ((InstanceKlass*)kelem())->allocate_instance(CHECK);
+        java_mirror->obj_field_put(fd.offset(), value);
+      } else {
+        report_error("unhandled staticfield");
+      }
+    }
+  }
+
+#if INCLUDE_JVMTI
+  void process_JvmtiExport(TRAPS) {
+    const char* field = parse_string();
+    bool value = parse_int("JvmtiExport flag") != 0;
+    if (strcmp(field, "can_access_local_variables") == 0) {
+      JvmtiExport::set_can_access_local_variables(value);
+    } else if (strcmp(field, "can_hotswap_or_post_breakpoint") == 0) {
+      JvmtiExport::set_can_hotswap_or_post_breakpoint(value);
+    } else if (strcmp(field, "can_post_on_exceptions") == 0) {
+      JvmtiExport::set_can_post_on_exceptions(value);
+    } else {
+      report_error("Unrecognized JvmtiExport directive");
+    }
+  }
+#endif // INCLUDE_JVMTI
+
+  // Create and initialize a record for a ciMethod
+  ciMethodRecord* new_ciMethod(Method* method) {
+    ciMethodRecord* rec = NEW_RESOURCE_OBJ(ciMethodRecord);
+    rec->klass =  method->method_holder()->name()->as_utf8();
+    rec->method = method->name()->as_utf8();
+    rec->signature = method->signature()->as_utf8();
+    ci_method_records.append(rec);
+    return rec;
+  }
+
+  // Lookup data for a ciMethod
+  ciMethodRecord* find_ciMethodRecord(Method* method) {
+    const char* klass_name =  method->method_holder()->name()->as_utf8();
+    const char* method_name = method->name()->as_utf8();
+    const char* signature = method->signature()->as_utf8();
+    for (int i = 0; i < ci_method_records.length(); i++) {
+      ciMethodRecord* rec = ci_method_records.at(i);
+      if (strcmp(rec->klass, klass_name) == 0 &&
+          strcmp(rec->method, method_name) == 0 &&
+          strcmp(rec->signature, signature) == 0) {
+        return rec;
+      }
+    }
+    return NULL;
+  }
+
+  // Create and initialize a record for a ciMethodData
+  ciMethodDataRecord* new_ciMethodData(Method* method) {
+    ciMethodDataRecord* rec = NEW_RESOURCE_OBJ(ciMethodDataRecord);
+    rec->klass =  method->method_holder()->name()->as_utf8();
+    rec->method = method->name()->as_utf8();
+    rec->signature = method->signature()->as_utf8();
+    ci_method_data_records.append(rec);
+    return rec;
+  }
+
+  // Lookup data for a ciMethodData
+  ciMethodDataRecord* find_ciMethodDataRecord(Method* method) {
+    const char* klass_name =  method->method_holder()->name()->as_utf8();
+    const char* method_name = method->name()->as_utf8();
+    const char* signature = method->signature()->as_utf8();
+    for (int i = 0; i < ci_method_data_records.length(); i++) {
+      ciMethodDataRecord* rec = ci_method_data_records.at(i);
+      if (strcmp(rec->klass, klass_name) == 0 &&
+          strcmp(rec->method, method_name) == 0 &&
+          strcmp(rec->signature, signature) == 0) {
+        return rec;
+      }
+    }
+    return NULL;
+  }
+
+  const char* error_message() {
+    return _error_message;
+  }
+
+  void reset() {
+    _error_message = NULL;
+    ci_method_records.clear();
+    ci_method_data_records.clear();
+  }
+
+  // Take an ascii string contain \u#### escapes and convert it to utf8
+  // in place.
+  static void unescape_string(char* value) {
+    char* from = value;
+    char* to = value;
+    while (*from != '\0') {
+      if (*from != '\\') {
+        *from++ = *to++;
+      } else {
+        switch (from[1]) {
+          case 'u': {
+            from += 2;
+            jchar value=0;
+            for (int i=0; i<4; i++) {
+              char c = *from++;
+              switch (c) {
+                case '0': case '1': case '2': case '3': case '4':
+                case '5': case '6': case '7': case '8': case '9':
+                  value = (value << 4) + c - '0';
+                  break;
+                case 'a': case 'b': case 'c':
+                case 'd': case 'e': case 'f':
+                  value = (value << 4) + 10 + c - 'a';
+                  break;
+                case 'A': case 'B': case 'C':
+                case 'D': case 'E': case 'F':
+                  value = (value << 4) + 10 + c - 'A';
+                  break;
+                default:
+                  ShouldNotReachHere();
+              }
+            }
+            UNICODE::convert_to_utf8(&value, 1, to);
+            to++;
+            break;
+          }
+          case 't': *to++ = '\t'; from += 2; break;
+          case 'n': *to++ = '\n'; from += 2; break;
+          case 'r': *to++ = '\r'; from += 2; break;
+          case 'f': *to++ = '\f'; from += 2; break;
+          default:
+            ShouldNotReachHere();
+        }
+      }
+    }
+    *from = *to;
+  }
+};
+
+void ciReplay::replay(TRAPS) {
+  int exit_code = replay_impl(THREAD);
+
+  Threads::destroy_vm();
+
+  vm_exit(exit_code);
+}
+
+int ciReplay::replay_impl(TRAPS) {
+  HandleMark hm;
+  ResourceMark rm;
+  // Make sure we don't run with background compilation
+  BackgroundCompilation = false;
+
+  if (ReplaySuppressInitializers > 2) {
+    // ReplaySuppressInitializers > 2 means that we want to allow
+    // normal VM bootstrap but once we get into the replay itself
+    // don't allow any intializers to be run.
+    ReplaySuppressInitializers = 1;
+  }
+
+  // Load and parse the replay data
+  CompileReplay rp(ReplayDataFile, THREAD);
+  int exit_code = 0;
+  if (rp.can_replay()) {
+    rp.process(THREAD);
+  } else {
+    exit_code = 1;
+    return exit_code;
+  }
+
+  if (HAS_PENDING_EXCEPTION) {
+    oop throwable = PENDING_EXCEPTION;
+    CLEAR_PENDING_EXCEPTION;
+    java_lang_Throwable::print(throwable, tty);
+    tty->cr();
+    java_lang_Throwable::print_stack_trace(throwable, tty);
+    tty->cr();
+    exit_code = 2;
+  }
+
+  if (rp.had_error()) {
+    tty->print_cr("Failed on %s", rp.error_message());
+    exit_code = 1;
+  }
+  return exit_code;
+}
+
+
+void ciReplay::initialize(ciMethodData* m) {
+  if (replay_state == NULL) {
+    return;
+  }
+
+  ASSERT_IN_VM;
+  ResourceMark rm;
+
+  Method* method = m->get_MethodData()->method();
+  ciMethodDataRecord* rec = replay_state->find_ciMethodDataRecord(method);
+  if (rec == NULL) {
+    // This indicates some mismatch with the original environment and
+    // the replay environment though it's not always enough to
+    // interfere with reproducing a bug
+    tty->print_cr("Warning: requesting ciMethodData record for method with no data: ");
+    method->print_name(tty);
+    tty->cr();
+  } else {
+    m->_state = rec->state;
+    m->_current_mileage = rec->current_mileage;
+    if (rec->data_length != 0) {
+      assert(m->_data_size == rec->data_length * (int)sizeof(rec->data[0]), "must agree");
+
+      // Write the correct ciObjects back into the profile data
+      ciEnv* env = ciEnv::current();
+      for (int i = 0; i < rec->oops_length; i++) {
+        KlassHandle *h = (KlassHandle *)rec->oops_handles[i];
+        *(ciMetadata**)(rec->data + rec->oops_offsets[i]) =
+          env->get_metadata((*h)());
+      }
+      // Copy the updated profile data into place as intptr_ts
+#ifdef _LP64
+      Copy::conjoint_jlongs_atomic((jlong *)rec->data, (jlong *)m->_data, rec->data_length);
+#else
+      Copy::conjoint_jints_atomic((jint *)rec->data, (jint *)m->_data, rec->data_length);
+#endif
+    }
+
+    // copy in the original header
+    Copy::conjoint_jbytes(rec->orig_data, (char*)&m->_orig, rec->orig_data_length);
+  }
+}
+
+
+bool ciReplay::should_not_inline(ciMethod* method) {
+  if (replay_state == NULL) {
+    return false;
+  }
+
+  VM_ENTRY_MARK;
+  // ciMethod without a record shouldn't be inlined.
+  return replay_state->find_ciMethodRecord(method->get_Method()) == NULL;
+}
+
+
+void ciReplay::initialize(ciMethod* m) {
+  if (replay_state == NULL) {
+    return;
+  }
+
+  ASSERT_IN_VM;
+  ResourceMark rm;
+
+  Method* method = m->get_Method();
+  ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
+  if (rec == NULL) {
+    // This indicates some mismatch with the original environment and
+    // the replay environment though it's not always enough to
+    // interfere with reproducing a bug
+    tty->print_cr("Warning: requesting ciMethod record for method with no data: ");
+    method->print_name(tty);
+    tty->cr();
+  } else {
+    // m->_instructions_size = rec->instructions_size;
+    m->_instructions_size = -1;
+    m->_interpreter_invocation_count = rec->interpreter_invocation_count;
+    m->_interpreter_throwout_count = rec->interpreter_throwout_count;
+    method->invocation_counter()->_counter = rec->invocation_counter;
+    method->backedge_counter()->_counter = rec->backedge_counter;
+  }
+}
+
+bool ciReplay::is_loaded(Method* method) {
+  if (replay_state == NULL) {
+    return true;
+  }
+
+  ASSERT_IN_VM;
+  ResourceMark rm;
+
+  ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
+  return rec != NULL;
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/ci/ciReplay.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -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
--- a/hotspot/src/share/vm/ci/ciSymbol.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciSymbol.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -63,6 +63,11 @@
   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() {
--- a/hotspot/src/share/vm/ci/ciSymbol.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciSymbol.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -73,6 +73,9 @@
   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);
 
--- a/hotspot/src/share/vm/ci/ciUtilities.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciUtilities.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -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);                                       \
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -348,6 +348,22 @@
   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.
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -154,6 +154,8 @@
   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.
--- a/hotspot/src/share/vm/code/dependencies.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/code/dependencies.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -569,6 +569,7 @@
 
 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++) {
--- a/hotspot/src/share/vm/interpreter/invocationCounter.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/interpreter/invocationCounter.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -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 @@
   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; }
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -1052,6 +1052,13 @@
 }
 
 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) {
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -133,6 +133,7 @@
 class InstanceKlass: public Klass {
   friend class VMStructs;
   friend class ClassFileParser;
+  friend class CompileReplay;
 
  protected:
   // Constructor
--- a/hotspot/src/share/vm/oops/symbol.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/oops/symbol.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -153,17 +153,15 @@
 
 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 {
--- a/hotspot/src/share/vm/oops/symbol.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/oops/symbol.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -189,6 +189,8 @@
   // 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(); }
--- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -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 @@
   } 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 @@
     }
 
     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 @@
   // 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 @@
     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() &&
--- a/hotspot/src/share/vm/prims/jni.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/prims/jni.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -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 @@
 
     // 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 {
--- a/hotspot/src/share/vm/prims/jvmtiExport.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiExport.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -64,6 +64,8 @@
 //
 class JvmtiExport : public AllStatic {
   friend class VMStructs;
+  friend class CompileReplay;
+
  private:
 
 #if INCLUDE_JVMTI
--- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -97,6 +97,9 @@
 // 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 @@
       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
--- a/hotspot/src/share/vm/runtime/globals.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -3189,6 +3189,26 @@
   product(ccstrlist, CompileCommand, "",                                    \
           "Prepend to .hotspot_compiler; e.g. log,java/lang/String.<init>") \
                                                                             \
+  develop(bool, ReplayCompiles, false,                                      \
+          "Enable replay of compilations from ReplayDataFile")              \
+                                                                            \
+  develop(ccstr, ReplayDataFile, "replay.txt",                              \
+          "file containing compilation replay information")                 \
+                                                                            \
+  develop(intx, ReplaySuppressInitializers, 2,                              \
+          "Controls handling of class initialization during replay"         \
+          "0 - don't do anything special"                                   \
+          "1 - treat all class initializers as empty"                       \
+          "2 - treat class initializers for application classes as empty"   \
+          "3 - allow all class initializers to run during bootstrap but"    \
+          "    pretend they are empty after starting replay")               \
+                                                                            \
+  develop(bool, ReplayIgnoreInitErrors, false,                              \
+          "Ignore exceptions thrown during initialization for replay")      \
+                                                                            \
+  develop(bool, DumpReplayDataOnError, true,                                \
+          "record replay data for crashing compiler threads")               \
+                                                                            \
   product(bool, CICompilerCountPerCPU, false,                               \
           "1 compiler thread for log(N CPUs)")                              \
                                                                             \
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -993,6 +993,7 @@
                                                                                                                                      \
  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)                                                                                       \
--- a/hotspot/src/share/vm/utilities/array.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/utilities/array.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -353,9 +353,9 @@
   // 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)); }
--- a/hotspot/src/share/vm/utilities/utf8.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/utilities/utf8.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -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 @@
 
 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 @@
   }
 }
 
+// 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 @@
   }
   *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';
+}
--- a/hotspot/src/share/vm/utilities/utf8.hpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/utilities/utf8.hpp	Mon Nov 12 14:03:53 2012 -0800
@@ -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 @@
   // 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
--- a/hotspot/src/share/vm/utilities/vmError.cpp	Fri Nov 09 08:36:17 2012 -0800
+++ b/hotspot/src/share/vm/utilities/vmError.cpp	Mon Nov 12 14:03:53 2012 -0800
@@ -1009,6 +1009,15 @@
     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;