This commit is contained in:
Erik Trimble 2009-11-05 15:44:04 -08:00
commit 98ce9a72d2
38 changed files with 757 additions and 365 deletions

View File

@ -48,8 +48,16 @@ if [ "$OS" = "Linux" ]; then
CPU=i386 CPU=i386
fi fi
else else
# configure audit helper library if SA_ALTROOT is set
if [ -n "$SA_ALTROOT" ]; then
LD_AUDIT_32=$STARTDIR/../src/os/solaris/proc/`uname -p`/libsaproc_audit.so LD_AUDIT_32=$STARTDIR/../src/os/solaris/proc/`uname -p`/libsaproc_audit.so
export LD_AUDIT_32 export LD_AUDIT_32
if [ ! -f $LD_AUDIT_32 ]; then
echo "SA_ALTROOT is set and can't find libsaproc_audit.so."
echo "Make sure to build it with 'make natives'."
exit 1
fi
fi
SA_LIBPATH=$STARTDIR/../src/os/solaris/proc/`uname -p`:$STARTDIR/solaris/`uname -p` SA_LIBPATH=$STARTDIR/../src/os/solaris/proc/`uname -p`:$STARTDIR/solaris/`uname -p`
OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger" OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger"
CPU=sparc CPU=sparc

View File

@ -43,8 +43,16 @@ else
fi fi
fi fi
# configure audit helper library if SA_ALTROOT is set
if [ -n "$SA_ALTROOT" ]; then
LD_AUDIT_64=$STARTDIR/../src/os/solaris/proc/$CPU/libsaproc_audit.so LD_AUDIT_64=$STARTDIR/../src/os/solaris/proc/$CPU/libsaproc_audit.so
export LD_AUDIT_64 export LD_AUDIT_64
if [ ! -f $LD_AUDIT_64 ]; then
echo "SA_ALTROOT is set and can't find libsaproc_audit.so."
echo "Make sure to build it with 'make natives'."
exit 1
fi
fi
SA_LIBPATH=$STARTDIR/../src/os/solaris/proc/$CPU:$STARTDIR/solaris/$CPU SA_LIBPATH=$STARTDIR/../src/os/solaris/proc/$CPU:$STARTDIR/solaris/$CPU
OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger" OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger"

View File

