提交 ae4113ff 编写于 作者: N neliasso

Merge

<html>
<head>
<title>
C2 Replay
</title>
</head>
<body>
<h1>C2 compiler replay</h1>
<p>
The C2 compiler replay is a function to repeat the compiling process from a crashed java process in compiled method<br>
This function only exists in debug version of VM
</p>
<h2>Usage</h2>
<pre>
First, use SA to attach to the core file, if suceeded, do
clhsdb>dumpreplaydata <address> | -a | <thread_id> [> replay.txt]
create file replay.txt, address is address of Method, or nmethod(CodeBlob)
clhsdb>buildreplayjars [all | boot | app]
create files:
all:
app.jar, boot.jar
boot:
boot.jar
app:
app.jar
exit SA now.
Second, use the obtained replay text file, replay.txt and jar files, app.jar and boot.jar, using debug version of java
java -Xbootclasspath/p:boot.jar -cp app.jar -XX:ReplayDataFile=<datafile> -XX:+ReplayCompiles ....
This will replay the compiling process.
With ReplayCompiles, the replay will recompile all the methods in app.jar, and in boot.jar to emulate the process in java app.
notes:
1) Most time, we don't need the boot.jar which is the classes loaded from JDK. It will be only modified when an agent(JVMDI) is running and modifies the classes.
2) If encounter error as "<flag>" not found, that means the SA is using a VMStructs which is different from the one with corefile. In this case, SA has a utility tool vmstructsdump which is located at agent/src/os/<os>/proc/<os_platform>
Use this tool to dump VM type library:
vmstructsdump libjvm.so > <type_name>.db
set env SA_TYPEDB=<type_name>.db (refer different shell for set envs)
......@@ -37,12 +37,19 @@ Each CLHSDB command can have zero or more arguments and optionally end with outp
Available commands:
assert true | false <font color="red">turn on/off asserts in SA code</font>
attach pid | exec core <font color="red">attach SA to a process or core</font>
buildreplayjars [all | boot | app] <font color="red">build jars for replay, boot.jar for bootclasses, app.jar for application classes</font>
class name <font color="red">find a Java class from debuggee and print oop</font>
classes <font color="red">print all loaded Java classes with Klass*</font>
detach <font color="red">detach SA from current target</font>
dis address [ length ] <font color="red">disassemble (sparc/x86) specified number of instructions from given address</font>
dissemble address <font color="red">disassemble nmethod</font>
dumpcfg -a | id <font color="red">Dump the PhaseCFG for every compiler thread that has one live</font>
dumpclass { address | name } [ directory ] <font color="red">dump .class file for given Klass* or class name</font>
dumpcodecache <font color="red">dump codecache contents</font>
dumpheap [ file ] <font color="red">dump heap in hprof binary format</font>
dumpideal -a | id <font color="red">dump ideal graph like debug flag -XX:+PrintIdeal</font>
dumpilt -a | id <font color="red">dump inline tree for C2 compilation</font>
dumpreplaydata <address> | -a | <thread_id> [>replay.txt] <font color="red">dump replay data into a file</font>
echo [ true | false ] <font color="red">turn on/off command echo mode</font>
examine [ address/count ] | [ address,address] <font color="red">show contents of memory from given address</font>
field [ type [ name fieldtype isStatic offset address ] ] <font color="red">print info about a field of HotSpot type</font>
......@@ -51,29 +58,35 @@ Available commands:
help [ command ] <font color="red">print help message for all commands or just given command</font>
history <font color="red">show command history. usual !command-number syntax works.</font>
inspect expression <font color="red">inspect a given oop</font>
intConstant [ name [ value ] ] <font color="red">print out hotspot integer constant(s)</font>
jdis address <font color="red">show bytecode disassembly of a given Method*</font>
jhisto <font color="red">show Java heap histogram</font>
jseval script <font color="red">evaluate a given string as JavaScript code</font>
jsload file <font color="red">load and evaluate a JavaScript file</font>
jstack [-v] <font color="red">show Java stack trace of all Java threads. -v is verbose mode</font>
livenmethods <font color="red">show all live nmethods</font>
longConstant [ name [ value ] ] <font color="red">print out hotspot long constant(s)s</font>
mem address [ length ] <font color="red">show contents of memory -- also shows closest ELF/COFF symbol if found</font>
pmap <font color="red">show Solaris pmap-like output</font>
print expression <font color="red">print given Klass*, Method* or arbitrary address</font>
printas type expression <font color="red">print given address as given HotSpot type. eg. print JavaThread &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 @@ hsdb&gt; jsload test.js
</code>
</pre>
<h3>C2 Compilation Replay</h3>
<p>
When a java process crashes in compiled method, usually a core file is saved.
The C2 replay function can reproduce the compiling process in the core.
<a href="c2replay.html">c2replay.html</a>
</body>
</html>
......@@ -220,6 +220,12 @@ These scripts are used to run SA remotely.
</tr>
</table>
<h3>C2 Compilation Replay</h3>
<p>
When a java process crashes in compiled method, usually a core file is saved.
The C2 replay function can reproduce the compiling process in the core.
<a href="c2replay.html">c2replay.html</a>
<h3>Debugging transported core dumps</h3>
<p>
When a core dump is moved from the machine where it was produced to a
......
......@@ -58,10 +58,8 @@ sun.jvm.hotspot.debugger.cdbg.basic \
sun.jvm.hotspot.debugger.cdbg.basic.amd64 \
sun.jvm.hotspot.debugger.cdbg.basic.x86 \
sun.jvm.hotspot.debugger.dummy \
sun.jvm.hotspot.debugger.ia64 \
sun.jvm.hotspot.debugger.linux \
sun.jvm.hotspot.debugger.linux.amd64 \
sun.jvm.hotspot.debugger.linux.ia64 \
sun.jvm.hotspot.debugger.linux.x86 \
sun.jvm.hotspot.debugger.posix \
sun.jvm.hotspot.debugger.posix.elf \
......@@ -77,7 +75,6 @@ sun.jvm.hotspot.debugger.sparc \
sun.jvm.hotspot.debugger.win32.coff \
sun.jvm.hotspot.debugger.windbg \
sun.jvm.hotspot.debugger.windbg.amd64 \
sun.jvm.hotspot.debugger.windbg.ia64 \
sun.jvm.hotspot.debugger.windbg.x86 \
sun.jvm.hotspot.debugger.x86 \
sun.jvm.hotspot.gc_implementation \
......@@ -97,10 +94,8 @@ sun.jvm.hotspot.runtime.amd64 \
sun.jvm.hotspot.runtime.bsd \
sun.jvm.hotspot.runtime.bsd_amd64 \
sun.jvm.hotspot.runtime.bsd_x86 \
sun.jvm.hotspot.runtime.ia64 \
sun.jvm.hotspot.runtime.linux \
sun.jvm.hotspot.runtime.linux_amd64 \
sun.jvm.hotspot.runtime.linux_ia64 \
sun.jvm.hotspot.runtime.linux_sparc \
sun.jvm.hotspot.runtime.linux_x86 \
sun.jvm.hotspot.runtime.posix \
......@@ -109,7 +104,6 @@ sun.jvm.hotspot.runtime.solaris_sparc \
sun.jvm.hotspot.runtime.solaris_x86 \
sun.jvm.hotspot.runtime.sparc \
sun.jvm.hotspot.runtime.win32_amd64 \
sun.jvm.hotspot.runtime.win32_ia64 \
sun.jvm.hotspot.runtime.win32_x86 \
sun.jvm.hotspot.runtime.x86 \
sun.jvm.hotspot.tools \
......@@ -152,7 +146,6 @@ sun/jvm/hotspot/debugger/cdbg/basic/*.java \
sun/jvm/hotspot/debugger/cdbg/basic/amd64/*.java \
sun/jvm/hotspot/debugger/cdbg/basic/x86/*.java \
sun/jvm/hotspot/debugger/dummy/*.java \
sun/jvm/hotspot/debugger/ia64/*.java \
sun/jvm/hotspot/debugger/linux/*.java \
sun/jvm/hotspot/debugger/linux/x86/*.java \
sun/jvm/hotspot/debugger/posix/*.java \
......@@ -168,7 +161,6 @@ sun/jvm/hotspot/debugger/remote/x86/*.java \
sun/jvm/hotspot/debugger/sparc/*.java \
sun/jvm/hotspot/debugger/win32/coff/*.java \
sun/jvm/hotspot/debugger/windbg/*.java \
sun/jvm/hotspot/debugger/windbg/ia64/*.java \
sun/jvm/hotspot/debugger/windbg/x86/*.java \
sun/jvm/hotspot/debugger/x86/*.java \
sun/jvm/hotspot/gc_implementation/g1/*.java \
......@@ -186,10 +178,8 @@ sun/jvm/hotspot/runtime/amd64/*.java \
sun/jvm/hotspot/runtime/bsd/*.java \
sun/jvm/hotspot/runtime/bsd_amd64/*.java \
sun/jvm/hotspot/runtime/bsd_x86/*.java \
sun/jvm/hotspot/runtime/ia64/*.java \
sun/jvm/hotspot/runtime/linux/*.java \
sun/jvm/hotspot/runtime/linux_amd64/*.java \
sun/jvm/hotspot/runtime/linux_ia64/*.java \
sun/jvm/hotspot/runtime/linux_sparc/*.java \
sun/jvm/hotspot/runtime/linux_x86/*.java \
sun/jvm/hotspot/runtime/posix/*.java \
......@@ -198,7 +188,6 @@ sun/jvm/hotspot/runtime/solaris_sparc/*.java \
sun/jvm/hotspot/runtime/solaris_x86/*.java \
sun/jvm/hotspot/runtime/sparc/*.java \
sun/jvm/hotspot/runtime/win32_amd64/*.java \
sun/jvm/hotspot/runtime/win32_ia64/*.java \
sun/jvm/hotspot/runtime/win32_x86/*.java \
sun/jvm/hotspot/runtime/x86/*.java \
sun/jvm/hotspot/tools/*.java \
......@@ -258,6 +247,7 @@ SA_BUILD_VERSION_PROP = "sun.jvm.hotspot.runtime.VM.saBuildVersion=$(SA_BUILD_VE
SA_PROPERTIES = $(OUTPUT_DIR)/sa.properties
JAVAC = $(JDK_HOME)/bin/javac
JAVA = $(JDK_HOME)/bin/java
JAVADOC = $(JDK_HOME)/bin/javadoc
RMIC = $(JDK_HOME)/bin/rmic
......@@ -298,7 +288,7 @@ filelist: $(ALLFILES)
.PHONY: natives
natives:
cd ../src/os/`java -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) all
cd ../src/os/`$(JAVA) -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) all
.PHONY: sa-jdi.jar
sa-jdi.jar:
......@@ -323,5 +313,5 @@ sa.jar:
clean::
rm -rf filelist
cd ../src/os/`java -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) clean
cd ../src/os/`$(JAVA) -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) clean
rm -rf $(BUILD_DIR)/*
......@@ -33,6 +33,7 @@ import sun.jvm.hotspot.types.Type;
import sun.jvm.hotspot.types.Field;
import sun.jvm.hotspot.HotSpotTypeDataBase;
import sun.jvm.hotspot.types.basic.BasicType;
import sun.jvm.hotspot.types.basic.BasicTypeDataBase;
import sun.jvm.hotspot.types.CIntegerType;
import sun.jvm.hotspot.code.*;
import sun.jvm.hotspot.compiler.*;
......@@ -448,6 +449,112 @@ public class CommandProcessor {
}
}
},
new Command("dumpreplaydata", "dumpreplaydata { <address > | -a | <thread_id> }", false) {
// This is used to dump replay data from ciInstanceKlass, ciMethodData etc
// default file name is replay.txt, also if java crashes in compiler
// thread, this file will be dumped in error processing.
public void doit(Tokens t) {
if (t.countTokens() != 1) {
usage();
return;
}
String name = t.nextToken();
Address a = null;
try {
a = VM.getVM().getDebugger().parseAddress(name);
} catch (NumberFormatException e) { }
if (a != null) {
// only nmethod, Method, MethodData and InstanceKlass needed to
// dump replay data
CodeBlob cb = VM.getVM().getCodeCache().findBlob(a);
if (cb != null && (cb instanceof NMethod)) {
((NMethod)cb).dumpReplayData(out);
return;
}
// assume it is Metadata
Metadata meta = Metadata.instantiateWrapperFor(a);
if (meta != null) {
meta.dumpReplayData(out);
} else {
usage();
return;
}
}
// Not an address
boolean all = name.equals("-a");
Threads threads = VM.getVM().getThreads();
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
if (thread instanceof CompilerThread) {
CompilerThread ct = (CompilerThread)thread;
ciEnv env = ct.env();
if (env != null) {
env.dumpReplayData(out);
}
}
}
}
}
},
new Command("buildreplayjars", "buildreplayjars [ all | app | boot ] | [ prefix ]", false) {
// This is used to dump jar files of all the classes
// loaded in the core. Everything on the bootclasspath
// will go in boot.jar and everything else will go in
// app.jar. Then the classes can be loaded by the replay
// jvm using -Xbootclasspath/p:boot.jar -cp app.jar. boot.jar usually
// not needed, unless changed by jvmti.
public void doit(Tokens t) {
int tcount = t.countTokens();
if (tcount > 2) {
usage();
return;
}
try {
String prefix = "";
String option = "all"; // default
switch(tcount) {
case 0:
break;
case 1:
option = t.nextToken();
if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") &&
!option.equalsIgnoreCase("root")) {
prefix = option;
option = "all";
}
break;
case 2:
option = t.nextToken();
prefix = t.nextToken();
break;
default:
usage();
return;
}
if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") &&
!option.equalsIgnoreCase("boot")) {
usage();
return;
}
ClassDump cd = new ClassDump();
if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("boot")) {
cd.setClassFilter(new BootFilter());
cd.setJarOutput(prefix + "boot.jar");
cd.run();
}
if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("app")) {
cd.setClassFilter(new NonBootFilter());
cd.setJarOutput(prefix + "app.jar");
cd.run();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
},
new Command("findpc", "findpc address", false) {
public void doit(Tokens t) {
if (t.countTokens() != 1) {
......
......@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
......@@ -50,4 +50,8 @@ public class ciBaseObject extends VMObject {
public ciBaseObject(Address addr) {
super(addr);
}
public void dumpReplayData(PrintStream out) {
out.println("# Unknown ci type " + getAddress().getAddressAt(0));
}
}
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
......@@ -60,4 +60,8 @@ public class ciConstant extends VMObject {
public ciConstant(Address addr) {
super(addr);
}
public void dumpReplayData(PrintStream out) {
// Nothing to be done
}
}
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
......@@ -74,4 +74,29 @@ public class ciEnv extends VMObject {
public CompileTask task() {
return new CompileTask(taskField.getValue(this.getAddress()));
}
public void dumpReplayData(PrintStream out) {
out.println("JvmtiExport can_access_local_variables " +
(JvmtiExport.canAccessLocalVariables() ? '1' : '0'));
out.println("JvmtiExport can_hotswap_or_post_breakpoint " +
(JvmtiExport.canHotswapOrPostBreakpoint() ? '1' : '0'));
out.println("JvmtiExport can_post_on_exceptions " +
(JvmtiExport.canPostOnExceptions() ? '1' : '0'));
GrowableArray<ciMetadata> objects = factory().objects();
out.println("# " + objects.length() + " ciObject found");
for (int i = 0; i < objects.length(); i++) {
ciMetadata o = objects.at(i);
out.println("# ciMetadata" + i + " @ " + o);
o.dumpReplayData(out);
}
CompileTask task = task();
Method method = task.method();
int entryBci = task.osrBci();
Klass holder = method.getMethodHolder();
out.println("compile " + holder.getName().asString() + " " +
OopUtilities.escapeString(method.getName().asString()) + " " +
method.getSignature().asString() + " " +
entryBci);
}
}
......@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
......@@ -80,4 +80,84 @@ public class ciInstanceKlass extends ciKlass {
public boolean isInitialized() {
return initState() == CLASS_STATE_FULLY_INITIALIZED;
}
public void dumpReplayData(PrintStream out) {
InstanceKlass ik = (InstanceKlass)getMetadata();
ConstantPool cp = ik.getConstants();
// Try to record related loaded classes
Klass sub = ik.getSubklassKlass();
while (sub != null) {
if (sub instanceof InstanceKlass) {
out.println("instanceKlass " + sub.getName().asString());
}
sub = sub.getNextSiblingKlass();
}
final int length = (int) cp.getLength();
out.print("ciInstanceKlass " + name() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
for (int index = 1; index < length; index++) {
out.print(" " + cp.getTags().at(index));
}
out.println();
if (isInitialized()) {
Field[] staticFields = ik.getStaticFields();
for (int i = 0; i < staticFields.length; i++) {
Field f = staticFields[i];
Oop mirror = ik.getJavaMirror();
if (f.isFinal() && !f.hasInitialValue()) {
out.print("staticfield " + name() + " " +
OopUtilities.escapeString(f.getID().getName()) + " " +
f.getFieldType().getSignature().asString() + " ");
if (f instanceof ByteField) {
ByteField bf = (ByteField)f;
out.println(bf.getValue(mirror));
} else if (f instanceof BooleanField) {
BooleanField bf = (BooleanField)f;
out.println(bf.getValue(mirror) ? 1 : 0);
} else if (f instanceof ShortField) {
ShortField bf = (ShortField)f;
out.println(bf.getValue(mirror));
} else if (f instanceof CharField) {
CharField bf = (CharField)f;
out.println(bf.getValue(mirror) & 0xffff);
} else if (f instanceof IntField) {
IntField bf = (IntField)f;
out.println(bf.getValue(mirror));
} else if (f instanceof LongField) {
LongField bf = (LongField)f;
out.println(bf.getValue(mirror));
} else if (f instanceof FloatField) {
FloatField bf = (FloatField)f;
out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
} else if (f instanceof DoubleField) {
DoubleField bf = (DoubleField)f;
out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
} else if (f instanceof OopField) {
OopField bf = (OopField)f;
Oop value = bf.getValue(mirror);
if (value == null) {
out.println("null");
} else if (value.isInstance()) {
Instance inst = (Instance)value;
if (inst.isA(SystemDictionary.getStringKlass())) {
out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
} else {
out.println(inst.getKlass().getName().asString());
}
} else if (value.isObjArray()) {
ObjArray oa = (ObjArray)value;
Klass ek = (ObjArrayKlass)oa.getKlass();
out.println(oa.getLength() + " " + ek.getName().asString());
} else if (value.isTypeArray()) {
TypeArray ta = (TypeArray)value;
out.println(ta.getLength());
} else {
out.println(value);
}
}
}
}
}
}
}
......@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
......@@ -88,4 +88,19 @@ public class ciMethod extends ciMetadata {
st.printf(" %s::%s", method.getMethodHolder().getName().asString().replace('/', '.'),
method.getName().asString());
}
public void dumpReplayData(PrintStream out) {
Method method = (Method)getMetadata();
NMethod nm = method.getNativeMethod();
Klass holder = method.getMethodHolder();
out.println("ciMethod " +
holder.getName().asString() + " " +
OopUtilities.escapeString(method.getName().asString()) + " " +
method.getSignature().asString() + " " +
method.getInvocationCounter() + " " +
method.getBackedgeCounter() + " " +
interpreterInvocationCount() + " " +
interpreterThrowoutCount() + " " +
instructionsSize());
}
}
......@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
......@@ -174,4 +174,52 @@ public class ciMethodData extends ciMetadata {
}
}
public void dumpReplayData(PrintStream out) {
MethodData mdo = (MethodData)getMetadata();
Method method = mdo.getMethod();
Klass holder = method.getMethodHolder();
out.print("ciMethodData " +
holder.getName().asString() + " " +
OopUtilities.escapeString(method.getName().asString()) + " " +
method.getSignature().asString() + " " +
state() + " " + currentMileage());
byte[] orig = orig();
out.print(" orig " + orig.length);
for (int i = 0; i < orig.length; i++) {
out.print(" " + (orig[i] & 0xff));
}
long[] data = data();
out.print(" data " + data.length);
for (int i = 0; i < data.length; i++) {
out.print(" 0x" + Long.toHexString(data[i]));
}
int count = 0;
for (int round = 0; round < 2; round++) {
if (round == 1) out.print(" oops " + count);
ProfileData pdata = firstData();
for ( ; isValid(pdata); pdata = nextData(pdata)) {
if (pdata instanceof ciReceiverTypeData) {
ciReceiverTypeData vdata = (ciReceiverTypeData)pdata;
for (int i = 0; i < vdata.rowLimit(); i++) {
ciKlass k = vdata.receiverAt(i);
if (k != null) {
if (round == 0) count++;
else out.print(" " + ((vdata.dp() + vdata.cellOffset(vdata.receiverCellIndex(i))) / MethodData.cellSize) + " " + k.name());
}
}
} else if (pdata instanceof ciVirtualCallData) {
ciVirtualCallData vdata = (ciVirtualCallData)pdata;
for (int i = 0; i < vdata.rowLimit(); i++) {
ciKlass k = vdata.receiverAt(i);
if (k != null) {
if (round == 0) count++;
else out.print(" " + ((vdata.dp() + vdata.cellOffset(vdata.receiverCellIndex(i))) / MethodData.cellSize + " " + k.name()));
}
}
}
}
}
out.println();
}
}
......@@ -498,6 +498,42 @@ public class NMethod extends CodeBlob {
method.getSignature().asString();
}
public void dumpReplayData(PrintStream out) {
HashMap h = new HashMap();
for (int i = 1; i < getMetadataLength(); i++) {
Metadata meta = Metadata.instantiateWrapperFor(getMetadataAt(i));
System.err.println(meta);
if (h.get(meta) != null) continue;
h.put(meta, meta);
if (meta instanceof InstanceKlass) {
((InstanceKlass)meta).dumpReplayData(out);
} else if (meta instanceof Method) {
((Method)meta).dumpReplayData(out);
MethodData mdo = ((Method)meta).getMethodData();
if (mdo != null) {
mdo.dumpReplayData(out);
}
}
}
Method method = getMethod();
if (h.get(method) == null) {
method.dumpReplayData(out);
MethodData mdo = method.getMethodData();
if (mdo != null) {
mdo.dumpReplayData(out);
}
}
if (h.get(method.getMethodHolder()) == null) {
((InstanceKlass)method.getMethodHolder()).dumpReplayData(out);
}
Klass holder = method.getMethodHolder();
out.println("compile " + holder.getName().asString() + " " +
OopUtilities.escapeString(method.getName().asString()) + " " +
method.getSignature().asString() + " " +
getEntryBCI());
}
//--------------------------------------------------------------------------------
// Internals only below this point
//
......
......@@ -56,7 +56,7 @@ public class CompileTask extends VMObject {
}
public Method method() {
Address oh = methodField.getValue(getAddress()).getAddressAt(0);
Address oh = methodField.getValue(getAddress());
return (Method)Metadata.instantiateWrapperFor(oh);
}
......
......@@ -86,7 +86,7 @@ public class ConstantPoolCache extends Metadata {
public void printValueOn(PrintStream tty) {
tty.print("ConstantPoolCache for " + getConstants().getPoolHolder().getName().asString());
tty.print("ConstantPoolCache for " + getConstants().getPoolHolder().getName().asString() + " address = " + getAddress() + " offset = " + baseOffset);
}
public int getLength() {
......
......@@ -110,6 +110,8 @@ public class Field {
public Symbol getSignature() { return signature; }
public Symbol getGenericSignature() { return genericSignature; }
public boolean hasInitialValue() { return holder.getFieldInitialValueIndex(fieldIndex) != 0; }
//
// Following acccessors are for named, non-VM fields only
//
......
......@@ -278,7 +278,7 @@ public class InstanceKlass extends Klass {
}
public short getFieldGenericSignatureIndex(int index) {
int len = getFields().length();
// int len = getFields().length();
int allFieldsCount = getAllFieldsCount();
int generic_signature_slot = allFieldsCount * FIELD_SLOTS;
for (int i = 0; i < allFieldsCount; i++) {
......@@ -325,7 +325,7 @@ public class InstanceKlass extends Klass {
public KlassArray getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); }
public int getJavaFieldsCount() { return (int) javaFieldsCount.getValue(this); }
public int getAllFieldsCount() {
int len = getFields().length();
int len = getFields().length();
int allFieldsCount = 0;
for (; allFieldsCount*FIELD_SLOTS < len; allFieldsCount++) {
short flags = getFieldAccessFlags(allFieldsCount);
......@@ -581,6 +581,19 @@ public class InstanceKlass extends Klass {
}
}
public Field[] getStaticFields() {
U2Array fields = getFields();
int length = getJavaFieldsCount();
ArrayList result = new ArrayList();
for (int index = 0; index < length; index++) {
Field f = newField(index);
if (f.isStatic()) {
result.add(f);
}
}
return (Field[])result.toArray(new Field[result.size()]);
}
public void iterateNonStaticFields(OopVisitor visitor, Oop obj) {
if (getSuper() != null) {
((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj);
......@@ -979,4 +992,84 @@ public class InstanceKlass extends Klass {
}
return -1;
}
public void dumpReplayData(PrintStream out) {
ConstantPool cp = getConstants();
// Try to record related loaded classes
Klass sub = getSubklassKlass();
while (sub != null) {
if (sub instanceof InstanceKlass) {
out.println("instanceKlass " + sub.getName().asString());
}
sub = sub.getNextSiblingKlass();
}
final int length = (int) cp.getLength();
out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
for (int index = 1; index < length; index++) {
out.print(" " + cp.getTags().at(index));
}
out.println();
if (isInitialized()) {
Field[] staticFields = getStaticFields();
for (int i = 0; i < staticFields.length; i++) {
Field f = staticFields[i];
Oop mirror = getJavaMirror();
if (f.isFinal() && !f.hasInitialValue()) {
out.print("staticfield " + getName().asString() + " " +
OopUtilities.escapeString(f.getID().getName()) + " " +
f.getFieldType().getSignature().asString() + " ");
if (f instanceof ByteField) {
ByteField bf = (ByteField)f;
out.println(bf.getValue(mirror));
} else if (f instanceof BooleanField) {
BooleanField bf = (BooleanField)f;
out.println(bf.getValue(mirror) ? 1 : 0);
} else if (f instanceof ShortField) {
ShortField bf = (ShortField)f;
out.println(bf.getValue(mirror));
} else if (f instanceof CharField) {
CharField bf = (CharField)f;
out.println(bf.getValue(mirror) & 0xffff);
} else if (f instanceof IntField) {
IntField bf = (IntField)f;
out.println(bf.getValue(mirror));
} else if (f instanceof LongField) {
LongField bf = (LongField)f;
out.println(bf.getValue(mirror));
} else if (f instanceof FloatField) {
FloatField bf = (FloatField)f;
out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
} else if (f instanceof DoubleField) {
DoubleField bf = (DoubleField)f;
out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
} else if (f instanceof OopField) {
OopField bf = (OopField)f;
Oop value = bf.getValue(mirror);
if (value == null) {
out.println("null");
} else if (value.isInstance()) {
Instance inst = (Instance)value;
if (inst.isA(SystemDictionary.getStringKlass())) {
out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
} else {
out.println(inst.getKlass().getName().asString());
}
} else if (value.isObjArray()) {
ObjArray oa = (ObjArray)value;
Klass ek = (ObjArrayKlass)oa.getKlass();
out.println(oa.getLength() + " " + ek.getName().asString());
} else if (value.isTypeArray()) {
TypeArray ta = (TypeArray)value;
out.println(ta.getLength());
} else {
out.println(value);
}
}
}
}
}
}
}
......@@ -79,4 +79,7 @@ abstract public class Metadata extends VMObject {
}
abstract public void printValueOn(PrintStream tty);
public void dumpReplayData(PrintStream out) {
out.println("# Unknown Metadata");
}
}
......@@ -358,6 +358,25 @@ public class Method extends Metadata {
buf.append(")");
return buf.toString().replace('/', '.');
}
public void dumpReplayData(PrintStream out) {
NMethod nm = getNativeMethod();
int code_size = 0;
if (nm != null) {
code_size = (int)nm.codeEnd().minus(nm.getVerifiedEntryPoint());
}
Klass holder = getMethodHolder();
out.println("ciMethod " +
holder.getName().asString() + " " +
OopUtilities.escapeString(getName().asString()) + " " +
getSignature().asString() + " " +
getInvocationCounter() + " " +
getBackedgeCounter() + " " +
interpreterInvocationCount() + " " +
interpreterThrowoutCount() + " " +
code_size);
}
public int interpreterThrowoutCount() {
return (int) interpreterThrowoutCountField.getValue(this);
}
......
......@@ -332,4 +332,59 @@ public class MethodData extends Metadata {
public int currentMileage() {
return 20000;
}
public void dumpReplayData(PrintStream out) {
Method method = getMethod();
Klass holder = method.getMethodHolder();
out.print("ciMethodData " +
holder.getName().asString() + " " +
OopUtilities.escapeString(method.getName().asString()) + " " +
method.getSignature().asString() + " " +
"2" + " " +
currentMileage());
byte[] orig = orig();
out.print(" orig " + orig.length);
for (int i = 0; i < orig.length; i++) {
out.print(" " + (orig[i] & 0xff));
}
long[] data = data();
out.print(" data " + data.length);
for (int i = 0; i < data.length; i++) {
out.print(" 0x" + Long.toHexString(data[i]));
}
int count = 0;
for (int round = 0; round < 2; round++) {
if (round == 1) out.print(" oops " + count);
ProfileData pdata = firstData();
for ( ; isValid(pdata); pdata = nextData(pdata)) {
if (pdata instanceof ReceiverTypeData) {
ReceiverTypeData vdata = (ReceiverTypeData)pdata;
for (int i = 0; i < vdata.rowLimit(); i++) {
Klass k = vdata.receiver(i);
if (k != null) {
if (round == 0) count++;
else out.print(" " +
(dpToDi(vdata.dp() +
vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " +
k.getName().asString());
}
}
} else if (pdata instanceof VirtualCallData) {
VirtualCallData vdata = (VirtualCallData)pdata;
for (int i = 0; i < vdata.rowLimit(); i++) {
Klass k = vdata.receiver(i);
if (k != null) {
if (round == 0) count++;
else out.print(" " +
(dpToDi(vdata.dp() +
vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " +
k.getName().asString());
}
}
}
}
}
out.println();
}
}
......@@ -1836,7 +1836,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
// check if we could do inlining
if (!PatchALot && Inline && klass->is_loaded() &&
(klass->is_initialized() || klass->is_interface() && target->holder()->is_initialized())
&& target->will_link(klass, callee_holder, code)) {
&& target->is_loaded()) {
// callee is known => check if we have static binding
assert(target->is_loaded(), "callee must be known");
if (code == Bytecodes::_invokestatic ||
......
......@@ -282,7 +282,7 @@ void BCEscapeAnalyzer::invoke(StateInfo &state, Bytecodes::Code code, ciMethod*
ciMethod* inline_target = NULL;
if (target->is_loaded() && klass->is_loaded()
&& (klass->is_initialized() || klass->is_interface() && target->holder()->is_initialized())
&& target->will_link(klass, callee_holder, code)) {
&& target->is_loaded()) {
if (code == Bytecodes::_invokestatic
|| code == Bytecodes::_invokespecial
|| code == Bytecodes::_invokevirtual && target->is_final_method()) {
......
......@@ -106,6 +106,7 @@ friend class ciSymbol; \
friend class ciArray; \
friend class ciObjArray; \
friend class ciMetadata; \
friend class ciReplay; \
friend class ciTypeArray; \
friend class ciType; \
friend class ciReturnAddress; \
......
......@@ -30,6 +30,7 @@
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciNullObject.hpp"
#include "ci/ciReplay.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
......@@ -772,6 +773,11 @@ ciMethod* ciEnv::get_method_by_index_impl(constantPoolHandle cpool,
: !m->method_holder()->is_loaded())) {
m = NULL;
}
#ifdef ASSERT
if (m != NULL && ReplayCompiles && !ciReplay::is_loaded(m)) {
m = NULL;
}
#endif
if (m != NULL) {
// We found the method.
return get_method(m);
......@@ -1144,3 +1150,43 @@ void ciEnv::record_out_of_memory_failure() {
// If memory is low, we stop compiling methods.
record_method_not_compilable("out of memory");
}
fileStream* ciEnv::_replay_data_stream = NULL;
void ciEnv::dump_replay_data() {
VM_ENTRY_MARK;
MutexLocker ml(Compile_lock);
if (_replay_data_stream == NULL) {
_replay_data_stream = new (ResourceObj::C_HEAP, mtCompiler) fileStream(ReplayDataFile);
if (_replay_data_stream == NULL) {
fatal(err_msg("Can't open %s for replay data", ReplayDataFile));
}
}
dump_replay_data(_replay_data_stream);
}
void ciEnv::dump_replay_data(outputStream* out) {
ASSERT_IN_VM;
#if INCLUDE_JVMTI
out->print_cr("JvmtiExport can_access_local_variables %d", _jvmti_can_access_local_variables);
out->print_cr("JvmtiExport can_hotswap_or_post_breakpoint %d", _jvmti_can_hotswap_or_post_breakpoint);
out->print_cr("JvmtiExport can_post_on_exceptions %d", _jvmti_can_post_on_exceptions);
#endif // INCLUDE_JVMTI
GrowableArray<ciMetadata*>* objects = _factory->get_ci_metadata();
out->print_cr("# %d ciObject found", objects->length());
for (int i = 0; i < objects->length(); i++) {
objects->at(i)->dump_replay_data(out);
}
Method* method = task()->method();
int entry_bci = task()->osr_bci();
// Klass holder = method->method_holder();
out->print_cr("compile %s %s %s %d",
method->klass_name()->as_quoted_ascii(),
method->name()->as_quoted_ascii(),
method->signature()->as_quoted_ascii(),
entry_bci);
out->flush();
}
......@@ -46,6 +46,8 @@ class ciEnv : StackObj {
friend class CompileBroker;
friend class Dependencies; // for get_object, during logging
static fileStream* _replay_data_stream;
private:
Arena* _arena; // Alias for _ciEnv_arena except in init_shared_objects()
Arena _ciEnv_arena;
......@@ -448,6 +450,13 @@ public:
// RedefineClasses support
void metadata_do(void f(Metadata*)) { _factory->metadata_do(f); }
// Dump the compilation replay data for this ciEnv to
// ReplayDataFile, creating the file if needed.
void dump_replay_data();
// Dump the compilation replay data for the ciEnv to the stream.
void dump_replay_data(outputStream* out);
};
#endif // SHARE_VM_CI_CIENV_HPP
......@@ -561,3 +561,114 @@ ciInstanceKlass* ciInstanceKlass::implementor() {
}
return impl;
}
// Utility class for printing of the contents of the static fields for
// use by compilation replay. It only prints out the information that
// could be consumed by the compiler, so for primitive types it prints
// out the actual value. For Strings it's the actual string value.
// For array types it it's first level array size since that's the
// only value which statically unchangeable. For all other reference
// types it simply prints out the dynamic type.
class StaticFinalFieldPrinter : public FieldClosure {
outputStream* _out;
const char* _holder;
public:
StaticFinalFieldPrinter(outputStream* out, const char* holder) :
_out(out),
_holder(holder) {
}
void do_field(fieldDescriptor* fd) {
if (fd->is_final() && !fd->has_initial_value()) {
oop mirror = fd->field_holder()->java_mirror();
_out->print("staticfield %s %s %s ", _holder, fd->name()->as_quoted_ascii(), fd->signature()->as_quoted_ascii());
switch (fd->field_type()) {
case T_BYTE: _out->print_cr("%d", mirror->byte_field(fd->offset())); break;
case T_BOOLEAN: _out->print_cr("%d", mirror->bool_field(fd->offset())); break;
case T_SHORT: _out->print_cr("%d", mirror->short_field(fd->offset())); break;
case T_CHAR: _out->print_cr("%d", mirror->char_field(fd->offset())); break;
case T_INT: _out->print_cr("%d", mirror->int_field(fd->offset())); break;
case T_LONG: _out->print_cr(INT64_FORMAT, mirror->long_field(fd->offset())); break;
case T_FLOAT: {
float f = mirror->float_field(fd->offset());
_out->print_cr("%d", *(int*)&f);
break;
}
case T_DOUBLE: {
double d = mirror->double_field(fd->offset());
_out->print_cr(INT64_FORMAT, *(jlong*)&d);
break;
}
case T_ARRAY: {
oop value = mirror->obj_field_acquire(fd->offset());
if (value == NULL) {
_out->print_cr("null");
} else {
typeArrayOop ta = (typeArrayOop)value;
_out->print("%d", ta->length());
if (value->is_objArray()) {
objArrayOop oa = (objArrayOop)value;
const char* klass_name = value->klass()->name()->as_quoted_ascii();
_out->print(" %s", klass_name);
}
_out->cr();
}
break;
}
case T_OBJECT: {
oop value = mirror->obj_field_acquire(fd->offset());
if (value == NULL) {
_out->print_cr("null");
} else if (value->is_instance()) {
if (value->is_a(SystemDictionary::String_klass())) {
_out->print("\"");
_out->print_raw(java_lang_String::as_quoted_ascii(value));
_out->print_cr("\"");
} else {
const char* klass_name = value->klass()->name()->as_quoted_ascii();
_out->print_cr(klass_name);
}
} else {
ShouldNotReachHere();
}
break;
}
default:
ShouldNotReachHere();
}
}
}
};
void ciInstanceKlass::dump_replay_data(outputStream* out) {
ASSERT_IN_VM;
InstanceKlass* ik = get_instanceKlass();
ConstantPool* cp = ik->constants();
// Try to record related loaded classes
Klass* sub = ik->subklass();
while (sub != NULL) {
if (sub->oop_is_instance()) {
out->print_cr("instanceKlass %s", sub->name()->as_quoted_ascii());
}
sub = sub->next_sibling();
}
// Dump out the state of the constant pool tags. During replay the
// tags will be validated for things which shouldn't change and
// classes will be resolved if the tags indicate that they were
// resolved at compile time.
out->print("ciInstanceKlass %s %d %d %d", ik->name()->as_quoted_ascii(),
is_linked(), is_initialized(), cp->length());
for (int index = 1; index < cp->length(); index++) {
out->print(" %d", cp->tags()->at(index));
}
out->cr();
if (is_initialized()) {
// Dump out the static final fields in case the compilation relies
// on their value for correct replay.
StaticFinalFieldPrinter sffp(out, ik->name()->as_quoted_ascii());
ik->do_local_static_fields(&sffp);
}
}
......@@ -230,6 +230,9 @@ public:
// What kind of ciObject is this?
bool is_instance_klass() const { return true; }
bool is_java_klass() const { return true; }
// Dump the current state of this klass for compilation replay.
virtual void dump_replay_data(outputStream* out);
};
#endif // SHARE_VM_CI_CIINSTANCEKLASS_HPP
......@@ -61,6 +61,7 @@ class ciMetadata: public ciBaseObject {
virtual bool is_array_klass() const { return false; }
virtual bool is_obj_array_klass() const { return false; }
virtual bool is_type_array_klass() const { return false; }
virtual void dump_replay_data(outputStream* st) { /* do nothing */ }
ciMethod* as_method() {
assert(is_method(), "bad cast");
......
......@@ -31,6 +31,7 @@
#include "ci/ciMethodData.hpp"
#include "ci/ciStreams.hpp"
#include "ci/ciSymbol.hpp"
#include "ci/ciReplay.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "compiler/abstractCompiler.hpp"
......@@ -139,6 +140,12 @@ ciMethod::ciMethod(methodHandle h_m) : ciMetadata(h_m()) {
}
if (_interpreter_invocation_count == 0)
_interpreter_invocation_count = 1;
_instructions_size = -1;
#ifdef ASSERT
if (ReplayCompiles) {
ciReplay::initialize(this);
}
#endif
}
......@@ -161,7 +168,8 @@ ciMethod::ciMethod(ciInstanceKlass* holder,
#if defined(COMPILER2) || defined(SHARK)
,
_flow( NULL),
_bcea( NULL)
_bcea( NULL),
_instructions_size(-1)
#endif // COMPILER2 || SHARK
{
// Usually holder and accessor are the same type but in some cases
......@@ -867,25 +875,6 @@ ciMethodData* ciMethod::method_data_or_null() {
return md;
}
// ------------------------------------------------------------------
// ciMethod::will_link
//
// Will this method link in a specific calling context?
bool ciMethod::will_link(ciKlass* accessing_klass,
ciKlass* declared_method_holder,
Bytecodes::Code bc) {
if (!is_loaded()) {
// Method lookup failed.
return false;
}
// The link checks have been front-loaded into the get_method
// call. This method (ciMethod::will_link()) will be removed
// in the future.
return true;
}
// ------------------------------------------------------------------
// ciMethod::should_exclude
//
......@@ -1000,8 +989,7 @@ bool ciMethod::can_be_osr_compiled(int entry_bci) {
// ------------------------------------------------------------------
// ciMethod::has_compiled_code
bool ciMethod::has_compiled_code() {
VM_ENTRY_MARK;
return get_Method()->code() != NULL;
return instructions_size() > 0;
}
int ciMethod::comp_level() {
......@@ -1039,14 +1027,18 @@ int ciMethod::code_size_for_inlining() {
// junk like exception handler, stubs, and constant table, which are
// not highly relevant to an inlined method. So we use the more
// specific accessor nmethod::insts_size.
int ciMethod::instructions_size(int comp_level) {
GUARDED_VM_ENTRY(
nmethod* code = get_Method()->code();
if (code != NULL && (comp_level == CompLevel_any || comp_level == code->comp_level())) {
return code->insts_end() - code->verified_entry_point();
}
return 0;
)
int ciMethod::instructions_size() {
if (_instructions_size == -1) {
GUARDED_VM_ENTRY(
nmethod* code = get_Method()->code();
if (code != NULL && (code->comp_level() == CompLevel_full_optimization)) {
_instructions_size = code->insts_end() - code->verified_entry_point();
} else {
_instructions_size = 0;
}
);
}
return _instructions_size;
}
// ------------------------------------------------------------------
......@@ -1166,6 +1158,20 @@ ciMethodBlocks *ciMethod::get_method_blocks() {
#undef FETCH_FLAG_FROM_VM
void ciMethod::dump_replay_data(outputStream* st) {
ASSERT_IN_VM;
Method* method = get_Method();
Klass* holder = method->method_holder();
st->print_cr("ciMethod %s %s %s %d %d %d %d %d",
holder->name()->as_quoted_ascii(),
method->name()->as_quoted_ascii(),
method->signature()->as_quoted_ascii(),
method->invocation_counter()->raw_counter(),
method->backedge_counter()->raw_counter(),
interpreter_invocation_count(),
interpreter_throwout_count(),
_instructions_size);
}
// ------------------------------------------------------------------
// ciMethod::print_codes
......
......@@ -51,6 +51,7 @@ class ciMethod : public ciMetadata {
friend class ciExceptionHandlerStream;
friend class ciBytecodeStream;
friend class ciMethodHandle;
friend class ciReplay;
private:
// General method information.
......@@ -69,6 +70,7 @@ class ciMethod : public ciMetadata {
int _handler_count;
int _interpreter_invocation_count;
int _interpreter_throwout_count;
int _instructions_size;
bool _uses_monitors;
bool _balanced_monitors;
......@@ -239,9 +241,6 @@ class ciMethod : public ciMetadata {
int resolve_vtable_index(ciKlass* caller, ciKlass* receiver);
// Compilation directives
bool will_link(ciKlass* accessing_klass,
ciKlass* declared_method_holder,
Bytecodes::Code bc);
bool should_exclude();
bool should_inline();
bool should_not_inline();
......@@ -252,7 +251,6 @@ class ciMethod : public ciMetadata {
bool can_be_osr_compiled(int entry_bci);
void set_not_compilable();
bool has_compiled_code();
int instructions_size(int comp_level = CompLevel_any);
void log_nmethod_identity(xmlStream* log);
bool is_not_reached(int bci);
bool was_executed_more_than(int times);
......@@ -260,6 +258,7 @@ class ciMethod : public ciMetadata {
bool is_klass_loaded(int refinfo_index, bool must_be_resolved) const;
bool check_call(int refinfo_index, bool is_static) const;
bool ensure_method_data(); // make sure it exists in the VM also
int instructions_size();
int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC
// JSR 292 support
......@@ -291,6 +290,7 @@ class ciMethod : public ciMetadata {
bool is_accessor () const;
bool is_initializer () const;
bool can_be_statically_bound() const { return _can_be_statically_bound; }
void dump_replay_data(outputStream* st);
// Print the bytecodes of this method.
void print_codes_on(outputStream* st);
......
......@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "ci/ciMetadata.hpp"
#include "ci/ciMethodData.hpp"
#include "ci/ciReplay.hpp"
#include "ci/ciUtilities.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
......@@ -115,6 +116,11 @@ void ciMethodData::load_data() {
_arg_local = mdo->arg_local();
_arg_stack = mdo->arg_stack();
_arg_returned = mdo->arg_returned();
#ifndef PRODUCT
if (ReplayCompiles) {
ciReplay::initialize(this);
}
#endif
}
void ciReceiverTypeData::translate_receiver_data_from(ProfileData* data) {
......@@ -366,6 +372,79 @@ void ciMethodData::print_impl(outputStream* st) {
ciMetadata::print_impl(st);
}
void ciMethodData::dump_replay_data(outputStream* out) {
ASSERT_IN_VM;
MethodData* mdo = get_MethodData();
Method* method = mdo->method();
Klass* holder = method->method_holder();
out->print("ciMethodData %s %s %s %d %d",
holder->name()->as_quoted_ascii(),
method->name()->as_quoted_ascii(),
method->signature()->as_quoted_ascii(),
_state,
current_mileage());
// dump the contents of the MDO header as raw data
unsigned char* orig = (unsigned char*)&_orig;
int length = sizeof(_orig);
out->print(" orig %d", length);
for (int i = 0; i < length; i++) {
out->print(" %d", orig[i]);
}
// dump the MDO data as raw data
int elements = data_size() / sizeof(intptr_t);
out->print(" data %d", elements);
for (int i = 0; i < elements; i++) {
// We could use INTPTR_FORMAT here but that's a zero justified
// which makes comparing it with the SA version of this output
// harder.
#ifdef _LP64
out->print(" 0x%" FORMAT64_MODIFIER "x", data()[i]);
#else
out->print(" 0x%x", data()[i]);
#endif
}
// The MDO contained oop references as ciObjects, so scan for those
// and emit pairs of offset and klass name so that they can be
// reconstructed at runtime. The first round counts the number of
// oop references and the second actually emits them.
int count = 0;
for (int round = 0; round < 2; round++) {
if (round == 1) out->print(" oops %d", count);
ProfileData* pdata = first_data();
for ( ; is_valid(pdata); pdata = next_data(pdata)) {
if (pdata->is_ReceiverTypeData()) {
ciReceiverTypeData* vdata = (ciReceiverTypeData*)pdata;
for (uint i = 0; i < vdata->row_limit(); i++) {
ciKlass* k = vdata->receiver(i);
if (k != NULL) {
if (round == 0) {
count++;
} else {
out->print(" %d %s", dp_to_di(vdata->dp() + in_bytes(vdata->receiver_offset(i))) / sizeof(intptr_t), k->name()->as_quoted_ascii());
}
}
}
} else if (pdata->is_VirtualCallData()) {
ciVirtualCallData* vdata = (ciVirtualCallData*)pdata;
for (uint i = 0; i < vdata->row_limit(); i++) {
ciKlass* k = vdata->receiver(i);
if (k != NULL) {
if (round == 0) {
count++;
} else {
out->print(" %d %s", dp_to_di(vdata->dp() + in_bytes(vdata->receiver_offset(i))) / sizeof(intptr_t), k->name()->as_quoted_ascii());
}
}
}
}
}
}
out->cr();
}
#ifndef PRODUCT
void ciMethodData::print() {
print_data_on(tty);
......
......@@ -144,6 +144,7 @@ public:
class ciMethodData : public ciMetadata {
CI_PACKAGE_ACCESS
friend class ciReplay;
private:
// Size in bytes
......@@ -320,6 +321,7 @@ public:
void print();
void print_data_on(outputStream* st);
#endif
void dump_replay_data(outputStream* out);
};
#endif // SHARE_VM_CI_CIMETHODDATA_HPP
......@@ -131,6 +131,7 @@ public:
// Is this a type or value which has no associated class?
// It is true of primitive types and null objects.
virtual bool is_classless() const { return false; }
virtual void dump_replay_data(outputStream* st) { /* do nothing */ }
// Note: some ciObjects refer to oops which have yet to be created.
// We refer to these as "unloaded". Specifically, there are
......
......@@ -137,6 +137,7 @@ public:
ciReturnAddress* get_return_address(int bci);
GrowableArray<ciMetadata*>* get_ci_metadata() const { return _ci_metadata; }
// RedefineClasses support
void metadata_do(void f(Metadata*));
......
此差异已折叠。
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_CI_CIREPLAY_HPP
#define SHARE_VM_CI_CIREPLAY_HPP
#include "ci/ciMethod.hpp"
// ciReplay
class ciReplay {
CI_PACKAGE_ACCESS
#ifdef ASSERT
private:
static int replay_impl(TRAPS);
public:
static void replay(TRAPS);
// These are used by the CI to fill in the cached data from the
// replay file when replaying compiles.
static void initialize(ciMethodData* method);
static void initialize(ciMethod* method);
static bool is_loaded(Method* method);
static bool is_loaded(Klass* klass);
static bool should_not_inline(ciMethod* method);
#endif
};
#endif // SHARE_VM_CI_CIREPLAY_HPP
......@@ -63,6 +63,11 @@ const char* ciSymbol::as_utf8() {
return s->as_utf8();
}
// The text of the symbol as a null-terminated C string.
const char* ciSymbol::as_quoted_ascii() {
GUARDED_VM_QUICK_ENTRY(return get_symbol()->as_quoted_ascii();)
}
// ------------------------------------------------------------------
// ciSymbol::base
const jbyte* ciSymbol::base() {
......
......@@ -73,6 +73,9 @@ public:
const char* as_utf8();
int utf8_length();
// The text of the symbol as ascii with all non-printable characters quoted as \u####
const char* as_quoted_ascii();
// Return the i-th utf8 byte, where i < utf8_length
int byte_at(int i);
......
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -80,6 +80,9 @@
#define GUARDED_VM_ENTRY(action) \
{if (IS_IN_VM) { action } else { VM_ENTRY_MARK; { action }}}
#define GUARDED_VM_QUICK_ENTRY(action) \
{if (IS_IN_VM) { action } else { VM_QUICK_ENTRY_MARK; { action }}}
// Redefine this later.
#define KILL_COMPILE_ON_FATAL_(result) \
THREAD); \
......
......@@ -348,6 +348,22 @@ unsigned int java_lang_String::to_hash(oop java_string) {
return java_lang_String::to_hash(value->char_at_addr(offset), length);
}
char* java_lang_String::as_quoted_ascii(oop java_string) {
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
int length = java_lang_String::length(java_string);
jchar* base = (length == 0) ? NULL : value->char_at_addr(offset);
if (base == NULL) return NULL;
int result_length = UNICODE::quoted_ascii_length(base, length) + 1;
char* result = NEW_RESOURCE_ARRAY(char, result_length);
UNICODE::as_quoted_ascii(base, length, result, result_length);
assert(result_length >= length + 1, "must not be shorter");
assert(result_length == (int)strlen(result) + 1, "must match");
return result;
}
unsigned int java_lang_String::hash_string(oop java_string) {
int length = java_lang_String::length(java_string);
// Zero length string doesn't hash necessarily hash to zero.
......
......@@ -154,6 +154,8 @@ class java_lang_String : AllStatic {
static char* as_utf8_string(oop java_string, int start, int len);
static char* as_platform_dependent_str(Handle java_string, TRAPS);
static jchar* as_unicode_string(oop java_string, int& length);
// produce an ascii string with all other values quoted using \u####
static char* as_quoted_ascii(oop java_string);
// Compute the hash value for a java.lang.String object which would
// contain the characters passed in.
......
......@@ -569,6 +569,7 @@ void Dependencies::print_dependency(DepType dept, int nargs, DepArgument args[],
void Dependencies::DepStream::log_dependency(Klass* witness) {
if (_deps == NULL && xtty == NULL) return; // fast cutout for runtime
ResourceMark rm;
int nargs = argument_count();
DepArgument args[max_arg_count];
for (int j = 0; j < nargs; j++) {
......
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -40,6 +40,7 @@
class InvocationCounter VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
friend class ciReplay;
private: // bit no: |31 3| 2 | 1 0 |
unsigned int _counter; // format: [count|carry|state]
......@@ -85,6 +86,8 @@ class InvocationCounter VALUE_OBJ_CLASS_SPEC {
void set_carry(); // set the sticky carry bit
void set_carry_flag() { _counter |= carry_mask; }
int raw_counter() { return _counter; }
// Accessors
State state() const { return (State)(_counter & state_mask); }
bool carry() const { return (_counter & carry_mask) != 0; }
......
......@@ -1052,6 +1052,13 @@ Method* InstanceKlass::class_initializer() {
}
void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_oop, TRAPS) {
if (ReplayCompiles &&
(ReplaySuppressInitializers == 1 ||
ReplaySuppressInitializers >= 2 && this_oop->class_loader() != NULL)) {
// Hide the existence of the initializer for the purpose of replaying the compile
return;
}
methodHandle h_method(THREAD, this_oop->class_initializer());
assert(!this_oop->is_initialized(), "we cannot initialize twice");
if (TraceClassInitialization) {
......
......@@ -133,6 +133,7 @@ class OopMapBlock VALUE_OBJ_CLASS_SPEC {
class InstanceKlass: public Klass {
friend class VMStructs;
friend class ClassFileParser;
friend class CompileReplay;
protected:
// Constructor
......
......@@ -153,17 +153,15 @@ char* Symbol::as_C_string_flexible_buffer(Thread* t,
void Symbol::print_symbol_on(outputStream* st) const {
st = st ? st : tty;
int length = UTF8::unicode_length((const char*)bytes(), utf8_length());
const char *ptr = (const char *)bytes();
jchar value;
for (int index = 0; index < length; index++) {
ptr = UTF8::next(ptr, &value);
if (value >= 32 && value < 127 || value == '\'' || value == '\\') {
st->put(value);
} else {
st->print("\\u%04x", value);
}
}
st->print("%s", as_quoted_ascii());
}
char* Symbol::as_quoted_ascii() const {
const char *ptr = (const char *)&_body[0];
int quoted_length = UTF8::quoted_ascii_length(ptr, utf8_length());
char* result = NEW_RESOURCE_ARRAY(char, quoted_length + 1);
UTF8::as_quoted_ascii(ptr, result, quoted_length + 1);
return result;
}
jchar* Symbol::as_unicode(int& length) const {
......
......@@ -189,6 +189,8 @@ class Symbol : public MetaspaceObj {
// Use buf if needed buffer length is <= size.
char* as_C_string_flexible_buffer(Thread* t, char* buf, int size) const;
// Returns an escaped form of a Java string.
char* as_quoted_ascii() const;
// Returns a null terminated utf8 string in a resource array
char* as_utf8() const { return as_C_string(); }
......
......@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "ci/ciReplay.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "compiler/compileBroker.hpp"
......@@ -150,7 +151,7 @@ const char* InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_
} else {
// Not hot. Check for medium-sized pre-existing nmethod at cold sites.
if (callee_method->has_compiled_code() &&
callee_method->instructions_size(CompLevel_full_optimization) > inline_small_code_size)
callee_method->instructions_size() > inline_small_code_size)
return "already compiled into a medium method";
}
if (size > max_inline_size) {
......@@ -192,7 +193,7 @@ const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* cal
}
if (callee_method->has_compiled_code() &&
callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode) {
callee_method->instructions_size() > InlineSmallCode) {
wci_result->set_profit(wci_result->profit() * 0.1);
// %%% adjust wci_result->size()?
}
......@@ -216,7 +217,7 @@ const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* cal
// Now perform checks which are heuristic
if (callee_method->has_compiled_code() &&
callee_method->instructions_size(CompLevel_full_optimization) > InlineSmallCode) {
callee_method->instructions_size() > InlineSmallCode) {
return "already compiled into a big method";
}
......@@ -235,6 +236,12 @@ const char* InlineTree::should_not_inline(ciMethod *callee_method, ciMethod* cal
return "disallowed by CompilerOracle";
}
#ifndef PRODUCT
if (ciReplay::should_not_inline(callee_method)) {
return "disallowed by ciReplay";
}
#endif
if (UseStringCache) {
// Do not inline StringCache::profile() method used only at the beginning.
if (callee_method->name() == ciSymbol::profile_name() &&
......
......@@ -334,7 +334,7 @@ bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* kl
return true;
}
assert(dest_method->will_link(method()->holder(), klass, bc()), "dest_method: typeflow responsibility");
assert(dest_method->is_loaded(), "dest_method: typeflow responsibility");
return false;
}
......
......@@ -24,6 +24,7 @@
*/
#include "precompiled.hpp"
#include "ci/ciReplay.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/javaClasses.hpp"
......@@ -5151,6 +5152,7 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, v
// Check if we should compile all classes on bootclasspath
NOT_PRODUCT(if (CompileTheWorld) ClassLoader::compile_the_world();)
NOT_PRODUCT(if (ReplayCompiles) ciReplay::replay(thread);)
// Since this is not a JVM_ENTRY we have to set the thread state manually before leaving.
ThreadStateTransition::transition_and_fence(thread, _thread_in_vm, _thread_in_native);
} else {
......
......@@ -64,6 +64,8 @@ class AttachOperation;
//
class JvmtiExport : public AllStatic {
friend class VMStructs;
friend class CompileReplay;
private:
#if INCLUDE_JVMTI
......
......@@ -97,6 +97,9 @@ void CompilationPolicy::completed_vm_startup() {
// This is intended to force compiles for methods (usually for
// debugging) that would otherwise be interpreted for some reason.
bool CompilationPolicy::must_be_compiled(methodHandle m, int comp_level) {
// Don't allow Xcomp to cause compiles in replay mode
if (ReplayCompiles) return false;
if (m->has_compiled_code()) return false; // already compiled
if (!can_be_compiled(m, comp_level)) return false;
......@@ -322,6 +325,16 @@ nmethod* NonTieredCompPolicy::event(methodHandle method, methodHandle inlinee, i
return NULL;
}
}
if (CompileTheWorld || ReplayCompiles) {
// Don't trigger other compiles in testing mode
if (bci == InvocationEntryBci) {
reset_counter_for_invocation_event(method);
} else {
reset_counter_for_back_branch_event(method);
}
return NULL;
}
if (bci == InvocationEntryBci) {
// when code cache is full, compilation gets switched off, UseCompiler
// is set to false
......
......@@ -3189,6 +3189,26 @@ class CommandLineFlags {
product(ccstrlist, CompileCommand, "", \
"Prepend to .hotspot_compiler; e.g. log,java/lang/String.<init>") \
\
develop(bool, ReplayCompiles, false, \
"Enable replay of compilations from ReplayDataFile") \
\
develop(ccstr, ReplayDataFile, "replay.txt", \
"file containing compilation replay information") \
\
develop(intx, ReplaySuppressInitializers, 2, \
"Controls handling of class initialization during replay" \
"0 - don't do anything special" \
"1 - treat all class initializers as empty" \
"2 - treat class initializers for application classes as empty" \
"3 - allow all class initializers to run during bootstrap but" \
" pretend they are empty after starting replay") \
\
develop(bool, ReplayIgnoreInitErrors, false, \
"Ignore exceptions thrown during initialization for replay") \
\
develop(bool, DumpReplayDataOnError, true, \
"record replay data for crashing compiler threads") \
\
product(bool, CICompilerCountPerCPU, false, \
"1 compiler thread for log(N CPUs)") \
\
......
......@@ -993,6 +993,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
\
nonstatic_field(ciMethod, _interpreter_invocation_count, int) \
nonstatic_field(ciMethod, _interpreter_throwout_count, int) \
nonstatic_field(ciMethod, _instructions_size, int) \
\
nonstatic_field(ciMethodData, _data_size, int) \
nonstatic_field(ciMethodData, _state, u_char) \
......
......@@ -353,9 +353,9 @@ protected:
// sort the array.
bool contains(const T& x) const { return index_of(x) >= 0; }
T at(int i) const { return _data[i]; }
void at_put(const int i, const T& x) { _data[i] = x; }
T* adr_at(const int i) { return &_data[i]; }
T at(int i) const { assert(i >= 0 && i< _length, err_msg_res("oob: 0 <= %d < %d", i, _length)); return _data[i]; }
void at_put(const int i, const T& x) { assert(i >= 0 && i< _length, err_msg_res("oob: 0 <= %d < %d", i, _length)); _data[i] = x; }
T* adr_at(const int i) { assert(i >= 0 && i< _length, err_msg_res("oob: 0 <= %d < %d", i, _length)); return &_data[i]; }
int find(const T& x) { return index_of(x); }
T at_acquire(const int which) { return OrderAccess::load_acquire(adr_at(which)); }
......
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -147,7 +147,7 @@ static u_char* utf8_write(u_char* base, jchar ch) {
void UTF8::convert_to_unicode(const char* utf8_str, jchar* unicode_str, int unicode_length) {
unsigned char ch;
const char *ptr = (const char *)utf8_str;
const char *ptr = utf8_str;
int index = 0;
/* ASCII case loop optimization */
......@@ -162,6 +162,119 @@ void UTF8::convert_to_unicode(const char* utf8_str, jchar* unicode_str, int unic
}
}
// returns the quoted ascii length of a 0-terminated utf8 string
int UTF8::quoted_ascii_length(const char* utf8_str, int utf8_length) {
const char *ptr = utf8_str;
const char* end = ptr + utf8_length;
int result = 0;
while (ptr < end) {
jchar c;
ptr = UTF8::next(ptr, &c);
if (c >= 32 && c < 127) {
result++;
} else {
result += 6;
}
}
return result;
}
// converts a utf8 string to quoted ascii
void UTF8::as_quoted_ascii(const char* utf8_str, char* buf, int buflen) {
const char *ptr = utf8_str;
char* p = buf;
char* end = buf + buflen;
while (*ptr != '\0') {
jchar c;
ptr = UTF8::next(ptr, &c);
if (c >= 32 && c < 127) {
if (p + 1 >= end) break; // string is truncated
*p++ = (char)c;
} else {
if (p + 6 >= end) break; // string is truncated
sprintf(p, "\\u%04x", c);
p += 6;
}
}
*p = '\0';
}
const char* UTF8::from_quoted_ascii(const char* quoted_ascii_str) {
const char *ptr = quoted_ascii_str;
char* result = NULL;
while (*ptr != '\0') {
char c = *ptr;
if (c < 32 || c >= 127) break;
}
if (*ptr == '\0') {
// nothing to do so return original string
return quoted_ascii_str;
}
// everything up to this point was ok.
int length = ptr - quoted_ascii_str;
char* buffer = NULL;
for (int round = 0; round < 2; round++) {
while (*ptr != '\0') {
if (*ptr != '\\') {
if (buffer != NULL) {
buffer[length] = *ptr;
}
length++;
} else {
switch (ptr[1]) {
case 'u': {
ptr += 2;
jchar value=0;
for (int i=0; i<4; i++) {
char c = *ptr++;
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
value = (value << 4) + c - '0';
break;
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
value = (value << 4) + 10 + c - 'a';
break;
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
value = (value << 4) + 10 + c - 'A';
break;
default:
ShouldNotReachHere();
}
}
if (buffer == NULL) {
char utf8_buffer[4];
char* next = (char*)utf8_write((u_char*)utf8_buffer, value);
length += next - utf8_buffer;
} else {
char* next = (char*)utf8_write((u_char*)&buffer[length], value);
length += next - &buffer[length];
}
break;
}
case 't': if (buffer != NULL) buffer[length] = '\t'; ptr += 2; length++; break;
case 'n': if (buffer != NULL) buffer[length] = '\n'; ptr += 2; length++; break;
case 'r': if (buffer != NULL) buffer[length] = '\r'; ptr += 2; length++; break;
case 'f': if (buffer != NULL) buffer[length] = '\f'; ptr += 2; length++; break;
default:
ShouldNotReachHere();
}
}
}
if (round == 0) {
buffer = NEW_RESOURCE_ARRAY(char, length + 1);
ptr = quoted_ascii_str;
} else {
buffer[length] = '\0';
}
}
return buffer;
}
// Returns NULL if 'c' it not found. This only works as long
// as 'c' is an ASCII character
const jbyte* UTF8::strrchr(const jbyte* base, int length, jbyte c) {
......@@ -242,3 +355,35 @@ void UNICODE::convert_to_utf8(const jchar* base, int length, char* utf8_buffer)
}
*utf8_buffer = '\0';
}
// returns the quoted ascii length of a unicode string
int UNICODE::quoted_ascii_length(jchar* base, int length) {
int result = 0;
for (int i = 0; i < length; i++) {
jchar c = base[i];
if (c >= 32 && c < 127) {
result++;
} else {
result += 6;
}
}
return result;
}
// converts a utf8 string to quoted ascii
void UNICODE::as_quoted_ascii(const jchar* base, int length, char* buf, int buflen) {
char* p = buf;
char* end = buf + buflen;
for (int index = 0; index < length; index++) {
jchar c = base[index];
if (c >= 32 && c < 127) {
if (p + 1 >= end) break; // string is truncated
*p++ = (char)c;
} else {
if (p + 6 >= end) break; // string is truncated
sprintf(p, "\\u%04x", c);
p += 6;
}
}
*p = '\0';
}
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -32,22 +32,32 @@
class UTF8 : AllStatic {
public:
// returns the unicode length of a 0-terminated uft8 string
static int unicode_length(const char* uft8_str);
// returns the unicode length of a 0-terminated utf8 string
static int unicode_length(const char* utf8_str);
// returns the unicode length of a non-0-terminated uft8 string
static int unicode_length(const char* uft8_str, int len);
// returns the unicode length of a non-0-terminated utf8 string
static int unicode_length(const char* utf8_str, int len);
// converts a uft8 string to a unicode string
// converts a utf8 string to a unicode string
static void convert_to_unicode(const char* utf8_str, jchar* unicode_buffer, int unicode_length);
// returns the quoted ascii length of a utf8 string
static int quoted_ascii_length(const char* utf8_str, int utf8_length);
// converts a utf8 string to quoted ascii
static void as_quoted_ascii(const char* utf8_str, char* buf, int buflen);
// converts a quoted ascii string to utf8 string. returns the original
// string unchanged if nothing needs to be done.
static const char* from_quoted_ascii(const char* quoted_ascii_string);
// decodes the current utf8 character, stores the result in value,
// and returns the end of the current uft8 chararacter.
// and returns the end of the current utf8 chararacter.
static char* next(const char* str, jchar* value);
// decodes the current utf8 character, gets the supplementary character instead of
// the surrogate pair when seeing a supplementary character in string,
// stores the result in value, and returns the end of the current uft8 chararacter.
// stores the result in value, and returns the end of the current utf8 chararacter.
static char* next_character(const char* str, jint* value);
// Utility methods
......@@ -79,6 +89,12 @@ class UNICODE : AllStatic {
// in resource area unless a buffer is provided.
static char* as_utf8(jchar* base, int length);
static char* as_utf8(jchar* base, int length, char* buf, int buflen);
// returns the quoted ascii length of a unicode string
static int quoted_ascii_length(jchar* base, int length);
// converts a utf8 string to quoted ascii
static void as_quoted_ascii(const jchar* base, int length, char* buf, int buflen);
};
#endif // SHARE_VM_UTILITIES_UTF8_HPP
......@@ -1009,6 +1009,15 @@ void VMError::report_and_die() {
OnError = NULL;
}
static bool skip_replay = false;
if (DumpReplayDataOnError && _thread && _thread->is_Compiler_thread() && !skip_replay) {
skip_replay = true;
ciEnv* env = ciEnv::current();
if (env != NULL) {
env->dump_replay_data();
}
}
static bool skip_bug_url = !should_report_bug(first_error->_id);
if (!skip_bug_url) {
skip_bug_url = true;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册