# HG changeset patch # User stefank # Date 1315572283 -7200 # Node ID e984655be42595224d940d7983b3fd18233e49a1 # Parent 5596e125fe4f958f05e3f20b89a0e685f0ba201d# Parent 3bddbf0f57d613263953b9908655c0617022af60 Merge diff -r 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/HSDB.java --- a/agent/src/share/classes/sun/jvm/hotspot/HSDB.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/HSDB.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/CodeBlob.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 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 Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/PCDesc.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/RicochetBlob.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/code/RuntimeStub.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/RuntimeStub.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/RuntimeStub.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapSet.java --- a/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapSet.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapSet.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java --- a/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java --- a/agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/jdi/ReferenceTypeImpl.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/jdi/StackFrameImpl.java --- a/agent/src/share/classes/sun/jvm/hotspot/jdi/StackFrameImpl.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/jdi/StackFrameImpl.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/SystemDictionary.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaVFrame.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/runtime/StackValue.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/StackValue.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/StackValue.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64CurrentFrameGuess.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64Frame.java Fri Sep 09 05:20:58 2011 -0400 +++ /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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64RegisterMap.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/amd64/AMD64RegisterMap.java Fri Sep 09 05:20:58 2011 -0400 +++ /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 3bddbf0f57d6 -r e984655be425 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 Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_amd64/LinuxAMD64JavaThreadPDAccess.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 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 Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/sparc/SPARCFrame.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 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 Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 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 Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/win32_amd64/Win32AMD64JavaThreadPDAccess.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java Fri Sep 09 05:20:58 2011 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/x86/X86Frame.java Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 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 Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 make/linux/makefiles/mapfile-vers-debug --- a/make/linux/makefiles/mapfile-vers-debug Fri Sep 09 05:20:58 2011 -0400 +++ b/make/linux/makefiles/mapfile-vers-debug Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 make/linux/makefiles/mapfile-vers-product --- a/make/linux/makefiles/mapfile-vers-product Fri Sep 09 05:20:58 2011 -0400 +++ b/make/linux/makefiles/mapfile-vers-product Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 make/solaris/makefiles/debug.make --- a/make/solaris/makefiles/debug.make Fri Sep 09 05:20:58 2011 -0400 +++ b/make/solaris/makefiles/debug.make Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 make/solaris/makefiles/fastdebug.make --- a/make/solaris/makefiles/fastdebug.make Fri Sep 09 05:20:58 2011 -0400 +++ b/make/solaris/makefiles/fastdebug.make Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 make/solaris/makefiles/jvmg.make --- a/make/solaris/makefiles/jvmg.make Fri Sep 09 05:20:58 2011 -0400 +++ b/make/solaris/makefiles/jvmg.make Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 make/solaris/makefiles/mapfile-vers-nonproduct --- a/make/solaris/makefiles/mapfile-vers-nonproduct Fri Sep 09 05:20:58 2011 -0400 +++ /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 3bddbf0f57d6 -r e984655be425 make/solaris/makefiles/optimized.make --- a/make/solaris/makefiles/optimized.make Fri Sep 09 05:20:58 2011 -0400 +++ b/make/solaris/makefiles/optimized.make Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 make/solaris/makefiles/product.make --- a/make/solaris/makefiles/product.make Fri Sep 09 05:20:58 2011 -0400 +++ b/make/solaris/makefiles/product.make Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/assembler_sparc.cpp --- a/src/cpu/sparc/vm/assembler_sparc.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/assembler_sparc.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/assembler_sparc.hpp --- a/src/cpu/sparc/vm/assembler_sparc.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/assembler_sparc.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/c1_Runtime1_sparc.cpp --- a/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/copy_sparc.hpp --- a/src/cpu/sparc/vm/copy_sparc.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/copy_sparc.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/frame_sparc.hpp --- a/src/cpu/sparc/vm/frame_sparc.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/frame_sparc.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/sparc.ad Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/stubGenerator_sparc.cpp --- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/templateTable_sparc.cpp --- a/src/cpu/sparc/vm/templateTable_sparc.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/templateTable_sparc.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/vm_version_sparc.cpp --- a/src/cpu/sparc/vm/vm_version_sparc.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/vm_version_sparc.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/sparc/vm/vm_version_sparc.hpp --- a/src/cpu/sparc/vm/vm_version_sparc.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/sparc/vm/vm_version_sparc.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/x86/vm/c1_LIRAssembler_x86.hpp --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/x86/vm/c1_Runtime1_x86.cpp --- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/cpu/x86/vm/methodHandles_x86.hpp --- a/src/cpu/x86/vm/methodHandles_x86.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/cpu/x86/vm/methodHandles_x86.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_Compilation.cpp --- a/src/share/vm/c1/c1_Compilation.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_Compilation.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -346,7 +346,6 @@ implicit_exception_table(), compiler(), _env->comp_level(), - true, has_unsafe_access() ); } diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_GraphBuilder.hpp --- a/src/share/vm/c1/c1_GraphBuilder.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_GraphBuilder.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_Instruction.cpp --- a/src/share/vm/c1/c1_Instruction.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_Instruction.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_Instruction.hpp --- a/src/share/vm/c1/c1_Instruction.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_Instruction.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_LIRAssembler.cpp --- a/src/share/vm/c1/c1_LIRAssembler.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_LIRAssembler.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_LIRAssembler.hpp --- a/src/share/vm/c1/c1_LIRAssembler.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_LIRAssembler.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_LinearScan.cpp --- a/src/share/vm/c1/c1_LinearScan.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_LinearScan.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -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 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_LinearScan.hpp --- a/src/share/vm/c1/c1_LinearScan.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_LinearScan.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -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* scope_values); int append_scope_value_for_operand(LIR_Opr opr, GrowableArray* scope_values); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_Runtime1.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -375,14 +375,6 @@ JRT_END -JRT_ENTRY(void, Runtime1::post_jvmti_exception_throw(JavaThread* thread)) - if (JvmtiExport::can_post_on_exceptions()) { - vframeStream vfst(thread, true); - address bcp = vfst.method()->bcp_from(vfst.bci()); - JvmtiExport::post_exception_throw(thread, vfst.method(), bcp, thread->exception_oop()); - } -JRT_END - // counter_overflow() is called from within C1-compiled methods. The enclosing method is the method // associated with the top activation record. The inlinee (that is possibly included in the enclosing // method) method oop is passed as an argument. In order to do that it is embedded in the code as diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_Runtime1.hpp --- a/src/share/vm/c1/c1_Runtime1.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_Runtime1.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -65,7 +65,6 @@ stub(monitorexit_nofpu) /* optimized version that does not preserve fpu registers */ \ stub(access_field_patching) \ stub(load_klass_patching) \ - stub(jvmti_exception_throw) \ stub(g1_pre_barrier_slow) \ stub(g1_post_barrier_slow) \ stub(fpu2long_stub) \ @@ -141,7 +140,6 @@ static void unimplemented_entry (JavaThread* thread, StubID id); static address exception_handler_for_pc(JavaThread* thread); - static void post_jvmti_exception_throw(JavaThread* thread); static void throw_range_check_exception(JavaThread* thread, int index); static void throw_index_exception(JavaThread* thread, int index); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/c1/c1_globals.hpp --- a/src/share/vm/c1/c1_globals.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/c1/c1_globals.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -278,7 +278,7 @@ product(intx, CompilationRepeat, 0, \ "Number of times to recompile method before returning result") \ \ - develop(intx, NMethodSizeLimit, (32*K)*wordSize, \ + develop(intx, NMethodSizeLimit, (64*K)*wordSize, \ "Maximum size of a compiled method.") \ \ develop(bool, TraceFPUStack, false, \ diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/ci/ciCallProfile.hpp --- a/src/share/vm/ci/ciCallProfile.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/ci/ciCallProfile.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -79,6 +79,17 @@ assert(i < _limit, "out of Call Profile MorphismLimit"); return _receiver[i]; } + + // Rescale the current profile based on the incoming scale + ciCallProfile rescale(double scale) { + assert(scale >= 0 && scale <= 1.0, "out of range"); + ciCallProfile call = *this; + call._count = (int)(call._count * scale); + for (int i = 0; i < _morphism; i++) { + call._receiver_count[i] = (int)(call._receiver_count[i] * scale); + } + return call; + } }; #endif // SHARE_VM_CI_CICALLPROFILE_HPP diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/ci/ciConstant.hpp --- a/src/share/vm/ci/ciConstant.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/ci/ciConstant.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -46,9 +46,6 @@ ciObject* _object; } _value; - // Implementation of the print method. - void print_impl(outputStream* st); - public: ciConstant() { diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/ci/ciEnv.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -884,19 +884,31 @@ } // ------------------------------------------------------------------ -// ciEnv::check_for_system_dictionary_modification -// Check for changes to the system dictionary during compilation -// class loads, evolution, breakpoints -void ciEnv::check_for_system_dictionary_modification(ciMethod* target) { +// ciEnv::validate_compile_task_dependencies +// +// Check for changes during compilation (e.g. class loads, evolution, +// breakpoints, call site invalidation). +void ciEnv::validate_compile_task_dependencies(ciMethod* target) { if (failing()) return; // no need for further checks - // Dependencies must be checked when the system dictionary changes. - // If logging is enabled all violated dependences will be recorded in - // the log. In debug mode check dependencies even if the system - // dictionary hasn't changed to verify that no invalid dependencies - // were inserted. Any violated dependences in this case are dumped to - // the tty. + // First, check non-klass dependencies as we might return early and + // not check klass dependencies if the system dictionary + // modification counter hasn't changed (see below). + for (Dependencies::DepStream deps(dependencies()); deps.next(); ) { + if (deps.is_klass_type()) continue; // skip klass dependencies + klassOop witness = deps.check_dependency(); + if (witness != NULL) { + record_failure("invalid non-klass dependency"); + return; + } + } + // Klass dependencies must be checked when the system dictionary + // changes. If logging is enabled all violated dependences will be + // recorded in the log. In debug mode check dependencies even if + // the system dictionary hasn't changed to verify that no invalid + // dependencies were inserted. Any violated dependences in this + // case are dumped to the tty. bool counter_changed = system_dictionary_modification_counter_changed(); bool test_deps = counter_changed; DEBUG_ONLY(test_deps = true); @@ -904,22 +916,21 @@ bool print_failures = false; DEBUG_ONLY(print_failures = !counter_changed); - bool keep_going = (print_failures || xtty != NULL); - - int violated = 0; + int klass_violations = 0; for (Dependencies::DepStream deps(dependencies()); deps.next(); ) { + if (!deps.is_klass_type()) continue; // skip non-klass dependencies klassOop witness = deps.check_dependency(); if (witness != NULL) { - ++violated; + klass_violations++; if (print_failures) deps.print_dependency(witness, /*verbose=*/ true); - // If there's no log and we're not sanity-checking, we're done. - if (!keep_going) break; } + // If there's no log and we're not sanity-checking, we're done. + if (!keep_going) break; } - if (violated != 0) { + if (klass_violations != 0) { assert(counter_changed, "failed dependencies, but counter didn't change"); record_failure("concurrent class loading"); } @@ -938,7 +949,6 @@ ImplicitExceptionTable* inc_table, AbstractCompiler* compiler, int comp_level, - bool has_debug_info, bool has_unsafe_access) { VM_ENTRY_MARK; nmethod* nm = NULL; @@ -978,8 +988,8 @@ // Encode the dependencies now, so we can check them right away. dependencies()->encode_content_bytes(); - // Check for {class loads, evolution, breakpoints} during compilation - check_for_system_dictionary_modification(target); + // Check for {class loads, evolution, breakpoints, ...} during compilation + validate_compile_task_dependencies(target); } methodHandle method(THREAD, target->get_methodOop()); @@ -1033,7 +1043,6 @@ CompileBroker::handle_full_code_cache(); } } else { - NOT_PRODUCT(nm->set_has_debug_info(has_debug_info); ) nm->set_has_unsafe_access(has_unsafe_access); // Record successful registration. diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/ci/ciEnv.hpp --- a/src/share/vm/ci/ciEnv.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/ci/ciEnv.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -247,9 +247,9 @@ // Is this thread currently in the VM state? static bool is_in_vm(); - // Helper routine for determining the validity of a compilation - // with respect to concurrent class loading. - void check_for_system_dictionary_modification(ciMethod* target); + // Helper routine for determining the validity of a compilation with + // respect to method dependencies (e.g. concurrent class loading). + void validate_compile_task_dependencies(ciMethod* target); public: enum { @@ -317,8 +317,7 @@ ImplicitExceptionTable* inc_table, AbstractCompiler* compiler, int comp_level, - bool has_debug_info = true, - bool has_unsafe_access = false); + bool has_unsafe_access); // Access to certain well known ciObjects. diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/ci/ciField.hpp --- a/src/share/vm/ci/ciField.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/ci/ciField.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -64,9 +64,6 @@ // shared constructor code void initialize_from(fieldDescriptor* fd); - // The implementation of the print method. - void print_impl(outputStream* st); - public: ciFlags flags() { return _flags; } @@ -178,7 +175,12 @@ bool is_volatile () { return flags().is_volatile(); } bool is_transient () { return flags().is_transient(); } - bool is_call_site_target() { return ((holder() == CURRENT_ENV->CallSite_klass()) && (name() == ciSymbol::target_name())); } + bool is_call_site_target() { + ciInstanceKlass* callsite_klass = CURRENT_ENV->CallSite_klass(); + if (callsite_klass == NULL) + return false; + return (holder()->is_subclass_of(callsite_klass) && (name() == ciSymbol::target_name())); + } // Debugging output void print(); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/ci/ciMethod.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -1017,6 +1017,34 @@ } // ------------------------------------------------------------------ +// ciMethod::code_size_for_inlining +// +// Code size for inlining decisions. +// +// Don't fully count method handle adapters against inlining budgets: +// the metric we use here is the number of call sites in the adapter +// as they are probably the instructions which generate some code. +int ciMethod::code_size_for_inlining() { + check_is_loaded(); + + // Method handle adapters + if (is_method_handle_adapter()) { + // Count call sites + int call_site_count = 0; + ciBytecodeStream iter(this); + while (iter.next() != ciBytecodeStream::EOBC()) { + if (Bytecodes::is_invoke(iter.cur_bc())) { + call_site_count++; + } + } + return call_site_count; + } + + // Normal method + return code_size(); +} + +// ------------------------------------------------------------------ // ciMethod::instructions_size // // This is a rough metric for "fat" methods, compared before inlining diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/ci/ciMethod.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -157,6 +157,9 @@ int interpreter_invocation_count() const { check_is_loaded(); return _interpreter_invocation_count; } int interpreter_throwout_count() const { check_is_loaded(); return _interpreter_throwout_count; } + // Code size for inlining decisions. + int code_size_for_inlining(); + int comp_level(); int highest_osr_comp_level(); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/ci/ciMethodHandle.cpp --- a/src/share/vm/ci/ciMethodHandle.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/ci/ciMethodHandle.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -37,7 +37,7 @@ // ciMethodHandle::get_adapter // // Return an adapter for this MethodHandle. -ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) const { +ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) { VM_ENTRY_MARK; Handle h(get_oop()); methodHandle callee(_callee->get_methodOop()); @@ -73,7 +73,7 @@ // ciMethodHandle::get_adapter // // Return an adapter for this MethodHandle. -ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const { +ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) { ciMethod* result = get_adapter_impl(is_invokedynamic); if (result) { // Fake up the MDO maturity. @@ -86,11 +86,22 @@ } +#ifndef PRODUCT // ------------------------------------------------------------------ -// ciMethodHandle::print_impl +// ciMethodHandle::print_chain_impl // // Implementation of the print method. -void ciMethodHandle::print_impl(outputStream* st) { - st->print(" type="); - get_oop()->print(); +void ciMethodHandle::print_chain_impl(outputStream* st) { + ASSERT_IN_VM; + MethodHandleChain::print(get_oop()); } + + +// ------------------------------------------------------------------ +// ciMethodHandle::print_chain +// +// Implementation of the print_chain method. +void ciMethodHandle::print_chain(outputStream* st) { + GUARDED_VM_ENTRY(print_chain_impl(st);); +} +#endif diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/ci/ciMethodHandle.hpp --- a/src/share/vm/ci/ciMethodHandle.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/ci/ciMethodHandle.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -37,19 +37,23 @@ ciMethod* _callee; ciMethod* _caller; ciCallProfile _profile; + ciMethod* _method_handle_adapter; + ciMethod* _invokedynamic_adapter; // Return an adapter for this MethodHandle. - ciMethod* get_adapter_impl(bool is_invokedynamic) const; - ciMethod* get_adapter( bool is_invokedynamic) const; + ciMethod* get_adapter_impl(bool is_invokedynamic); + ciMethod* get_adapter( bool is_invokedynamic); protected: - void print_impl(outputStream* st); + void print_chain_impl(outputStream* st) PRODUCT_RETURN; public: ciMethodHandle(instanceHandle h_i) : ciInstance(h_i), _callee(NULL), - _caller(NULL) + _caller(NULL), + _method_handle_adapter(NULL), + _invokedynamic_adapter(NULL) {} // What kind of ciObject is this? @@ -60,10 +64,22 @@ void set_call_profile(ciCallProfile profile) { _profile = profile; } // Return an adapter for a MethodHandle call. - ciMethod* get_method_handle_adapter() const { return get_adapter(false); } + ciMethod* get_method_handle_adapter() { + if (_method_handle_adapter == NULL) { + _method_handle_adapter = get_adapter(false); + } + return _method_handle_adapter; + } // Return an adapter for an invokedynamic call. - ciMethod* get_invokedynamic_adapter() const { return get_adapter(true); } + ciMethod* get_invokedynamic_adapter() { + if (_invokedynamic_adapter == NULL) { + _invokedynamic_adapter = get_adapter(true); + } + return _invokedynamic_adapter; + } + + void print_chain(outputStream* st = tty) PRODUCT_RETURN; }; #endif // SHARE_VM_CI_CIMETHODHANDLE_HPP diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/ci/ciObject.cpp --- a/src/share/vm/ci/ciObject.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/ci/ciObject.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -194,16 +194,26 @@ // ciObject::should_be_constant() bool ciObject::should_be_constant() { if (ScavengeRootsInCode >= 2) return true; // force everybody to be a constant - if (!JavaObjectsInPerm && !is_null_object()) { + if (is_null_object()) return true; + + ciEnv* env = CURRENT_ENV; + if (!JavaObjectsInPerm) { // We want Strings and Classes to be embeddable by default since // they used to be in the perm world. Not all Strings used to be // embeddable but there's no easy way to distinguish the interned // from the regulars ones so just treat them all that way. - ciEnv* env = CURRENT_ENV; if (klass() == env->String_klass() || klass() == env->Class_klass()) { return true; } } + if (EnableInvokeDynamic && + (klass()->is_subclass_of(env->MethodHandle_klass()) || + klass()->is_subclass_of(env->CallSite_klass()))) { + assert(ScavengeRootsInCode >= 1, "must be"); + // We want to treat these aggressively. + return true; + } + return handle() == NULL || is_perm(); } diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/ci/ciStreams.hpp --- a/src/share/vm/ci/ciStreams.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/ci/ciStreams.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -129,7 +129,8 @@ // Return current ByteCode and increment PC to next bytecode, skipping all // intermediate constants. Returns EOBC at end. // Expected usage: - // while( (bc = iter.next()) != EOBC() ) { ... } + // ciBytecodeStream iter(m); + // while (iter.next() != ciBytecodeStream::EOBC()) { ... } Bytecodes::Code next() { _bc_start = _pc; // Capture start of bc if( _pc >= _end ) return EOBC(); // End-Of-Bytecodes diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/classfile/javaClasses.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -28,6 +28,7 @@ #include "classfile/vmSymbols.hpp" #include "code/debugInfo.hpp" #include "code/pcDesc.hpp" +#include "compiler/compilerOracle.hpp" #include "interpreter/interpreter.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" @@ -2323,6 +2324,8 @@ int java_lang_invoke_AdapterMethodHandle::_conversion_offset; +int java_lang_invoke_CountingMethodHandle::_vmcount_offset; + void java_lang_invoke_MethodHandle::compute_offsets() { klassOop k = SystemDictionary::MethodHandle_klass(); if (k != NULL && EnableInvokeDynamic) { @@ -2371,6 +2374,23 @@ } } +void java_lang_invoke_CountingMethodHandle::compute_offsets() { + klassOop k = SystemDictionary::CountingMethodHandle_klass(); + if (k != NULL && EnableInvokeDynamic) { + compute_offset(_vmcount_offset, k, vmSymbols::vmcount_name(), vmSymbols::int_signature(), true); + } +} + +int java_lang_invoke_CountingMethodHandle::vmcount(oop mh) { + assert(is_instance(mh), "CMH only"); + return mh->int_field(_vmcount_offset); +} + +void java_lang_invoke_CountingMethodHandle::set_vmcount(oop mh, int count) { + assert(is_instance(mh), "CMH only"); + mh->int_field_put(_vmcount_offset, count); +} + oop java_lang_invoke_MethodHandle::type(oop mh) { return mh->obj_field(_type_offset); } @@ -2674,6 +2694,17 @@ if (k != NULL) { compute_offset(_target_offset, k, vmSymbols::target_name(), vmSymbols::java_lang_invoke_MethodHandle_signature()); } + + // Disallow compilation of CallSite.setTargetNormal and CallSite.setTargetVolatile + // (For C2: keep this until we have throttling logic for uncommon traps.) + if (k != NULL) { + instanceKlass* ik = instanceKlass::cast(k); + methodOop m_normal = ik->lookup_method(vmSymbols::setTargetNormal_name(), vmSymbols::setTarget_signature()); + methodOop m_volatile = ik->lookup_method(vmSymbols::setTargetVolatile_name(), vmSymbols::setTarget_signature()); + guarantee(m_normal && m_volatile, "must exist"); + m_normal->set_not_compilable_quietly(); + m_volatile->set_not_compilable_quietly(); + } } oop java_lang_invoke_CallSite::target(oop site) { @@ -3031,6 +3062,7 @@ java_lang_invoke_MethodType::compute_offsets(); java_lang_invoke_MethodTypeForm::compute_offsets(); java_lang_invoke_CallSite::compute_offsets(); + java_lang_invoke_CountingMethodHandle::compute_offsets(); } java_security_AccessControlContext::compute_offsets(); // Initialize reflection classes. The layouts of these classes diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/classfile/javaClasses.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -981,6 +981,34 @@ }; +// A simple class that maintains an invocation count +class java_lang_invoke_CountingMethodHandle: public java_lang_invoke_MethodHandle { + friend class JavaClasses; + + private: + static int _vmcount_offset; + static void compute_offsets(); + + public: + // Accessors + static int vmcount(oop mh); + static void set_vmcount(oop mh, int count); + + // Testers + static bool is_subclass(klassOop klass) { + return SystemDictionary::CountingMethodHandle_klass() != NULL && + Klass::cast(klass)->is_subclass_of(SystemDictionary::CountingMethodHandle_klass()); + } + static bool is_instance(oop obj) { + return obj != NULL && is_subclass(obj->klass()); + } + + // Accessors for code generation: + static int vmcount_offset_in_bytes() { return _vmcount_offset; } +}; + + + // Interface to java.lang.invoke.MemberName objects // (These are a private interface for Java code to query the class hierarchy.) diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/classfile/systemDictionary.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -133,14 +133,14 @@ template(reflect_Method_klass, java_lang_reflect_Method, Pre) \ template(reflect_Constructor_klass, java_lang_reflect_Constructor, Pre) \ \ - /* NOTE: needed too early in bootstrapping process to have checks based on JDK version */ \ - /* Universe::is_gte_jdk14x_version() is not set up by this point. */ \ - /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ - template(reflect_MagicAccessorImpl_klass, sun_reflect_MagicAccessorImpl, Opt) \ - template(reflect_MethodAccessorImpl_klass, sun_reflect_MethodAccessorImpl, Opt_Only_JDK14NewRef) \ - template(reflect_ConstructorAccessorImpl_klass, sun_reflect_ConstructorAccessorImpl, Opt_Only_JDK14NewRef) \ - template(reflect_DelegatingClassLoader_klass, sun_reflect_DelegatingClassLoader, Opt) \ - template(reflect_ConstantPool_klass, sun_reflect_ConstantPool, Opt_Only_JDK15) \ + /* NOTE: needed too early in bootstrapping process to have checks based on JDK version */ \ + /* Universe::is_gte_jdk14x_version() is not set up by this point. */ \ + /* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \ + template(reflect_MagicAccessorImpl_klass, sun_reflect_MagicAccessorImpl, Opt) \ + template(reflect_MethodAccessorImpl_klass, sun_reflect_MethodAccessorImpl, Opt_Only_JDK14NewRef) \ + template(reflect_ConstructorAccessorImpl_klass, sun_reflect_ConstructorAccessorImpl, Opt_Only_JDK14NewRef) \ + template(reflect_DelegatingClassLoader_klass, sun_reflect_DelegatingClassLoader, Opt) \ + template(reflect_ConstantPool_klass, sun_reflect_ConstantPool, Opt_Only_JDK15) \ template(reflect_UnsafeStaticFieldAccessorImpl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15) \ \ /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \ @@ -155,6 +155,7 @@ template(BootstrapMethodError_klass, java_lang_BootstrapMethodError, Pre_JSR292) \ template(WrongMethodTypeException_klass, java_lang_invoke_WrongMethodTypeException, Pre_JSR292) \ template(CallSite_klass, java_lang_invoke_CallSite, Pre_JSR292) \ + template(CountingMethodHandle_klass, java_lang_invoke_CountingMethodHandle, Opt) \ template(ConstantCallSite_klass, java_lang_invoke_ConstantCallSite, Pre_JSR292) \ template(MutableCallSite_klass, java_lang_invoke_MutableCallSite, Pre_JSR292) \ template(VolatileCallSite_klass, java_lang_invoke_VolatileCallSite, Pre_JSR292) \ diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -218,6 +218,7 @@ template(returnType_name, "returnType") \ template(signature_name, "signature") \ template(slot_name, "slot") \ + template(selectAlternative_name, "selectAlternative") \ \ /* Support for annotations (JDK 1.5 and above) */ \ \ @@ -246,9 +247,11 @@ template(java_lang_invoke_MethodTypeForm_signature, "Ljava/lang/invoke/MethodTypeForm;") \ template(java_lang_invoke_MemberName, "java/lang/invoke/MemberName") \ template(java_lang_invoke_MethodHandleNatives, "java/lang/invoke/MethodHandleNatives") \ + template(java_lang_invoke_MethodHandleImpl, "java/lang/invoke/MethodHandleImpl") \ template(java_lang_invoke_AdapterMethodHandle, "java/lang/invoke/AdapterMethodHandle") \ template(java_lang_invoke_BoundMethodHandle, "java/lang/invoke/BoundMethodHandle") \ template(java_lang_invoke_DirectMethodHandle, "java/lang/invoke/DirectMethodHandle") \ + template(java_lang_invoke_CountingMethodHandle, "java/lang/invoke/CountingMethodHandle") \ /* internal up-calls made only by the JVM, via class sun.invoke.MethodHandleNatives: */ \ template(findMethodHandleType_name, "findMethodHandleType") \ template(findMethodHandleType_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/invoke/MethodType;") \ @@ -258,8 +261,12 @@ template(linkMethodHandleConstant_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;") \ template(makeDynamicCallSite_name, "makeDynamicCallSite") \ template(makeDynamicCallSite_signature, "(Ljava/lang/invoke/MethodHandle;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/Object;Ljava/lang/invoke/MemberName;I)Ljava/lang/invoke/CallSite;") \ + template(setTargetNormal_name, "setTargetNormal") \ + template(setTargetVolatile_name, "setTargetVolatile") \ + template(setTarget_signature, "(Ljava/lang/invoke/MethodHandle;)V") \ NOT_LP64( do_alias(machine_word_signature, int_signature) ) \ LP64_ONLY( do_alias(machine_word_signature, long_signature) ) \ + template(selectAlternative_signature, "(ZLjava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/MethodHandle;") \ \ /* common method and field names */ \ template(object_initializer_name, "") \ @@ -344,6 +351,7 @@ template(vmmethod_name, "vmmethod") \ template(vmtarget_name, "vmtarget") \ template(vmentry_name, "vmentry") \ + template(vmcount_name, "vmcount") \ template(vmslots_name, "vmslots") \ template(vmlayout_name, "vmlayout") \ template(vmindex_name, "vmindex") \ @@ -907,6 +915,8 @@ do_intrinsic(_invokeVarargs, java_lang_invoke_MethodHandle, invokeVarargs_name, object_array_object_signature, F_R) \ do_intrinsic(_invokeDynamic, java_lang_invoke_InvokeDynamic, star_name, object_array_object_signature, F_SN) \ \ + do_intrinsic(_selectAlternative, java_lang_invoke_MethodHandleImpl, selectAlternative_name, selectAlternative_signature, F_S) \ + \ /* unboxing methods: */ \ do_intrinsic(_booleanValue, java_lang_Boolean, booleanValue_name, void_boolean_signature, F_R) \ do_name( booleanValue_name, "booleanValue") \ diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/code/dependencies.cpp --- a/src/share/vm/code/dependencies.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/code/dependencies.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -113,9 +113,9 @@ assert_common_1(no_finalizable_subclasses, ctxk); } -void Dependencies::assert_call_site_target_value(ciKlass* ctxk, ciCallSite* call_site, ciMethodHandle* method_handle) { - check_ctxk(ctxk); - assert_common_3(call_site_target_value, ctxk, call_site, method_handle); +void Dependencies::assert_call_site_target_value(ciCallSite* call_site, ciMethodHandle* method_handle) { + check_ctxk(call_site->klass()); + assert_common_2(call_site_target_value, call_site, method_handle); } // Helper function. If we are adding a new dep. under ctxk2, @@ -135,7 +135,7 @@ } } -void Dependencies::assert_common_1(Dependencies::DepType dept, ciObject* x) { +void Dependencies::assert_common_1(DepType dept, ciObject* x) { assert(dep_args(dept) == 1, "sanity"); log_dependency(dept, x); GrowableArray* deps = _deps[dept]; @@ -148,21 +148,37 @@ } } -void Dependencies::assert_common_2(Dependencies::DepType dept, - ciKlass* ctxk, ciObject* x) { - assert(dep_context_arg(dept) == 0, "sanity"); +void Dependencies::assert_common_2(DepType dept, + ciObject* x0, ciObject* x1) { assert(dep_args(dept) == 2, "sanity"); - log_dependency(dept, ctxk, x); + log_dependency(dept, x0, x1); GrowableArray* deps = _deps[dept]; // see if the same (or a similar) dep is already recorded - if (note_dep_seen(dept, x)) { - // look in this bucket for redundant assertions - const int stride = 2; - for (int i = deps->length(); (i -= stride) >= 0; ) { - ciObject* x1 = deps->at(i+1); - if (x == x1) { // same subject; check the context - if (maybe_merge_ctxk(deps, i+0, ctxk)) { + bool has_ctxk = has_explicit_context_arg(dept); + if (has_ctxk) { + assert(dep_context_arg(dept) == 0, "sanity"); + if (note_dep_seen(dept, x1)) { + // look in this bucket for redundant assertions + const int stride = 2; + for (int i = deps->length(); (i -= stride) >= 0; ) { + ciObject* y1 = deps->at(i+1); + if (x1 == y1) { // same subject; check the context + if (maybe_merge_ctxk(deps, i+0, x0->as_klass())) { + return; + } + } + } + } + } else { + assert(dep_implicit_context_arg(dept) == 0, "sanity"); + if (note_dep_seen(dept, x0) && note_dep_seen(dept, x1)) { + // look in this bucket for redundant assertions + const int stride = 2; + for (int i = deps->length(); (i -= stride) >= 0; ) { + ciObject* y0 = deps->at(i+0); + ciObject* y1 = deps->at(i+1); + if (x0 == y0 && x1 == y1) { return; } } @@ -170,11 +186,11 @@ } // append the assertion in the correct bucket: - deps->append(ctxk); - deps->append(x); + deps->append(x0); + deps->append(x1); } -void Dependencies::assert_common_3(Dependencies::DepType dept, +void Dependencies::assert_common_3(DepType dept, ciKlass* ctxk, ciObject* x, ciObject* x2) { assert(dep_context_arg(dept) == 0, "sanity"); assert(dep_args(dept) == 3, "sanity"); @@ -361,7 +377,7 @@ 3, // unique_concrete_subtypes_2 ctxk, k1, k2 3, // unique_concrete_methods_2 ctxk, m1, m2 1, // no_finalizable_subclasses ctxk - 3 // call_site_target_value ctxk, call_site, method_handle + 2 // call_site_target_value call_site, method_handle }; const char* Dependencies::dep_name(Dependencies::DepType dept) { @@ -375,10 +391,7 @@ } void Dependencies::check_valid_dependency_type(DepType dept) { - for (int deptv = (int) FIRST_TYPE; deptv < (int) TYPE_LIMIT; deptv++) { - if (dept == ((DepType) deptv)) return; - } - ShouldNotReachHere(); + guarantee(FIRST_TYPE <= dept && dept < TYPE_LIMIT, err_msg("invalid dependency type: %d", (int) dept)); } // for the sake of the compiler log, print out current dependencies: @@ -586,8 +599,7 @@ code_byte -= ctxk_bit; DepType dept = (DepType)code_byte; _type = dept; - guarantee((dept - FIRST_TYPE) < (TYPE_LIMIT - FIRST_TYPE), - "bad dependency type tag"); + Dependencies::check_valid_dependency_type(dept); int stride = _dep_args[dept]; assert(stride == dep_args(dept), "sanity"); int skipj = -1; @@ -615,18 +627,35 @@ klassOop Dependencies::DepStream::context_type() { assert(must_be_in_vm(), "raw oops here"); - int ctxkj = dep_context_arg(_type); // -1 if no context arg - if (ctxkj < 0) { - return NULL; // for example, evol_method - } else { - oop k = recorded_oop_at(_xi[ctxkj]); - if (k != NULL) { // context type was not compressed away + + // Most dependencies have an explicit context type argument. + { + int ctxkj = dep_context_arg(_type); // -1 if no explicit context arg + if (ctxkj >= 0) { + oop k = argument(ctxkj); + if (k != NULL) { // context type was not compressed away + assert(k->is_klass(), "type check"); + return (klassOop) k; + } + // recompute "default" context type + return ctxk_encoded_as_null(_type, argument(ctxkj+1)); + } + } + + // Some dependencies are using the klass of the first object + // argument as implicit context type (e.g. call_site_target_value). + { + int ctxkj = dep_implicit_context_arg(_type); + if (ctxkj >= 0) { + oop k = argument(ctxkj)->klass(); assert(k->is_klass(), "type check"); return (klassOop) k; - } else { // recompute "default" context type - return ctxk_encoded_as_null(_type, recorded_oop_at(_xi[ctxkj+1])); } } + + // And some dependencies don't have a context type at all, + // e.g. evol_method. + return NULL; } /// Checking dependencies: @@ -1409,21 +1438,20 @@ } -klassOop Dependencies::check_call_site_target_value(klassOop ctxk, oop call_site, oop method_handle, CallSiteDepChange* changes) { +klassOop Dependencies::check_call_site_target_value(oop call_site, oop method_handle, CallSiteDepChange* changes) { assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "sanity"); assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "sanity"); if (changes == NULL) { // Validate all CallSites if (java_lang_invoke_CallSite::target(call_site) != method_handle) - return ctxk; // assertion failed + return call_site->klass(); // assertion failed } else { // Validate the given CallSite if (call_site == changes->call_site() && java_lang_invoke_CallSite::target(call_site) != changes->method_handle()) { assert(method_handle != changes->method_handle(), "must be"); - return ctxk; // assertion failed + return call_site->klass(); // assertion failed } } - assert(java_lang_invoke_CallSite::target(call_site) == method_handle, "should still be valid"); return NULL; // assertion still valid } @@ -1488,7 +1516,7 @@ klassOop witness = NULL; switch (type()) { case call_site_target_value: - witness = check_call_site_target_value(context_type(), argument(1), argument(2), changes); + witness = check_call_site_target_value(argument(0), argument(1), changes); break; default: witness = NULL; diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/code/dependencies.hpp --- a/src/share/vm/code/dependencies.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/code/dependencies.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -166,9 +166,14 @@ LG2_TYPE_LIMIT = 4, // assert(TYPE_LIMIT <= (1< recorded_oop_at(argument_index(i)) klassOop context_type(); + bool is_klass_type() { return Dependencies::is_klass_type(type()); } + methodOop method_argument(int i) { oop x = argument(i); assert(x->is_method(), "type"); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/code/nmethod.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -451,7 +451,6 @@ _stack_traversal_mark = 0; _unload_reported = false; // jvmti state - NOT_PRODUCT(_has_debug_info = false); #ifdef ASSERT _oops_are_stale = false; #endif diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/code/nmethod.hpp --- a/src/share/vm/code/nmethod.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/code/nmethod.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -191,8 +191,6 @@ jbyte _scavenge_root_state; - NOT_PRODUCT(bool _has_debug_info; ) - // Nmethod Flushing lock. If non-zero, then the nmethod is not removed // and is not made into a zombie. However, once the nmethod is made into // a zombie, it will be locked one final time if CompiledMethodUnload @@ -329,11 +327,6 @@ methodOop method() const { return _method; } AbstractCompiler* compiler() const { return _compiler; } -#ifndef PRODUCT - bool has_debug_info() const { return _has_debug_info; } - void set_has_debug_info(bool f) { _has_debug_info = false; } -#endif // NOT PRODUCT - // type info bool is_nmethod() const { return true; } bool is_java_method() const { return !method()->is_native(); } diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/code/pcDesc.cpp --- a/src/share/vm/code/pcDesc.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/code/pcDesc.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -30,11 +30,10 @@ #include "memory/resourceArea.hpp" PcDesc::PcDesc(int pc_offset, int scope_decode_offset, int obj_decode_offset) { - assert(sizeof(PcDescFlags) <= 4, "occupies more than a word"); _pc_offset = pc_offset; _scope_decode_offset = scope_decode_offset; _obj_decode_offset = obj_decode_offset; - _flags.word = 0; + _flags = 0; } address PcDesc::real_pc(const nmethod* code) const { @@ -44,7 +43,7 @@ void PcDesc::print(nmethod* code) { #ifndef PRODUCT ResourceMark rm; - tty->print_cr("PcDesc(pc=0x%lx offset=%x bits=%x):", real_pc(code), pc_offset(), _flags.bits); + tty->print_cr("PcDesc(pc=0x%lx offset=%x bits=%x):", real_pc(code), pc_offset(), _flags); if (scope_decode_offset() == DebugInformationRecorder::serialized_null) { return; diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/code/pcDesc.hpp --- a/src/share/vm/code/pcDesc.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/code/pcDesc.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -39,15 +39,17 @@ int _scope_decode_offset; // offset for scope in nmethod int _obj_decode_offset; - union PcDescFlags { - int word; - struct { - unsigned int reexecute: 1; - unsigned int is_method_handle_invoke: 1; - unsigned int return_oop: 1; - } bits; - bool operator ==(const PcDescFlags& other) { return word == other.word; } - } _flags; + enum { + PCDESC_reexecute = 1 << 0, + PCDESC_is_method_handle_invoke = 1 << 1, + PCDESC_return_oop = 1 << 2 + }; + + int _flags; + + void set_flag(int mask, bool z) { + _flags = z ? (_flags | mask) : (_flags & ~mask); + } public: int pc_offset() const { return _pc_offset; } @@ -69,8 +71,8 @@ }; // Flags - bool should_reexecute() const { return _flags.bits.reexecute; } - void set_should_reexecute(bool z) { _flags.bits.reexecute = z; } + bool should_reexecute() const { return (_flags & PCDESC_reexecute) != 0; } + void set_should_reexecute(bool z) { set_flag(PCDESC_reexecute, z); } // Does pd refer to the same information as pd? bool is_same_info(const PcDesc* pd) { @@ -79,11 +81,11 @@ _flags == pd->_flags; } - bool is_method_handle_invoke() const { return _flags.bits.is_method_handle_invoke; } - void set_is_method_handle_invoke(bool z) { _flags.bits.is_method_handle_invoke = z; } + bool is_method_handle_invoke() const { return (_flags & PCDESC_is_method_handle_invoke) != 0; } + void set_is_method_handle_invoke(bool z) { set_flag(PCDESC_is_method_handle_invoke, z); } - bool return_oop() const { return _flags.bits.return_oop; } - void set_return_oop(bool z) { _flags.bits.return_oop = z; } + bool return_oop() const { return (_flags & PCDESC_return_oop) != 0; } + void set_return_oop(bool z) { set_flag(PCDESC_return_oop, z); } // Returns the real pc address real_pc(const nmethod* code) const; diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/gc_interface/collectedHeap.cpp --- a/src/share/vm/gc_interface/collectedHeap.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/gc_interface/collectedHeap.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -157,8 +157,14 @@ // ..and clear it. Copy::zero_to_words(obj, new_tlab_size); } else { - // ...and clear just the allocated object. - Copy::zero_to_words(obj, size); + // ...and zap just allocated object. +#ifdef ASSERT + // Skip mangling the space corresponding to the object header to + // ensure that the returned space is not considered parsable by + // any concurrent GC thread. + size_t hdr_size = oopDesc::header_size(); + Copy::fill_to_words(obj + hdr_size, new_tlab_size - hdr_size, badHeapWordVal); +#endif // ASSERT } thread->tlab().fill(obj, obj + size, new_tlab_size); return obj; diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/gc_interface/collectedHeap.inline.hpp --- a/src/share/vm/gc_interface/collectedHeap.inline.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/gc_interface/collectedHeap.inline.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -287,7 +287,10 @@ assert(size >= 0, "int won't convert to size_t"); HeapWord* obj = common_permanent_mem_allocate_init(size, CHECK_NULL); post_allocation_setup_no_klass_install(klass, obj, size); - NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size)); +#ifndef PRODUCT + const size_t hs = oopDesc::header_size(); + Universe::heap()->check_for_bad_heap_word_value(obj+hs, size-hs); +#endif return (oop)obj; } diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/interpreter/bytecodes.hpp --- a/src/share/vm/interpreter/bytecodes.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/interpreter/bytecodes.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -419,6 +419,8 @@ static bool is_zero_const (Code code) { return (code == _aconst_null || code == _iconst_0 || code == _fconst_0 || code == _dconst_0); } + static bool is_invoke (Code code) { return (_invokevirtual <= code && code <= _invokedynamic); } + static int compute_flags (const char* format, int more_flags = 0); // compute the flags static int flags (int code, bool is_wide) { assert(code == (u_char)code, "must be a byte"); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -555,7 +555,7 @@ assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "must be"); { - // Walk all nmethods depending on CallSite + // Walk all nmethods depending on this call site. MutexLocker mu(Compile_lock, thread); Universe::flush_dependents_on(call_site, method_handle); } @@ -1244,7 +1244,7 @@ // preparing the same method will be sure to see non-null entry & mirror. IRT_END -#if defined(IA32) || defined(AMD64) +#if defined(IA32) || defined(AMD64) || defined(ARM) IRT_LEAF(void, InterpreterRuntime::popframe_move_outgoing_args(JavaThread* thread, void* src_address, void* dest_address)) if (src_address == dest_address) { return; diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/interpreter/interpreterRuntime.hpp --- a/src/share/vm/interpreter/interpreterRuntime.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/interpreter/interpreterRuntime.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -141,8 +141,8 @@ methodOopDesc* method, intptr_t* from, intptr_t* to); -#if defined(IA32) || defined(AMD64) - // Popframe support (only needed on x86 and AMD64) +#if defined(IA32) || defined(AMD64) || defined(ARM) + // Popframe support (only needed on x86, AMD64 and ARM) static void popframe_move_outgoing_args(JavaThread* thread, void* src_address, void* dest_address); #endif diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/memory/universe.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -1203,12 +1203,12 @@ // Compute the dependent nmethods that have a reference to a // CallSite object. We use instanceKlass::mark_dependent_nmethod // directly instead of CodeCache::mark_for_deoptimization because we - // want dependents on the class CallSite only not all classes in the - // ContextStream. + // want dependents on the call site class only not all classes in + // the ContextStream. int marked = 0; { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - instanceKlass* call_site_klass = instanceKlass::cast(SystemDictionary::CallSite_klass()); + instanceKlass* call_site_klass = instanceKlass::cast(call_site->klass()); marked = call_site_klass->mark_dependent_nmethods(changes); } if (marked > 0) { diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/oops/constMethodKlass.cpp --- a/src/share/vm/oops/constMethodKlass.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/oops/constMethodKlass.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -172,11 +172,6 @@ int constMethodKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { assert(obj->is_constMethod(), "should be constMethod"); constMethodOop cm_oop = constMethodOop(obj); -#if 0 - PSParallelCompact::adjust_pointer(cm_oop->adr_method()); - PSParallelCompact::adjust_pointer(cm_oop->adr_exception_table()); - PSParallelCompact::adjust_pointer(cm_oop->adr_stackmap_data()); -#endif oop* const beg_oop = cm_oop->oop_block_beg(); oop* const end_oop = cm_oop->oop_block_end(); for (oop* cur_oop = beg_oop; cur_oop < end_oop; ++cur_oop) { diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/oops/cpCacheKlass.cpp --- a/src/share/vm/oops/cpCacheKlass.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/oops/cpCacheKlass.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -63,8 +63,10 @@ // CollectedHeap::permanent_obj_allocate(klass, size, CHECK_NULL); oop obj = CollectedHeap::permanent_obj_allocate_no_klass_install(klass, size, CHECK_NULL); - NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value((HeapWord*) obj, - size)); +#ifndef PRODUCT + const size_t hs = oopDesc::header_size(); + Universe::heap()->check_for_bad_heap_word_value(((HeapWord*) obj)+hs, size-hs); +#endif constantPoolCacheOop cache = (constantPoolCacheOop) obj; assert(!UseConcMarkSweepGC || obj->klass_or_null() == NULL, "klass should be NULL here when using CMS"); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/oops/methodDataOop.hpp --- a/src/share/vm/oops/methodDataOop.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/oops/methodDataOop.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -600,6 +600,11 @@ uint taken() { return uint_at(taken_off_set); } + + void set_taken(uint cnt) { + set_uint_at(taken_off_set, cnt); + } + // Saturating counter uint inc_taken() { uint cnt = taken() + 1; @@ -926,6 +931,10 @@ return uint_at(not_taken_off_set); } + void set_not_taken(uint cnt) { + set_uint_at(not_taken_off_set, cnt); + } + uint inc_not_taken() { uint cnt = not_taken() + 1; // Did we wrap? Will compiler screw us?? diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/oops/methodOop.cpp --- a/src/share/vm/oops/methodOop.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/oops/methodOop.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -914,6 +914,7 @@ Symbol* name, Symbol* signature, Handle method_type, TRAPS) { + ResourceMark rm; methodHandle empty; assert(holder() == SystemDictionary::MethodHandle_klass(), diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/bytecodeInfo.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -45,7 +45,7 @@ _method(callee), _site_invoke_ratio(site_invoke_ratio), _max_inline_level(max_inline_level), - _count_inline_bcs(method()->code_size()) + _count_inline_bcs(method()->code_size_for_inlining()) { NOT_PRODUCT(_count_inlines = 0;) if (_caller_jvms != NULL) { @@ -107,7 +107,7 @@ // positive filter: should send be inlined? returns NULL (--> yes) // or rejection msg - int size = callee_method->code_size(); + int size = callee_method->code_size_for_inlining(); // Check for too many throws (and not too huge) if(callee_method->interpreter_throwout_count() > InlineThrowCount && @@ -141,7 +141,21 @@ assert(mha_profile, "must exist"); CounterData* cd = mha_profile->as_CounterData(); invoke_count = cd->count(); - call_site_count = invoke_count; // use the same value + if (invoke_count == 0) { + return "method handle not reached"; + } + + if (_caller_jvms != NULL && _caller_jvms->method() != NULL && + _caller_jvms->method()->method_data() != NULL && + !_caller_jvms->method()->method_data()->is_empty()) { + ciMethodData* mdo = _caller_jvms->method()->method_data(); + ciProfileData* mha_profile = mdo->bci_to_data(_caller_jvms->bci()); + assert(mha_profile, "must exist"); + CounterData* cd = mha_profile->as_CounterData(); + call_site_count = cd->count(); + } else { + call_site_count = invoke_count; // use the same value + } } assert(invoke_count != 0, "require invocation count greater than zero"); @@ -244,7 +258,7 @@ } // use frequency-based objections only for non-trivial methods - if (callee_method->code_size() <= MaxTrivialSize) return NULL; + if (callee_method->code_size_for_inlining() <= MaxTrivialSize) return NULL; // don't use counts with -Xcomp or CTW if (UseInterpreter && !CompileTheWorld) { @@ -305,7 +319,7 @@ } // suppress a few checks for accessors and trivial methods - if (callee_method->code_size() > MaxTrivialSize) { + if (callee_method->code_size_for_inlining() > MaxTrivialSize) { // don't inline into giant methods if (C->unique() > (uint)NodeCountInliningCutoff) { @@ -349,7 +363,7 @@ } } - int size = callee_method->code_size(); + int size = callee_method->code_size_for_inlining(); if (UseOldInlining && ClipInlining && (int)count_inline_bcs() + size >= DesiredMethodLimit) { @@ -394,6 +408,16 @@ return true; } +//------------------------------check_can_parse-------------------------------- +const char* InlineTree::check_can_parse(ciMethod* callee) { + // Certain methods cannot be parsed at all: + if ( callee->is_native()) return "native method"; + if (!callee->can_be_compiled()) return "not compilable (disabled)"; + if (!callee->has_balanced_monitors()) return "not compilable (unbalanced monitors)"; + if ( callee->get_flow_analysis()->failing()) return "not compilable (flow analysis failed)"; + return NULL; +} + //------------------------------print_inlining--------------------------------- // Really, the failure_msg can be a success message also. void InlineTree::print_inlining(ciMethod* callee_method, int caller_bci, const char* failure_msg) const { @@ -423,14 +447,22 @@ int caller_bci = jvms->bci(); ciMethod *caller_method = jvms->method(); - if( !pass_initial_checks(caller_method, caller_bci, callee_method)) { - if( PrintInlining ) { + // Do some initial checks. + if (!pass_initial_checks(caller_method, caller_bci, callee_method)) { + if (PrintInlining) { failure_msg = "failed_initial_checks"; - print_inlining( callee_method, caller_bci, failure_msg); + print_inlining(callee_method, caller_bci, failure_msg); } return NULL; } + // Do some parse checks. + failure_msg = check_can_parse(callee_method); + if (failure_msg != NULL) { + if (PrintInlining) print_inlining(callee_method, caller_bci, failure_msg); + return NULL; + } + // Check if inlining policy says no. WarmCallInfo wci = *(initial_wci); failure_msg = try_to_inline(callee_method, caller_method, caller_bci, profile, &wci); @@ -471,7 +503,7 @@ if (failure_msg == NULL) failure_msg = "inline (hot)"; // Inline! - if( PrintInlining ) print_inlining( callee_method, caller_bci, failure_msg); + if (PrintInlining) print_inlining(callee_method, caller_bci, failure_msg); if (UseOldInlining) build_inline_tree_for_callee(callee_method, jvms, caller_bci); if (InlineWarmCalls && !wci.is_hot()) @@ -481,7 +513,7 @@ // Do not inline if (failure_msg == NULL) failure_msg = "too cold to inline"; - if( PrintInlining ) print_inlining( callee_method, caller_bci, failure_msg); + if (PrintInlining) print_inlining(callee_method, caller_bci, failure_msg); return NULL; } diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/callGenerator.cpp --- a/src/share/vm/opto/callGenerator.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/callGenerator.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -61,12 +61,9 @@ { _is_osr = is_osr; _expected_uses = expected_uses; - assert(can_parse(method, is_osr), "parse must be possible"); + assert(InlineTree::check_can_parse(method) == NULL, "parse must be possible"); } - // Can we build either an OSR or a regular parser for this method? - static bool can_parse(ciMethod* method, int is_osr = false); - virtual bool is_parse() const { return true; } virtual JVMState* generate(JVMState* jvms); int is_osr() { return _is_osr; } @@ -152,7 +149,6 @@ call->set_optimized_virtual(true); if (method()->is_method_handle_invoke()) { call->set_method_handle_invoke(true); - kit.C->set_has_method_handle_invokes(true); } } kit.set_arguments_for_java_call(call); @@ -210,7 +206,6 @@ call->set_optimized_virtual(true); // Take extra care (in the presence of argument motion) not to trash the SP: call->set_method_handle_invoke(true); - kit.C->set_has_method_handle_invokes(true); // Pass the target MethodHandle as first argument and shift the // other arguments. @@ -303,20 +298,8 @@ return kit.transfer_exceptions_into_jvms(); } -bool ParseGenerator::can_parse(ciMethod* m, int entry_bci) { - // Certain methods cannot be parsed at all: - if (!m->can_be_compiled()) return false; - if (!m->has_balanced_monitors()) return false; - if (m->get_flow_analysis()->failing()) return false; - - // (Methods may bail out for other reasons, after the parser is run. - // We try to avoid this, but if forced, we must return (Node*)NULL. - // The user of the CallGenerator must check for this condition.) - return true; -} - CallGenerator* CallGenerator::for_inline(ciMethod* m, float expected_uses) { - if (!ParseGenerator::can_parse(m)) return NULL; + if (InlineTree::check_can_parse(m) != NULL) return NULL; return new ParseGenerator(m, expected_uses); } @@ -324,7 +307,7 @@ // for the method execution already in progress, not just the JVMS // of the caller. Thus, this CallGenerator cannot be mixed with others! CallGenerator* CallGenerator::for_osr(ciMethod* m, int osr_bci) { - if (!ParseGenerator::can_parse(m, true)) return NULL; + if (InlineTree::check_can_parse(m) != NULL) return NULL; float past_uses = m->interpreter_invocation_count(); float expected_uses = past_uses; return new ParseGenerator(m, expected_uses, true); @@ -336,7 +319,7 @@ } CallGenerator* CallGenerator::for_dynamic_call(ciMethod* m) { - assert(m->is_method_handle_invoke(), "for_dynamic_call mismatch"); + assert(m->is_method_handle_invoke() || m->is_method_handle_adapter(), "for_dynamic_call mismatch"); return new DynamicCallGenerator(m); } @@ -715,24 +698,36 @@ // Get an adapter for the MethodHandle. ciMethod* target_method = method_handle->get_method_handle_adapter(); if (target_method != NULL) { - CallGenerator* hit_cg = Compile::current()->call_generator(target_method, -1, false, jvms, true, 1); - if (hit_cg != NULL && hit_cg->is_inline()) - return hit_cg; + CallGenerator* cg = Compile::current()->call_generator(target_method, -1, false, jvms, true, PROB_ALWAYS); + if (cg != NULL && cg->is_inline()) + return cg; } } else if (method_handle->Opcode() == Op_Phi && method_handle->req() == 3 && method_handle->in(1)->Opcode() == Op_ConP && method_handle->in(2)->Opcode() == Op_ConP) { + float prob = PROB_FAIR; + Node* meth_region = method_handle->in(0); + if (meth_region->is_Region() && + meth_region->in(1)->is_Proj() && meth_region->in(2)->is_Proj() && + meth_region->in(1)->in(0) == meth_region->in(2)->in(0) && + meth_region->in(1)->in(0)->is_If()) { + // If diamond, so grab the probability of the test to drive the inlining below + prob = meth_region->in(1)->in(0)->as_If()->_prob; + if (meth_region->in(1)->is_IfTrue()) { + prob = 1 - prob; + } + } + // selectAlternative idiom merging two constant MethodHandles. // Generate a guard so that each can be inlined. We might want to // do more inputs at later point but this gets the most common // case. - const TypeOopPtr* oop_ptr = method_handle->in(1)->bottom_type()->is_oopptr(); - ciObject* const_oop = oop_ptr->const_oop(); - ciMethodHandle* mh = const_oop->as_method_handle(); - - CallGenerator* cg1 = for_method_handle_inline(method_handle->in(1), jvms, caller, callee, profile); - CallGenerator* cg2 = for_method_handle_inline(method_handle->in(2), jvms, caller, callee, profile); + CallGenerator* cg1 = for_method_handle_inline(method_handle->in(1), jvms, caller, callee, profile.rescale(1.0 - prob)); + CallGenerator* cg2 = for_method_handle_inline(method_handle->in(2), jvms, caller, callee, profile.rescale(prob)); if (cg1 != NULL && cg2 != NULL) { - return new PredictedDynamicCallGenerator(mh, cg2, cg1, PROB_FAIR); + const TypeOopPtr* oop_ptr = method_handle->in(1)->bottom_type()->is_oopptr(); + ciObject* const_oop = oop_ptr->const_oop(); + ciMethodHandle* mh = const_oop->as_method_handle(); + return new PredictedDynamicCallGenerator(mh, cg2, cg1, prob); } } return NULL; @@ -741,7 +736,6 @@ CallGenerator* CallGenerator::for_invokedynamic_inline(ciCallSite* call_site, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile) { - assert(call_site->is_constant_call_site() || call_site->is_mutable_call_site(), "must be"); ciMethodHandle* method_handle = call_site->get_target(); // Set the callee to have access to the class and signature in the @@ -754,13 +748,13 @@ ciMethod* target_method = method_handle->get_invokedynamic_adapter(); if (target_method != NULL) { Compile *C = Compile::current(); - CallGenerator* hit_cg = C->call_generator(target_method, -1, false, jvms, true, PROB_ALWAYS); - if (hit_cg != NULL && hit_cg->is_inline()) { + CallGenerator* cg = C->call_generator(target_method, -1, false, jvms, true, PROB_ALWAYS); + if (cg != NULL && cg->is_inline()) { // Add a dependence for invalidation of the optimization. - if (call_site->is_mutable_call_site()) { - C->dependencies()->assert_call_site_target_value(C->env()->CallSite_klass(), call_site, method_handle); + if (!call_site->is_constant_call_site()) { + C->dependencies()->assert_call_site_target_value(call_site, method_handle); } - return hit_cg; + return cg; } } return NULL; diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/compile.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -817,7 +817,6 @@ &_handler_table, &_inc_table, compiler, env()->comp_level(), - true, /*has_debug_info*/ has_unsafe_access() ); } diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/connode.hpp --- a/src/share/vm/opto/connode.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/connode.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -496,14 +496,6 @@ virtual bool depends_only_on_test() const { return false; } }; -//------------------------------MemMoveNode------------------------------------ -// Memory to memory move. Inserted very late, after allocation. -class MemMoveNode : public Node { -public: - MemMoveNode( Node *dst, Node *src ) : Node(0,dst,src) {} - virtual int Opcode() const; -}; - //------------------------------ThreadLocalNode-------------------------------- // Ideal Node which returns the base of ThreadLocalStorage. class ThreadLocalNode : public Node { diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/doCall.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -136,15 +136,9 @@ str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci. ciCallSite* call_site = str.get_call_site(); - // Inline constant and mutable call sites. We don't inline - // volatile call sites optimistically since they are specified - // to change their value often and that would result in a lot of - // deoptimizations and recompiles. - if (call_site->is_constant_call_site() || call_site->is_mutable_call_site()) { - CallGenerator* cg = CallGenerator::for_invokedynamic_inline(call_site, jvms, caller, call_method, profile); - if (cg != NULL) { - return cg; - } + CallGenerator* cg = CallGenerator::for_invokedynamic_inline(call_site, jvms, caller, call_method, profile); + if (cg != NULL) { + return cg; } // If something failed, generate a normal dynamic call. return CallGenerator::for_dynamic_call(call_method); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/idealGraphPrinter.cpp --- a/src/share/vm/opto/idealGraphPrinter.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/idealGraphPrinter.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -375,9 +375,9 @@ return (intptr_t)(n); } -void IdealGraphPrinter::visit_node(Node *n, void *param) { +void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) { - if(param) { + if (edges) { // Output edge intptr_t dest_id = get_node_id(n); @@ -599,16 +599,11 @@ #ifdef ASSERT if (node->debug_orig() != NULL) { + temp_set->Clear(); stringStream dorigStream; Node* dorig = node->debug_orig(); - if (dorig) { + while (dorig && temp_set->test_set(dorig->_idx)) { dorigStream.print("%d ", dorig->_idx); - Node* first = dorig; - dorig = first->debug_orig(); - while (dorig && dorig != first) { - dorigStream.print("%d ", dorig->_idx); - dorig = dorig->debug_orig(); - } } print_prop("debug_orig", dorigStream.as_string()); } @@ -629,7 +624,7 @@ } } -void IdealGraphPrinter::walk_nodes(Node *start, void *param) { +void IdealGraphPrinter::walk_nodes(Node *start, bool edges, VectorSet* temp_set) { VectorSet visited(Thread::current()->resource_area()); @@ -650,7 +645,7 @@ while(nodeStack.length() > 0) { Node *n = nodeStack.pop(); - visit_node(n, param); + visit_node(n, edges, temp_set); if (_traverse_outs) { for (DUIterator i = n->outs(); n->has_out(i); i++) { @@ -689,12 +684,14 @@ print_attr(GRAPH_NAME_PROPERTY, (const char *)name); end_head(); + VectorSet temp_set(Thread::current()->resource_area()); + head(NODES_ELEMENT); - walk_nodes(node, NULL); + walk_nodes(node, false, &temp_set); tail(NODES_ELEMENT); head(EDGES_ELEMENT); - walk_nodes(node, (void *)1); + walk_nodes(node, true, &temp_set); tail(EDGES_ELEMENT); if (C->cfg() != NULL) { head(CONTROL_FLOW_ELEMENT); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/idealGraphPrinter.hpp --- a/src/share/vm/opto/idealGraphPrinter.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/idealGraphPrinter.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -104,8 +104,8 @@ void print_indent(); void print_method(ciMethod *method, int bci, InlineTree *tree); void print_inline_tree(InlineTree *tree); - void visit_node(Node *n, void *param); - void walk_nodes(Node *start, void *param); + void visit_node(Node *n, bool edges, VectorSet* temp_set); + void walk_nodes(Node *start, bool edges, VectorSet* temp_set); void begin_elem(const char *s); void end_elem(); void begin_head(const char *s); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/matcher.cpp --- a/src/share/vm/opto/matcher.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/matcher.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -501,6 +501,12 @@ idealreg2spillmask[Op_RegP]->OR(*idealreg2regmask[Op_RegD]); #else idealreg2spillmask[Op_RegP]->OR(*idealreg2regmask[Op_RegF]); +#ifdef ARM + // ARM has support for moving 64bit values between a pair of + // integer registers and a double register + idealreg2spillmask[Op_RegL]->OR(*idealreg2regmask[Op_RegD]); + idealreg2spillmask[Op_RegD]->OR(*idealreg2regmask[Op_RegL]); +#endif #endif } @@ -1106,6 +1112,9 @@ mcall_java->_optimized_virtual = call_java->is_optimized_virtual(); is_method_handle_invoke = call_java->is_method_handle_invoke(); mcall_java->_method_handle_invoke = is_method_handle_invoke; + if (is_method_handle_invoke) { + C->set_has_method_handle_invokes(true); + } if( mcall_java->is_MachCallStaticJava() ) mcall_java->as_MachCallStaticJava()->_name = call_java->as_CallStaticJava()->_name; diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/memnode.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -1493,6 +1493,7 @@ if (tp == NULL || tp->empty()) return Type::TOP; int off = tp->offset(); assert(off != Type::OffsetTop, "case covered by TypePtr::empty"); + Compile* C = phase->C; // Try to guess loaded type from pointer type if (tp->base() == Type::AryPtr) { @@ -1536,7 +1537,7 @@ Node* base = adr->in(AddPNode::Base); if (base != NULL && !phase->type(base)->higher_equal(TypePtr::NULL_PTR)) { - Compile::AliasType* atp = phase->C->alias_type(base->adr_type()); + Compile::AliasType* atp = C->alias_type(base->adr_type()); if (is_autobox_cache(atp)) { return jt->join(TypePtr::NOTNULL)->is_ptr(); } @@ -1546,22 +1547,23 @@ } } } else if (tp->base() == Type::InstPtr) { + ciEnv* env = C->env(); const TypeInstPtr* tinst = tp->is_instptr(); ciKlass* klass = tinst->klass(); assert( off != Type::OffsetBot || // arrays can be cast to Objects tp->is_oopptr()->klass()->is_java_lang_Object() || // unsafe field access may not have a constant offset - phase->C->has_unsafe_access(), + C->has_unsafe_access(), "Field accesses must be precise" ); // For oop loads, we expect the _type to be precise - if (klass == phase->C->env()->String_klass() && + if (klass == env->String_klass() && adr->is_AddP() && off != Type::OffsetBot) { // For constant Strings treat the final fields as compile time constants. Node* base = adr->in(AddPNode::Base); const TypeOopPtr* t = phase->type(base)->isa_oopptr(); if (t != NULL && t->singleton()) { - ciField* field = phase->C->env()->String_klass()->get_field_by_offset(off, false); + ciField* field = env->String_klass()->get_field_by_offset(off, false); if (field != NULL && field->is_final()) { ciObject* string = t->const_oop(); ciConstant constant = string->as_instance()->field_value(field); @@ -1577,6 +1579,32 @@ } } } + // Optimizations for constant objects + ciObject* const_oop = tinst->const_oop(); + if (const_oop != NULL) { + // For constant CallSites treat the target field as a compile time constant. + if (const_oop->is_call_site()) { + ciCallSite* call_site = const_oop->as_call_site(); + ciField* field = call_site->klass()->as_instance_klass()->get_field_by_offset(off, /*is_static=*/ false); + if (field != NULL && field->is_call_site_target()) { + ciMethodHandle* target = call_site->get_target(); + if (target != NULL) { // just in case + ciConstant constant(T_OBJECT, target); + const Type* t; + if (adr->bottom_type()->is_ptr_to_narrowoop()) { + t = TypeNarrowOop::make_from_constant(constant.as_object(), true); + } else { + t = TypeOopPtr::make_from_constant(constant.as_object(), true); + } + // Add a dependence for invalidation of the optimization. + if (!call_site->is_constant_call_site()) { + C->dependencies()->assert_call_site_target_value(call_site, target); + } + return t; + } + } + } + } } else if (tp->base() == Type::KlassPtr) { assert( off != Type::OffsetBot || // arrays can be cast to Objects diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/parse.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -78,6 +78,8 @@ int stack_depth() const { return _caller_jvms ? _caller_jvms->depth() : 0; } public: + static const char* check_can_parse(ciMethod* callee); + static InlineTree* build_inline_tree_root(); static InlineTree* find_subtree_from_root(InlineTree* root, JVMState* jvms, ciMethod* callee, bool create_if_not_found = false); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/parse2.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -752,20 +752,12 @@ // Handle ret bytecode void Parse::do_ret() { // Find to whom we return. -#if 0 // %%%% MAKE THIS WORK - Node* con = local(); - const TypePtr* tp = con->bottom_type()->isa_ptr(); - assert(tp && tp->singleton(), ""); - int return_bci = (int) tp->get_con(); - merge(return_bci); -#else assert(block()->num_successors() == 1, "a ret can only go one place now"); Block* target = block()->successor_at(0); assert(!target->is_ready(), "our arrival must be expected"); profile_ret(target->flow()->start()); int pnum = target->next_path_num(); merge_common(target, pnum); -#endif } //--------------------------dynamic_branch_prediction-------------------------- diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/parse3.cpp --- a/src/share/vm/opto/parse3.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/parse3.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -100,11 +100,11 @@ } } - // Deoptimize on putfield writes to CallSite.target + // Deoptimize on putfield writes to call site target field. if (!is_get && field->is_call_site_target()) { uncommon_trap(Deoptimization::Reason_unhandled, Deoptimization::Action_reinterpret, - NULL, "put to CallSite.target field"); + NULL, "put to call site target field"); return; } @@ -147,19 +147,21 @@ void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) { // Does this field have a constant value? If so, just push the value. if (field->is_constant()) { + // final field if (field->is_static()) { // final static field if (push_constant(field->constant_value())) return; } else { - // final non-static field of a trusted class (classes in - // java.lang.invoke and sun.invoke packages and subpackages). + // final non-static field + // Treat final non-static fields of trusted classes (classes in + // java.lang.invoke and sun.invoke packages and subpackages) as + // compile time constants. if (obj->is_Con()) { const TypeOopPtr* oop_ptr = obj->bottom_type()->isa_oopptr(); ciObject* constant_oop = oop_ptr->const_oop(); ciConstant constant = field->constant_value_of(constant_oop); - if (push_constant(constant, true)) return; } diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/runtime.cpp --- a/src/share/vm/opto/runtime.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/runtime.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -978,7 +978,6 @@ thread->set_exception_pc(pc); thread->set_exception_handler_pc(handler_address); - thread->set_exception_stack_size(0); // Check if the exception PC is a MethodHandle call site. thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/opto/split_if.cpp --- a/src/share/vm/opto/split_if.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/opto/split_if.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -500,19 +500,14 @@ region_cache.lru_insert( new_false, new_false ); region_cache.lru_insert( new_true , new_true ); // Now handle all uses of the splitting block - for (DUIterator_Last kmin, k = region->last_outs(kmin); k >= kmin; --k) { - Node* phi = region->last_out(k); - if( !phi->in(0) ) { // Dead phi? Remove it + for (DUIterator k = region->outs(); region->has_out(k); k++) { + Node* phi = region->out(k); + if (!phi->in(0)) { // Dead phi? Remove it _igvn.remove_dead_node(phi); - continue; - } - assert( phi->in(0) == region, "" ); - if( phi == region ) { // Found the self-reference - phi->set_req(0, NULL); - continue; // Break the self-cycle - } - // Expected common case: Phi hanging off of Region - if( phi->is_Phi() ) { + } else if (phi == region) { // Found the self-reference + continue; // No roll-back of DUIterator + } else if (phi->is_Phi()) { // Expected common case: Phi hanging off of Region + assert(phi->in(0) == region, "Inconsistent graph"); // Need a per-def cache. Phi represents a def, so make a cache small_cache phi_cache; @@ -524,22 +519,24 @@ // collection of PHI's merging values from different paths. The Phis // inserted depend only on the location of the USE. We use a // 2-element cache to handle multiple uses from the same block. - handle_use( use, phi, &phi_cache, region_dom, new_false, new_true, old_false, old_true ); + handle_use(use, phi, &phi_cache, region_dom, new_false, new_true, old_false, old_true); } // End of while phi has uses - - // Because handle_use might relocate region->_out, - // we must refresh the iterator. - k = region->last_outs(kmin); - // Remove the dead Phi _igvn.remove_dead_node( phi ); - } else { + assert(phi->in(0) == region, "Inconsistent graph"); // Random memory op guarded by Region. Compute new DEF for USE. - handle_use( phi, region, ®ion_cache, region_dom, new_false, new_true, old_false, old_true ); + handle_use(phi, region, ®ion_cache, region_dom, new_false, new_true, old_false, old_true); } + // Every path above deletes a use of the region, except for the region + // self-cycle (which is needed by handle_use calling find_use_block + // calling get_ctrl calling get_ctrl_no_update looking for dead + // regions). So roll back the DUIterator innards. + --k; + } // End of while merge point has phis - } // End of while merge point has phis + assert(region->outcnt() == 1, "Only self reference should remain"); // Just Self on the Region + region->set_req(0, NULL); // Break the self-cycle // Any leftover bits in the splitting block must not have depended on local // Phi inputs (these have already been split-up). Hence it's safe to hoist diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/precompiled.hpp --- a/src/share/vm/precompiled.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/precompiled.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -206,7 +206,6 @@ # include "runtime/perfMemory.hpp" # include "runtime/prefetch.hpp" # include "runtime/reflection.hpp" -# include "runtime/reflectionCompat.hpp" # include "runtime/reflectionUtils.hpp" # include "runtime/registerMap.hpp" # include "runtime/safepoint.hpp" diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/prims/forte.cpp --- a/src/share/vm/prims/forte.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/prims/forte.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -522,25 +522,6 @@ extern "C" { JNIEXPORT void AsyncGetCallTrace(ASGCT_CallTrace *trace, jint depth, void* ucontext) { - -// This is if'd out because we no longer use thread suspension. -// However if someone wanted to backport this to a 5.0 jvm then this -// code would be important. -#if 0 - if (SafepointSynchronize::is_synchronizing()) { - // The safepoint mechanism is trying to synchronize all the threads. - // Since this can involve thread suspension, it is not safe for us - // to be here. We can reduce the deadlock risk window by quickly - // returning to the SIGPROF handler. However, it is still possible - // for VMThread to catch us here or in the SIGPROF handler. If we - // are suspended while holding a resource and another thread blocks - // on that resource in the SIGPROF handler, then we will have a - // three-thread deadlock (VMThread, this thread, the other thread). - trace->num_frames = ticks_safepoint; // -10 - return; - } -#endif - JavaThread* thread; if (trace->env_id == NULL || diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/prims/jvm.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -4020,249 +4020,6 @@ #endif -//--------------------------------------------------------------------------- -// -// Support for old native code-based reflection (pre-JDK 1.4) -// Disabled by default in the product build. -// -// See reflection.hpp for information on SUPPORT_OLD_REFLECTION -// -//--------------------------------------------------------------------------- - -#ifdef SUPPORT_OLD_REFLECTION - -JVM_ENTRY(jobjectArray, JVM_GetClassFields(JNIEnv *env, jclass cls, jint which)) - JVMWrapper("JVM_GetClassFields"); - JvmtiVMObjectAllocEventCollector oam; - oop mirror = JNIHandles::resolve_non_null(cls); - objArrayOop result = Reflection::reflect_fields(mirror, which, CHECK_NULL); - return (jobjectArray) JNIHandles::make_local(env, result); -JVM_END - - -JVM_ENTRY(jobjectArray, JVM_GetClassMethods(JNIEnv *env, jclass cls, jint which)) - JVMWrapper("JVM_GetClassMethods"); - JvmtiVMObjectAllocEventCollector oam; - oop mirror = JNIHandles::resolve_non_null(cls); - objArrayOop result = Reflection::reflect_methods(mirror, which, CHECK_NULL); - //%note jvm_r4 - return (jobjectArray) JNIHandles::make_local(env, result); -JVM_END - - -JVM_ENTRY(jobjectArray, JVM_GetClassConstructors(JNIEnv *env, jclass cls, jint which)) - JVMWrapper("JVM_GetClassConstructors"); - JvmtiVMObjectAllocEventCollector oam; - oop mirror = JNIHandles::resolve_non_null(cls); - objArrayOop result = Reflection::reflect_constructors(mirror, which, CHECK_NULL); - //%note jvm_r4 - return (jobjectArray) JNIHandles::make_local(env, result); -JVM_END - - -JVM_ENTRY(jobject, JVM_GetClassField(JNIEnv *env, jclass cls, jstring name, jint which)) - JVMWrapper("JVM_GetClassField"); - JvmtiVMObjectAllocEventCollector oam; - if (name == NULL) return NULL; - Handle str (THREAD, JNIHandles::resolve_non_null(name)); - - const char* cstr = java_lang_String::as_utf8_string(str()); - TempNewSymbol field_name = SymbolTable::probe(cstr, (int)strlen(cstr)); - if (field_name == NULL) { - THROW_0(vmSymbols::java_lang_NoSuchFieldException()); - } - - oop mirror = JNIHandles::resolve_non_null(cls); - oop result = Reflection::reflect_field(mirror, field_name, which, CHECK_NULL); - if (result == NULL) { - THROW_0(vmSymbols::java_lang_NoSuchFieldException()); - } - return JNIHandles::make_local(env, result); -JVM_END - - -JVM_ENTRY(jobject, JVM_GetClassMethod(JNIEnv *env, jclass cls, jstring name, jobjectArray types, jint which)) - JVMWrapper("JVM_GetClassMethod"); - JvmtiVMObjectAllocEventCollector oam; - if (name == NULL) { - THROW_0(vmSymbols::java_lang_NullPointerException()); - } - Handle str (THREAD, JNIHandles::resolve_non_null(name)); - - const char* cstr = java_lang_String::as_utf8_string(str()); - TempNewSymbol method_name = SymbolTable::probe(cstr, (int)strlen(cstr)); - if (method_name == NULL) { - THROW_0(vmSymbols::java_lang_NoSuchMethodException()); - } - - oop mirror = JNIHandles::resolve_non_null(cls); - objArrayHandle tarray (THREAD, objArrayOop(JNIHandles::resolve(types))); - oop result = Reflection::reflect_method(mirror, method_name, tarray, - which, CHECK_NULL); - if (result == NULL) { - THROW_0(vmSymbols::java_lang_NoSuchMethodException()); - } - return JNIHandles::make_local(env, result); -JVM_END - - -JVM_ENTRY(jobject, JVM_GetClassConstructor(JNIEnv *env, jclass cls, jobjectArray types, jint which)) - JVMWrapper("JVM_GetClassConstructor"); - JvmtiVMObjectAllocEventCollector oam; - oop mirror = JNIHandles::resolve_non_null(cls); - objArrayHandle tarray (THREAD, objArrayOop(JNIHandles::resolve(types))); - oop result = Reflection::reflect_constructor(mirror, tarray, which, CHECK_NULL); - if (result == NULL) { - THROW_0(vmSymbols::java_lang_NoSuchMethodException()); - } - return (jobject) JNIHandles::make_local(env, result); -JVM_END - - -// Instantiation /////////////////////////////////////////////////////////////////////////////// - -JVM_ENTRY(jobject, JVM_NewInstance(JNIEnv *env, jclass cls)) - JVMWrapper("JVM_NewInstance"); - Handle mirror(THREAD, JNIHandles::resolve_non_null(cls)); - - methodOop resolved_constructor = java_lang_Class::resolved_constructor(mirror()); - if (resolved_constructor == NULL) { - klassOop k = java_lang_Class::as_klassOop(mirror()); - // The java.lang.Class object caches a resolved constructor if all the checks - // below were done successfully and a constructor was found. - - // Do class based checks - if (java_lang_Class::is_primitive(mirror())) { - const char* msg = ""; - if (mirror == Universe::bool_mirror()) msg = "java/lang/Boolean"; - else if (mirror == Universe::char_mirror()) msg = "java/lang/Character"; - else if (mirror == Universe::float_mirror()) msg = "java/lang/Float"; - else if (mirror == Universe::double_mirror()) msg = "java/lang/Double"; - else if (mirror == Universe::byte_mirror()) msg = "java/lang/Byte"; - else if (mirror == Universe::short_mirror()) msg = "java/lang/Short"; - else if (mirror == Universe::int_mirror()) msg = "java/lang/Integer"; - else if (mirror == Universe::long_mirror()) msg = "java/lang/Long"; - THROW_MSG_0(vmSymbols::java_lang_NullPointerException(), msg); - } - - // Check whether we are allowed to instantiate this class - Klass::cast(k)->check_valid_for_instantiation(false, CHECK_NULL); // Array classes get caught here - instanceKlassHandle klass(THREAD, k); - // Make sure class is initialized (also so all methods are rewritten) - klass->initialize(CHECK_NULL); - - // Lookup default constructor - resolved_constructor = klass->find_method(vmSymbols::object_initializer_name(), vmSymbols::void_method_signature()); - if (resolved_constructor == NULL) { - ResourceMark rm(THREAD); - THROW_MSG_0(vmSymbols::java_lang_InstantiationException(), klass->external_name()); - } - - // Cache result in java.lang.Class object. Does not have to be MT safe. - java_lang_Class::set_resolved_constructor(mirror(), resolved_constructor); - } - - assert(resolved_constructor != NULL, "sanity check"); - methodHandle constructor = methodHandle(THREAD, resolved_constructor); - - // We have an initialized instanceKlass with a default constructor - instanceKlassHandle klass(THREAD, java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(cls))); - assert(klass->is_initialized() || klass->is_being_initialized(), "sanity check"); - - // Do security check - klassOop caller_klass = NULL; - if (UsePrivilegedStack) { - caller_klass = thread->security_get_caller_class(2); - - if (!Reflection::verify_class_access(caller_klass, klass(), false) || - !Reflection::verify_field_access(caller_klass, - klass(), - klass(), - constructor->access_flags(), - false, - true)) { - ResourceMark rm(THREAD); - THROW_MSG_0(vmSymbols::java_lang_IllegalAccessException(), klass->external_name()); - } - } - - // Allocate object and call constructor - Handle receiver = klass->allocate_instance_handle(CHECK_NULL); - JavaCalls::call_default_constructor(thread, constructor, receiver, CHECK_NULL); - - jobject res = JNIHandles::make_local(env, receiver()); - if (JvmtiExport::should_post_vm_object_alloc()) { - JvmtiExport::post_vm_object_alloc(JavaThread::current(), receiver()); - } - return res; -JVM_END - - -// Field //////////////////////////////////////////////////////////////////////////////////////////// - -JVM_ENTRY(jobject, JVM_GetField(JNIEnv *env, jobject field, jobject obj)) - JVMWrapper("JVM_GetField"); - JvmtiVMObjectAllocEventCollector oam; - Handle field_mirror(thread, JNIHandles::resolve(field)); - Handle receiver (thread, JNIHandles::resolve(obj)); - fieldDescriptor fd; - Reflection::resolve_field(field_mirror, receiver, &fd, false, CHECK_NULL); - jvalue value; - BasicType type = Reflection::field_get(&value, &fd, receiver); - oop box = Reflection::box(&value, type, CHECK_NULL); - return JNIHandles::make_local(env, box); -JVM_END - - -JVM_ENTRY(jvalue, JVM_GetPrimitiveField(JNIEnv *env, jobject field, jobject obj, unsigned char wCode)) - JVMWrapper("JVM_GetPrimitiveField"); - Handle field_mirror(thread, JNIHandles::resolve(field)); - Handle receiver (thread, JNIHandles::resolve(obj)); - fieldDescriptor fd; - jvalue value; - value.j = 0; - Reflection::resolve_field(field_mirror, receiver, &fd, false, CHECK_(value)); - BasicType type = Reflection::field_get(&value, &fd, receiver); - BasicType wide_type = (BasicType) wCode; - if (type != wide_type) { - Reflection::widen(&value, type, wide_type, CHECK_(value)); - } - return value; -JVM_END // should really be JVM_END, but that doesn't work for union types! - - -JVM_ENTRY(void, JVM_SetField(JNIEnv *env, jobject field, jobject obj, jobject val)) - JVMWrapper("JVM_SetField"); - Handle field_mirror(thread, JNIHandles::resolve(field)); - Handle receiver (thread, JNIHandles::resolve(obj)); - oop box = JNIHandles::resolve(val); - fieldDescriptor fd; - Reflection::resolve_field(field_mirror, receiver, &fd, true, CHECK); - BasicType field_type = fd.field_type(); - jvalue value; - BasicType value_type; - if (field_type == T_OBJECT || field_type == T_ARRAY) { - // Make sure we do no unbox e.g. java/lang/Integer instances when storing into an object array - value_type = Reflection::unbox_for_regular_object(box, &value); - Reflection::field_set(&value, &fd, receiver, field_type, CHECK); - } else { - value_type = Reflection::unbox_for_primitive(box, &value, CHECK); - Reflection::field_set(&value, &fd, receiver, value_type, CHECK); - } -JVM_END - - -JVM_ENTRY(void, JVM_SetPrimitiveField(JNIEnv *env, jobject field, jobject obj, jvalue v, unsigned char vCode)) - JVMWrapper("JVM_SetPrimitiveField"); - Handle field_mirror(thread, JNIHandles::resolve(field)); - Handle receiver (thread, JNIHandles::resolve(obj)); - fieldDescriptor fd; - Reflection::resolve_field(field_mirror, receiver, &fd, true, CHECK); - BasicType value_type = (BasicType) vCode; - Reflection::field_set(&v, &fd, receiver, value_type, CHECK); -JVM_END - - // Method /////////////////////////////////////////////////////////////////////////////////////////// JVM_ENTRY(jobject, JVM_InvokeMethod(JNIEnv *env, jobject method, jobject obj, jobjectArray args0)) @@ -4302,8 +4059,6 @@ return res; JVM_END -#endif /* SUPPORT_OLD_REFLECTION */ - // Atomic /////////////////////////////////////////////////////////////////////////////////////////// JVM_LEAF(jboolean, JVM_SupportsCX8()) diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/prims/jvm.h --- a/src/share/vm/prims/jvm.h Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/prims/jvm.h Fri Sep 09 14:44:43 2011 +0200 @@ -26,7 +26,6 @@ #define SHARE_VM_PRIMS_JVM_H #include "prims/jni.h" -#include "runtime/reflectionCompat.hpp" #ifdef TARGET_OS_FAMILY_linux # include "jvm_linux.h" #endif @@ -43,8 +42,7 @@ // HotSpot integration note: // // This file and jvm.h used with the JDK are identical, -// except for the three includes removed below and the -// SUPPORT_OLD_REFLECTION sections cut out of the JDK's jvm.h. +// except for the three includes removed below // #include // #include "jni.h" @@ -443,14 +441,6 @@ jsize len, jobject pd, const char *source, jboolean verify); -/* Define a class with a source (MLVM) */ -JNIEXPORT jclass JNICALL -JVM_DefineClassWithCP(JNIEnv *env, const char *name, jobject loader, - const jbyte *buf, jsize len, jobject pd, - const char *source, - // same args as JVM_DefineClassWithSource to this point - jobjectArray constants); - /* * Reflection support functions */ @@ -1442,65 +1432,6 @@ JNIEXPORT void JNICALL JVM_RawMonitorExit(void *mon); - -#ifdef SUPPORT_OLD_REFLECTION - -/* - * Support for old native code-based (pre-JDK 1.4) reflection implementation. - * Disabled by default in the product build. - * - * See reflection.hpp for information on SUPPORT_OLD_REFLECTION - */ - -/* - * reflecting fields and methods. - * which: 0 --- MEMBER_PUBLIC - * 1 --- MEMBER_DECLARED - * NOTE: absent in product build by default - */ - -JNIEXPORT jobjectArray JNICALL -JVM_GetClassFields(JNIEnv *env, jclass cls, jint which); - -JNIEXPORT jobjectArray JNICALL -JVM_GetClassMethods(JNIEnv *env, jclass cls, jint which); - -JNIEXPORT jobjectArray JNICALL -JVM_GetClassConstructors(JNIEnv *env, jclass cls, jint which); - -JNIEXPORT jobject JNICALL -JVM_GetClassField(JNIEnv *env, jclass cls, jstring name, jint which); - -JNIEXPORT jobject JNICALL -JVM_GetClassMethod(JNIEnv *env, jclass cls, jstring name, jobjectArray types, - jint which); -JNIEXPORT jobject JNICALL -JVM_GetClassConstructor(JNIEnv *env, jclass cls, jobjectArray types, - jint which); - -/* - * Implements Class.newInstance - */ -JNIEXPORT jobject JNICALL -JVM_NewInstance(JNIEnv *env, jclass cls); - -/* - * java.lang.reflect.Field - */ -JNIEXPORT jobject JNICALL -JVM_GetField(JNIEnv *env, jobject field, jobject obj); - -JNIEXPORT jvalue JNICALL -JVM_GetPrimitiveField(JNIEnv *env, jobject field, jobject obj, - unsigned char wCode); - -JNIEXPORT void JNICALL -JVM_SetField(JNIEnv *env, jobject field, jobject obj, jobject val); - -JNIEXPORT void JNICALL -JVM_SetPrimitiveField(JNIEnv *env, jobject field, jobject obj, jvalue v, - unsigned char vCode); - /* * java.lang.reflect.Method */ @@ -1513,8 +1444,6 @@ JNIEXPORT jobject JNICALL JVM_NewInstanceFromConstructor(JNIEnv *env, jobject c, jobjectArray args0); -#endif /* SUPPORT_OLD_REFLECTION */ - /* * java.lang.management support */ diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/prims/methodHandleWalk.cpp --- a/src/share/vm/prims/methodHandleWalk.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/prims/methodHandleWalk.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -182,10 +182,6 @@ HandleMark hm; ResourceMark rm; Handle mh(m); - print(mh); -} - -void MethodHandleChain::print(Handle mh) { EXCEPTION_MARK; MethodHandleChain mhc(mh, THREAD); if (HAS_PENDING_EXCEPTION) { @@ -222,16 +218,33 @@ if (o != NULL) { if (o->is_instance()) { tty->print(" instance %s", o->klass()->klass_part()->internal_name()); + if (java_lang_invoke_CountingMethodHandle::is_instance(o)) { + tty->print(" vmcount: %d", java_lang_invoke_CountingMethodHandle::vmcount(o)); + } } else { o->print(); } } + oop vmt = chain.vmtarget_oop(); + if (vmt != NULL) { + if (vmt->is_method()) { + tty->print(" "); + methodOop(vmt)->print_short_name(tty); + } else if (java_lang_invoke_MethodHandle::is_instance(vmt)) { + tty->print(" method handle " INTPTR_FORMAT, vmt); + } else { + ShouldNotReachHere(); + } + } } else if (chain.is_adapter()) { tty->print("adapter: arg_slot %d conversion op %s", chain.adapter_arg_slot(), adapter_op_to_string(chain.adapter_conversion_op())); switch (chain.adapter_conversion_op()) { case java_lang_invoke_AdapterMethodHandle::OP_RETYPE_ONLY: + if (java_lang_invoke_CountingMethodHandle::is_instance(chain.method_handle_oop())) { + tty->print(" vmcount: %d", java_lang_invoke_CountingMethodHandle::vmcount(chain.method_handle_oop())); + } case java_lang_invoke_AdapterMethodHandle::OP_RETYPE_RAW: case java_lang_invoke_AdapterMethodHandle::OP_CHECK_CAST: case java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_PRIM: @@ -907,7 +920,10 @@ _non_bcp_klasses(THREAD, 5), _cur_stack(0), _max_stack(0), - _rtype(T_ILLEGAL) + _rtype(T_ILLEGAL), + _selectAlternative_bci(-1), + _taken_count(0), + _not_taken_count(0) { // Element zero is always the null constant. @@ -1115,11 +1131,50 @@ _bytecode.push(0); break; + case Bytecodes::_ifeq: + assert((unsigned short) index == index, "index does not fit in 16-bit"); + _bytecode.push(op); + _bytecode.push(index >> 8); + _bytecode.push(index); + break; + default: ShouldNotReachHere(); } } +void MethodHandleCompiler::update_branch_dest(int src, int dst) { + switch (_bytecode.at(src)) { + case Bytecodes::_ifeq: + dst -= src; // compute the offset + assert((unsigned short) dst == dst, "index does not fit in 16-bit"); + _bytecode.at_put(src + 1, dst >> 8); + _bytecode.at_put(src + 2, dst); + break; + default: + ShouldNotReachHere(); + } +} + +void MethodHandleCompiler::emit_load(ArgToken arg) { + TokenType tt = arg.token_type(); + BasicType bt = arg.basic_type(); + + switch (tt) { + case tt_parameter: + case tt_temporary: + emit_load(bt, arg.index()); + break; + case tt_constant: + emit_load_constant(arg); + break; + case tt_illegal: + case tt_void: + default: + ShouldNotReachHere(); + } +} + void MethodHandleCompiler::emit_load(BasicType bt, int index) { if (index <= 3) { @@ -1318,6 +1373,29 @@ jvalue MethodHandleCompiler::zero_jvalue = { 0 }; jvalue MethodHandleCompiler::one_jvalue = { 1 }; +// Fetch any values from CountingMethodHandles and capture them for profiles +bool MethodHandleCompiler::fetch_counts(ArgToken arg1, ArgToken arg2) { + int count1 = -1, count2 = -1; + if (arg1.token_type() == tt_constant && arg1.basic_type() == T_OBJECT && + java_lang_invoke_CountingMethodHandle::is_instance(arg1.object()())) { + count1 = java_lang_invoke_CountingMethodHandle::vmcount(arg1.object()()); + } + if (arg2.token_type() == tt_constant && arg2.basic_type() == T_OBJECT && + java_lang_invoke_CountingMethodHandle::is_instance(arg2.object()())) { + count2 = java_lang_invoke_CountingMethodHandle::vmcount(arg2.object()()); + } + int total = count1 + count2; + if (count1 != -1 && count2 != -1 && total != 0) { + // Normalize the collect counts to the invoke_count + tty->print("counts %d %d scaled by %d = ", count2, count1, _invoke_count); + if (count1 != 0) _not_taken_count = (int)(_invoke_count * count1 / (double)total); + if (count2 != 0) _taken_count = (int)(_invoke_count * count2 / (double)total); + tty->print_cr("%d %d", _taken_count, _not_taken_count); + return true; + } + return false; +} + // Emit bytecodes for the given invoke instruction. MethodHandleWalker::ArgToken MethodHandleCompiler::make_invoke(methodHandle m, vmIntrinsics::ID iid, @@ -1367,6 +1445,29 @@ } } + if (m->intrinsic_id() == vmIntrinsics::_selectAlternative && + fetch_counts(argv[1], argv[2])) { + assert(argc == 3, "three arguments"); + assert(tailcall, "only"); + + // do inline bytecodes so we can drop profile data into it, + // 0: iload_0 + emit_load(argv[0]); + // 1: ifeq 8 + _selectAlternative_bci = _bytecode.length(); + emit_bc(Bytecodes::_ifeq, 0); // emit placeholder offset + // 4: aload_1 + emit_load(argv[1]); + // 5: areturn; + emit_bc(Bytecodes::_areturn); + // 8: aload_2 + update_branch_dest(_selectAlternative_bci, cur_bci()); + emit_load(argv[2]); + // 9: areturn + emit_bc(Bytecodes::_areturn); + return ArgToken(); // Dummy return value. + } + check_non_bcp_klass(klass, CHECK_(zero)); if (m->is_method_handle_invoke()) { check_non_bcp_klasses(m->method_handle_type(), CHECK_(zero)); @@ -1377,10 +1478,6 @@ assert(argc == asc.size() + ((op == Bytecodes::_invokestatic || op == Bytecodes::_invokedynamic) ? 0 : 1), "argc mismatch"); - // Inline the method. - InvocationCounter* ic = m->invocation_counter(); - ic->set_carry_flag(); - for (int i = 0; i < argc; i++) { ArgToken arg = argv[i]; TokenType tt = arg.token_type(); @@ -1686,7 +1783,7 @@ } -methodHandle MethodHandleCompiler::get_method_oop(TRAPS) const { +methodHandle MethodHandleCompiler::get_method_oop(TRAPS) { methodHandle empty; // Create a method that holds the generated bytecode. invokedynamic // has no receiver, normal MH calls do. @@ -1765,6 +1862,7 @@ assert(m->method_data() == NULL, "there should not be an MDO yet"); m->set_method_data(mdo); + bool found_selectAlternative = false; // Iterate over all profile data and set the count of the counter // data entries to the original call site counter. for (ProfileData* profile_data = mdo->first_data(); @@ -1774,7 +1872,15 @@ CounterData* counter_data = profile_data->as_CounterData(); counter_data->set_count(_invoke_count); } + if (profile_data->is_BranchData() && + profile_data->bci() == _selectAlternative_bci) { + BranchData* bd = profile_data->as_BranchData(); + bd->set_taken(_taken_count); + bd->set_not_taken(_not_taken_count); + found_selectAlternative = true; + } } + assert(_selectAlternative_bci == -1 || found_selectAlternative, "must have found profile entry"); } #ifndef PRODUCT diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/prims/methodHandleWalk.hpp --- a/src/share/vm/prims/methodHandleWalk.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/prims/methodHandleWalk.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -74,6 +74,7 @@ set_method_handle(MethodHandle_vmtarget_oop(), THREAD); } + Handle root() { return _root; } Handle method_handle() { return _method_handle; } oop method_handle_oop() { return _method_handle(); } oop method_type_oop() { return MethodHandle_type_oop(); } @@ -110,7 +111,6 @@ // the signature for each method. The signatures are printed in // slot order to make it easier to understand. void print(); - static void print(Handle mh); static void print(oopDesc* mh); #endif }; @@ -277,6 +277,10 @@ KlassHandle _target_klass; Thread* _thread; + int _selectAlternative_bci; // These are used for capturing profiles from GWTs + int _taken_count; + int _not_taken_count; + // Values used by the compiler. static jvalue zero_jvalue; static jvalue one_jvalue; @@ -372,6 +376,7 @@ unsigned char* bytecode() const { return _bytecode.adr_at(0); } int bytecode_length() const { return _bytecode.length(); } + int cur_bci() const { return _bytecode.length(); } // Fake constant pool. int cpool_oop_put(int tag, Handle con) { @@ -436,6 +441,8 @@ } void emit_bc(Bytecodes::Code op, int index = 0, int args_size = -1); + void update_branch_dest(int src, int dst); + void emit_load(ArgToken arg); void emit_load(BasicType bt, int index); void emit_store(BasicType bt, int index); void emit_load_constant(ArgToken arg); @@ -455,11 +462,14 @@ virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS); virtual ArgToken make_invoke(methodHandle m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS); + // Check for profiling information on a GWT and return true if it's found + bool fetch_counts(ArgToken a1, ArgToken a2); + // Get a real constant pool. constantPoolHandle get_constant_pool(TRAPS) const; // Get a real methodOop. - methodHandle get_method_oop(TRAPS) const; + methodHandle get_method_oop(TRAPS); public: MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool for_invokedynamic, TRAPS); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/prims/methodHandles.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -158,6 +158,8 @@ "adapter_fold/4/ref", "adapter_fold/5/ref", + "adapter_opt_profiling", + NULL }; @@ -2653,6 +2655,11 @@ // Finalize the conversion field. (Note that it is final to Java code.) java_lang_invoke_AdapterMethodHandle::set_conversion(mh(), new_conversion); + if (java_lang_invoke_CountingMethodHandle::is_instance(mh())) { + assert(ek_orig == _adapter_retype_only, "only one handled"); + ek_opt = _adapter_opt_profiling; + } + // Done! java_lang_invoke_MethodHandle::set_vmentry(mh(), entry(ek_opt)); @@ -2905,8 +2912,12 @@ return MethodHandles::stack_move_unit(); case MethodHandles::GC_CONV_OP_IMPLEMENTED_MASK: return MethodHandles::adapter_conversion_ops_supported_mask(); - case MethodHandles::GC_OP_ROT_ARGS_DOWN_LIMIT_BIAS: - return MethodHandles::OP_ROT_ARGS_DOWN_LIMIT_BIAS; + case MethodHandles::GC_COUNT_GWT: +#ifdef COMPILER2 + return true; +#else + return false; +#endif } return 0; } diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/prims/methodHandles.hpp --- a/src/share/vm/prims/methodHandles.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/prims/methodHandles.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -187,6 +187,8 @@ _adapter_opt_fold_FIRST = _adapter_opt_fold_ref, _adapter_opt_fold_LAST = _adapter_opt_fold_5_ref, + _adapter_opt_profiling, + _EK_LIMIT, _EK_FIRST = 0 }; @@ -266,6 +268,8 @@ return _adapter_fold_args; if (ek >= _adapter_opt_return_FIRST && ek <= _adapter_opt_return_LAST) return _adapter_opt_return_any; + if (ek == _adapter_opt_profiling) + return _adapter_retype_only; assert(false, "oob"); return _EK_LIMIT; } @@ -582,6 +586,7 @@ GC_JVM_STACK_MOVE_UNIT = 1, GC_CONV_OP_IMPLEMENTED_MASK = 2, GC_OP_ROT_ARGS_DOWN_LIMIT_BIAS = 3, + GC_COUNT_GWT = 4, // format of result from getTarget / encode_target: ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method) diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/prims/unsafe.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -33,7 +33,6 @@ #include "runtime/globals.hpp" #include "runtime/interfaceSupport.hpp" #include "runtime/reflection.hpp" -#include "runtime/reflectionCompat.hpp" #include "runtime/synchronizer.hpp" #include "services/threadService.hpp" #include "utilities/copy.hpp" @@ -303,6 +302,19 @@ UnsafeWrapper("Unsafe_SetObjectVolatile"); oop x = JNIHandles::resolve(x_h); oop p = JNIHandles::resolve(obj); + // Catch VolatileCallSite.target stores (via + // CallSite.setTargetVolatile) and check call site dependencies. + if ((offset == java_lang_invoke_CallSite::target_offset_in_bytes()) && p->is_a(SystemDictionary::CallSite_klass())) { + oop call_site = p; + oop method_handle = x; + assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "must be"); + assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "must be"); + { + // Walk all nmethods depending on this call site. + MutexLocker mu(Compile_lock, thread); + Universe::flush_dependents_on(call_site, method_handle); + } + } void* addr = index_oop_from_field_offset_long(p, offset); OrderAccess::release(); if (UseCompressedOops) { diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/runtime/globals.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -1985,6 +1985,18 @@ product(bool, TLABStats, true, \ "Print various TLAB related information") \ \ + product(bool, UseBlockZeroing, false, \ + "Use special cpu instructions for block zeroing") \ + \ + product(intx, BlockZeroingLowLimit, 2048, \ + "Minimum size in bytes when block zeroing will be used") \ + \ + product(bool, UseBlockCopy, false, \ + "Use special cpu instructions for block copy") \ + \ + product(intx, BlockCopyLowLimit, 2048, \ + "Minimum size in bytes when block copy will be used") \ + \ product(bool, PrintRevisitStats, false, \ "Print revisit (klass and MDO) stack related information") \ \ @@ -2918,6 +2930,12 @@ product(intx, ReadPrefetchInstr, 0, \ "Prefetch instruction to prefetch ahead") \ \ + product(uintx, ArraycopySrcPrefetchDistance, 0, \ + "Distance to prefetch source array in arracopy") \ + \ + product(uintx, ArraycopyDstPrefetchDistance, 0, \ + "Distance to prefetch destination array in arracopy") \ + \ /* deoptimization */ \ develop(bool, TraceDeoptimization, false, \ "Trace deoptimization") \ diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/runtime/reflection.cpp --- a/src/share/vm/runtime/reflection.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/runtime/reflection.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -844,16 +844,6 @@ } -//--------------------------------------------------------------------------- -// -// Supporting routines for old native code-based reflection (pre-JDK 1.4). -// -// See reflection.hpp for details. -// -//--------------------------------------------------------------------------- - -#ifdef SUPPORT_OLD_REFLECTION - methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, methodHandle method, KlassHandle recv_klass, Handle receiver, TRAPS) { assert(!method.is_null() , "method should not be null"); @@ -1081,519 +1071,6 @@ return java_lang_Class::primitive_type(basic_type_mirror); } - -bool Reflection::match_parameter_types(methodHandle method, objArrayHandle types, int parameter_count, TRAPS) { - int types_len = types.is_null() ? 0 : types->length(); - if (types_len != parameter_count) return false; - if (parameter_count > 0) { - objArrayHandle method_types = get_parameter_types(method, parameter_count, NULL, CHECK_false); - for (int index = 0; index < parameter_count; index++) { - if (types->obj_at(index) != method_types->obj_at(index)) { - return false; - } - } - } - return true; -} - - -oop Reflection::new_field(FieldStream* st, TRAPS) { - Symbol* field_name = st->name(); - Handle name = java_lang_String::create_from_symbol(field_name, CHECK_NULL); - Symbol* signature = st->signature(); - Handle type = new_type(signature, st->klass(), CHECK_NULL); - Handle rh = java_lang_reflect_Field::create(CHECK_NULL); - oop result = rh(); - - java_lang_reflect_Field::set_clazz(result, st->klass()->java_mirror()); - java_lang_reflect_Field::set_slot(result, st->index()); - java_lang_reflect_Field::set_name(result, name()); - java_lang_reflect_Field::set_type(result, type()); - // Note the ACC_ANNOTATION bit, which is a per-class access flag, is never set here. - java_lang_reflect_Field::set_modifiers(result, st->access_flags().as_int() & JVM_RECOGNIZED_FIELD_MODIFIERS); - java_lang_reflect_Field::set_override(result, false); - return result; -} - - -bool Reflection::resolve_field(Handle field_mirror, Handle& receiver, fieldDescriptor* fd, bool check_final, TRAPS) { - if (field_mirror.is_null()) { - THROW_(vmSymbols::java_lang_NullPointerException(), false); - } - - instanceKlassHandle klass (THREAD, java_lang_Class::as_klassOop(java_lang_reflect_Field::clazz(field_mirror()))); - int slot = java_lang_reflect_Field::slot(field_mirror()); - - // Ensure klass is initialized - klass->initialize(CHECK_false); - fd->initialize(klass(), slot); - - bool is_static = fd->is_static(); - KlassHandle receiver_klass; - - if (is_static) { - receiver = KlassHandle(THREAD, klass()); - receiver_klass = klass; - } else { - // Check object is a non-null instance of declaring class - if (receiver.is_null()) { - THROW_(vmSymbols::java_lang_NullPointerException(), false); - } - if (!receiver->is_a(klass())) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), "object is not an instance of declaring class", false); - } - receiver_klass = KlassHandle(THREAD, receiver->klass()); - } - - // Access checking (unless overridden by Field) - if (!java_lang_reflect_Field::override(field_mirror())) { - if (!(klass->is_public() && fd->is_public())) { - bool access_check = reflect_check_access(klass(), fd->access_flags(), receiver_klass(), false, CHECK_false); - if (!access_check) { - return false; // exception - } - } - } - - if (check_final && fd->is_final()) { - // In 1.3 we always throw an error when attempting to set a final field. - // In 1.2.x, this was allowed in the override bit was set by calling Field.setAccessible(true). - // We currently maintain backwards compatibility. See bug 4250960. - bool strict_final_check = !JDK_Version::is_jdk12x_version(); - if (strict_final_check || !java_lang_reflect_Field::override(field_mirror())) { - THROW_MSG_(vmSymbols::java_lang_IllegalAccessException(), "field is final", false); - } - } - return true; -} - - -BasicType Reflection::field_get(jvalue* value, fieldDescriptor* fd, Handle receiver) { - BasicType field_type = fd->field_type(); - int offset = fd->offset(); - switch (field_type) { - case T_BOOLEAN: - value->z = receiver->bool_field(offset); - break; - case T_CHAR: - value->c = receiver->char_field(offset); - break; - case T_FLOAT: - value->f = receiver->float_field(offset); - break; - case T_DOUBLE: - value->d = receiver->double_field(offset); - break; - case T_BYTE: - value->b = receiver->byte_field(offset); - break; - case T_SHORT: - value->s = receiver->short_field(offset); - break; - case T_INT: - value->i = receiver->int_field(offset); - break; - case T_LONG: - value->j = receiver->long_field(offset); - break; - case T_OBJECT: - case T_ARRAY: - value->l = (jobject) receiver->obj_field(offset); - break; - default: - return T_ILLEGAL; - } - return field_type; -} - - -void Reflection::field_set(jvalue* value, fieldDescriptor* fd, Handle receiver, BasicType value_type, TRAPS) { - BasicType field_type = fd->field_type(); - if (field_type != value_type) { - widen(value, value_type, field_type, CHECK); - } - - int offset = fd->offset(); - switch (field_type) { - case T_BOOLEAN: - receiver->bool_field_put(offset, value->z); - break; - case T_CHAR: - receiver->char_field_put(offset, value->c); - break; - case T_FLOAT: - receiver->float_field_put(offset, value->f); - break; - case T_DOUBLE: - receiver->double_field_put(offset, value->d); - break; - case T_BYTE: - receiver->byte_field_put(offset, value->b); - break; - case T_SHORT: - receiver->short_field_put(offset, value->s); - break; - case T_INT: - receiver->int_field_put(offset, value->i); - break; - case T_LONG: - receiver->long_field_put(offset, value->j); - break; - case T_OBJECT: - case T_ARRAY: { - Handle obj(THREAD, (oop) value->l); - if (obj.not_null()) { - Symbol* signature = fd->signature(); - Handle loader (THREAD, fd->loader()); - Handle protect (THREAD, Klass::cast(fd->field_holder())->protection_domain()); - klassOop k = SystemDictionary::resolve_or_fail(signature, loader, protect, true, CHECK); // may block - if (!obj->is_a(k)) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "field type mismatch"); - } - } - receiver->obj_field_put(offset, obj()); - break; - } - default: - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "field type mismatch"); - } -} - - -oop Reflection::reflect_field(oop mirror, Symbol* field_name, jint which, TRAPS) { - // Exclude primitive types and array types - if (java_lang_Class::is_primitive(mirror)) return NULL; - if (Klass::cast(java_lang_Class::as_klassOop(mirror))->oop_is_array()) return NULL; - - instanceKlassHandle k(THREAD, java_lang_Class::as_klassOop(mirror)); - bool local_fields_only = (which == DECLARED); - - // Ensure class is linked - k->link_class(CHECK_NULL); - - // Search class and interface fields - for (FieldStream st(k, local_fields_only, false); !st.eos(); st.next()) { - if (st.name() == field_name) { - if (local_fields_only || st.access_flags().is_public()) { - return new_field(&st, THREAD); - } - } - } - - return NULL; -} - - -objArrayOop Reflection::reflect_fields(oop mirror, jint which, TRAPS) { - // Exclude primitive types and array types - if (java_lang_Class::is_primitive(mirror) - || Klass::cast(java_lang_Class::as_klassOop(mirror))->oop_is_array()) { - Symbol* name = vmSymbols::java_lang_reflect_Field(); - klassOop klass = SystemDictionary::resolve_or_fail(name, true, CHECK_NULL); - return oopFactory::new_objArray(klass, 0, CHECK_NULL); // Return empty array - } - - instanceKlassHandle k(THREAD, java_lang_Class::as_klassOop(mirror)); - - // Ensure class is linked - k->link_class(CHECK_NULL); - - bool local_fields_only = (which == DECLARED); - int count = 0; - { // Compute fields count for class and interface fields - for (FieldStream st(k, local_fields_only, false); !st.eos(); st.next()) { - if (local_fields_only || st.access_flags().is_public()) { - count++; - } - } - } - - // Allocate result - Symbol* name = vmSymbols::java_lang_reflect_Field(); - klassOop klass = SystemDictionary::resolve_or_fail(name, true, CHECK_NULL); - objArrayOop r = oopFactory::new_objArray(klass, count, CHECK_NULL); - objArrayHandle result (THREAD, r); - - // Fill in results backwards - { - for (FieldStream st(k, local_fields_only, false); !st.eos(); st.next()) { - if (local_fields_only || st.access_flags().is_public()) { - oop field = new_field(&st, CHECK_NULL); - result->obj_at_put(--count, field); - } - } - assert(count == 0, "just checking"); - } - return result(); -} - - -oop Reflection::reflect_method(oop mirror, Symbol* method_name, objArrayHandle types, jint which, TRAPS) { - if (java_lang_Class::is_primitive(mirror)) return NULL; - klassOop klass = java_lang_Class::as_klassOop(mirror); - if (Klass::cast(klass)->oop_is_array() && which == MEMBER_DECLARED) return NULL; - - if (Klass::cast(java_lang_Class::as_klassOop(mirror))->oop_is_array()) { - klass = SystemDictionary::Object_klass(); - } - instanceKlassHandle h_k(THREAD, klass); - - // Ensure klass is linked (need not be initialized) - h_k->link_class(CHECK_NULL); - - // For interfaces include static initializers under jdk1.2.x (since classic does that) - bool include_clinit = JDK_Version::is_jdk12x_version() && h_k->is_interface(); - - switch (which) { - case MEMBER_PUBLIC: - // First the public non-static methods (works if method holder is an interface) - // Note that we can ignore checks for overridden methods, since we go up the hierarchy. - { - for (MethodStream st(h_k, false, false); !st.eos(); st.next()) { - methodHandle m(THREAD, st.method()); - // For interfaces include static initializers since classic does that! - if (method_name == m->name() && (include_clinit || (m->is_public() && !m->is_static() && !m->is_initializer()))) { - Symbol* signature = m->signature(); - bool parameter_match = match_parameter_types(m, types, ArgumentCount(signature).size(), CHECK_NULL); - if (parameter_match) { - return new_method(m, false, false, THREAD); - } - } - } - } - // Then the public static methods (works if method holder is an interface) - { - for (MethodStream st(h_k, false, false); !st.eos(); st.next()) { - methodHandle m(THREAD, st.method()); - if (method_name == m->name() && m->is_public() && m->is_static() && !m->is_initializer()) { - Symbol* signature = m->signature(); - bool parameter_match = match_parameter_types(m, types, ArgumentCount(signature).size(), CHECK_NULL); - if (parameter_match) { - return new_method(m, false, false, THREAD); - } - } - } - } - break; - case MEMBER_DECLARED: - // All local methods - { - for (MethodStream st(h_k, true, true); !st.eos(); st.next()) { - methodHandle m(THREAD, st.method()); - if (method_name == m->name() && !m->is_initializer()) { - Symbol* signature = m->signature(); - bool parameter_match = match_parameter_types(m, types, ArgumentCount(signature).size(), CHECK_NULL); - if (parameter_match) { - return new_method(m, false, false, THREAD); - } - } - } - } - break; - default: - break; - } - return NULL; -} - - -objArrayOop Reflection::reflect_methods(oop mirror, jint which, TRAPS) { - // Exclude primitive types - if (java_lang_Class::is_primitive(mirror) || - (Klass::cast(java_lang_Class::as_klassOop(mirror))->oop_is_array() && (which == MEMBER_DECLARED))) { - klassOop klass = SystemDictionary::reflect_Method_klass(); - return oopFactory::new_objArray(klass, 0, CHECK_NULL); // Return empty array - } - - klassOop klass = java_lang_Class::as_klassOop(mirror); - if (Klass::cast(java_lang_Class::as_klassOop(mirror))->oop_is_array()) { - klass = SystemDictionary::Object_klass(); - } - instanceKlassHandle h_k(THREAD, klass); - - // Ensure klass is linked (need not be initialized) - h_k->link_class(CHECK_NULL); - - // We search the (super)interfaces only if h_k is an interface itself - bool is_interface = h_k->is_interface(); - - // For interfaces include static initializers under jdk1.2.x (since classic does that) - bool include_clinit = JDK_Version::is_jdk12x_version() && is_interface; - - switch (which) { - case MEMBER_PUBLIC: - { - - // Count public methods (non-static and static) - int count = 0; - { - for (MethodStream st(h_k, false, false); !st.eos(); st.next()) { - methodOop m = st.method(); - // For interfaces include static initializers since classic does that! - if (include_clinit || (!m->is_initializer() && m->is_public() && !m->is_overridden_in(h_k()))) { - count++; - } - } - } - - // Allocate result - klassOop klass = SystemDictionary::reflect_Method_klass(); - objArrayOop r = oopFactory::new_objArray(klass, count, CHECK_NULL); - objArrayHandle h_result (THREAD, r); - - // Fill in results backwards - { - // First the non-static public methods - for (MethodStream st(h_k, false, false); !st.eos(); st.next()) { - methodHandle m (THREAD, st.method()); - if (!m->is_static() && !m->is_initializer() && m->is_public() && !m->is_overridden_in(h_k())) { - oop method = new_method(m, false, false, CHECK_NULL); - if (method == NULL) { - return NULL; - } else { - h_result->obj_at_put(--count, method); - } - } - } - } - { - // Then the static public methods - for (MethodStream st(h_k, false, !is_interface); !st.eos(); st.next()) { - methodHandle m (THREAD, st.method()); - if (m->is_static() && (include_clinit || (!m->is_initializer()) && m->is_public() && !m->is_overridden_in(h_k()))) { - oop method = new_method(m, false, false, CHECK_NULL); - if (method == NULL) { - return NULL; - } else { - h_result->obj_at_put(--count, method); - } - } - } - } - - assert(count == 0, "just checking"); - return h_result(); - } - - case MEMBER_DECLARED: - { - // Count all methods - int count = 0; - { - for (MethodStream st(h_k, true, !is_interface); !st.eos(); st.next()) { - methodOop m = st.method(); - if (!m->is_initializer()) { - count++; - } - } - } - // Allocate result - klassOop klass = SystemDictionary::reflect_Method_klass(); - objArrayOop r = oopFactory::new_objArray(klass, count, CHECK_NULL); - objArrayHandle h_result (THREAD, r); - - // Fill in results backwards - { - for (MethodStream st(h_k, true, true); !st.eos(); st.next()) { - methodHandle m (THREAD, st.method()); - if (!m->is_initializer()) { - oop method = new_method(m, false, false, CHECK_NULL); - if (method == NULL) { - return NULL; - } else { - h_result->obj_at_put(--count, method); - } - } - } - } - assert(count == 0, "just checking"); - return h_result(); - } - } - ShouldNotReachHere(); - return NULL; -} - - -oop Reflection::reflect_constructor(oop mirror, objArrayHandle types, jint which, TRAPS) { - - // Exclude primitive, interface and array types - bool prim = java_lang_Class::is_primitive(mirror); - Klass* klass = prim ? NULL : Klass::cast(java_lang_Class::as_klassOop(mirror)); - if (prim || klass->is_interface() || klass->oop_is_array()) return NULL; - - // Must be instance klass - instanceKlassHandle h_k(THREAD, java_lang_Class::as_klassOop(mirror)); - - // Ensure klass is linked (need not be initialized) - h_k->link_class(CHECK_NULL); - - bool local_only = (which == MEMBER_DECLARED); - for (MethodStream st(h_k, true, true); !st.eos(); st.next()) { - methodHandle m(THREAD, st.method()); - if (m->name() == vmSymbols::object_initializer_name() && (local_only || m->is_public())) { - Symbol* signature = m->signature(); - bool parameter_match = match_parameter_types(m, types, ArgumentCount(signature).size(), CHECK_NULL); - if (parameter_match) { - return new_constructor(m, THREAD); - } - } - } - - return NULL; -} - - -objArrayOop Reflection::reflect_constructors(oop mirror, jint which, TRAPS) { - // Exclude primitive, interface and array types - bool prim = java_lang_Class::is_primitive(mirror); - Klass* k = prim ? NULL : Klass::cast(java_lang_Class::as_klassOop(mirror)); - if (prim || k->is_interface() || k->oop_is_array()) { - return oopFactory::new_objArray(SystemDictionary::reflect_Constructor_klass(), 0, CHECK_NULL); // Return empty array - } - - // Must be instanceKlass at this point - instanceKlassHandle h_k(THREAD, java_lang_Class::as_klassOop(mirror)); - - // Ensure klass is linked (need not be initialized) - h_k->link_class(CHECK_NULL); - - bool local_only = (which == MEMBER_DECLARED); - int count = 0; - { - for (MethodStream st(h_k, true, true); !st.eos(); st.next()) { - methodOop m = st.method(); - if (m->name() == vmSymbols::object_initializer_name() && (local_only || m->is_public())) { - count++; - } - } - } - - // Allocate result - Symbol* name = vmSymbols::java_lang_reflect_Constructor(); - klassOop klass = SystemDictionary::resolve_or_fail(name, true, CHECK_NULL); - objArrayOop r = oopFactory::new_objArray(klass, count, CHECK_NULL); - objArrayHandle h_result (THREAD, r); - - // Fill in results backwards - { - for (MethodStream st(h_k, true, true); !st.eos(); st.next()) { - methodHandle m (THREAD, st.method()); - if (m->name() == vmSymbols::object_initializer_name() && (local_only || m->is_public())) { - oop constr = new_constructor(m, CHECK_NULL); - if (constr == NULL) { - return NULL; - } else { - h_result->obj_at_put(--count, constr); - } - } - } - assert(count == 0, "just checking"); - } - return h_result(); -} - - // This would be nicer if, say, java.lang.reflect.Method was a subclass // of java.lang.reflect.Constructor @@ -1647,6 +1124,3 @@ invoke(klass, method, receiver, override, ptypes, T_VOID, args, false, CHECK_NULL); return receiver(); } - - -#endif /* SUPPORT_OLD_REFLECTION */ diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/runtime/reflection.hpp --- a/src/share/vm/runtime/reflection.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/runtime/reflection.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -27,7 +27,6 @@ #include "oops/oop.hpp" #include "runtime/fieldDescriptor.hpp" -#include "runtime/reflectionCompat.hpp" #include "utilities/accessFlags.hpp" #include "utilities/growableArray.hpp" @@ -120,16 +119,6 @@ // Create a java.lang.reflect.Field object based on a field descriptor static oop new_field(fieldDescriptor* fd, bool intern_name, TRAPS); - //--------------------------------------------------------------------------- - // - // Support for old native code-based reflection (pre-JDK 1.4) - // - // NOTE: the method and constructor invocation code is still used - // for startup time reasons; see reflectionCompat.hpp. - // - //--------------------------------------------------------------------------- - -#ifdef SUPPORT_OLD_REFLECTION private: // method resolution for invoke static methodHandle resolve_interface_call(instanceKlassHandle klass, methodHandle method, KlassHandle recv_klass, Handle receiver, TRAPS); @@ -144,35 +133,11 @@ // Conversion static BasicType basic_type_mirror_to_basic_type(oop basic_type_mirror, TRAPS); - static bool match_parameter_types(methodHandle method, objArrayHandle types, int parameter_count, TRAPS); - // Creating new java.lang.reflect.xxx wrappers - static oop new_field(FieldStream* st, TRAPS); - public: - // Field lookup and verification. - static bool resolve_field(Handle field_mirror, Handle& receiver, fieldDescriptor* fd, bool check_final, TRAPS); - - // Reflective field access. Returns type code. Throws IllegalArgumentException. - static BasicType field_get(jvalue* value, fieldDescriptor* fd, Handle receiver); - static void field_set(jvalue* value, fieldDescriptor* fd, Handle receiver, BasicType value_type, TRAPS); - - // Reflective lookup of fields. Returns java.lang.reflect.Field instances. - static oop reflect_field(oop mirror, Symbol* field_name, jint which, TRAPS); - static objArrayOop reflect_fields(oop mirror, jint which, TRAPS); - - // Reflective lookup of methods. Returns java.lang.reflect.Method instances. - static oop reflect_method(oop mirror, Symbol* method_name, objArrayHandle types, jint which, TRAPS); - static objArrayOop reflect_methods(oop mirror, jint which, TRAPS); - - // Reflective lookup of constructors. Returns java.lang.reflect.Constructor instances. - static oop reflect_constructor(oop mirror, objArrayHandle types, jint which, TRAPS); - static objArrayOop reflect_constructors(oop mirror, jint which, TRAPS); - // Method invokation through java.lang.reflect.Method static oop invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS); // Method invokation through java.lang.reflect.Constructor static oop invoke_constructor(oop method_mirror, objArrayHandle args, TRAPS); -#endif /* SUPPORT_OLD_REFLECTION */ }; diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/runtime/reflectionCompat.hpp --- a/src/share/vm/runtime/reflectionCompat.hpp Fri Sep 09 05:20:58 2011 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_VM_RUNTIME_REFLECTIONCOMPAT_HPP -#define SHARE_VM_RUNTIME_REFLECTIONCOMPAT_HPP - -// During the development of the JDK 1.4 reflection implementation -// based on dynamic bytecode generation, it was hoped that the bulk of -// the native code for reflection could be removed. Unfortunately -// there is currently a significant cost associated with loading the -// stub classes which impacts startup time. Until this cost can be -// reduced, the JVM entry points JVM_InvokeMethod and -// JVM_NewInstanceFromConstructor are still needed; these and their -// dependents currently constitute the bulk of the native code for -// reflection. If this cost is reduced in the future, the -// NativeMethodAccessorImpl and NativeConstructorAccessorImpl classes -// can be removed from sun.reflect and all of the code guarded by this -// flag removed from the product build. (Non-product builds, -// specifically the "optimized" target, would retain the code so they -// could be dropped into earlier JDKs for comparative benchmarking.) - -//#ifndef PRODUCT -# define SUPPORT_OLD_REFLECTION -//#endif - -#endif // SHARE_VM_RUNTIME_REFLECTIONCOMPAT_HPP diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/runtime/sharedRuntime.hpp --- a/src/share/vm/runtime/sharedRuntime.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/runtime/sharedRuntime.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -45,6 +45,8 @@ // information, etc. class SharedRuntime: AllStatic { + friend class VMStructs; + private: static methodHandle resolve_sub_helper(JavaThread *thread, bool is_virtual, diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/runtime/stubRoutines.cpp --- a/src/share/vm/runtime/stubRoutines.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/runtime/stubRoutines.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -108,6 +108,7 @@ address StubRoutines::_arrayof_oop_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_oop_copy); address StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_oop_copy_uninit); +address StubRoutines::_zero_aligned_words = CAST_FROM_FN_PTR(address, Copy::zero_to_words); address StubRoutines::_checkcast_arraycopy = NULL; address StubRoutines::_checkcast_arraycopy_uninit = NULL; diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/runtime/stubRoutines.hpp --- a/src/share/vm/runtime/stubRoutines.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/runtime/stubRoutines.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -199,6 +199,9 @@ static address _arrayof_jshort_fill; static address _arrayof_jint_fill; + // zero heap space aligned to jlong (8 bytes) + static address _zero_aligned_words; + // These are versions of the java.lang.Math methods which perform // the same operations as the intrinsic version. They are used for // constant folding in the compiler to ensure equivalence. If the @@ -332,6 +335,7 @@ static address select_fill_function(BasicType t, bool aligned, const char* &name); + static address zero_aligned_words() { return _zero_aligned_words; } static double intrinsic_log(double d) { assert(_intrinsic_log != NULL, "must be defined"); diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/runtime/thread.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -1272,7 +1272,6 @@ _exception_oop = NULL; _exception_pc = 0; _exception_handler_pc = 0; - _exception_stack_size = 0; _is_method_handle_return = 0; _jvmti_thread_state= NULL; _should_post_on_exceptions_flag = JNI_FALSE; @@ -2860,6 +2859,44 @@ } } +class PrintAndVerifyOopClosure: public OopClosure { + protected: + template inline void do_oop_work(T* p) { + oop obj = oopDesc::load_decode_heap_oop(p); + if (obj == NULL) return; + tty->print(INTPTR_FORMAT ": ", p); + if (obj->is_oop_or_null()) { + if (obj->is_objArray()) { + tty->print_cr("valid objArray: " INTPTR_FORMAT, (oopDesc*) obj); + } else { + obj->print(); + } + } else { + tty->print_cr("invalid oop: " INTPTR_FORMAT, (oopDesc*) obj); + } + tty->cr(); + } + public: + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } +}; + + +static void oops_print(frame* f, const RegisterMap *map) { + PrintAndVerifyOopClosure print; + f->print_value(); + f->oops_do(&print, NULL, (RegisterMap*)map); +} + +// Print our all the locations that contain oops and whether they are +// valid or not. This useful when trying to find the oldest frame +// where an oop has gone bad since the frame walk is from youngest to +// oldest. +void JavaThread::trace_oops() { + tty->print_cr("[Trace oops]"); + frames_do(oops_print); +} + #ifdef ASSERT // Print or validate the layout of stack frames diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/runtime/thread.hpp Fri Sep 09 14:44:43 2011 +0200 @@ -841,7 +841,6 @@ volatile oop _exception_oop; // Exception thrown in compiled code volatile address _exception_pc; // PC where exception happened volatile address _exception_handler_pc; // PC for handler of exception - volatile int _exception_stack_size; // Size of frame where exception happened volatile int _is_method_handle_return; // true (== 1) if the current exception PC is a MethodHandle call site. // support for compilation @@ -1182,7 +1181,6 @@ // Exception handling for compiled methods oop exception_oop() const { return _exception_oop; } - int exception_stack_size() const { return _exception_stack_size; } address exception_pc() const { return _exception_pc; } address exception_handler_pc() const { return _exception_handler_pc; } bool is_method_handle_return() const { return _is_method_handle_return == 1; } @@ -1190,7 +1188,6 @@ void set_exception_oop(oop o) { _exception_oop = o; } void set_exception_pc(address a) { _exception_pc = a; } void set_exception_handler_pc(address a) { _exception_handler_pc = a; } - void set_exception_stack_size(int size) { _exception_stack_size = size; } void set_is_method_handle_return(bool value) { _is_method_handle_return = value ? 1 : 0; } // Stack overflow support @@ -1264,7 +1261,6 @@ static ByteSize exception_oop_offset() { return byte_offset_of(JavaThread, _exception_oop ); } static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc ); } static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); } - static ByteSize exception_stack_size_offset() { return byte_offset_of(JavaThread, _exception_stack_size); } static ByteSize is_method_handle_return_offset() { return byte_offset_of(JavaThread, _is_method_handle_return); } static ByteSize stack_guard_state_offset() { return byte_offset_of(JavaThread, _stack_guard_state ); } static ByteSize suspend_flags_offset() { return byte_offset_of(JavaThread, _suspend_flags ); } @@ -1379,6 +1375,7 @@ void trace_stack() PRODUCT_RETURN; void trace_stack_from(vframe* start_vf) PRODUCT_RETURN; void trace_frames() PRODUCT_RETURN; + void trace_oops() PRODUCT_RETURN; // Print an annotated view of the stack frames void print_frame_layout(int depth = 0, bool validate_only = false) NOT_DEBUG_RETURN; diff -r 3bddbf0f57d6 -r e984655be425 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Fri Sep 09 05:20:58 2011 -0400 +++ b/src/share/vm/runtime/vmStructs.cpp Fri Sep 09 14:44:43 2011 +0200 @@ -652,6 +652,7 @@ static_field(SystemDictionary, WK_KLASS(ThreadGroup_klass), klassOop) \ static_field(SystemDictionary, WK_KLASS(Properties_klass), klassOop) \ static_field(SystemDictionary, WK_KLASS(StringBuffer_klass), klassOop) \ + static_field(SystemDictionary, WK_KLASS(MethodHandle_klass), klassOop) \ static_field(SystemDictionary, _box_klasses[0], klassOop) \ static_field(SystemDictionary, _java_system_loader, oop) \ \ @@ -757,12 +758,19 @@ nonstatic_field(PcDesc, _pc_offset, int) \ nonstatic_field(PcDesc, _scope_decode_offset, int) \ nonstatic_field(PcDesc, _obj_decode_offset, int) \ - nonstatic_field(PcDesc, _flags, PcDesc::PcDescFlags) \ + nonstatic_field(PcDesc, _flags, int) \ \ /***************************************************/ \ /* CodeBlobs (NOTE: incomplete, but only a little) */ \ /***************************************************/ \ \ + X86_ONLY(nonstatic_field(MethodHandles::RicochetFrame, _sender_pc, address)) \ + X86_ONLY(nonstatic_field(MethodHandles::RicochetFrame, _exact_sender_sp, intptr_t*)) \ + X86_ONLY(nonstatic_field(MethodHandles::RicochetFrame, _sender_link, intptr_t*)) \ + X86_ONLY(nonstatic_field(MethodHandles::RicochetFrame, _saved_args_base, intptr_t*)) \ + \ + static_field(SharedRuntime, _ricochet_blob, RicochetBlob*) \ + \ nonstatic_field(CodeBlob, _name, const char*) \ nonstatic_field(CodeBlob, _size, int) \ nonstatic_field(CodeBlob, _header_size, int) \ @@ -774,6 +782,8 @@ nonstatic_field(CodeBlob, _frame_size, int) \ nonstatic_field(CodeBlob, _oop_maps, OopMapSet*) \ \ + nonstatic_field(RuntimeStub, _caller_must_gc_arguments, bool) \ + \ /**************************************************/ \ /* NMethods (NOTE: incomplete, but only a little) */ \ /**************************************************/ \ @@ -786,6 +796,7 @@ nonstatic_field(nmethod, _state, unsigned char) \ nonstatic_field(nmethod, _exception_offset, int) \ nonstatic_field(nmethod, _deoptimize_offset, int) \ + nonstatic_field(nmethod, _deoptimize_mh_offset, int) \ nonstatic_field(nmethod, _orig_pc_offset, int) \ nonstatic_field(nmethod, _stub_offset, int) \ nonstatic_field(nmethod, _consts_offset, int) \ @@ -804,6 +815,9 @@ nonstatic_field(nmethod, _compile_id, int) \ nonstatic_field(nmethod, _marked_for_deoptimization, bool) \ \ + nonstatic_field(RicochetBlob, _bounce_offset, int) \ + nonstatic_field(RicochetBlob, _exception_offset, int) \ + \ /********************************/ \ /* JavaCalls (NOTE: incomplete) */ \ /********************************/ \ @@ -1310,24 +1324,27 @@ /* CodeBlob hierarchy (needed for run-time type information) */ \ /*************************************************************/ \ \ + declare_toplevel_type(SharedRuntime) \ + X86_ONLY(declare_toplevel_type(MethodHandles::RicochetFrame)) \ + \ declare_toplevel_type(CodeBlob) \ - declare_type(BufferBlob, CodeBlob) \ - declare_type(AdapterBlob, BufferBlob) \ - declare_type(nmethod, CodeBlob) \ - declare_type(RuntimeStub, CodeBlob) \ - declare_type(SingletonBlob, CodeBlob) \ - declare_type(SafepointBlob, SingletonBlob) \ - declare_type(DeoptimizationBlob, SingletonBlob) \ - declare_type(RicochetBlob, SingletonBlob) \ - declare_c2_type(ExceptionBlob, SingletonBlob) \ - declare_c2_type(UncommonTrapBlob, CodeBlob) \ + declare_type(BufferBlob, CodeBlob) \ + declare_type(AdapterBlob, BufferBlob) \ + declare_type(MethodHandlesAdapterBlob, BufferBlob) \ + declare_type(nmethod, CodeBlob) \ + declare_type(RuntimeStub, CodeBlob) \ + declare_type(SingletonBlob, CodeBlob) \ + declare_type(SafepointBlob, SingletonBlob) \ + declare_type(DeoptimizationBlob, SingletonBlob) \ + declare_type(RicochetBlob, SingletonBlob) \ + declare_c2_type(ExceptionBlob, SingletonBlob) \ + declare_c2_type(UncommonTrapBlob, CodeBlob) \ \ /***************************************/ \ /* PcDesc and other compiled code info */ \ /***************************************/ \ \ declare_toplevel_type(PcDesc) \ - declare_integer_type(PcDesc::PcDescFlags) \ \ /************************/ \ /* OopMap and OopMapSet */ \ @@ -1796,6 +1813,21 @@ \ declare_constant(ObjectSynchronizer::_BLOCKSIZE) \ \ + /**********************/ \ + /* PcDesc */ \ + /**********************/ \ + \ + declare_constant(PcDesc::PCDESC_reexecute) \ + declare_constant(PcDesc::PCDESC_is_method_handle_invoke) \ + declare_constant(PcDesc::PCDESC_return_oop) \ + \ + /**********************/ \ + /* frame */ \ + /**********************/ \ + \ + X86_ONLY(declare_constant(frame::entry_frame_call_wrapper_offset)) \ + declare_constant(frame::pc_return_offset) \ + \ /********************************/ \ /* Calling convention constants */ \ /********************************/ \ diff -r 3bddbf0f57d6 -r e984655be425 test/compiler/7082949/Test7082949.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/7082949/Test7082949.java Fri Sep 09 14:44:43 2011 +0200 @@ -0,0 +1,54 @@ +/* + * 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. + * + */ + +/** + * @test + * @bug 7082949 + * @summary JSR 292: missing ResourceMark in methodOopDesc::make_invoke_method + * + * @run main Test7082949 + */ + +import java.lang.invoke.*; +import static java.lang.invoke.MethodHandles.*; +import static java.lang.invoke.MethodType.*; + +public class Test7082949 implements Runnable { + public static void main(String... args) throws Throwable { + new Thread(new Test7082949()).start(); + } + + public static Test7082949 test() { + return null; + } + + public void run() { + try { + MethodHandle m1 = MethodHandles.lookup().findStatic(Test7082949.class, "test", methodType(Test7082949.class)); + Test7082949 v = (Test7082949)m1.invokeExact(); + } catch (Throwable t) { + t.printStackTrace(); + } + } +}