@ -926,6 +926,28 @@ public class CommandProcessor {
} }
} }
}, },
new Command("dumpcodecache", "dumpcodecache", false) {
public void doit(Tokens t) {
if (t.countTokens() != 0) {
usage();
} else {
final PrintStream fout = out;
final HTMLGenerator gen = new HTMLGenerator(false);
CodeCacheVisitor v = new CodeCacheVisitor() {
public void prologue(Address start, Address end) {
}
public void visit(CodeBlob blob) {
fout.println(gen.genHTML(blob.instructionsBegin()));
}
public void epilogue() {
}
};
VM.getVM().getCodeCache().iterate(v);
}
}
},
new Command("where", "where { -a | id }", false) { new Command("where", "where { -a | id }", false) {
public void doit(Tokens t) { public void doit(Tokens t) {
if (t.countTokens() != 1) { if (t.countTokens() != 1) {

View File

@ -173,7 +173,8 @@ public class CodeCache {
CodeBlob lastBlob = null; CodeBlob lastBlob = null;
while (ptr != null && ptr.lessThan(end)) { while (ptr != null && ptr.lessThan(end)) {
try { try {
CodeBlob blob = findBlobUnsafe(ptr); // Use findStart to get a pointer inside blob other findBlob asserts
CodeBlob blob = findBlobUnsafe(heap.findStart(ptr));
if (blob != null) { if (blob != null) {
visitor.visit(blob); visitor.visit(blob);
if (blob == lastBlob) { if (blob == lastBlob) {

View File

@ -42,7 +42,7 @@ public class NMethod extends CodeBlob {
/** To support simple linked-list chaining of nmethods */ /** To support simple linked-list chaining of nmethods */
private static AddressField osrLinkField; private static AddressField osrLinkField;
private static AddressField scavengeRootLinkField; private static AddressField scavengeRootLinkField;
private static CIntegerField scavengeRootStateField; private static JByteField scavengeRootStateField;
/** Offsets for different nmethod parts */ /** Offsets for different nmethod parts */
private static CIntegerField exceptionOffsetField; private static CIntegerField exceptionOffsetField;
@ -92,7 +92,7 @@ public class NMethod extends CodeBlob {
entryBCIField = type.getCIntegerField("_entry_bci"); entryBCIField = type.getCIntegerField("_entry_bci");
osrLinkField = type.getAddressField("_osr_link"); osrLinkField = type.getAddressField("_osr_link");
scavengeRootLinkField = type.getAddressField("_scavenge_root_link"); scavengeRootLinkField = type.getAddressField("_scavenge_root_link");
scavengeRootStateField = type.getCIntegerField("_scavenge_root_state"); scavengeRootStateField = type.getJByteField("_scavenge_root_state");
exceptionOffsetField = type.getCIntegerField("_exception_offset"); exceptionOffsetField = type.getCIntegerField("_exception_offset");
deoptOffsetField = type.getCIntegerField("_deoptimize_offset"); deoptOffsetField = type.getCIntegerField("_deoptimize_offset");
@ -274,7 +274,7 @@ public class NMethod extends CodeBlob {
if (Assert.ASSERTS_ENABLED) { if (Assert.ASSERTS_ENABLED) {
Assert.that(pd != null, "scope must be present"); Assert.that(pd != null, "scope must be present");
} }
return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getReexecute()); return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getObjDecodeOffset(), pd.getReexecute());
} }
/** This is only for use by the debugging system, and is only /** This is only for use by the debugging system, and is only
@ -306,11 +306,11 @@ public class NMethod extends CodeBlob {
public ScopeDesc getScopeDescNearDbg(Address pc) { public ScopeDesc getScopeDescNearDbg(Address pc) {
PCDesc pd = getPCDescNearDbg(pc); PCDesc pd = getPCDescNearDbg(pc);
if (pd == null) return null; if (pd == null) return null;
return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getReexecute()); return new ScopeDesc(this, pd.getScopeDecodeOffset(), pd.getObjDecodeOffset(), pd.getReexecute());
} }
public Map/*<Address, PcDesc>*/ getSafepoints() { public Map/*<Address, PCDesc>*/ getSafepoints() {
Map safepoints = new HashMap(); // Map<Address, PcDesc> Map safepoints = new HashMap(); // Map<Address, PCDesc>
sun.jvm.hotspot.debugger.Address p = null; sun.jvm.hotspot.debugger.Address p = null;
for (p = scopesPCsBegin(); p.lessThan(scopesPCsEnd()); for (p = scopesPCsBegin(); p.lessThan(scopesPCsEnd());
p = p.addOffsetTo(pcDescSize)) { p = p.addOffsetTo(pcDescSize)) {

View File

@ -36,6 +36,7 @@ import sun.jvm.hotspot.types.*;
public class PCDesc extends VMObject { public class PCDesc extends VMObject {
private static CIntegerField pcOffsetField; private static CIntegerField pcOffsetField;
private static CIntegerField scopeDecodeOffsetField; private static CIntegerField scopeDecodeOffsetField;
private static CIntegerField objDecodeOffsetField;
private static CIntegerField pcFlagsField; private static CIntegerField pcFlagsField;
static { static {
@ -51,6 +52,7 @@ public class PCDesc extends VMObject {
pcOffsetField = type.getCIntegerField("_pc_offset"); pcOffsetField = type.getCIntegerField("_pc_offset");
scopeDecodeOffsetField = type.getCIntegerField("_scope_decode_offset"); scopeDecodeOffsetField = type.getCIntegerField("_scope_decode_offset");
objDecodeOffsetField = type.getCIntegerField("_obj_decode_offset");
pcFlagsField = type.getCIntegerField("_flags"); pcFlagsField = type.getCIntegerField("_flags");
} }
@ -68,6 +70,10 @@ public class PCDesc extends VMObject {
return ((int) scopeDecodeOffsetField.getValue(addr)); return ((int) scopeDecodeOffsetField.getValue(addr));
} }
public int getObjDecodeOffset() {
return ((int) objDecodeOffsetField.getValue(addr));
}
public Address getRealPC(NMethod code) { public Address getRealPC(NMethod code) {
return code.instructionsBegin().addOffsetTo(getPCOffset()); return code.instructionsBegin().addOffsetTo(getPCOffset());
} }

View File

@ -51,11 +51,10 @@ public class ScopeDesc {
/** Scalar replaced bjects pool */ /** Scalar replaced bjects pool */
private List objects; // ArrayList<ScopeValue> private List objects; // ArrayList<ScopeValue>
private ScopeDesc(NMethod code, int decodeOffset, List objects, boolean reexecute) {
public ScopeDesc(NMethod code, int decodeOffset, boolean reexecute) {
this.code = code; this.code = code;
this.decodeOffset = decodeOffset; this.decodeOffset = decodeOffset;
this.objects = decodeObjectValues(DebugInformationRecorder.SERIALIZED_NULL); this.objects = objects;
this.reexecute = reexecute; this.reexecute = reexecute;
// Decode header // Decode header
@ -108,7 +107,7 @@ public class ScopeDesc {
return decodeMonitorValues(monitorsDecodeOffset); return decodeMonitorValues(monitorsDecodeOffset);
} }
/** Returns a List&lt;MonitorValue&gt; */ /** Returns a List&lt;ObjectValue&gt; */
public List getObjects() { public List getObjects() {
return objects; return objects;
} }
@ -119,7 +118,7 @@ public class ScopeDesc {
return null; return null;
} }
return new ScopeDesc(code, senderDecodeOffset, false); return new ScopeDesc(code, senderDecodeOffset, objects, false);
} }
/** Returns where the scope was decoded */ /** Returns where the scope was decoded */

View File

@ -807,6 +807,9 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
Interpreter interp = VM.getVM().getInterpreter(); Interpreter interp = VM.getVM().getInterpreter();
if (interp.contains(pc)) { if (interp.contains(pc)) {
InterpreterCodelet codelet = interp.getCodeletContaining(pc); InterpreterCodelet codelet = interp.getCodeletContaining(pc);
if (codelet == null) {
return "Unknown location in the Interpreter: " + pc;
}
return genHTML(codelet); return genHTML(codelet);
} }
return genHTML(blob); return genHTML(blob);
@ -972,10 +975,18 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
ScopeDesc sd = nm.getScopeDescAt(pcDesc.getRealPC(nm)); ScopeDesc sd = nm.getScopeDescAt(pcDesc.getRealPC(nm));
Formatter buf = new Formatter(genHTML); Formatter buf = new Formatter(genHTML);
Formatter tabs = new Formatter(genHTML); Formatter tabs = new Formatter(genHTML);
tabs.append(tab + tab + tab); // Initial indent for debug info
buf.beginTag("pre"); buf.beginTag("pre");
genScope(buf, tabs, sd); genScope(buf, tabs, sd);
// Reset indent for scalar replaced objects
tabs = new Formatter(genHTML);
tabs.append(tab + tab + tab); // Initial indent for debug info
genScObjInfo(buf, tabs, sd);
buf.endTag("pre"); buf.endTag("pre");
buf.append(genOopMapInfo(nm, pcDesc)); buf.append(genOopMapInfo(nm, pcDesc));
return buf.toString(); return buf.toString();
@ -1022,8 +1033,95 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
buf.append(genHTMLForMonitors(sd, monitors)); buf.append(genHTMLForMonitors(sd, monitors));
} }
tabs.append(tab);
buf.br(); buf.br();
tabs.append(tab);
}
protected void genScObjInfo(Formatter buf, Formatter tabs, ScopeDesc sd) {
if (sd == null) {
return;
}
List objects = sd.getObjects();
if (objects == null) {
return;
}
int length = objects.size();
for (int i = 0; i < length; i++) {
buf.append(tabs);
ObjectValue ov = (ObjectValue)objects.get(i);
buf.append("ScObj" + i);
ScopeValue sv = ov.getKlass();
if (Assert.ASSERTS_ENABLED) {
Assert.that(sv.isConstantOop(), "scalar replaced object klass must be constant oop");
}
ConstantOopReadValue klv = (ConstantOopReadValue)sv;
OopHandle klHandle = klv.getValue();
if (Assert.ASSERTS_ENABLED) {
Assert.that(klHandle != null, "scalar replaced object klass must be not NULL");
}
Oop obj = VM.getVM().getObjectHeap().newOop(klHandle);
if (obj instanceof InstanceKlass) {
InstanceKlass kls = (InstanceKlass) obj;
buf.append(" " + kls.getName().asString() + "={");
int flen = ov.fieldsSize();
TypeArray klfields = kls.getFields();
int klen = (int) klfields.getLength();
ConstantPool cp = kls.getConstants();
int findex = 0;
for (int index = 0; index < klen; index += kls.NEXT_OFFSET) {
int accsFlags = klfields.getShortAt(index + kls.ACCESS_FLAGS_OFFSET);
int nameIndex = klfields.getShortAt(index + kls.NAME_INDEX_OFFSET);
AccessFlags access = new AccessFlags(accsFlags);
if (!access.isStatic()) {
ScopeValue svf = ov.getFieldAt(findex++);
String fstr = scopeValueAsString(sd, svf);
Symbol f_name = cp.getSymbolAt(nameIndex);
buf.append(" [" + f_name.asString() + " :"+ index + "]=(#" + fstr + ")");
}
}
buf.append(" }");
} else {
buf.append(" ");
int flen = ov.fieldsSize();
if (obj instanceof TypeArrayKlass) {
TypeArrayKlass kls = (TypeArrayKlass) obj;
buf.append(kls.getElementTypeName() + "[" + flen + "]");
} else if (obj instanceof ObjArrayKlass) {
ObjArrayKlass kls = (ObjArrayKlass) obj;
Klass elobj = kls.getBottomKlass();
if (elobj instanceof InstanceKlass) {
buf.append(elobj.getName().asString());
} else if (elobj instanceof TypeArrayKlass) {
TypeArrayKlass elkls = (TypeArrayKlass) elobj;
buf.append(elkls.getElementTypeName());
} else {
if (Assert.ASSERTS_ENABLED) {
Assert.that(false, "unknown scalar replaced object klass!");
}
}
buf.append("[" + flen + "]");
int ndim = (int) kls.getDimension();
while (--ndim > 0) {
buf.append("[]");
}
} else {
if (Assert.ASSERTS_ENABLED) {
Assert.that(false, "unknown scalar replaced object klass!");
}
}
buf.append("={");
for (int findex = 0; findex < flen; findex++) {
ScopeValue svf = ov.getFieldAt(findex);
String fstr = scopeValueAsString(sd, svf);
buf.append(" [" + findex + "]=(#" + fstr + ")");
}
buf.append(" }");
}
buf.br();
}
} }
protected String genHTMLForOopMap(OopMap map) { protected String genHTMLForOopMap(OopMap map) {
@ -1037,8 +1135,6 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
tmpBuf.beginTag("tr"); tmpBuf.beginTag("tr");
tmpBuf.beginTag("td"); tmpBuf.beginTag("td");
tmpBuf.append(type); tmpBuf.append(type);
tmpBuf.endTag("td");
tmpBuf.endTag("tr");
for (; ! oms.isDone(); oms.next()) { for (; ! oms.isDone(); oms.next()) {
OopMapValue omv = oms.getCurrent(); OopMapValue omv = oms.getCurrent();
if (omv == null) { if (omv == null) {
@ -1048,7 +1144,7 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
VMReg vmReg = omv.getReg(); VMReg vmReg = omv.getReg();
int reg = vmReg.getValue(); int reg = vmReg.getValue();
if (reg < stack0) { if (reg < stack0) {
tmpBuf.append(VMRegImpl.getRegisterName(vmReg.getValue())); tmpBuf.append(VMRegImpl.getRegisterName(reg));
} else { } else {
tmpBuf.append('['); tmpBuf.append('[');
tmpBuf.append(Integer.toString((reg - stack0) * 4)); tmpBuf.append(Integer.toString((reg - stack0) * 4));
@ -1058,7 +1154,13 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
tmpBuf.append(" = "); tmpBuf.append(" = ");
VMReg vmContentReg = omv.getContentReg(); VMReg vmContentReg = omv.getContentReg();
int contentReg = vmContentReg.getValue(); int contentReg = vmContentReg.getValue();
tmpBuf.append(VMRegImpl.getRegisterName(vmContentReg.getValue())); if (contentReg < stack0) {
tmpBuf.append(VMRegImpl.getRegisterName(contentReg));
} else {
tmpBuf.append('[');
tmpBuf.append(Integer.toString((contentReg - stack0) * 4));
tmpBuf.append(']');
}
} }
tmpBuf.append(spaces); tmpBuf.append(spaces);
} }
@ -1072,19 +1174,19 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
OopMapValueIterator omvIterator = new OopMapValueIterator(); OopMapValueIterator omvIterator = new OopMapValueIterator();
OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.OOP_VALUE); OopMapStream oms = new OopMapStream(map, OopMapValue.OopTypes.OOP_VALUE);
buf.append(omvIterator.iterate(oms, "Oop:", false)); buf.append(omvIterator.iterate(oms, "Oops:", false));
oms = new OopMapStream(map, OopMapValue.OopTypes.VALUE_VALUE);
buf.append(omvIterator.iterate(oms, "Value:", false));
oms = new OopMapStream(map, OopMapValue.OopTypes.NARROWOOP_VALUE); oms = new OopMapStream(map, OopMapValue.OopTypes.NARROWOOP_VALUE);
buf.append(omvIterator.iterate(oms, "Oop:", false)); buf.append(omvIterator.iterate(oms, "narrowOops:", false));
oms = new OopMapStream(map, OopMapValue.OopTypes.VALUE_VALUE);
buf.append(omvIterator.iterate(oms, "Values:", false));
oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE); oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE);
buf.append(omvIterator.iterate(oms, "Callee saved:", true)); buf.append(omvIterator.iterate(oms, "Callee saved:", true));
oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE); oms = new OopMapStream(map, OopMapValue.OopTypes.DERIVED_OOP_VALUE);
buf.append(omvIterator.iterate(oms, "Derived oop:", true)); buf.append(omvIterator.iterate(oms, "Derived oops:", true));
buf.endTag("table"); buf.endTag("table");
return buf.toString(); return buf.toString();
@ -1093,6 +1195,8 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
protected String genOopMapInfo(NMethod nmethod, PCDesc pcDesc) { protected String genOopMapInfo(NMethod nmethod, PCDesc pcDesc) {
OopMapSet mapSet = nmethod.getOopMaps(); OopMapSet mapSet = nmethod.getOopMaps();
if (mapSet == null || (mapSet.getSize() <= 0))
return "";
int pcOffset = pcDesc.getPCOffset(); int pcOffset = pcDesc.getPCOffset();
OopMap map = mapSet.findMapAtOffset(pcOffset, VM.getVM().isDebugging()); OopMap map = mapSet.findMapAtOffset(pcOffset, VM.getVM().isDebugging());
if (map == null) { if (map == null) {
@ -1106,6 +1210,7 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
Formatter buf = new Formatter(genHTML); Formatter buf = new Formatter(genHTML);
buf.beginTag("pre"); buf.beginTag("pre");
buf.append("OopMap: "); buf.append("OopMap: ");
buf.br();
buf.append(genHTMLForOopMap(map)); buf.append(genHTMLForOopMap(map));
buf.endTag("pre"); buf.endTag("pre");
@ -1154,7 +1259,7 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
return buf.toString(); return buf.toString();
} }
private String scopeValueAsString(ScopeValue sv) { private String scopeValueAsString(ScopeDesc sd, ScopeValue sv) {
Formatter buf = new Formatter(genHTML); Formatter buf = new Formatter(genHTML);
if (sv.isConstantInt()) { if (sv.isConstantInt()) {
buf.append("int "); buf.append("int ");
@ -1187,6 +1292,11 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
} else { } else {
buf.append("null"); buf.append("null");
} }
} else if (sv.isObject()) {
ObjectValue ov = (ObjectValue)sv;
buf.append("#ScObj" + sd.getObjects().indexOf(ov));
} else {
buf.append("unknown scope value " + sv);
} }
return buf.toString(); return buf.toString();
} }
@ -1219,7 +1329,7 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
} }
buf.append(", "); buf.append(", ");
buf.append(scopeValueAsString(sv)); buf.append(scopeValueAsString(sd, sv));
buf.append(") "); buf.append(") ");
} }
@ -1246,7 +1356,7 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
buf.append("(owner = "); buf.append("(owner = ");
ScopeValue owner = mv.owner(); ScopeValue owner = mv.owner();
if (owner != null) { if (owner != null) {
buf.append(scopeValueAsString(owner)); buf.append(scopeValueAsString(sd, owner));
} else { } else {
buf.append("null"); buf.append("null");
} }
@ -1324,11 +1434,11 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
buf.append(instr.asString(currentPc, symFinder)); buf.append(instr.asString(currentPc, symFinder));
} }
buf.br();
if (isSafepoint && !prevWasCall) { if (isSafepoint && !prevWasCall) {
buf.append(genSafepointInfo(nmethod, pcDesc)); buf.append(genSafepointInfo(nmethod, pcDesc));
} }
buf.br();
prevWasCall = instr.isCall(); prevWasCall = instr.isCall();
} }

View File

@ -1047,7 +1047,7 @@ while (tmp.itr.hasNext()) {
} else { } else {
// some type names have ':'. replace to make it as a // some type names have ':'. replace to make it as a
// JavaScript identifier // JavaScript identifier
tmp.name = tmp.name.replace(':', '_'); tmp.name = tmp.name.replace(':', '_').replace('<', '_').replace('>', '_').replace('*', '_').replace(' ', '_');
eval("function read" + tmp.name + "(addr) {" + eval("function read" + tmp.name + "(addr) {" +
" return readVMType('" + tmp.name + "', addr);}"); " return readVMType('" + tmp.name + "', addr);}");
eval("function print" + tmp.name + "(addr) {" + eval("function print" + tmp.name + "(addr) {" +

View File

@ -3213,9 +3213,8 @@ void SharedRuntime::generate_deopt_blob() {
Register Oreturn0 = O0; Register Oreturn0 = O0;
Register Oreturn1 = O1; Register Oreturn1 = O1;
Register O2UnrollBlock = O2; Register O2UnrollBlock = O2;
Register O3tmp = O3; Register L0deopt_mode = L0;
Register I5exception_tmp = I5; Register G4deopt_mode = G4_scratch;
Register G4exception_tmp = G4_scratch;
int frame_size_words; int frame_size_words;
Address saved_Freturn0_addr(FP, -sizeof(double) + STACK_BIAS); Address saved_Freturn0_addr(FP, -sizeof(double) + STACK_BIAS);
#if !defined(_LP64) && defined(COMPILER2) #if !defined(_LP64) && defined(COMPILER2)
@ -3265,7 +3264,7 @@ void SharedRuntime::generate_deopt_blob() {
map = RegisterSaver::save_live_registers(masm, 0, &frame_size_words); map = RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
__ ba(false, cont); __ ba(false, cont);
__ delayed()->mov(Deoptimization::Unpack_deopt, I5exception_tmp); __ delayed()->mov(Deoptimization::Unpack_deopt, L0deopt_mode);
int exception_offset = __ offset() - start; int exception_offset = __ offset() - start;
@ -3316,7 +3315,7 @@ void SharedRuntime::generate_deopt_blob() {
#endif #endif
__ ba(false, cont); __ ba(false, cont);
__ delayed()->mov(Deoptimization::Unpack_exception, I5exception_tmp);; __ delayed()->mov(Deoptimization::Unpack_exception, L0deopt_mode);;
// //
// Reexecute entry, similar to c2 uncommon trap // Reexecute entry, similar to c2 uncommon trap
@ -3326,7 +3325,7 @@ void SharedRuntime::generate_deopt_blob() {
// No need to update oop_map as each call to save_live_registers will produce identical oopmap // No need to update oop_map as each call to save_live_registers will produce identical oopmap
(void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
__ mov(Deoptimization::Unpack_reexecute, I5exception_tmp); __ mov(Deoptimization::Unpack_reexecute, L0deopt_mode);
__ bind(cont); __ bind(cont);
@ -3349,14 +3348,14 @@ void SharedRuntime::generate_deopt_blob() {
// NOTE: we know that only O0/O1 will be reloaded by restore_result_registers // NOTE: we know that only O0/O1 will be reloaded by restore_result_registers
// so this move will survive // so this move will survive
__ mov(I5exception_tmp, G4exception_tmp); __ mov(L0deopt_mode, G4deopt_mode);
__ mov(O0, O2UnrollBlock->after_save()); __ mov(O0, O2UnrollBlock->after_save());
RegisterSaver::restore_result_registers(masm); RegisterSaver::restore_result_registers(masm);
Label noException; Label noException;
__ cmp(G4exception_tmp, Deoptimization::Unpack_exception); // Was exception pending? __ cmp(G4deopt_mode, Deoptimization::Unpack_exception); // Was exception pending?
__ br(Assembler::notEqual, false, Assembler::pt, noException); __ br(Assembler::notEqual, false, Assembler::pt, noException);
__ delayed()->nop(); __ delayed()->nop();
@ -3390,10 +3389,10 @@ void SharedRuntime::generate_deopt_blob() {
} }
#endif #endif
__ set_last_Java_frame(SP, noreg); __ set_last_Java_frame(SP, noreg);
__ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames), G2_thread, G4exception_tmp); __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames), G2_thread, G4deopt_mode);
#else #else
// LP64 uses g4 in set_last_Java_frame // LP64 uses g4 in set_last_Java_frame
__ mov(G4exception_tmp, O1); __ mov(G4deopt_mode, O1);
__ set_last_Java_frame(SP, G0); __ set_last_Java_frame(SP, G0);
__ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames), G2_thread, O1); __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames), G2_thread, O1);
#endif #endif
@ -3446,7 +3445,6 @@ void SharedRuntime::generate_uncommon_trap_blob() {
#endif #endif
MacroAssembler* masm = new MacroAssembler(&buffer); MacroAssembler* masm = new MacroAssembler(&buffer);
Register O2UnrollBlock = O2; Register O2UnrollBlock = O2;
Register O3tmp = O3;
Register O2klass_index = O2; Register O2klass_index = O2;
// //

View File

@ -9419,8 +9419,9 @@ instruct countLeadingZerosI(iRegI dst, iRegI src, iRegI tmp, flagsReg cr) %{
// x |= (x >> 8); // x |= (x >> 8);
// x |= (x >> 16); // x |= (x >> 16);
// return (WORDBITS - popc(x)); // return (WORDBITS - popc(x));
format %{ "SRL $src,1,$dst\t! count leading zeros (int)\n\t" format %{ "SRL $src,1,$tmp\t! count leading zeros (int)\n\t"
"OR $src,$tmp,$dst\n\t" "SRL $src,0,$dst\t! 32-bit zero extend\n\t"
"OR $dst,$tmp,$dst\n\t"
"SRL $dst,2,$tmp\n\t" "SRL $dst,2,$tmp\n\t"
"OR $dst,$tmp,$dst\n\t" "OR $dst,$tmp,$dst\n\t"
"SRL $dst,4,$tmp\n\t" "SRL $dst,4,$tmp\n\t"
@ -9437,7 +9438,8 @@ instruct countLeadingZerosI(iRegI dst, iRegI src, iRegI tmp, flagsReg cr) %{
Register Rsrc = $src$$Register; Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register; Register Rtmp = $tmp$$Register;
__ srl(Rsrc, 1, Rtmp); __ srl(Rsrc, 1, Rtmp);
__ or3(Rsrc, Rtmp, Rdst); __ srl(Rsrc, 0, Rdst);
__ or3(Rdst, Rtmp, Rdst);
__ srl(Rdst, 2, Rtmp); __ srl(Rdst, 2, Rtmp);
__ or3(Rdst, Rtmp, Rdst); __ or3(Rdst, Rtmp, Rdst);
__ srl(Rdst, 4, Rtmp); __ srl(Rdst, 4, Rtmp);
@ -9465,7 +9467,7 @@ instruct countLeadingZerosL(iRegI dst, iRegL src, iRegL tmp, flagsReg cr) %{
// x |= (x >> 16); // x |= (x >> 16);
// x |= (x >> 32); // x |= (x >> 32);
// return (WORDBITS - popc(x)); // return (WORDBITS - popc(x));
format %{ "SRLX $src,1,$dst\t! count leading zeros (long)\n\t" format %{ "SRLX $src,1,$tmp\t! count leading zeros (long)\n\t"
"OR $src,$tmp,$dst\n\t" "OR $src,$tmp,$dst\n\t"
"SRLX $dst,2,$tmp\n\t" "SRLX $dst,2,$tmp\n\t"
"OR $dst,$tmp,$dst\n\t" "OR $dst,$tmp,$dst\n\t"

View File

@ -8214,6 +8214,15 @@ void MacroAssembler::store_heap_oop(Address dst, Register src) {
} }
} }
// Used for storing NULLs.
void MacroAssembler::store_heap_oop_null(Address dst) {
if (UseCompressedOops) {
movl(dst, (int32_t)NULL_WORD);
} else {
movslq(dst, (int32_t)NULL_WORD);
}
}
// Algorithm must match oop.inline.hpp encode_heap_oop. // Algorithm must match oop.inline.hpp encode_heap_oop.
void MacroAssembler::encode_heap_oop(Register r) { void MacroAssembler::encode_heap_oop(Register r) {
assert (UseCompressedOops, "should be compressed"); assert (UseCompressedOops, "should be compressed");

View File

@ -1682,6 +1682,17 @@ class MacroAssembler: public Assembler {
void load_heap_oop(Register dst, Address src); void load_heap_oop(Register dst, Address src);
void store_heap_oop(Address dst, Register src); void store_heap_oop(Address dst, Register src);
// This dummy is to prevent a call to store_heap_oop from
// converting a zero (like NULL) into a Register by giving
// the compiler two choices it can't resolve
void store_heap_oop(Address dst, void* dummy);
// Used for storing NULL. All other oop constants should be
// stored using routines that take a jobject.
void store_heap_oop_null(Address dst);
void encode_heap_oop(Register r); void encode_heap_oop(Register r);
void decode_heap_oop(Register r); void decode_heap_oop(Register r);
void encode_heap_oop_not_null(Register r); void encode_heap_oop_not_null(Register r);

View File

@ -271,9 +271,15 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
void trace_method_handle_stub(const char* adaptername, void trace_method_handle_stub(const char* adaptername,
oopDesc* mh, oopDesc* mh,
intptr_t* entry_sp, intptr_t* entry_sp,
intptr_t* saved_sp) { intptr_t* saved_sp,
intptr_t* saved_bp) {
// called as a leaf from native code: do not block the JVM! // called as a leaf from native code: do not block the JVM!
printf("MH %s "PTR_FORMAT" "PTR_FORMAT" "INTX_FORMAT"\n", adaptername, (void*)mh, entry_sp, entry_sp - saved_sp); intptr_t* last_sp = (intptr_t*) saved_bp[frame::interpreter_frame_last_sp_offset];
intptr_t* base_sp = (intptr_t*) saved_bp[frame::interpreter_frame_monitor_block_top_offset];
printf("MH %s mh="INTPTR_FORMAT" sp=("INTPTR_FORMAT"+"INTX_FORMAT") stack_size="INTX_FORMAT" bp="INTPTR_FORMAT"\n",
adaptername, (intptr_t)mh, (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp);
if (last_sp != saved_sp)
printf("*** last_sp="INTPTR_FORMAT"\n", (intptr_t)last_sp);
} }
#endif //PRODUCT #endif //PRODUCT
@ -293,6 +299,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
Register rbx_temp = rbx; Register rbx_temp = rbx;
Register rdx_temp = rdx; Register rdx_temp = rdx;
// This guy is set up by prepare_to_jump_from_interpreted (from interpreted calls)
// and gen_c2i_adapter (from compiled calls):
Register saved_last_sp = LP64_ONLY(r13) NOT_LP64(rsi);
guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets"); guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets");
// some handy addresses // some handy addresses
@ -315,6 +325,8 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
assert(tag_offset = wordSize, "stack grows as expected"); assert(tag_offset = wordSize, "stack grows as expected");
} }
const int java_mirror_offset = klassOopDesc::klass_part_offset_in_bytes() + Klass::java_mirror_offset_in_bytes();
if (have_entry(ek)) { if (have_entry(ek)) {
__ nop(); // empty stubs make SG sick __ nop(); // empty stubs make SG sick
return; return;
@ -328,45 +340,65 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ push(rax); __ push(rbx); __ push(rcx); __ push(rdx); __ push(rsi); __ push(rdi); __ push(rax); __ push(rbx); __ push(rcx); __ push(rdx); __ push(rsi); __ push(rdi);
__ lea(rax, Address(rsp, wordSize*6)); // entry_sp __ lea(rax, Address(rsp, wordSize*6)); // entry_sp
// arguments: // arguments:
__ push(rbp); // interpreter frame pointer
__ push(rsi); // saved_sp __ push(rsi); // saved_sp
__ push(rax); // entry_sp __ push(rax); // entry_sp
__ push(rcx); // mh __ push(rcx); // mh
__ push(rcx); __ push(rcx);
__ movptr(Address(rsp, 0), (intptr_t)entry_name(ek)); __ movptr(Address(rsp, 0), (intptr_t)entry_name(ek));
__ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 4); __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 5);
__ pop(rdi); __ pop(rsi); __ pop(rdx); __ pop(rcx); __ pop(rbx); __ pop(rax); __ pop(rdi); __ pop(rsi); __ pop(rdx); __ pop(rcx); __ pop(rbx); __ pop(rax);
} }
#endif //PRODUCT #endif //PRODUCT
switch ((int) ek) { switch ((int) ek) {
case _check_mtype: case _raise_exception:
{ {
// this stub is special, because it requires a live mtype argument // Not a real MH entry, but rather shared code for raising an exception.
Register rax_mtype = rax; // Extra local arguments are pushed on stack, as required type at TOS+8,
// failing object (or NULL) at TOS+4, failing bytecode type at TOS.
// Beyond those local arguments are the PC, of course.
Register rdx_code = rdx_temp;
Register rcx_fail = rcx_recv;
Register rax_want = rax_argslot;
Register rdi_pc = rdi;
__ pop(rdx_code); // TOS+0
__ pop(rcx_fail); // TOS+4
__ pop(rax_want); // TOS+8
__ pop(rdi_pc); // caller PC
// emit WrongMethodType path first, to enable jccb back-branch __ mov(rsp, rsi); // cut the stack back to where the caller started
Label wrong_method_type;
__ bind(wrong_method_type);
__ movptr(rdx_temp, ExternalAddress((address) &_entries[_wrong_method_type]));
__ jmp(Address(rdx_temp, MethodHandleEntry::from_interpreted_entry_offset_in_bytes()));
__ hlt();
interp_entry = __ pc(); // Repush the arguments as if coming from the interpreter.
__ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type); if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_INT));
// now rax_mtype is dead; subsequent stubs will use it as a temp __ push(rdx_code);
if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_OBJECT));
__ push(rcx_fail);
if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_OBJECT));
__ push(rax_want);
__ jump_to_method_handle_entry(rcx_recv, rdx_temp); Register rbx_method = rbx_temp;
} Label no_method;
break; // FIXME: fill in _raise_exception_method with a suitable sun.dyn method
__ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method));
__ testptr(rbx_method, rbx_method);
__ jcc(Assembler::zero, no_method);
int jobject_oop_offset = 0;
__ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject
__ testptr(rbx_method, rbx_method);
__ jcc(Assembler::zero, no_method);
__ verify_oop(rbx_method);
__ push(rdi_pc); // and restore caller PC
__ jmp(rbx_method_fie);
case _wrong_method_type: // If we get here, the Java runtime did not do its job of creating the exception.
{ // Do something that is at least causes a valid throw from the interpreter.
// this stub is special, because it requires a live mtype argument __ bind(no_method);
Register rax_mtype = rax; __ pop(rax_want);
if (TaggedStackInterpreter) __ pop(rcx_fail);
interp_entry = __ pc(); __ pop(rcx_fail);
__ push(rax_mtype); // required mtype __ push(rax_want);
__ push(rcx_recv); // random mh (1st stacked argument) __ push(rcx_fail);
__ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
} }
break; break;
@ -442,7 +474,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ load_klass(rax_klass, rcx_recv); __ load_klass(rax_klass, rcx_recv);
__ verify_oop(rax_klass); __ verify_oop(rax_klass);
Register rcx_temp = rcx_recv; Register rdi_temp = rdi;
Register rbx_method = rbx_index; Register rbx_method = rbx_index;
// get interface klass // get interface klass
@ -451,7 +483,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ lookup_interface_method(rax_klass, rdx_intf, __ lookup_interface_method(rax_klass, rdx_intf,
// note: next two args must be the same: // note: next two args must be the same:
rbx_index, rbx_method, rbx_index, rbx_method,
rcx_temp, rdi_temp,
no_such_interface); no_such_interface);
__ verify_oop(rbx_method); __ verify_oop(rbx_method);
@ -461,7 +493,10 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ bind(no_such_interface); __ bind(no_such_interface);
// Throw an exception. // Throw an exception.
// For historical reasons, it will be IncompatibleClassChangeError. // For historical reasons, it will be IncompatibleClassChangeError.
__ should_not_reach_here(); // %%% FIXME NYI __ pushptr(Address(rdx_intf, java_mirror_offset)); // required interface
__ push(rcx_recv); // bad receiver
__ push((int)Bytecodes::_invokeinterface); // who is complaining?
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
} }
break; break;
@ -524,6 +559,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
break; break;
case _adapter_retype_only: case _adapter_retype_only:
case _adapter_retype_raw:
// immediately jump to the next MH layer: // immediately jump to the next MH layer:
__ movptr(rcx_recv, rcx_mh_vmtarget); __ movptr(rcx_recv, rcx_mh_vmtarget);
__ verify_oop(rcx_recv); __ verify_oop(rcx_recv);
@ -545,10 +581,6 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ movptr(rbx_klass, rcx_amh_argument); // this is a Class object! __ movptr(rbx_klass, rcx_amh_argument); // this is a Class object!
__ movptr(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes())); __ movptr(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes()));
// get the new MH:
__ movptr(rcx_recv, rcx_mh_vmtarget);
// (now we are done with the old MH)
Label done; Label done;
__ movptr(rdx_temp, vmarg); __ movptr(rdx_temp, vmarg);
__ testl(rdx_temp, rdx_temp); __ testl(rdx_temp, rdx_temp);
@ -558,17 +590,23 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
// live at this point: // live at this point:
// - rbx_klass: klass required by the target method // - rbx_klass: klass required by the target method
// - rdx_temp: argument klass to test // - rdx_temp: argument klass to test
// - rcx_recv: method handle to invoke (after cast succeeds) // - rcx_recv: adapter method handle
__ check_klass_subtype(rdx_temp, rbx_klass, rax_argslot, done); __ check_klass_subtype(rdx_temp, rbx_klass, rax_argslot, done);
// If we get here, the type check failed! // If we get here, the type check failed!
// Call the wrong_method_type stub, passing the failing argument type in rax. // Call the wrong_method_type stub, passing the failing argument type in rax.
Register rax_mtype = rax_argslot; Register rax_mtype = rax_argslot;
__ push(rbx_klass); // missed klass (required type) __ movl(rax_argslot, rcx_amh_vmargslot); // reload argslot field
__ push(rdx_temp); // bad actual type (1st stacked argument) __ movptr(rdx_temp, vmarg);
__ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
__ pushptr(rcx_amh_argument); // required class
__ push(rdx_temp); // bad object
__ push((int)Bytecodes::_checkcast); // who is complaining?
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
__ bind(done); __ bind(done);
// get the new MH:
__ movptr(rcx_recv, rcx_mh_vmtarget);
__ jump_to_method_handle_entry(rcx_recv, rdx_temp); __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
} }
break; break;
@ -1107,11 +1145,17 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
__ bind(bad_array_klass); __ bind(bad_array_klass);
UNPUSH_RSI_RDI; UNPUSH_RSI_RDI;
__ stop("bad array klass NYI"); __ pushptr(Address(rdx_array_klass, java_mirror_offset)); // required type
__ pushptr(vmarg); // bad array
__ push((int)Bytecodes::_aaload); // who is complaining?
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
__ bind(bad_array_length); __ bind(bad_array_length);
UNPUSH_RSI_RDI; UNPUSH_RSI_RDI;
__ stop("bad array length NYI"); __ push(rcx_recv); // AMH requiring a certain length
__ pushptr(vmarg); // bad array
__ push((int)Bytecodes::_arraylength); // who is complaining?
__ jump(ExternalAddress(from_interpreted_entry(_raise_exception)));
#undef UNPUSH_RSI_RDI #undef UNPUSH_RSI_RDI
} }

