--- a/hotspot/agent/make/saenv.sh Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/agent/make/saenv.sh Thu Oct 29 08:49:31 2009 -0700
@@ -48,8 +48,16 @@
CPU=i386
fi
else
- LD_AUDIT_32=$STARTDIR/../src/os/solaris/proc/`uname -p`/libsaproc_audit.so
- export LD_AUDIT_32
+ # 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
+ 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`
OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger"
CPU=sparc
--- a/hotspot/agent/make/saenv64.sh Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/agent/make/saenv64.sh Thu Oct 29 08:49:31 2009 -0700
@@ -43,8 +43,16 @@
fi
fi
-LD_AUDIT_64=$STARTDIR/../src/os/solaris/proc/$CPU/libsaproc_audit.so
-export LD_AUDIT_64
+# 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
+ 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
OPTIONS="-Dsa.library.path=$SA_LIBPATH -Dsun.jvm.hotspot.debugger.useProcDebugger"
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Thu Oct 29 08:49:31 2009 -0700
@@ -926,6 +926,28 @@
}
}
},
+ 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) {
public void doit(Tokens t) {
if (t.countTokens() != 1) {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java Thu Oct 29 08:49:31 2009 -0700
@@ -173,7 +173,8 @@
CodeBlob lastBlob = null;
while (ptr != null && ptr.lessThan(end)) {
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) {
visitor.visit(blob);
if (blob == lastBlob) {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Thu Oct 29 08:49:31 2009 -0700
@@ -42,7 +42,7 @@
/** To support simple linked-list chaining of nmethods */
private static AddressField osrLinkField;
private static AddressField scavengeRootLinkField;
- private static CIntegerField scavengeRootStateField;
+ private static JByteField scavengeRootStateField;
/** Offsets for different nmethod parts */
private static CIntegerField exceptionOffsetField;
@@ -92,7 +92,7 @@
entryBCIField = type.getCIntegerField("_entry_bci");
osrLinkField = type.getAddressField("_osr_link");
scavengeRootLinkField = type.getAddressField("_scavenge_root_link");
- scavengeRootStateField = type.getCIntegerField("_scavenge_root_state");
+ scavengeRootStateField = type.getJByteField("_scavenge_root_state");
exceptionOffsetField = type.getCIntegerField("_exception_offset");
deoptOffsetField = type.getCIntegerField("_deoptimize_offset");
@@ -274,7 +274,7 @@
if (Assert.ASSERTS_ENABLED) {
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
@@ -306,11 +306,11 @@
public ScopeDesc getScopeDescNearDbg(Address pc) {
PCDesc pd = getPCDescNearDbg(pc);
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() {
- Map safepoints = new HashMap(); // Map<Address, PcDesc>
+ public Map/*<Address, PCDesc>*/ getSafepoints() {
+ Map safepoints = new HashMap(); // Map<Address, PCDesc>
sun.jvm.hotspot.debugger.Address p = null;
for (p = scopesPCsBegin(); p.lessThan(scopesPCsEnd());
p = p.addOffsetTo(pcDescSize)) {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java Thu Oct 29 08:49:31 2009 -0700
@@ -36,6 +36,7 @@
public class PCDesc extends VMObject {
private static CIntegerField pcOffsetField;
private static CIntegerField scopeDecodeOffsetField;
+ private static CIntegerField objDecodeOffsetField;
private static CIntegerField pcFlagsField;
static {
@@ -51,6 +52,7 @@
pcOffsetField = type.getCIntegerField("_pc_offset");
scopeDecodeOffsetField = type.getCIntegerField("_scope_decode_offset");
+ objDecodeOffsetField = type.getCIntegerField("_obj_decode_offset");
pcFlagsField = type.getCIntegerField("_flags");
}
@@ -68,6 +70,10 @@
return ((int) scopeDecodeOffsetField.getValue(addr));
}
+ public int getObjDecodeOffset() {
+ return ((int) objDecodeOffsetField.getValue(addr));
+ }
+
public Address getRealPC(NMethod code) {
return code.instructionsBegin().addOffsetTo(getPCOffset());
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ScopeDesc.java Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/code/ScopeDesc.java Thu Oct 29 08:49:31 2009 -0700
@@ -51,11 +51,10 @@
/** Scalar replaced bjects pool */
private List objects; // ArrayList<ScopeValue>
-
- public ScopeDesc(NMethod code, int decodeOffset, boolean reexecute) {
+ private ScopeDesc(NMethod code, int decodeOffset, List objects, boolean reexecute) {
this.code = code;
this.decodeOffset = decodeOffset;
- this.objects = decodeObjectValues(DebugInformationRecorder.SERIALIZED_NULL);
+ this.objects = objects;
this.reexecute = reexecute;
// Decode header
@@ -108,7 +107,7 @@
return decodeMonitorValues(monitorsDecodeOffset);
}
- /** Returns a List<MonitorValue> */
+ /** Returns a List<ObjectValue> */
public List getObjects() {
return objects;
}
@@ -119,7 +118,7 @@
return null;
}
- return new ScopeDesc(code, senderDecodeOffset, false);
+ return new ScopeDesc(code, senderDecodeOffset, objects, false);
}
/** Returns where the scope was decoded */
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Thu Oct 29 08:49:31 2009 -0700
@@ -807,6 +807,9 @@
Interpreter interp = VM.getVM().getInterpreter();
if (interp.contains(pc)) {
InterpreterCodelet codelet = interp.getCodeletContaining(pc);
+ if (codelet == null) {
+ return "Unknown location in the Interpreter: " + pc;
+ }
return genHTML(codelet);
}
return genHTML(blob);
@@ -969,16 +972,24 @@
}
protected String genSafepointInfo(NMethod nm, PCDesc pcDesc) {
- ScopeDesc sd = nm.getScopeDescAt(pcDesc.getRealPC(nm));
- Formatter buf = new Formatter(genHTML);
- Formatter tabs = new Formatter(genHTML);
+ ScopeDesc sd = nm.getScopeDescAt(pcDesc.getRealPC(nm));
+ Formatter buf = new Formatter(genHTML);
+ Formatter tabs = new Formatter(genHTML);
+ tabs.append(tab + tab + tab); // Initial indent for debug info
+
+ buf.beginTag("pre");
+ genScope(buf, tabs, sd);
- buf.beginTag("pre");
- genScope(buf, tabs, sd);
- buf.endTag("pre");
- buf.append(genOopMapInfo(nm, pcDesc));
+ // Reset indent for scalar replaced objects
+ tabs = new Formatter(genHTML);
+ tabs.append(tab + tab + tab); // Initial indent for debug info
- return buf.toString();
+ genScObjInfo(buf, tabs, sd);
+ buf.endTag("pre");
+
+ buf.append(genOopMapInfo(nm, pcDesc));
+
+ return buf.toString();
}
protected void genScope(Formatter buf, Formatter tabs, ScopeDesc sd) {
@@ -1022,8 +1033,95 @@
buf.append(genHTMLForMonitors(sd, monitors));
}
+ buf.br();
tabs.append(tab);
- buf.br();
+ }
+
+ 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) {
@@ -1037,8 +1135,6 @@
tmpBuf.beginTag("tr");
tmpBuf.beginTag("td");
tmpBuf.append(type);
- tmpBuf.endTag("td");
- tmpBuf.endTag("tr");
for (; ! oms.isDone(); oms.next()) {
OopMapValue omv = oms.getCurrent();
if (omv == null) {
@@ -1048,7 +1144,7 @@
VMReg vmReg = omv.getReg();
int reg = vmReg.getValue();
if (reg < stack0) {
- tmpBuf.append(VMRegImpl.getRegisterName(vmReg.getValue()));
+ tmpBuf.append(VMRegImpl.getRegisterName(reg));
} else {
tmpBuf.append('[');
tmpBuf.append(Integer.toString((reg - stack0) * 4));
@@ -1058,7 +1154,13 @@
tmpBuf.append(" = ");
VMReg vmContentReg = omv.getContentReg();
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);
}
@@ -1072,19 +1174,19 @@
OopMapValueIterator omvIterator = new OopMapValueIterator();
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.NARROWOOP_VALUE);
+ buf.append(omvIterator.iterate(oms, "narrowOops:", false));
oms = new OopMapStream(map, OopMapValue.OopTypes.VALUE_VALUE);
- buf.append(omvIterator.iterate(oms, "Value:", false));
-
- oms = new OopMapStream(map, OopMapValue.OopTypes.NARROWOOP_VALUE);
- buf.append(omvIterator.iterate(oms, "Oop:", false));
+ buf.append(omvIterator.iterate(oms, "Values:", false));
oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE);
buf.append(omvIterator.iterate(oms, "Callee saved:", true));
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");
return buf.toString();
@@ -1093,6 +1195,8 @@
protected String genOopMapInfo(NMethod nmethod, PCDesc pcDesc) {
OopMapSet mapSet = nmethod.getOopMaps();
+ if (mapSet == null || (mapSet.getSize() <= 0))
+ return "";
int pcOffset = pcDesc.getPCOffset();
OopMap map = mapSet.findMapAtOffset(pcOffset, VM.getVM().isDebugging());
if (map == null) {
@@ -1106,6 +1210,7 @@
Formatter buf = new Formatter(genHTML);
buf.beginTag("pre");
buf.append("OopMap: ");
+ buf.br();
buf.append(genHTMLForOopMap(map));
buf.endTag("pre");
@@ -1154,7 +1259,7 @@
return buf.toString();
}
- private String scopeValueAsString(ScopeValue sv) {
+ private String scopeValueAsString(ScopeDesc sd, ScopeValue sv) {
Formatter buf = new Formatter(genHTML);
if (sv.isConstantInt()) {
buf.append("int ");
@@ -1187,6 +1292,11 @@
} else {
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();
}
@@ -1219,7 +1329,7 @@
}
buf.append(", ");
- buf.append(scopeValueAsString(sv));
+ buf.append(scopeValueAsString(sd, sv));
buf.append(") ");
}
@@ -1246,7 +1356,7 @@
buf.append("(owner = ");
ScopeValue owner = mv.owner();
if (owner != null) {
- buf.append(scopeValueAsString(owner));
+ buf.append(scopeValueAsString(sd, owner));
} else {
buf.append("null");
}
@@ -1324,11 +1434,11 @@
buf.append(instr.asString(currentPc, symFinder));
}
+ buf.br();
if (isSafepoint && !prevWasCall) {
- buf.append(genSafepointInfo(nmethod, pcDesc));
+ buf.append(genSafepointInfo(nmethod, pcDesc));
}
- buf.br();
prevWasCall = instr.isCall();
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js Thu Oct 29 08:49:31 2009 -0700
@@ -1047,7 +1047,7 @@
} else {
// some type names have ':'. replace to make it as a
// JavaScript identifier
- tmp.name = tmp.name.replace(':', '_');
+ tmp.name = tmp.name.replace(':', '_').replace('<', '_').replace('>', '_').replace('*', '_').replace(' ', '_');
eval("function read" + tmp.name + "(addr) {" +
" return readVMType('" + tmp.name + "', addr);}");
eval("function print" + tmp.name + "(addr) {" +
--- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Thu Oct 29 08:49:31 2009 -0700
@@ -3213,9 +3213,8 @@
Register Oreturn0 = O0;
Register Oreturn1 = O1;
Register O2UnrollBlock = O2;
- Register O3tmp = O3;
- Register I5exception_tmp = I5;
- Register G4exception_tmp = G4_scratch;
+ Register L0deopt_mode = L0;
+ Register G4deopt_mode = G4_scratch;
int frame_size_words;
Address saved_Freturn0_addr(FP, -sizeof(double) + STACK_BIAS);
#if !defined(_LP64) && defined(COMPILER2)
@@ -3265,7 +3264,7 @@
map = RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
__ ba(false, cont);
- __ delayed()->mov(Deoptimization::Unpack_deopt, I5exception_tmp);
+ __ delayed()->mov(Deoptimization::Unpack_deopt, L0deopt_mode);
int exception_offset = __ offset() - start;
@@ -3316,7 +3315,7 @@
#endif
__ ba(false, cont);
- __ delayed()->mov(Deoptimization::Unpack_exception, I5exception_tmp);;
+ __ delayed()->mov(Deoptimization::Unpack_exception, L0deopt_mode);;
//
// Reexecute entry, similar to c2 uncommon trap
@@ -3326,7 +3325,7 @@
// 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);
- __ mov(Deoptimization::Unpack_reexecute, I5exception_tmp);
+ __ mov(Deoptimization::Unpack_reexecute, L0deopt_mode);
__ bind(cont);
@@ -3349,14 +3348,14 @@
// NOTE: we know that only O0/O1 will be reloaded by restore_result_registers
// so this move will survive
- __ mov(I5exception_tmp, G4exception_tmp);
+ __ mov(L0deopt_mode, G4deopt_mode);
__ mov(O0, O2UnrollBlock->after_save());
RegisterSaver::restore_result_registers(masm);
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);
__ delayed()->nop();
@@ -3390,10 +3389,10 @@
}
#endif
__ 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
// LP64 uses g4 in set_last_Java_frame
- __ mov(G4exception_tmp, O1);
+ __ mov(G4deopt_mode, O1);
__ set_last_Java_frame(SP, G0);
__ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames), G2_thread, O1);
#endif
@@ -3446,7 +3445,6 @@
#endif
MacroAssembler* masm = new MacroAssembler(&buffer);
Register O2UnrollBlock = O2;
- Register O3tmp = O3;
Register O2klass_index = O2;
//
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Thu Oct 29 08:49:31 2009 -0700
@@ -9419,8 +9419,9 @@
// x |= (x >> 8);
// x |= (x >> 16);
// return (WORDBITS - popc(x));
- format %{ "SRL $src,1,$dst\t! count leading zeros (int)\n\t"
- "OR $src,$tmp,$dst\n\t"
+ format %{ "SRL $src,1,$tmp\t! count leading zeros (int)\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"
"OR $dst,$tmp,$dst\n\t"
"SRL $dst,4,$tmp\n\t"
@@ -9437,7 +9438,8 @@
Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register;
__ srl(Rsrc, 1, Rtmp);
- __ or3(Rsrc, Rtmp, Rdst);
+ __ srl(Rsrc, 0, Rdst);
+ __ or3(Rdst, Rtmp, Rdst);
__ srl(Rdst, 2, Rtmp);
__ or3(Rdst, Rtmp, Rdst);
__ srl(Rdst, 4, Rtmp);
@@ -9465,7 +9467,7 @@
// x |= (x >> 16);
// x |= (x >> 32);
// 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"
"SRLX $dst,2,$tmp\n\t"
"OR $dst,$tmp,$dst\n\t"
--- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Thu Oct 29 08:49:31 2009 -0700
@@ -271,9 +271,15 @@
void trace_method_handle_stub(const char* adaptername,
oopDesc* mh,
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!
- 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
@@ -293,6 +299,10 @@
Register rbx_temp = rbx;
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");
// some handy addresses
@@ -315,6 +325,8 @@
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)) {
__ nop(); // empty stubs make SG sick
return;
@@ -328,45 +340,65 @@
__ push(rax); __ push(rbx); __ push(rcx); __ push(rdx); __ push(rsi); __ push(rdi);
__ lea(rax, Address(rsp, wordSize*6)); // entry_sp
// arguments:
+ __ push(rbp); // interpreter frame pointer
__ push(rsi); // saved_sp
__ push(rax); // entry_sp
__ push(rcx); // mh
__ push(rcx);
__ 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);
}
#endif //PRODUCT
switch ((int) ek) {
- case _check_mtype:
+ case _raise_exception:
{
- // this stub is special, because it requires a live mtype argument
- Register rax_mtype = rax;
+ // Not a real MH entry, but rather shared code for raising an exception.
+ // 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
- 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();
+ __ mov(rsp, rsi); // cut the stack back to where the caller started
- interp_entry = __ pc();
- __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
- // now rax_mtype is dead; subsequent stubs will use it as a temp
-
- __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
- }
- break;
+ // Repush the arguments as if coming from the interpreter.
+ if (TaggedStackInterpreter) __ push(frame::tag_for_basic_type(T_INT));
+ __ 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);
- case _wrong_method_type:
- {
- // this stub is special, because it requires a live mtype argument
- Register rax_mtype = rax;
+ Register rbx_method = rbx_temp;
+ Label no_method;
+ // 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);
- interp_entry = __ pc();
- __ push(rax_mtype); // required mtype
- __ push(rcx_recv); // random mh (1st stacked argument)
+ // 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.
+ __ bind(no_method);
+ __ pop(rax_want);
+ if (TaggedStackInterpreter) __ pop(rcx_fail);
+ __ pop(rcx_fail);
+ __ push(rax_want);
+ __ push(rcx_fail);
__ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
}
break;
@@ -442,7 +474,7 @@
__ load_klass(rax_klass, rcx_recv);
__ verify_oop(rax_klass);
- Register rcx_temp = rcx_recv;
+ Register rdi_temp = rdi;
Register rbx_method = rbx_index;
// get interface klass
@@ -451,7 +483,7 @@
__ lookup_interface_method(rax_klass, rdx_intf,
// note: next two args must be the same:
rbx_index, rbx_method,
- rcx_temp,
+ rdi_temp,
no_such_interface);
__ verify_oop(rbx_method);
@@ -461,7 +493,10 @@
__ bind(no_such_interface);
// Throw an exception.
// 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;
@@ -524,6 +559,7 @@
break;
case _adapter_retype_only:
+ case _adapter_retype_raw:
// immediately jump to the next MH layer:
__ movptr(rcx_recv, rcx_mh_vmtarget);
__ verify_oop(rcx_recv);
@@ -545,10 +581,6 @@
__ movptr(rbx_klass, rcx_amh_argument); // this is a Class object!
__ 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;
__ movptr(rdx_temp, vmarg);
__ testl(rdx_temp, rdx_temp);
@@ -558,17 +590,23 @@
// live at this point:
// - rbx_klass: klass required by the target method
// - 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);
// If we get here, the type check failed!
// Call the wrong_method_type stub, passing the failing argument type in rax.
Register rax_mtype = rax_argslot;
- __ push(rbx_klass); // missed klass (required type)
- __ push(rdx_temp); // bad actual type (1st stacked argument)
- __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
+ __ movl(rax_argslot, rcx_amh_vmargslot); // reload argslot field
+ __ movptr(rdx_temp, vmarg);
+
+ __ 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);
+ // get the new MH:
+ __ movptr(rcx_recv, rcx_mh_vmtarget);
__ jump_to_method_handle_entry(rcx_recv, rdx_temp);
}
break;
@@ -1107,11 +1145,17 @@
__ bind(bad_array_klass);
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);
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
}
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Oct 29 08:49:31 2009 -0700
@@ -92,8 +92,7 @@
return entry;
}
-// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4.
-// pc at TOS (just for debugging)
+// Arguments are: required type at TOS+4, failing object (or NULL) at TOS.
address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
address entry = __ pc();
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Thu Oct 29 08:49:31 2009 -0700
@@ -903,19 +903,20 @@
// Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
enum {
OP_RETYPE_ONLY = 0x0, // no argument changes; straight retype
- OP_CHECK_CAST = 0x1, // ref-to-ref conversion; requires a Class argument
- OP_PRIM_TO_PRIM = 0x2, // converts from one primitive to another
- OP_REF_TO_PRIM = 0x3, // unboxes a wrapper to produce a primitive
- OP_PRIM_TO_REF = 0x4, // boxes a primitive into a wrapper (NYI)
- OP_SWAP_ARGS = 0x5, // swap arguments (vminfo is 2nd arg)
- OP_ROT_ARGS = 0x6, // rotate arguments (vminfo is displaced arg)
- OP_DUP_ARGS = 0x7, // duplicates one or more arguments (at TOS)
- OP_DROP_ARGS = 0x8, // remove one or more argument slots
- OP_COLLECT_ARGS = 0x9, // combine one or more arguments into a varargs (NYI)
- OP_SPREAD_ARGS = 0xA, // expand in place a varargs array (of known size)
- OP_FLYBY = 0xB, // operate first on reified argument list (NYI)
- OP_RICOCHET = 0xC, // run an adapter chain on the return value (NYI)
- CONV_OP_LIMIT = 0xD, // limit of CONV_OP enumeration
+ OP_RETYPE_RAW = 0x1, // straight retype, trusted (void->int, Object->T)
+ OP_CHECK_CAST = 0x2, // ref-to-ref conversion; requires a Class argument
+ OP_PRIM_TO_PRIM = 0x3, // converts from one primitive to another
+ OP_REF_TO_PRIM = 0x4, // unboxes a wrapper to produce a primitive
+ OP_PRIM_TO_REF = 0x5, // boxes a primitive into a wrapper (NYI)
+ OP_SWAP_ARGS = 0x6, // swap arguments (vminfo is 2nd arg)
+ OP_ROT_ARGS = 0x7, // rotate arguments (vminfo is displaced arg)
+ OP_DUP_ARGS = 0x8, // duplicates one or more arguments (at TOS)
+ OP_DROP_ARGS = 0x9, // remove one or more argument slots
+ OP_COLLECT_ARGS = 0xA, // combine one or more arguments into a varargs (NYI)
+ OP_SPREAD_ARGS = 0xB, // expand in place a varargs array (of known size)
+ OP_FLYBY = 0xC, // operate first on reified argument list (NYI)
+ 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_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Oct 29 08:49:31 2009 -0700
@@ -1963,7 +1963,7 @@
WKID meth_group_end = WK_KLASS_ENUM_NAME(WrongMethodTypeException_klass);
initialize_wk_klasses_until(meth_group_start, scan, CHECK);
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) {
// Skip the rest of the method handle classes, if MethodHandle is not loaded.
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Oct 29 08:49:31 2009 -0700
@@ -1900,7 +1900,7 @@
}
}
-char* instanceKlass::signature_name() const {
+const char* instanceKlass::signature_name() const {
const char* src = (const char*) (name()->as_C_string());
const int src_length = (int)strlen(src);
char* dest = NEW_RESOURCE_ARRAY(char, src_length + 3);
@@ -2259,6 +2259,10 @@
st->print(BULLET"fake entry for array: ");
array_klass->print_value_on(st);
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 @@
const char* tname = type2name(java_lang_Class::primitive_type(obj));
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)) {
st->print(" = ");
java_lang_boxing_object::print(obj, st);
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Thu Oct 29 08:49:31 2009 -0700
@@ -722,7 +722,7 @@
#endif // SERIALGC
// Naming
- char* signature_name() const;
+ const char* signature_name() const;
// Iterators
int oop_oop_iterate(oop obj, OopClosure* blk) {
--- a/hotspot/src/share/vm/oops/klass.cpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/oops/klass.cpp Thu Oct 29 08:49:31 2009 -0700
@@ -496,11 +496,13 @@
return result;
}
}
+ if (name() == NULL) return "<unknown>";
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();
}
--- a/hotspot/src/share/vm/oops/klass.hpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/oops/klass.hpp Thu Oct 29 08:49:31 2009 -0700
@@ -546,7 +546,7 @@
// 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 ';'
// and the package separators as '/'.
- virtual char* signature_name() const;
+ virtual const char* signature_name() const;
// garbage collection support
virtual void oop_follow_contents(oop obj) = 0;
--- a/hotspot/src/share/vm/oops/markOop.cpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/oops/markOop.cpp Thu Oct 29 08:49:31 2009 -0700
@@ -31,8 +31,9 @@
st->print("locked(0x%lx)->", value());
markOop(*(markOop*)value())->print_on(st);
} else {
- assert(is_unlocked(), "just checking");
+ assert(is_unlocked() || has_bias_pattern(), "just checking");
st->print("mark(");
+ if (has_bias_pattern()) st->print("biased,");
st->print("hash %#lx,", hash());
st->print("age %d)", age());
}
--- a/hotspot/src/share/vm/oops/methodOop.cpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/oops/methodOop.cpp Thu Oct 29 08:49:31 2009 -0700
@@ -881,7 +881,7 @@
assert((oop)p == method_type(), "pointer chase is correct");
#endif
- if (TraceMethodHandles)
+ if (TraceMethodHandles && (Verbose || WizardMode))
m->print_on(tty);
return m;
--- a/hotspot/src/share/vm/opto/callnode.cpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/opto/callnode.cpp Thu Oct 29 08:49:31 2009 -0700
@@ -421,21 +421,23 @@
iklass = cik->as_instance_klass();
} else if (cik->is_type_array_klass()) {
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()) {
- ciType* cie = cik->as_array_klass()->base_element_type();
- int ndim = 1;
- while (cie->is_obj_array_klass()) {
- ndim += 1;
- cie = cie->as_array_klass()->base_element_type();
+ ciKlass* cie = cik->as_obj_array_klass()->base_element_klass();
+ if (cie->is_instance_klass()) {
+ 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();
}
- cie->print_name_on(st);
+ st->print("[%d]", spobj->n_fields());
+ int ndim = cik->as_array_klass()->dimension() - 1;
while (ndim-- > 0) {
st->print("[]");
}
- st->print("[%d]=", spobj->n_fields());
}
- st->print("{");
+ st->print("={");
uint nf = spobj->n_fields();
if (nf > 0) {
uint first_ind = spobj->first_index();
--- a/hotspot/src/share/vm/prims/methodHandles.cpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp Thu Oct 29 08:49:31 2009 -0700
@@ -33,8 +33,7 @@
MethodHandleEntry* MethodHandles::_entries[MethodHandles::_EK_LIMIT] = {NULL};
const char* MethodHandles::_entry_names[_EK_LIMIT+1] = {
- "check_mtype",
- "wrong_method_type", // what happens when there is a type mismatch
+ "raise_exception",
"invokestatic", // how a MH emulates invokestatic
"invokespecial", // ditto for the other invokes...
"invokevirtual",
@@ -48,6 +47,7 @@
// starting at _adapter_mh_first:
"adapter_retype_only", // these are for AMH...
+ "adapter_retype_raw",
"adapter_check_cast",
"adapter_prim_to_prim",
"adapter_ref_to_prim",
@@ -82,6 +82,8 @@
NULL
};
+jobject MethodHandles::_raise_exception_method;
+
#ifdef ASSERT
bool MethodHandles::spot_check_entry_names() {
assert(!strcmp(entry_name(_invokestatic_mh), "invokestatic"), "");
@@ -157,7 +159,8 @@
}
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;;) {
// Bound MHs can be stacked to bind several arguments.
oop target = java_dyn_MethodHandle::vmtarget(bmh);
@@ -174,10 +177,9 @@
} else {
// Optimized case: binding a receiver to a non-dispatched DMH
// short-circuits directly to the methodOop.
+ // (It might be another argument besides a receiver also.)
assert(target->is_method(), "must be a simple method");
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;
return m;
}
@@ -214,6 +216,9 @@
return decode_BoundMethodHandle(mh, receiver_limit_result, decode_flags_result);
} else if (mhk == SystemDictionary::AdapterMethodHandle_klass()) {
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 {
assert(false, "cannot parse this MH");
return NULL; // random MH?
@@ -366,7 +371,13 @@
oop vmtarget = sun_dyn_MemberName::vmtarget(mname);
int vmindex = sun_dyn_MemberName::vmindex(mname);
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.
@@ -789,6 +800,30 @@
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) {
if (src == dst || dst == SystemDictionary::object_klass())
return false; // quickest checks
@@ -805,6 +840,12 @@
//srck = Klass::cast(SystemDictionary::object_klass());
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());
}
@@ -814,9 +855,15 @@
bool MethodHandles::same_basic_type_for_arguments(BasicType src,
BasicType dst,
+ bool raw,
bool for_return) {
- // return values can always be forgotten:
- if (for_return && dst == T_VOID) return true;
+ if (for_return) {
+ // return values can always be forgotten:
+ 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");
if (src == dst) return true;
if (type2size[src] != type2size[dst]) return false;
@@ -929,8 +976,8 @@
const char* err = NULL;
int first_ptype_pos = m_needs_receiver ? 1 : 0;
- if (has_bound_recv && err == NULL) {
- first_ptype_pos -= 1;
+ if (has_bound_recv) {
+ first_ptype_pos -= 1; // ptypes do not include the bound argument; start earlier in them
if (m_needs_receiver && bound_recv_type.is_null())
{ err = "bound receiver is not an object"; goto die; }
}
@@ -939,10 +986,10 @@
objArrayOop ptypes = java_dyn_MethodType::ptypes(mtype());
if (ptypes->length() < first_ptype_pos)
{ 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());
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;
}
@@ -983,7 +1030,8 @@
int insert_argnum, oop insert_type,
int change_argnum, oop change_type,
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 dst_ptypes = java_dyn_MethodType::ptypes(dst_mtype);
@@ -1042,7 +1090,7 @@
if (src_type != dst_type) {
if (src_type == NULL) return "not enough 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;
}
}
@@ -1051,7 +1099,7 @@
oop src_rtype = java_dyn_MethodType::rtype(src_mtype);
oop dst_rtype = java_dyn_MethodType::rtype(dst_mtype);
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;
}
@@ -1061,38 +1109,45 @@
const char* MethodHandles::check_argument_type_change(BasicType src_type,
- klassOop src_klass,
- BasicType dst_type,
- klassOop dst_klass,
- int argnum) {
+ klassOop src_klass,
+ BasicType dst_type,
+ klassOop dst_klass,
+ int argnum,
+ bool raw) {
const char* err = NULL;
+ bool for_return = (argnum < 0);
// just in case:
if (src_type == T_ARRAY) src_type = T_OBJECT;
if (dst_type == T_ARRAY) dst_type = T_OBJECT;
// 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 (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)
? "type mismatch: passing a %s for method argument #%d, which expects primitive %s"
: "type mismatch: returning a %s, but caller expects primitive %s");
} 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: returning a primitive %s, but caller expects %s");
} else {
- err = ((argnum < 0)
+ err = ((argnum >= 0)
? "type mismatch: passing a %s for method argument #%d, which 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)) {
- 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: returning a %s, but caller expects %s");
} else {
- err = ((argnum < 0)
+ err = ((argnum >= 0)
? "reference mismatch: passing a %s for method argument #%d, which expects %s"
: "reference mismatch: returning a %s, but caller expects %s");
}
@@ -1429,10 +1484,10 @@
assert(this_pushes == slots_pushed, "BMH pushes one or two stack slots");
assert(slots_pushed <= MethodHandlePushLimit, "");
} else {
- int prev_pushes = decode_MethodHandle_stack_pushes(target());
- assert(this_pushes == slots_pushed + prev_pushes, "BMH stack motion must be correct");
+ int target_pushes = decode_MethodHandle_stack_pushes(target());
+ 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
- if (slots_pushed + prev_pushes > MethodHandlePushLimit)
+ if (slots_pushed + target_pushes > MethodHandlePushLimit)
err = "too many bound parameters";
}
}
@@ -1588,6 +1643,11 @@
if (err == NULL) {
// Check that the src/dest types are supplied if needed.
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:
if (!is_java_primitive(src) || !is_java_primitive(dest) || src == dest) {
err = "adapter requires primitive src/dest conversion subfields"; break;
@@ -1616,9 +1676,9 @@
err = "adapter requires src/dest conversion subfields for swap"; break;
}
int swap_size = type2size[src];
- oop src_mtype = sun_dyn_AdapterMethodHandle::type(target());
- oop dest_mtype = sun_dyn_AdapterMethodHandle::type(mh());
- int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(src_mtype);
+ oop src_mtype = sun_dyn_AdapterMethodHandle::type(mh());
+ oop dest_mtype = sun_dyn_AdapterMethodHandle::type(target());
+ int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(target());
int src_slot = argslot;
int dest_slot = vminfo;
bool rotate_up = (src_slot > dest_slot); // upward rotation
@@ -1729,22 +1789,22 @@
// Make sure this adapter does not push too deeply.
int slots_pushed = stack_move / stack_move_unit();
int this_vmslots = java_dyn_MethodHandle::vmslots(mh());
- int prev_vmslots = java_dyn_MethodHandle::vmslots(target());
- if (slots_pushed != (this_vmslots - prev_vmslots)) {
+ int target_vmslots = java_dyn_MethodHandle::vmslots(target());
+ if (slots_pushed != (target_vmslots - this_vmslots)) {
err = "stack_move inconsistent with previous and current MethodType vmslots";
} else if (slots_pushed > 0) {
// 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
- if (slots_pushed + prev_pushes > MethodHandlePushLimit) {
+ if (slots_pushed + target_pushes > MethodHandlePushLimit) {
err = "adapter pushes too many parameters";
}
}
// 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()));
- 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) {
@@ -1761,7 +1821,11 @@
if (err == NULL) {
switch (ek) {
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;
case _adapter_check_cast:
@@ -1821,6 +1885,7 @@
// Now it's time to finish the case analysis and pick a MethodHandleEntry.
switch (ek_orig) {
case _adapter_retype_only:
+ case _adapter_retype_raw:
case _adapter_check_cast:
case _adapter_dup_args:
case _adapter_drop_args:
@@ -1888,8 +1953,7 @@
case _adapter_rot_args:
{
int swap_slots = type2size[src];
- oop mtype = sun_dyn_AdapterMethodHandle::type(mh());
- int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(mtype);
+ int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(mh());
int src_slot = argslot;
int dest_slot = vminfo;
int rotate = (ek_orig == _adapter_swap_args) ? 0 : (src_slot > dest_slot) ? 1 : -1;
@@ -2133,7 +2197,7 @@
guarantee(MethodHandlePushLimit >= 2 && MethodHandlePushLimit <= 0xFF,
"MethodHandlePushLimit parameter must be in valid range");
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 MethodHandles::stack_move_unit();
}
@@ -2144,7 +2208,7 @@
#ifndef PRODUCT
#define EACH_NAMED_CON(template) \
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_DIRECT_HANDLE) \
template(MethodHandles,ETF_METHOD_NAME) \
@@ -2157,6 +2221,7 @@
template(sun_dyn_MemberName,MN_SEARCH_INTERFACES) \
template(sun_dyn_MemberName,VM_INDEX_UNINITIALIZED) \
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_PRIM_TO_PRIM) \
template(sun_dyn_AdapterMethodHandle,OP_REF_TO_PRIM) \
@@ -2345,10 +2410,12 @@
// note: this explicit warning-producing stuff will be replaced by auto-detection of the JSR 292 classes
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
}
+ bool enable_MH = true;
+
{
ThreadToNativeFromVM ttnfv(thread);
@@ -2356,14 +2423,33 @@
if (env->ExceptionOccurred()) {
MethodHandles::set_enabled(false);
warning("JSR 292 method handle code is mismatched to this JVM. Disabling support.");
+ enable_MH = false;
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) {
- 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
}
--- a/hotspot/src/share/vm/prims/methodHandles.hpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/prims/methodHandles.hpp Thu Oct 29 08:49:31 2009 -0700
@@ -32,8 +32,7 @@
// See also javaClasses for layouts java_dyn_Method{Handle,Type,Type::Form}.
public:
enum EntryKind {
- _check_mtype, // how a caller calls a MH
- _wrong_method_type, // what happens when there is a type mismatch
+ _raise_exception, // stub for error generation from other stubs
_invokestatic_mh, // how a MH emulates invokestatic
_invokespecial_mh, // ditto for the other invokes...
_invokevirtual_mh,
@@ -47,6 +46,7 @@
_adapter_mh_first, // adapter sequence goes here...
_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_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,
@@ -113,6 +113,8 @@
static bool _enabled;
static MethodHandleEntry* _entries[_EK_LIMIT];
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 conv_op_valid(int op) { return (uint)op < (uint)CONV_OP_LIMIT; }
@@ -131,6 +133,16 @@
_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,
int stack_move = 0, int vminfo = 0) {
assert(conv_op_valid(conv_op), "oob");
@@ -243,7 +255,7 @@
enum {
// format of query to getConstant:
GC_JVM_PUSH_LIMIT = 0,
- GC_JVM_STACK_MOVE_LIMIT = 1,
+ GC_JVM_STACK_MOVE_UNIT = 1,
// format of result from getTarget / encode_target:
ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
@@ -261,7 +273,8 @@
int insert_argnum, oop insert_type,
int change_argnum, oop change_type,
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,
int insert_argnum, oop insert_type,
oop dst_mtype) {
@@ -278,29 +291,29 @@
change_argnum, change_type,
-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;
return check_method_type_change(src_mtype, 0, -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:
static const char* check_argument_type_change(BasicType src_type, klassOop src_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,
- int argnum) {
+ int argnum, bool raw = false) {
klassOop src_klass = NULL, dst_klass = NULL;
BasicType src_bt = java_lang_Class::as_BasicType(src_type, &src_klass);
BasicType dst_bt = java_lang_Class::as_BasicType(dst_type, &dst_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) {
- return check_argument_type_change(src_type, dst_type, -1);
+ 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, raw);
}
static const char* check_return_type_change(BasicType src_type, klassOop src_klass,
@@ -357,9 +370,10 @@
TRAPS);
static bool same_basic_type_for_arguments(BasicType src, BasicType dst,
+ bool raw = false,
bool for_return = false);
- static bool same_basic_type_for_returns(BasicType src, BasicType dst) {
- return same_basic_type_for_arguments(src, dst, true);
+ static bool same_basic_type_for_returns(BasicType src, BasicType dst, bool raw = false) {
+ return same_basic_type_for_arguments(src, dst, raw, true);
}
enum { // arg_mask values
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Oct 28 10:37:17 2009 -0700
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Oct 29 08:49:31 2009 -0700
@@ -594,6 +594,7 @@
\
nonstatic_field(PcDesc, _pc_offset, int) \
nonstatic_field(PcDesc, _scope_decode_offset, int) \
+ nonstatic_field(PcDesc, _obj_decode_offset, int) \
nonstatic_field(PcDesc, _flags, PcDesc::PcDescFlags) \
\
/***************************************************/ \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6891750/Test6891750.java Thu Oct 29 08:49:31 2009 -0700
@@ -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();
+ }
+}