# HG changeset patch # User rottenha # Date 1315488991 25200 # Node ID 5596e125fe4f958f05e3f20b89a0e685f0ba201d # Parent d968f546734e7a1db0a69e5a6b5e02eeadeb7ec8# Parent 2fecca53a2c6338fc0be3d72c2e65a1ce2404ea4 Merge diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/HSDB.java --- a/agent/src/share/classes/sun/jvm/hotspot/HSDB.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/HSDB.java Thu Sep 08 06:36:31 2011 -0700 @@ -1740,7 +1740,7 @@ else if (f.isCompiledFrame()) { tty.print("compiled"); } else if (f.isEntryFrame()) { tty.print("entry"); } else if (f.isNativeFrame()) { tty.print("native"); } - else if (f.isGlueFrame()) { tty.print("glue"); } + else if (f.isRuntimeFrame()) { tty.print("runtime"); } else { tty.print("external"); } tty.print(" frame with PC = " + f.getPC() + ", SP = " + f.getSP() + ", FP = " + f.getFP()); if (f.isSignalHandlerFrameDbg()) { diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java Thu Sep 08 06:36:31 2011 -0700 @@ -102,6 +102,11 @@ /** On-Stack Replacement method */ public boolean isOSRMethod() { return false; } + public NMethod asNMethodOrNull() { + if (isNMethod()) return (NMethod)this; + return null; + } + // Boundaries public Address headerBegin() { return addr; @@ -195,7 +200,7 @@ } // Returns true, if the next frame is responsible for GC'ing oops passed as arguments - public boolean callerMustGCArguments(JavaThread thread) { return false; } + public boolean callerMustGCArguments() { return false; } public String getName() { return CStringUtilities.getString(nameField.getValue(addr)); diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java Thu Sep 08 06:36:31 2011 -0700 @@ -59,6 +59,7 @@ virtualConstructor.addMapping("RuntimeStub", RuntimeStub.class); virtualConstructor.addMapping("RicochetBlob", RicochetBlob.class); virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class); + virtualConstructor.addMapping("MethodHandlesAdapterBlob", MethodHandlesAdapterBlob.class); virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class); virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class); if (VM.getVM().isServerCompiler()) { @@ -126,6 +127,10 @@ Assert.that(result.blobContains(start) || result.blobContains(start.addOffsetTo(8)), "found wrong CodeBlob"); } + if (result.isRicochetBlob()) { + // This should probably be done for other SingletonBlobs + return VM.getVM().ricochetBlob(); + } return result; } diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/MethodHandlesAdapterBlob.java Thu Sep 08 06:36:31 2011 -0700 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.jvm.hotspot.code; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; + +public class MethodHandlesAdapterBlob extends AdapterBlob { + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static void initialize(TypeDataBase db) { + Type type = db.lookupType("MethodHandlesAdapterBlob"); + + // FIXME: add any needed fields + } + + public MethodHandlesAdapterBlob(Address addr) { + super(addr); + } + + public boolean isMethodHandlesAdapterBlob() { + return true; + } + + public String getName() { + return "MethodHandlesAdapterBlob: " + super.getName(); + } +} diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Thu Sep 08 06:36:31 2011 -0700 @@ -46,6 +46,7 @@ /** Offsets for different nmethod parts */ private static CIntegerField exceptionOffsetField; private static CIntegerField deoptOffsetField; + private static CIntegerField deoptMhOffsetField; private static CIntegerField origPCOffsetField; private static CIntegerField stubOffsetField; private static CIntegerField oopsOffsetField; @@ -95,6 +96,7 @@ exceptionOffsetField = type.getCIntegerField("_exception_offset"); deoptOffsetField = type.getCIntegerField("_deoptimize_offset"); + deoptMhOffsetField = type.getCIntegerField("_deoptimize_mh_offset"); origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); stubOffsetField = type.getCIntegerField("_stub_offset"); oopsOffsetField = type.getCIntegerField("_oops_offset"); @@ -136,10 +138,11 @@ /** Boundaries for different parts */ public Address constantsBegin() { return contentBegin(); } public Address constantsEnd() { return getEntryPoint(); } - public Address instsBegin() { return codeBegin(); } + public Address instsBegin() { return codeBegin(); } public Address instsEnd() { return headerBegin().addOffsetTo(getStubOffset()); } public Address exceptionBegin() { return headerBegin().addOffsetTo(getExceptionOffset()); } - public Address deoptBegin() { return headerBegin().addOffsetTo(getDeoptOffset()); } + public Address deoptHandlerBegin() { return headerBegin().addOffsetTo(getDeoptOffset()); } + public Address deoptMhHandlerBegin() { return headerBegin().addOffsetTo(getDeoptMhOffset()); } public Address stubBegin() { return headerBegin().addOffsetTo(getStubOffset()); } public Address stubEnd() { return headerBegin().addOffsetTo(getOopsOffset()); } public Address oopsBegin() { return headerBegin().addOffsetTo(getOopsOffset()); } @@ -250,6 +253,22 @@ return (int) scavengeRootStateField.getValue(addr); } + // MethodHandle + public boolean isMethodHandleReturn(Address returnPc) { + // Hard to read a bit fields from Java and it's only there for performance + // so just go directly to the PCDesc + // if (!hasMethodHandleInvokes()) return false; + PCDesc pd = getPCDescAt(returnPc); + if (pd == null) + return false; + return pd.isMethodHandleInvoke(); + } + + // Deopt + // Return true is the PC is one would expect if the frame is being deopted. + public boolean isDeoptPc (Address pc) { return isDeoptEntry(pc) || isDeoptMhEntry(pc); } + public boolean isDeoptEntry (Address pc) { return pc == deoptHandlerBegin(); } + public boolean isDeoptMhEntry (Address pc) { return pc == deoptMhHandlerBegin(); } /** Tells whether frames described by this nmethod can be deoptimized. Note: native wrappers cannot be deoptimized. */ @@ -388,6 +407,7 @@ private int getEntryBCI() { return (int) entryBCIField .getValue(addr); } private int getExceptionOffset() { return (int) exceptionOffsetField .getValue(addr); } private int getDeoptOffset() { return (int) deoptOffsetField .getValue(addr); } + private int getDeoptMhOffset() { return (int) deoptMhOffsetField .getValue(addr); } private int getStubOffset() { return (int) stubOffsetField .getValue(addr); } private int getOopsOffset() { return (int) oopsOffsetField .getValue(addr); } private int getScopesDataOffset() { return (int) scopesDataOffsetField .getValue(addr); } diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java Thu Sep 08 06:36:31 2011 -0700 @@ -38,6 +38,9 @@ private static CIntegerField scopeDecodeOffsetField; private static CIntegerField objDecodeOffsetField; private static CIntegerField pcFlagsField; + private static int reexecuteMask; + private static int isMethodHandleInvokeMask; + private static int returnOopMask; static { VM.registerVMInitializedObserver(new Observer() { @@ -54,6 +57,10 @@ scopeDecodeOffsetField = type.getCIntegerField("_scope_decode_offset"); objDecodeOffsetField = type.getCIntegerField("_obj_decode_offset"); pcFlagsField = type.getCIntegerField("_flags"); + + reexecuteMask = db.lookupIntConstant("PcDesc::PCDESC_reexecute"); + isMethodHandleInvokeMask = db.lookupIntConstant("PcDesc::PCDESC_is_method_handle_invoke"); + returnOopMask = db.lookupIntConstant("PcDesc::PCDESC_return_oop"); } public PCDesc(Address addr) { @@ -81,7 +88,12 @@ public boolean getReexecute() { int flags = (int)pcFlagsField.getValue(addr); - return ((flags & 0x1)== 1); //first is the reexecute bit + return (flags & reexecuteMask) != 0; + } + + public boolean isMethodHandleInvoke() { + int flags = (int)pcFlagsField.getValue(addr); + return (flags & isMethodHandleInvokeMask) != 0; } public void print(NMethod code) { diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java Thu Sep 08 06:36:31 2011 -0700 @@ -41,11 +41,15 @@ } private static void initialize(TypeDataBase db) { - // Type type = db.lookupType("RicochetBlob"); + Type type = db.lookupType("RicochetBlob"); - // FIXME: add any needed fields + bounceOffsetField = type.getCIntegerField("_bounce_offset"); + exceptionOffsetField = type.getCIntegerField("_exception_offset"); } + private static CIntegerField bounceOffsetField; + private static CIntegerField exceptionOffsetField; + public RicochetBlob(Address addr) { super(addr); } @@ -53,4 +57,14 @@ public boolean isRicochetBlob() { return true; } + + public Address bounceAddr() { + return codeBegin().addOffsetTo(bounceOffsetField.getValue(addr)); + } + + public boolean returnsToBounceAddr(Address pc) { + Address bouncePc = bounceAddr(); + return (pc.equals(bouncePc) || pc.addOffsetTo(Frame.pcReturnOffset()).equals(bouncePc)); + } + } diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/code/RuntimeStub.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/RuntimeStub.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/RuntimeStub.java Thu Sep 08 06:36:31 2011 -0700 @@ -30,6 +30,8 @@ import sun.jvm.hotspot.types.*; public class RuntimeStub extends CodeBlob { + private static CIntegerField callerMustGCArgumentsField; + static { VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { @@ -40,6 +42,7 @@ private static void initialize(TypeDataBase db) { Type type = db.lookupType("RuntimeStub"); + callerMustGCArgumentsField = type.getCIntegerField("_caller_must_gc_arguments"); // FIXME: add any needed fields } @@ -52,6 +55,11 @@ return true; } + public boolean callerMustGCArguments() { + return callerMustGCArgumentsField.getValue(addr) != 0; + } + + public String getName() { return "RuntimeStub: " + super.getName(); } diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapSet.java --- a/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapSet.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapSet.java Thu Sep 08 06:36:31 2011 -0700 @@ -246,7 +246,7 @@ } // Check if caller must update oop argument - regMap.setIncludeArgumentOops(cb.callerMustGCArguments(regMap.getThread())); + regMap.setIncludeArgumentOops(cb.callerMustGCArguments()); int nofCallee = 0; Address[] locs = new Address[2 * REG_COUNT + 1]; diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java --- a/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java Thu Sep 08 06:36:31 2011 -0700 @@ -90,7 +90,7 @@ jcode == Bytecodes._ldc2_w; if (! codeOk) return false; - ConstantTag ctag = method().getConstants().getTagAt(rawIndex()); + ConstantTag ctag = method().getConstants().getTagAt(poolIndex()); if (jcode == Bytecodes._ldc2_w) { // has to be double or long return (ctag.isDouble() || ctag.isLong()) ? true: false; diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java --- a/agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java Thu Sep 08 06:36:31 2011 -0700 @@ -28,11 +28,13 @@ import com.sun.jdi.*; +import sun.jvm.hotspot.memory.SystemDictionary; import sun.jvm.hotspot.oops.Instance; import sun.jvm.hotspot.oops.InstanceKlass; import sun.jvm.hotspot.oops.ArrayKlass; import sun.jvm.hotspot.oops.JVMDIClassStatus; import sun.jvm.hotspot.oops.Klass; +import sun.jvm.hotspot.oops.ObjArray; import sun.jvm.hotspot.oops.Oop; import sun.jvm.hotspot.oops.Symbol; import sun.jvm.hotspot.oops.DefaultHeapVisitor; @@ -53,6 +55,7 @@ private SoftReference methodsCache; private SoftReference allMethodsCache; private SoftReference nestedTypesCache; + private SoftReference methodInvokesCache; /* to mark when no info available */ static final SDE NO_SDE_INFO_MARK = new SDE(); @@ -82,6 +85,27 @@ return method; } } + if (ref.getMethodHolder().equals(SystemDictionary.getMethodHandleKlass())) { + // invoke methods are generated as needed, so make mirrors as needed + List mis = null; + if (methodInvokesCache == null) { + mis = new ArrayList(); + methodInvokesCache = new SoftReference(mis); + } else { + mis = (List)methodInvokesCache.get(); + } + it = mis.iterator(); + while (it.hasNext()) { + MethodImpl method = (MethodImpl)it.next(); + if (ref.equals(method.ref())) { + return method; + } + } + + MethodImpl method = MethodImpl.createMethodImpl(vm, this, ref); + mis.add(method); + return method; + } throw new IllegalArgumentException("Invalid method id: " + ref); } diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/jdi/StackFrameImpl.java --- a/agent/src/share/classes/sun/jvm/hotspot/jdi/StackFrameImpl.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/jdi/StackFrameImpl.java Thu Sep 08 06:36:31 2011 -0700 @@ -123,6 +123,9 @@ Assert.that(values.size() > 0, "this is missing"); } // 'this' at index 0. + if (values.get(0).getType() == BasicType.getTConflict()) { + return null; + } OopHandle handle = values.oopHandleAt(0); ObjectHeap heap = vm.saObjectHeap(); thisObject = vm.objectMirror(heap.newOop(handle)); @@ -210,6 +213,8 @@ validateStackFrame(); StackValueCollection values = saFrame.getLocals(); MethodImpl mmm = (MethodImpl)location.method(); + if (mmm.isNative()) + return null; List argSigs = mmm.argumentSignatures(); int count = argSigs.size(); List res = new ArrayList(0); @@ -231,34 +236,67 @@ ValueImpl valueImpl = null; OopHandle handle = null; ObjectHeap heap = vm.saObjectHeap(); - if (variableType == BasicType.T_BOOLEAN) { + if (values.get(ss).getType() == BasicType.getTConflict()) { + // Dead locals, so just represent them as a zero of the appropriate type + if (variableType == BasicType.T_BOOLEAN) { + valueImpl = (BooleanValueImpl) vm.mirrorOf(false); + } else if (variableType == BasicType.T_CHAR) { + valueImpl = (CharValueImpl) vm.mirrorOf((char)0); + } else if (variableType == BasicType.T_FLOAT) { + valueImpl = (FloatValueImpl) vm.mirrorOf((float)0); + } else if (variableType == BasicType.T_DOUBLE) { + valueImpl = (DoubleValueImpl) vm.mirrorOf((double)0); + } else if (variableType == BasicType.T_BYTE) { + valueImpl = (ByteValueImpl) vm.mirrorOf((byte)0); + } else if (variableType == BasicType.T_SHORT) { + valueImpl = (ShortValueImpl) vm.mirrorOf((short)0); + } else if (variableType == BasicType.T_INT) { + valueImpl = (IntegerValueImpl) vm.mirrorOf((int)0); + } else if (variableType == BasicType.T_LONG) { + valueImpl = (LongValueImpl) vm.mirrorOf((long)0); + } else if (variableType == BasicType.T_OBJECT) { + // we may have an [Ljava/lang/Object; - i.e., Object[] with the + // elements themselves may be arrays because every array is an Object. + handle = null; + valueImpl = (ObjectReferenceImpl) vm.objectMirror(heap.newOop(handle)); + } else if (variableType == BasicType.T_ARRAY) { + handle = null; + valueImpl = vm.arrayMirror((Array)heap.newOop(handle)); + } else if (variableType == BasicType.T_VOID) { + valueImpl = new VoidValueImpl(vm); + } else { + throw new RuntimeException("Should not read here"); + } + } else { + if (variableType == BasicType.T_BOOLEAN) { valueImpl = (BooleanValueImpl) vm.mirrorOf(values.booleanAt(ss)); - } else if (variableType == BasicType.T_CHAR) { + } else if (variableType == BasicType.T_CHAR) { valueImpl = (CharValueImpl) vm.mirrorOf(values.charAt(ss)); - } else if (variableType == BasicType.T_FLOAT) { + } else if (variableType == BasicType.T_FLOAT) { valueImpl = (FloatValueImpl) vm.mirrorOf(values.floatAt(ss)); - } else if (variableType == BasicType.T_DOUBLE) { + } else if (variableType == BasicType.T_DOUBLE) { valueImpl = (DoubleValueImpl) vm.mirrorOf(values.doubleAt(ss)); - } else if (variableType == BasicType.T_BYTE) { + } else if (variableType == BasicType.T_BYTE) { valueImpl = (ByteValueImpl) vm.mirrorOf(values.byteAt(ss)); - } else if (variableType == BasicType.T_SHORT) { + } else if (variableType == BasicType.T_SHORT) { valueImpl = (ShortValueImpl) vm.mirrorOf(values.shortAt(ss)); - } else if (variableType == BasicType.T_INT) { + } else if (variableType == BasicType.T_INT) { valueImpl = (IntegerValueImpl) vm.mirrorOf(values.intAt(ss)); - } else if (variableType == BasicType.T_LONG) { + } else if (variableType == BasicType.T_LONG) { valueImpl = (LongValueImpl) vm.mirrorOf(values.longAt(ss)); - } else if (variableType == BasicType.T_OBJECT) { + } else if (variableType == BasicType.T_OBJECT) { // we may have an [Ljava/lang/Object; - i.e., Object[] with the // elements themselves may be arrays because every array is an Object. handle = values.oopHandleAt(ss); valueImpl = (ObjectReferenceImpl) vm.objectMirror(heap.newOop(handle)); - } else if (variableType == BasicType.T_ARRAY) { + } else if (variableType == BasicType.T_ARRAY) { handle = values.oopHandleAt(ss); valueImpl = vm.arrayMirror((Array)heap.newOop(handle)); - } else if (variableType == BasicType.T_VOID) { + } else if (variableType == BasicType.T_VOID) { valueImpl = new VoidValueImpl(vm); - } else { + } else { throw new RuntimeException("Should not read here"); + } } return valueImpl; diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java Thu Sep 08 06:36:31 2011 -0700 @@ -44,6 +44,7 @@ private static sun.jvm.hotspot.types.OopField systemKlassField; private static sun.jvm.hotspot.types.OopField threadKlassField; private static sun.jvm.hotspot.types.OopField threadGroupKlassField; + private static sun.jvm.hotspot.types.OopField methodHandleKlassField; static { VM.registerVMInitializedObserver(new Observer() { @@ -69,6 +70,7 @@ systemKlassField = type.getOopField(WK_KLASS("System_klass")); threadKlassField = type.getOopField(WK_KLASS("Thread_klass")); threadGroupKlassField = type.getOopField(WK_KLASS("ThreadGroup_klass")); + methodHandleKlassField = type.getOopField(WK_KLASS("MethodHandle_klass")); } // This WK functions must follow the definitions in systemDictionary.hpp: @@ -127,6 +129,10 @@ return (InstanceKlass) newOop(systemKlassField.getValue()); } + public static InstanceKlass getMethodHandleKlass() { + return (InstanceKlass) newOop(methodHandleKlassField.getValue()); + } + public InstanceKlass getAbstractOwnableSynchronizerKlass() { return (InstanceKlass) find("java/util/concurrent/locks/AbstractOwnableSynchronizer", null, null); diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java Thu Sep 08 06:36:31 2011 -0700 @@ -93,6 +93,8 @@ } public StackValueCollection getLocals() { + if (getScope() == null) + return new StackValueCollection(); List scvList = getScope().getLocals(); if (scvList == null) return new StackValueCollection(); @@ -108,6 +110,8 @@ } public StackValueCollection getExpressions() { + if (getScope() == null) + return new StackValueCollection(); List scvList = getScope().getExpressions(); if (scvList == null) return new StackValueCollection(); diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java Thu Sep 08 06:36:31 2011 -0700 @@ -33,6 +33,7 @@ import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.interpreter.*; import sun.jvm.hotspot.oops.*; +import sun.jvm.hotspot.runtime.sparc.SPARCFrame; import sun.jvm.hotspot.types.*; import sun.jvm.hotspot.utilities.*; @@ -74,11 +75,19 @@ /** Size of constMethodOopDesc for computing BCI from BCP (FIXME: hack) */ private static long constMethodOopDescSize; + private static int pcReturnOffset; + + public static int pcReturnOffset() { + return pcReturnOffset; + } + private static synchronized void initialize(TypeDataBase db) { Type constMethodOopType = db.lookupType("constMethodOopDesc"); // FIXME: not sure whether alignment here is correct or how to // force it (round up to address size?) constMethodOopDescSize = constMethodOopType.getSize(); + + pcReturnOffset = db.lookupIntConstant("frame::pc_return_offset").intValue(); } protected int bcpToBci(Address bcp, ConstMethod cm) { @@ -106,6 +115,10 @@ public void setPC(Address newpc) { pc = newpc; } public boolean isDeoptimized() { return deoptimized; } + public CodeBlob cb() { + return VM.getVM().getCodeCache().findBlob(getPC()); + } + public abstract Address getSP(); public abstract Address getID(); public abstract Address getFP(); @@ -134,6 +147,12 @@ } } + public boolean isRicochetFrame() { + CodeBlob cb = VM.getVM().getCodeCache().findBlob(getPC()); + RicochetBlob rcb = VM.getVM().ricochetBlob(); + return (cb == rcb && rcb != null && rcb.returnsToBounceAddr(getPC())); + } + public boolean isCompiledFrame() { if (Assert.ASSERTS_ENABLED) { Assert.that(!VM.getVM().isCore(), "noncore builds only"); @@ -142,7 +161,7 @@ return (cb != null && cb.isJavaMethod()); } - public boolean isGlueFrame() { + public boolean isRuntimeFrame() { if (Assert.ASSERTS_ENABLED) { Assert.that(!VM.getVM().isCore(), "noncore builds only"); } @@ -197,7 +216,8 @@ public Frame realSender(RegisterMap map) { if (!VM.getVM().isCore()) { Frame result = sender(map); - while (result.isGlueFrame()) { + while (result.isRuntimeFrame() || + result.isRicochetFrame()) { result = result.sender(map); } return result; @@ -611,6 +631,9 @@ if (Assert.ASSERTS_ENABLED) { Assert.that(cb != null, "sanity check"); } + if (cb == VM.getVM().ricochetBlob()) { + oopsRicochetDo(oopVisitor, regMap); + } if (cb.getOopMaps() != null) { OopMapSet.oopsDo(this, cb, regMap, oopVisitor, VM.getVM().isDebugging()); @@ -627,6 +650,10 @@ // } } + private void oopsRicochetDo (AddressVisitor oopVisitor, RegisterMap regMap) { + // XXX Empty for now + } + // FIXME: implement the above routines, plus add // oops_interpreted_arguments_do and oops_compiled_arguments_do } diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java Thu Sep 08 06:36:31 2011 -0700 @@ -128,14 +128,14 @@ } // dynamic part - we just compare the frame pointer - if (! getFrame().getFP().equals(other.getFrame().getFP())) { + if (! getFrame().equals(other.getFrame())) { return false; } return true; } public int hashCode() { - return getMethod().hashCode() ^ getBCI() ^ getFrame().getFP().hashCode(); + return getMethod().hashCode() ^ getBCI() ^ getFrame().hashCode(); } /** Structural compare */ diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/StackValue.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/StackValue.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/StackValue.java Thu Sep 08 06:36:31 2011 -0700 @@ -100,7 +100,7 @@ public int hashCode() { if (type == BasicType.getTObject()) { - return handleValue.hashCode(); + return handleValue != null ? handleValue.hashCode() : 5; } else { // Returns 0 for conflict type return (int) integerValue; diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java Thu Sep 08 06:36:31 2011 -0700 @@ -77,7 +77,7 @@ return new CompiledVFrame(f, regMap, thread, scope, mayBeImprecise); } - if (f.isGlueFrame()) { + if (f.isRuntimeFrame()) { // This is a conversion frame. Skip this frame and try again. RegisterMap tempMap = regMap.copy(); Frame s = f.sender(tempMap); diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Thu Sep 08 06:36:31 2011 -0700 @@ -30,6 +30,7 @@ import java.util.regex.*; import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.c1.*; +import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.interpreter.*; import sun.jvm.hotspot.memory.*; @@ -85,6 +86,9 @@ private Interpreter interpreter; private StubRoutines stubRoutines; private Bytes bytes; + + private RicochetBlob ricochetBlob; + /** Flags indicating whether we are attached to a core, C1, or C2 build */ private boolean usingClientCompiler; private boolean usingServerCompiler; @@ -618,6 +622,18 @@ return stubRoutines; } + public RicochetBlob ricochetBlob() { + if (ricochetBlob == null) { + Type ricochetType = db.lookupType("SharedRuntime"); + AddressField ricochetBlobAddress = ricochetType.getAddressField("_ricochet_blob"); + Address addr = ricochetBlobAddress.getValue(); + if (addr != null) { + ricochetBlob = new RicochetBlob(addr); + } + } + return ricochetBlob; + } + public VMRegImpl getVMRegImplInfo() { if (vmregImpl == null) { vmregImpl = new VMRegImpl(); diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java Wed Sep 07 14:15:07 2011 +0200 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java Thu Sep 08 06:36:31 2011 -0700 @@ -29,6 +29,7 @@ import sun.jvm.hotspot.code.*; import sun.jvm.hotspot.interpreter.*; import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.x86.*; /**
Should be able to be used on all amd64 platforms we support
(Linux/amd64) to implement JavaThread's
@@ -123,7 +124,7 @@
offset += vm.getAddressSize()) {
try {
Address curSP = sp.addOffsetTo(offset);
- Frame frame = new AMD64Frame(curSP, null, pc);
+ Frame frame = new X86Frame(curSP, null, pc);
RegisterMap map = thread.newRegisterMap(false);
while (frame != null) {
if (frame.isEntryFrame() && frame.entryFrameIsFirst()) {
diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java Wed Sep 07 14:15:07 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,528 +0,0 @@
-/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-package sun.jvm.hotspot.runtime.amd64;
-
-import java.util.*;
-import sun.jvm.hotspot.code.*;
-import sun.jvm.hotspot.compiler.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.types.*;
-import sun.jvm.hotspot.utilities.*;
-
-/** Specialization of and implementation of abstract methods of the
- Frame class for the amd64 CPU. */
-
-public class AMD64Frame extends Frame {
- private static final boolean DEBUG;
- static {
- DEBUG = System.getProperty("sun.jvm.hotspot.runtime.amd64.AMD64Frame.DEBUG") != null;
- }
-
- // refer to frame_amd64.hpp
- private static final int PC_RETURN_OFFSET = 0;
- // All frames
- private static final int LINK_OFFSET = 0;
- private static final int RETURN_ADDR_OFFSET = 1;
- private static final int SENDER_SP_OFFSET = 2;
-
- // Interpreter frames
- private static final int INTERPRETER_FRAME_MIRROR_OFFSET = 2; // for native calls only
- private static final int INTERPRETER_FRAME_SENDER_SP_OFFSET = -1;
- private static final int INTERPRETER_FRAME_LAST_SP_OFFSET = INTERPRETER_FRAME_SENDER_SP_OFFSET - 1;
- private static final int INTERPRETER_FRAME_METHOD_OFFSET = INTERPRETER_FRAME_LAST_SP_OFFSET - 1;
- private static int INTERPRETER_FRAME_MDX_OFFSET; // Non-core builds only
- private static int INTERPRETER_FRAME_CACHE_OFFSET;
- private static int INTERPRETER_FRAME_LOCALS_OFFSET;
- private static int INTERPRETER_FRAME_BCX_OFFSET;
- private static int INTERPRETER_FRAME_INITIAL_SP_OFFSET;
- private static int INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET;
- private static int INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET;
-
- // Entry frames
- private static final int ENTRY_FRAME_CALL_WRAPPER_OFFSET = -6;
-
- // Native frames
- private static final int NATIVE_FRAME_INITIAL_PARAM_OFFSET = 2;
-
- static {
- VM.registerVMInitializedObserver(new Observer() {
- public void update(Observable o, Object data) {
- initialize(VM.getVM().getTypeDataBase());
- }
- });
- }
-
- private static synchronized void initialize(TypeDataBase db) {
- if (VM.getVM().isCore()) {
- INTERPRETER_FRAME_CACHE_OFFSET = INTERPRETER_FRAME_METHOD_OFFSET - 1;
- } else {
- INTERPRETER_FRAME_MDX_OFFSET = INTERPRETER_FRAME_METHOD_OFFSET - 1;
- INTERPRETER_FRAME_CACHE_OFFSET = INTERPRETER_FRAME_MDX_OFFSET - 1;
- }
- INTERPRETER_FRAME_LOCALS_OFFSET = INTERPRETER_FRAME_CACHE_OFFSET - 1;
- INTERPRETER_FRAME_BCX_OFFSET = INTERPRETER_FRAME_LOCALS_OFFSET - 1;
- INTERPRETER_FRAME_INITIAL_SP_OFFSET = INTERPRETER_FRAME_BCX_OFFSET - 1;
- INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
- INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
- }
-
- // an additional field beyond sp and pc:
- Address raw_fp; // frame pointer
- private Address raw_unextendedSP;
-
- private AMD64Frame() {
- }
-
- private void adjustForDeopt() {
- if ( pc != null) {
- // Look for a deopt pc and if it is deopted convert to original pc
- CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc);
- if (cb != null && cb.isJavaMethod()) {
- NMethod nm = (NMethod) cb;
- if (pc.equals(nm.deoptBegin())) {
- // adjust pc if frame is deoptimized.
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(this.getUnextendedSP() != null, "null SP in Java frame");
- }
- pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset());
- deoptimized = true;
- }
- }
- }
- }
-
- public AMD64Frame(Address raw_sp, Address raw_fp, Address pc) {
- this.raw_sp = raw_sp;
- this.raw_unextendedSP = raw_sp;
- this.raw_fp = raw_fp;
- this.pc = pc;
-
- // Frame must be fully constructed before this call
- adjustForDeopt();
-
- if (DEBUG) {
- System.out.println("AMD64Frame(sp, fp, pc): " + this);
- dumpStack();
- }
- }
-
- public AMD64Frame(Address raw_sp, Address raw_fp) {
- this.raw_sp = raw_sp;
- this.raw_unextendedSP = raw_sp;
- this.raw_fp = raw_fp;
- this.pc = raw_sp.getAddressAt(-1 * VM.getVM().getAddressSize());
-
- // Frame must be fully constructed before this call
- adjustForDeopt();
-
- if (DEBUG) {
- System.out.println("AMD64Frame(sp, fp): " + this);
- dumpStack();
- }
- }
-
- // This constructor should really take the unextended SP as an arg
- // but then the constructor is ambiguous with constructor that takes
- // a PC so take an int and convert it.
- public AMD64Frame(Address raw_sp, Address raw_fp, long extension) {
- this.raw_sp = raw_sp;
- if ( raw_sp == null) {
- this.raw_unextendedSP = null;
- } else {
- this.raw_unextendedSP = raw_sp.addOffsetTo(extension);
- }
- this.raw_fp = raw_fp;
- this.pc = raw_sp.getAddressAt(-1 * VM.getVM().getAddressSize());
-
- // Frame must be fully constructed before this call
- adjustForDeopt();
-
- if (DEBUG) {
- System.out.println("AMD64Frame(sp, fp, extension): " + this);
- dumpStack();
- }
-
- }
-
- public Object clone() {
- AMD64Frame frame = new AMD64Frame();
- frame.raw_sp = raw_sp;
- frame.raw_unextendedSP = raw_unextendedSP;
- frame.raw_fp = raw_fp;
- frame.pc = pc;
- frame.deoptimized = deoptimized;
- return frame;
- }
-
- public boolean equals(Object arg) {
- if (arg == null) {
- return false;
- }
-
- if (!(arg instanceof AMD64Frame)) {
- return false;
- }
-
- AMD64Frame other = (AMD64Frame) arg;
-
- return (AddressOps.equal(getSP(), other.getSP()) &&
- AddressOps.equal(getFP(), other.getFP()) &&
- AddressOps.equal(getUnextendedSP(), other.getUnextendedSP()) &&
- AddressOps.equal(getPC(), other.getPC()));
- }
-
- public int hashCode() {
- if (raw_sp == null) {
- return 0;
- }
-
- return raw_sp.hashCode();
- }
-
- public String toString() {
- return "sp: " + (getSP() == null? "null" : getSP().toString()) +
- ", unextendedSP: " + (getUnextendedSP() == null? "null" : getUnextendedSP().toString()) +
- ", fp: " + (getFP() == null? "null" : getFP().toString()) +
- ", pc: " + (pc == null? "null" : pc.toString());
- }
-
- // accessors for the instance variables
- public Address getFP() { return raw_fp; }
- public Address getSP() { return raw_sp; }
- public Address getID() { return raw_sp; }
-
- // FIXME: not implemented yet (should be done for Solaris/AMD64)
- public boolean isSignalHandlerFrameDbg() { return false; }
- public int getSignalNumberDbg() { return 0; }
- public String getSignalNameDbg() { return null; }
-
- public boolean isInterpretedFrameValid() {
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(isInterpretedFrame(), "Not an interpreted frame");
- }
-
- // These are reasonable sanity checks
- if (getFP() == null || getFP().andWithMask(0x3) != null) {
- return false;
- }
-
- if (getSP() == null || getSP().andWithMask(0x3) != null) {
- return false;
- }
-
- if (getFP().addOffsetTo(INTERPRETER_FRAME_INITIAL_SP_OFFSET * VM.getVM().getAddressSize()).lessThan(getSP())) {
- return false;
- }
-
- // These are hacks to keep us out of trouble.
- // The problem with these is that they mask other problems
- if (getFP().lessThanOrEqual(getSP())) {
- // this attempts to deal with unsigned comparison above
- return false;
- }
-
- if (getFP().minus(getSP()) > 4096 * VM.getVM().getAddressSize()) {
- // stack frames shouldn't be large.
- return false;
- }
-
- return true;
- }
-
- // FIXME: not applicable in current system
- // void patch_pc(Thread* thread, address pc);
-
- public Frame sender(RegisterMap regMap, CodeBlob cb) {
- AMD64RegisterMap map = (AMD64RegisterMap) regMap;
-
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(map != null, "map must be set");
- }
-
- // Default is we done have to follow them. The sender_for_xxx will
- // update it accordingly
- map.setIncludeArgumentOops(false);
-
- if (isEntryFrame()) return senderForEntryFrame(map);
- if (isInterpretedFrame()) return senderForInterpreterFrame(map);
-
-
- if (!VM.getVM().isCore()) {
- if(cb == null) {
- cb = VM.getVM().getCodeCache().findBlob(getPC());
- } else {
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same");
- }
- }
-
- if (cb != null) {
- return senderForCompiledFrame(map, cb);
- }
- }
-
- // Must be native-compiled frame, i.e. the marshaling code for native
- // methods that exists in the core system.
- return new AMD64Frame(getSenderSP(), getLink(), getSenderPC());
- }
-
- private Frame senderForEntryFrame(AMD64RegisterMap map) {
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(map != null, "map must be set");
- }
- // Java frame called from C; skip all C frames and return top C
- // frame of that chunk as the sender
- AMD64JavaCallWrapper jcw = (AMD64JavaCallWrapper) getEntryFrameCallWrapper();
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(!entryFrameIsFirst(), "next Java fp must be non zero");
- Assert.that(jcw.getLastJavaSP().greaterThan(getSP()), "must be above this frame on stack");
- }
- AMD64Frame fr;
- if (jcw.getLastJavaPC() != null) {
- fr = new AMD64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP(), jcw.getLastJavaPC());
- } else {
- fr = new AMD64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP());
- }
- map.clear();
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(map.getIncludeArgumentOops(), "should be set by clear");
- }
- return fr;
- }
-
- private Frame senderForInterpreterFrame(AMD64RegisterMap map) {
- Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
- Address sp = addressOfStackSlot(SENDER_SP_OFFSET);
- // We do not need to update the callee-save register mapping because above
- // us is either another interpreter frame or a converter-frame, but never
- // directly a compiled frame.
- // 11/24/04 SFG. This is no longer true after adapter were removed. However at the moment
- // C2 no longer uses callee save register for java calls so there are no callee register
- // to find.
- return new AMD64Frame(sp, getLink(), unextendedSP.minus(sp));
- }
-
- private Frame senderForCompiledFrame(AMD64RegisterMap map, CodeBlob cb) {
- //
- // NOTE: some of this code is (unfortunately) duplicated in AMD64CurrentFrameGuess
- //
-
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(map != null, "map must be set");
- }
-
- // frame owned by optimizing compiler
- Address sender_sp = null;
-
-
- if (VM.getVM().isClientCompiler()) {
- sender_sp = addressOfStackSlot(SENDER_SP_OFFSET);
- } else {
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(cb.getFrameSize() >= 0, "Compiled by Compiler1: do not use");
- }
- sender_sp = getUnextendedSP().addOffsetTo(cb.getFrameSize());
- }
-
- // On Intel the return_address is always the word on the stack
- Address sender_pc = sender_sp.getAddressAt(-1 * VM.getVM().getAddressSize());
-
- if (map.getUpdateMap() && cb.getOopMaps() != null) {
- OopMapSet.updateRegisterMap(this, cb, map, true);
- }
-
- if (VM.getVM().isClientCompiler()) {
- // Move this here for C1 and collecting oops in arguments (According to Rene)
- map.setIncludeArgumentOops(cb.callerMustGCArguments(map.getThread()));
- }
-
- Address saved_fp = null;
- if (VM.getVM().isClientCompiler()) {
- saved_fp = getFP().getAddressAt(0);
- } else if (VM.getVM().isServerCompiler() &&
- (VM.getVM().getInterpreter().contains(sender_pc) ||
- VM.getVM().getStubRoutines().returnsToCallStub(sender_pc))) {
- // C2 prologue saves EBP in the usual place.
- // however only use it if the sender had link infomration in it.
- saved_fp = sender_sp.getAddressAt(-2 * VM.getVM().getAddressSize());
- }
-
- return new AMD64Frame(sender_sp, saved_fp, sender_pc);
- }
-
- protected boolean hasSenderPD() {
- // FIXME
- // Check for null ebp? Need to do some tests.
- return true;
- }
-
- public long frameSize() {
- return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize());
- }
-
- public Address getLink() {
- return addressOfStackSlot(LINK_OFFSET).getAddressAt(0);
- }
-
- // FIXME: not implementable yet
- //inline void frame::set_link(intptr_t* addr) { *(intptr_t **)addr_at(link_offset) = addr; }
-
- public Address getUnextendedSP() { return raw_unextendedSP; }
-
- // Return address:
- public Address getSenderPCAddr() { return addressOfStackSlot(RETURN_ADDR_OFFSET); }
- public Address getSenderPC() { return getSenderPCAddr().getAddressAt(0); }
-
- // return address of param, zero origin index.
- public Address getNativeParamAddr(int idx) {
- return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx);
- }
-
- public Address getSenderSP() { return addressOfStackSlot(SENDER_SP_OFFSET); }
-
- public Address compiledArgumentToLocationPD(VMReg reg, RegisterMap regMap, int argSize) {
- if (VM.getVM().isCore() || VM.getVM().isClientCompiler()) {
- throw new RuntimeException("Should not reach here");
- }
-
- return oopMapRegToLocation(reg, regMap);
- }
-
- public Address addressOfInterpreterFrameLocals() {
- return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET);
- }
-
- private Address addressOfInterpreterFrameBCX() {
- return addressOfStackSlot(INTERPRETER_FRAME_BCX_OFFSET);
- }
-
- public int getInterpreterFrameBCI() {
- // FIXME: this is not atomic with respect to GC and is unsuitable
- // for use in a non-debugging, or reflective, system. Need to
- // figure out how to express this.
- Address bcp = addressOfInterpreterFrameBCX().getAddressAt(0);
- OopHandle methodHandle = addressOfInterpreterFrameMethod().getOopHandleAt(0);
- Method method = (Method) VM.getVM().getObjectHeap().newOop(methodHandle);
- return (int) bcpToBci(bcp, method);
- }
-
- public Address addressOfInterpreterFrameMDX() {
- return addressOfStackSlot(INTERPRETER_FRAME_MDX_OFFSET);
- }
-
- // FIXME
- //inline int frame::interpreter_frame_monitor_size() {
- // return BasicObjectLock::size();
- //}
-
- // expression stack
- // (the max_stack arguments are used by the GC; see class FrameClosure)
-
- public Address addressOfInterpreterFrameExpressionStack() {
- Address monitorEnd = interpreterFrameMonitorEnd().address();
- return monitorEnd.addOffsetTo(-1 * VM.getVM().getAddressSize());
- }
-
- public int getInterpreterFrameExpressionStackDirection() { return -1; }
-
- // top of expression stack
- public Address addressOfInterpreterFrameTOS() {
- return getSP();
- }
-
- /** Expression stack from top down */
- public Address addressOfInterpreterFrameTOSAt(int slot) {
- return addressOfInterpreterFrameTOS().addOffsetTo(slot * VM.getVM().getAddressSize());
- }
-
- public Address getInterpreterFrameSenderSP() {
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(isInterpretedFrame(), "interpreted frame expected");
- }
- return addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
- }
-
- // Monitors
- public BasicObjectLock interpreterFrameMonitorBegin() {
- return new BasicObjectLock(addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET));
- }
-
- public BasicObjectLock interpreterFrameMonitorEnd() {
- Address result = addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET).getAddressAt(0);
- if (Assert.ASSERTS_ENABLED) {
- // make sure the pointer points inside the frame
- Assert.that(AddressOps.gt(getFP(), result), "result must < than frame pointer");
- Assert.that(AddressOps.lte(getSP(), result), "result must >= than stack pointer");
- }
- return new BasicObjectLock(result);
- }
-
- public int interpreterFrameMonitorSize() {
- return BasicObjectLock.size();
- }
-
- // Method
- public Address addressOfInterpreterFrameMethod() {
- return addressOfStackSlot(INTERPRETER_FRAME_METHOD_OFFSET);
- }
-
- // Constant pool cache
- public Address addressOfInterpreterFrameCPCache() {
- return addressOfStackSlot(INTERPRETER_FRAME_CACHE_OFFSET);
- }
-
- // Entry frames
- public JavaCallWrapper getEntryFrameCallWrapper() {
- return new AMD64JavaCallWrapper(addressOfStackSlot(ENTRY_FRAME_CALL_WRAPPER_OFFSET).getAddressAt(0));
- }
-
- protected Address addressOfSavedOopResult() {
- // offset is 2 for compiler2 and 3 for compiler1
- return getSP().addOffsetTo((VM.getVM().isClientCompiler() ? 2 : 3) *
- VM.getVM().getAddressSize());
- }
-
- protected Address addressOfSavedReceiver() {
- return getSP().addOffsetTo(-4 * VM.getVM().getAddressSize());
- }
-
- private void dumpStack() {
- if (getFP() != null) {
- for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize());
- AddressOps.lte(addr, getFP().addOffsetTo(5 * VM.getVM().getAddressSize()));
- addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
- System.out.println(addr + ": " + addr.getAddressAt(0));
- }
- } else {
- for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize());
- AddressOps.lte(addr, getSP().addOffsetTo(20 * VM.getVM().getAddressSize()));
- addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
- System.out.println(addr + ": " + addr.getAddressAt(0));
- }
- }
- }
-}
diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64RegisterMap.java
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64RegisterMap.java Wed Sep 07 14:15:07 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-package sun.jvm.hotspot.runtime.amd64;
-
-import sun.jvm.hotspot.asm.amd64.*;
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.runtime.*;
-
-public class AMD64RegisterMap extends RegisterMap {
-
- /** This is the only public constructor */
- public AMD64RegisterMap(JavaThread thread, boolean updateMap) {
- super(thread, updateMap);
- }
-
- protected AMD64RegisterMap(RegisterMap map) {
- super(map);
- }
-
- public Object clone() {
- AMD64RegisterMap retval = new AMD64RegisterMap(this);
- return retval;
- }
-
- // no PD state to clear or copy:
- protected void clearPD() {}
- protected void initializePD() {}
- protected void initializeFromPD(RegisterMap map) {}
- protected Address getLocationPD(VMReg reg) { return null; }
-}
diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/linux_amd64/LinuxAMD64JavaThreadPDAccess.java
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_amd64/LinuxAMD64JavaThreadPDAccess.java Wed Sep 07 14:15:07 2011 +0200
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_amd64/LinuxAMD64JavaThreadPDAccess.java Thu Sep 08 06:36:31 2011 -0700
@@ -30,6 +30,7 @@
import sun.jvm.hotspot.debugger.amd64.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.runtime.amd64.*;
+import sun.jvm.hotspot.runtime.x86.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;
@@ -80,11 +81,11 @@
if (fp == null) {
return null; // no information
}
- return new AMD64Frame(thread.getLastJavaSP(), fp);
+ return new X86Frame(thread.getLastJavaSP(), fp);
}
public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) {
- return new AMD64RegisterMap(thread, updateMap);
+ return new X86RegisterMap(thread, updateMap);
}
public Frame getCurrentFrameGuess(JavaThread thread, Address addr) {
@@ -95,9 +96,9 @@
return null;
}
if (guesser.getPC() == null) {
- return new AMD64Frame(guesser.getSP(), guesser.getFP());
+ return new X86Frame(guesser.getSP(), guesser.getFP());
} else {
- return new AMD64Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
+ return new X86Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
}
}
diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java Wed Sep 07 14:15:07 2011 +0200
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java Thu Sep 08 06:36:31 2011 -0700
@@ -30,6 +30,7 @@
import sun.jvm.hotspot.debugger.amd64.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.runtime.amd64.*;
+import sun.jvm.hotspot.runtime.x86.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;
@@ -84,14 +85,14 @@
}
Address pc = thread.getLastJavaPC();
if ( pc != null ) {
- return new AMD64Frame(thread.getLastJavaSP(), fp, pc);
+ return new X86Frame(thread.getLastJavaSP(), fp, pc);
} else {
- return new AMD64Frame(thread.getLastJavaSP(), fp);
+ return new X86Frame(thread.getLastJavaSP(), fp);
}
}
public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) {
- return new AMD64RegisterMap(thread, updateMap);
+ return new X86RegisterMap(thread, updateMap);
}
public Frame getCurrentFrameGuess(JavaThread thread, Address addr) {
@@ -102,9 +103,9 @@
return null;
}
if (guesser.getPC() == null) {
- return new AMD64Frame(guesser.getSP(), guesser.getFP());
+ return new X86Frame(guesser.getSP(), guesser.getFP());
} else {
- return new AMD64Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
+ return new X86Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
}
}
diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java Wed Sep 07 14:15:07 2011 +0200
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java Thu Sep 08 06:36:31 2011 -0700
@@ -236,7 +236,7 @@
CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc);
if (cb != null && cb.isJavaMethod()) {
NMethod nm = (NMethod) cb;
- if (pc.equals(nm.deoptBegin())) {
+ if (pc.equals(nm.deoptHandlerBegin())) {
// adjust pc if frame is deoptimized.
pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset());
deoptimized = true;
@@ -559,49 +559,46 @@
}
}
- if (!VM.getVM().isCore()) {
- // Note: The version of this operation on any platform with callee-save
- // registers must update the register map (if not null).
- // In order to do this correctly, the various subtypes of
- // of frame (interpreted, compiled, glue, native),
- // must be distinguished. There is no need on SPARC for
- // such distinctions, because all callee-save registers are
- // preserved for all frames via SPARC-specific mechanisms.
- //
- // *** HOWEVER, *** if and when we make any floating-point
- // registers callee-saved, then we will have to copy over
- // the RegisterMap update logic from the Intel code.
+ // Note: The version of this operation on any platform with callee-save
+ // registers must update the register map (if not null).
+ // In order to do this correctly, the various subtypes of
+ // of frame (interpreted, compiled, glue, native),
+ // must be distinguished. There is no need on SPARC for
+ // such distinctions, because all callee-save registers are
+ // preserved for all frames via SPARC-specific mechanisms.
+ //
+ // *** HOWEVER, *** if and when we make any floating-point
+ // registers callee-saved, then we will have to copy over
+ // the RegisterMap update logic from the Intel code.
+ if (isRicochetFrame()) return senderForRicochetFrame(map);
- // The constructor of the sender must know whether this frame is interpreted so it can set the
- // sender's _interpreter_sp_adjustment field.
- if (VM.getVM().getInterpreter().contains(pc)) {
- isInterpreted = true;
- map.makeIntegerRegsUnsaved();
+ // The constructor of the sender must know whether this frame is interpreted so it can set the
+ // sender's _interpreter_sp_adjustment field.
+ if (VM.getVM().getInterpreter().contains(pc)) {
+ isInterpreted = true;
+ map.makeIntegerRegsUnsaved();
+ map.shiftWindow(sp, youngerSP);
+ } else {
+ // Find a CodeBlob containing this frame's pc or elide the lookup and use the
+ // supplied blob which is already known to be associated with this frame.
+ cb = VM.getVM().getCodeCache().findBlob(pc);
+ if (cb != null) {
+ // Update the location of all implicitly saved registers
+ // as the address of these registers in the register save
+ // area (for %o registers we use the address of the %i
+ // register in the next younger frame)
map.shiftWindow(sp, youngerSP);
- } else {
- // Find a CodeBlob containing this frame's pc or elide the lookup and use the
- // supplied blob which is already known to be associated with this frame.
- cb = VM.getVM().getCodeCache().findBlob(pc);
- if (cb != null) {
-
- if (cb.callerMustGCArguments(map.getThread())) {
+ if (map.getUpdateMap()) {
+ if (cb.callerMustGCArguments()) {
map.setIncludeArgumentOops(true);
}
-
- // Update the location of all implicitly saved registers
- // as the address of these registers in the register save
- // area (for %o registers we use the address of the %i
- // register in the next younger frame)
- map.shiftWindow(sp, youngerSP);
- if (map.getUpdateMap()) {
- if (cb.getOopMaps() != null) {
- OopMapSet.updateRegisterMap(this, cb, map, VM.getVM().isDebugging());
- }
+ if (cb.getOopMaps() != null) {
+ OopMapSet.updateRegisterMap(this, cb, map, VM.getVM().isDebugging());
}
}
}
- } // #ifndef CORE
+ }
return new SPARCFrame(biasSP(sp), biasSP(youngerSP), isInterpreted);
}
@@ -948,6 +945,20 @@
}
+ private Frame senderForRicochetFrame(SPARCRegisterMap map) {
+ if (DEBUG) {
+ System.out.println("senderForRicochetFrame");
+ }
+ //RicochetFrame* f = RicochetFrame::from_frame(fr);
+ // Cf. is_interpreted_frame path of frame::sender
+ Address youngerSP = getSP();
+ Address sp = getSenderSP();
+ map.makeIntegerRegsUnsaved();
+ map.shiftWindow(sp, youngerSP);
+ boolean thisFrameAdjustedStack = true; // I5_savedSP is live in this RF
+ return new SPARCFrame(sp, youngerSP, thisFrameAdjustedStack);
+ }
+
private Frame senderForEntryFrame(RegisterMap regMap) {
SPARCRegisterMap map = (SPARCRegisterMap) regMap;
@@ -965,10 +976,8 @@
Address lastJavaPC = jcw.getLastJavaPC();
map.clear();
- if (!VM.getVM().isCore()) {
- map.makeIntegerRegsUnsaved();
- map.shiftWindow(lastJavaSP, null);
- }
+ map.makeIntegerRegsUnsaved();
+ map.shiftWindow(lastJavaSP, null);
if (Assert.ASSERTS_ENABLED) {
Assert.that(map.getIncludeArgumentOops(), "should be set by clear");
diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCRicochetFrame.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCRicochetFrame.java Thu Sep 08 06:36:31 2011 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.sparc;
+
+import java.util.*;
+import sun.jvm.hotspot.asm.sparc.SPARCRegister;
+import sun.jvm.hotspot.asm.sparc.SPARCRegisters;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.types.*;
+
+public class SPARCRicochetFrame {
+ static {
+ VM.registerVMInitializedObserver(new Observer() {
+ public void update(Observable o, Object data) {
+ initialize(VM.getVM().getTypeDataBase());
+ }
+ });
+ }
+
+ private SPARCFrame frame;
+
+ private static void initialize(TypeDataBase db) {
+ // Type type = db.lookupType("MethodHandles::RicochetFrame");
+
+ }
+
+ static SPARCRicochetFrame fromFrame(SPARCFrame f) {
+ return new SPARCRicochetFrame(f);
+ }
+
+ private SPARCRicochetFrame(SPARCFrame f) {
+ frame = f;
+ }
+
+ private Address registerValue(SPARCRegister reg) {
+ return frame.getSP().addOffsetTo(reg.spOffsetInSavedWindow()).getAddressAt(0);
+ }
+
+ public Address savedArgsBase() {
+ return registerValue(SPARCRegisters.L4);
+ }
+ public Address exactSenderSP() {
+ return registerValue(SPARCRegisters.I5);
+ }
+ public Address senderLink() {
+ return frame.getSenderSP();
+ }
+ public Address senderPC() {
+ return frame.getSenderPC();
+ }
+ public Address extendedSenderSP() {
+ return savedArgsBase();
+ }
+}
diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java Wed Sep 07 14:15:07 2011 +0200
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java Thu Sep 08 06:36:31 2011 -0700
@@ -31,6 +31,7 @@
import sun.jvm.hotspot.debugger.amd64.*;
import sun.jvm.hotspot.runtime.*;
import sun.jvm.hotspot.runtime.amd64.*;
+import sun.jvm.hotspot.runtime.x86.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.utilities.*;
@@ -86,14 +87,14 @@
}
Address pc = thread.getLastJavaPC();
if ( pc != null ) {
- return new AMD64Frame(thread.getLastJavaSP(), fp, pc);
+ return new X86Frame(thread.getLastJavaSP(), fp, pc);
} else {
- return new AMD64Frame(thread.getLastJavaSP(), fp);
+ return new X86Frame(thread.getLastJavaSP(), fp);
}
}
public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) {
- return new AMD64RegisterMap(thread, updateMap);
+ return new X86RegisterMap(thread, updateMap);
}
public Frame getCurrentFrameGuess(JavaThread thread, Address addr) {
@@ -104,9 +105,9 @@
return null;
}
if (guesser.getPC() == null) {
- return new AMD64Frame(guesser.getSP(), guesser.getFP());
+ return new X86Frame(guesser.getSP(), guesser.getFP());
} else {
- return new AMD64Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
+ return new X86Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
}
}
diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java Wed Sep 07 14:15:07 2011 +0200
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java Thu Sep 08 06:36:31 2011 -0700
@@ -25,7 +25,6 @@
package sun.jvm.hotspot.runtime.x86;
import java.util.*;
-import sun.jvm.hotspot.asm.x86.*;
import sun.jvm.hotspot.code.*;
import sun.jvm.hotspot.compiler.*;
import sun.jvm.hotspot.debugger.*;
@@ -62,11 +61,13 @@
private static int INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET;
// Entry frames
- private static final int ENTRY_FRAME_CALL_WRAPPER_OFFSET = 2;
+ private static int ENTRY_FRAME_CALL_WRAPPER_OFFSET;
// Native frames
private static final int NATIVE_FRAME_INITIAL_PARAM_OFFSET = 2;
+ private static VMReg rbp;
+
static {
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
@@ -76,19 +77,23 @@
}
private static synchronized void initialize(TypeDataBase db) {
- if (VM.getVM().isCore()) {
- INTERPRETER_FRAME_CACHE_OFFSET = INTERPRETER_FRAME_METHOD_OFFSET - 1;
- } else {
- INTERPRETER_FRAME_MDX_OFFSET = INTERPRETER_FRAME_METHOD_OFFSET - 1;
- INTERPRETER_FRAME_CACHE_OFFSET = INTERPRETER_FRAME_MDX_OFFSET - 1;
- }
+ INTERPRETER_FRAME_MDX_OFFSET = INTERPRETER_FRAME_METHOD_OFFSET - 1;
+ INTERPRETER_FRAME_CACHE_OFFSET = INTERPRETER_FRAME_MDX_OFFSET - 1;
INTERPRETER_FRAME_LOCALS_OFFSET = INTERPRETER_FRAME_CACHE_OFFSET - 1;
INTERPRETER_FRAME_BCX_OFFSET = INTERPRETER_FRAME_LOCALS_OFFSET - 1;
INTERPRETER_FRAME_INITIAL_SP_OFFSET = INTERPRETER_FRAME_BCX_OFFSET - 1;
INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
+
+ ENTRY_FRAME_CALL_WRAPPER_OFFSET = db.lookupIntConstant("frame::entry_frame_call_wrapper_offset");
+ if (VM.getVM().getAddressSize() == 4) {
+ rbp = new VMReg(5);
+ } else {
+ rbp = new VMReg(5 << 1);
+ }
}
+
// an additional field beyond sp and pc:
Address raw_fp; // frame pointer
private Address raw_unextendedSP;
@@ -102,7 +107,7 @@
CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc);
if (cb != null && cb.isJavaMethod()) {
NMethod nm = (NMethod) cb;
- if (pc.equals(nm.deoptBegin())) {
+ if (pc.equals(nm.deoptHandlerBegin())) {
if (Assert.ASSERTS_ENABLED) {
Assert.that(this.getUnextendedSP() != null, "null SP in Java frame");
}
@@ -119,6 +124,7 @@
this.raw_unextendedSP = raw_sp;
this.raw_fp = raw_fp;
this.pc = pc;
+ adjustUnextendedSP();
// Frame must be fully constructed before this call
adjustForDeopt();
@@ -134,6 +140,7 @@
this.raw_unextendedSP = raw_sp;
this.raw_fp = raw_fp;
this.pc = raw_sp.getAddressAt(-1 * VM.getVM().getAddressSize());
+ adjustUnextendedSP();
// Frame must be fully constructed before this call
adjustForDeopt();
@@ -144,24 +151,18 @@
}
}
- // This constructor should really take the unextended SP as an arg
- // but then the constructor is ambiguous with constructor that takes
- // a PC so take an int and convert it.
- public X86Frame(Address raw_sp, Address raw_fp, long extension) {
+ public X86Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Address pc) {
this.raw_sp = raw_sp;
- if (raw_sp == null) {
- this.raw_unextendedSP = null;
- } else {
- this.raw_unextendedSP = raw_sp.addOffsetTo(extension);
- }
+ this.raw_unextendedSP = raw_unextendedSp;
this.raw_fp = raw_fp;
- this.pc = raw_sp.getAddressAt(-1 * VM.getVM().getAddressSize());
+ this.pc = pc;
+ adjustUnextendedSP();
// Frame must be fully constructed before this call
adjustForDeopt();
if (DEBUG) {
- System.out.println("X86Frame(sp, fp): " + this);
+ System.out.println("X86Frame(sp, unextendedSP, fp, pc): " + this);
dumpStack();
}
@@ -172,7 +173,6 @@
frame.raw_sp = raw_sp;
frame.raw_unextendedSP = raw_unextendedSP;
frame.raw_fp = raw_fp;
- frame.raw_fp = raw_fp;
frame.pc = pc;
frame.deoptimized = deoptimized;
return frame;
@@ -269,19 +269,18 @@
if (isEntryFrame()) return senderForEntryFrame(map);
if (isInterpretedFrame()) return senderForInterpreterFrame(map);
+ if (isRicochetFrame()) return senderForRicochetFrame(map);
- if (!VM.getVM().isCore()) {
- if(cb == null) {
- cb = VM.getVM().getCodeCache().findBlob(getPC());
- } else {
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same");
- }
+ if(cb == null) {
+ cb = VM.getVM().getCodeCache().findBlob(getPC());
+ } else {
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same");
}
+ }
- if (cb != null) {
- return senderForCompiledFrame(map, cb);
- }
+ if (cb != null) {
+ return senderForCompiledFrame(map, cb);
}
// Must be native-compiled frame, i.e. the marshaling code for native
@@ -289,7 +288,20 @@
return new X86Frame(getSenderSP(), getLink(), getSenderPC());
}
+ private Frame senderForRicochetFrame(X86RegisterMap map) {
+ if (DEBUG) {
+ System.out.println("senderForRicochetFrame");
+ }
+ X86RicochetFrame f = X86RicochetFrame.fromFrame(this);
+ if (map.getUpdateMap())
+ updateMapWithSavedLink(map, f.senderLinkAddress());
+ return new X86Frame(f.extendedSenderSP(), f.exactSenderSP(), f.senderLink(), f.senderPC());
+ }
+
private Frame senderForEntryFrame(X86RegisterMap map) {
+ if (DEBUG) {
+ System.out.println("senderForEntryFrame");
+ }
if (Assert.ASSERTS_ENABLED) {
Assert.that(map != null, "map must be set");
}
@@ -313,7 +325,37 @@
return fr;
}
+ //------------------------------------------------------------------------------
+ // frame::adjust_unextended_sp
+ private void adjustUnextendedSP() {
+ // If we are returning to a compiled MethodHandle call site, the
+ // saved_fp will in fact be a saved value of the unextended SP. The
+ // simplest way to tell whether we are returning to such a call site
+ // is as follows:
+
+ CodeBlob cb = cb();
+ NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull();
+ if (senderNm != null) {
+ // If the sender PC is a deoptimization point, get the original
+ // PC. For MethodHandle call site the unextended_sp is stored in
+ // saved_fp.
+ if (senderNm.isDeoptMhEntry(getPC())) {
+ // DEBUG_ONLY(verifyDeoptMhOriginalPc(senderNm, getFP()));
+ raw_unextendedSP = getFP();
+ }
+ else if (senderNm.isDeoptEntry(getPC())) {
+ // DEBUG_ONLY(verifyDeoptOriginalPc(senderNm, raw_unextendedSp));
+ }
+ else if (senderNm.isMethodHandleReturn(getPC())) {
+ raw_unextendedSP = getFP();
+ }
+ }
+ }
+
private Frame senderForInterpreterFrame(X86RegisterMap map) {
+ if (DEBUG) {
+ System.out.println("senderForInterpreterFrame");
+ }
Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
Address sp = addressOfStackSlot(SENDER_SP_OFFSET);
// We do not need to update the callee-save register mapping because above
@@ -323,10 +365,21 @@
// However c2 no longer uses callee save register for java calls so there
// are no callee register to find.
- return new X86Frame(sp, getLink(), unextendedSP.minus(sp));
+ if (map.getUpdateMap())
+ updateMapWithSavedLink(map, addressOfStackSlot(LINK_OFFSET));
+
+ return new X86Frame(sp, unextendedSP, getLink(), getSenderPC());
+ }
+
+ private void updateMapWithSavedLink(RegisterMap map, Address savedFPAddr) {
+ map.setLocation(rbp, savedFPAddr);
}
private Frame senderForCompiledFrame(X86RegisterMap map, CodeBlob cb) {
+ if (DEBUG) {
+ System.out.println("senderForCompiledFrame");
+ }
+
//
// NOTE: some of this code is (unfortunately) duplicated in X86CurrentFrameGuess
//
@@ -336,41 +389,35 @@
}
// frame owned by optimizing compiler
- Address sender_sp = null;
-
- if (VM.getVM().isClientCompiler()) {
- sender_sp = addressOfStackSlot(SENDER_SP_OFFSET);
- } else {
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(cb.getFrameSize() >= 0, "Compiled by Compiler1: do not use");
- }
- sender_sp = getUnextendedSP().addOffsetTo(cb.getFrameSize());
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(cb.getFrameSize() >= 0, "must have non-zero frame size");
}
+ Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize());
// On Intel the return_address is always the word on the stack
- Address sender_pc = sender_sp.getAddressAt(-1 * VM.getVM().getAddressSize());
+ Address senderPC = senderSP.getAddressAt(-1 * VM.getVM().getAddressSize());
+
+ // This is the saved value of EBP which may or may not really be an FP.
+ // It is only an FP if the sender is an interpreter frame (or C1?).
+ Address savedFPAddr = senderSP.addOffsetTo(- SENDER_SP_OFFSET * VM.getVM().getAddressSize());
- if (map.getUpdateMap() && cb.getOopMaps() != null) {
- OopMapSet.updateRegisterMap(this, cb, map, true);
+ if (map.getUpdateMap()) {
+ // Tell GC to use argument oopmaps for some runtime stubs that need it.
+ // For C1, the runtime stub might not have oop maps, so set this flag
+ // outside of update_register_map.
+ map.setIncludeArgumentOops(cb.callerMustGCArguments());
+
+ if (cb.getOopMaps() != null) {
+ OopMapSet.updateRegisterMap(this, cb, map, true);
+ }
+
+ // Since the prolog does the save and restore of EBP there is no oopmap
+ // for it so we must fill in its location as if there was an oopmap entry
+ // since if our caller was compiled code there could be live jvm state in it.
+ updateMapWithSavedLink(map, savedFPAddr);
}
- if (VM.getVM().isClientCompiler()) {
- // Move this here for C1 and collecting oops in arguments (According to Rene)
- map.setIncludeArgumentOops(cb.callerMustGCArguments(map.getThread()));
- }
-
- Address saved_fp = null;
- if (VM.getVM().isClientCompiler()) {
- saved_fp = getFP().getAddressAt(0);
- } else if (VM.getVM().isServerCompiler() &&
- (VM.getVM().getInterpreter().contains(sender_pc) ||
- VM.getVM().getStubRoutines().returnsToCallStub(sender_pc))) {
- // C2 prologue saves EBP in the usual place.
- // however only use it if the sender had link infomration in it.
- saved_fp = sender_sp.getAddressAt(-2 * VM.getVM().getAddressSize());
- }
-
- return new X86Frame(sender_sp, saved_fp, sender_pc);
+ return new X86Frame(senderSP, savedFPAddr.getAddressAt(0), senderPC);
}
protected boolean hasSenderPD() {
@@ -403,14 +450,6 @@
public Address getSenderSP() { return addressOfStackSlot(SENDER_SP_OFFSET); }
- public Address compiledArgumentToLocationPD(VMReg reg, RegisterMap regMap, int argSize) {
- if (VM.getVM().isCore() || VM.getVM().isClientCompiler()) {
- throw new RuntimeException("Should not reach here");
- }
-
- return oopMapRegToLocation(reg, regMap);
- }
-
public Address addressOfInterpreterFrameLocals() {
return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET);
}
diff -r 2fecca53a2c6 -r 5596e125fe4f agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86RicochetFrame.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86RicochetFrame.java Thu Sep 08 06:36:31 2011 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.x86;
+
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.types.*;
+
+public class X86RicochetFrame extends VMObject {
+ static {
+ VM.registerVMInitializedObserver(new Observer() {
+ public void update(Observable o, Object data) {
+ initialize(VM.getVM().getTypeDataBase());
+ }
+ });
+ }
+
+ private static void initialize(TypeDataBase db) {
+ Type type = db.lookupType("MethodHandles::RicochetFrame");
+
+ senderLinkField = type.getAddressField("_sender_link");
+ savedArgsBaseField = type.getAddressField("_saved_args_base");
+ exactSenderSPField = type.getAddressField("_exact_sender_sp");
+ senderPCField = type.getAddressField("_sender_pc");
+ }
+
+ private static AddressField senderLinkField;
+ private static AddressField savedArgsBaseField;
+ private static AddressField exactSenderSPField;
+ private static AddressField senderPCField;
+
+ static X86RicochetFrame fromFrame(X86Frame f) {
+ return new X86RicochetFrame(f.getFP().addOffsetTo(- senderLinkField.getOffset()));
+ }
+
+ private X86RicochetFrame(Address addr) {
+ super(addr);
+ }
+
+ public Address senderLink() {
+ return senderLinkField.getValue(addr);
+ }
+ public Address senderLinkAddress() {
+ return addr.addOffsetTo(senderLinkField.getOffset());
+ }
+ public Address savedArgsBase() {
+ return savedArgsBaseField.getValue(addr);
+ }
+ public Address extendedSenderSP() {
+ return savedArgsBase();
+ }
+ public Address exactSenderSP() {
+ return exactSenderSPField.getValue(addr);
+ }
+ public Address senderPC() {
+ return senderPCField.getValue(addr);
+ }
+}
diff -r 2fecca53a2c6 -r 5596e125fe4f make/linux/makefiles/mapfile-vers-debug
--- a/make/linux/makefiles/mapfile-vers-debug Wed Sep 07 14:15:07 2011 +0200
+++ b/make/linux/makefiles/mapfile-vers-debug Thu Sep 08 06:36:31 2011 -0700
@@ -244,24 +244,6 @@
JVM_Yield;
JVM_handle_linux_signal;
- # Old reflection routines
- # These do not need to be present in the product build in JDK 1.4
- # but their code has not been removed yet because there will not
- # be a substantial code savings until JVM_InvokeMethod and
- # JVM_NewInstanceFromConstructor can also be removed; see
- # reflectionCompat.hpp.
- JVM_GetClassConstructor;
- JVM_GetClassConstructors;
- JVM_GetClassField;
- JVM_GetClassFields;
- JVM_GetClassMethod;
- JVM_GetClassMethods;
- JVM_GetField;
- JVM_GetPrimitiveField;
- JVM_NewInstance;
- JVM_SetField;
- JVM_SetPrimitiveField;
-
# debug JVM
JVM_AccessVMBooleanFlag;
JVM_AccessVMIntFlag;
diff -r 2fecca53a2c6 -r 5596e125fe4f make/linux/makefiles/mapfile-vers-product
--- a/make/linux/makefiles/mapfile-vers-product Wed Sep 07 14:15:07 2011 +0200
+++ b/make/linux/makefiles/mapfile-vers-product Thu Sep 08 06:36:31 2011 -0700
@@ -244,24 +244,6 @@
JVM_Yield;
JVM_handle_linux_signal;
- # Old reflection routines
- # These do not need to be present in the product build in JDK 1.4
- # but their code has not been removed yet because there will not
- # be a substantial code savings until JVM_InvokeMethod and
- # JVM_NewInstanceFromConstructor can also be removed; see
- # reflectionCompat.hpp.
- JVM_GetClassConstructor;
- JVM_GetClassConstructors;
- JVM_GetClassField;
- JVM_GetClassFields;
- JVM_GetClassMethod;
- JVM_GetClassMethods;
- JVM_GetField;
- JVM_GetPrimitiveField;
- JVM_NewInstance;
- JVM_SetField;
- JVM_SetPrimitiveField;
-
# miscellaneous functions
jio_fprintf;
jio_printf;
diff -r 2fecca53a2c6 -r 5596e125fe4f make/solaris/makefiles/debug.make
--- a/make/solaris/makefiles/debug.make Wed Sep 07 14:15:07 2011 +0200
+++ b/make/solaris/makefiles/debug.make Thu Sep 08 06:36:31 2011 -0700
@@ -41,8 +41,7 @@
# Linker mapfiles
MAPFILE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers \
- $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-debug \
- $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-nonproduct
+ $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-debug
# This mapfile is only needed when compiling with dtrace support,
# and mustn't be otherwise.
diff -r 2fecca53a2c6 -r 5596e125fe4f make/solaris/makefiles/fastdebug.make
--- a/make/solaris/makefiles/fastdebug.make Wed Sep 07 14:15:07 2011 +0200
+++ b/make/solaris/makefiles/fastdebug.make Thu Sep 08 06:36:31 2011 -0700
@@ -107,8 +107,7 @@
# Linker mapfiles
MAPFILE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers \
- $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-debug \
- $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-nonproduct
+ $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-debug
# This mapfile is only needed when compiling with dtrace support,
# and mustn't be otherwise.
diff -r 2fecca53a2c6 -r 5596e125fe4f make/solaris/makefiles/jvmg.make
--- a/make/solaris/makefiles/jvmg.make Wed Sep 07 14:15:07 2011 +0200
+++ b/make/solaris/makefiles/jvmg.make Thu Sep 08 06:36:31 2011 -0700
@@ -44,8 +44,7 @@
# Linker mapfiles
MAPFILE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers \
- $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-debug \
- $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-nonproduct
+ $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-debug
# This mapfile is only needed when compiling with dtrace support,
# and mustn't be otherwise.
diff -r 2fecca53a2c6 -r 5596e125fe4f make/solaris/makefiles/mapfile-vers-nonproduct
--- a/make/solaris/makefiles/mapfile-vers-nonproduct Wed Sep 07 14:15:07 2011 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-#
-
-#
-# Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-#
-
-# Define public interface.
-
-SUNWprivate_1.1 {
- global:
- # Old reflection routines
- # These do not need to be present in the product build in JDK 1.4
- # but their code has not been removed yet because there will not
- # be a substantial code savings until JVM_InvokeMethod and
- # JVM_NewInstanceFromConstructor can also be removed; see
- # reflectionCompat.hpp.
- JVM_GetClassConstructor;
- JVM_GetClassConstructors;
- JVM_GetClassField;
- JVM_GetClassFields;
- JVM_GetClassMethod;
- JVM_GetClassMethods;
- JVM_GetField;
- JVM_GetPrimitiveField;
- JVM_NewInstance;
- JVM_SetField;
- JVM_SetPrimitiveField;
-};
diff -r 2fecca53a2c6 -r 5596e125fe4f make/solaris/makefiles/optimized.make
--- a/make/solaris/makefiles/optimized.make Wed Sep 07 14:15:07 2011 +0200
+++ b/make/solaris/makefiles/optimized.make Thu Sep 08 06:36:31 2011 -0700
@@ -48,9 +48,7 @@
CFLAGS$(HOTSPARC_GENERIC) += $(OPT_CFLAGS/BYFILE)
# Linker mapfiles
-# NOTE: inclusion of nonproduct mapfile not necessary; read it for details
-MAPFILE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers \
- $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-nonproduct
+MAPFILE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers
# This mapfile is only needed when compiling with dtrace support,
# and mustn't be otherwise.
diff -r 2fecca53a2c6 -r 5596e125fe4f make/solaris/makefiles/product.make
--- a/make/solaris/makefiles/product.make Wed Sep 07 14:15:07 2011 +0200
+++ b/make/solaris/makefiles/product.make Thu Sep 08 06:36:31 2011 -0700
@@ -58,13 +58,9 @@
# to inhibit the effect of the previous line on CFLAGS.
# Linker mapfiles
-# NOTE: inclusion of nonproduct mapfile not necessary; read it for details
-ifdef USE_GCC
MAPFILE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers
-else
-MAPFILE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers \
- $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-nonproduct
+ifndef USE_GCC
# This mapfile is only needed when compiling with dtrace support,
# and mustn't be otherwise.
MAPFILE_DTRACE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-$(TYPE)
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/assembler_sparc.cpp
--- a/src/cpu/sparc/vm/assembler_sparc.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/assembler_sparc.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -1794,7 +1794,8 @@
mov(reg,O0); // Move arg into O0; arg might be in O7 which is about to be crushed
stx(O7,SP,frame::register_save_words*wordSize+STACK_BIAS+7*8);
- set((intptr_t)real_msg, O1);
+ // Size of set() should stay the same
+ patchable_set((intptr_t)real_msg, O1);
// Load address to call to into O7
load_ptr_contents(a, O7);
// Register call to verify_oop_subroutine
@@ -1831,7 +1832,8 @@
ld_ptr(addr.base(), addr.disp() + 8*8, O0); // Load arg into O0; arg might be in O7 which is about to be crushed
stx(O7,SP,frame::register_save_words*wordSize+STACK_BIAS+7*8);
- set((intptr_t)real_msg, O1);
+ // Size of set() should stay the same
+ patchable_set((intptr_t)real_msg, O1);
// Load address to call to into O7
load_ptr_contents(a, O7);
// Register call to verify_oop_subroutine
@@ -1976,7 +1978,8 @@
save_frame(::round_to(sizeof(RegistersForDebugging) / BytesPerWord, 2));
// stop_subroutine expects message pointer in I1.
- set((intptr_t)msg, O1);
+ // Size of set() should stay the same
+ patchable_set((intptr_t)msg, O1);
// factor long stop-sequence into subroutine to save space
assert(StubRoutines::Sparc::stop_subroutine_entry_address(), "hasn't been generated yet");
@@ -1998,7 +2001,8 @@
save_frame(::round_to(sizeof(RegistersForDebugging) / BytesPerWord, 2));
RegistersForDebugging::save_registers(this);
mov(O0, L0);
- set((intptr_t)msg, O0);
+ // Size of set() should stay the same
+ patchable_set((intptr_t)msg, O0);
call( CAST_FROM_FN_PTR(address, warning) );
delayed()->nop();
// ret();
@@ -4901,3 +4905,65 @@
// Caller should set it:
// add(G0, 1, result); // equals
}
+
+// Use BIS for zeroing (count is in bytes).
+void MacroAssembler::bis_zeroing(Register to, Register count, Register temp, Label& Ldone) {
+ assert(UseBlockZeroing && VM_Version::has_block_zeroing(), "only works with BIS zeroing");
+ Register end = count;
+ int cache_line_size = VM_Version::prefetch_data_size();
+ // Minimum count when BIS zeroing can be used since
+ // it needs membar which is expensive.
+ int block_zero_size = MAX2(cache_line_size*3, (int)BlockZeroingLowLimit);
+
+ Label small_loop;
+ // Check if count is negative (dead code) or zero.
+ // Note, count uses 64bit in 64 bit VM.
+ cmp_and_brx_short(count, 0, Assembler::lessEqual, Assembler::pn, Ldone);
+
+ // Use BIS zeroing only for big arrays since it requires membar.
+ if (Assembler::is_simm13(block_zero_size)) { // < 4096
+ cmp(count, block_zero_size);
+ } else {
+ set(block_zero_size, temp);
+ cmp(count, temp);
+ }
+ br(Assembler::lessUnsigned, false, Assembler::pt, small_loop);
+ delayed()->add(to, count, end);
+
+ // Note: size is >= three (32 bytes) cache lines.
+
+ // Clean the beginning of space up to next cache line.
+ for (int offs = 0; offs < cache_line_size; offs += 8) {
+ stx(G0, to, offs);
+ }
+
+ // align to next cache line
+ add(to, cache_line_size, to);
+ and3(to, -cache_line_size, to);
+
+ // Note: size left >= two (32 bytes) cache lines.
+
+ // BIS should not be used to zero tail (64 bytes)
+ // to avoid zeroing a header of the following object.
+ sub(end, (cache_line_size*2)-8, end);
+
+ Label bis_loop;
+ bind(bis_loop);
+ stxa(G0, to, G0, Assembler::ASI_ST_BLKINIT_PRIMARY);
+ add(to, cache_line_size, to);
+ cmp_and_brx_short(to, end, Assembler::lessUnsigned, Assembler::pt, bis_loop);
+
+ // BIS needs membar.
+ membar(Assembler::StoreLoad);
+
+ add(end, (cache_line_size*2)-8, end); // restore end
+ cmp_and_brx_short(to, end, Assembler::greaterEqualUnsigned, Assembler::pn, Ldone);
+
+ // Clean the tail.
+ bind(small_loop);
+ stx(G0, to, 0);
+ add(to, 8, to);
+ cmp_and_brx_short(to, end, Assembler::lessUnsigned, Assembler::pt, small_loop);
+ nop(); // Separate short branches
+}
+
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/assembler_sparc.hpp
--- a/src/cpu/sparc/vm/assembler_sparc.hpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/assembler_sparc.hpp Thu Sep 08 06:36:31 2011 -0700
@@ -885,8 +885,9 @@
}
enum ASIs { // page 72, v9
- ASI_PRIMARY = 0x80,
- ASI_PRIMARY_LITTLE = 0x88,
+ ASI_PRIMARY = 0x80,
+ ASI_PRIMARY_NOFAULT = 0x82,
+ ASI_PRIMARY_LITTLE = 0x88,
// Block initializing store
ASI_ST_BLKINIT_PRIMARY = 0xE2,
// Most-Recently-Used (MRU) BIS variant
@@ -1786,9 +1787,12 @@
rs1(s) |
op3(wrreg_op3) |
u_field(2, 29, 25) |
- u_field(1, 13, 13) |
+ immed(true) |
simm(simm13a, 13)); }
- inline void wrasi( Register d) { v9_only(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25)); }
+ inline void wrasi(Register d) { v9_only(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25)); }
+ // wrasi(d, imm) stores (d xor imm) to asi
+ inline void wrasi(Register d, int simm13a) { v9_only(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) |
+ u_field(3, 29, 25) | immed(true) | simm(simm13a, 13)); }
inline void wrfprs( Register d) { v9_only(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(6, 29, 25)); }
@@ -2625,6 +2629,8 @@
void char_arrays_equals(Register ary1, Register ary2,
Register limit, Register result,
Register chr1, Register chr2, Label& Ldone);
+ // Use BIS for zeroing
+ void bis_zeroing(Register to, Register count, Register temp, Label& Ldone);
#undef VIRTUAL
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
--- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -142,11 +142,6 @@
}
-LIR_Opr LIR_Assembler::incomingReceiverOpr() {
- return FrameMap::I0_oop_opr;
-}
-
-
LIR_Opr LIR_Assembler::osrBufferPointer() {
return FrameMap::I0_opr;
}
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/c1_Runtime1_sparc.cpp
--- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -782,13 +782,6 @@
}
break;
- case jvmti_exception_throw_id:
- { // Oexception : exception
- __ set_info("jvmti_exception_throw", dont_gc_arguments);
- oop_maps = generate_stub_call(sasm, noreg, CAST_FROM_FN_PTR(address, Runtime1::post_jvmti_exception_throw), I0);
- }
- break;
-
case dtrace_object_alloc_id:
{ // O0: object
__ set_info("dtrace_object_alloc", dont_gc_arguments);
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/copy_sparc.hpp
--- a/src/cpu/sparc/vm/copy_sparc.hpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/copy_sparc.hpp Thu Sep 08 06:36:31 2011 -0700
@@ -156,9 +156,16 @@
#endif // _LP64
}
+typedef void (*_zero_Fn)(HeapWord* to, size_t count);
+
static void pd_fill_to_aligned_words(HeapWord* tohw, size_t count, juint value) {
assert(MinObjAlignmentInBytes >= BytesPerLong, "need alternate implementation");
+ if (value == 0 && UseBlockZeroing &&
+ (count > (BlockZeroingLowLimit >> LogHeapWordSize))) {
+ // Call it only when block zeroing is used
+ ((_zero_Fn)StubRoutines::zero_aligned_words())(tohw, count);
+ } else {
julong* to = (julong*)tohw;
julong v = ((julong)value << 32) | value;
// If count is odd, odd will be equal to 1 on 32-bit platform
@@ -176,6 +183,7 @@
*((juint*)to) = value;
}
+ }
}
static void pd_fill_to_bytes(void* to, size_t count, jubyte value) {
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/frame_sparc.hpp
--- a/src/cpu/sparc/vm/frame_sparc.hpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/frame_sparc.hpp Thu Sep 08 06:36:31 2011 -0700
@@ -259,13 +259,8 @@
};
#endif /* CC_INTERP */
- // the compiler frame has many of the same fields as the interpreter frame
- // %%%%% factor out declarations of the shared fields
enum compiler_frame_fixed_locals {
- compiler_frame_d_scratch_fp_offset = -2,
- compiler_frame_vm_locals_fp_offset = -2, // should be same as above
-
- compiler_frame_vm_local_words = -compiler_frame_vm_locals_fp_offset
+ compiler_frame_vm_locals_fp_offset = -2
};
private:
@@ -283,9 +278,6 @@
inline void interpreter_frame_set_tos_address(intptr_t* x);
-
- // %%%%% Another idea: instead of defining 3 fns per item, just define one returning a ref
-
// monitors:
// next two fns read and write Lmonitors value,
@@ -298,22 +290,8 @@
return ((interpreterState)sp_at(interpreter_state_ptr_offset));
}
-
#endif /* CC_INTERP */
-
-
- // Compiled frames
-
public:
- // Tells if this register can hold 64 bits on V9 (really, V8+).
- static bool holds_a_doubleword(Register reg) {
-#ifdef _LP64
- // return true;
- return reg->is_out() || reg->is_global();
-#else
- return reg->is_out() || reg->is_global();
-#endif
- }
#endif // CPU_SPARC_VM_FRAME_SPARC_HPP
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/methodHandles_sparc.cpp
--- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -1262,6 +1262,15 @@
}
break;
+ case _adapter_opt_profiling:
+ if (java_lang_invoke_CountingMethodHandle::vmcount_offset_in_bytes() != 0) {
+ Address G3_mh_vmcount(G3_method_handle, java_lang_invoke_CountingMethodHandle::vmcount_offset_in_bytes());
+ __ ld(G3_mh_vmcount, O1_scratch);
+ __ add(O1_scratch, 1, O1_scratch);
+ __ st(O1_scratch, G3_mh_vmcount);
+ }
+ // fall through
+
case _adapter_retype_only:
case _adapter_retype_raw:
// Immediately jump to the next MH layer:
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/sparc.ad
--- a/src/cpu/sparc/vm/sparc.ad Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/sparc.ad Thu Sep 08 06:36:31 2011 -0700
@@ -460,6 +460,8 @@
// Must be visible to the DFA in dfa_sparc.cpp
extern bool can_branch_register( Node *bol, Node *cmp );
+extern bool use_block_zeroing(Node* count);
+
// Macros to extract hi & lo halves from a long pair.
// G0 is not part of any long pair, so assert on that.
// Prevents accidentally using G1 instead of G0.
@@ -521,6 +523,12 @@
return false;
}
+bool use_block_zeroing(Node* count) {
+ // Use BIS for zeroing if count is not constant
+ // or it is >= BlockZeroingLowLimit.
+ return UseBlockZeroing && (count->find_intptr_t_con(BlockZeroingLowLimit) >= BlockZeroingLowLimit);
+}
+
// ****************************************************************************
// REQUIRED FUNCTIONALITY
@@ -832,6 +840,7 @@
!(n->ideal_Opcode()==Op_ConvI2D && ld_op==Op_LoadF) &&
!(n->ideal_Opcode()==Op_PrefetchRead && ld_op==Op_LoadI) &&
!(n->ideal_Opcode()==Op_PrefetchWrite && ld_op==Op_LoadI) &&
+ !(n->ideal_Opcode()==Op_PrefetchAllocation && ld_op==Op_LoadI) &&
!(n->ideal_Opcode()==Op_Load2I && ld_op==Op_LoadD) &&
!(n->ideal_Opcode()==Op_Load4C && ld_op==Op_LoadD) &&
!(n->ideal_Opcode()==Op_Load4S && ld_op==Op_LoadD) &&
@@ -2810,25 +2819,6 @@
__ float_cmp( $primary, -1, Fsrc1, Fsrc2, Rdst);
%}
- // Compiler ensures base is doubleword aligned and cnt is count of doublewords
- enc_class enc_Clear_Array(iRegX cnt, iRegP base, iRegX temp) %{
- MacroAssembler _masm(&cbuf);
- Register nof_bytes_arg = reg_to_register_object($cnt$$reg);
- Register nof_bytes_tmp = reg_to_register_object($temp$$reg);
- Register base_pointer_arg = reg_to_register_object($base$$reg);
-
- Label loop;
- __ mov(nof_bytes_arg, nof_bytes_tmp);
-
- // Loop and clear, walking backwards through the array.
- // nof_bytes_tmp (if >0) is always the number of bytes to zero
- __ bind(loop);
- __ deccc(nof_bytes_tmp, 8);
- __ br(Assembler::greaterEqual, true, Assembler::pt, loop);
- __ delayed()-> stx(G0, base_pointer_arg, nof_bytes_tmp);
- // %%%% this mini-loop must not cross a cache boundary!
- %}
-
enc_class enc_String_Compare(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result) %{
Label Ldone, Lloop;
@@ -10257,9 +10247,9 @@
ins_pipe(long_memory_op);
%}
-// Count and Base registers are fixed because the allocator cannot
-// kill unknown registers. The encodings are generic.
+// The encodings are generic.
instruct clear_array(iRegX cnt, iRegP base, iRegX temp, Universe dummy, flagsReg ccr) %{
+ predicate(!use_block_zeroing(n->in(2)) );
match(Set dummy (ClearArray cnt base));
effect(TEMP temp, KILL ccr);
ins_cost(300);
@@ -10267,7 +10257,71 @@
"loop: SUBcc $temp,8,$temp\t! Count down a dword of bytes\n"
" BRge loop\t\t! Clearing loop\n"
" STX G0,[$base+$temp]\t! delay slot" %}
- ins_encode( enc_Clear_Array(cnt, base, temp) );
+
+ ins_encode %{
+ // Compiler ensures base is doubleword aligned and cnt is count of doublewords
+ Register nof_bytes_arg = $cnt$$Register;
+ Register nof_bytes_tmp = $temp$$Register;
+ Register base_pointer_arg = $base$$Register;
+
+ Label loop;
+ __ mov(nof_bytes_arg, nof_bytes_tmp);
+
+ // Loop and clear, walking backwards through the array.
+ // nof_bytes_tmp (if >0) is always the number of bytes to zero
+ __ bind(loop);
+ __ deccc(nof_bytes_tmp, 8);
+ __ br(Assembler::greaterEqual, true, Assembler::pt, loop);
+ __ delayed()-> stx(G0, base_pointer_arg, nof_bytes_tmp);
+ // %%%% this mini-loop must not cross a cache boundary!
+ %}
+ ins_pipe(long_memory_op);
+%}
+
+instruct clear_array_bis(g1RegX cnt, o0RegP base, Universe dummy, flagsReg ccr) %{
+ predicate(use_block_zeroing(n->in(2)));
+ match(Set dummy (ClearArray cnt base));
+ effect(USE_KILL cnt, USE_KILL base, KILL ccr);
+ ins_cost(300);
+ format %{ "CLEAR [$base, $cnt]\t! ClearArray" %}
+
+ ins_encode %{
+
+ assert(MinObjAlignmentInBytes >= BytesPerLong, "need alternate implementation");
+ Register to = $base$$Register;
+ Register count = $cnt$$Register;
+
+ Label Ldone;
+ __ nop(); // Separate short branches
+ // Use BIS for zeroing (temp is not used).
+ __ bis_zeroing(to, count, G0, Ldone);
+ __ bind(Ldone);
+
+ %}
+ ins_pipe(long_memory_op);
+%}
+
+instruct clear_array_bis_2(g1RegX cnt, o0RegP base, iRegX tmp, Universe dummy, flagsReg ccr) %{
+ predicate(use_block_zeroing(n->in(2)) && !Assembler::is_simm13((int)BlockZeroingLowLimit));
+ match(Set dummy (ClearArray cnt base));
+ effect(TEMP tmp, USE_KILL cnt, USE_KILL base, KILL ccr);
+ ins_cost(300);
+ format %{ "CLEAR [$base, $cnt]\t! ClearArray" %}
+
+ ins_encode %{
+
+ assert(MinObjAlignmentInBytes >= BytesPerLong, "need alternate implementation");
+ Register to = $base$$Register;
+ Register count = $cnt$$Register;
+ Register temp = $tmp$$Register;
+
+ Label Ldone;
+ __ nop(); // Separate short branches
+ // Use BIS for zeroing
+ __ bis_zeroing(to, count, temp, Ldone);
+ __ bind(Ldone);
+
+ %}
ins_pipe(long_memory_op);
%}
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/stubGenerator_sparc.cpp
--- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -1124,6 +1124,126 @@
}
}
+ //
+ // Generate main code for disjoint arraycopy
+ //
+ typedef void (StubGenerator::*CopyLoopFunc)(Register from, Register to, Register count, int count_dec,
+ Label& L_loop, bool use_prefetch, bool use_bis);
+
+ void disjoint_copy_core(Register from, Register to, Register count, int log2_elem_size,
+ int iter_size, CopyLoopFunc copy_loop_func) {
+ Label L_copy;
+
+ assert(log2_elem_size <= 3, "the following code should be changed");
+ int count_dec = 16>>log2_elem_size;
+
+ int prefetch_dist = MAX2(ArraycopySrcPrefetchDistance, ArraycopyDstPrefetchDistance);
+ assert(prefetch_dist < 4096, "invalid value");
+ prefetch_dist = (prefetch_dist + (iter_size-1)) & (-iter_size); // round up to one iteration copy size
+ int prefetch_count = (prefetch_dist >> log2_elem_size); // elements count
+
+ if (UseBlockCopy) {
+ Label L_block_copy, L_block_copy_prefetch, L_skip_block_copy;
+
+ // 64 bytes tail + bytes copied in one loop iteration
+ int tail_size = 64 + iter_size;
+ int block_copy_count = (MAX2(tail_size, (int)BlockCopyLowLimit)) >> log2_elem_size;
+ // Use BIS copy only for big arrays since it requires membar.
+ __ set(block_copy_count, O4);
+ __ cmp_and_br_short(count, O4, Assembler::lessUnsigned, Assembler::pt, L_skip_block_copy);
+ // This code is for disjoint source and destination:
+ // to <= from || to >= from+count
+ // but BIS will stomp over 'from' if (to > from-tail_size && to <= from)
+ __ sub(from, to, O4);
+ __ srax(O4, 4, O4); // divide by 16 since following short branch have only 5 bits for imm.
+ __ cmp_and_br_short(O4, (tail_size>>4), Assembler::lessEqualUnsigned, Assembler::pn, L_skip_block_copy);
+
+ __ wrasi(G0, Assembler::ASI_ST_BLKINIT_PRIMARY);
+ // BIS should not be used to copy tail (64 bytes+iter_size)
+ // to avoid zeroing of following values.
+ __ sub(count, (tail_size>>log2_elem_size), count); // count is still positive >= 0
+
+ if (prefetch_count > 0) { // rounded up to one iteration count
+ // Do prefetching only if copy size is bigger
+ // than prefetch distance.
+ __ set(prefetch_count, O4);
+ __ cmp_and_brx_short(count, O4, Assembler::less, Assembler::pt, L_block_copy);
+ __ sub(count, prefetch_count, count);
+
+ (this->*copy_loop_func)(from, to, count, count_dec, L_block_copy_prefetch, true, true);
+ __ add(count, prefetch_count, count); // restore count
+
+ } // prefetch_count > 0
+
+ (this->*copy_loop_func)(from, to, count, count_dec, L_block_copy, false, true);
+ __ add(count, (tail_size>>log2_elem_size), count); // restore count
+
+ __ wrasi(G0, Assembler::ASI_PRIMARY_NOFAULT);
+ // BIS needs membar.
+ __ membar(Assembler::StoreLoad);
+ // Copy tail
+ __ ba_short(L_copy);
+
+ __ BIND(L_skip_block_copy);
+ } // UseBlockCopy
+
+ if (prefetch_count > 0) { // rounded up to one iteration count
+ // Do prefetching only if copy size is bigger
+ // than prefetch distance.
+ __ set(prefetch_count, O4);
+ __ cmp_and_brx_short(count, O4, Assembler::lessUnsigned, Assembler::pt, L_copy);
+ __ sub(count, prefetch_count, count);
+
+ Label L_copy_prefetch;
+ (this->*copy_loop_func)(from, to, count, count_dec, L_copy_prefetch, true, false);
+ __ add(count, prefetch_count, count); // restore count
+
+ } // prefetch_count > 0
+
+ (this->*copy_loop_func)(from, to, count, count_dec, L_copy, false, false);
+ }
+
+
+
+ //
+ // Helper methods for copy_16_bytes_forward_with_shift()
+ //
+ void copy_16_bytes_shift_loop(Register from, Register to, Register count, int count_dec,
+ Label& L_loop, bool use_prefetch, bool use_bis) {
+
+ const Register left_shift = G1; // left shift bit counter
+ const Register right_shift = G5; // right shift bit counter
+
+ __ align(OptoLoopAlignment);
+ __ BIND(L_loop);
+ if (use_prefetch) {
+ if (ArraycopySrcPrefetchDistance > 0) {
+ __ prefetch(from, ArraycopySrcPrefetchDistance, Assembler::severalReads);
+ }
+ if (ArraycopyDstPrefetchDistance > 0) {
+ __ prefetch(to, ArraycopyDstPrefetchDistance, Assembler::severalWritesAndPossiblyReads);
+ }
+ }
+ __ ldx(from, 0, O4);
+ __ ldx(from, 8, G4);
+ __ inc(to, 16);
+ __ inc(from, 16);
+ __ deccc(count, count_dec); // Can we do next iteration after this one?
+ __ srlx(O4, right_shift, G3);
+ __ bset(G3, O3);
+ __ sllx(O4, left_shift, O4);
+ __ srlx(G4, right_shift, G3);
+ __ bset(G3, O4);
+ if (use_bis) {
+ __ stxa(O3, to, -16);
+ __ stxa(O4, to, -8);
+ } else {
+ __ stx(O3, to, -16);
+ __ stx(O4, to, -8);
+ }
+ __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop);
+ __ delayed()->sllx(G4, left_shift, O3);
+ }
// Copy big chunks forward with shift
//
@@ -1135,64 +1255,51 @@
// L_copy_bytes - copy exit label
//
void copy_16_bytes_forward_with_shift(Register from, Register to,
- Register count, int count_dec, Label& L_copy_bytes) {
- Label L_loop, L_aligned_copy, L_copy_last_bytes;
+ Register count, int log2_elem_size, Label& L_copy_bytes) {
+ Label L_aligned_copy, L_copy_last_bytes;
+ assert(log2_elem_size <= 3, "the following code should be changed");
+ int count_dec = 16>>log2_elem_size;
// if both arrays have the same alignment mod 8, do 8 bytes aligned copy
- __ andcc(from, 7, G1); // misaligned bytes
- __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy);
- __ delayed()->nop();
+ __ andcc(from, 7, G1); // misaligned bytes
+ __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy);
+ __ delayed()->nop();
const Register left_shift = G1; // left shift bit counter
const Register right_shift = G5; // right shift bit counter
- __ sll(G1, LogBitsPerByte, left_shift);
- __ mov(64, right_shift);
- __ sub(right_shift, left_shift, right_shift);
+ __ sll(G1, LogBitsPerByte, left_shift);
+ __ mov(64, right_shift);
+ __ sub(right_shift, left_shift, right_shift);
//
// Load 2 aligned 8-bytes chunks and use one from previous iteration
// to form 2 aligned 8-bytes chunks to store.
//
- __ deccc(count, count_dec); // Pre-decrement 'count'
- __ andn(from, 7, from); // Align address
- __ ldx(from, 0, O3);
- __ inc(from, 8);
- __ align(OptoLoopAlignment);
- __ BIND(L_loop);
- __ ldx(from, 0, O4);
- __ deccc(count, count_dec); // Can we do next iteration after this one?
- __ ldx(from, 8, G4);
- __ inc(to, 16);
- __ inc(from, 16);
- __ sllx(O3, left_shift, O3);
- __ srlx(O4, right_shift, G3);
- __ bset(G3, O3);
- __ stx(O3, to, -16);
- __ sllx(O4, left_shift, O4);
- __ srlx(G4, right_shift, G3);
- __ bset(G3, O4);
- __ stx(O4, to, -8);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop);
- __ delayed()->mov(G4, O3);
-
- __ inccc(count, count_dec>>1 ); // + 8 bytes
- __ brx(Assembler::negative, true, Assembler::pn, L_copy_last_bytes);
- __ delayed()->inc(count, count_dec>>1); // restore 'count'
-
- // copy 8 bytes, part of them already loaded in O3
- __ ldx(from, 0, O4);
- __ inc(to, 8);
- __ inc(from, 8);
- __ sllx(O3, left_shift, O3);
- __ srlx(O4, right_shift, G3);
- __ bset(O3, G3);
- __ stx(G3, to, -8);
+ __ dec(count, count_dec); // Pre-decrement 'count'
+ __ andn(from, 7, from); // Align address
+ __ ldx(from, 0, O3);
+ __ inc(from, 8);
+ __ sllx(O3, left_shift, O3);
+
+ disjoint_copy_core(from, to, count, log2_elem_size, 16, copy_16_bytes_shift_loop);
+
+ __ inccc(count, count_dec>>1 ); // + 8 bytes
+ __ brx(Assembler::negative, true, Assembler::pn, L_copy_last_bytes);
+ __ delayed()->inc(count, count_dec>>1); // restore 'count'
+
+ // copy 8 bytes, part of them already loaded in O3
+ __ ldx(from, 0, O4);
+ __ inc(to, 8);
+ __ inc(from, 8);
+ __ srlx(O4, right_shift, G3);
+ __ bset(O3, G3);
+ __ stx(G3, to, -8);
__ BIND(L_copy_last_bytes);
- __ srl(right_shift, LogBitsPerByte, right_shift); // misaligned bytes
- __ br(Assembler::always, false, Assembler::pt, L_copy_bytes);
- __ delayed()->sub(from, right_shift, from); // restore address
+ __ srl(right_shift, LogBitsPerByte, right_shift); // misaligned bytes
+ __ br(Assembler::always, false, Assembler::pt, L_copy_bytes);
+ __ delayed()->sub(from, right_shift, from); // restore address
__ BIND(L_aligned_copy);
}
@@ -1348,7 +1455,7 @@
// The compare above (count >= 23) guarantes 'count' >= 16 bytes.
// Also jump over aligned copy after the copy with shift completed.
- copy_16_bytes_forward_with_shift(from, to, count, 16, L_copy_byte);
+ copy_16_bytes_forward_with_shift(from, to, count, 0, L_copy_byte);
}
// Both array are 8 bytes aligned, copy 16 bytes at a time
@@ -1576,7 +1683,7 @@
// The compare above (count >= 11) guarantes 'count' >= 16 bytes.
// Also jump over aligned copy after the copy with shift completed.
- copy_16_bytes_forward_with_shift(from, to, count, 8, L_copy_2_bytes);
+ copy_16_bytes_forward_with_shift(from, to, count, 1, L_copy_2_bytes);
}
// Both array are 8 bytes aligned, copy 16 bytes at a time
@@ -1950,6 +2057,45 @@
}
//
+ // Helper methods for generate_disjoint_int_copy_core()
+ //
+ void copy_16_bytes_loop(Register from, Register to, Register count, int count_dec,
+ Label& L_loop, bool use_prefetch, bool use_bis) {
+
+ __ align(OptoLoopAlignment);
+ __ BIND(L_loop);
+ if (use_prefetch) {
+ if (ArraycopySrcPrefetchDistance > 0) {
+ __ prefetch(from, ArraycopySrcPrefetchDistance, Assembler::severalReads);
+ }
+ if (ArraycopyDstPrefetchDistance > 0) {
+ __ prefetch(to, ArraycopyDstPrefetchDistance, Assembler::severalWritesAndPossiblyReads);
+ }
+ }
+ __ ldx(from, 4, O4);
+ __ ldx(from, 12, G4);
+ __ inc(to, 16);
+ __ inc(from, 16);
+ __ deccc(count, 4); // Can we do next iteration after this one?
+
+ __ srlx(O4, 32, G3);
+ __ bset(G3, O3);
+ __ sllx(O4, 32, O4);
+ __ srlx(G4, 32, G3);
+ __ bset(G3, O4);
+ if (use_bis) {
+ __ stxa(O3, to, -16);
+ __ stxa(O4, to, -8);
+ } else {
+ __ stx(O3, to, -16);
+ __ stx(O4, to, -8);
+ }
+ __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop);
+ __ delayed()->sllx(G4, 32, O3);
+
+ }
+
+ //
// Generate core code for disjoint int copy (and oop copy on 32-bit).
// If "aligned" is true, the "from" and "to" addresses are assumed
// to be heapword aligned.
@@ -1962,7 +2108,7 @@
void generate_disjoint_int_copy_core(bool aligned) {
Label L_skip_alignment, L_aligned_copy;
- Label L_copy_16_bytes, L_copy_4_bytes, L_copy_4_bytes_loop, L_exit;
+ Label L_copy_4_bytes, L_copy_4_bytes_loop, L_exit;
const Register from = O0; // source array address
const Register to = O1; // destination array address
@@ -2013,30 +2159,16 @@
// copy with shift 4 elements (16 bytes) at a time
__ dec(count, 4); // The cmp at the beginning guaranty count >= 4
-
- __ align(OptoLoopAlignment);
- __ BIND(L_copy_16_bytes);
- __ ldx(from, 4, O4);
- __ deccc(count, 4); // Can we do next iteration after this one?
- __ ldx(from, 12, G4);
- __ inc(to, 16);
- __ inc(from, 16);
- __ sllx(O3, 32, O3);
- __ srlx(O4, 32, G3);
- __ bset(G3, O3);
- __ stx(O3, to, -16);
- __ sllx(O4, 32, O4);
- __ srlx(G4, 32, G3);
- __ bset(G3, O4);
- __ stx(O4, to, -8);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_16_bytes);
- __ delayed()->mov(G4, O3);
+ __ sllx(O3, 32, O3);
+
+ disjoint_copy_core(from, to, count, 2, 16, copy_16_bytes_loop);
__ br(Assembler::always, false, Assembler::pt, L_copy_4_bytes);
__ delayed()->inc(count, 4); // restore 'count'
__ BIND(L_aligned_copy);
- }
+ } // !aligned
+
// copy 4 elements (16 bytes) at a time
__ and3(count, 1, G4); // Save
__ srl(count, 1, count);
@@ -2223,6 +2355,38 @@
}
//
+ // Helper methods for generate_disjoint_long_copy_core()
+ //
+ void copy_64_bytes_loop(Register from, Register to, Register count, int count_dec,
+ Label& L_loop, bool use_prefetch, bool use_bis) {
+ __ align(OptoLoopAlignment);
+ __ BIND(L_loop);
+ for (int off = 0; off < 64; off += 16) {
+ if (use_prefetch && (off & 31) == 0) {
+ if (ArraycopySrcPrefetchDistance > 0) {
+ __ prefetch(from, ArraycopySrcPrefetchDistance, Assembler::severalReads);
+ }
+ if (ArraycopyDstPrefetchDistance > 0) {
+ __ prefetch(to, ArraycopyDstPrefetchDistance, Assembler::severalWritesAndPossiblyReads);
+ }
+ }
+ __ ldx(from, off+0, O4);
+ __ ldx(from, off+8, O5);
+ if (use_bis) {
+ __ stxa(O4, to, off+0);
+ __ stxa(O5, to, off+8);
+ } else {
+ __ stx(O4, to, off+0);
+ __ stx(O5, to, off+8);
+ }
+ }
+ __ deccc(count, 8);
+ __ inc(from, 64);
+ __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop);
+ __ delayed()->inc(to, 64);
+ }
+
+ //
// Generate core code for disjoint long copy (and oop copy on 64-bit).
// "aligned" is ignored, because we must make the stronger
// assumption that both addresses are always 64-bit aligned.
@@ -2261,38 +2425,28 @@
const Register offset0 = O4; // element offset
const Register offset8 = O5; // next element offset
- __ deccc(count, 2);
- __ mov(G0, offset0); // offset from start of arrays (0)
- __ brx(Assembler::negative, false, Assembler::pn, L_copy_8_bytes );
- __ delayed()->add(offset0, 8, offset8);
+ __ deccc(count, 2);
+ __ mov(G0, offset0); // offset from start of arrays (0)
+ __ brx(Assembler::negative, false, Assembler::pn, L_copy_8_bytes );
+ __ delayed()->add(offset0, 8, offset8);
// Copy by 64 bytes chunks
- Label L_copy_64_bytes;
+
const Register from64 = O3; // source address
const Register to64 = G3; // destination address
- __ subcc(count, 6, O3);
- __ brx(Assembler::negative, false, Assembler::pt, L_copy_16_bytes );
- __ delayed()->mov(to, to64);
- // Now we can use O4(offset0), O5(offset8) as temps
- __ mov(O3, count);
- __ mov(from, from64);
-
- __ align(OptoLoopAlignment);
- __ BIND(L_copy_64_bytes);
- for( int off = 0; off < 64; off += 16 ) {
- __ ldx(from64, off+0, O4);
- __ ldx(from64, off+8, O5);
- __ stx(O4, to64, off+0);
- __ stx(O5, to64, off+8);
- }
- __ deccc(count, 8);
- __ inc(from64, 64);
- __ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_64_bytes);
- __ delayed()->inc(to64, 64);
+ __ subcc(count, 6, O3);
+ __ brx(Assembler::negative, false, Assembler::pt, L_copy_16_bytes );
+ __ delayed()->mov(to, to64);
+ // Now we can use O4(offset0), O5(offset8) as temps
+ __ mov(O3, count);
+ // count >= 0 (original count - 8)
+ __ mov(from, from64);
+
+ disjoint_copy_core(from64, to64, count, 3, 64, copy_64_bytes_loop);
// Restore O4(offset0), O5(offset8)
__ sub(from64, from, offset0);
- __ inccc(count, 6);
+ __ inccc(count, 6); // restore count
__ brx(Assembler::negative, false, Assembler::pn, L_copy_8_bytes );
__ delayed()->add(offset0, 8, offset8);
@@ -3069,6 +3223,34 @@
return start;
}
+ //
+ // Generate stub for heap zeroing.
+ // "to" address is aligned to jlong (8 bytes).
+ //
+ // Arguments for generated stub:
+ // to: O0
+ // count: O1 treated as signed (count of HeapWord)
+ // count could be 0
+ //
+ address generate_zero_aligned_words(const char* name) {
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", name);
+ address start = __ pc();
+
+ const Register to = O0; // source array address
+ const Register count = O1; // HeapWords count
+ const Register temp = O2; // scratch
+
+ Label Ldone;
+ __ sllx(count, LogHeapWordSize, count); // to bytes count
+ // Use BIS for zeroing
+ __ bis_zeroing(to, count, temp, Ldone);
+ __ bind(Ldone);
+ __ retl();
+ __ delayed()->nop();
+ return start;
+}
+
void generate_arraycopy_stubs() {
address entry;
address entry_jbyte_arraycopy;
@@ -3195,6 +3377,10 @@
StubRoutines::_arrayof_jbyte_fill = generate_fill(T_BYTE, true, "arrayof_jbyte_fill");
StubRoutines::_arrayof_jshort_fill = generate_fill(T_SHORT, true, "arrayof_jshort_fill");
StubRoutines::_arrayof_jint_fill = generate_fill(T_INT, true, "arrayof_jint_fill");
+
+ if (UseBlockZeroing) {
+ StubRoutines::_zero_aligned_words = generate_zero_aligned_words("zero_aligned_words");
+ }
}
void generate_initial() {
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/templateTable_sparc.cpp
--- a/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/templateTable_sparc.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -3374,7 +3374,7 @@
if(UseTLAB) {
Register RoldTopValue = RallocatedObject;
- Register RtopAddr = G3_scratch, RtlabWasteLimitValue = G3_scratch;
+ Register RtlabWasteLimitValue = G3_scratch;
Register RnewTopValue = G1_scratch;
Register RendValue = Rscratch;
Register RfreeValue = RnewTopValue;
@@ -3455,7 +3455,11 @@
__ delayed()->add(RallocatedObject, sizeof(oopDesc), G3_scratch);
// initialize remaining object fields
- { Label loop;
+ if (UseBlockZeroing) {
+ // Use BIS for zeroing
+ __ bis_zeroing(G3_scratch, Roffset, G1_scratch, initialize_header);
+ } else {
+ Label loop;
__ subcc(Roffset, wordSize, Roffset);
__ bind(loop);
//__ subcc(Roffset, wordSize, Roffset); // executed above loop or in delay slot
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/vm_version_sparc.cpp
--- a/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -75,6 +75,24 @@
FLAG_SET_DEFAULT(AllocatePrefetchStyle, 1);
}
+ if (has_v9()) {
+ assert(ArraycopySrcPrefetchDistance < 4096, "invalid value");
+ if (ArraycopySrcPrefetchDistance >= 4096)
+ ArraycopySrcPrefetchDistance = 4064;
+ assert(ArraycopyDstPrefetchDistance < 4096, "invalid value");
+ if (ArraycopyDstPrefetchDistance >= 4096)
+ ArraycopyDstPrefetchDistance = 4064;
+ } else {
+ if (ArraycopySrcPrefetchDistance > 0) {
+ warning("prefetch instructions are not available on this CPU");
+ FLAG_SET_DEFAULT(ArraycopySrcPrefetchDistance, 0);
+ }
+ if (ArraycopyDstPrefetchDistance > 0) {
+ warning("prefetch instructions are not available on this CPU");
+ FLAG_SET_DEFAULT(ArraycopyDstPrefetchDistance, 0);
+ }
+ }
+
UseSSE = 0; // Only on x86 and x64
_supports_cx8 = has_v9();
@@ -170,6 +188,26 @@
FLAG_SET_DEFAULT(UseCBCond, false);
}
+ assert(BlockZeroingLowLimit > 0, "invalid value");
+ if (has_block_zeroing()) {
+ if (FLAG_IS_DEFAULT(UseBlockZeroing)) {
+ FLAG_SET_DEFAULT(UseBlockZeroing, true);
+ }
+ } else if (UseBlockZeroing) {
+ warning("BIS zeroing instructions are not available on this CPU");
+ FLAG_SET_DEFAULT(UseBlockZeroing, false);
+ }
+
+ assert(BlockCopyLowLimit > 0, "invalid value");
+ if (has_block_zeroing()) { // has_blk_init() && is_T4(): core's local L2 cache
+ if (FLAG_IS_DEFAULT(UseBlockCopy)) {
+ FLAG_SET_DEFAULT(UseBlockCopy, true);
+ }
+ } else if (UseBlockCopy) {
+ warning("BIS instructions are not available or expensive on this CPU");
+ FLAG_SET_DEFAULT(UseBlockCopy, false);
+ }
+
#ifdef COMPILER2
// T4 and newer Sparc cpus have fast RDPC.
if (has_fast_rdpc() && FLAG_IS_DEFAULT(UseRDPCForConstantTableBase)) {
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/sparc/vm/vm_version_sparc.hpp
--- a/src/cpu/sparc/vm/vm_version_sparc.hpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/sparc/vm/vm_version_sparc.hpp Thu Sep 08 06:36:31 2011 -0700
@@ -135,8 +135,8 @@
// T4 and newer Sparc have fast RDPC instruction.
static bool has_fast_rdpc() { return is_T4(); }
- // T4 and newer Sparc have Most-Recently-Used (MRU) BIS.
- static bool has_mru_blk_init() { return has_blk_init() && is_T4(); }
+ // On T4 and newer Sparc BIS to the beginning of cache line always zeros it.
+ static bool has_block_zeroing() { return has_blk_init() && is_T4(); }
static const char* cpu_features() { return _features_str; }
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -129,10 +129,6 @@
return FrameMap::receiver_opr;
}
-LIR_Opr LIR_Assembler::incomingReceiverOpr() {
- return receiverOpr();
-}
-
LIR_Opr LIR_Assembler::osrBufferPointer() {
return FrameMap::as_pointer_opr(receiverOpr()->as_register());
}
@@ -371,55 +367,6 @@
}
-void LIR_Assembler::monitorexit(LIR_Opr obj_opr, LIR_Opr lock_opr, Register new_hdr, int monitor_no, Register exception) {
- if (exception->is_valid()) {
- // preserve exception
- // note: the monitor_exit runtime call is a leaf routine
- // and cannot block => no GC can happen
- // The slow case (MonitorAccessStub) uses the first two stack slots
- // ([esp+0] and [esp+4]), therefore we store the exception at [esp+8]
- __ movptr (Address(rsp, 2*wordSize), exception);
- }
-
- Register obj_reg = obj_opr->as_register();
- Register lock_reg = lock_opr->as_register();
-
- // setup registers (lock_reg must be rax, for lock_object)
- assert(obj_reg != SYNC_header && lock_reg != SYNC_header, "rax, must be available here");
- Register hdr = lock_reg;
- assert(new_hdr == SYNC_header, "wrong register");
- lock_reg = new_hdr;
- // compute pointer to BasicLock
- Address lock_addr = frame_map()->address_for_monitor_lock(monitor_no);
- __ lea(lock_reg, lock_addr);
- // unlock object
- MonitorAccessStub* slow_case = new MonitorExitStub(lock_opr, true, monitor_no);
- // _slow_case_stubs->append(slow_case);
- // temporary fix: must be created after exceptionhandler, therefore as call stub
- _slow_case_stubs->append(slow_case);
- if (UseFastLocking) {
- // try inlined fast unlocking first, revert to slow locking if it fails
- // note: lock_reg points to the displaced header since the displaced header offset is 0!
- assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header");
- __ unlock_object(hdr, obj_reg, lock_reg, *slow_case->entry());
- } else {
- // always do slow unlocking
- // note: the slow unlocking code could be inlined here, however if we use
- // slow unlocking, speed doesn't matter anyway and this solution is
- // simpler and requires less duplicated code - additionally, the
- // slow unlocking code is the same in either case which simplifies
- // debugging
- __ jmp(*slow_case->entry());
- }
- // done
- __ bind(*slow_case->continuation());
-
- if (exception->is_valid()) {
- // restore exception
- __ movptr (exception, Address(rsp, 2 * wordSize));
- }
-}
-
// This specifies the rsp decrement needed to build the frame
int LIR_Assembler::initial_frame_size_in_bytes() {
// if rounding, must let FrameMap know!
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/x86/vm/c1_LIRAssembler_x86.hpp
--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp Thu Sep 08 06:36:31 2011 -0700
@@ -29,8 +29,6 @@
Address::ScaleFactor array_element_size(BasicType type) const;
- void monitorexit(LIR_Opr obj_opr, LIR_Opr lock_opr, Register new_hdr, int monitor_no, Register exception);
-
void arith_fpu_implementation(LIR_Code code, int left_index, int right_index, int dest_index, bool pop_fpu_stack);
// helper functions which checks for overflow and sets bailout if it
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/x86/vm/c1_Runtime1_x86.cpp
--- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -1465,19 +1465,6 @@
}
break;
- case jvmti_exception_throw_id:
- { // rax,: exception oop
- StubFrame f(sasm, "jvmti_exception_throw", dont_gc_arguments);
- // Preserve all registers across this potentially blocking call
- const int num_rt_args = 2; // thread, exception oop
- OopMap* map = save_live_registers(sasm, num_rt_args);
- int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, Runtime1::post_jvmti_exception_throw), rax);
- oop_maps = new OopMapSet();
- oop_maps->add_gc_map(call_offset, map);
- restore_live_registers(sasm);
- }
- break;
-
case dtrace_object_alloc_id:
{ // rax,: object
StubFrame f(sasm, "dtrace_object_alloc", dont_gc_arguments);
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/x86/vm/methodHandles_x86.cpp
--- a/src/cpu/x86/vm/methodHandles_x86.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/x86/vm/methodHandles_x86.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -1343,6 +1343,13 @@
}
break;
+ case _adapter_opt_profiling:
+ if (java_lang_invoke_CountingMethodHandle::vmcount_offset_in_bytes() != 0) {
+ Address rcx_mh_vmcount(rcx_recv, java_lang_invoke_CountingMethodHandle::vmcount_offset_in_bytes());
+ __ incrementl(rcx_mh_vmcount);
+ }
+ // fall through
+
case _adapter_retype_only:
case _adapter_retype_raw:
// immediately jump to the next MH layer:
diff -r 2fecca53a2c6 -r 5596e125fe4f src/cpu/x86/vm/methodHandles_x86.hpp
--- a/src/cpu/x86/vm/methodHandles_x86.hpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/cpu/x86/vm/methodHandles_x86.hpp Thu Sep 08 06:36:31 2011 -0700
@@ -110,6 +110,7 @@
class RicochetFrame {
friend class MethodHandles;
+ friend class VMStructs;
private:
intptr_t* _continuation; // what to do when control gets back here
diff -r 2fecca53a2c6 -r 5596e125fe4f src/share/vm/c1/c1_Compilation.cpp
--- a/src/share/vm/c1/c1_Compilation.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/share/vm/c1/c1_Compilation.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -346,7 +346,6 @@
implicit_exception_table(),
compiler(),
_env->comp_level(),
- true,
has_unsafe_access()
);
}
diff -r 2fecca53a2c6 -r 5596e125fe4f src/share/vm/c1/c1_GraphBuilder.cpp
--- a/src/share/vm/c1/c1_GraphBuilder.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -28,8 +28,10 @@
#include "c1/c1_Compilation.hpp"
#include "c1/c1_GraphBuilder.hpp"
#include "c1/c1_InstructionPrinter.hpp"
+#include "ci/ciCallSite.hpp"
#include "ci/ciField.hpp"
#include "ci/ciKlass.hpp"
+#include "ci/ciMethodHandle.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/bytecode.hpp"
#include "runtime/sharedRuntime.hpp"
@@ -1424,7 +1426,7 @@
// See whether this is the first return; if so, store off some
// of the state for later examination
if (num_returns() == 0) {
- set_inline_cleanup_info(_block, _last, state());
+ set_inline_cleanup_info();
}
// The current bci() is in the wrong scope, so use the bci() of
@@ -1582,6 +1584,8 @@
code = Bytecodes::_invokespecial;
}
+ bool is_invokedynamic = code == Bytecodes::_invokedynamic;
+
// NEEDS_CLEANUP
// I've added the target-is_loaded() test below but I don't really understand
// how klass->is_loaded() can be true and yet target->is_loaded() is false.
@@ -1693,26 +1697,31 @@
&& target->will_link(klass, callee_holder, code)) {
// callee is known => check if we have static binding
assert(target->is_loaded(), "callee must be known");
- if (code == Bytecodes::_invokestatic
- || code == Bytecodes::_invokespecial
- || code == Bytecodes::_invokevirtual && target->is_final_method()
- ) {
- // static binding => check if callee is ok
- ciMethod* inline_target = (cha_monomorphic_target != NULL)
- ? cha_monomorphic_target
- : target;
- bool res = try_inline(inline_target, (cha_monomorphic_target != NULL) || (exact_target != NULL));
+ if (code == Bytecodes::_invokestatic ||
+ code == Bytecodes::_invokespecial ||
+ code == Bytecodes::_invokevirtual && target->is_final_method() ||
+ code == Bytecodes::_invokedynamic) {
+ ciMethod* inline_target = (cha_monomorphic_target != NULL) ? cha_monomorphic_target : target;
+ bool success = false;
+ if (target->is_method_handle_invoke()) {
+ // method handle invokes
+ success = !is_invokedynamic ? for_method_handle_inline(target) : for_invokedynamic_inline(target);
+ }
+ if (!success) {
+ // static binding => check if callee is ok
+ success = try_inline(inline_target, (cha_monomorphic_target != NULL) || (exact_target != NULL));
+ }
CHECK_BAILOUT();
#ifndef PRODUCT
// printing
- if (PrintInlining && !res) {
+ if (PrintInlining && !success) {
// if it was successfully inlined, then it was already printed.
- print_inline_result(inline_target, res);
+ print_inline_result(inline_target, success);
}
#endif
clear_inline_bailout();
- if (res) {
+ if (success) {
// Register dependence if JVMTI has either breakpoint
// setting or hotswapping of methods capabilities since they may
// cause deoptimization.
@@ -1740,7 +1749,6 @@
code == Bytecodes::_invokespecial ||
code == Bytecodes::_invokevirtual ||
code == Bytecodes::_invokeinterface;
- bool is_invokedynamic = code == Bytecodes::_invokedynamic;
ValueType* result_type = as_ValueType(target->return_type());
// We require the debug info to be the "state before" because
@@ -3038,7 +3046,7 @@
INLINE_BAILOUT("disallowed by CompilerOracle")
} else if (!callee->can_be_compiled()) {
// callee is not compilable (prob. has breakpoints)
- INLINE_BAILOUT("not compilable")
+ INLINE_BAILOUT("not compilable (disabled)")
} else if (callee->intrinsic_id() != vmIntrinsics::_none && try_inline_intrinsics(callee)) {
// intrinsics can be native or not
return true;
@@ -3397,7 +3405,7 @@
}
-bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known) {
+bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, BlockBegin* cont_block) {
assert(!callee->is_native(), "callee must not be native");
if (CompilationPolicy::policy()->should_not_inline(compilation()->env(), callee)) {
INLINE_BAILOUT("inlining prohibited by policy");
@@ -3430,7 +3438,7 @@
} else {
if (inline_level() > MaxInlineLevel ) INLINE_BAILOUT("too-deep inlining");
if (recursive_inline_level(callee) > MaxRecursiveInlineLevel) INLINE_BAILOUT("too-deep recursive inlining");
- if (callee->code_size() > max_inline_size() ) INLINE_BAILOUT("callee is too large");
+ if (callee->code_size_for_inlining() > max_inline_size() ) INLINE_BAILOUT("callee is too large");
// don't inline throwable methods unless the inlining tree is rooted in a throwable class
if (callee->name() == ciSymbol::object_initializer_name() &&
@@ -3468,7 +3476,8 @@
// Insert null check if necessary
Value recv = NULL;
- if (code() != Bytecodes::_invokestatic) {
+ if (code() != Bytecodes::_invokestatic &&
+ code() != Bytecodes::_invokedynamic) {
// note: null check must happen even if first instruction of callee does
// an implicit null check since the callee is in a different scope
// and we must make sure exception handling does the right thing
@@ -3496,7 +3505,7 @@
// fall-through of control flow, all return instructions of the
// callee will need to be replaced by Goto's pointing to this
// continuation point.
- BlockBegin* cont = block_at(next_bci());
+ BlockBegin* cont = cont_block != NULL ? cont_block : block_at(next_bci());
bool continuation_existed = true;
if (cont == NULL) {
cont = new BlockBegin(next_bci());
@@ -3608,27 +3617,29 @@
// block merging. This allows load elimination and CSE to take place
// across multiple callee scopes if they are relatively simple, and
// is currently essential to making inlining profitable.
- if ( num_returns() == 1
- && block() == orig_block
- && block() == inline_cleanup_block()) {
- _last = inline_cleanup_return_prev();
- _state = inline_cleanup_state();
- } else if (continuation_preds == cont->number_of_preds()) {
- // Inlining caused that the instructions after the invoke in the
- // caller are not reachable any more. So skip filling this block
- // with instructions!
- assert (cont == continuation(), "");
- assert(_last && _last->as_BlockEnd(), "");
- _skip_block = true;
- } else {
- // Resume parsing in continuation block unless it was already parsed.
- // Note that if we don't change _last here, iteration in
- // iterate_bytecodes_for_block will stop when we return.
- if (!continuation()->is_set(BlockBegin::was_visited_flag)) {
- // add continuation to work list instead of parsing it immediately
+ if (cont_block == NULL) {
+ if (num_returns() == 1
+ && block() == orig_block
+ && block() == inline_cleanup_block()) {
+ _last = inline_cleanup_return_prev();
+ _state = inline_cleanup_state();
+ } else if (continuation_preds == cont->number_of_preds()) {
+ // Inlining caused that the instructions after the invoke in the
+ // caller are not reachable any more. So skip filling this block
+ // with instructions!
+ assert(cont == continuation(), "");
assert(_last && _last->as_BlockEnd(), "");
- scope_data()->parent()->add_to_work_list(continuation());
_skip_block = true;
+ } else {
+ // Resume parsing in continuation block unless it was already parsed.
+ // Note that if we don't change _last here, iteration in
+ // iterate_bytecodes_for_block will stop when we return.
+ if (!continuation()->is_set(BlockBegin::was_visited_flag)) {
+ // add continuation to work list instead of parsing it immediately
+ assert(_last && _last->as_BlockEnd(), "");
+ scope_data()->parent()->add_to_work_list(continuation());
+ _skip_block = true;
+ }
}
}
@@ -3645,6 +3656,114 @@
}
+bool GraphBuilder::for_method_handle_inline(ciMethod* callee) {
+ assert(!callee->is_static(), "change next line");
+ int index = state()->stack_size() - (callee->arg_size_no_receiver() + 1);
+ Value receiver = state()->stack_at(index);
+
+ if (receiver->type()->is_constant()) {
+ ciMethodHandle* method_handle = receiver->type()->as_ObjectType()->constant_value()->as_method_handle();
+
+ // Set the callee to have access to the class and signature in
+ // the MethodHandleCompiler.
+ method_handle->set_callee(callee);
+ method_handle->set_caller(method());
+
+ // Get an adapter for the MethodHandle.
+ ciMethod* method_handle_adapter = method_handle->get_method_handle_adapter();
+ if (method_handle_adapter != NULL) {
+ return try_inline(method_handle_adapter, /*holder_known=*/ true);
+ }
+ } else if (receiver->as_CheckCast()) {
+ // Match MethodHandle.selectAlternative idiom
+ Phi* phi = receiver->as_CheckCast()->obj()->as_Phi();
+
+ if (phi != NULL && phi->operand_count() == 2) {
+ // Get the two MethodHandle inputs from the Phi.
+ Value op1 = phi->operand_at(0);
+ Value op2 = phi->operand_at(1);
+ ciMethodHandle* mh1 = op1->type()->as_ObjectType()->constant_value()->as_method_handle();
+ ciMethodHandle* mh2 = op2->type()->as_ObjectType()->constant_value()->as_method_handle();
+
+ // Set the callee to have access to the class and signature in
+ // the MethodHandleCompiler.
+ mh1->set_callee(callee);
+ mh1->set_caller(method());
+ mh2->set_callee(callee);
+ mh2->set_caller(method());
+
+ // Get adapters for the MethodHandles.
+ ciMethod* mh1_adapter = mh1->get_method_handle_adapter();
+ ciMethod* mh2_adapter = mh2->get_method_handle_adapter();
+
+ if (mh1_adapter != NULL && mh2_adapter != NULL) {
+ set_inline_cleanup_info();
+
+ // Build the If guard
+ BlockBegin* one = new BlockBegin(next_bci());
+ BlockBegin* two = new BlockBegin(next_bci());
+ BlockBegin* end = new BlockBegin(next_bci());
+ Instruction* iff = append(new If(phi, If::eql, false, op1, one, two, NULL, false));
+ block()->set_end(iff->as_BlockEnd());
+
+ // Connect up the states
+ one->merge(block()->end()->state());
+ two->merge(block()->end()->state());
+
+ // Save the state for the second inlinee
+ ValueStack* state_before = copy_state_before();
+
+ // Parse first adapter
+ _last = _block = one;
+ if (!try_inline_full(mh1_adapter, /*holder_known=*/ true, end)) {
+ restore_inline_cleanup_info();
+ block()->clear_end(); // remove appended iff
+ return false;
+ }
+
+ // Parse second adapter
+ _last = _block = two;
+ _state = state_before;
+ if (!try_inline_full(mh2_adapter, /*holder_known=*/ true, end)) {
+ restore_inline_cleanup_info();
+ block()->clear_end(); // remove appended iff
+ return false;
+ }
+
+ connect_to_end(end);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+bool GraphBuilder::for_invokedynamic_inline(ciMethod* callee) {
+ // Get the MethodHandle from the CallSite.
+ ciCallSite* call_site = stream()->get_call_site();
+ ciMethodHandle* method_handle = call_site->get_target();
+
+ // Set the callee to have access to the class and signature in the
+ // MethodHandleCompiler.
+ method_handle->set_callee(callee);
+ method_handle->set_caller(method());
+
+ // Get an adapter for the MethodHandle.
+ ciMethod* method_handle_adapter = method_handle->get_invokedynamic_adapter();
+ if (method_handle_adapter != NULL) {
+ if (try_inline(method_handle_adapter, /*holder_known=*/ true)) {
+ // Add a dependence for invalidation of the optimization.
+ if (!call_site->is_constant_call_site()) {
+ dependency_recorder()->assert_call_site_target_value(call_site, method_handle);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+
void GraphBuilder::inline_bailout(const char* msg) {
assert(msg != NULL, "inline bailout msg must exist");
_inline_bailout_msg = msg;
diff -r 2fecca53a2c6 -r 5596e125fe4f src/share/vm/c1/c1_GraphBuilder.hpp
--- a/src/share/vm/c1/c1_GraphBuilder.hpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/share/vm/c1/c1_GraphBuilder.hpp Thu Sep 08 06:36:31 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -315,9 +315,17 @@
ValueStack* return_state) { scope_data()->set_inline_cleanup_info(block,
return_prev,
return_state); }
+ void set_inline_cleanup_info() {
+ set_inline_cleanup_info(_block, _last, _state);
+ }
BlockBegin* inline_cleanup_block() const { return scope_data()->inline_cleanup_block(); }
Instruction* inline_cleanup_return_prev() const { return scope_data()->inline_cleanup_return_prev(); }
ValueStack* inline_cleanup_state() const { return scope_data()->inline_cleanup_state(); }
+ void restore_inline_cleanup_info() {
+ _block = inline_cleanup_block();
+ _last = inline_cleanup_return_prev();
+ _state = inline_cleanup_state();
+ }
void incr_num_returns() { scope_data()->incr_num_returns(); }
int num_returns() const { return scope_data()->num_returns(); }
intx max_inline_size() const { return scope_data()->max_inline_size(); }
@@ -329,11 +337,15 @@
void fill_sync_handler(Value lock, BlockBegin* sync_handler, bool default_handler = false);
// inliners
- bool try_inline(ciMethod* callee, bool holder_known);
+ bool try_inline( ciMethod* callee, bool holder_known);
bool try_inline_intrinsics(ciMethod* callee);
- bool try_inline_full (ciMethod* callee, bool holder_known);
+ bool try_inline_full( ciMethod* callee, bool holder_known, BlockBegin* cont_block = NULL);
bool try_inline_jsr(int jsr_dest_bci);
+ // JSR 292 support
+ bool for_method_handle_inline(ciMethod* callee);
+ bool for_invokedynamic_inline(ciMethod* callee);
+
// helpers
void inline_bailout(const char* msg);
BlockBegin* header_block(BlockBegin* entry, BlockBegin::Flag f, ValueStack* state);
diff -r 2fecca53a2c6 -r 5596e125fe4f src/share/vm/c1/c1_Instruction.cpp
--- a/src/share/vm/c1/c1_Instruction.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/share/vm/c1/c1_Instruction.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -514,28 +514,17 @@
void BlockBegin::set_end(BlockEnd* end) {
assert(end != NULL, "should not reset block end to NULL");
- BlockEnd* old_end = _end;
- if (end == old_end) {
+ if (end == _end) {
return;
}
- // Must make the predecessors/successors match up with the
- // BlockEnd's notion.
- int i, n;
- if (old_end != NULL) {
- // disconnect from the old end
- old_end->set_begin(NULL);
+ clear_end();
- // disconnect this block from it's current successors
- for (i = 0; i < _successors.length(); i++) {
- _successors.at(i)->remove_predecessor(this);
- }
- }
+ // Set the new end
_end = end;
_successors.clear();
// Now reset successors list based on BlockEnd
- n = end->number_of_sux();
- for (i = 0; i < n; i++) {
+ for (int i = 0; i < end->number_of_sux(); i++) {
BlockBegin* sux = end->sux_at(i);
_successors.append(sux);
sux->_predecessors.append(this);
@@ -544,6 +533,22 @@
}
+void BlockBegin::clear_end() {
+ // Must make the predecessors/successors match up with the
+ // BlockEnd's notion.
+ if (_end != NULL) {
+ // disconnect from the old end
+ _end->set_begin(NULL);
+
+ // disconnect this block from it's current successors
+ for (int i = 0; i < _successors.length(); i++) {
+ _successors.at(i)->remove_predecessor(this);
+ }
+ _end = NULL;
+ }
+}
+
+
void BlockBegin::disconnect_edge(BlockBegin* from, BlockBegin* to) {
// disconnect any edges between from and to
#ifndef PRODUCT
diff -r 2fecca53a2c6 -r 5596e125fe4f src/share/vm/c1/c1_Instruction.hpp
--- a/src/share/vm/c1/c1_Instruction.hpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/share/vm/c1/c1_Instruction.hpp Thu Sep 08 06:36:31 2011 -0700
@@ -1601,6 +1601,7 @@
void set_depth_first_number(int dfn) { _depth_first_number = dfn; }
void set_linear_scan_number(int lsn) { _linear_scan_number = lsn; }
void set_end(BlockEnd* end);
+ void clear_end();
void disconnect_from_graph();
static void disconnect_edge(BlockBegin* from, BlockBegin* to);
BlockBegin* insert_block_between(BlockBegin* sux);
diff -r 2fecca53a2c6 -r 5596e125fe4f src/share/vm/c1/c1_LIRAssembler.cpp
--- a/src/share/vm/c1/c1_LIRAssembler.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/share/vm/c1/c1_LIRAssembler.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -121,7 +121,7 @@
void LIR_Assembler::check_codespace() {
CodeSection* cs = _masm->code_section();
- if (cs->remaining() < (int)(1*K)) {
+ if (cs->remaining() < (int)(NOT_LP64(1*K)LP64_ONLY(2*K))) {
BAILOUT("CodeBuffer overflow");
}
}
diff -r 2fecca53a2c6 -r 5596e125fe4f src/share/vm/c1/c1_LIRAssembler.hpp
--- a/src/share/vm/c1/c1_LIRAssembler.hpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/share/vm/c1/c1_LIRAssembler.hpp Thu Sep 08 06:36:31 2011 -0700
@@ -133,7 +133,6 @@
static bool is_small_constant(LIR_Opr opr);
static LIR_Opr receiverOpr();
- static LIR_Opr incomingReceiverOpr();
static LIR_Opr osrBufferPointer();
// stubs
diff -r 2fecca53a2c6 -r 5596e125fe4f src/share/vm/c1/c1_LinearScan.cpp
--- a/src/share/vm/c1/c1_LinearScan.cpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/share/vm/c1/c1_LinearScan.cpp Thu Sep 08 06:36:31 2011 -0700
@@ -2404,7 +2404,7 @@
assert(!is_call_site || assigned_reg >= nof_regs || !is_caller_save(assigned_reg), "interval is in a caller-save register at a call -> register will be overwritten");
VMReg name = vm_reg_for_interval(interval);
- map->set_oop(name);
+ set_oop(map, name);
// Spill optimization: when the stack value is guaranteed to be always correct,
// then it must be added to the oop map even if the interval is currently in a register
@@ -2415,7 +2415,7 @@
assert(interval->canonical_spill_slot() >= LinearScan::nof_regs, "no spill slot assigned");
assert(interval->assigned_reg() < LinearScan::nof_regs, "interval is on stack, so stack slot is registered twice");
- map->set_oop(frame_map()->slot_regname(interval->canonical_spill_slot() - LinearScan::nof_regs));
+ set_oop(map, frame_map()->slot_regname(interval->canonical_spill_slot() - LinearScan::nof_regs));
}
}
}
@@ -2424,7 +2424,7 @@
assert(info->stack() != NULL, "CodeEmitInfo must always have a stack");
int locks_count = info->stack()->total_locks_size();
for (int i = 0; i < locks_count; i++) {
- map->set_oop(frame_map()->monitor_object_regname(i));
+ set_oop(map, frame_map()->monitor_object_regname(i));
}
return map;
diff -r 2fecca53a2c6 -r 5596e125fe4f src/share/vm/c1/c1_LinearScan.hpp
--- a/src/share/vm/c1/c1_LinearScan.hpp Wed Sep 07 14:15:07 2011 +0200
+++ b/src/share/vm/c1/c1_LinearScan.hpp Thu Sep 08 06:36:31 2011 -0700
@@ -352,6 +352,13 @@
MonitorValue* location_for_monitor_index(int monitor_index);
LocationValue* location_for_name(int name, Location::Type loc_type);
+ void set_oop(OopMap* map, VMReg name) {
+ if (map->legal_vm_reg_name(name)) {
+ map->set_oop(name);
+ } else {
+ bailout("illegal oopMap register name");
+ }
+ }
int append_scope_value_for_constant(LIR_Opr opr, GrowableArray