View File

@ -92,8 +92,7 @@ address TemplateInterpreterGenerator::generate_ClassCastException_handler() {
return entry; return entry;
} }
// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4. // Arguments are: required type at TOS+4, failing object (or NULL) at TOS.
// pc at TOS (just for debugging)
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() { address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
address entry = __ pc(); address entry = __ pc();

View File

@ -139,7 +139,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm,
} }
__ g1_write_barrier_pre(rdx, r8, rbx, val != noreg); __ g1_write_barrier_pre(rdx, r8, rbx, val != noreg);
if (val == noreg) { if (val == noreg) {
__ store_heap_oop(Address(rdx, 0), NULL_WORD); __ store_heap_oop_null(Address(rdx, 0));
} else { } else {
__ store_heap_oop(Address(rdx, 0), val); __ store_heap_oop(Address(rdx, 0), val);
__ g1_write_barrier_post(rdx, val, r8, rbx); __ g1_write_barrier_post(rdx, val, r8, rbx);
@ -152,7 +152,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm,
case BarrierSet::CardTableExtension: case BarrierSet::CardTableExtension:
{ {
if (val == noreg) { if (val == noreg) {
__ store_heap_oop(obj, NULL_WORD); __ store_heap_oop_null(obj);
} else { } else {
__ store_heap_oop(obj, val); __ store_heap_oop(obj, val);
// flatten object address if needed // flatten object address if needed
@ -168,7 +168,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm,
case BarrierSet::ModRef: case BarrierSet::ModRef:
case BarrierSet::Other: case BarrierSet::Other:
if (val == noreg) { if (val == noreg) {
__ store_heap_oop(obj, NULL_WORD); __ store_heap_oop_null(obj);
} else { } else {
__ store_heap_oop(obj, val); __ store_heap_oop(obj, val);
} }

View File

@ -903,19 +903,20 @@ class sun_dyn_AdapterMethodHandle: public sun_dyn_BoundMethodHandle {
// Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants): // Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
enum { enum {
OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype
OP_CHECK_CAST = 0x1, // ref-to-ref conversion; requires a Class argument OP_RETYPE_RAW = 0x1, // straight retype, trusted (void->int, Object->T)
OP_PRIM_TO_PRIM = 0x2, // converts from one primitive to another OP_CHECK_CAST = 0x2, // ref-to-ref conversion; requires a Class argument
OP_REF_TO_PRIM = 0x3, // unboxes a wrapper to produce a primitive OP_PRIM_TO_PRIM = 0x3, // converts from one primitive to another
OP_PRIM_TO_REF = 0x4, // boxes a primitive into a wrapper (NYI) OP_REF_TO_PRIM = 0x4, // unboxes a wrapper to produce a primitive
OP_SWAP_ARGS = 0x5, // swap arguments (vminfo is 2nd arg) OP_PRIM_TO_REF = 0x5, // boxes a primitive into a wrapper (NYI)
OP_ROT_ARGS = 0x6, // rotate arguments (vminfo is displaced arg) OP_SWAP_ARGS = 0x6, // swap arguments (vminfo is 2nd arg)
OP_DUP_ARGS = 0x7, // duplicates one or more arguments (at TOS) OP_ROT_ARGS = 0x7, // rotate arguments (vminfo is displaced arg)
OP_DROP_ARGS = 0x8, // remove one or more argument slots OP_DUP_ARGS = 0x8, // duplicates one or more arguments (at TOS)
OP_COLLECT_ARGS = 0x9, // combine one or more arguments into a varargs (NYI) OP_DROP_ARGS = 0x9, // remove one or more argument slots
OP_SPREAD_ARGS = 0xA, // expand in place a varargs array (of known size) OP_COLLECT_ARGS = 0xA, // combine one or more arguments into a varargs (NYI)
OP_FLYBY = 0xB, // operate first on reified argument list (NYI) OP_SPREAD_ARGS = 0xB, // expand in place a varargs array (of known size)
OP_RICOCHET = 0xC, // run an adapter chain on the return value (NYI) OP_FLYBY = 0xC, // operate first on reified argument list (NYI)
CONV_OP_LIMIT = 0xD, // limit of CONV_OP enumeration OP_RICOCHET = 0xD, // run an adapter chain on the return value (NYI)
CONV_OP_LIMIT = 0xE, // limit of CONV_OP enumeration
CONV_OP_MASK = 0xF00, // this nybble contains the conversion op field CONV_OP_MASK = 0xF00, // this nybble contains the conversion op field
CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use

View File

@ -1963,7 +1963,7 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) {
WKID meth_group_end = WK_KLASS_ENUM_NAME(WrongMethodTypeException_klass); WKID meth_group_end = WK_KLASS_ENUM_NAME(WrongMethodTypeException_klass);
initialize_wk_klasses_until(meth_group_start, scan, CHECK); initialize_wk_klasses_until(meth_group_start, scan, CHECK);
if (EnableMethodHandles) { if (EnableMethodHandles) {
initialize_wk_klasses_through(meth_group_start, scan, CHECK); initialize_wk_klasses_through(meth_group_end, scan, CHECK);
} }
if (_well_known_klasses[meth_group_start] == NULL) { if (_well_known_klasses[meth_group_start] == NULL) {
// Skip the rest of the method handle classes, if MethodHandle is not loaded. // Skip the rest of the method handle classes, if MethodHandle is not loaded.

View File

@ -667,39 +667,6 @@ ConcurrentMark::~ConcurrentMark() {
// Called at the first checkpoint. // Called at the first checkpoint.
// //
#define PRINT_REACHABLE_AT_INITIAL_MARK 0
#if PRINT_REACHABLE_AT_INITIAL_MARK
static FILE* reachable_file = NULL;
class PrintReachableClosure: public OopsInGenClosure {
CMBitMap* _bm;
int _level;
public:
PrintReachableClosure(CMBitMap* bm) :
_bm(bm), _level(0) {
guarantee(reachable_file != NULL, "pre-condition");
}
void do_oop(oop* p) {
oop obj = *p;
HeapWord* obj_addr = (HeapWord*)obj;
if (obj == NULL) return;
fprintf(reachable_file, "%d: "PTR_FORMAT" -> "PTR_FORMAT" (%d)\n",
_level, p, (void*) obj, _bm->isMarked(obj_addr));
if (!_bm->isMarked(obj_addr)) {
_bm->mark(obj_addr);
_level++;
obj->oop_iterate(this);
_level--;
}
}
};
#endif // PRINT_REACHABLE_AT_INITIAL_MARK
#define SEND_HEAP_DUMP_TO_FILE 0
#if SEND_HEAP_DUMP_TO_FILE
static FILE* heap_dump_file = NULL;
#endif // SEND_HEAP_DUMP_TO_FILE
void ConcurrentMark::clearNextBitmap() { void ConcurrentMark::clearNextBitmap() {
guarantee(!G1CollectedHeap::heap()->mark_in_progress(), "Precondition."); guarantee(!G1CollectedHeap::heap()->mark_in_progress(), "Precondition.");
@ -737,32 +704,9 @@ void ConcurrentMark::checkpointRootsInitialPre() {
_has_aborted = false; _has_aborted = false;
// Find all the reachable objects... if (G1PrintReachableAtInitialMark) {
#if PRINT_REACHABLE_AT_INITIAL_MARK print_reachable(true, "before");
guarantee(reachable_file == NULL, "Protocol"); }
char fn_buf[100];
sprintf(fn_buf, "/tmp/reachable.txt.%d", os::current_process_id());
reachable_file = fopen(fn_buf, "w");
// clear the mark bitmap (no grey objects to start with)
_nextMarkBitMap->clearAll();
PrintReachableClosure prcl(_nextMarkBitMap);
g1h->process_strong_roots(true, // activate StrongRootsScope
false, // fake perm gen collection
SharedHeap::SO_AllClasses,
&prcl, // Regular roots
NULL, // do not visit active blobs
&prcl // Perm Gen Roots
);
// The root iteration above "consumed" dirty cards in the perm gen.
// Therefore, as a shortcut, we dirty all such cards.
g1h->rem_set()->invalidate(g1h->perm_gen()->used_region(), false);
fclose(reachable_file);
reachable_file = NULL;
// clear the mark bitmap again.
_nextMarkBitMap->clearAll();
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
COMPILER2_PRESENT(DerivedPointerTable::clear());
#endif // PRINT_REACHABLE_AT_INITIAL_MARK
// Initialise marking structures. This has to be done in a STW phase. // Initialise marking structures. This has to be done in a STW phase.
reset(); reset();
@ -1965,15 +1909,21 @@ void ConcurrentMark::checkpointRootsFinalWork() {
#endif #endif
} }
#ifndef PRODUCT
class ReachablePrinterOopClosure: public OopClosure { class ReachablePrinterOopClosure: public OopClosure {
private: private:
G1CollectedHeap* _g1h; G1CollectedHeap* _g1h;
CMBitMapRO* _bitmap; CMBitMapRO* _bitmap;
outputStream* _out; outputStream* _out;
bool _use_prev_marking;
public: public:
ReachablePrinterOopClosure(CMBitMapRO* bitmap, outputStream* out) : ReachablePrinterOopClosure(CMBitMapRO* bitmap,
_bitmap(bitmap), _g1h(G1CollectedHeap::heap()), _out(out) { } outputStream* out,
bool use_prev_marking) :
_g1h(G1CollectedHeap::heap()),
_bitmap(bitmap), _out(out), _use_prev_marking(use_prev_marking) { }
void do_oop(narrowOop* p) { do_oop_work(p); } void do_oop(narrowOop* p) { do_oop_work(p); }
void do_oop( oop* p) { do_oop_work(p); } void do_oop( oop* p) { do_oop_work(p); }
@ -1988,15 +1938,24 @@ public:
else { else {
HeapRegion* hr = _g1h->heap_region_containing(obj); HeapRegion* hr = _g1h->heap_region_containing(obj);
guarantee(hr != NULL, "invariant"); guarantee(hr != NULL, "invariant");
if (hr->obj_allocated_since_prev_marking(obj)) { bool over_tams = false;
if (_use_prev_marking) {
over_tams = hr->obj_allocated_since_prev_marking(obj);
} else {
over_tams = hr->obj_allocated_since_next_marking(obj);
}
if (over_tams) {
str = "over TAMS"; str = "over TAMS";
if (_bitmap->isMarked((HeapWord*) obj)) if (_bitmap->isMarked((HeapWord*) obj)) {
str2 = " AND MARKED"; str2 = " AND MARKED";
} else if (_bitmap->isMarked((HeapWord*) obj)) }
} else if (_bitmap->isMarked((HeapWord*) obj)) {
str = "marked"; str = "marked";
else } else {
str = "#### NOT MARKED ####"; str = "#### NOT MARKED ####";
} }
}
_out->print_cr(" "PTR_FORMAT" contains "PTR_FORMAT" %s%s", _out->print_cr(" "PTR_FORMAT" contains "PTR_FORMAT" %s%s",
p, (void*) obj, str, str2); p, (void*) obj, str, str2);
@ -2007,14 +1966,17 @@ class ReachablePrinterClosure: public BitMapClosure {
private: private:
CMBitMapRO* _bitmap; CMBitMapRO* _bitmap;
outputStream* _out; outputStream* _out;
bool _use_prev_marking;
public: public:
ReachablePrinterClosure(CMBitMapRO* bitmap, outputStream* out) : ReachablePrinterClosure(CMBitMapRO* bitmap,
_bitmap(bitmap), _out(out) { } outputStream* out,
bool use_prev_marking) :
_bitmap(bitmap), _out(out), _use_prev_marking(use_prev_marking) { }
bool do_bit(size_t offset) { bool do_bit(size_t offset) {
HeapWord* addr = _bitmap->offsetToHeapWord(offset); HeapWord* addr = _bitmap->offsetToHeapWord(offset);
ReachablePrinterOopClosure oopCl(_bitmap, _out); ReachablePrinterOopClosure oopCl(_bitmap, _out, _use_prev_marking);
_out->print_cr(" obj "PTR_FORMAT", offset %10d (marked)", addr, offset); _out->print_cr(" obj "PTR_FORMAT", offset %10d (marked)", addr, offset);
oop(addr)->oop_iterate(&oopCl); oop(addr)->oop_iterate(&oopCl);
@ -2028,74 +1990,109 @@ class ObjInRegionReachablePrinterClosure : public ObjectClosure {
private: private:
CMBitMapRO* _bitmap; CMBitMapRO* _bitmap;
outputStream* _out; outputStream* _out;
bool _use_prev_marking;
public: public:
ObjInRegionReachablePrinterClosure(CMBitMapRO* bitmap,
outputStream* out,
bool use_prev_marking) :
_bitmap(bitmap), _out(out), _use_prev_marking(use_prev_marking) { }
void do_object(oop o) { void do_object(oop o) {
ReachablePrinterOopClosure oopCl(_bitmap, _out); ReachablePrinterOopClosure oopCl(_bitmap, _out, _use_prev_marking);
_out->print_cr(" obj "PTR_FORMAT" (over TAMS)", (void*) o); _out->print_cr(" obj "PTR_FORMAT" (over TAMS)", (void*) o);
o->oop_iterate(&oopCl); o->oop_iterate(&oopCl);
_out->print_cr(""); _out->print_cr("");
} }
ObjInRegionReachablePrinterClosure(CMBitMapRO* bitmap, outputStream* out) :
_bitmap(bitmap), _out(out) { }
}; };
class RegionReachablePrinterClosure : public HeapRegionClosure { class RegionReachablePrinterClosure : public HeapRegionClosure {
private: private:
CMBitMapRO* _bitmap; CMBitMapRO* _bitmap;
outputStream* _out; outputStream* _out;
bool _use_prev_marking;
public: public:
bool doHeapRegion(HeapRegion* hr) { bool doHeapRegion(HeapRegion* hr) {
HeapWord* b = hr->bottom(); HeapWord* b = hr->bottom();
HeapWord* e = hr->end(); HeapWord* e = hr->end();
HeapWord* t = hr->top(); HeapWord* t = hr->top();
HeapWord* p = hr->prev_top_at_mark_start(); HeapWord* p = NULL;
if (_use_prev_marking) {
p = hr->prev_top_at_mark_start();
} else {
p = hr->next_top_at_mark_start();
}
_out->print_cr("** ["PTR_FORMAT", "PTR_FORMAT"] top: "PTR_FORMAT" " _out->print_cr("** ["PTR_FORMAT", "PTR_FORMAT"] top: "PTR_FORMAT" "
"PTAMS: "PTR_FORMAT, b, e, t, p); "TAMS: "PTR_FORMAT, b, e, t, p);
_out->print_cr(""); _out->print_cr("");
ObjInRegionReachablePrinterClosure ocl(_bitmap, _out); ObjInRegionReachablePrinterClosure ocl(_bitmap, _out, _use_prev_marking);
hr->object_iterate_mem_careful(MemRegion(p, t), &ocl); hr->object_iterate_mem_careful(MemRegion(p, t), &ocl);
return false; return false;
} }
RegionReachablePrinterClosure(CMBitMapRO* bitmap, RegionReachablePrinterClosure(CMBitMapRO* bitmap,
outputStream* out) : outputStream* out,
_bitmap(bitmap), _out(out) { } bool use_prev_marking) :
_bitmap(bitmap), _out(out), _use_prev_marking(use_prev_marking) { }
}; };
void ConcurrentMark::print_prev_bitmap_reachable() { void ConcurrentMark::print_reachable(bool use_prev_marking, const char* str) {
outputStream* out = gclog_or_tty; gclog_or_tty->print_cr("== Doing reachable object dump... ");
#if SEND_HEAP_DUMP_TO_FILE if (G1PrintReachableBaseFile == NULL) {
guarantee(heap_dump_file == NULL, "Protocol"); gclog_or_tty->print_cr(" #### error: no base file defined");
char fn_buf[100]; return;
sprintf(fn_buf, "/tmp/dump.txt.%d", os::current_process_id());
heap_dump_file = fopen(fn_buf, "w");
fileStream fstream(heap_dump_file);
out = &fstream;
#endif // SEND_HEAP_DUMP_TO_FILE
RegionReachablePrinterClosure rcl(_prevMarkBitMap, out);
out->print_cr("--- ITERATING OVER REGIONS WITH PTAMS < TOP");
_g1h->heap_region_iterate(&rcl);
out->print_cr("");
ReachablePrinterClosure cl(_prevMarkBitMap, out);
out->print_cr("--- REACHABLE OBJECTS ON THE BITMAP");
_prevMarkBitMap->iterate(&cl);
out->print_cr("");
#if SEND_HEAP_DUMP_TO_FILE
fclose(heap_dump_file);
heap_dump_file = NULL;
#endif // SEND_HEAP_DUMP_TO_FILE
} }
if (strlen(G1PrintReachableBaseFile) + 1 + strlen(str) >
(JVM_MAXPATHLEN - 1)) {
gclog_or_tty->print_cr(" #### error: file name too long");
return;
}
char file_name[JVM_MAXPATHLEN];
sprintf(file_name, "%s.%s", G1PrintReachableBaseFile, str);
gclog_or_tty->print_cr(" dumping to file %s", file_name);
fileStream fout(file_name);
if (!fout.is_open()) {
gclog_or_tty->print_cr(" #### error: could not open file");
return;
}
outputStream* out = &fout;
CMBitMapRO* bitmap = NULL;
if (use_prev_marking) {
bitmap = _prevMarkBitMap;
} else {
bitmap = _nextMarkBitMap;
}
out->print_cr("-- USING %s", (use_prev_marking) ? "PTAMS" : "NTAMS");
out->cr();
RegionReachablePrinterClosure rcl(bitmap, out, use_prev_marking);
out->print_cr("--- ITERATING OVER REGIONS WITH TAMS < TOP");
out->cr();
_g1h->heap_region_iterate(&rcl);
out->cr();
ReachablePrinterClosure cl(bitmap, out, use_prev_marking);
out->print_cr("--- ITERATING OVER MARKED OBJECTS ON THE BITMAP");
out->cr();
bitmap->iterate(&cl);
out->cr();
gclog_or_tty->print_cr(" done");
}
#endif // PRODUCT
// This note is for drainAllSATBBuffers and the code in between. // This note is for drainAllSATBBuffers and the code in between.
// In the future we could reuse a task to do this work during an // In the future we could reuse a task to do this work during an
// evacuation pause (since now tasks are not active and can be claimed // evacuation pause (since now tasks are not active and can be claimed

View File

@ -612,10 +612,11 @@ public:
// we do nothing. // we do nothing.
void markAndGrayObjectIfNecessary(oop p); void markAndGrayObjectIfNecessary(oop p);
// This iterates over the bitmap of the previous marking and prints // This iterates over the marking bitmap (either prev or next) and
// out all objects that are marked on the bitmap and indicates // prints out all objects that are marked on the bitmap and indicates
// whether what they point to is also marked or not. // whether what they point to is also marked or not. It also iterates
void print_prev_bitmap_reachable(); // the objects over TAMS (either prev or next).
void print_reachable(bool use_prev_marking, const char* str);
// Clear the next marking bitmap (will be called concurrently). // Clear the next marking bitmap (will be called concurrently).
void clearNextBitmap(); void clearNextBitmap();

View File

@ -2371,8 +2371,9 @@ void G1CollectedHeap::verify(bool allow_dirty,
gclog_or_tty->print_cr("Heap:"); gclog_or_tty->print_cr("Heap:");
print_on(gclog_or_tty, true /* extended */); print_on(gclog_or_tty, true /* extended */);
gclog_or_tty->print_cr(""); gclog_or_tty->print_cr("");
if (VerifyDuringGC && G1VerifyConcMarkPrintReachable) { if (VerifyDuringGC && G1VerifyDuringGCPrintReachable) {
concurrent_mark()->print_prev_bitmap_reachable(); concurrent_mark()->print_reachable(use_prev_marking,
"failed-verification");
} }
gclog_or_tty->flush(); gclog_or_tty->flush();
} }
@ -3135,7 +3136,7 @@ void G1CollectedHeap::finalize_for_evac_failure() {
_evac_failure_scan_stack->length() == 0, _evac_failure_scan_stack->length() == 0,
"Postcondition"); "Postcondition");
assert(!_drain_in_progress, "Postcondition"); assert(!_drain_in_progress, "Postcondition");
// Don't have to delete, since the scan stack is a resource object. delete _evac_failure_scan_stack;
_evac_failure_scan_stack = NULL; _evac_failure_scan_stack = NULL;
} }

View File

@ -1516,7 +1516,8 @@ void G1CollectorPolicy::record_collection_pause_end(bool abandoned) {
(end_time_sec - _recent_prev_end_times_for_all_gcs_sec->oldest()) * 1000.0; (end_time_sec - _recent_prev_end_times_for_all_gcs_sec->oldest()) * 1000.0;
update_recent_gc_times(end_time_sec, elapsed_ms); update_recent_gc_times(end_time_sec, elapsed_ms);
_recent_avg_pause_time_ratio = _recent_gc_times_ms->sum()/interval_ms; _recent_avg_pause_time_ratio = _recent_gc_times_ms->sum()/interval_ms;
assert(recent_avg_pause_time_ratio() < 1.00, "All GC?"); // using 1.01 to account for floating point inaccuracies
assert(recent_avg_pause_time_ratio() < 1.01, "All GC?");
} }
if (G1PolicyVerbose > 1) { if (G1PolicyVerbose > 1) {

View File

@ -55,8 +55,14 @@
develop(intx, G1MarkingVerboseLevel, 0, \ develop(intx, G1MarkingVerboseLevel, 0, \
"Level (0-4) of verboseness of the marking code") \ "Level (0-4) of verboseness of the marking code") \
\ \
develop(bool, G1VerifyConcMarkPrintReachable, false, \ develop(bool, G1PrintReachableAtInitialMark, false, \
"If conc mark verification fails, print reachable objects") \ "Reachable object dump at the initial mark pause") \
\
develop(bool, G1VerifyDuringGCPrintReachable, false, \
"If conc mark verification fails, dump reachable objects") \
\
develop(ccstr, G1PrintReachableBaseFile, NULL, \
"The base file name for the reachable object dumps") \
\ \
develop(bool, G1TraceMarkStackOverflow, false, \ develop(bool, G1TraceMarkStackOverflow, false, \
"If true, extra debugging code for CM restart for ovflw.") \ "If true, extra debugging code for CM restart for ovflw.") \

View File

@ -135,7 +135,6 @@ RSHashTable::RSHashTable(size_t capacity) :
_occupied_entries(0), _occupied_cards(0), _occupied_entries(0), _occupied_cards(0),
_entries(NEW_C_HEAP_ARRAY(SparsePRTEntry, capacity)), _entries(NEW_C_HEAP_ARRAY(SparsePRTEntry, capacity)),
_buckets(NEW_C_HEAP_ARRAY(int, capacity)), _buckets(NEW_C_HEAP_ARRAY(int, capacity)),
_next_deleted(NULL), _deleted(false),
_free_list(NullEntry), _free_region(0) _free_list(NullEntry), _free_region(0)
{ {
clear(); clear();
@ -296,40 +295,6 @@ void RSHashTable::add_entry(SparsePRTEntry* e) {
assert(e2->num_valid_cards() > 0, "Postcondition."); assert(e2->num_valid_cards() > 0, "Postcondition.");
} }
RSHashTable* RSHashTable::_head_deleted_list = NULL;
void RSHashTable::add_to_deleted_list(RSHashTable* rsht) {
assert(!rsht->deleted(), "Should delete only once.");
rsht->set_deleted(true);
RSHashTable* hd = _head_deleted_list;
while (true) {
rsht->_next_deleted = hd;
RSHashTable* res =
(RSHashTable*)
Atomic::cmpxchg_ptr(rsht, &_head_deleted_list, hd);
if (res == hd) return;
else hd = res;
}
}
RSHashTable* RSHashTable::get_from_deleted_list() {
RSHashTable* hd = _head_deleted_list;
while (hd != NULL) {
RSHashTable* next = hd->next_deleted();
RSHashTable* res =
(RSHashTable*)
Atomic::cmpxchg_ptr(next, &_head_deleted_list, hd);
if (res == hd) {
hd->set_next_deleted(NULL);
hd->set_deleted(false);
return hd;
} else {
hd = res;
}
}
return NULL;
}
CardIdx_t /* RSHashTable:: */ RSHashTableIter::find_first_card_in_list() { CardIdx_t /* RSHashTable:: */ RSHashTableIter::find_first_card_in_list() {
CardIdx_t res; CardIdx_t res;
while (_bl_ind != RSHashTable::NullEntry) { while (_bl_ind != RSHashTable::NullEntry) {
@ -442,15 +407,6 @@ void SparsePRT::cleanup_all() {
sprt->cleanup(); sprt->cleanup();
sprt = get_from_expanded_list(); sprt = get_from_expanded_list();
} }
// Now delete all deleted RSHashTables.
RSHashTable* rsht = RSHashTable::get_from_deleted_list();
while (rsht != NULL) {
#if SPARSE_PRT_VERBOSE
gclog_or_tty->print_cr("About to delete RSHT " PTR_FORMAT ".", rsht);
#endif
delete rsht;
rsht = RSHashTable::get_from_deleted_list();
}
} }
@ -511,8 +467,10 @@ void SparsePRT::clear() {
} }
void SparsePRT::cleanup() { void SparsePRT::cleanup() {
// Make sure that the current and next tables agree. (Another mechanism // Make sure that the current and next tables agree.
// takes care of deleting now-unused tables.) if (_cur != _next) {
delete _cur;
}
_cur = _next; _cur = _next;
set_expanded(false); set_expanded(false);
} }
@ -535,7 +493,8 @@ void SparsePRT::expand() {
_next->add_entry(e); _next->add_entry(e);
} }
} }
if (last != _cur) if (last != _cur) {
RSHashTable::add_to_deleted_list(last); delete last;
}
add_to_expanded_list(this); add_to_expanded_list(this);
} }

View File

@ -102,13 +102,6 @@ class RSHashTable : public CHeapObj {
int _free_region; int _free_region;
int _free_list; int _free_list;
static RSHashTable* _head_deleted_list;
RSHashTable* _next_deleted;
RSHashTable* next_deleted() { return _next_deleted; }
void set_next_deleted(RSHashTable* rsht) { _next_deleted = rsht; }
bool _deleted;
void set_deleted(bool b) { _deleted = b; }
// Requires that the caller hold a lock preventing parallel modifying // Requires that the caller hold a lock preventing parallel modifying
// operations, and that the the table be less than completely full. If // operations, and that the the table be less than completely full. If
// an entry for "region_ind" is already in the table, finds it and // an entry for "region_ind" is already in the table, finds it and
@ -154,14 +147,10 @@ public:
size_t occupied_entries() const { return _occupied_entries; } size_t occupied_entries() const { return _occupied_entries; }
size_t occupied_cards() const { return _occupied_cards; } size_t occupied_cards() const { return _occupied_cards; }
size_t mem_size() const; size_t mem_size() const;
bool deleted() { return _deleted; }
SparsePRTEntry* entry(int i) const { return &_entries[i]; } SparsePRTEntry* entry(int i) const { return &_entries[i]; }
void print(); void print();
static void add_to_deleted_list(RSHashTable* rsht);
static RSHashTable* get_from_deleted_list();
}; };
// ValueObj because will be embedded in HRRS iterator. // ValueObj because will be embedded in HRRS iterator.

View File

@ -1900,7 +1900,7 @@ void instanceKlass::release_C_heap_structures() {
} }
} }
char* instanceKlass::signature_name() const { const char* instanceKlass::signature_name() const {
const char* src = (const char*) (name()->as_C_string()); const char* src = (const char*) (name()->as_C_string());
const int src_length = (int)strlen(src); const int src_length = (int)strlen(src);
char* dest = NEW_RESOURCE_ARRAY(char, src_length + 3); char* dest = NEW_RESOURCE_ARRAY(char, src_length + 3);
@ -2259,6 +2259,10 @@ void instanceKlass::oop_print_on(oop obj, outputStream* st) {
st->print(BULLET"fake entry for array: "); st->print(BULLET"fake entry for array: ");
array_klass->print_value_on(st); array_klass->print_value_on(st);
st->cr(); st->cr();
} else if (as_klassOop() == SystemDictionary::MethodType_klass()) {
st->print(BULLET"signature: ");
java_dyn_MethodType::print_signature(obj, st);
st->cr();
} }
} }
@ -2284,6 +2288,9 @@ void instanceKlass::oop_print_value_on(oop obj, outputStream* st) {
const char* tname = type2name(java_lang_Class::primitive_type(obj)); const char* tname = type2name(java_lang_Class::primitive_type(obj));
st->print("%s", tname ? tname : "type?"); st->print("%s", tname ? tname : "type?");
} }
} else if (as_klassOop() == SystemDictionary::MethodType_klass()) {
st->print(" = ");
java_dyn_MethodType::print_signature(obj, st);
} else if (java_lang_boxing_object::is_instance(obj)) { } else if (java_lang_boxing_object::is_instance(obj)) {
st->print(" = "); st->print(" = ");
java_lang_boxing_object::print(obj, st); java_lang_boxing_object::print(obj, st);

View File

@ -722,7 +722,7 @@ class instanceKlass: public Klass {
#endif // SERIALGC #endif // SERIALGC
// Naming // Naming
char* signature_name() const; const char* signature_name() const;
// Iterators // Iterators
int oop_oop_iterate(oop obj, OopClosure* blk) { int oop_oop_iterate(oop obj, OopClosure* blk) {

View File

@ -496,11 +496,13 @@ const char* Klass::external_name() const {
return result; return result;
} }
} }
if (name() == NULL) return "<unknown>";
return name()->as_klass_external_name(); return name()->as_klass_external_name();
} }
char* Klass::signature_name() const { const char* Klass::signature_name() const {
if (name() == NULL) return "<unknown>";
return name()->as_C_string(); return name()->as_C_string();
} }

View File

@ -546,7 +546,7 @@ class Klass : public Klass_vtbl {
// For arrays, this returns the name of the element with a leading '['. // For arrays, this returns the name of the element with a leading '['.
// For classes, this returns the name with a leading 'L' and a trailing ';' // For classes, this returns the name with a leading 'L' and a trailing ';'
// and the package separators as '/'. // and the package separators as '/'.
virtual char* signature_name() const; virtual const char* signature_name() const;
// garbage collection support // garbage collection support
virtual void oop_follow_contents(oop obj) = 0; virtual void oop_follow_contents(oop obj) = 0;

View File

@ -31,8 +31,9 @@ void markOopDesc::print_on(outputStream* st) const {
st->print("locked(0x%lx)->", value()); st->print("locked(0x%lx)->", value());
markOop(*(markOop*)value())->print_on(st); markOop(*(markOop*)value())->print_on(st);
} else { } else {
assert(is_unlocked(), "just checking"); assert(is_unlocked() || has_bias_pattern(), "just checking");
st->print("mark("); st->print("mark(");
if (has_bias_pattern()) st->print("biased,");
st->print("hash %#lx,", hash()); st->print("hash %#lx,", hash());
st->print("age %d)", age()); st->print("age %d)", age());
} }

View File

@ -881,7 +881,7 @@ methodHandle methodOopDesc::make_invoke_method(KlassHandle holder,
assert((oop)p == method_type(), "pointer chase is correct"); assert((oop)p == method_type(), "pointer chase is correct");
#endif #endif
if (TraceMethodHandles) if (TraceMethodHandles && (Verbose || WizardMode))
m->print_on(tty); m->print_on(tty);
return m; return m;

View File

@ -421,21 +421,23 @@ void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st)
iklass = cik->as_instance_klass(); iklass = cik->as_instance_klass();
} else if (cik->is_type_array_klass()) { } else if (cik->is_type_array_klass()) {
cik->as_array_klass()->base_element_type()->print_name_on(st); cik->as_array_klass()->base_element_type()->print_name_on(st);
st->print("[%d]=", spobj->n_fields()); st->print("[%d]", spobj->n_fields());
} else if (cik->is_obj_array_klass()) { } else if (cik->is_obj_array_klass()) {
ciType* cie = cik->as_array_klass()->base_element_type(); ciKlass* cie = cik->as_obj_array_klass()->base_element_klass();
int ndim = 1; if (cie->is_instance_klass()) {
while (cie->is_obj_array_klass()) {
ndim += 1;
cie = cie->as_array_klass()->base_element_type();
}
cie->print_name_on(st); cie->print_name_on(st);
} else if (cie->is_type_array_klass()) {
cie->as_array_klass()->base_element_type()->print_name_on(st);
} else {
ShouldNotReachHere();
}
st->print("[%d]", spobj->n_fields());
int ndim = cik->as_array_klass()->dimension() - 1;
while (ndim-- > 0) { while (ndim-- > 0) {
st->print("[]"); st->print("[]");
} }
st->print("[%d]=", spobj->n_fields());
} }
st->print("{"); st->print("={");
uint nf = spobj->n_fields(); uint nf = spobj->n_fields();
if (nf > 0) { if (nf > 0) {
uint first_ind = spobj->first_index(); uint first_ind = spobj->first_index();

View File

@ -2116,7 +2116,7 @@ JNI_ENTRY(jobject, jni_GetObjectArrayElement(JNIEnv *env, jobjectArray array, js
DT_RETURN_MARK(GetObjectArrayElement, jobject, (const jobject&)ret); DT_RETURN_MARK(GetObjectArrayElement, jobject, (const jobject&)ret);
objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array)); objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array));
if (a->is_within_bounds(index)) { if (a->is_within_bounds(index)) {
jobject ret = JNIHandles::make_local(env, a->obj_at(index)); ret = JNIHandles::make_local(env, a->obj_at(index));
return ret; return ret;
} else { } else {
char buf[jintAsStringSize]; char buf[jintAsStringSize];
@ -2150,14 +2150,14 @@ JNI_END
#define DEFINE_NEWSCALARARRAY(Return,Allocator,Result) \ #define DEFINE_NEWSCALARARRAY(Return,Allocator,Result) \
\ \
DT_RETURN_MARK_DECL_FOR(Result, New##Result##Array, Return);\ DT_RETURN_MARK_DECL(New##Result##Array, Return);\
\ \
JNI_ENTRY(Return, \ JNI_ENTRY(Return, \
jni_New##Result##Array(JNIEnv *env, jsize len)) \ jni_New##Result##Array(JNIEnv *env, jsize len)) \
JNIWrapper("New" XSTR(Result) "Array"); \ JNIWrapper("New" XSTR(Result) "Array"); \
DTRACE_PROBE2(hotspot_jni, New##Result##Array__entry, env, len);\ DTRACE_PROBE2(hotspot_jni, New##Result##Array__entry, env, len);\
Return ret = NULL;\ Return ret = NULL;\
DT_RETURN_MARK_FOR(Result, New##Result##Array, Return, (const Return&)ret);\ DT_RETURN_MARK(New##Result##Array, Return, (const Return&)ret);\
\ \
oop obj= oopFactory::Allocator(len, CHECK_0); \ oop obj= oopFactory::Allocator(len, CHECK_0); \
ret = (Return) JNIHandles::make_local(env, obj); \ ret = (Return) JNIHandles::make_local(env, obj); \

View File

@ -33,8 +33,7 @@ bool MethodHandles::_enabled = false; // set true after successful native linkag
MethodHandleEntry* MethodHandles::_entries[MethodHandles::_EK_LIMIT] = {NULL}; MethodHandleEntry* MethodHandles::_entries[MethodHandles::_EK_LIMIT] = {NULL};
const char* MethodHandles::_entry_names[_EK_LIMIT+1] = { const char* MethodHandles::_entry_names[_EK_LIMIT+1] = {
"check_mtype", "raise_exception",
"wrong_method_type", // what happens when there is a type mismatch
"invokestatic", // how a MH emulates invokestatic "invokestatic", // how a MH emulates invokestatic
"invokespecial", // ditto for the other invokes... "invokespecial", // ditto for the other invokes...
"invokevirtual", "invokevirtual",
@ -48,6 +47,7 @@ const char* MethodHandles::_entry_names[_EK_LIMIT+1] = {
// starting at _adapter_mh_first: // starting at _adapter_mh_first:
"adapter_retype_only", // these are for AMH... "adapter_retype_only", // these are for AMH...
"adapter_retype_raw",
"adapter_check_cast", "adapter_check_cast",
"adapter_prim_to_prim", "adapter_prim_to_prim",
"adapter_ref_to_prim", "adapter_ref_to_prim",
@ -82,6 +82,8 @@ const char* MethodHandles::_entry_names[_EK_LIMIT+1] = {
NULL NULL
}; };
jobject MethodHandles::_raise_exception_method;
#ifdef ASSERT #ifdef ASSERT
bool MethodHandles::spot_check_entry_names() { bool MethodHandles::spot_check_entry_names() {
assert(!strcmp(entry_name(_invokestatic_mh), "invokestatic"), ""); assert(!strcmp(entry_name(_invokestatic_mh), "invokestatic"), "");
@ -157,7 +159,8 @@ methodOop MethodHandles::decode_DirectMethodHandle(oop mh, klassOop& receiver_li
} }
methodOop MethodHandles::decode_BoundMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) { methodOop MethodHandles::decode_BoundMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
assert(mh->klass() == SystemDictionary::BoundMethodHandle_klass(), ""); assert(sun_dyn_BoundMethodHandle::is_instance(mh), "");
assert(mh->klass() != SystemDictionary::AdapterMethodHandle_klass(), "");
for (oop bmh = mh;;) { for (oop bmh = mh;;) {
// Bound MHs can be stacked to bind several arguments. // Bound MHs can be stacked to bind several arguments.
oop target = java_dyn_MethodHandle::vmtarget(bmh); oop target = java_dyn_MethodHandle::vmtarget(bmh);
@ -174,10 +177,9 @@ methodOop MethodHandles::decode_BoundMethodHandle(oop mh, klassOop& receiver_lim
} else { } else {
// Optimized case: binding a receiver to a non-dispatched DMH // Optimized case: binding a receiver to a non-dispatched DMH
// short-circuits directly to the methodOop. // short-circuits directly to the methodOop.
// (It might be another argument besides a receiver also.)
assert(target->is_method(), "must be a simple method"); assert(target->is_method(), "must be a simple method");
methodOop m = (methodOop) target; methodOop m = (methodOop) target;
DEBUG_ONLY(int argslot = sun_dyn_BoundMethodHandle::vmargslot(bmh));
assert(argslot == m->size_of_parameters() - 1, "must be initial argument (receiver)");
decode_flags_result |= MethodHandles::_dmf_binds_method; decode_flags_result |= MethodHandles::_dmf_binds_method;
return m; return m;
} }
@ -214,6 +216,9 @@ methodOop MethodHandles::decode_MethodHandle(oop mh, klassOop& receiver_limit_re
return decode_BoundMethodHandle(mh, receiver_limit_result, decode_flags_result); return decode_BoundMethodHandle(mh, receiver_limit_result, decode_flags_result);
} else if (mhk == SystemDictionary::AdapterMethodHandle_klass()) { } else if (mhk == SystemDictionary::AdapterMethodHandle_klass()) {
return decode_AdapterMethodHandle(mh, receiver_limit_result, decode_flags_result); return decode_AdapterMethodHandle(mh, receiver_limit_result, decode_flags_result);
} else if (sun_dyn_BoundMethodHandle::is_subclass(mhk)) {
// could be a JavaMethodHandle (but not an adapter MH)
return decode_BoundMethodHandle(mh, receiver_limit_result, decode_flags_result);
} else { } else {
assert(false, "cannot parse this MH"); assert(false, "cannot parse this MH");
return NULL; // random MH? return NULL; // random MH?
@ -366,7 +371,13 @@ methodOop MethodHandles::decode_MemberName(oop mname, klassOop& receiver_limit_r
oop vmtarget = sun_dyn_MemberName::vmtarget(mname); oop vmtarget = sun_dyn_MemberName::vmtarget(mname);
int vmindex = sun_dyn_MemberName::vmindex(mname); int vmindex = sun_dyn_MemberName::vmindex(mname);
if (vmindex == VM_INDEX_UNINITIALIZED) return NULL; // not resolved if (vmindex == VM_INDEX_UNINITIALIZED) return NULL; // not resolved
return decode_vmtarget(vmtarget, vmindex, NULL, receiver_limit_result, decode_flags_result); methodOop m = decode_vmtarget(vmtarget, vmindex, NULL, receiver_limit_result, decode_flags_result);
oop clazz = sun_dyn_MemberName::clazz(mname);
if (clazz != NULL && java_lang_Class::is_instance(clazz)) {
klassOop klass = java_lang_Class::as_klassOop(clazz);
if (klass != NULL) receiver_limit_result = klass;
}
return m;
} }
// An unresolved member name is a mere symbolic reference. // An unresolved member name is a mere symbolic reference.
@ -789,6 +800,30 @@ oop MethodHandles::encode_target(Handle mh, int format, TRAPS) {
THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), msg); THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), msg);
} }
static const char* always_null_names[] = {
"java/lang/Void",
"java/lang/Null",
//"java/lang/Nothing",
"sun/dyn/empty/Empty",
NULL
};
static bool is_always_null_type(klassOop klass) {
if (!Klass::cast(klass)->oop_is_instance()) return false;
instanceKlass* ik = instanceKlass::cast(klass);
// Must be on the boot class path:
if (ik->class_loader() != NULL) return false;
// Check the name.
symbolOop name = ik->name();
for (int i = 0; ; i++) {
const char* test_name = always_null_names[i];
if (test_name == NULL) break;
if (name->equals(test_name, (int) strlen(test_name)))
return true;
}
return false;
}
bool MethodHandles::class_cast_needed(klassOop src, klassOop dst) { bool MethodHandles::class_cast_needed(klassOop src, klassOop dst) {
if (src == dst || dst == SystemDictionary::object_klass()) if (src == dst || dst == SystemDictionary::object_klass())
return false; // quickest checks return false; // quickest checks
@ -805,6 +840,12 @@ bool MethodHandles::class_cast_needed(klassOop src, klassOop dst) {
//srck = Klass::cast(SystemDictionary::object_klass()); //srck = Klass::cast(SystemDictionary::object_klass());
return true; return true;
} }
if (is_always_null_type(src)) {
// some source types are known to be never instantiated;
// they represent references which are always null
// such null references never fail to convert safely
return false;
}
return !srck->is_subclass_of(dstk->as_klassOop()); return !srck->is_subclass_of(dstk->as_klassOop());
} }
@ -814,9 +855,15 @@ static oop object_java_mirror() {
bool MethodHandles::same_basic_type_for_arguments(BasicType src, bool MethodHandles::same_basic_type_for_arguments(BasicType src,
BasicType dst, BasicType dst,
bool raw,
bool for_return) { bool for_return) {
if (for_return) {
// return values can always be forgotten: // return values can always be forgotten:
if (for_return && dst == T_VOID) return true; if (dst == T_VOID) return true;
if (src == T_VOID) return raw && (dst == T_INT);
// We allow caller to receive a garbage int, which is harmless.
// This trick is pulled by trusted code (see VerifyType.canPassRaw).
}
assert(src != T_VOID && dst != T_VOID, "should not be here"); assert(src != T_VOID && dst != T_VOID, "should not be here");
if (src == dst) return true; if (src == dst) return true;
if (type2size[src] != type2size[dst]) return false; if (type2size[src] != type2size[dst]) return false;
@ -929,8 +976,8 @@ void MethodHandles::verify_method_type(methodHandle m,
const char* err = NULL; const char* err = NULL;
int first_ptype_pos = m_needs_receiver ? 1 : 0; int first_ptype_pos = m_needs_receiver ? 1 : 0;
if (has_bound_recv && err == NULL) { if (has_bound_recv) {
first_ptype_pos -= 1; first_ptype_pos -= 1; // ptypes do not include the bound argument; start earlier in them
if (m_needs_receiver && bound_recv_type.is_null()) if (m_needs_receiver && bound_recv_type.is_null())
{ err = "bound receiver is not an object"; goto die; } { err = "bound receiver is not an object"; goto die; }
} }
@ -939,10 +986,10 @@ void MethodHandles::verify_method_type(methodHandle m,
objArrayOop ptypes = java_dyn_MethodType::ptypes(mtype()); objArrayOop ptypes = java_dyn_MethodType::ptypes(mtype());
if (ptypes->length() < first_ptype_pos) if (ptypes->length() < first_ptype_pos)
{ err = "receiver argument is missing"; goto die; } { err = "receiver argument is missing"; goto die; }
if (first_ptype_pos == -1) if (has_bound_recv)
err = check_method_receiver(m(), bound_recv_type->as_klassOop()); err = check_method_receiver(m(), bound_recv_type->as_klassOop());
else else
err = check_method_receiver(m(), java_lang_Class::as_klassOop(ptypes->obj_at(0))); err = check_method_receiver(m(), java_lang_Class::as_klassOop(ptypes->obj_at(first_ptype_pos-1)));
if (err != NULL) goto die; if (err != NULL) goto die;
} }
@ -983,7 +1030,8 @@ const char* MethodHandles::check_method_type_change(oop src_mtype, int src_beg,
int insert_argnum, oop insert_type, int insert_argnum, oop insert_type,
int change_argnum, oop change_type, int change_argnum, oop change_type,
int delete_argnum, int delete_argnum,
oop dst_mtype, int dst_beg, int dst_end) { oop dst_mtype, int dst_beg, int dst_end,
bool raw) {
objArrayOop src_ptypes = java_dyn_MethodType::ptypes(src_mtype); objArrayOop src_ptypes = java_dyn_MethodType::ptypes(src_mtype);
objArrayOop dst_ptypes = java_dyn_MethodType::ptypes(dst_mtype); objArrayOop dst_ptypes = java_dyn_MethodType::ptypes(dst_mtype);
@ -1042,7 +1090,7 @@ const char* MethodHandles::check_method_type_change(oop src_mtype, int src_beg,
if (src_type != dst_type) { if (src_type != dst_type) {
if (src_type == NULL) return "not enough arguments"; if (src_type == NULL) return "not enough arguments";
if (dst_type == NULL) return "too many arguments"; if (dst_type == NULL) return "too many arguments";
err = check_argument_type_change(src_type, dst_type, dst_idx); err = check_argument_type_change(src_type, dst_type, dst_idx, raw);
if (err != NULL) return err; if (err != NULL) return err;
} }
} }
@ -1051,7 +1099,7 @@ const char* MethodHandles::check_method_type_change(oop src_mtype, int src_beg,
oop src_rtype = java_dyn_MethodType::rtype(src_mtype); oop src_rtype = java_dyn_MethodType::rtype(src_mtype);
oop dst_rtype = java_dyn_MethodType::rtype(dst_mtype); oop dst_rtype = java_dyn_MethodType::rtype(dst_mtype);
if (src_rtype != dst_rtype) { if (src_rtype != dst_rtype) {
err = check_return_type_change(dst_rtype, src_rtype); // note reversal! err = check_return_type_change(dst_rtype, src_rtype, raw); // note reversal!
if (err != NULL) return err; if (err != NULL) return err;
} }
@ -1064,35 +1112,42 @@ const char* MethodHandles::check_argument_type_change(BasicType src_type,
klassOop src_klass, klassOop src_klass,
BasicType dst_type, BasicType dst_type,
klassOop dst_klass, klassOop dst_klass,
int argnum) { int argnum,
bool raw) {
const char* err = NULL; const char* err = NULL;
bool for_return = (argnum < 0);
// just in case: // just in case:
if (src_type == T_ARRAY) src_type = T_OBJECT; if (src_type == T_ARRAY) src_type = T_OBJECT;
if (dst_type == T_ARRAY) dst_type = T_OBJECT; if (dst_type == T_ARRAY) dst_type = T_OBJECT;
// Produce some nice messages if VerifyMethodHandles is turned on: // Produce some nice messages if VerifyMethodHandles is turned on:
if (!same_basic_type_for_arguments(src_type, dst_type, (argnum < 0))) { if (!same_basic_type_for_arguments(src_type, dst_type, raw, for_return)) {
if (src_type == T_OBJECT) { if (src_type == T_OBJECT) {
if (raw && dst_type == T_INT && is_always_null_type(src_klass))
return NULL; // OK to convert a null pointer to a garbage int
err = ((argnum >= 0) err = ((argnum >= 0)
? "type mismatch: passing a %s for method argument #%d, which expects primitive %s" ? "type mismatch: passing a %s for method argument #%d, which expects primitive %s"
: "type mismatch: returning a %s, but caller expects primitive %s"); : "type mismatch: returning a %s, but caller expects primitive %s");
} else if (dst_type == T_OBJECT) { } else if (dst_type == T_OBJECT) {
err = ((argnum < 0) err = ((argnum >= 0)
? "type mismatch: passing a primitive %s for method argument #%d, which expects %s" ? "type mismatch: passing a primitive %s for method argument #%d, which expects %s"
: "type mismatch: returning a primitive %s, but caller expects %s"); : "type mismatch: returning a primitive %s, but caller expects %s");
} else { } else {
err = ((argnum < 0) err = ((argnum >= 0)
? "type mismatch: passing a %s for method argument #%d, which expects %s" ? "type mismatch: passing a %s for method argument #%d, which expects %s"
: "type mismatch: returning a %s, but caller expects %s"); : "type mismatch: returning a %s, but caller expects %s");
} }
} else if (src_type == T_OBJECT && class_cast_needed(src_klass, dst_klass)) { } else if (src_type == T_OBJECT && dst_type == T_OBJECT &&
class_cast_needed(src_klass, dst_klass)) {
if (!class_cast_needed(dst_klass, src_klass)) { if (!class_cast_needed(dst_klass, src_klass)) {
err = ((argnum < 0) if (raw)
return NULL; // reverse cast is OK; the MH target is trusted to enforce it
err = ((argnum >= 0)
? "cast required: passing a %s for method argument #%d, which expects %s" ? "cast required: passing a %s for method argument #%d, which expects %s"
: "cast required: returning a %s, but caller expects %s"); : "cast required: returning a %s, but caller expects %s");
} else { } else {
err = ((argnum < 0) err = ((argnum >= 0)
? "reference mismatch: passing a %s for method argument #%d, which expects %s" ? "reference mismatch: passing a %s for method argument #%d, which expects %s"
: "reference mismatch: returning a %s, but caller expects %s"); : "reference mismatch: returning a %s, but caller expects %s");
} }
@ -1429,10 +1484,10 @@ void MethodHandles::verify_BoundMethodHandle(Handle mh, Handle target, int argnu
assert(this_pushes == slots_pushed, "BMH pushes one or two stack slots"); assert(this_pushes == slots_pushed, "BMH pushes one or two stack slots");
assert(slots_pushed <= MethodHandlePushLimit, ""); assert(slots_pushed <= MethodHandlePushLimit, "");
} else { } else {
int prev_pushes = decode_MethodHandle_stack_pushes(target()); int target_pushes = decode_MethodHandle_stack_pushes(target());
assert(this_pushes == slots_pushed + prev_pushes, "BMH stack motion must be correct"); assert(this_pushes == slots_pushed + target_pushes, "BMH stack motion must be correct");
// do not blow the stack; use a Java-based adapter if this limit is exceeded // do not blow the stack; use a Java-based adapter if this limit is exceeded
if (slots_pushed + prev_pushes > MethodHandlePushLimit) if (slots_pushed + target_pushes > MethodHandlePushLimit)
err = "too many bound parameters"; err = "too many bound parameters";
} }
} }
@ -1588,6 +1643,11 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
if (err == NULL) { if (err == NULL) {
// Check that the src/dest types are supplied if needed. // Check that the src/dest types are supplied if needed.
switch (ek) { switch (ek) {
case _adapter_check_cast:
if (src != T_OBJECT || dest != T_OBJECT) {
err = "adapter requires object src/dest conversion subfields";
}
break;
case _adapter_prim_to_prim: case _adapter_prim_to_prim:
if (!is_java_primitive(src) || !is_java_primitive(dest) || src == dest) { if (!is_java_primitive(src) || !is_java_primitive(dest) || src == dest) {
err = "adapter requires primitive src/dest conversion subfields"; break; err = "adapter requires primitive src/dest conversion subfields"; break;
@ -1616,9 +1676,9 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
err = "adapter requires src/dest conversion subfields for swap"; break; err = "adapter requires src/dest conversion subfields for swap"; break;
} }
int swap_size = type2size[src]; int swap_size = type2size[src];
oop src_mtype = sun_dyn_AdapterMethodHandle::type(target()); oop src_mtype = sun_dyn_AdapterMethodHandle::type(mh());
oop dest_mtype = sun_dyn_AdapterMethodHandle::type(mh()); oop dest_mtype = sun_dyn_AdapterMethodHandle::type(target());
int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(src_mtype); int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(target());
int src_slot = argslot; int src_slot = argslot;
int dest_slot = vminfo; int dest_slot = vminfo;
bool rotate_up = (src_slot > dest_slot); // upward rotation bool rotate_up = (src_slot > dest_slot); // upward rotation
@ -1729,22 +1789,22 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
// Make sure this adapter does not push too deeply. // Make sure this adapter does not push too deeply.
int slots_pushed = stack_move / stack_move_unit(); int slots_pushed = stack_move / stack_move_unit();
int this_vmslots = java_dyn_MethodHandle::vmslots(mh()); int this_vmslots = java_dyn_MethodHandle::vmslots(mh());
int prev_vmslots = java_dyn_MethodHandle::vmslots(target()); int target_vmslots = java_dyn_MethodHandle::vmslots(target());
if (slots_pushed != (this_vmslots - prev_vmslots)) { if (slots_pushed != (target_vmslots - this_vmslots)) {
err = "stack_move inconsistent with previous and current MethodType vmslots"; err = "stack_move inconsistent with previous and current MethodType vmslots";
} else if (slots_pushed > 0) { } else if (slots_pushed > 0) {
// verify stack_move against MethodHandlePushLimit // verify stack_move against MethodHandlePushLimit
int prev_pushes = decode_MethodHandle_stack_pushes(target()); int target_pushes = decode_MethodHandle_stack_pushes(target());
// do not blow the stack; use a Java-based adapter if this limit is exceeded // do not blow the stack; use a Java-based adapter if this limit is exceeded
if (slots_pushed + prev_pushes > MethodHandlePushLimit) { if (slots_pushed + target_pushes > MethodHandlePushLimit) {
err = "adapter pushes too many parameters"; err = "adapter pushes too many parameters";
} }
} }
// While we're at it, check that the stack motion decoder works: // While we're at it, check that the stack motion decoder works:
DEBUG_ONLY(int prev_pushes = decode_MethodHandle_stack_pushes(target())); DEBUG_ONLY(int target_pushes = decode_MethodHandle_stack_pushes(target()));
DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh())); DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh()));
assert(this_pushes == slots_pushed + prev_pushes, "AMH stack motion must be correct"); assert(this_pushes == slots_pushed + target_pushes, "AMH stack motion must be correct");
} }
if (err == NULL && vminfo != 0) { if (err == NULL && vminfo != 0) {
@ -1761,7 +1821,11 @@ void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
if (err == NULL) { if (err == NULL) {
switch (ek) { switch (ek) {
case _adapter_retype_only: case _adapter_retype_only:
err = check_method_type_passthrough(src_mtype(), dst_mtype()); err = check_method_type_passthrough(src_mtype(), dst_mtype(), false);
break;
case _adapter_retype_raw:
err = check_method_type_passthrough(src_mtype(), dst_mtype(), true);
break; break;
case _adapter_check_cast: case _adapter_check_cast:
@ -1821,6 +1885,7 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
// Now it's time to finish the case analysis and pick a MethodHandleEntry. // Now it's time to finish the case analysis and pick a MethodHandleEntry.
switch (ek_orig) { switch (ek_orig) {
case _adapter_retype_only: case _adapter_retype_only:
case _adapter_retype_raw:
case _adapter_check_cast: case _adapter_check_cast:
case _adapter_dup_args: case _adapter_dup_args:
case _adapter_drop_args: case _adapter_drop_args:
@ -1888,8 +1953,7 @@ void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnu
case _adapter_rot_args: case _adapter_rot_args:
{ {
int swap_slots = type2size[src]; int swap_slots = type2size[src];
oop mtype = sun_dyn_AdapterMethodHandle::type(mh()); int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(mh());
int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(mtype);
int src_slot = argslot; int src_slot = argslot;
int dest_slot = vminfo; int dest_slot = vminfo;
int rotate = (ek_orig == _adapter_swap_args) ? 0 : (src_slot > dest_slot) ? 1 : -1; int rotate = (ek_orig == _adapter_swap_args) ? 0 : (src_slot > dest_slot) ? 1 : -1;
@ -2133,7 +2197,7 @@ JVM_ENTRY(jint, MHI_getConstant(JNIEnv *env, jobject igcls, jint which)) {
guarantee(MethodHandlePushLimit >= 2 && MethodHandlePushLimit <= 0xFF, guarantee(MethodHandlePushLimit >= 2 && MethodHandlePushLimit <= 0xFF,
"MethodHandlePushLimit parameter must be in valid range"); "MethodHandlePushLimit parameter must be in valid range");
return MethodHandlePushLimit; return MethodHandlePushLimit;
case MethodHandles::GC_JVM_STACK_MOVE_LIMIT: case MethodHandles::GC_JVM_STACK_MOVE_UNIT:
// return number of words per slot, signed according to stack direction // return number of words per slot, signed according to stack direction
return MethodHandles::stack_move_unit(); return MethodHandles::stack_move_unit();
} }
@ -2144,7 +2208,7 @@ JVM_END
#ifndef PRODUCT #ifndef PRODUCT
#define EACH_NAMED_CON(template) \ #define EACH_NAMED_CON(template) \
template(MethodHandles,GC_JVM_PUSH_LIMIT) \ template(MethodHandles,GC_JVM_PUSH_LIMIT) \
template(MethodHandles,GC_JVM_STACK_MOVE_LIMIT) \ template(MethodHandles,GC_JVM_STACK_MOVE_UNIT) \
template(MethodHandles,ETF_HANDLE_OR_METHOD_NAME) \ template(MethodHandles,ETF_HANDLE_OR_METHOD_NAME) \
template(MethodHandles,ETF_DIRECT_HANDLE) \ template(MethodHandles,ETF_DIRECT_HANDLE) \
template(MethodHandles,ETF_METHOD_NAME) \ template(MethodHandles,ETF_METHOD_NAME) \
@ -2157,6 +2221,7 @@ JVM_END
template(sun_dyn_MemberName,MN_SEARCH_INTERFACES) \ template(sun_dyn_MemberName,MN_SEARCH_INTERFACES) \
template(sun_dyn_MemberName,VM_INDEX_UNINITIALIZED) \ template(sun_dyn_MemberName,VM_INDEX_UNINITIALIZED) \
template(sun_dyn_AdapterMethodHandle,OP_RETYPE_ONLY) \ template(sun_dyn_AdapterMethodHandle,OP_RETYPE_ONLY) \
template(sun_dyn_AdapterMethodHandle,OP_RETYPE_RAW) \
template(sun_dyn_AdapterMethodHandle,OP_CHECK_CAST) \ template(sun_dyn_AdapterMethodHandle,OP_CHECK_CAST) \
template(sun_dyn_AdapterMethodHandle,OP_PRIM_TO_PRIM) \ template(sun_dyn_AdapterMethodHandle,OP_PRIM_TO_PRIM) \
template(sun_dyn_AdapterMethodHandle,OP_REF_TO_PRIM) \ template(sun_dyn_AdapterMethodHandle,OP_REF_TO_PRIM) \
@ -2345,10 +2410,12 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class))
// note: this explicit warning-producing stuff will be replaced by auto-detection of the JSR 292 classes // note: this explicit warning-producing stuff will be replaced by auto-detection of the JSR 292 classes
if (!EnableMethodHandles) { if (!EnableMethodHandles) {
warning("JSR 292 method handles are disabled in this JVM. Use -XX:+EnableMethodHandles to enable."); warning("JSR 292 method handles are disabled in this JVM. Use -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles to enable.");
return; // bind nothing return; // bind nothing
} }
bool enable_MH = true;
{ {
ThreadToNativeFromVM ttnfv(thread); ThreadToNativeFromVM ttnfv(thread);
@ -2356,14 +2423,33 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class))
if (env->ExceptionOccurred()) { if (env->ExceptionOccurred()) {
MethodHandles::set_enabled(false); MethodHandles::set_enabled(false);
warning("JSR 292 method handle code is mismatched to this JVM. Disabling support."); warning("JSR 292 method handle code is mismatched to this JVM. Disabling support.");
enable_MH = false;
env->ExceptionClear(); env->ExceptionClear();
} else {
MethodHandles::set_enabled(true);
} }
} }
if (enable_MH) {
KlassHandle MHI_klass = SystemDictionaryHandles::MethodHandleImpl_klass();
if (MHI_klass.not_null()) {
symbolHandle raiseException_name = oopFactory::new_symbol_handle("raiseException", CHECK);
symbolHandle raiseException_sig = oopFactory::new_symbol_handle("(ILjava/lang/Object;Ljava/lang/Object;)V", CHECK);
methodOop raiseException_method = instanceKlass::cast(MHI_klass->as_klassOop())
->find_method(raiseException_name(), raiseException_sig());
if (raiseException_method != NULL && raiseException_method->is_static()) {
MethodHandles::set_raise_exception_method(raiseException_method);
} else {
warning("JSR 292 method handle code is mismatched to this JVM. Disabling support.");
enable_MH = false;
}
}
}
if (enable_MH) {
MethodHandles::set_enabled(true);
}
if (!EnableInvokeDynamic) { if (!EnableInvokeDynamic) {
warning("JSR 292 invokedynamic is disabled in this JVM. Use -XX:+EnableInvokeDynamic to enable."); warning("JSR 292 invokedynamic is disabled in this JVM. Use -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic to enable.");
return; // bind nothing return; // bind nothing
} }

View File

@ -32,8 +32,7 @@ class MethodHandles: AllStatic {
// See also javaClasses for layouts java_dyn_Method{Handle,Type,Type::Form}. // See also javaClasses for layouts java_dyn_Method{Handle,Type,Type::Form}.
public: public:
enum EntryKind { enum EntryKind {
_check_mtype, // how a caller calls a MH _raise_exception, // stub for error generation from other stubs
_wrong_method_type, // what happens when there is a type mismatch
_invokestatic_mh, // how a MH emulates invokestatic _invokestatic_mh, // how a MH emulates invokestatic
_invokespecial_mh, // ditto for the other invokes... _invokespecial_mh, // ditto for the other invokes...
_invokevirtual_mh, _invokevirtual_mh,
@ -47,6 +46,7 @@ class MethodHandles: AllStatic {
_adapter_mh_first, // adapter sequence goes here... _adapter_mh_first, // adapter sequence goes here...
_adapter_retype_only = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_RETYPE_ONLY, _adapter_retype_only = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_RETYPE_ONLY,
_adapter_retype_raw = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_RETYPE_RAW,
_adapter_check_cast = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_CHECK_CAST, _adapter_check_cast = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_CHECK_CAST,
_adapter_prim_to_prim = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_PRIM_TO_PRIM, _adapter_prim_to_prim = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_PRIM_TO_PRIM,
_adapter_ref_to_prim = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_REF_TO_PRIM, _adapter_ref_to_prim = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_REF_TO_PRIM,
@ -113,6 +113,8 @@ class MethodHandles: AllStatic {
static bool _enabled; static bool _enabled;
static MethodHandleEntry* _entries[_EK_LIMIT]; static MethodHandleEntry* _entries[_EK_LIMIT];
static const char* _entry_names[_EK_LIMIT+1]; static const char* _entry_names[_EK_LIMIT+1];
static jobject _raise_exception_method;
static bool ek_valid(EntryKind ek) { return (uint)ek < (uint)_EK_LIMIT; } static bool ek_valid(EntryKind ek) { return (uint)ek < (uint)_EK_LIMIT; }
static bool conv_op_valid(int op) { return (uint)op < (uint)CONV_OP_LIMIT; } static bool conv_op_valid(int op) { return (uint)op < (uint)CONV_OP_LIMIT; }
@ -131,6 +133,16 @@ class MethodHandles: AllStatic {
_entries[ek] = me; _entries[ek] = me;
} }
static methodOop raise_exception_method() {
oop rem = JNIHandles::resolve(_raise_exception_method);
assert(rem == NULL || rem->is_method(), "");
return (methodOop) rem;
}
static void set_raise_exception_method(methodOop rem) {
assert(_raise_exception_method == NULL, "");
_raise_exception_method = JNIHandles::make_global(Handle(rem));
}
static jint adapter_conversion(int conv_op, BasicType src, BasicType dest, static jint adapter_conversion(int conv_op, BasicType src, BasicType dest,
int stack_move = 0, int vminfo = 0) { int stack_move = 0, int vminfo = 0) {
assert(conv_op_valid(conv_op), "oob"); assert(conv_op_valid(conv_op), "oob");
@ -243,7 +255,7 @@ class MethodHandles: AllStatic {
enum { enum {
// format of query to getConstant: // format of query to getConstant:
GC_JVM_PUSH_LIMIT = 0, GC_JVM_PUSH_LIMIT = 0,
GC_JVM_STACK_MOVE_LIMIT = 1, GC_JVM_STACK_MOVE_UNIT = 1,
// format of result from getTarget / encode_target: // format of result from getTarget / encode_target:
ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method) ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
@ -261,7 +273,8 @@ class MethodHandles: AllStatic {
int insert_argnum, oop insert_type, int insert_argnum, oop insert_type,
int change_argnum, oop change_type, int change_argnum, oop change_type,
int delete_argnum, int delete_argnum,
oop dst_mtype, int dst_beg, int dst_end); oop dst_mtype, int dst_beg, int dst_end,
bool raw = false);
static const char* check_method_type_insertion(oop src_mtype, static const char* check_method_type_insertion(oop src_mtype,
int insert_argnum, oop insert_type, int insert_argnum, oop insert_type,
oop dst_mtype) { oop dst_mtype) {
@ -278,29 +291,29 @@ class MethodHandles: AllStatic {
change_argnum, change_type, change_argnum, change_type,
-1, dst_mtype, 0, -1); -1, dst_mtype, 0, -1);
} }
static const char* check_method_type_passthrough(oop src_mtype, oop dst_mtype) { static const char* check_method_type_passthrough(oop src_mtype, oop dst_mtype, bool raw) {
oop no_ref = NULL; oop no_ref = NULL;
return check_method_type_change(src_mtype, 0, -1, return check_method_type_change(src_mtype, 0, -1,
-1, no_ref, -1, no_ref, -1, -1, no_ref, -1, no_ref, -1,
dst_mtype, 0, -1); dst_mtype, 0, -1, raw);
} }
// These checkers operate on pairs of argument or return types: // These checkers operate on pairs of argument or return types:
static const char* check_argument_type_change(BasicType src_type, klassOop src_klass, static const char* check_argument_type_change(BasicType src_type, klassOop src_klass,
BasicType dst_type, klassOop dst_klass, BasicType dst_type, klassOop dst_klass,
int argnum); int argnum, bool raw = false);
static const char* check_argument_type_change(oop src_type, oop dst_type, static const char* check_argument_type_change(oop src_type, oop dst_type,
int argnum) { int argnum, bool raw = false) {
klassOop src_klass = NULL, dst_klass = NULL; klassOop src_klass = NULL, dst_klass = NULL;
BasicType src_bt = java_lang_Class::as_BasicType(src_type, &src_klass); BasicType src_bt = java_lang_Class::as_BasicType(src_type, &src_klass);
BasicType dst_bt = java_lang_Class::as_BasicType(dst_type, &dst_klass); BasicType dst_bt = java_lang_Class::as_BasicType(dst_type, &dst_klass);
return check_argument_type_change(src_bt, src_klass, return check_argument_type_change(src_bt, src_klass,
dst_bt, dst_klass, argnum); dst_bt, dst_klass, argnum, raw);
} }
static const char* check_return_type_change(oop src_type, oop dst_type) { static const char* check_return_type_change(oop src_type, oop dst_type, bool raw = false) {
return check_argument_type_change(src_type, dst_type, -1); return check_argument_type_change(src_type, dst_type, -1, raw);
} }
static const char* check_return_type_change(BasicType src_type, klassOop src_klass, static const char* check_return_type_change(BasicType src_type, klassOop src_klass,
@ -357,9 +370,10 @@ class MethodHandles: AllStatic {
TRAPS); TRAPS);
static bool same_basic_type_for_arguments(BasicType src, BasicType dst, static bool same_basic_type_for_arguments(BasicType src, BasicType dst,
bool raw = false,
bool for_return = false); bool for_return = false);
static bool same_basic_type_for_returns(BasicType src, BasicType dst) { static bool same_basic_type_for_returns(BasicType src, BasicType dst, bool raw = false) {
return same_basic_type_for_arguments(src, dst, true); return same_basic_type_for_arguments(src, dst, raw, true);
} }
enum { // arg_mask values enum { // arg_mask values

View File

@ -594,6 +594,7 @@ static inline uint64_t cast_uint64_t(size_t x)
\ \
nonstatic_field(PcDesc, _pc_offset, int) \ nonstatic_field(PcDesc, _pc_offset, int) \
nonstatic_field(PcDesc, _scope_decode_offset, int) \ nonstatic_field(PcDesc, _scope_decode_offset, int) \
nonstatic_field(PcDesc, _obj_decode_offset, int) \
nonstatic_field(PcDesc, _flags, PcDesc::PcDescFlags) \ nonstatic_field(PcDesc, _flags, PcDesc::PcDescFlags) \
\ \
/***************************************************/ \ /***************************************************/ \

View File

@ -1913,8 +1913,9 @@ void HeapDumper::dump_heap() {
if (use_default_filename) { if (use_default_filename) {
char fn[32]; char fn[32];
sprintf(fn, "java_pid%d", os::current_process_id()); sprintf(fn, "java_pid%d", os::current_process_id());
assert(strlen(base_path) + strlen(fn) < sizeof(base_path), "HeapDumpPath too long"); assert(strlen(base_path) + strlen(fn) + strlen(".hprof") < sizeof(base_path), "HeapDumpPath too long");
strcat(base_path, fn); strcat(base_path, fn);
strcat(base_path, ".hprof");
} }
assert(strlen(base_path) < sizeof(my_path), "Buffer too small"); assert(strlen(base_path) < sizeof(my_path), "Buffer too small");
strcpy(my_path, base_path); strcpy(my_path, base_path);
@ -1927,8 +1928,6 @@ void HeapDumper::dump_heap() {
strcat(my_path, fn); strcat(my_path, fn);
} }
dump_file_seq++; // increment seq number for next time we dump dump_file_seq++; // increment seq number for next time we dump
assert(strlen(".hprof") + strlen(my_path) < sizeof(my_path), "HeapDumpPath too long");
strcat(my_path, ".hprof");
HeapDumper dumper(false /* no GC before heap dump */, HeapDumper dumper(false /* no GC before heap dump */,
true /* send to tty */); true /* send to tty */);

View File

@ -0,0 +1,108 @@
/*
* Copyright 2009 Sun Microsystems, Inc. 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 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.
*
*/
/**
* @test
* @bug 6891750
* @summary deopt blob kills values in O5
*
* @run main Test6891750
*/
abstract class Base6891750 extends Thread {
abstract public long m();
}
class Other6891750 extends Base6891750 {
public long m() {
return 0;
}
}
public class Test6891750 extends Base6891750 {
Base6891750 d;
volatile long value = 9;
static int limit = 400000;
Test6891750() {
d = this;
}
public long m() {
return value;
}
public long test(boolean doit) {
if (doit) {
long total0 = 0;
long total1 = 0;
long total2 = 0;
long total3 = 0;
long total4 = 0;
long total5 = 0;
long total6 = 0;
long total7 = 0;
long total8 = 0;
long total9 = 0;
for (int i = 0; i < limit; i++) {
total0 += d.m();
total1 += d.m();
total2 += d.m();
total3 += d.m();
total4 += d.m();
total5 += d.m();
total6 += d.m();
total7 += d.m();
total8 += d.m();
total9 += d.m();
}
return total0 + total1 + total2 + total3 + total4 + total5 + total6 + total7 + total8 + total9;
}
return 0;
}
public void run() {
long result = test(true);
for (int i = 0; i < 300; i++) {
long result2 = test(true);
if (result != result2) {
throw new InternalError(result + " != " + result2);
}
}
}
public static void main(String[] args) throws Exception {
Test6891750 Test6891750 = new Test6891750();
// warm it up
for (int i = 0; i < 200000; i++) {
Test6891750.test(false);
}
// set in off running
Test6891750.start();
Thread.sleep(2000);
// Load a class to invalidate CHA
new Other6891750();
}
}