Merge
This commit is contained in:
commit
48903ca91e
@ -112,3 +112,4 @@ ddc2fcb3682ffd27f44354db666128827be7e3c3 jdk7-b134
|
||||
783bd02b4ab4596059c74b10a1793d7bd2f1c157 jdk7-b135
|
||||
2fe76e73adaa5133ac559f0b3c2c0707eca04580 jdk7-b136
|
||||
7654afc6a29e43cb0a1343ce7f1287bf690d5e5f jdk7-b137
|
||||
fc47c97bbbd91b1f774d855c48a7e285eb1a351a jdk7-b138
|
||||
|
@ -162,3 +162,5 @@ bd586e392d93b7ed7a1636dcc8da2b6a4203a102 jdk7-b136
|
||||
bd586e392d93b7ed7a1636dcc8da2b6a4203a102 hs21-b06
|
||||
2dbcb4a4d8dace5fe78ceb563b134f1fb296cd8f jdk7-b137
|
||||
2dbcb4a4d8dace5fe78ceb563b134f1fb296cd8f hs21-b07
|
||||
0930dc920c185afbf40fed9a655290b8e5b16783 jdk7-b138
|
||||
0930dc920c185afbf40fed9a655290b8e5b16783 hs21-b08
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 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
|
||||
@ -55,7 +55,7 @@ public class HelloWorld {
|
||||
synchronized(lock) {
|
||||
if (useMethodInvoke) {
|
||||
try {
|
||||
Method method = HelloWorld.class.getMethod("e", null);
|
||||
Method method = HelloWorld.class.getMethod("e");
|
||||
Integer result = (Integer) method.invoke(null, new Object[0]);
|
||||
return result.intValue();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -52,12 +52,10 @@ public class ByteValueImpl extends PrimitiveValueImpl
|
||||
return intValue();
|
||||
}
|
||||
|
||||
public int compareTo(Object obj) {
|
||||
byte other = ((ByteValue)obj).value();
|
||||
return value() - other;
|
||||
public int compareTo(ByteValue byteVal) {
|
||||
return value() - byteVal.value();
|
||||
}
|
||||
|
||||
|
||||
public Type type() {
|
||||
return vm.theByteType();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -52,9 +52,8 @@ public class CharValueImpl extends PrimitiveValueImpl
|
||||
return intValue();
|
||||
}
|
||||
|
||||
public int compareTo(Object obj) {
|
||||
char other = ((CharValue)obj).value();
|
||||
return value() - other;
|
||||
public int compareTo(CharValue charVal) {
|
||||
return value() - charVal.value();
|
||||
}
|
||||
|
||||
public Type type() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -186,7 +186,7 @@ abstract class ConnectorImpl implements Connector {
|
||||
// assert isVMVersionMismatch(throwable), "not a VMVersionMismatch"
|
||||
Class expClass = throwable.getClass();
|
||||
Method targetVersionMethod = expClass.getMethod("getTargetVersion", new Class[0]);
|
||||
return (String) targetVersionMethod.invoke(throwable, null);
|
||||
return (String) targetVersionMethod.invoke(throwable);
|
||||
}
|
||||
|
||||
/** If the causal chain has a sun.jvm.hotspot.runtime.VMVersionMismatchException,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -45,8 +45,8 @@ public class DoubleValueImpl extends PrimitiveValueImpl
|
||||
}
|
||||
}
|
||||
|
||||
public int compareTo(Object obj) {
|
||||
double other = ((DoubleValue)obj).value();
|
||||
public int compareTo(DoubleValue doubleVal) {
|
||||
double other = doubleVal.value();
|
||||
if (value() < other) {
|
||||
return -1;
|
||||
} else if (value() == other) {
|
||||
|
@ -145,8 +145,7 @@ public class FieldImpl extends TypeComponentImpl implements Field {
|
||||
}
|
||||
|
||||
// From interface Comparable
|
||||
public int compareTo(Object object) {
|
||||
Field field = (Field)object;
|
||||
public int compareTo(Field field) {
|
||||
ReferenceTypeImpl declaringType = (ReferenceTypeImpl)declaringType();
|
||||
int rc = declaringType.compareTo(field.declaringType());
|
||||
if (rc == 0) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -52,8 +52,8 @@ public class FloatValueImpl extends PrimitiveValueImpl
|
||||
return intValue();
|
||||
}
|
||||
|
||||
public int compareTo(Object obj) {
|
||||
float other = ((FloatValue)obj).value();
|
||||
public int compareTo(FloatValue floatVal) {
|
||||
float other = floatVal.value();
|
||||
if (value() < other) {
|
||||
return -1;
|
||||
} else if (value() == other) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -52,9 +52,8 @@ public class IntegerValueImpl extends PrimitiveValueImpl
|
||||
return intValue();
|
||||
}
|
||||
|
||||
public int compareTo(Object obj) {
|
||||
int other = ((IntegerValue)obj).value();
|
||||
return value() - other;
|
||||
public int compareTo(IntegerValue integerVal) {
|
||||
return value() - integerVal.value();
|
||||
}
|
||||
|
||||
public Type type() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -67,8 +67,8 @@ public class LocalVariableImpl extends MirrorImpl
|
||||
return (int)method.hashCode() + slot();
|
||||
}
|
||||
|
||||
public int compareTo(Object object) {
|
||||
LocalVariableImpl other = (LocalVariableImpl)object;
|
||||
public int compareTo(LocalVariable localVar) {
|
||||
LocalVariableImpl other = (LocalVariableImpl) localVar;
|
||||
int rc = method.compareTo(other.method);
|
||||
if (rc == 0) {
|
||||
rc = slot() - other.slot();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -78,8 +78,7 @@ public class LocationImpl extends MirrorImpl implements Location {
|
||||
return method().hashCode() + (int)codeIndex();
|
||||
}
|
||||
|
||||
public int compareTo(Object object) {
|
||||
LocationImpl other = (LocationImpl)object;
|
||||
public int compareTo(Location other) {
|
||||
int rc = method().compareTo(other.method());
|
||||
if (rc == 0) {
|
||||
long diff = codeIndex() - other.codeIndex();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -52,8 +52,8 @@ public class LongValueImpl extends PrimitiveValueImpl
|
||||
return intValue();
|
||||
}
|
||||
|
||||
public int compareTo(Object obj) {
|
||||
long other = ((LongValue)obj).value();
|
||||
public int compareTo(LongValue longVal) {
|
||||
long other = longVal.value();
|
||||
if (value() < other) {
|
||||
return -1;
|
||||
} else if (value() == other) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -200,8 +200,7 @@ public abstract class MethodImpl extends TypeComponentImpl implements Method {
|
||||
}
|
||||
|
||||
// From interface Comparable
|
||||
public int compareTo(Object object) {
|
||||
Method method = (Method)object;
|
||||
public int compareTo(Method method) {
|
||||
ReferenceTypeImpl declaringType = (ReferenceTypeImpl)declaringType();
|
||||
int rc = declaringType.compareTo(method.declaringType());
|
||||
if (rc == 0) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -99,7 +99,7 @@ implements ReferenceType {
|
||||
return saKlass.hashCode();
|
||||
}
|
||||
|
||||
public int compareTo(Object object) {
|
||||
public int compareTo(ReferenceType refType) {
|
||||
/*
|
||||
* Note that it is critical that compareTo() == 0
|
||||
* implies that equals() == true. Otherwise, TreeSet
|
||||
@ -108,7 +108,7 @@ implements ReferenceType {
|
||||
* (Classes of the same name loaded by different class loaders
|
||||
* or in different VMs must not return 0).
|
||||
*/
|
||||
ReferenceTypeImpl other = (ReferenceTypeImpl)object;
|
||||
ReferenceTypeImpl other = (ReferenceTypeImpl)refType;
|
||||
int comp = name().compareTo(other.name());
|
||||
if (comp == 0) {
|
||||
Oop rf1 = ref();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -52,9 +52,8 @@ public class ShortValueImpl extends PrimitiveValueImpl
|
||||
return intValue();
|
||||
}
|
||||
|
||||
public int compareTo(Object obj) {
|
||||
short other = ((ShortValue)obj).value();
|
||||
return value() - other;
|
||||
public int compareTo(ShortValue shortVal) {
|
||||
return value() - shortVal.value();
|
||||
}
|
||||
|
||||
public Type type() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -798,12 +798,11 @@ public class VirtualMachineImpl extends MirrorImpl implements PathSearchingVirtu
|
||||
}
|
||||
|
||||
public String description() {
|
||||
String[] versionParts = {"" + vmmgr.majorInterfaceVersion(),
|
||||
"" + vmmgr.minorInterfaceVersion(),
|
||||
name()};
|
||||
return java.text.MessageFormat.format(java.util.ResourceBundle.
|
||||
getBundle("com.sun.tools.jdi.resources.jdi").getString("version_format"),
|
||||
versionParts);
|
||||
"" + vmmgr.majorInterfaceVersion(),
|
||||
"" + vmmgr.minorInterfaceVersion(),
|
||||
name());
|
||||
}
|
||||
|
||||
public String version() {
|
||||
|
@ -331,8 +331,6 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||
if (Assert.ASSERTS_ENABLED) {
|
||||
Assert.that(getTagAt(i).isInvokeDynamic(), "Corrupted constant pool");
|
||||
}
|
||||
if (getTagAt(i).value() == JVM_CONSTANT_InvokeDynamicTrans)
|
||||
return null;
|
||||
int bsmSpec = extractLowShortFromInt(this.getIntAt(i));
|
||||
TypeArray operands = getOperands();
|
||||
if (operands == null) return null; // safety first
|
||||
@ -368,7 +366,6 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||
case JVM_CONSTANT_MethodHandle: return "JVM_CONSTANT_MethodHandle";
|
||||
case JVM_CONSTANT_MethodType: return "JVM_CONSTANT_MethodType";
|
||||
case JVM_CONSTANT_InvokeDynamic: return "JVM_CONSTANT_InvokeDynamic";
|
||||
case JVM_CONSTANT_InvokeDynamicTrans: return "JVM_CONSTANT_InvokeDynamic/transitional";
|
||||
case JVM_CONSTANT_Invalid: return "JVM_CONSTANT_Invalid";
|
||||
case JVM_CONSTANT_UnresolvedClass: return "JVM_CONSTANT_UnresolvedClass";
|
||||
case JVM_CONSTANT_UnresolvedClassInError: return "JVM_CONSTANT_UnresolvedClassInError";
|
||||
@ -428,7 +425,6 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||
case JVM_CONSTANT_MethodHandle:
|
||||
case JVM_CONSTANT_MethodType:
|
||||
case JVM_CONSTANT_InvokeDynamic:
|
||||
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||
visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
|
||||
break;
|
||||
}
|
||||
@ -592,7 +588,6 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||
break;
|
||||
}
|
||||
|
||||
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||
case JVM_CONSTANT_InvokeDynamic: {
|
||||
dos.writeByte(cpConstType);
|
||||
int value = getIntAt(ci);
|
||||
|
@ -42,7 +42,7 @@ public interface ClassConstants
|
||||
public static final int JVM_CONSTANT_NameAndType = 12;
|
||||
public static final int JVM_CONSTANT_MethodHandle = 15;
|
||||
public static final int JVM_CONSTANT_MethodType = 16;
|
||||
public static final int JVM_CONSTANT_InvokeDynamicTrans = 17; // only occurs in old class files
|
||||
// static final int JVM_CONSTANT_(unused) = 17;
|
||||
public static final int JVM_CONSTANT_InvokeDynamic = 18;
|
||||
|
||||
// JVM_CONSTANT_MethodHandle subtypes
|
||||
|
@ -321,7 +321,6 @@ public class ClassWriter implements /* imports */ ClassConstants
|
||||
break;
|
||||
}
|
||||
|
||||
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||
case JVM_CONSTANT_InvokeDynamic: {
|
||||
dos.writeByte(cpConstType);
|
||||
int value = cpool.getIntAt(ci);
|
||||
|
@ -598,7 +598,6 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
|
||||
buf.cell(Integer.toString(cpool.getIntAt(index)));
|
||||
break;
|
||||
|
||||
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||
case JVM_CONSTANT_InvokeDynamic:
|
||||
buf.cell("JVM_CONSTANT_InvokeDynamic");
|
||||
buf.cell(genLowHighShort(cpool.getIntAt(index)) +
|
||||
|
@ -40,7 +40,7 @@ public class ConstantTag {
|
||||
private static int JVM_CONSTANT_NameAndType = 12;
|
||||
private static int JVM_CONSTANT_MethodHandle = 15; // JSR 292
|
||||
private static int JVM_CONSTANT_MethodType = 16; // JSR 292
|
||||
private static int JVM_CONSTANT_InvokeDynamicTrans = 17; // JSR 292, only occurs in old class files
|
||||
// static int JVM_CONSTANT_(unused) = 17; // JSR 292 early drafts only
|
||||
private static int JVM_CONSTANT_InvokeDynamic = 18; // JSR 292
|
||||
private static int JVM_CONSTANT_Invalid = 0; // For bad value initialization
|
||||
private static int JVM_CONSTANT_UnresolvedClass = 100; // Temporary tag until actual use
|
||||
@ -83,7 +83,6 @@ public class ConstantTag {
|
||||
public boolean isMethodHandle() { return tag == JVM_CONSTANT_MethodHandle; }
|
||||
public boolean isMethodType() { return tag == JVM_CONSTANT_MethodType; }
|
||||
public boolean isInvokeDynamic() { return tag == JVM_CONSTANT_InvokeDynamic; }
|
||||
public boolean isInvokeDynamicTrans() { return tag == JVM_CONSTANT_InvokeDynamicTrans; }
|
||||
|
||||
public boolean isInvalid() { return tag == JVM_CONSTANT_Invalid; }
|
||||
|
||||
|
@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2011
|
||||
|
||||
HS_MAJOR_VER=21
|
||||
HS_MINOR_VER=0
|
||||
HS_BUILD_NUMBER=08
|
||||
HS_BUILD_NUMBER=09
|
||||
|
||||
JDK_MAJOR_VER=1
|
||||
JDK_MINOR_VER=7
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2003, 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
|
||||
@ -97,8 +97,8 @@ $(GENERATED)/sa-jdi.jar: $(AGENT_FILES1) $(AGENT_FILES2)
|
||||
$(foreach file,$(AGENT_FILES1),$(shell echo $(file) >> $(AGENT_FILES1_LIST)))
|
||||
$(foreach file,$(AGENT_FILES2),$(shell echo $(file) >> $(AGENT_FILES2_LIST)))
|
||||
|
||||
$(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST)
|
||||
$(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST)
|
||||
$(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST)
|
||||
$(QUIETLY) $(REMOTE) $(COMPILE.JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST)
|
||||
|
||||
$(QUIETLY) $(REMOTE) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer
|
||||
$(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES)
|
||||
|
@ -142,13 +142,15 @@ COMPILER2_PATHS += $(HS_COMMON_SRC)/share/vm/opto
|
||||
COMPILER2_PATHS += $(HS_COMMON_SRC)/share/vm/libadt
|
||||
COMPILER2_PATHS += $(GENERATED)/adfiles
|
||||
|
||||
SHARK_PATHS := $(GAMMADIR)/src/share/vm/shark
|
||||
|
||||
# Include dirs per type.
|
||||
Src_Dirs/CORE := $(CORE_PATHS)
|
||||
Src_Dirs/COMPILER1 := $(CORE_PATHS) $(COMPILER1_PATHS)
|
||||
Src_Dirs/COMPILER2 := $(CORE_PATHS) $(COMPILER2_PATHS)
|
||||
Src_Dirs/TIERED := $(CORE_PATHS) $(COMPILER1_PATHS) $(COMPILER2_PATHS)
|
||||
Src_Dirs/ZERO := $(CORE_PATHS)
|
||||
Src_Dirs/SHARK := $(CORE_PATHS)
|
||||
Src_Dirs/SHARK := $(CORE_PATHS) $(SHARK_PATHS)
|
||||
Src_Dirs := $(Src_Dirs/$(TYPE))
|
||||
|
||||
COMPILER2_SPECIFIC_FILES := opto libadt bcEscapeAnalyzer.cpp chaitin\* c2_\* runtime_\*
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2003, 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
|
||||
@ -88,8 +88,8 @@ $(GENERATED)/sa-jdi.jar: $(AGENT_FILES1) $(AGENT_FILES2)
|
||||
$(foreach file,$(AGENT_FILES1),$(shell echo $(file) >> $(AGENT_FILES1_LIST)))
|
||||
$(foreach file,$(AGENT_FILES2),$(shell echo $(file) >> $(AGENT_FILES2_LIST)))
|
||||
|
||||
$(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST)
|
||||
$(QUIETLY) $(COMPILE.JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST)
|
||||
$(QUIETLY) $(COMPILE.JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES1_LIST)
|
||||
$(QUIETLY) $(COMPILE.JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) @$(AGENT_FILES2_LIST)
|
||||
|
||||
$(QUIETLY) $(COMPILE.RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer
|
||||
$(QUIETLY) echo "$(SA_BUILD_VERSION_PROP)" > $(SA_PROPERTIES)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2003, 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
|
||||
@ -55,9 +55,9 @@ default:: $(GENERATED)\sa-jdi.jar
|
||||
$(GENERATED)\sa-jdi.jar: $(AGENT_FILES1:/=\) $(AGENT_FILES2:/=\)
|
||||
@if not exist $(SA_CLASSDIR) mkdir $(SA_CLASSDIR)
|
||||
@echo ...Building sa-jdi.jar
|
||||
@echo ...$(COMPILE_JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -d $(SA_CLASSDIR) ....
|
||||
@$(COMPILE_JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES1:/=\)
|
||||
@$(COMPILE_JAVAC) -source 1.4 -target 1.4 -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES2:/=\)
|
||||
@echo ...$(COMPILE_JAVAC) -classpath $(SA_CLASSPATH) -d $(SA_CLASSDIR) ....
|
||||
@$(COMPILE_JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES1:/=\)
|
||||
@$(COMPILE_JAVAC) -classpath $(SA_CLASSPATH) -sourcepath $(AGENT_SRC_DIR) -d $(SA_CLASSDIR) $(AGENT_FILES2:/=\)
|
||||
$(COMPILE_RMIC) -classpath $(SA_CLASSDIR) -d $(SA_CLASSDIR) sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer
|
||||
$(QUIETLY) echo $(SA_BUILD_VERSION_PROP)> $(SA_PROPERTIES)
|
||||
$(QUIETLY) rm -f $(SA_CLASSDIR)/sun/jvm/hotspot/utilities/soql/sa.js
|
||||
|
@ -2058,6 +2058,13 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL;
|
||||
if (basic_type == T_ARRAY) basic_type = T_OBJECT;
|
||||
|
||||
#ifdef _LP64
|
||||
// higher 32bits must be null
|
||||
__ sra(dst_pos, 0, dst_pos);
|
||||
__ sra(src_pos, 0, src_pos);
|
||||
__ sra(length, 0, length);
|
||||
#endif
|
||||
|
||||
// set up the arraycopy stub information
|
||||
ArrayCopyStub* stub = op->stub();
|
||||
|
||||
@ -2065,20 +2072,36 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
// the known type isn't loaded since the code sanity checks
|
||||
// in debug mode and the type isn't required when we know the exact type
|
||||
// also check that the type is an array type.
|
||||
// We also, for now, always call the stub if the barrier set requires a
|
||||
// write_ref_pre barrier (which the stub does, but none of the optimized
|
||||
// cases currently does).
|
||||
if (op->expected_type() == NULL ||
|
||||
Universe::heap()->barrier_set()->has_write_ref_pre_barrier()) {
|
||||
if (op->expected_type() == NULL) {
|
||||
__ mov(src, O0);
|
||||
__ mov(src_pos, O1);
|
||||
__ mov(dst, O2);
|
||||
__ mov(dst_pos, O3);
|
||||
__ mov(length, O4);
|
||||
__ call_VM_leaf(tmp, CAST_FROM_FN_PTR(address, Runtime1::arraycopy));
|
||||
address copyfunc_addr = StubRoutines::generic_arraycopy();
|
||||
|
||||
__ br_zero(Assembler::less, false, Assembler::pn, O0, *stub->entry());
|
||||
__ delayed()->nop();
|
||||
if (copyfunc_addr == NULL) { // Use C version if stub was not generated
|
||||
__ call_VM_leaf(tmp, CAST_FROM_FN_PTR(address, Runtime1::arraycopy));
|
||||
} else {
|
||||
#ifndef PRODUCT
|
||||
if (PrintC1Statistics) {
|
||||
address counter = (address)&Runtime1::_generic_arraycopystub_cnt;
|
||||
__ inc_counter(counter, G1, G3);
|
||||
}
|
||||
#endif
|
||||
__ call_VM_leaf(tmp, copyfunc_addr);
|
||||
}
|
||||
|
||||
if (copyfunc_addr != NULL) {
|
||||
__ xor3(O0, -1, tmp);
|
||||
__ sub(length, tmp, length);
|
||||
__ add(src_pos, tmp, src_pos);
|
||||
__ br_zero(Assembler::less, false, Assembler::pn, O0, *stub->entry());
|
||||
__ delayed()->add(dst_pos, tmp, dst_pos);
|
||||
} else {
|
||||
__ br_zero(Assembler::less, false, Assembler::pn, O0, *stub->entry());
|
||||
__ delayed()->nop();
|
||||
}
|
||||
__ bind(*stub->continuation());
|
||||
return;
|
||||
}
|
||||
@ -2135,20 +2158,137 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
__ delayed()->nop();
|
||||
}
|
||||
|
||||
int shift = shift_amount(basic_type);
|
||||
|
||||
if (flags & LIR_OpArrayCopy::type_check) {
|
||||
if (UseCompressedOops) {
|
||||
// We don't need decode because we just need to compare
|
||||
__ lduw(src, oopDesc::klass_offset_in_bytes(), tmp);
|
||||
__ lduw(dst, oopDesc::klass_offset_in_bytes(), tmp2);
|
||||
__ cmp(tmp, tmp2);
|
||||
__ br(Assembler::notEqual, false, Assembler::pt, *stub->entry());
|
||||
// We don't know the array types are compatible
|
||||
if (basic_type != T_OBJECT) {
|
||||
// Simple test for basic type arrays
|
||||
if (UseCompressedOops) {
|
||||
// We don't need decode because we just need to compare
|
||||
__ lduw(src, oopDesc::klass_offset_in_bytes(), tmp);
|
||||
__ lduw(dst, oopDesc::klass_offset_in_bytes(), tmp2);
|
||||
__ cmp(tmp, tmp2);
|
||||
__ br(Assembler::notEqual, false, Assembler::pt, *stub->entry());
|
||||
} else {
|
||||
__ ld_ptr(src, oopDesc::klass_offset_in_bytes(), tmp);
|
||||
__ ld_ptr(dst, oopDesc::klass_offset_in_bytes(), tmp2);
|
||||
__ cmp(tmp, tmp2);
|
||||
__ brx(Assembler::notEqual, false, Assembler::pt, *stub->entry());
|
||||
}
|
||||
__ delayed()->nop();
|
||||
} else {
|
||||
__ ld_ptr(src, oopDesc::klass_offset_in_bytes(), tmp);
|
||||
__ ld_ptr(dst, oopDesc::klass_offset_in_bytes(), tmp2);
|
||||
__ cmp(tmp, tmp2);
|
||||
__ brx(Assembler::notEqual, false, Assembler::pt, *stub->entry());
|
||||
// For object arrays, if src is a sub class of dst then we can
|
||||
// safely do the copy.
|
||||
address copyfunc_addr = StubRoutines::checkcast_arraycopy();
|
||||
|
||||
Label cont, slow;
|
||||
assert_different_registers(tmp, tmp2, G3, G1);
|
||||
|
||||
__ load_klass(src, G3);
|
||||
__ load_klass(dst, G1);
|
||||
|
||||
__ check_klass_subtype_fast_path(G3, G1, tmp, tmp2, &cont, copyfunc_addr == NULL ? stub->entry() : &slow, NULL);
|
||||
|
||||
__ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type);
|
||||
__ delayed()->nop();
|
||||
|
||||
__ cmp(G3, 0);
|
||||
if (copyfunc_addr != NULL) { // use stub if available
|
||||
// src is not a sub class of dst so we have to do a
|
||||
// per-element check.
|
||||
__ br(Assembler::notEqual, false, Assembler::pt, cont);
|
||||
__ delayed()->nop();
|
||||
|
||||
__ bind(slow);
|
||||
|
||||
int mask = LIR_OpArrayCopy::src_objarray|LIR_OpArrayCopy::dst_objarray;
|
||||
if ((flags & mask) != mask) {
|
||||
// Check that at least both of them object arrays.
|
||||
assert(flags & mask, "one of the two should be known to be an object array");
|
||||
|
||||
if (!(flags & LIR_OpArrayCopy::src_objarray)) {
|
||||
__ load_klass(src, tmp);
|
||||
} else if (!(flags & LIR_OpArrayCopy::dst_objarray)) {
|
||||
__ load_klass(dst, tmp);
|
||||
}
|
||||
int lh_offset = klassOopDesc::header_size() * HeapWordSize +
|
||||
Klass::layout_helper_offset_in_bytes();
|
||||
|
||||
__ lduw(tmp, lh_offset, tmp2);
|
||||
|
||||
jint objArray_lh = Klass::array_layout_helper(T_OBJECT);
|
||||
__ set(objArray_lh, tmp);
|
||||
__ cmp(tmp, tmp2);
|
||||
__ br(Assembler::notEqual, false, Assembler::pt, *stub->entry());
|
||||
__ delayed()->nop();
|
||||
}
|
||||
|
||||
Register src_ptr = O0;
|
||||
Register dst_ptr = O1;
|
||||
Register len = O2;
|
||||
Register chk_off = O3;
|
||||
Register super_k = O4;
|
||||
|
||||
__ add(src, arrayOopDesc::base_offset_in_bytes(basic_type), src_ptr);
|
||||
if (shift == 0) {
|
||||
__ add(src_ptr, src_pos, src_ptr);
|
||||
} else {
|
||||
__ sll(src_pos, shift, tmp);
|
||||
__ add(src_ptr, tmp, src_ptr);
|
||||
}
|
||||
|
||||
__ add(dst, arrayOopDesc::base_offset_in_bytes(basic_type), dst_ptr);
|
||||
if (shift == 0) {
|
||||
__ add(dst_ptr, dst_pos, dst_ptr);
|
||||
} else {
|
||||
__ sll(dst_pos, shift, tmp);
|
||||
__ add(dst_ptr, tmp, dst_ptr);
|
||||
}
|
||||
__ mov(length, len);
|
||||
__ load_klass(dst, tmp);
|
||||
|
||||
int ek_offset = (klassOopDesc::header_size() * HeapWordSize +
|
||||
objArrayKlass::element_klass_offset_in_bytes());
|
||||
__ ld_ptr(tmp, ek_offset, super_k);
|
||||
|
||||
int sco_offset = (klassOopDesc::header_size() * HeapWordSize +
|
||||
Klass::super_check_offset_offset_in_bytes());
|
||||
__ lduw(super_k, sco_offset, chk_off);
|
||||
|
||||
__ call_VM_leaf(tmp, copyfunc_addr);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (PrintC1Statistics) {
|
||||
Label failed;
|
||||
__ br_notnull(O0, false, Assembler::pn, failed);
|
||||
__ delayed()->nop();
|
||||
__ inc_counter((address)&Runtime1::_arraycopy_checkcast_cnt, G1, G3);
|
||||
__ bind(failed);
|
||||
}
|
||||
#endif
|
||||
|
||||
__ br_null(O0, false, Assembler::pt, *stub->continuation());
|
||||
__ delayed()->xor3(O0, -1, tmp);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (PrintC1Statistics) {
|
||||
__ inc_counter((address)&Runtime1::_arraycopy_checkcast_attempt_cnt, G1, G3);
|
||||
}
|
||||
#endif
|
||||
|
||||
__ sub(length, tmp, length);
|
||||
__ add(src_pos, tmp, src_pos);
|
||||
__ br(Assembler::always, false, Assembler::pt, *stub->entry());
|
||||
__ delayed()->add(dst_pos, tmp, dst_pos);
|
||||
|
||||
__ bind(cont);
|
||||
} else {
|
||||
__ br(Assembler::equal, false, Assembler::pn, *stub->entry());
|
||||
__ delayed()->nop();
|
||||
__ bind(cont);
|
||||
}
|
||||
}
|
||||
__ delayed()->nop();
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
@ -2207,14 +2347,18 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
}
|
||||
#endif
|
||||
|
||||
int shift = shift_amount(basic_type);
|
||||
#ifndef PRODUCT
|
||||
if (PrintC1Statistics) {
|
||||
address counter = Runtime1::arraycopy_count_address(basic_type);
|
||||
__ inc_counter(counter, G1, G3);
|
||||
}
|
||||
#endif
|
||||
|
||||
Register src_ptr = O0;
|
||||
Register dst_ptr = O1;
|
||||
Register len = O2;
|
||||
|
||||
__ add(src, arrayOopDesc::base_offset_in_bytes(basic_type), src_ptr);
|
||||
LP64_ONLY(__ sra(src_pos, 0, src_pos);) //higher 32bits must be null
|
||||
if (shift == 0) {
|
||||
__ add(src_ptr, src_pos, src_ptr);
|
||||
} else {
|
||||
@ -2223,7 +2367,6 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
}
|
||||
|
||||
__ add(dst, arrayOopDesc::base_offset_in_bytes(basic_type), dst_ptr);
|
||||
LP64_ONLY(__ sra(dst_pos, 0, dst_pos);) //higher 32bits must be null
|
||||
if (shift == 0) {
|
||||
__ add(dst_ptr, dst_pos, dst_ptr);
|
||||
} else {
|
||||
@ -2231,18 +2374,14 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
__ add(dst_ptr, tmp, dst_ptr);
|
||||
}
|
||||
|
||||
if (basic_type != T_OBJECT) {
|
||||
if (shift == 0) {
|
||||
__ mov(length, len);
|
||||
} else {
|
||||
__ sll(length, shift, len);
|
||||
}
|
||||
__ call_VM_leaf(tmp, CAST_FROM_FN_PTR(address, Runtime1::primitive_arraycopy));
|
||||
} else {
|
||||
// oop_arraycopy takes a length in number of elements, so don't scale it.
|
||||
__ mov(length, len);
|
||||
__ call_VM_leaf(tmp, CAST_FROM_FN_PTR(address, Runtime1::oop_arraycopy));
|
||||
}
|
||||
bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0;
|
||||
bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0;
|
||||
const char *name;
|
||||
address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false);
|
||||
|
||||
// arraycopy stubs takes a length in number of elements, so don't scale it.
|
||||
__ mov(length, len);
|
||||
__ call_VM_leaf(tmp, entry);
|
||||
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
|
@ -387,7 +387,7 @@ void C1_MacroAssembler::verify_stack_oop(int stack_offset) {
|
||||
|
||||
void C1_MacroAssembler::verify_not_null_oop(Register r) {
|
||||
Label not_null;
|
||||
br_zero(Assembler::notEqual, false, Assembler::pt, r, not_null);
|
||||
br_notnull(r, false, Assembler::pt, not_null);
|
||||
delayed()->nop();
|
||||
stop("non-null oop required");
|
||||
bind(not_null);
|
||||
|
@ -2317,7 +2317,7 @@ void Assembler::prefetchnta(Address src) {
|
||||
}
|
||||
|
||||
void Assembler::prefetchr(Address src) {
|
||||
NOT_LP64(assert(VM_Version::supports_3dnow(), "must support"));
|
||||
NOT_LP64(assert(VM_Version::supports_3dnow_prefetch(), "must support"));
|
||||
InstructionMark im(this);
|
||||
prefetch_prefix(src);
|
||||
emit_byte(0x0D);
|
||||
@ -2349,7 +2349,7 @@ void Assembler::prefetcht2(Address src) {
|
||||
}
|
||||
|
||||
void Assembler::prefetchw(Address src) {
|
||||
NOT_LP64(assert(VM_Version::supports_3dnow(), "must support"));
|
||||
NOT_LP64(assert(VM_Version::supports_3dnow_prefetch(), "must support"));
|
||||
InstructionMark im(this);
|
||||
prefetch_prefix(src);
|
||||
emit_byte(0x0D);
|
||||
@ -7941,12 +7941,12 @@ void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
|
||||
#endif
|
||||
push(rax); // save rax,
|
||||
// addr may contain rsp so we will have to adjust it based on the push
|
||||
// we just did
|
||||
// we just did (and on 64 bit we do two pushes)
|
||||
// NOTE: 64bit seemed to have had a bug in that it did movq(addr, rax); which
|
||||
// stores rax into addr which is backwards of what was intended.
|
||||
if (addr.uses(rsp)) {
|
||||
lea(rax, addr);
|
||||
pushptr(Address(rax, BytesPerWord));
|
||||
pushptr(Address(rax, LP64_ONLY(2 *) BytesPerWord));
|
||||
} else {
|
||||
pushptr(addr);
|
||||
}
|
||||
@ -8396,6 +8396,17 @@ void MacroAssembler::load_heap_oop(Register dst, Address src) {
|
||||
movptr(dst, src);
|
||||
}
|
||||
|
||||
// Doesn't do verfication, generates fixed size code
|
||||
void MacroAssembler::load_heap_oop_not_null(Register dst, Address src) {
|
||||
#ifdef _LP64
|
||||
if (UseCompressedOops) {
|
||||
movl(dst, src);
|
||||
decode_heap_oop_not_null(dst);
|
||||
} else
|
||||
#endif
|
||||
movptr(dst, src);
|
||||
}
|
||||
|
||||
void MacroAssembler::store_heap_oop(Address dst, Register src) {
|
||||
#ifdef _LP64
|
||||
if (UseCompressedOops) {
|
||||
|
@ -385,10 +385,18 @@ class OopAddress: public AddressLiteral {
|
||||
};
|
||||
|
||||
class ExternalAddress: public AddressLiteral {
|
||||
private:
|
||||
static relocInfo::relocType reloc_for_target(address target) {
|
||||
// Sometimes ExternalAddress is used for values which aren't
|
||||
// exactly addresses, like the card table base.
|
||||
// external_word_type can't be used for values in the first page
|
||||
// so just skip the reloc in that case.
|
||||
return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none;
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
ExternalAddress(address target) : AddressLiteral(target, relocInfo::external_word_type){}
|
||||
ExternalAddress(address target) : AddressLiteral(target, reloc_for_target(target)) {}
|
||||
|
||||
};
|
||||
|
||||
@ -1701,6 +1709,7 @@ class MacroAssembler: public Assembler {
|
||||
void store_klass(Register dst, Register src);
|
||||
|
||||
void load_heap_oop(Register dst, Address src);
|
||||
void load_heap_oop_not_null(Register dst, Address src);
|
||||
void store_heap_oop(Address dst, Register src);
|
||||
|
||||
// Used for storing NULL. All other oop constants should be
|
||||
|
@ -316,7 +316,9 @@ void PatchingStub::emit_code(LIR_Assembler* ce) {
|
||||
Register tmp2 = rbx;
|
||||
__ push(tmp);
|
||||
__ push(tmp2);
|
||||
__ load_heap_oop(tmp2, Address(_obj, java_lang_Class::klass_offset_in_bytes()));
|
||||
// Load without verification to keep code size small. We need it because
|
||||
// begin_initialized_entry_offset has to fit in a byte. Also, we know it's not null.
|
||||
__ load_heap_oop_not_null(tmp2, Address(_obj, java_lang_Class::klass_offset_in_bytes()));
|
||||
__ get_thread(tmp);
|
||||
__ cmpptr(tmp, Address(tmp2, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc)));
|
||||
__ pop(tmp2);
|
||||
|
@ -1401,7 +1401,7 @@ void LIR_Assembler::prefetchr(LIR_Opr src) {
|
||||
default:
|
||||
ShouldNotReachHere(); break;
|
||||
}
|
||||
} else if (VM_Version::supports_3dnow()) {
|
||||
} else if (VM_Version::supports_3dnow_prefetch()) {
|
||||
__ prefetchr(from_addr);
|
||||
}
|
||||
}
|
||||
@ -1424,7 +1424,7 @@ void LIR_Assembler::prefetchw(LIR_Opr src) {
|
||||
default:
|
||||
ShouldNotReachHere(); break;
|
||||
}
|
||||
} else if (VM_Version::supports_3dnow()) {
|
||||
} else if (VM_Version::supports_3dnow_prefetch()) {
|
||||
__ prefetchw(from_addr);
|
||||
}
|
||||
}
|
||||
@ -3102,7 +3102,7 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL;
|
||||
if (basic_type == T_ARRAY) basic_type = T_OBJECT;
|
||||
|
||||
// if we don't know anything or it's an object array, just go through the generic arraycopy
|
||||
// if we don't know anything, just go through the generic arraycopy
|
||||
if (default_type == NULL) {
|
||||
Label done;
|
||||
// save outgoing arguments on stack in case call to System.arraycopy is needed
|
||||
@ -3123,7 +3123,9 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
store_parameter(src, 4);
|
||||
NOT_LP64(assert(src == rcx && src_pos == rdx, "mismatch in calling convention");)
|
||||
|
||||
address entry = CAST_FROM_FN_PTR(address, Runtime1::arraycopy);
|
||||
address C_entry = CAST_FROM_FN_PTR(address, Runtime1::arraycopy);
|
||||
|
||||
address copyfunc_addr = StubRoutines::generic_arraycopy();
|
||||
|
||||
// pass arguments: may push as this is not a safepoint; SP must be fix at each safepoint
|
||||
#ifdef _LP64
|
||||
@ -3141,11 +3143,29 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
// Allocate abi space for args but be sure to keep stack aligned
|
||||
__ subptr(rsp, 6*wordSize);
|
||||
store_parameter(j_rarg4, 4);
|
||||
__ call(RuntimeAddress(entry));
|
||||
if (copyfunc_addr == NULL) { // Use C version if stub was not generated
|
||||
__ call(RuntimeAddress(C_entry));
|
||||
} else {
|
||||
#ifndef PRODUCT
|
||||
if (PrintC1Statistics) {
|
||||
__ incrementl(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt));
|
||||
}
|
||||
#endif
|
||||
__ call(RuntimeAddress(copyfunc_addr));
|
||||
}
|
||||
__ addptr(rsp, 6*wordSize);
|
||||
#else
|
||||
__ mov(c_rarg4, j_rarg4);
|
||||
__ call(RuntimeAddress(entry));
|
||||
if (copyfunc_addr == NULL) { // Use C version if stub was not generated
|
||||
__ call(RuntimeAddress(C_entry));
|
||||
} else {
|
||||
#ifndef PRODUCT
|
||||
if (PrintC1Statistics) {
|
||||
__ incrementl(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt));
|
||||
}
|
||||
#endif
|
||||
__ call(RuntimeAddress(copyfunc_addr));
|
||||
}
|
||||
#endif // _WIN64
|
||||
#else
|
||||
__ push(length);
|
||||
@ -3153,13 +3173,28 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
__ push(dst);
|
||||
__ push(src_pos);
|
||||
__ push(src);
|
||||
__ call_VM_leaf(entry, 5); // removes pushed parameter from the stack
|
||||
|
||||
if (copyfunc_addr == NULL) { // Use C version if stub was not generated
|
||||
__ call_VM_leaf(C_entry, 5); // removes pushed parameter from the stack
|
||||
} else {
|
||||
#ifndef PRODUCT
|
||||
if (PrintC1Statistics) {
|
||||
__ incrementl(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt));
|
||||
}
|
||||
#endif
|
||||
__ call_VM_leaf(copyfunc_addr, 5); // removes pushed parameter from the stack
|
||||
}
|
||||
|
||||
#endif // _LP64
|
||||
|
||||
__ cmpl(rax, 0);
|
||||
__ jcc(Assembler::equal, *stub->continuation());
|
||||
|
||||
if (copyfunc_addr != NULL) {
|
||||
__ mov(tmp, rax);
|
||||
__ xorl(tmp, -1);
|
||||
}
|
||||
|
||||
// Reload values from the stack so they are where the stub
|
||||
// expects them.
|
||||
__ movptr (dst, Address(rsp, 0*BytesPerWord));
|
||||
@ -3167,6 +3202,12 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
__ movptr (length, Address(rsp, 2*BytesPerWord));
|
||||
__ movptr (src_pos, Address(rsp, 3*BytesPerWord));
|
||||
__ movptr (src, Address(rsp, 4*BytesPerWord));
|
||||
|
||||
if (copyfunc_addr != NULL) {
|
||||
__ subl(length, tmp);
|
||||
__ addl(src_pos, tmp);
|
||||
__ addl(dst_pos, tmp);
|
||||
}
|
||||
__ jmp(*stub->entry());
|
||||
|
||||
__ bind(*stub->continuation());
|
||||
@ -3226,10 +3267,6 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
__ testl(dst_pos, dst_pos);
|
||||
__ jcc(Assembler::less, *stub->entry());
|
||||
}
|
||||
if (flags & LIR_OpArrayCopy::length_positive_check) {
|
||||
__ testl(length, length);
|
||||
__ jcc(Assembler::less, *stub->entry());
|
||||
}
|
||||
|
||||
if (flags & LIR_OpArrayCopy::src_range_check) {
|
||||
__ lea(tmp, Address(src_pos, length, Address::times_1, 0));
|
||||
@ -3242,15 +3279,190 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
__ jcc(Assembler::above, *stub->entry());
|
||||
}
|
||||
|
||||
if (flags & LIR_OpArrayCopy::length_positive_check) {
|
||||
__ testl(length, length);
|
||||
__ jcc(Assembler::less, *stub->entry());
|
||||
__ jcc(Assembler::zero, *stub->continuation());
|
||||
}
|
||||
|
||||
#ifdef _LP64
|
||||
__ movl2ptr(src_pos, src_pos); //higher 32bits must be null
|
||||
__ movl2ptr(dst_pos, dst_pos); //higher 32bits must be null
|
||||
#endif
|
||||
|
||||
if (flags & LIR_OpArrayCopy::type_check) {
|
||||
if (UseCompressedOops) {
|
||||
__ movl(tmp, src_klass_addr);
|
||||
__ cmpl(tmp, dst_klass_addr);
|
||||
// We don't know the array types are compatible
|
||||
if (basic_type != T_OBJECT) {
|
||||
// Simple test for basic type arrays
|
||||
if (UseCompressedOops) {
|
||||
__ movl(tmp, src_klass_addr);
|
||||
__ cmpl(tmp, dst_klass_addr);
|
||||
} else {
|
||||
__ movptr(tmp, src_klass_addr);
|
||||
__ cmpptr(tmp, dst_klass_addr);
|
||||
}
|
||||
__ jcc(Assembler::notEqual, *stub->entry());
|
||||
} else {
|
||||
__ movptr(tmp, src_klass_addr);
|
||||
__ cmpptr(tmp, dst_klass_addr);
|
||||
// For object arrays, if src is a sub class of dst then we can
|
||||
// safely do the copy.
|
||||
Label cont, slow;
|
||||
|
||||
__ push(src);
|
||||
__ push(dst);
|
||||
|
||||
__ load_klass(src, src);
|
||||
__ load_klass(dst, dst);
|
||||
|
||||
__ check_klass_subtype_fast_path(src, dst, tmp, &cont, &slow, NULL);
|
||||
|
||||
__ push(src);
|
||||
__ push(dst);
|
||||
__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id)));
|
||||
__ pop(dst);
|
||||
__ pop(src);
|
||||
|
||||
__ cmpl(src, 0);
|
||||
__ jcc(Assembler::notEqual, cont);
|
||||
|
||||
__ bind(slow);
|
||||
__ pop(dst);
|
||||
__ pop(src);
|
||||
|
||||
address copyfunc_addr = StubRoutines::checkcast_arraycopy();
|
||||
if (copyfunc_addr != NULL) { // use stub if available
|
||||
// src is not a sub class of dst so we have to do a
|
||||
// per-element check.
|
||||
|
||||
int mask = LIR_OpArrayCopy::src_objarray|LIR_OpArrayCopy::dst_objarray;
|
||||
if ((flags & mask) != mask) {
|
||||
// Check that at least both of them object arrays.
|
||||
assert(flags & mask, "one of the two should be known to be an object array");
|
||||
|
||||
if (!(flags & LIR_OpArrayCopy::src_objarray)) {
|
||||
__ load_klass(tmp, src);
|
||||
} else if (!(flags & LIR_OpArrayCopy::dst_objarray)) {
|
||||
__ load_klass(tmp, dst);
|
||||
}
|
||||
int lh_offset = klassOopDesc::header_size() * HeapWordSize +
|
||||
Klass::layout_helper_offset_in_bytes();
|
||||
Address klass_lh_addr(tmp, lh_offset);
|
||||
jint objArray_lh = Klass::array_layout_helper(T_OBJECT);
|
||||
__ cmpl(klass_lh_addr, objArray_lh);
|
||||
__ jcc(Assembler::notEqual, *stub->entry());
|
||||
}
|
||||
|
||||
#ifndef _LP64
|
||||
// save caller save registers
|
||||
store_parameter(rax, 2);
|
||||
store_parameter(rcx, 1);
|
||||
store_parameter(rdx, 0);
|
||||
|
||||
__ movptr(tmp, dst_klass_addr);
|
||||
__ movptr(tmp, Address(tmp, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc)));
|
||||
__ push(tmp);
|
||||
__ movl(tmp, Address(tmp, Klass::super_check_offset_offset_in_bytes() + sizeof(oopDesc)));
|
||||
__ push(tmp);
|
||||
__ push(length);
|
||||
__ lea(tmp, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
|
||||
__ push(tmp);
|
||||
__ lea(tmp, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
|
||||
__ push(tmp);
|
||||
|
||||
__ call_VM_leaf(copyfunc_addr, 5);
|
||||
#else
|
||||
__ movl2ptr(length, length); //higher 32bits must be null
|
||||
|
||||
// save caller save registers: copy them to callee save registers
|
||||
__ mov(rbx, rdx);
|
||||
__ mov(r13, r8);
|
||||
__ mov(r14, r9);
|
||||
#ifndef _WIN64
|
||||
store_parameter(rsi, 1);
|
||||
store_parameter(rcx, 0);
|
||||
// on WIN64 other incoming parameters are in rdi and rsi saved
|
||||
// across the call
|
||||
#endif
|
||||
|
||||
__ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
|
||||
assert_different_registers(c_rarg0, dst, dst_pos, length);
|
||||
__ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
|
||||
assert_different_registers(c_rarg1, dst, length);
|
||||
|
||||
__ mov(c_rarg2, length);
|
||||
assert_different_registers(c_rarg2, dst);
|
||||
|
||||
#ifdef _WIN64
|
||||
// Allocate abi space for args but be sure to keep stack aligned
|
||||
__ subptr(rsp, 6*wordSize);
|
||||
__ load_klass(c_rarg3, dst);
|
||||
__ movptr(c_rarg3, Address(c_rarg3, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc)));
|
||||
store_parameter(c_rarg3, 4);
|
||||
__ movl(c_rarg3, Address(c_rarg3, Klass::super_check_offset_offset_in_bytes() + sizeof(oopDesc)));
|
||||
__ call(RuntimeAddress(copyfunc_addr));
|
||||
__ addptr(rsp, 6*wordSize);
|
||||
#else
|
||||
__ load_klass(c_rarg4, dst);
|
||||
__ movptr(c_rarg4, Address(c_rarg4, objArrayKlass::element_klass_offset_in_bytes() + sizeof(oopDesc)));
|
||||
__ movl(c_rarg3, Address(c_rarg4, Klass::super_check_offset_offset_in_bytes() + sizeof(oopDesc)));
|
||||
__ call(RuntimeAddress(copyfunc_addr));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (PrintC1Statistics) {
|
||||
Label failed;
|
||||
__ testl(rax, rax);
|
||||
__ jcc(Assembler::notZero, failed);
|
||||
__ incrementl(ExternalAddress((address)&Runtime1::_arraycopy_checkcast_cnt));
|
||||
__ bind(failed);
|
||||
}
|
||||
#endif
|
||||
|
||||
__ testl(rax, rax);
|
||||
__ jcc(Assembler::zero, *stub->continuation());
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (PrintC1Statistics) {
|
||||
__ incrementl(ExternalAddress((address)&Runtime1::_arraycopy_checkcast_attempt_cnt));
|
||||
}
|
||||
#endif
|
||||
|
||||
__ mov(tmp, rax);
|
||||
|
||||
__ xorl(tmp, -1);
|
||||
|
||||
#ifndef _LP64
|
||||
// restore caller save registers
|
||||
assert_different_registers(tmp, rdx, rcx, rax); // result of stub will be lost
|
||||
__ movptr(rdx, Address(rsp, 0*BytesPerWord));
|
||||
__ movptr(rcx, Address(rsp, 1*BytesPerWord));
|
||||
__ movptr(rax, Address(rsp, 2*BytesPerWord));
|
||||
#else
|
||||
// restore caller save registers
|
||||
__ mov(rdx, rbx);
|
||||
__ mov(r8, r13);
|
||||
__ mov(r9, r14);
|
||||
#ifndef _WIN64
|
||||
assert_different_registers(tmp, rdx, r8, r9, rcx, rsi); // result of stub will be lost
|
||||
__ movptr(rcx, Address(rsp, 0*BytesPerWord));
|
||||
__ movptr(rsi, Address(rsp, 1*BytesPerWord));
|
||||
#else
|
||||
assert_different_registers(tmp, rdx, r8, r9); // result of stub will be lost
|
||||
#endif
|
||||
#endif
|
||||
|
||||
__ subl(length, tmp);
|
||||
__ addl(src_pos, tmp);
|
||||
__ addl(dst_pos, tmp);
|
||||
}
|
||||
|
||||
__ jmp(*stub->entry());
|
||||
|
||||
__ bind(cont);
|
||||
__ pop(dst);
|
||||
__ pop(src);
|
||||
}
|
||||
__ jcc(Assembler::notEqual, *stub->entry());
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
@ -3291,16 +3503,16 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (shift_amount > 0 && basic_type != T_OBJECT) {
|
||||
__ shlptr(length, shift_amount);
|
||||
#ifndef PRODUCT
|
||||
if (PrintC1Statistics) {
|
||||
__ incrementl(ExternalAddress(Runtime1::arraycopy_count_address(basic_type)));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _LP64
|
||||
assert_different_registers(c_rarg0, dst, dst_pos, length);
|
||||
__ movl2ptr(src_pos, src_pos); //higher 32bits must be null
|
||||
__ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
|
||||
assert_different_registers(c_rarg1, length);
|
||||
__ movl2ptr(dst_pos, dst_pos); //higher 32bits must be null
|
||||
__ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type)));
|
||||
__ mov(c_rarg2, length);
|
||||
|
||||
@ -3311,11 +3523,12 @@ void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
|
||||
store_parameter(tmp, 1);
|
||||
store_parameter(length, 2);
|
||||
#endif // _LP64
|
||||
if (basic_type == T_OBJECT) {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, Runtime1::oop_arraycopy), 0);
|
||||
} else {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, Runtime1::primitive_arraycopy), 0);
|
||||
}
|
||||
|
||||
bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0;
|
||||
bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0;
|
||||
const char *name;
|
||||
address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false);
|
||||
__ call_VM_leaf(entry, 0);
|
||||
|
||||
__ bind(*stub->continuation());
|
||||
}
|
||||
|
@ -348,7 +348,7 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
|
||||
char buf[256];
|
||||
jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||
cores_per_cpu(), threads_per_core(),
|
||||
cpu_family(), _model, _stepping,
|
||||
(supports_cmov() ? ", cmov" : ""),
|
||||
@ -363,8 +363,7 @@ void VM_Version::get_processor_features() {
|
||||
(supports_sse4_2() ? ", sse4.2" : ""),
|
||||
(supports_popcnt() ? ", popcnt" : ""),
|
||||
(supports_mmx_ext() ? ", mmxext" : ""),
|
||||
(supports_3dnow() ? ", 3dnow" : ""),
|
||||
(supports_3dnow2() ? ", 3dnowext" : ""),
|
||||
(supports_3dnow_prefetch() ? ", 3dnowpref" : ""),
|
||||
(supports_lzcnt() ? ", lzcnt": ""),
|
||||
(supports_sse4a() ? ", sse4a": ""),
|
||||
(supports_ht() ? ", ht": ""));
|
||||
@ -522,13 +521,13 @@ void VM_Version::get_processor_features() {
|
||||
// set valid Prefetch instruction
|
||||
if( ReadPrefetchInstr < 0 ) ReadPrefetchInstr = 0;
|
||||
if( ReadPrefetchInstr > 3 ) ReadPrefetchInstr = 3;
|
||||
if( ReadPrefetchInstr == 3 && !supports_3dnow() ) ReadPrefetchInstr = 0;
|
||||
if( !supports_sse() && supports_3dnow() ) ReadPrefetchInstr = 3;
|
||||
if( ReadPrefetchInstr == 3 && !supports_3dnow_prefetch() ) ReadPrefetchInstr = 0;
|
||||
if( !supports_sse() && supports_3dnow_prefetch() ) ReadPrefetchInstr = 3;
|
||||
|
||||
if( AllocatePrefetchInstr < 0 ) AllocatePrefetchInstr = 0;
|
||||
if( AllocatePrefetchInstr > 3 ) AllocatePrefetchInstr = 3;
|
||||
if( AllocatePrefetchInstr == 3 && !supports_3dnow() ) AllocatePrefetchInstr=0;
|
||||
if( !supports_sse() && supports_3dnow() ) AllocatePrefetchInstr = 3;
|
||||
if( AllocatePrefetchInstr == 3 && !supports_3dnow_prefetch() ) AllocatePrefetchInstr=0;
|
||||
if( !supports_sse() && supports_3dnow_prefetch() ) AllocatePrefetchInstr = 3;
|
||||
|
||||
// Allocation prefetch settings
|
||||
intx cache_line_size = L1_data_cache_line_size();
|
||||
@ -576,10 +575,10 @@ void VM_Version::get_processor_features() {
|
||||
logical_processors_per_package());
|
||||
tty->print_cr("UseSSE=%d",UseSSE);
|
||||
tty->print("Allocation: ");
|
||||
if (AllocatePrefetchStyle <= 0 || UseSSE == 0 && !supports_3dnow()) {
|
||||
if (AllocatePrefetchStyle <= 0 || UseSSE == 0 && !supports_3dnow_prefetch()) {
|
||||
tty->print_cr("no prefetching");
|
||||
} else {
|
||||
if (UseSSE == 0 && supports_3dnow()) {
|
||||
if (UseSSE == 0 && supports_3dnow_prefetch()) {
|
||||
tty->print("PREFETCHW");
|
||||
} else if (UseSSE >= 1) {
|
||||
if (AllocatePrefetchInstr == 0) {
|
||||
|
@ -188,7 +188,8 @@ protected:
|
||||
CPU_FXSR = (1 << 2),
|
||||
CPU_HT = (1 << 3),
|
||||
CPU_MMX = (1 << 4),
|
||||
CPU_3DNOW = (1 << 5), // 3DNow comes from cpuid 0x80000001 (EDX)
|
||||
CPU_3DNOW_PREFETCH = (1 << 5), // Processor supports 3dnow prefetch and prefetchw instructions
|
||||
// may not necessarily support other 3dnow instructions
|
||||
CPU_SSE = (1 << 6),
|
||||
CPU_SSE2 = (1 << 7),
|
||||
CPU_SSE3 = (1 << 8), // SSE3 comes from cpuid 1 (ECX)
|
||||
@ -328,8 +329,9 @@ protected:
|
||||
|
||||
// AMD features.
|
||||
if (is_amd()) {
|
||||
if (_cpuid_info.ext_cpuid1_edx.bits.tdnow != 0)
|
||||
result |= CPU_3DNOW;
|
||||
if ((_cpuid_info.ext_cpuid1_edx.bits.tdnow != 0) ||
|
||||
(_cpuid_info.ext_cpuid1_ecx.bits.prefetchw != 0))
|
||||
result |= CPU_3DNOW_PREFETCH;
|
||||
if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt != 0)
|
||||
result |= CPU_LZCNT;
|
||||
if (_cpuid_info.ext_cpuid1_ecx.bits.sse4a != 0)
|
||||
@ -446,9 +448,8 @@ public:
|
||||
//
|
||||
// AMD features
|
||||
//
|
||||
static bool supports_3dnow() { return (_cpuFeatures & CPU_3DNOW) != 0; }
|
||||
static bool supports_3dnow_prefetch() { return (_cpuFeatures & CPU_3DNOW_PREFETCH) != 0; }
|
||||
static bool supports_mmx_ext() { return is_amd() && _cpuid_info.ext_cpuid1_edx.bits.mmx_amd != 0; }
|
||||
static bool supports_3dnow2() { return is_amd() && _cpuid_info.ext_cpuid1_edx.bits.tdnow2 != 0; }
|
||||
static bool supports_lzcnt() { return (_cpuFeatures & CPU_LZCNT) != 0; }
|
||||
static bool supports_sse4a() { return (_cpuFeatures & CPU_SSE4A) != 0; }
|
||||
|
||||
|
@ -3423,7 +3423,7 @@ encode %{
|
||||
masm.movptr(boxReg, tmpReg); // consider: LEA box, [tmp-2]
|
||||
|
||||
// Using a prefetchw helps avoid later RTS->RTO upgrades and cache probes
|
||||
if ((EmitSync & 2048) && VM_Version::supports_3dnow() && os::is_MP()) {
|
||||
if ((EmitSync & 2048) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) {
|
||||
// prefetchw [eax + Offset(_owner)-2]
|
||||
masm.prefetchw(Address(rax, ObjectMonitor::owner_offset_in_bytes()-2));
|
||||
}
|
||||
@ -3467,7 +3467,7 @@ encode %{
|
||||
masm.movptr(boxReg, tmpReg) ;
|
||||
|
||||
// Using a prefetchw helps avoid later RTS->RTO upgrades and cache probes
|
||||
if ((EmitSync & 2048) && VM_Version::supports_3dnow() && os::is_MP()) {
|
||||
if ((EmitSync & 2048) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) {
|
||||
// prefetchw [eax + Offset(_owner)-2]
|
||||
masm.prefetchw(Address(rax, ObjectMonitor::owner_offset_in_bytes()-2));
|
||||
}
|
||||
@ -3614,7 +3614,7 @@ encode %{
|
||||
// See also http://gee.cs.oswego.edu/dl/jmm/cookbook.html.
|
||||
|
||||
masm.get_thread (boxReg) ;
|
||||
if ((EmitSync & 4096) && VM_Version::supports_3dnow() && os::is_MP()) {
|
||||
if ((EmitSync & 4096) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) {
|
||||
// prefetchw [ebx + Offset(_owner)-2]
|
||||
masm.prefetchw(Address(rbx, ObjectMonitor::owner_offset_in_bytes()-2));
|
||||
}
|
||||
@ -7333,7 +7333,7 @@ instruct loadSSD(regD dst, stackSlotD src) %{
|
||||
// Must be safe to execute with invalid address (cannot fault).
|
||||
|
||||
instruct prefetchr0( memory mem ) %{
|
||||
predicate(UseSSE==0 && !VM_Version::supports_3dnow());
|
||||
predicate(UseSSE==0 && !VM_Version::supports_3dnow_prefetch());
|
||||
match(PrefetchRead mem);
|
||||
ins_cost(0);
|
||||
size(0);
|
||||
@ -7343,7 +7343,7 @@ instruct prefetchr0( memory mem ) %{
|
||||
%}
|
||||
|
||||
instruct prefetchr( memory mem ) %{
|
||||
predicate(UseSSE==0 && VM_Version::supports_3dnow() || ReadPrefetchInstr==3);
|
||||
predicate(UseSSE==0 && VM_Version::supports_3dnow_prefetch() || ReadPrefetchInstr==3);
|
||||
match(PrefetchRead mem);
|
||||
ins_cost(100);
|
||||
|
||||
@ -7387,7 +7387,7 @@ instruct prefetchrT2( memory mem ) %{
|
||||
%}
|
||||
|
||||
instruct prefetchw0( memory mem ) %{
|
||||
predicate(UseSSE==0 && !VM_Version::supports_3dnow());
|
||||
predicate(UseSSE==0 && !VM_Version::supports_3dnow_prefetch());
|
||||
match(PrefetchWrite mem);
|
||||
ins_cost(0);
|
||||
size(0);
|
||||
@ -7397,7 +7397,7 @@ instruct prefetchw0( memory mem ) %{
|
||||
%}
|
||||
|
||||
instruct prefetchw( memory mem ) %{
|
||||
predicate(UseSSE==0 && VM_Version::supports_3dnow() || AllocatePrefetchInstr==3);
|
||||
predicate(UseSSE==0 && VM_Version::supports_3dnow_prefetch() || AllocatePrefetchInstr==3);
|
||||
match( PrefetchWrite mem );
|
||||
ins_cost(100);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2007, 2008 Red Hat, Inc.
|
||||
* Copyright 2007, 2008, 2011 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -150,4 +150,22 @@
|
||||
#define SET_LOCALS_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = \
|
||||
((VMJavaVal64*)(addr))->l)
|
||||
|
||||
// VMSlots implementation
|
||||
|
||||
#define VMSLOTS_SLOT(offset) ((intptr_t*)&vmslots[(offset)])
|
||||
#define VMSLOTS_ADDR(offset) ((address)vmslots[(offset)])
|
||||
#define VMSLOTS_INT(offset) (*((jint*)&vmslots[(offset)]))
|
||||
#define VMSLOTS_FLOAT(offset) (*((jfloat*)&vmslots[(offset)]))
|
||||
#define VMSLOTS_OBJECT(offset) ((oop)vmslots[(offset)])
|
||||
#define VMSLOTS_DOUBLE(offset) (((VMJavaVal64*)&vmslots[(offset) - 1])->d)
|
||||
#define VMSLOTS_LONG(offset) (((VMJavaVal64*)&vmslots[(offset) - 1])->l)
|
||||
|
||||
#define SET_VMSLOTS_SLOT(value, offset) (*(intptr_t*)&vmslots[(offset)] = *(intptr_t *)(value))
|
||||
#define SET_VMSLOTS_ADDR(value, offset) (*((address *)&vmslots[(offset)]) = (value))
|
||||
#define SET_VMSLOTS_INT(value, offset) (*((jint *)&vmslots[(offset)]) = (value))
|
||||
#define SET_VMSLOTS_FLOAT(value, offset) (*((jfloat *)&vmslots[(offset)]) = (value))
|
||||
#define SET_VMSLOTS_OBJECT(value, offset) (*((oop *)&vmslots[(offset)]) = (value))
|
||||
#define SET_VMSLOTS_DOUBLE(value, offset) (((VMJavaVal64*)&vmslots[(offset) - 1])->d = (value))
|
||||
#define SET_VMSLOTS_LONG(value, offset) (((VMJavaVal64*)&vmslots[(offset) - 1])->l = (value))
|
||||
|
||||
#endif // CPU_ZERO_VM_BYTECODEINTERPRETER_ZERO_HPP
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2007, 2008, 2009, 2010 Red Hat, Inc.
|
||||
* Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -56,10 +56,13 @@
|
||||
#define fixup_after_potential_safepoint() \
|
||||
method = istate->method()
|
||||
|
||||
#define CALL_VM_NOCHECK(func) \
|
||||
#define CALL_VM_NOCHECK_NOFIX(func) \
|
||||
thread->set_last_Java_frame(); \
|
||||
func; \
|
||||
thread->reset_last_Java_frame(); \
|
||||
thread->reset_last_Java_frame();
|
||||
|
||||
#define CALL_VM_NOCHECK(func) \
|
||||
CALL_VM_NOCHECK_NOFIX(func) \
|
||||
fixup_after_potential_safepoint()
|
||||
|
||||
int CppInterpreter::normal_entry(methodOop method, intptr_t UNUSED, TRAPS) {
|
||||
@ -177,6 +180,25 @@ void CppInterpreter::main_loop(int recurse, TRAPS) {
|
||||
method, istate->osr_entry(), istate->osr_buf(), THREAD);
|
||||
return;
|
||||
}
|
||||
else if (istate->msg() == BytecodeInterpreter::call_method_handle) {
|
||||
oop method_handle = istate->callee();
|
||||
|
||||
// Trim back the stack to put the parameters at the top
|
||||
stack->set_sp(istate->stack() + 1);
|
||||
|
||||
// Make the call
|
||||
process_method_handle(method_handle, THREAD);
|
||||
fixup_after_potential_safepoint();
|
||||
|
||||
// Convert the result
|
||||
istate->set_stack(stack->sp() - 1);
|
||||
|
||||
// Restore the stack
|
||||
stack->set_sp(istate->stack_limit() + 1);
|
||||
|
||||
// Resume the interpreter
|
||||
istate->set_msg(BytecodeInterpreter::method_resume);
|
||||
}
|
||||
else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
@ -607,6 +629,549 @@ int CppInterpreter::empty_entry(methodOop method, intptr_t UNUSED, TRAPS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CppInterpreter::method_handle_entry(methodOop method,
|
||||
intptr_t UNUSED, TRAPS) {
|
||||
JavaThread *thread = (JavaThread *) THREAD;
|
||||
ZeroStack *stack = thread->zero_stack();
|
||||
int argument_slots = method->size_of_parameters();
|
||||
int result_slots = type2size[result_type_of(method)];
|
||||
intptr_t *vmslots = stack->sp();
|
||||
intptr_t *unwind_sp = vmslots + argument_slots;
|
||||
|
||||
// Find the MethodType
|
||||
address p = (address) method;
|
||||
for (jint* pc = method->method_type_offsets_chain(); (*pc) != -1; pc++) {
|
||||
p = *(address*)(p + (*pc));
|
||||
}
|
||||
oop method_type = (oop) p;
|
||||
|
||||
// The MethodHandle is in the slot after the arguments
|
||||
oop form = java_lang_invoke_MethodType::form(method_type);
|
||||
int num_vmslots = java_lang_invoke_MethodTypeForm::vmslots(form);
|
||||
assert(argument_slots == num_vmslots + 1, "should be");
|
||||
oop method_handle = VMSLOTS_OBJECT(num_vmslots);
|
||||
|
||||
// InvokeGeneric requires some extra shuffling
|
||||
oop mhtype = java_lang_invoke_MethodHandle::type(method_handle);
|
||||
bool is_exact = mhtype == method_type;
|
||||
if (!is_exact) {
|
||||
if (method->intrinsic_id() == vmIntrinsics::_invokeExact) {
|
||||
CALL_VM_NOCHECK_NOFIX(
|
||||
InterpreterRuntime::throw_WrongMethodTypeException(
|
||||
thread, method_type, mhtype));
|
||||
// NB all oops trashed!
|
||||
assert(HAS_PENDING_EXCEPTION, "should do");
|
||||
stack->set_sp(unwind_sp);
|
||||
return 0;
|
||||
}
|
||||
assert(method->intrinsic_id() == vmIntrinsics::_invokeGeneric, "should be");
|
||||
|
||||
// Load up an adapter from the calling type
|
||||
// NB the x86 code for this (in methodHandles_x86.cpp, search for
|
||||
// "genericInvoker") is really really odd. I'm hoping it's trying
|
||||
// to accomodate odd VM/class library combinations I can ignore.
|
||||
oop adapter = java_lang_invoke_MethodTypeForm::genericInvoker(form);
|
||||
if (adapter == NULL) {
|
||||
CALL_VM_NOCHECK_NOFIX(
|
||||
InterpreterRuntime::throw_WrongMethodTypeException(
|
||||
thread, method_type, mhtype));
|
||||
// NB all oops trashed!
|
||||
assert(HAS_PENDING_EXCEPTION, "should do");
|
||||
stack->set_sp(unwind_sp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Adapters are shared among form-families of method-type. The
|
||||
// type being called is passed as a trusted first argument so that
|
||||
// the adapter knows the actual types of its arguments and return
|
||||
// values.
|
||||
insert_vmslots(num_vmslots + 1, 1, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
// NB all oops trashed!
|
||||
stack->set_sp(unwind_sp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vmslots = stack->sp();
|
||||
num_vmslots++;
|
||||
SET_VMSLOTS_OBJECT(method_type, num_vmslots);
|
||||
|
||||
method_handle = adapter;
|
||||
}
|
||||
|
||||
// Start processing
|
||||
process_method_handle(method_handle, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION)
|
||||
result_slots = 0;
|
||||
|
||||
// If this is an invokeExact then the eventual callee will not
|
||||
// have unwound the method handle argument so we have to do it.
|
||||
// If a result is being returned the it will be above the method
|
||||
// handle argument we're unwinding.
|
||||
if (is_exact) {
|
||||
intptr_t result[2];
|
||||
for (int i = 0; i < result_slots; i++)
|
||||
result[i] = stack->pop();
|
||||
stack->pop();
|
||||
for (int i = result_slots - 1; i >= 0; i--)
|
||||
stack->push(result[i]);
|
||||
}
|
||||
|
||||
// Check
|
||||
assert(stack->sp() == unwind_sp - result_slots, "should be");
|
||||
|
||||
// No deoptimized frames on the stack
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CppInterpreter::process_method_handle(oop method_handle, TRAPS) {
|
||||
JavaThread *thread = (JavaThread *) THREAD;
|
||||
ZeroStack *stack = thread->zero_stack();
|
||||
intptr_t *vmslots = stack->sp();
|
||||
|
||||
bool direct_to_method = false;
|
||||
BasicType src_rtype = T_ILLEGAL;
|
||||
BasicType dst_rtype = T_ILLEGAL;
|
||||
|
||||
MethodHandleEntry *entry =
|
||||
java_lang_invoke_MethodHandle::vmentry(method_handle);
|
||||
MethodHandles::EntryKind entry_kind =
|
||||
(MethodHandles::EntryKind) (((intptr_t) entry) & 0xffffffff);
|
||||
|
||||
methodOop method = NULL;
|
||||
switch (entry_kind) {
|
||||
case MethodHandles::_invokestatic_mh:
|
||||
direct_to_method = true;
|
||||
break;
|
||||
|
||||
case MethodHandles::_invokespecial_mh:
|
||||
case MethodHandles::_invokevirtual_mh:
|
||||
case MethodHandles::_invokeinterface_mh:
|
||||
{
|
||||
oop receiver =
|
||||
VMSLOTS_OBJECT(
|
||||
java_lang_invoke_MethodHandle::vmslots(method_handle) - 1);
|
||||
if (receiver == NULL) {
|
||||
stack->set_sp(calculate_unwind_sp(stack, method_handle));
|
||||
CALL_VM_NOCHECK_NOFIX(
|
||||
throw_exception(
|
||||
thread, vmSymbols::java_lang_NullPointerException()));
|
||||
// NB all oops trashed!
|
||||
assert(HAS_PENDING_EXCEPTION, "should do");
|
||||
return;
|
||||
}
|
||||
if (entry_kind != MethodHandles::_invokespecial_mh) {
|
||||
int index = java_lang_invoke_DirectMethodHandle::vmindex(method_handle);
|
||||
instanceKlass* rcvrKlass =
|
||||
(instanceKlass *) receiver->klass()->klass_part();
|
||||
if (entry_kind == MethodHandles::_invokevirtual_mh) {
|
||||
method = (methodOop) rcvrKlass->start_of_vtable()[index];
|
||||
}
|
||||
else {
|
||||
oop iclass = java_lang_invoke_MethodHandle::vmtarget(method_handle);
|
||||
itableOffsetEntry* ki =
|
||||
(itableOffsetEntry *) rcvrKlass->start_of_itable();
|
||||
int i, length = rcvrKlass->itable_length();
|
||||
for (i = 0; i < length; i++, ki++ ) {
|
||||
if (ki->interface_klass() == iclass)
|
||||
break;
|
||||
}
|
||||
if (i == length) {
|
||||
stack->set_sp(calculate_unwind_sp(stack, method_handle));
|
||||
CALL_VM_NOCHECK_NOFIX(
|
||||
throw_exception(
|
||||
thread, vmSymbols::java_lang_IncompatibleClassChangeError()));
|
||||
// NB all oops trashed!
|
||||
assert(HAS_PENDING_EXCEPTION, "should do");
|
||||
return;
|
||||
}
|
||||
itableMethodEntry* im = ki->first_method_entry(receiver->klass());
|
||||
method = im[index].method();
|
||||
if (method == NULL) {
|
||||
stack->set_sp(calculate_unwind_sp(stack, method_handle));
|
||||
CALL_VM_NOCHECK_NOFIX(
|
||||
throw_exception(
|
||||
thread, vmSymbols::java_lang_AbstractMethodError()));
|
||||
// NB all oops trashed!
|
||||
assert(HAS_PENDING_EXCEPTION, "should do");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
direct_to_method = true;
|
||||
break;
|
||||
|
||||
case MethodHandles::_bound_ref_direct_mh:
|
||||
case MethodHandles::_bound_int_direct_mh:
|
||||
case MethodHandles::_bound_long_direct_mh:
|
||||
direct_to_method = true;
|
||||
// fall through
|
||||
case MethodHandles::_bound_ref_mh:
|
||||
case MethodHandles::_bound_int_mh:
|
||||
case MethodHandles::_bound_long_mh:
|
||||
{
|
||||
BasicType arg_type = T_ILLEGAL;
|
||||
int arg_mask = -1;
|
||||
int arg_slots = -1;
|
||||
MethodHandles::get_ek_bound_mh_info(
|
||||
entry_kind, arg_type, arg_mask, arg_slots);
|
||||
int arg_slot =
|
||||
java_lang_invoke_BoundMethodHandle::vmargslot(method_handle);
|
||||
|
||||
// Create the new slot(s)
|
||||
intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
|
||||
insert_vmslots(arg_slot, arg_slots, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
// all oops trashed
|
||||
stack->set_sp(unwind_sp);
|
||||
return;
|
||||
}
|
||||
vmslots = stack->sp();
|
||||
|
||||
// Store bound argument into new stack slot
|
||||
oop arg = java_lang_invoke_BoundMethodHandle::argument(method_handle);
|
||||
if (arg_type == T_OBJECT) {
|
||||
assert(arg_slots == 1, "should be");
|
||||
SET_VMSLOTS_OBJECT(arg, arg_slot);
|
||||
}
|
||||
else {
|
||||
jvalue arg_value;
|
||||
arg_type = java_lang_boxing_object::get_value(arg, &arg_value);
|
||||
switch (arg_type) {
|
||||
case T_BOOLEAN:
|
||||
SET_VMSLOTS_INT(arg_value.z, arg_slot);
|
||||
break;
|
||||
case T_CHAR:
|
||||
SET_VMSLOTS_INT(arg_value.c, arg_slot);
|
||||
break;
|
||||
case T_BYTE:
|
||||
SET_VMSLOTS_INT(arg_value.b, arg_slot);
|
||||
break;
|
||||
case T_SHORT:
|
||||
SET_VMSLOTS_INT(arg_value.s, arg_slot);
|
||||
break;
|
||||
case T_INT:
|
||||
SET_VMSLOTS_INT(arg_value.i, arg_slot);
|
||||
break;
|
||||
case T_FLOAT:
|
||||
SET_VMSLOTS_FLOAT(arg_value.f, arg_slot);
|
||||
break;
|
||||
case T_LONG:
|
||||
SET_VMSLOTS_LONG(arg_value.j, arg_slot + 1);
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
SET_VMSLOTS_DOUBLE(arg_value.d, arg_slot + 1);
|
||||
break;
|
||||
default:
|
||||
tty->print_cr("unhandled type %s", type2name(arg_type));
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MethodHandles::_adapter_retype_only:
|
||||
case MethodHandles::_adapter_retype_raw:
|
||||
src_rtype = result_type_of_handle(
|
||||
java_lang_invoke_MethodHandle::vmtarget(method_handle));
|
||||
dst_rtype = result_type_of_handle(method_handle);
|
||||
break;
|
||||
|
||||
case MethodHandles::_adapter_check_cast:
|
||||
{
|
||||
int arg_slot =
|
||||
java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
|
||||
oop arg = VMSLOTS_OBJECT(arg_slot);
|
||||
if (arg != NULL) {
|
||||
klassOop objKlassOop = arg->klass();
|
||||
klassOop klassOf = java_lang_Class::as_klassOop(
|
||||
java_lang_invoke_AdapterMethodHandle::argument(method_handle));
|
||||
|
||||
if (objKlassOop != klassOf &&
|
||||
!objKlassOop->klass_part()->is_subtype_of(klassOf)) {
|
||||
ResourceMark rm(THREAD);
|
||||
const char* objName = Klass::cast(objKlassOop)->external_name();
|
||||
const char* klassName = Klass::cast(klassOf)->external_name();
|
||||
char* message = SharedRuntime::generate_class_cast_message(
|
||||
objName, klassName);
|
||||
|
||||
stack->set_sp(calculate_unwind_sp(stack, method_handle));
|
||||
CALL_VM_NOCHECK_NOFIX(
|
||||
throw_exception(
|
||||
thread, vmSymbols::java_lang_ClassCastException(), message));
|
||||
// NB all oops trashed!
|
||||
assert(HAS_PENDING_EXCEPTION, "should do");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MethodHandles::_adapter_dup_args:
|
||||
{
|
||||
int arg_slot =
|
||||
java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
|
||||
int conv =
|
||||
java_lang_invoke_AdapterMethodHandle::conversion(method_handle);
|
||||
int num_slots = -MethodHandles::adapter_conversion_stack_move(conv);
|
||||
assert(num_slots > 0, "should be");
|
||||
|
||||
// Create the new slot(s)
|
||||
intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
|
||||
stack->overflow_check(num_slots, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
// all oops trashed
|
||||
stack->set_sp(unwind_sp);
|
||||
return;
|
||||
}
|
||||
|
||||
// Duplicate the arguments
|
||||
for (int i = num_slots - 1; i >= 0; i--)
|
||||
stack->push(*VMSLOTS_SLOT(arg_slot + i));
|
||||
|
||||
vmslots = stack->sp(); // unused, but let the compiler figure that out
|
||||
}
|
||||
break;
|
||||
|
||||
case MethodHandles::_adapter_drop_args:
|
||||
{
|
||||
int arg_slot =
|
||||
java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
|
||||
int conv =
|
||||
java_lang_invoke_AdapterMethodHandle::conversion(method_handle);
|
||||
int num_slots = MethodHandles::adapter_conversion_stack_move(conv);
|
||||
assert(num_slots > 0, "should be");
|
||||
|
||||
remove_vmslots(arg_slot, num_slots, THREAD); // doesn't trap
|
||||
vmslots = stack->sp(); // unused, but let the compiler figure that out
|
||||
}
|
||||
break;
|
||||
|
||||
case MethodHandles::_adapter_opt_swap_1:
|
||||
case MethodHandles::_adapter_opt_swap_2:
|
||||
case MethodHandles::_adapter_opt_rot_1_up:
|
||||
case MethodHandles::_adapter_opt_rot_1_down:
|
||||
case MethodHandles::_adapter_opt_rot_2_up:
|
||||
case MethodHandles::_adapter_opt_rot_2_down:
|
||||
{
|
||||
int arg1 =
|
||||
java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
|
||||
int conv =
|
||||
java_lang_invoke_AdapterMethodHandle::conversion(method_handle);
|
||||
int arg2 = MethodHandles::adapter_conversion_vminfo(conv);
|
||||
|
||||
int swap_bytes = 0, rotate = 0;
|
||||
MethodHandles::get_ek_adapter_opt_swap_rot_info(
|
||||
entry_kind, swap_bytes, rotate);
|
||||
int swap_slots = swap_bytes >> LogBytesPerWord;
|
||||
|
||||
intptr_t tmp;
|
||||
switch (rotate) {
|
||||
case 0: // swap
|
||||
for (int i = 0; i < swap_slots; i++) {
|
||||
tmp = *VMSLOTS_SLOT(arg1 + i);
|
||||
SET_VMSLOTS_SLOT(VMSLOTS_SLOT(arg2 + i), arg1 + i);
|
||||
SET_VMSLOTS_SLOT(&tmp, arg2 + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // up
|
||||
assert(arg1 - swap_slots > arg2, "should be");
|
||||
|
||||
tmp = *VMSLOTS_SLOT(arg1);
|
||||
for (int i = arg1 - swap_slots; i >= arg2; i--)
|
||||
SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i + swap_slots);
|
||||
SET_VMSLOTS_SLOT(&tmp, arg2);
|
||||
|
||||
break;
|
||||
|
||||
case -1: // down
|
||||
assert(arg2 - swap_slots > arg1, "should be");
|
||||
|
||||
tmp = *VMSLOTS_SLOT(arg1);
|
||||
for (int i = arg1 + swap_slots; i <= arg2; i++)
|
||||
SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i - swap_slots);
|
||||
SET_VMSLOTS_SLOT(&tmp, arg2);
|
||||
break;
|
||||
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MethodHandles::_adapter_opt_i2l:
|
||||
{
|
||||
int arg_slot =
|
||||
java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
|
||||
int arg = VMSLOTS_INT(arg_slot);
|
||||
intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
|
||||
insert_vmslots(arg_slot, 1, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
// all oops trashed
|
||||
stack->set_sp(unwind_sp);
|
||||
return;
|
||||
}
|
||||
vmslots = stack->sp();
|
||||
arg_slot++;
|
||||
SET_VMSLOTS_LONG(arg, arg_slot);
|
||||
}
|
||||
break;
|
||||
|
||||
case MethodHandles::_adapter_opt_unboxi:
|
||||
case MethodHandles::_adapter_opt_unboxl:
|
||||
{
|
||||
int arg_slot =
|
||||
java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
|
||||
oop arg = VMSLOTS_OBJECT(arg_slot);
|
||||
jvalue arg_value;
|
||||
BasicType arg_type = java_lang_boxing_object::get_value(arg, &arg_value);
|
||||
if (arg_type == T_LONG || arg_type == T_DOUBLE) {
|
||||
intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
|
||||
insert_vmslots(arg_slot, 1, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
// all oops trashed
|
||||
stack->set_sp(unwind_sp);
|
||||
return;
|
||||
}
|
||||
vmslots = stack->sp();
|
||||
arg_slot++;
|
||||
}
|
||||
switch (arg_type) {
|
||||
case T_BOOLEAN:
|
||||
SET_VMSLOTS_INT(arg_value.z, arg_slot);
|
||||
break;
|
||||
case T_CHAR:
|
||||
SET_VMSLOTS_INT(arg_value.c, arg_slot);
|
||||
break;
|
||||
case T_BYTE:
|
||||
SET_VMSLOTS_INT(arg_value.b, arg_slot);
|
||||
break;
|
||||
case T_SHORT:
|
||||
SET_VMSLOTS_INT(arg_value.s, arg_slot);
|
||||
break;
|
||||
case T_INT:
|
||||
SET_VMSLOTS_INT(arg_value.i, arg_slot);
|
||||
break;
|
||||
case T_FLOAT:
|
||||
SET_VMSLOTS_FLOAT(arg_value.f, arg_slot);
|
||||
break;
|
||||
case T_LONG:
|
||||
SET_VMSLOTS_LONG(arg_value.j, arg_slot);
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
SET_VMSLOTS_DOUBLE(arg_value.d, arg_slot);
|
||||
break;
|
||||
default:
|
||||
tty->print_cr("unhandled type %s", type2name(arg_type));
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
tty->print_cr("unhandled entry_kind %s",
|
||||
MethodHandles::entry_name(entry_kind));
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
// Continue along the chain
|
||||
if (direct_to_method) {
|
||||
if (method == NULL) {
|
||||
method =
|
||||
(methodOop) java_lang_invoke_MethodHandle::vmtarget(method_handle);
|
||||
}
|
||||
address entry_point = method->from_interpreted_entry();
|
||||
Interpreter::invoke_method(method, entry_point, THREAD);
|
||||
}
|
||||
else {
|
||||
process_method_handle(
|
||||
java_lang_invoke_MethodHandle::vmtarget(method_handle), THREAD);
|
||||
}
|
||||
// NB all oops now trashed
|
||||
|
||||
// Adapt the result type, if necessary
|
||||
if (src_rtype != dst_rtype && !HAS_PENDING_EXCEPTION) {
|
||||
switch (dst_rtype) {
|
||||
case T_VOID:
|
||||
for (int i = 0; i < type2size[src_rtype]; i++)
|
||||
stack->pop();
|
||||
return;
|
||||
|
||||
case T_INT:
|
||||
switch (src_rtype) {
|
||||
case T_VOID:
|
||||
stack->overflow_check(1, CHECK);
|
||||
stack->push(0);
|
||||
return;
|
||||
|
||||
case T_BOOLEAN:
|
||||
case T_CHAR:
|
||||
case T_BYTE:
|
||||
case T_SHORT:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tty->print_cr("unhandled conversion:");
|
||||
tty->print_cr("src_rtype = %s", type2name(src_rtype));
|
||||
tty->print_cr("dst_rtype = %s", type2name(dst_rtype));
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
// The new slots will be inserted before slot insert_before.
|
||||
// Slots < insert_before will have the same slot number after the insert.
|
||||
// Slots >= insert_before will become old_slot + num_slots.
|
||||
void CppInterpreter::insert_vmslots(int insert_before, int num_slots, TRAPS) {
|
||||
JavaThread *thread = (JavaThread *) THREAD;
|
||||
ZeroStack *stack = thread->zero_stack();
|
||||
|
||||
// Allocate the space
|
||||
stack->overflow_check(num_slots, CHECK);
|
||||
stack->alloc(num_slots * wordSize);
|
||||
intptr_t *vmslots = stack->sp();
|
||||
|
||||
// Shuffle everything up
|
||||
for (int i = 0; i < insert_before; i++)
|
||||
SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i + num_slots), i);
|
||||
}
|
||||
|
||||
void CppInterpreter::remove_vmslots(int first_slot, int num_slots, TRAPS) {
|
||||
JavaThread *thread = (JavaThread *) THREAD;
|
||||
ZeroStack *stack = thread->zero_stack();
|
||||
intptr_t *vmslots = stack->sp();
|
||||
|
||||
// Move everything down
|
||||
for (int i = first_slot - 1; i >= 0; i--)
|
||||
SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i + num_slots);
|
||||
|
||||
// Deallocate the space
|
||||
stack->set_sp(stack->sp() + num_slots);
|
||||
}
|
||||
|
||||
BasicType CppInterpreter::result_type_of_handle(oop method_handle) {
|
||||
oop method_type = java_lang_invoke_MethodHandle::type(method_handle);
|
||||
oop return_type = java_lang_invoke_MethodType::rtype(method_type);
|
||||
return java_lang_Class::as_BasicType(return_type, (klassOop *) NULL);
|
||||
}
|
||||
|
||||
intptr_t* CppInterpreter::calculate_unwind_sp(ZeroStack* stack,
|
||||
oop method_handle) {
|
||||
oop method_type = java_lang_invoke_MethodHandle::type(method_handle);
|
||||
oop form = java_lang_invoke_MethodType::form(method_type);
|
||||
int argument_slots = java_lang_invoke_MethodTypeForm::vmslots(form);
|
||||
|
||||
return stack->sp() + argument_slots;
|
||||
}
|
||||
|
||||
IRT_ENTRY(void, CppInterpreter::throw_exception(JavaThread* thread,
|
||||
Symbol* name,
|
||||
char* message))
|
||||
THROW_MSG(name, message);
|
||||
IRT_END
|
||||
|
||||
InterpreterFrame *InterpreterFrame::build(const methodOop method, TRAPS) {
|
||||
JavaThread *thread = (JavaThread *) THREAD;
|
||||
ZeroStack *stack = thread->zero_stack();
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2007, 2008, 2010 Red Hat, Inc.
|
||||
* Copyright 2007, 2008, 2010, 2011 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -36,11 +36,21 @@
|
||||
static int native_entry(methodOop method, intptr_t UNUSED, TRAPS);
|
||||
static int accessor_entry(methodOop method, intptr_t UNUSED, TRAPS);
|
||||
static int empty_entry(methodOop method, intptr_t UNUSED, TRAPS);
|
||||
static int method_handle_entry(methodOop method, intptr_t UNUSED, TRAPS);
|
||||
|
||||
public:
|
||||
// Main loop of normal_entry
|
||||
static void main_loop(int recurse, TRAPS);
|
||||
|
||||
private:
|
||||
// Helpers for method_handle_entry
|
||||
static void process_method_handle(oop method_handle, TRAPS);
|
||||
static void insert_vmslots(int insert_before, int num_slots, TRAPS);
|
||||
static void remove_vmslots(int first_slot, int num_slots, TRAPS);
|
||||
static BasicType result_type_of_handle(oop method_handle);
|
||||
static intptr_t* calculate_unwind_sp(ZeroStack* stack, oop method_handle);
|
||||
static void throw_exception(JavaThread* thread, Symbol* name,char *msg=NULL);
|
||||
|
||||
private:
|
||||
// Fast result type determination
|
||||
static BasicType result_type_of(methodOop method);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2007, 2008, 2009, 2010 Red Hat, Inc.
|
||||
* Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -54,4 +54,6 @@ define_pd_global(bool, RewriteFrequentPairs, true);
|
||||
|
||||
define_pd_global(bool, UseMembar, false);
|
||||
|
||||
// GC Ergo Flags
|
||||
define_pd_global(intx, CMSYoungGenPerWorker, 16*M); // default max size of CMS young gen, per GC worker thread
|
||||
#endif // CPU_ZERO_VM_GLOBALS_ZERO_HPP
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2007, 2008, 2009, 2010 Red Hat, Inc.
|
||||
* Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -49,6 +49,9 @@
|
||||
#ifdef COMPILER1
|
||||
#include "c1/c1_Runtime1.hpp"
|
||||
#endif
|
||||
#ifdef CC_INTERP
|
||||
#include "interpreter/cppInterpreter.hpp"
|
||||
#endif
|
||||
|
||||
address AbstractInterpreterGenerator::generate_slow_signature_handler() {
|
||||
_masm->advance(1);
|
||||
@ -64,11 +67,15 @@ address InterpreterGenerator::generate_math_entry(
|
||||
}
|
||||
|
||||
address InterpreterGenerator::generate_abstract_entry() {
|
||||
return ShouldNotCallThisEntry();
|
||||
return generate_entry((address) ShouldNotCallThisEntry());
|
||||
}
|
||||
|
||||
address InterpreterGenerator::generate_method_handle_entry() {
|
||||
return ShouldNotCallThisEntry();
|
||||
#ifdef CC_INTERP
|
||||
return generate_entry((address) CppInterpreter::method_handle_entry);
|
||||
#else
|
||||
return generate_entry((address) ShouldNotCallThisEntry());
|
||||
#endif // CC_INTERP
|
||||
}
|
||||
|
||||
bool AbstractInterpreter::can_be_compiled(methodHandle m) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2009, 2010 Red Hat, Inc.
|
||||
* Copyright 2009, 2010, 2011 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,10 +29,21 @@
|
||||
#include "prims/methodHandles.hpp"
|
||||
|
||||
int MethodHandles::adapter_conversion_ops_supported_mask() {
|
||||
ShouldNotCallThis();
|
||||
return ((1<<java_lang_invoke_AdapterMethodHandle::OP_RETYPE_ONLY)
|
||||
|(1<<java_lang_invoke_AdapterMethodHandle::OP_RETYPE_RAW)
|
||||
|(1<<java_lang_invoke_AdapterMethodHandle::OP_CHECK_CAST)
|
||||
|(1<<java_lang_invoke_AdapterMethodHandle::OP_PRIM_TO_PRIM)
|
||||
|(1<<java_lang_invoke_AdapterMethodHandle::OP_REF_TO_PRIM)
|
||||
|(1<<java_lang_invoke_AdapterMethodHandle::OP_SWAP_ARGS)
|
||||
|(1<<java_lang_invoke_AdapterMethodHandle::OP_ROT_ARGS)
|
||||
|(1<<java_lang_invoke_AdapterMethodHandle::OP_DUP_ARGS)
|
||||
|(1<<java_lang_invoke_AdapterMethodHandle::OP_DROP_ARGS)
|
||||
//|(1<<java_lang_invoke_AdapterMethodHandle::OP_SPREAD_ARGS) //BUG!
|
||||
);
|
||||
// FIXME: MethodHandlesTest gets a crash if we enable OP_SPREAD_ARGS.
|
||||
}
|
||||
|
||||
void MethodHandles::generate_method_handle_stub(MacroAssembler* masm,
|
||||
MethodHandles::EntryKind ek) {
|
||||
ShouldNotCallThis();
|
||||
init_entry(ek, (MethodHandleEntry *) ek);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2007, 2009 Red Hat, Inc.
|
||||
* Copyright 2007, 2009, 2010, 2011 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,7 +31,7 @@
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
|
||||
void Relocation::pd_set_data_value(address x, intptr_t o) {
|
||||
void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) {
|
||||
ShouldNotCallThis();
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2007, 2008, 2009, 2010 Red Hat, Inc.
|
||||
* Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -78,15 +78,17 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(
|
||||
|
||||
nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
methodHandle method,
|
||||
int total_in_args,
|
||||
int comp_args_on_stack,
|
||||
BasicType *in_sig_bt,
|
||||
VMRegPair *in_regs,
|
||||
int compile_id,
|
||||
int total_args_passed,
|
||||
int max_arg,
|
||||
BasicType *sig_bt,
|
||||
VMRegPair *regs,
|
||||
BasicType ret_type) {
|
||||
#ifdef SHARK
|
||||
return SharkCompiler::compiler()->generate_native_wrapper(masm,
|
||||
method,
|
||||
in_sig_bt,
|
||||
compile_id,
|
||||
sig_bt,
|
||||
ret_type);
|
||||
#else
|
||||
ShouldNotCallThis();
|
||||
|
@ -2648,45 +2648,39 @@ bool os::uncommit_memory(char* addr, size_t size) {
|
||||
// writing thread stacks don't use growable mappings (i.e. those
|
||||
// creeated with MAP_GROWSDOWN), and aren't marked "[stack]", so this
|
||||
// only applies to the main thread.
|
||||
static bool
|
||||
get_stack_bounds(uintptr_t *bottom, uintptr_t *top)
|
||||
{
|
||||
FILE *f = fopen("/proc/self/maps", "r");
|
||||
if (f == NULL)
|
||||
|
||||
static
|
||||
bool get_stack_bounds(uintptr_t *bottom, uintptr_t *top) {
|
||||
|
||||
char buf[128];
|
||||
int fd, sz;
|
||||
|
||||
if ((fd = ::open("/proc/self/maps", O_RDONLY)) < 0) {
|
||||
return false;
|
||||
|
||||
while (!feof(f)) {
|
||||
size_t dummy;
|
||||
char *str = NULL;
|
||||
ssize_t len = getline(&str, &dummy, f);
|
||||
if (len == -1) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (len > 0 && str[len-1] == '\n') {
|
||||
str[len-1] = 0;
|
||||
len--;
|
||||
}
|
||||
|
||||
static const char *stack_str = "[stack]";
|
||||
if (len > (ssize_t)strlen(stack_str)
|
||||
&& (strcmp(str + len - strlen(stack_str), stack_str) == 0)) {
|
||||
if (sscanf(str, "%" SCNxPTR "-%" SCNxPTR, bottom, top) == 2) {
|
||||
uintptr_t sp = (uintptr_t)__builtin_frame_address(0);
|
||||
if (sp >= *bottom && sp <= *top) {
|
||||
free(str);
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
const char kw[] = "[stack]";
|
||||
const int kwlen = sizeof(kw)-1;
|
||||
|
||||
// Address part of /proc/self/maps couldn't be more than 128 bytes
|
||||
while ((sz = os::get_line_chars(fd, buf, sizeof(buf))) > 0) {
|
||||
if (sz > kwlen && ::memcmp(buf+sz-kwlen, kw, kwlen) == 0) {
|
||||
// Extract addresses
|
||||
if (sscanf(buf, "%" SCNxPTR "-%" SCNxPTR, bottom, top) == 2) {
|
||||
uintptr_t sp = (uintptr_t) __builtin_frame_address(0);
|
||||
if (sp >= *bottom && sp <= *top) {
|
||||
::close(fd);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// If the (growable) stack mapping already extends beyond the point
|
||||
// where we're going to put our guard pages, truncate the mapping at
|
||||
// that point by munmap()ping it. This ensures that when we later
|
||||
|
@ -497,6 +497,9 @@ class CompilerInterfaceVC10 extends CompilerInterface {
|
||||
addAttr(rv, "TargetMachine", "MachineX64");
|
||||
}
|
||||
|
||||
// We always want the /DEBUG option to get full symbol information in the pdb files
|
||||
addAttr(rv, "GenerateDebugInformation", "true");
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -504,8 +507,7 @@ class CompilerInterfaceVC10 extends CompilerInterface {
|
||||
Vector getDebugLinkerFlags() {
|
||||
Vector rv = new Vector();
|
||||
|
||||
// /DEBUG option
|
||||
addAttr(rv, "GenerateDebugInformation", "true");
|
||||
// Empty now that /DEBUG option is used by all configs
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -2824,7 +2824,7 @@ ValueStack* GraphBuilder::state_at_entry() {
|
||||
int idx = 0;
|
||||
if (!method()->is_static()) {
|
||||
// we should always see the receiver
|
||||
state->store_local(idx, new Local(objectType, idx));
|
||||
state->store_local(idx, new Local(method()->holder(), objectType, idx));
|
||||
idx = 1;
|
||||
}
|
||||
|
||||
@ -2836,7 +2836,7 @@ ValueStack* GraphBuilder::state_at_entry() {
|
||||
// don't allow T_ARRAY to propagate into locals types
|
||||
if (basic_type == T_ARRAY) basic_type = T_OBJECT;
|
||||
ValueType* vt = as_ValueType(basic_type);
|
||||
state->store_local(idx, new Local(vt, idx));
|
||||
state->store_local(idx, new Local(type, vt, idx));
|
||||
idx += type->size();
|
||||
}
|
||||
|
||||
|
@ -135,6 +135,33 @@ bool AccessIndexed::compute_needs_range_check() {
|
||||
}
|
||||
|
||||
|
||||
ciType* Local::exact_type() const {
|
||||
ciType* type = declared_type();
|
||||
|
||||
// for primitive arrays, the declared type is the exact type
|
||||
if (type->is_type_array_klass()) {
|
||||
return type;
|
||||
} else if (type->is_instance_klass()) {
|
||||
ciInstanceKlass* ik = (ciInstanceKlass*)type;
|
||||
if (ik->is_loaded() && ik->is_final() && !ik->is_interface()) {
|
||||
return type;
|
||||
}
|
||||
} else if (type->is_obj_array_klass()) {
|
||||
ciObjArrayKlass* oak = (ciObjArrayKlass*)type;
|
||||
ciType* base = oak->base_element_type();
|
||||
if (base->is_instance_klass()) {
|
||||
ciInstanceKlass* ik = base->as_instance_klass();
|
||||
if (ik->is_loaded() && ik->is_final()) {
|
||||
return type;
|
||||
}
|
||||
} else if (base->is_primitive_type()) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ciType* LoadIndexed::exact_type() const {
|
||||
ciType* array_type = array()->exact_type();
|
||||
if (array_type == NULL) {
|
||||
@ -189,16 +216,21 @@ ciType* NewTypeArray::exact_type() const {
|
||||
return ciTypeArrayKlass::make(elt_type());
|
||||
}
|
||||
|
||||
|
||||
ciType* NewObjectArray::exact_type() const {
|
||||
return ciObjArrayKlass::make(klass());
|
||||
}
|
||||
|
||||
ciType* NewArray::declared_type() const {
|
||||
return exact_type();
|
||||
}
|
||||
|
||||
ciType* NewInstance::exact_type() const {
|
||||
return klass();
|
||||
}
|
||||
|
||||
ciType* NewInstance::declared_type() const {
|
||||
return exact_type();
|
||||
}
|
||||
|
||||
ciType* CheckCast::declared_type() const {
|
||||
return klass();
|
||||
@ -349,6 +381,11 @@ void Invoke::state_values_do(ValueVisitor* f) {
|
||||
if (state() != NULL) state()->values_do(f);
|
||||
}
|
||||
|
||||
ciType* Invoke::declared_type() const {
|
||||
ciType *t = _target->signature()->return_type();
|
||||
assert(t->basic_type() != T_VOID, "need return value of void method?");
|
||||
return t;
|
||||
}
|
||||
|
||||
// Implementation of Contant
|
||||
intx Constant::hash() const {
|
||||
|
@ -621,16 +621,21 @@ LEAF(Phi, Instruction)
|
||||
LEAF(Local, Instruction)
|
||||
private:
|
||||
int _java_index; // the local index within the method to which the local belongs
|
||||
ciType* _declared_type;
|
||||
public:
|
||||
// creation
|
||||
Local(ValueType* type, int index)
|
||||
Local(ciType* declared, ValueType* type, int index)
|
||||
: Instruction(type)
|
||||
, _java_index(index)
|
||||
, _declared_type(declared)
|
||||
{}
|
||||
|
||||
// accessors
|
||||
int java_index() const { return _java_index; }
|
||||
|
||||
ciType* declared_type() const { return _declared_type; }
|
||||
ciType* exact_type() const;
|
||||
|
||||
// generic
|
||||
virtual void input_values_do(ValueVisitor* f) { /* no values */ }
|
||||
};
|
||||
@ -1146,6 +1151,8 @@ LEAF(Invoke, StateSplit)
|
||||
BasicTypeList* signature() const { return _signature; }
|
||||
ciMethod* target() const { return _target; }
|
||||
|
||||
ciType* declared_type() const;
|
||||
|
||||
// Returns false if target is not loaded
|
||||
bool target_is_final() const { return check_flag(TargetIsFinalFlag); }
|
||||
bool target_is_loaded() const { return check_flag(TargetIsLoadedFlag); }
|
||||
@ -1187,6 +1194,7 @@ LEAF(NewInstance, StateSplit)
|
||||
// generic
|
||||
virtual bool can_trap() const { return true; }
|
||||
ciType* exact_type() const;
|
||||
ciType* declared_type() const;
|
||||
};
|
||||
|
||||
|
||||
@ -1208,6 +1216,8 @@ BASE(NewArray, StateSplit)
|
||||
|
||||
virtual bool needs_exception_state() const { return false; }
|
||||
|
||||
ciType* declared_type() const;
|
||||
|
||||
// generic
|
||||
virtual bool can_trap() const { return true; }
|
||||
virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_length); }
|
||||
@ -1397,6 +1407,7 @@ LEAF(Intrinsic, StateSplit)
|
||||
vmIntrinsics::ID _id;
|
||||
Values* _args;
|
||||
Value _recv;
|
||||
int _nonnull_state; // mask identifying which args are nonnull
|
||||
|
||||
public:
|
||||
// preserves_state can be set to true for Intrinsics
|
||||
@ -1417,6 +1428,7 @@ LEAF(Intrinsic, StateSplit)
|
||||
, _id(id)
|
||||
, _args(args)
|
||||
, _recv(NULL)
|
||||
, _nonnull_state(AllBits)
|
||||
{
|
||||
assert(args != NULL, "args must exist");
|
||||
ASSERT_VALUES
|
||||
@ -1442,6 +1454,23 @@ LEAF(Intrinsic, StateSplit)
|
||||
Value receiver() const { assert(has_receiver(), "must have receiver"); return _recv; }
|
||||
bool preserves_state() const { return check_flag(PreservesStateFlag); }
|
||||
|
||||
bool arg_needs_null_check(int i) {
|
||||
if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
|
||||
return is_set_nth_bit(_nonnull_state, i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_arg_needs_null_check(int i, bool check) {
|
||||
if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
|
||||
if (check) {
|
||||
_nonnull_state |= nth_bit(i);
|
||||
} else {
|
||||
_nonnull_state &= ~(nth_bit(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generic
|
||||
virtual bool can_trap() const { return check_flag(CanTrapFlag); }
|
||||
virtual void input_values_do(ValueVisitor* f) {
|
||||
|
@ -1215,7 +1215,11 @@ public:
|
||||
src_range_check = 1 << 5,
|
||||
dst_range_check = 1 << 6,
|
||||
type_check = 1 << 7,
|
||||
all_flags = (1 << 8) - 1
|
||||
overlapping = 1 << 8,
|
||||
unaligned = 1 << 9,
|
||||
src_objarray = 1 << 10,
|
||||
dst_objarray = 1 << 11,
|
||||
all_flags = (1 << 12) - 1
|
||||
};
|
||||
|
||||
LIR_OpArrayCopy(LIR_Opr src, LIR_Opr src_pos, LIR_Opr dst, LIR_Opr dst_pos, LIR_Opr length, LIR_Opr tmp,
|
||||
|
@ -836,6 +836,9 @@ void LIR_Assembler::verify_oop_map(CodeEmitInfo* info) {
|
||||
_masm->verify_stack_oop(r->reg2stack() * VMRegImpl::stack_slot_size);
|
||||
}
|
||||
}
|
||||
check_codespace();
|
||||
CHECK_BAILOUT();
|
||||
|
||||
s.next();
|
||||
}
|
||||
VerifyOops = v;
|
||||
|
@ -706,6 +706,38 @@ static ciArrayKlass* as_array_klass(ciType* type) {
|
||||
}
|
||||
}
|
||||
|
||||
static Value maxvalue(IfOp* ifop) {
|
||||
switch (ifop->cond()) {
|
||||
case If::eql: return NULL;
|
||||
case If::neq: return NULL;
|
||||
case If::lss: // x < y ? x : y
|
||||
case If::leq: // x <= y ? x : y
|
||||
if (ifop->x() == ifop->tval() &&
|
||||
ifop->y() == ifop->fval()) return ifop->y();
|
||||
return NULL;
|
||||
|
||||
case If::gtr: // x > y ? y : x
|
||||
case If::geq: // x >= y ? y : x
|
||||
if (ifop->x() == ifop->tval() &&
|
||||
ifop->y() == ifop->fval()) return ifop->y();
|
||||
return NULL;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static ciType* phi_declared_type(Phi* phi) {
|
||||
ciType* t = phi->operand_at(0)->declared_type();
|
||||
if (t == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
for(int i = 1; i < phi->operand_count(); i++) {
|
||||
if (t != phi->operand_at(i)->declared_type()) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void LIRGenerator::arraycopy_helper(Intrinsic* x, int* flagsp, ciArrayKlass** expected_typep) {
|
||||
Instruction* src = x->argument_at(0);
|
||||
Instruction* src_pos = x->argument_at(1);
|
||||
@ -715,12 +747,20 @@ void LIRGenerator::arraycopy_helper(Intrinsic* x, int* flagsp, ciArrayKlass** ex
|
||||
|
||||
// first try to identify the likely type of the arrays involved
|
||||
ciArrayKlass* expected_type = NULL;
|
||||
bool is_exact = false;
|
||||
bool is_exact = false, src_objarray = false, dst_objarray = false;
|
||||
{
|
||||
ciArrayKlass* src_exact_type = as_array_klass(src->exact_type());
|
||||
ciArrayKlass* src_declared_type = as_array_klass(src->declared_type());
|
||||
Phi* phi;
|
||||
if (src_declared_type == NULL && (phi = src->as_Phi()) != NULL) {
|
||||
src_declared_type = as_array_klass(phi_declared_type(phi));
|
||||
}
|
||||
ciArrayKlass* dst_exact_type = as_array_klass(dst->exact_type());
|
||||
ciArrayKlass* dst_declared_type = as_array_klass(dst->declared_type());
|
||||
if (dst_declared_type == NULL && (phi = dst->as_Phi()) != NULL) {
|
||||
dst_declared_type = as_array_klass(phi_declared_type(phi));
|
||||
}
|
||||
|
||||
if (src_exact_type != NULL && src_exact_type == dst_exact_type) {
|
||||
// the types exactly match so the type is fully known
|
||||
is_exact = true;
|
||||
@ -744,17 +784,60 @@ void LIRGenerator::arraycopy_helper(Intrinsic* x, int* flagsp, ciArrayKlass** ex
|
||||
if (expected_type == NULL) expected_type = dst_exact_type;
|
||||
if (expected_type == NULL) expected_type = src_declared_type;
|
||||
if (expected_type == NULL) expected_type = dst_declared_type;
|
||||
|
||||
src_objarray = (src_exact_type && src_exact_type->is_obj_array_klass()) || (src_declared_type && src_declared_type->is_obj_array_klass());
|
||||
dst_objarray = (dst_exact_type && dst_exact_type->is_obj_array_klass()) || (dst_declared_type && dst_declared_type->is_obj_array_klass());
|
||||
}
|
||||
|
||||
// if a probable array type has been identified, figure out if any
|
||||
// of the required checks for a fast case can be elided.
|
||||
int flags = LIR_OpArrayCopy::all_flags;
|
||||
|
||||
if (!src_objarray)
|
||||
flags &= ~LIR_OpArrayCopy::src_objarray;
|
||||
if (!dst_objarray)
|
||||
flags &= ~LIR_OpArrayCopy::dst_objarray;
|
||||
|
||||
if (!x->arg_needs_null_check(0))
|
||||
flags &= ~LIR_OpArrayCopy::src_null_check;
|
||||
if (!x->arg_needs_null_check(2))
|
||||
flags &= ~LIR_OpArrayCopy::dst_null_check;
|
||||
|
||||
|
||||
if (expected_type != NULL) {
|
||||
// try to skip null checks
|
||||
if (src->as_NewArray() != NULL)
|
||||
Value length_limit = NULL;
|
||||
|
||||
IfOp* ifop = length->as_IfOp();
|
||||
if (ifop != NULL) {
|
||||
// look for expressions like min(v, a.length) which ends up as
|
||||
// x > y ? y : x or x >= y ? y : x
|
||||
if ((ifop->cond() == If::gtr || ifop->cond() == If::geq) &&
|
||||
ifop->x() == ifop->fval() &&
|
||||
ifop->y() == ifop->tval()) {
|
||||
length_limit = ifop->y();
|
||||
}
|
||||
}
|
||||
|
||||
// try to skip null checks and range checks
|
||||
NewArray* src_array = src->as_NewArray();
|
||||
if (src_array != NULL) {
|
||||
flags &= ~LIR_OpArrayCopy::src_null_check;
|
||||
if (dst->as_NewArray() != NULL)
|
||||
if (length_limit != NULL &&
|
||||
src_array->length() == length_limit &&
|
||||
is_constant_zero(src_pos)) {
|
||||
flags &= ~LIR_OpArrayCopy::src_range_check;
|
||||
}
|
||||
}
|
||||
|
||||
NewArray* dst_array = dst->as_NewArray();
|
||||
if (dst_array != NULL) {
|
||||
flags &= ~LIR_OpArrayCopy::dst_null_check;
|
||||
if (length_limit != NULL &&
|
||||
dst_array->length() == length_limit &&
|
||||
is_constant_zero(dst_pos)) {
|
||||
flags &= ~LIR_OpArrayCopy::dst_range_check;
|
||||
}
|
||||
}
|
||||
|
||||
// check from incoming constant values
|
||||
if (positive_constant(src_pos))
|
||||
@ -788,6 +871,28 @@ void LIRGenerator::arraycopy_helper(Intrinsic* x, int* flagsp, ciArrayKlass** ex
|
||||
}
|
||||
}
|
||||
|
||||
IntConstant* src_int = src_pos->type()->as_IntConstant();
|
||||
IntConstant* dst_int = dst_pos->type()->as_IntConstant();
|
||||
if (src_int && dst_int) {
|
||||
int s_offs = src_int->value();
|
||||
int d_offs = dst_int->value();
|
||||
if (src_int->value() >= dst_int->value()) {
|
||||
flags &= ~LIR_OpArrayCopy::overlapping;
|
||||
}
|
||||
if (expected_type != NULL) {
|
||||
BasicType t = expected_type->element_type()->basic_type();
|
||||
int element_size = type2aelembytes(t);
|
||||
if (((arrayOopDesc::base_offset_in_bytes(t) + s_offs * element_size) % HeapWordSize == 0) &&
|
||||
((arrayOopDesc::base_offset_in_bytes(t) + d_offs * element_size) % HeapWordSize == 0)) {
|
||||
flags &= ~LIR_OpArrayCopy::unaligned;
|
||||
}
|
||||
}
|
||||
} else if (src_pos == dst_pos || is_constant_zero(dst_pos)) {
|
||||
// src and dest positions are the same, or dst is zero so assume
|
||||
// nonoverlapping copy.
|
||||
flags &= ~LIR_OpArrayCopy::overlapping;
|
||||
}
|
||||
|
||||
if (src == dst) {
|
||||
// moving within a single array so no type checks are needed
|
||||
if (flags & LIR_OpArrayCopy::type_check) {
|
||||
@ -1351,7 +1456,7 @@ void LIRGenerator::G1SATBCardTableModRef_post_barrier(LIR_OprDesc* addr, LIR_Opr
|
||||
|
||||
if (addr->is_address()) {
|
||||
LIR_Address* address = addr->as_address_ptr();
|
||||
LIR_Opr ptr = new_register(T_OBJECT);
|
||||
LIR_Opr ptr = new_pointer_register();
|
||||
if (!address->index()->is_valid() && address->disp() == 0) {
|
||||
__ move(address->base(), ptr);
|
||||
} else {
|
||||
@ -1403,7 +1508,9 @@ void LIRGenerator::CardTableModRef_post_barrier(LIR_OprDesc* addr, LIR_OprDesc*
|
||||
LIR_Const* card_table_base = new LIR_Const(((CardTableModRefBS*)_bs)->byte_map_base);
|
||||
if (addr->is_address()) {
|
||||
LIR_Address* address = addr->as_address_ptr();
|
||||
LIR_Opr ptr = new_register(T_OBJECT);
|
||||
// ptr cannot be an object because we use this barrier for array card marks
|
||||
// and addr can point in the middle of an array.
|
||||
LIR_Opr ptr = new_pointer_register();
|
||||
if (!address->index()->is_valid() && address->disp() == 0) {
|
||||
__ move(address->base(), ptr);
|
||||
} else {
|
||||
|
@ -644,7 +644,7 @@ void NullCheckVisitor::do_CheckCast (CheckCast* x) {}
|
||||
void NullCheckVisitor::do_InstanceOf (InstanceOf* x) {}
|
||||
void NullCheckVisitor::do_MonitorEnter (MonitorEnter* x) { nce()->handle_AccessMonitor(x); }
|
||||
void NullCheckVisitor::do_MonitorExit (MonitorExit* x) { nce()->handle_AccessMonitor(x); }
|
||||
void NullCheckVisitor::do_Intrinsic (Intrinsic* x) { nce()->clear_last_explicit_null_check(); }
|
||||
void NullCheckVisitor::do_Intrinsic (Intrinsic* x) { nce()->handle_Intrinsic(x); }
|
||||
void NullCheckVisitor::do_BlockBegin (BlockBegin* x) {}
|
||||
void NullCheckVisitor::do_Goto (Goto* x) {}
|
||||
void NullCheckVisitor::do_If (If* x) {}
|
||||
@ -1023,6 +1023,12 @@ void NullCheckEliminator::handle_AccessMonitor(AccessMonitor* x) {
|
||||
|
||||
void NullCheckEliminator::handle_Intrinsic(Intrinsic* x) {
|
||||
if (!x->has_receiver()) {
|
||||
if (x->id() == vmIntrinsics::_arraycopy) {
|
||||
for (int i = 0; i < x->number_of_arguments(); i++) {
|
||||
x->set_arg_needs_null_check(i, !set_contains(x->argument_at(i)));
|
||||
}
|
||||
}
|
||||
|
||||
// Be conservative
|
||||
clear_last_explicit_null_check();
|
||||
return;
|
||||
|
@ -103,7 +103,10 @@ const char *Runtime1::_blob_names[] = {
|
||||
int Runtime1::_generic_arraycopy_cnt = 0;
|
||||
int Runtime1::_primitive_arraycopy_cnt = 0;
|
||||
int Runtime1::_oop_arraycopy_cnt = 0;
|
||||
int Runtime1::_generic_arraycopystub_cnt = 0;
|
||||
int Runtime1::_arraycopy_slowcase_cnt = 0;
|
||||
int Runtime1::_arraycopy_checkcast_cnt = 0;
|
||||
int Runtime1::_arraycopy_checkcast_attempt_cnt = 0;
|
||||
int Runtime1::_new_type_array_slowcase_cnt = 0;
|
||||
int Runtime1::_new_object_array_slowcase_cnt = 0;
|
||||
int Runtime1::_new_instance_slowcase_cnt = 0;
|
||||
@ -119,6 +122,32 @@ int Runtime1::_throw_class_cast_exception_count = 0;
|
||||
int Runtime1::_throw_incompatible_class_change_error_count = 0;
|
||||
int Runtime1::_throw_array_store_exception_count = 0;
|
||||
int Runtime1::_throw_count = 0;
|
||||
|
||||
static int _byte_arraycopy_cnt = 0;
|
||||
static int _short_arraycopy_cnt = 0;
|
||||
static int _int_arraycopy_cnt = 0;
|
||||
static int _long_arraycopy_cnt = 0;
|
||||
static int _oop_arraycopy_cnt = 0;
|
||||
|
||||
address Runtime1::arraycopy_count_address(BasicType type) {
|
||||
switch (type) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE: return (address)&_byte_arraycopy_cnt;
|
||||
case T_CHAR:
|
||||
case T_SHORT: return (address)&_short_arraycopy_cnt;
|
||||
case T_FLOAT:
|
||||
case T_INT: return (address)&_int_arraycopy_cnt;
|
||||
case T_DOUBLE:
|
||||
case T_LONG: return (address)&_long_arraycopy_cnt;
|
||||
case T_ARRAY:
|
||||
case T_OBJECT: return (address)&_oop_arraycopy_cnt;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
// Simple helper to see if the caller of a runtime stub which
|
||||
@ -1229,9 +1258,17 @@ void Runtime1::print_statistics() {
|
||||
tty->print_cr(" _handle_wrong_method_cnt: %d", SharedRuntime::_wrong_method_ctr);
|
||||
tty->print_cr(" _ic_miss_cnt: %d", SharedRuntime::_ic_miss_ctr);
|
||||
tty->print_cr(" _generic_arraycopy_cnt: %d", _generic_arraycopy_cnt);
|
||||
tty->print_cr(" _generic_arraycopystub_cnt: %d", _generic_arraycopystub_cnt);
|
||||
tty->print_cr(" _byte_arraycopy_cnt: %d", _byte_arraycopy_cnt);
|
||||
tty->print_cr(" _short_arraycopy_cnt: %d", _short_arraycopy_cnt);
|
||||
tty->print_cr(" _int_arraycopy_cnt: %d", _int_arraycopy_cnt);
|
||||
tty->print_cr(" _long_arraycopy_cnt: %d", _long_arraycopy_cnt);
|
||||
tty->print_cr(" _primitive_arraycopy_cnt: %d", _primitive_arraycopy_cnt);
|
||||
tty->print_cr(" _oop_arraycopy_cnt: %d", _oop_arraycopy_cnt);
|
||||
tty->print_cr(" _oop_arraycopy_cnt (C): %d", Runtime1::_oop_arraycopy_cnt);
|
||||
tty->print_cr(" _oop_arraycopy_cnt (stub): %d", _oop_arraycopy_cnt);
|
||||
tty->print_cr(" _arraycopy_slowcase_cnt: %d", _arraycopy_slowcase_cnt);
|
||||
tty->print_cr(" _arraycopy_checkcast_cnt: %d", _arraycopy_checkcast_cnt);
|
||||
tty->print_cr(" _arraycopy_checkcast_attempt_cnt:%d", _arraycopy_checkcast_attempt_cnt);
|
||||
|
||||
tty->print_cr(" _new_type_array_slowcase_cnt: %d", _new_type_array_slowcase_cnt);
|
||||
tty->print_cr(" _new_object_array_slowcase_cnt: %d", _new_object_array_slowcase_cnt);
|
||||
|
@ -94,7 +94,10 @@ class Runtime1: public AllStatic {
|
||||
static int _generic_arraycopy_cnt;
|
||||
static int _primitive_arraycopy_cnt;
|
||||
static int _oop_arraycopy_cnt;
|
||||
static int _generic_arraycopystub_cnt;
|
||||
static int _arraycopy_slowcase_cnt;
|
||||
static int _arraycopy_checkcast_cnt;
|
||||
static int _arraycopy_checkcast_attempt_cnt;
|
||||
static int _new_type_array_slowcase_cnt;
|
||||
static int _new_object_array_slowcase_cnt;
|
||||
static int _new_instance_slowcase_cnt;
|
||||
@ -174,7 +177,8 @@ class Runtime1: public AllStatic {
|
||||
static void trace_block_entry(jint block_id);
|
||||
|
||||
#ifndef PRODUCT
|
||||
static address throw_count_address() { return (address)&_throw_count; }
|
||||
static address throw_count_address() { return (address)&_throw_count; }
|
||||
static address arraycopy_count_address(BasicType type);
|
||||
#endif
|
||||
|
||||
// directly accessible leaf routine
|
||||
|
@ -66,8 +66,8 @@ ciConstant ciInstance::field_value(ciField* field) {
|
||||
"invalid access");
|
||||
VM_ENTRY_MARK;
|
||||
ciConstant result;
|
||||
oop obj = get_oop();
|
||||
assert(obj != NULL, "bad oop");
|
||||
Handle obj = get_oop();
|
||||
assert(!obj.is_null(), "bad oop");
|
||||
BasicType field_btype = field->type()->basic_type();
|
||||
int offset = field->offset();
|
||||
|
||||
|
@ -42,9 +42,20 @@ ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const {
|
||||
methodHandle callee(_callee->get_methodOop());
|
||||
// We catch all exceptions here that could happen in the method
|
||||
// handle compiler and stop the VM.
|
||||
MethodHandleCompiler mhc(h, callee, is_invokedynamic, CATCH);
|
||||
methodHandle m = mhc.compile(CATCH);
|
||||
return CURRENT_ENV->get_object(m())->as_method();
|
||||
MethodHandleCompiler mhc(h, callee, is_invokedynamic, THREAD);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
methodHandle m = mhc.compile(THREAD);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
return CURRENT_ENV->get_object(m())->as_method();
|
||||
}
|
||||
}
|
||||
if (PrintMiscellaneous && (Verbose || WizardMode)) {
|
||||
tty->print("*** ciMethodHandle::get_adapter => ");
|
||||
PENDING_EXCEPTION->print();
|
||||
tty->print("*** get_adapter (%s): ", is_invokedynamic ? "indy" : "mh"); ((ciObject*)this)->print(); //@@
|
||||
}
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "ci/ciEnv.hpp"
|
||||
#include "ci/ciKlass.hpp"
|
||||
#include "ci/ciMethodBlocks.hpp"
|
||||
#include "shark/shark_globals.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -170,7 +170,6 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
break;
|
||||
case JVM_CONSTANT_InvokeDynamicTrans : // this tag appears only in old classfiles
|
||||
case JVM_CONSTANT_InvokeDynamic :
|
||||
{
|
||||
if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
|
||||
@ -186,14 +185,6 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
|
||||
cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags
|
||||
u2 bootstrap_specifier_index = cfs->get_u2_fast();
|
||||
u2 name_and_type_index = cfs->get_u2_fast();
|
||||
if (tag == JVM_CONSTANT_InvokeDynamicTrans) {
|
||||
if (!AllowTransitionalJSR292)
|
||||
classfile_parse_error(
|
||||
"This JVM does not support transitional InvokeDynamic tag %u in class file %s",
|
||||
tag, CHECK);
|
||||
cp->invoke_dynamic_trans_at_put(index, bootstrap_specifier_index, name_and_type_index);
|
||||
break;
|
||||
}
|
||||
if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index)
|
||||
_max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later
|
||||
cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index);
|
||||
@ -492,7 +483,6 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
|
||||
ref_index, CHECK_(nullHandle));
|
||||
}
|
||||
break;
|
||||
case JVM_CONSTANT_InvokeDynamicTrans :
|
||||
case JVM_CONSTANT_InvokeDynamic :
|
||||
{
|
||||
int name_and_type_ref_index = cp->invoke_dynamic_name_and_type_ref_index_at(index);
|
||||
@ -501,14 +491,6 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
|
||||
"Invalid constant pool index %u in class file %s",
|
||||
name_and_type_ref_index,
|
||||
CHECK_(nullHandle));
|
||||
if (tag == JVM_CONSTANT_InvokeDynamicTrans) {
|
||||
int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index);
|
||||
check_property(valid_cp_range(bootstrap_method_ref_index, length) &&
|
||||
cp->tag_at(bootstrap_method_ref_index).is_method_handle(),
|
||||
"Invalid constant pool index %u in class file %s",
|
||||
bootstrap_method_ref_index,
|
||||
CHECK_(nullHandle));
|
||||
}
|
||||
// bootstrap specifier index must be checked later, when BootstrapMethods attr is available
|
||||
break;
|
||||
}
|
||||
@ -578,6 +560,7 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JVM_CONSTANT_InvokeDynamic:
|
||||
case JVM_CONSTANT_Fieldref:
|
||||
case JVM_CONSTANT_Methodref:
|
||||
case JVM_CONSTANT_InterfaceMethodref: {
|
||||
@ -2783,7 +2766,6 @@ void ClassFileParser::java_lang_invoke_MethodHandle_fix_pre(constantPoolHandle c
|
||||
}
|
||||
}
|
||||
|
||||
if (AllowTransitionalJSR292 && word_sig_index == 0) return;
|
||||
if (word_sig_index == 0)
|
||||
THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
|
||||
"missing I or J signature (for vmentry) in java.lang.invoke.MethodHandle");
|
||||
@ -2823,7 +2805,6 @@ void ClassFileParser::java_lang_invoke_MethodHandle_fix_pre(constantPoolHandle c
|
||||
}
|
||||
}
|
||||
|
||||
if (AllowTransitionalJSR292 && !found_vmentry) return;
|
||||
if (!found_vmentry)
|
||||
THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
|
||||
"missing vmentry byte field in java.lang.invoke.MethodHandle");
|
||||
@ -3194,15 +3175,6 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
|
||||
if (EnableInvokeDynamic && class_name == vmSymbols::java_lang_invoke_MethodHandle() && class_loader.is_null()) {
|
||||
java_lang_invoke_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle));
|
||||
}
|
||||
if (AllowTransitionalJSR292 &&
|
||||
EnableInvokeDynamic && class_name == vmSymbols::java_dyn_MethodHandle() && class_loader.is_null()) {
|
||||
java_lang_invoke_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle));
|
||||
}
|
||||
if (AllowTransitionalJSR292 &&
|
||||
EnableInvokeDynamic && class_name == vmSymbols::sun_dyn_MethodHandleImpl() && class_loader.is_null()) {
|
||||
// allow vmentry field in MethodHandleImpl also
|
||||
java_lang_invoke_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle));
|
||||
}
|
||||
|
||||
// Add a fake "discovered" field if it is not present
|
||||
// for compatibility with earlier jdk's.
|
||||
|
@ -67,28 +67,6 @@ static bool find_field(instanceKlass* ik,
|
||||
return ik->find_local_field(name_symbol, signature_symbol, fd);
|
||||
}
|
||||
|
||||
static bool find_hacked_field(instanceKlass* ik,
|
||||
Symbol* name_symbol, Symbol* signature_symbol,
|
||||
fieldDescriptor* fd,
|
||||
bool allow_super = false) {
|
||||
bool found = find_field(ik, name_symbol, signature_symbol, fd, allow_super);
|
||||
if (!found && AllowTransitionalJSR292) {
|
||||
Symbol* backup_sig = SystemDictionary::find_backup_signature(signature_symbol);
|
||||
if (backup_sig != NULL) {
|
||||
found = find_field(ik, name_symbol, backup_sig, fd, allow_super);
|
||||
if (TraceMethodHandles) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("MethodHandles: %s.%s: backup for %s => %s%s",
|
||||
ik->name()->as_C_string(), name_symbol->as_C_string(),
|
||||
signature_symbol->as_C_string(), backup_sig->as_C_string(),
|
||||
(found ? "" : " (NOT FOUND)"));
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
#define find_field find_hacked_field /* remove after AllowTransitionalJSR292 */
|
||||
|
||||
// Helpful routine for computing field offsets at run time rather than hardcoding them
|
||||
static void
|
||||
compute_offset(int &dest_offset,
|
||||
@ -1453,32 +1431,41 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, TRAPS) {
|
||||
}
|
||||
}
|
||||
#ifdef ASSERT
|
||||
assert(st_method() == method && st.bci() == bci,
|
||||
"Wrong stack trace");
|
||||
st.next();
|
||||
// vframeStream::method isn't GC-safe so store off a copy
|
||||
// of the methodOop in case we GC.
|
||||
if (!st.at_end()) {
|
||||
st_method = st.method();
|
||||
}
|
||||
assert(st_method() == method && st.bci() == bci,
|
||||
"Wrong stack trace");
|
||||
st.next();
|
||||
// vframeStream::method isn't GC-safe so store off a copy
|
||||
// of the methodOop in case we GC.
|
||||
if (!st.at_end()) {
|
||||
st_method = st.method();
|
||||
}
|
||||
#endif
|
||||
|
||||
// the format of the stacktrace will be:
|
||||
// - 1 or more fillInStackTrace frames for the exception class (skipped)
|
||||
// - 0 or more <init> methods for the exception class (skipped)
|
||||
// - rest of the stack
|
||||
|
||||
if (!skip_fillInStackTrace_check) {
|
||||
// check "fillInStackTrace" only once, so we negate the flag
|
||||
// after the first time check.
|
||||
skip_fillInStackTrace_check = true;
|
||||
if (method->name() == vmSymbols::fillInStackTrace_name()) {
|
||||
if ((method->name() == vmSymbols::fillInStackTrace_name() ||
|
||||
method->name() == vmSymbols::fillInStackTrace0_name()) &&
|
||||
throwable->is_a(method->method_holder())) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
skip_fillInStackTrace_check = true; // gone past them all
|
||||
}
|
||||
}
|
||||
// skip <init> methods of the exceptions klass. If there is <init> methods
|
||||
// that belongs to a superclass of the exception we are going to skipping
|
||||
// them in stack trace. This is simlar to classic VM.
|
||||
if (!skip_throwableInit_check) {
|
||||
assert(skip_fillInStackTrace_check, "logic error in backtrace filtering");
|
||||
|
||||
// skip <init> methods of the exception class and superclasses
|
||||
// This is simlar to classic VM.
|
||||
if (method->name() == vmSymbols::object_initializer_name() &&
|
||||
throwable->is_a(method->method_holder())) {
|
||||
continue;
|
||||
} else {
|
||||
// if no "Throwable.init()" method found, we stop checking it next time.
|
||||
// there are none or we've seen them all - either way stop checking
|
||||
skip_throwableInit_check = true;
|
||||
}
|
||||
}
|
||||
@ -2333,7 +2320,6 @@ void java_lang_invoke_MethodHandle::compute_offsets() {
|
||||
klassOop k = SystemDictionary::MethodHandle_klass();
|
||||
if (k != NULL && EnableInvokeDynamic) {
|
||||
bool allow_super = false;
|
||||
if (AllowTransitionalJSR292) allow_super = true; // temporary, to access java.dyn.MethodHandleImpl
|
||||
compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_lang_invoke_MethodType_signature(), allow_super);
|
||||
compute_offset(_vmtarget_offset, k, vmSymbols::vmtarget_name(), vmSymbols::object_signature(), allow_super);
|
||||
compute_offset(_vmentry_offset, k, vmSymbols::vmentry_name(), vmSymbols::machine_word_signature(), allow_super);
|
||||
|
@ -208,8 +208,10 @@ bool StackMapFrame::has_flag_match_exception(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StackMapFrame::is_assignable_to(const StackMapFrame* target, TRAPS) const {
|
||||
if (_max_locals != target->max_locals() || _stack_size != target->stack_size()) {
|
||||
bool StackMapFrame::is_assignable_to(
|
||||
const StackMapFrame* target, bool is_exception_handler, TRAPS) const {
|
||||
if (_max_locals != target->max_locals() ||
|
||||
_stack_size != target->stack_size()) {
|
||||
return false;
|
||||
}
|
||||
// Only need to compare type elements up to target->locals() or target->stack().
|
||||
@ -222,7 +224,7 @@ bool StackMapFrame::is_assignable_to(const StackMapFrame* target, TRAPS) const {
|
||||
bool match_flags = (_flags | target->flags()) == target->flags();
|
||||
|
||||
return match_locals && match_stack &&
|
||||
(match_flags || has_flag_match_exception(target));
|
||||
(match_flags || (is_exception_handler && has_flag_match_exception(target)));
|
||||
}
|
||||
|
||||
VerificationType StackMapFrame::pop_stack_ex(VerificationType type, TRAPS) {
|
||||
|
@ -134,7 +134,8 @@ class StackMapFrame : public ResourceObj {
|
||||
void copy_stack(const StackMapFrame* src);
|
||||
|
||||
// Return true if this stack map frame is assignable to target.
|
||||
bool is_assignable_to(const StackMapFrame* target, TRAPS) const;
|
||||
bool is_assignable_to(const StackMapFrame* target,
|
||||
bool is_exception_handler, TRAPS) const;
|
||||
|
||||
// Push type into stack type array.
|
||||
inline void push_stack(VerificationType type, TRAPS) {
|
||||
|
@ -98,10 +98,13 @@ bool StackMapTable::match_stackmap(
|
||||
bool result = true;
|
||||
StackMapFrame *stackmap_frame = _frame_array[frame_index];
|
||||
if (match) {
|
||||
// when checking handler target, match == true && update == false
|
||||
bool is_exception_handler = !update;
|
||||
// Has direct control flow from last instruction, need to match the two
|
||||
// frames.
|
||||
result = frame->is_assignable_to(
|
||||
stackmap_frame, CHECK_VERIFY_(frame->verifier(), false));
|
||||
stackmap_frame, is_exception_handler,
|
||||
CHECK_VERIFY_(frame->verifier(), false));
|
||||
}
|
||||
if (update) {
|
||||
// Use the frame in stackmap table as current frame
|
||||
|
@ -1887,99 +1887,27 @@ static const short wk_init_info[] = {
|
||||
0
|
||||
};
|
||||
|
||||
Symbol* SystemDictionary::find_backup_symbol(Symbol* symbol,
|
||||
const char* from_prefix,
|
||||
const char* to_prefix) {
|
||||
assert(AllowTransitionalJSR292, ""); // delete this subroutine
|
||||
Symbol* backup_symbol = NULL;
|
||||
size_t from_len = strlen(from_prefix);
|
||||
if (strncmp((const char*) symbol->base(), from_prefix, from_len) != 0)
|
||||
return NULL;
|
||||
char buf[100];
|
||||
size_t to_len = strlen(to_prefix);
|
||||
size_t tail_len = symbol->utf8_length() - from_len;
|
||||
size_t new_len = to_len + tail_len;
|
||||
guarantee(new_len < sizeof(buf), "buf too small");
|
||||
memcpy(buf, to_prefix, to_len);
|
||||
memcpy(buf + to_len, symbol->base() + from_len, tail_len);
|
||||
buf[new_len] = '\0';
|
||||
vmSymbols::SID backup_sid = vmSymbols::find_sid(buf);
|
||||
if (backup_sid != vmSymbols::NO_SID) {
|
||||
backup_symbol = vmSymbols::symbol_at(backup_sid);
|
||||
}
|
||||
return backup_symbol;
|
||||
}
|
||||
|
||||
Symbol* SystemDictionary::find_backup_class_name(Symbol* symbol) {
|
||||
assert(AllowTransitionalJSR292, ""); // delete this subroutine
|
||||
if (symbol == NULL) return NULL;
|
||||
Symbol* backup_symbol = find_backup_symbol(symbol, "java/lang/invoke/", "java/dyn/"); // AllowTransitionalJSR292 ONLY
|
||||
if (backup_symbol == NULL)
|
||||
backup_symbol = find_backup_symbol(symbol, "java/dyn/", "sun/dyn/"); // AllowTransitionalJSR292 ONLY
|
||||
return backup_symbol;
|
||||
}
|
||||
|
||||
Symbol* SystemDictionary::find_backup_signature(Symbol* symbol) {
|
||||
assert(AllowTransitionalJSR292, ""); // delete this subroutine
|
||||
if (symbol == NULL) return NULL;
|
||||
return find_backup_symbol(symbol, "Ljava/lang/invoke/", "Ljava/dyn/");
|
||||
}
|
||||
|
||||
bool SystemDictionary::initialize_wk_klass(WKID id, int init_opt, TRAPS) {
|
||||
assert(id >= (int)FIRST_WKID && id < (int)WKID_LIMIT, "oob");
|
||||
int info = wk_init_info[id - FIRST_WKID];
|
||||
int sid = (info >> CEIL_LG_OPTION_LIMIT);
|
||||
Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid);
|
||||
klassOop* klassp = &_well_known_klasses[id];
|
||||
bool pre_load = (init_opt < SystemDictionary::Opt);
|
||||
bool try_load = true;
|
||||
bool must_load = (init_opt < SystemDictionary::Opt);
|
||||
bool try_load = true;
|
||||
if (init_opt == SystemDictionary::Opt_Kernel) {
|
||||
#ifndef KERNEL
|
||||
try_load = false;
|
||||
#endif //KERNEL
|
||||
}
|
||||
Symbol* backup_symbol = NULL; // symbol to try if the current symbol fails
|
||||
if (init_opt == SystemDictionary::Pre_JSR292) {
|
||||
if (!EnableInvokeDynamic) try_load = false; // do not bother to load such classes
|
||||
if (AllowTransitionalJSR292) {
|
||||
backup_symbol = find_backup_class_name(symbol);
|
||||
if (try_load && PreferTransitionalJSR292) {
|
||||
while (backup_symbol != NULL) {
|
||||
(*klassp) = resolve_or_null(backup_symbol, CHECK_0); // try backup early
|
||||
if (TraceMethodHandles) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("MethodHandles: try backup first for %s => %s (%s)",
|
||||
symbol->as_C_string(), backup_symbol->as_C_string(),
|
||||
((*klassp) == NULL) ? "no such class" : "backup load succeeded");
|
||||
}
|
||||
if ((*klassp) != NULL) return true;
|
||||
backup_symbol = find_backup_class_name(backup_symbol); // find next backup
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((*klassp) != NULL) return true;
|
||||
if (!try_load) return false;
|
||||
while (symbol != NULL) {
|
||||
bool must_load = (pre_load && (backup_symbol == NULL));
|
||||
if ((*klassp) == NULL && try_load) {
|
||||
if (must_load) {
|
||||
(*klassp) = resolve_or_fail(symbol, true, CHECK_0); // load required class
|
||||
} else {
|
||||
(*klassp) = resolve_or_null(symbol, CHECK_0); // load optional klass
|
||||
}
|
||||
if ((*klassp) != NULL) return true;
|
||||
// Go around again. Example of long backup sequence:
|
||||
// java.lang.invoke.MemberName, java.dyn.MemberName, sun.dyn.MemberName, ONLY if AllowTransitionalJSR292
|
||||
if (TraceMethodHandles && (backup_symbol != NULL)) {
|
||||
ResourceMark rm;
|
||||
tty->print_cr("MethodHandles: backup for %s => %s",
|
||||
symbol->as_C_string(), backup_symbol->as_C_string());
|
||||
}
|
||||
symbol = backup_symbol;
|
||||
if (AllowTransitionalJSR292)
|
||||
backup_symbol = find_backup_class_name(symbol);
|
||||
}
|
||||
return false;
|
||||
return ((*klassp) != NULL);
|
||||
}
|
||||
|
||||
void SystemDictionary::initialize_wk_klasses_until(WKID limit_id, WKID &start_id, TRAPS) {
|
||||
@ -2409,9 +2337,7 @@ methodOop SystemDictionary::find_method_handle_invoke(Symbol* name,
|
||||
// Must create lots of stuff here, but outside of the SystemDictionary lock.
|
||||
if (THREAD->is_Compiler_thread())
|
||||
return NULL; // do not attempt from within compiler
|
||||
bool for_invokeGeneric = (name_id == vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name));
|
||||
if (AllowInvokeForInvokeGeneric && name_id == vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name))
|
||||
for_invokeGeneric = true;
|
||||
bool for_invokeGeneric = (name_id != vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name));
|
||||
bool found_on_bcp = false;
|
||||
Handle mt = find_method_handle_type(signature, accessing_klass,
|
||||
for_invokeGeneric,
|
||||
@ -2498,14 +2424,10 @@ Handle SystemDictionary::find_method_handle_type(Symbol* signature,
|
||||
JavaCallArguments args(Handle(THREAD, rt()));
|
||||
args.push_oop(pts());
|
||||
JavaValue result(T_OBJECT);
|
||||
Symbol* findMethodHandleType_signature = vmSymbols::findMethodHandleType_signature();
|
||||
if (AllowTransitionalJSR292 && SystemDictionaryHandles::MethodType_klass()->name() == vmSymbols::java_dyn_MethodType()) {
|
||||
findMethodHandleType_signature = vmSymbols::findMethodHandleType_TRANS_signature();
|
||||
}
|
||||
JavaCalls::call_static(&result,
|
||||
SystemDictionary::MethodHandleNatives_klass(),
|
||||
vmSymbols::findMethodHandleType_name(),
|
||||
findMethodHandleType_signature,
|
||||
vmSymbols::findMethodHandleType_signature(),
|
||||
&args, CHECK_(empty));
|
||||
Handle method_type(THREAD, (oop) result.get_jobject());
|
||||
|
||||
@ -2513,14 +2435,10 @@ Handle SystemDictionary::find_method_handle_type(Symbol* signature,
|
||||
// call java.lang.invoke.MethodHandleNatives::notifyGenericMethodType(MethodType) -> void
|
||||
JavaCallArguments args(Handle(THREAD, method_type()));
|
||||
JavaValue no_result(T_VOID);
|
||||
Symbol* notifyGenericMethodType_signature = vmSymbols::notifyGenericMethodType_signature();
|
||||
if (AllowTransitionalJSR292 && SystemDictionaryHandles::MethodType_klass()->name() == vmSymbols::java_dyn_MethodType()) {
|
||||
notifyGenericMethodType_signature = vmSymbols::notifyGenericMethodType_TRANS_signature();
|
||||
}
|
||||
JavaCalls::call_static(&no_result,
|
||||
SystemDictionary::MethodHandleNatives_klass(),
|
||||
vmSymbols::notifyGenericMethodType_name(),
|
||||
notifyGenericMethodType_signature,
|
||||
vmSymbols::notifyGenericMethodType_signature(),
|
||||
&args, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
// If the notification fails, just kill it.
|
||||
@ -2569,14 +2487,10 @@ Handle SystemDictionary::link_method_handle_constant(KlassHandle caller,
|
||||
args.push_oop(name());
|
||||
args.push_oop(type());
|
||||
JavaValue result(T_OBJECT);
|
||||
Symbol* linkMethodHandleConstant_signature = vmSymbols::linkMethodHandleConstant_signature();
|
||||
if (AllowTransitionalJSR292 && SystemDictionaryHandles::MethodHandle_klass()->name() == vmSymbols::java_dyn_MethodHandle()) {
|
||||
linkMethodHandleConstant_signature = vmSymbols::linkMethodHandleConstant_TRANS_signature();
|
||||
}
|
||||
JavaCalls::call_static(&result,
|
||||
SystemDictionary::MethodHandleNatives_klass(),
|
||||
vmSymbols::linkMethodHandleConstant_name(),
|
||||
linkMethodHandleConstant_signature,
|
||||
vmSymbols::linkMethodHandleConstant_signature(),
|
||||
&args, CHECK_(empty));
|
||||
return Handle(THREAD, (oop) result.get_jobject());
|
||||
}
|
||||
@ -2607,17 +2521,10 @@ Handle SystemDictionary::make_dynamic_call_site(Handle bootstrap_method,
|
||||
args.push_oop(caller_mname());
|
||||
args.push_int(caller_bci);
|
||||
JavaValue result(T_OBJECT);
|
||||
Symbol* makeDynamicCallSite_signature = vmSymbols::makeDynamicCallSite_signature();
|
||||
if (AllowTransitionalJSR292 && SystemDictionaryHandles::MethodHandleNatives_klass()->name() == vmSymbols::sun_dyn_MethodHandleNatives()) {
|
||||
makeDynamicCallSite_signature = vmSymbols::makeDynamicCallSite_TRANS_signature();
|
||||
}
|
||||
if (AllowTransitionalJSR292 && SystemDictionaryHandles::MethodHandleNatives_klass()->name() == vmSymbols::java_dyn_MethodHandleNatives()) {
|
||||
makeDynamicCallSite_signature = vmSymbols::makeDynamicCallSite_TRANS2_signature();
|
||||
}
|
||||
JavaCalls::call_static(&result,
|
||||
SystemDictionary::MethodHandleNatives_klass(),
|
||||
vmSymbols::makeDynamicCallSite_name(),
|
||||
makeDynamicCallSite_signature,
|
||||
vmSymbols::makeDynamicCallSite_signature(),
|
||||
&args, CHECK_(empty));
|
||||
oop call_site_oop = (oop) result.get_jobject();
|
||||
assert(call_site_oop->is_oop()
|
||||
@ -2698,28 +2605,10 @@ Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int c
|
||||
argument_info_result = argument_info; // return argument_info to caller
|
||||
return bsm;
|
||||
}
|
||||
// else null BSM; fall through
|
||||
} else if (tag.is_name_and_type()) {
|
||||
// JSR 292 EDR does not have JVM_CONSTANT_InvokeDynamic
|
||||
// a bare name&type defaults its BSM to null, so fall through...
|
||||
} else {
|
||||
ShouldNotReachHere(); // verifier does not allow this
|
||||
}
|
||||
|
||||
// Fall through to pick up the per-class bootstrap method.
|
||||
// This mechanism may go away in the PFD.
|
||||
assert(AllowTransitionalJSR292, "else the verifier should have stopped us already");
|
||||
argument_info_result = empty; // return no argument_info to caller
|
||||
oop bsm_oop = instanceKlass::cast(caller_method->method_holder())->bootstrap_method();
|
||||
if (bsm_oop != NULL) {
|
||||
if (TraceMethodHandles) {
|
||||
tty->print_cr("bootstrap method for "PTR_FORMAT" registered as "PTR_FORMAT":",
|
||||
(intptr_t) caller_method(), (intptr_t) bsm_oop);
|
||||
}
|
||||
assert(bsm_oop->is_oop(), "must be sane");
|
||||
return Handle(THREAD, bsm_oop);
|
||||
}
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,6 @@ class SymbolPropertyTable;
|
||||
/* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \
|
||||
template(MethodHandle_klass, java_lang_invoke_MethodHandle, Pre_JSR292) \
|
||||
template(MemberName_klass, java_lang_invoke_MemberName, Pre_JSR292) \
|
||||
template(MethodHandleImpl_klass, sun_dyn_MethodHandleImpl, Opt) /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(MethodHandleNatives_klass, java_lang_invoke_MethodHandleNatives, Pre_JSR292) \
|
||||
template(AdapterMethodHandle_klass, java_lang_invoke_AdapterMethodHandle, Pre_JSR292) \
|
||||
template(BoundMethodHandle_klass, java_lang_invoke_BoundMethodHandle, Pre_JSR292) \
|
||||
@ -154,7 +153,6 @@ class SymbolPropertyTable;
|
||||
template(MethodType_klass, java_lang_invoke_MethodType, Pre_JSR292) \
|
||||
template(MethodTypeForm_klass, java_lang_invoke_MethodTypeForm, Pre_JSR292) \
|
||||
template(WrongMethodTypeException_klass, java_lang_invoke_WrongMethodTypeException, Pre_JSR292) \
|
||||
template(Linkage_klass, java_lang_invoke_Linkage, Opt) /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(CallSite_klass, java_lang_invoke_CallSite, Pre_JSR292) \
|
||||
/* Note: MethodHandle must be first, and CallSite last in group */ \
|
||||
\
|
||||
@ -422,8 +420,6 @@ public:
|
||||
initialize_wk_klasses_until((WKID) limit, start_id, THREAD);
|
||||
}
|
||||
|
||||
static Symbol* find_backup_symbol(Symbol* symbol, const char* from_prefix, const char* to_prefix);
|
||||
|
||||
public:
|
||||
#define WK_KLASS_DECLARE(name, ignore_symbol, option) \
|
||||
static klassOop name() { return check_klass_##option(_well_known_klasses[WK_KLASS_ENUM_NAME(name)]); }
|
||||
@ -445,9 +441,6 @@ public:
|
||||
|
||||
static void load_abstract_ownable_synchronizer_klass(TRAPS);
|
||||
|
||||
static Symbol* find_backup_class_name(Symbol* class_name_symbol);
|
||||
static Symbol* find_backup_signature(Symbol* signature_symbol);
|
||||
|
||||
private:
|
||||
// Tells whether ClassLoader.loadClassInternal is present
|
||||
static bool has_loadClassInternal() { return _has_loadClassInternal; }
|
||||
|
@ -1671,19 +1671,13 @@ void ClassVerifier::verify_ldc(
|
||||
VerificationType::long_type(),
|
||||
VerificationType::long2_type(), CHECK_VERIFY(this));
|
||||
} else if (tag.is_method_handle()) {
|
||||
Symbol* methodHandle_name = vmSymbols::java_lang_invoke_MethodHandle();
|
||||
if (AllowTransitionalJSR292 && !Universe::is_bootstrapping())
|
||||
methodHandle_name = SystemDictionaryHandles::MethodHandle_klass()->name();
|
||||
current_frame->push_stack(
|
||||
VerificationType::reference_type(
|
||||
methodHandle_name), CHECK_VERIFY(this));
|
||||
vmSymbols::java_lang_invoke_MethodHandle()), CHECK_VERIFY(this));
|
||||
} else if (tag.is_method_type()) {
|
||||
Symbol* methodType_name = vmSymbols::java_lang_invoke_MethodType();
|
||||
if (AllowTransitionalJSR292 && !Universe::is_bootstrapping())
|
||||
methodType_name = SystemDictionaryHandles::MethodType_klass()->name();
|
||||
current_frame->push_stack(
|
||||
VerificationType::reference_type(
|
||||
methodType_name), CHECK_VERIFY(this));
|
||||
vmSymbols::java_lang_invoke_MethodType()), CHECK_VERIFY(this));
|
||||
} else {
|
||||
verify_error(bci, "Invalid index in ldc");
|
||||
return;
|
||||
@ -1950,8 +1944,7 @@ void ClassVerifier::verify_invoke_instructions(
|
||||
unsigned int types = (opcode == Bytecodes::_invokeinterface
|
||||
? 1 << JVM_CONSTANT_InterfaceMethodref
|
||||
: opcode == Bytecodes::_invokedynamic
|
||||
? ((AllowTransitionalJSR292 ? 1 << JVM_CONSTANT_NameAndType : 0)
|
||||
|1 << JVM_CONSTANT_InvokeDynamic)
|
||||
? 1 << JVM_CONSTANT_InvokeDynamic
|
||||
: 1 << JVM_CONSTANT_Methodref);
|
||||
verify_cp_type(index, cp, types, CHECK_VERIFY(this));
|
||||
|
||||
|
@ -245,44 +245,15 @@
|
||||
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") \
|
||||
/* temporary transitional public names from 6839872: */ \
|
||||
template(java_dyn_InvokeDynamic, "java/dyn/InvokeDynamic") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_Linkage, "java/dyn/Linkage") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_CallSite, "java/dyn/CallSite") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_MethodHandle, "java/dyn/MethodHandle") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_MethodType, "java/dyn/MethodType") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_WrongMethodTypeException, "java/dyn/WrongMethodTypeException") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_MethodType_signature, "Ljava/dyn/MethodType;") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_MethodHandle_signature, "Ljava/dyn/MethodHandle;") /* AllowTransitionalJSR292 ONLY */ \
|
||||
/* temporary transitional internal names from 6839872: */ \
|
||||
template(java_dyn_MethodTypeForm, "java/dyn/MethodTypeForm") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_MethodTypeForm_signature, "Ljava/dyn/MethodTypeForm;") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_MemberName, "java/dyn/MemberName") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_MethodHandleNatives, "java/dyn/MethodHandleNatives") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_AdapterMethodHandle, "java/dyn/AdapterMethodHandle") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_BoundMethodHandle, "java/dyn/BoundMethodHandle") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(java_dyn_DirectMethodHandle, "java/dyn/DirectMethodHandle") /* AllowTransitionalJSR292 ONLY */ \
|
||||
/* temporary transitional internal names from EDR: */ \
|
||||
template(sun_dyn_MemberName, "sun/dyn/MemberName") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(sun_dyn_MethodHandleImpl, "sun/dyn/MethodHandleImpl") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(sun_dyn_MethodHandleNatives, "sun/dyn/MethodHandleNatives") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(sun_dyn_AdapterMethodHandle, "sun/dyn/AdapterMethodHandle") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(sun_dyn_BoundMethodHandle, "sun/dyn/BoundMethodHandle") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(sun_dyn_DirectMethodHandle, "sun/dyn/DirectMethodHandle") /* AllowTransitionalJSR292 ONLY */ \
|
||||
/* 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;") \
|
||||
template(findMethodHandleType_TRANS_signature, "(Ljava/lang/Class;[Ljava/lang/Class;)Ljava/dyn/MethodType;") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(notifyGenericMethodType_name, "notifyGenericMethodType") \
|
||||
template(notifyGenericMethodType_signature, "(Ljava/lang/invoke/MethodType;)V") \
|
||||
template(notifyGenericMethodType_TRANS_signature, "(Ljava/dyn/MethodType;)V") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(linkMethodHandleConstant_name, "linkMethodHandleConstant") \
|
||||
template(linkMethodHandleConstant_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;") \
|
||||
template(linkMethodHandleConstant_TRANS_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Ljava/dyn/MethodHandle;") /* AllowTransitionalJSR292 ONLY */ \
|
||||
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(makeDynamicCallSite_TRANS_signature, "(Ljava/dyn/MethodHandle;Ljava/lang/String;Ljava/dyn/MethodType;Ljava/lang/Object;Lsun/dyn/MemberName;I)Ljava/dyn/CallSite;") /* AllowTransitionalJSR292 ONLY */ \
|
||||
template(makeDynamicCallSite_TRANS2_signature, "(Ljava/dyn/MethodHandle;Ljava/lang/String;Ljava/dyn/MethodType;Ljava/lang/Object;Ljava/dyn/MemberName;I)Ljava/dyn/CallSite;") /* AllowTransitionalJSR292 ONLY */ \
|
||||
NOT_LP64( do_alias(machine_word_signature, int_signature) ) \
|
||||
LP64_ONLY( do_alias(machine_word_signature, long_signature) ) \
|
||||
\
|
||||
@ -330,6 +301,7 @@
|
||||
template(dispatch_name, "dispatch") \
|
||||
template(getSystemClassLoader_name, "getSystemClassLoader") \
|
||||
template(fillInStackTrace_name, "fillInStackTrace") \
|
||||
template(fillInStackTrace0_name, "fillInStackTrace0") \
|
||||
template(getCause_name, "getCause") \
|
||||
template(initCause_name, "initCause") \
|
||||
template(setProperty_name, "setProperty") \
|
||||
@ -910,8 +882,6 @@
|
||||
do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_object_array_object_signature, F_R) \
|
||||
/* (symbols invoke_name and invoke_signature defined above) */ \
|
||||
do_intrinsic(_checkSpreadArgument, java_lang_invoke_MethodHandleNatives, checkSpreadArgument_name, checkSpreadArgument_signature, F_S) \
|
||||
do_intrinsic(_checkSpreadArgument_TRANS,sun_dyn_MethodHandleImpl, checkSpreadArgument_name, checkSpreadArgument_signature, F_S) /* AllowTransitionalJSR292 ONLY */ \
|
||||
do_intrinsic(_checkSpreadArgument_TRANS2,java_dyn_MethodHandleNatives, checkSpreadArgument_name, checkSpreadArgument_signature, F_S) /* AllowTransitionalJSR292 ONLY */ \
|
||||
do_name( checkSpreadArgument_name, "checkSpreadArgument") \
|
||||
do_name( checkSpreadArgument_signature, "(Ljava/lang/Object;I)V") \
|
||||
do_intrinsic(_invokeExact, java_lang_invoke_MethodHandle, invokeExact_name, object_array_object_signature, F_RN) \
|
||||
|
@ -964,3 +964,14 @@ void CodeCache::log_state(outputStream* st) {
|
||||
nof_blobs(), nof_nmethods(), nof_adapters(),
|
||||
unallocated_capacity(), largest_free_block());
|
||||
}
|
||||
|
||||
size_t CodeCache::largest_free_block() {
|
||||
// This is called both with and without CodeCache_lock held so
|
||||
// handle both cases.
|
||||
if (CodeCache_lock->owned_by_self()) {
|
||||
return _heap->largest_free_block();
|
||||
} else {
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
return _heap->largest_free_block();
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ class CodeCache : AllStatic {
|
||||
static size_t capacity() { return _heap->capacity(); }
|
||||
static size_t max_capacity() { return _heap->max_capacity(); }
|
||||
static size_t unallocated_capacity() { return _heap->unallocated_capacity(); }
|
||||
static size_t largest_free_block() { return _heap->largest_free_block(); }
|
||||
static size_t largest_free_block();
|
||||
static bool needs_flushing() { return largest_free_block() < CodeCacheFlushingMinimumFreeSpace; }
|
||||
|
||||
static bool needs_cache_clean() { return _needs_cache_clean; }
|
||||
|
@ -472,20 +472,14 @@ RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) {
|
||||
return itr._rh;
|
||||
}
|
||||
|
||||
|
||||
static inline bool is_index(intptr_t index) {
|
||||
return 0 < index && index < os::vm_page_size();
|
||||
}
|
||||
|
||||
|
||||
int32_t Relocation::runtime_address_to_index(address runtime_address) {
|
||||
assert(!is_index((intptr_t)runtime_address), "must not look like an index");
|
||||
assert(!is_reloc_index((intptr_t)runtime_address), "must not look like an index");
|
||||
|
||||
if (runtime_address == NULL) return 0;
|
||||
|
||||
StubCodeDesc* p = StubCodeDesc::desc_for(runtime_address);
|
||||
if (p != NULL && p->begin() == runtime_address) {
|
||||
assert(is_index(p->index()), "there must not be too many stubs");
|
||||
assert(is_reloc_index(p->index()), "there must not be too many stubs");
|
||||
return (int32_t)p->index();
|
||||
} else {
|
||||
// Known "miscellaneous" non-stub pointers:
|
||||
@ -506,7 +500,7 @@ int32_t Relocation::runtime_address_to_index(address runtime_address) {
|
||||
address Relocation::index_to_runtime_address(int32_t index) {
|
||||
if (index == 0) return NULL;
|
||||
|
||||
if (is_index(index)) {
|
||||
if (is_reloc_index(index)) {
|
||||
StubCodeDesc* p = StubCodeDesc::desc_for_index(index);
|
||||
assert(p != NULL, "there must be a stub for this index");
|
||||
return p->begin();
|
||||
@ -634,7 +628,7 @@ void external_word_Relocation::pack_data_to(CodeSection* dest) {
|
||||
#ifndef _LP64
|
||||
p = pack_1_int_to(p, index);
|
||||
#else
|
||||
if (is_index(index)) {
|
||||
if (is_reloc_index(index)) {
|
||||
p = pack_2_ints_to(p, index, 0);
|
||||
} else {
|
||||
jlong t = (jlong) _target;
|
||||
@ -642,7 +636,7 @@ void external_word_Relocation::pack_data_to(CodeSection* dest) {
|
||||
int32_t hi = high(t);
|
||||
p = pack_2_ints_to(p, lo, hi);
|
||||
DEBUG_ONLY(jlong t1 = jlong_from(hi, lo));
|
||||
assert(!is_index(t1) && (address) t1 == _target, "not symmetric");
|
||||
assert(!is_reloc_index(t1) && (address) t1 == _target, "not symmetric");
|
||||
}
|
||||
#endif /* _LP64 */
|
||||
dest->set_locs_end((relocInfo*) p);
|
||||
@ -656,7 +650,7 @@ void external_word_Relocation::unpack_data() {
|
||||
int32_t lo, hi;
|
||||
unpack_2_ints(lo, hi);
|
||||
jlong t = jlong_from(hi, lo);;
|
||||
if (is_index(t)) {
|
||||
if (is_reloc_index(t)) {
|
||||
_target = index_to_runtime_address(t);
|
||||
} else {
|
||||
_target = (address) t;
|
||||
|
@ -703,6 +703,10 @@ class Relocation VALUE_OBJ_CLASS_SPEC {
|
||||
assert(datalen()==0 || type()==relocInfo::none, "no data here");
|
||||
}
|
||||
|
||||
static bool is_reloc_index(intptr_t index) {
|
||||
return 0 < index && index < os::vm_page_size();
|
||||
}
|
||||
|
||||
protected:
|
||||
// Helper functions for pack_data_to() and unpack_data().
|
||||
|
||||
@ -1127,6 +1131,12 @@ class external_word_Relocation : public DataRelocation {
|
||||
return rh;
|
||||
}
|
||||
|
||||
// Some address looking values aren't safe to treat as relocations
|
||||
// and should just be treated as constants.
|
||||
static bool can_be_relocated(address target) {
|
||||
return target != NULL && !is_reloc_index((intptr_t)target);
|
||||
}
|
||||
|
||||
private:
|
||||
address _target; // address in runtime
|
||||
|
||||
|
@ -847,9 +847,9 @@ CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQue
|
||||
// Initialize the compilation queue
|
||||
void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler_count) {
|
||||
EXCEPTION_MARK;
|
||||
#ifndef ZERO
|
||||
#if !defined(ZERO) && !defined(SHARK)
|
||||
assert(c2_compiler_count > 0 || c1_compiler_count > 0, "No compilers?");
|
||||
#endif // !ZERO
|
||||
#endif // !ZERO && !SHARK
|
||||
if (c2_compiler_count > 0) {
|
||||
_c2_method_queue = new CompileQueue("C2MethodQueue", MethodCompileQueue_lock);
|
||||
}
|
||||
@ -1118,7 +1118,7 @@ nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
|
||||
|
||||
assert(!HAS_PENDING_EXCEPTION, "No exception should be present");
|
||||
// some prerequisites that are compiler specific
|
||||
if (compiler(comp_level)->is_c2()) {
|
||||
if (compiler(comp_level)->is_c2() || compiler(comp_level)->is_shark()) {
|
||||
method->constants()->resolve_string_constants(CHECK_0);
|
||||
// Resolve all classes seen in the signature of the method
|
||||
// we are compiling.
|
||||
@ -1736,8 +1736,14 @@ void CompileBroker::handle_full_code_cache() {
|
||||
UseInterpreter = true;
|
||||
if (UseCompiler || AlwaysCompileLoopMethods ) {
|
||||
if (xtty != NULL) {
|
||||
stringStream s;
|
||||
// Dump code cache state into a buffer before locking the tty,
|
||||
// because log_state() will use locks causing lock conflicts.
|
||||
CodeCache::log_state(&s);
|
||||
// Lock to prevent tearing
|
||||
ttyLocker ttyl;
|
||||
xtty->begin_elem("code_cache_full");
|
||||
CodeCache::log_state(xtty);
|
||||
xtty->print(s.as_string());
|
||||
xtty->stamp();
|
||||
xtty->end_elem();
|
||||
}
|
||||
|
@ -554,7 +554,7 @@ BytecodeInterpreter::run(interpreterState istate) {
|
||||
|
||||
/* 0xB0 */ &&opc_areturn, &&opc_return, &&opc_getstatic, &&opc_putstatic,
|
||||
/* 0xB4 */ &&opc_getfield, &&opc_putfield, &&opc_invokevirtual,&&opc_invokespecial,
|
||||
/* 0xB8 */ &&opc_invokestatic,&&opc_invokeinterface,&&opc_default, &&opc_new,
|
||||
/* 0xB8 */ &&opc_invokestatic,&&opc_invokeinterface,&&opc_invokedynamic,&&opc_new,
|
||||
/* 0xBC */ &&opc_newarray, &&opc_anewarray, &&opc_arraylength, &&opc_athrow,
|
||||
|
||||
/* 0xC0 */ &&opc_checkcast, &&opc_instanceof, &&opc_monitorenter, &&opc_monitorexit,
|
||||
@ -568,7 +568,7 @@ BytecodeInterpreter::run(interpreterState istate) {
|
||||
/* 0xDC */ &&opc_default, &&opc_default, &&opc_default, &&opc_default,
|
||||
|
||||
/* 0xE0 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default,
|
||||
/* 0xE4 */ &&opc_default, &&opc_return_register_finalizer, &&opc_default, &&opc_default,
|
||||
/* 0xE4 */ &&opc_default, &&opc_fast_aldc, &&opc_fast_aldc_w, &&opc_return_register_finalizer,
|
||||
/* 0xE8 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default,
|
||||
/* 0xEC */ &&opc_default, &&opc_default, &&opc_default, &&opc_default,
|
||||
|
||||
@ -1718,8 +1718,7 @@ run:
|
||||
}
|
||||
// Need to throw illegal monitor state exception
|
||||
CALL_VM(InterpreterRuntime::throw_illegal_monitor_state_exception(THREAD), handle_exception);
|
||||
// Should never reach here...
|
||||
assert(false, "Should have thrown illegal monitor exception");
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
/* All of the non-quick opcodes. */
|
||||
@ -2147,6 +2146,74 @@ run:
|
||||
UPDATE_PC_AND_TOS_AND_CONTINUE(3, 2);
|
||||
}
|
||||
|
||||
CASE(_fast_aldc_w):
|
||||
CASE(_fast_aldc): {
|
||||
if (!EnableInvokeDynamic) {
|
||||
// We should not encounter this bytecode if !EnableInvokeDynamic.
|
||||
// The verifier will stop it. However, if we get past the verifier,
|
||||
// this will stop the thread in a reasonable way, without crashing the JVM.
|
||||
CALL_VM(InterpreterRuntime::throw_IncompatibleClassChangeError(THREAD),
|
||||
handle_exception);
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
u2 index;
|
||||
int incr;
|
||||
if (opcode == Bytecodes::_fast_aldc) {
|
||||
index = pc[1];
|
||||
incr = 2;
|
||||
} else {
|
||||
index = Bytes::get_native_u2(pc+1);
|
||||
incr = 3;
|
||||
}
|
||||
|
||||
// We are resolved if the f1 field contains a non-null object (CallSite, etc.)
|
||||
// This kind of CP cache entry does not need to match the flags byte, because
|
||||
// there is a 1-1 relation between bytecode type and CP entry type.
|
||||
ConstantPoolCacheEntry* cache = cp->entry_at(index);
|
||||
if (cache->is_f1_null()) {
|
||||
CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode),
|
||||
handle_exception);
|
||||
}
|
||||
|
||||
VERIFY_OOP(cache->f1());
|
||||
SET_STACK_OBJECT(cache->f1(), 0);
|
||||
UPDATE_PC_AND_TOS_AND_CONTINUE(incr, 1);
|
||||
}
|
||||
|
||||
CASE(_invokedynamic): {
|
||||
if (!EnableInvokeDynamic) {
|
||||
// We should not encounter this bytecode if !EnableInvokeDynamic.
|
||||
// The verifier will stop it. However, if we get past the verifier,
|
||||
// this will stop the thread in a reasonable way, without crashing the JVM.
|
||||
CALL_VM(InterpreterRuntime::throw_IncompatibleClassChangeError(THREAD),
|
||||
handle_exception);
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
int index = Bytes::get_native_u4(pc+1);
|
||||
|
||||
// We are resolved if the f1 field contains a non-null object (CallSite, etc.)
|
||||
// This kind of CP cache entry does not need to match the flags byte, because
|
||||
// there is a 1-1 relation between bytecode type and CP entry type.
|
||||
assert(constantPoolCacheOopDesc::is_secondary_index(index), "incorrect format");
|
||||
ConstantPoolCacheEntry* cache = cp->secondary_entry_at(index);
|
||||
if (cache->is_f1_null()) {
|
||||
CALL_VM(InterpreterRuntime::resolve_invokedynamic(THREAD),
|
||||
handle_exception);
|
||||
}
|
||||
|
||||
VERIFY_OOP(cache->f1());
|
||||
oop method_handle = java_lang_invoke_CallSite::target(cache->f1());
|
||||
CHECK_NULL(method_handle);
|
||||
|
||||
istate->set_msg(call_method_handle);
|
||||
istate->set_callee((methodOop) method_handle);
|
||||
istate->set_bcp_advance(5);
|
||||
|
||||
UPDATE_PC_AND_RETURN(0); // I'll be back...
|
||||
}
|
||||
|
||||
CASE(_invokeinterface): {
|
||||
u2 index = Bytes::get_native_u2(pc+1);
|
||||
|
||||
|
@ -107,6 +107,7 @@ public:
|
||||
rethrow_exception, // unwinding and throwing exception
|
||||
// requests to frame manager from C++ interpreter
|
||||
call_method, // request for new frame from interpreter, manager responds with method_entry
|
||||
call_method_handle, // like the above, except the callee is a method handle
|
||||
return_from_method, // request from interpreter to unwind, manager responds with method_continue
|
||||
more_monitors, // need a new monitor
|
||||
throwing_exception, // unwind stack and rethrow
|
||||
|
@ -345,7 +345,6 @@ void BytecodePrinter::print_field_or_method(int orig_i, int i, outputStream* st)
|
||||
break;
|
||||
case JVM_CONSTANT_NameAndType:
|
||||
case JVM_CONSTANT_InvokeDynamic:
|
||||
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||
has_klass = false;
|
||||
break;
|
||||
default:
|
||||
|
@ -369,10 +369,7 @@ IRT_ENTRY(void, InterpreterRuntime::throw_WrongMethodTypeException(JavaThread* t
|
||||
}
|
||||
|
||||
// create exception
|
||||
Symbol* java_lang_invoke_WrongMethodTypeException = vmSymbols::java_lang_invoke_WrongMethodTypeException();
|
||||
if (AllowTransitionalJSR292)
|
||||
java_lang_invoke_WrongMethodTypeException = SystemDictionaryHandles::WrongMethodTypeException_klass()->name();
|
||||
THROW_MSG(java_lang_invoke_WrongMethodTypeException, message);
|
||||
THROW_MSG(vmSymbols::java_lang_invoke_WrongMethodTypeException(), message);
|
||||
}
|
||||
IRT_END
|
||||
|
||||
|
@ -221,9 +221,7 @@ void LinkResolver::lookup_implicit_method(methodHandle& result,
|
||||
// Make sure the Java part of the runtime has been booted up.
|
||||
klassOop natives = SystemDictionary::MethodHandleNatives_klass();
|
||||
if (natives == NULL || instanceKlass::cast(natives)->is_not_initialized()) {
|
||||
Symbol* natives_name = vmSymbols::java_lang_invoke_MethodHandleNatives();
|
||||
if (natives != NULL && AllowTransitionalJSR292) natives_name = Klass::cast(natives)->name();
|
||||
SystemDictionary::resolve_or_fail(natives_name,
|
||||
SystemDictionary::resolve_or_fail(vmSymbols::java_lang_invoke_MethodHandleNatives(),
|
||||
Handle(),
|
||||
Handle(),
|
||||
true,
|
||||
|
@ -52,7 +52,6 @@ void Rewriter::compute_index_maps() {
|
||||
case JVM_CONSTANT_MethodHandle : // fall through
|
||||
case JVM_CONSTANT_MethodType : // fall through
|
||||
case JVM_CONSTANT_InvokeDynamic : // fall through
|
||||
case JVM_CONSTANT_InvokeDynamicTrans: // fall through
|
||||
add_cp_cache_entry(i);
|
||||
break;
|
||||
}
|
||||
@ -62,7 +61,6 @@ void Rewriter::compute_index_maps() {
|
||||
"all cp cache indexes fit in a u2");
|
||||
|
||||
_have_invoke_dynamic = ((tag_mask & (1 << JVM_CONSTANT_InvokeDynamic)) != 0);
|
||||
_have_invoke_dynamic |= ((tag_mask & (1 << JVM_CONSTANT_InvokeDynamicTrans)) != 0);
|
||||
}
|
||||
|
||||
|
||||
@ -81,16 +79,10 @@ void Rewriter::make_constant_pool_cache(TRAPS) {
|
||||
if (pool_index >= 0 &&
|
||||
_pool->tag_at(pool_index).is_invoke_dynamic()) {
|
||||
int bsm_index = _pool->invoke_dynamic_bootstrap_method_ref_index_at(pool_index);
|
||||
if (bsm_index != 0) {
|
||||
assert(_pool->tag_at(bsm_index).is_method_handle(), "must be a MH constant");
|
||||
// There is a CP cache entry holding the BSM for these calls.
|
||||
int bsm_cache_index = cp_entry_to_cp_cache(bsm_index);
|
||||
cache->entry_at(i)->initialize_bootstrap_method_index_in_cache(bsm_cache_index);
|
||||
} else {
|
||||
// There is no CP cache entry holding the BSM for these calls.
|
||||
// We will need to look for a class-global BSM, later.
|
||||
guarantee(AllowTransitionalJSR292, "");
|
||||
}
|
||||
assert(_pool->tag_at(bsm_index).is_method_handle(), "must be a MH constant");
|
||||
// There is a CP cache entry holding the BSM for these calls.
|
||||
int bsm_cache_index = cp_entry_to_cp_cache(bsm_index);
|
||||
cache->entry_at(i)->initialize_bootstrap_method_index_in_cache(bsm_cache_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -381,7 +381,6 @@ void constantPoolKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
case JVM_CONSTANT_MethodType :
|
||||
st->print("signature_index=%d", cp->method_type_index_at(index));
|
||||
break;
|
||||
case JVM_CONSTANT_InvokeDynamicTrans :
|
||||
case JVM_CONSTANT_InvokeDynamic :
|
||||
{
|
||||
st->print("bootstrap_method_index=%d", cp->invoke_dynamic_bootstrap_method_ref_index_at(index));
|
||||
|
@ -284,17 +284,13 @@ int constantPoolOopDesc::impl_name_and_type_ref_index_at(int which, bool uncache
|
||||
if (constantPoolCacheOopDesc::is_secondary_index(which)) {
|
||||
// Invokedynamic index.
|
||||
int pool_index = cache()->main_entry_at(which)->constant_pool_index();
|
||||
if (!AllowTransitionalJSR292 || tag_at(pool_index).is_invoke_dynamic())
|
||||
pool_index = invoke_dynamic_name_and_type_ref_index_at(pool_index);
|
||||
pool_index = invoke_dynamic_name_and_type_ref_index_at(pool_index);
|
||||
assert(tag_at(pool_index).is_name_and_type(), "");
|
||||
return pool_index;
|
||||
}
|
||||
// change byte-ordering and go via cache
|
||||
i = remap_instruction_operand_from_cache(which);
|
||||
} else {
|
||||
if (AllowTransitionalJSR292 && tag_at(which).is_name_and_type())
|
||||
// invokedynamic index is a simple name-and-type
|
||||
return which;
|
||||
if (tag_at(which).is_invoke_dynamic()) {
|
||||
int pool_index = invoke_dynamic_name_and_type_ref_index_at(which);
|
||||
assert(tag_at(pool_index).is_name_and_type(), "");
|
||||
@ -953,7 +949,6 @@ bool constantPoolOopDesc::compare_entry_to(int index1, constantPoolHandle cp2,
|
||||
} break;
|
||||
|
||||
case JVM_CONSTANT_InvokeDynamic:
|
||||
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||
{
|
||||
int k1 = invoke_dynamic_bootstrap_method_ref_index_at(index1);
|
||||
int k2 = cp2->invoke_dynamic_bootstrap_method_ref_index_at(index2);
|
||||
@ -1227,13 +1222,6 @@ void constantPoolOopDesc::copy_entry_to(constantPoolHandle from_cp, int from_i,
|
||||
to_cp->method_handle_index_at_put(to_i, k1, k2);
|
||||
} break;
|
||||
|
||||
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||
{
|
||||
int k1 = from_cp->invoke_dynamic_bootstrap_method_ref_index_at(from_i);
|
||||
int k2 = from_cp->invoke_dynamic_name_and_type_ref_index_at(from_i);
|
||||
to_cp->invoke_dynamic_trans_at_put(to_i, k1, k2);
|
||||
} break;
|
||||
|
||||
case JVM_CONSTANT_InvokeDynamic:
|
||||
{
|
||||
int k1 = from_cp->invoke_dynamic_bootstrap_specifier_index(from_i);
|
||||
@ -1459,7 +1447,6 @@ jint constantPoolOopDesc::cpool_entry_size(jint idx) {
|
||||
return 5;
|
||||
|
||||
case JVM_CONSTANT_InvokeDynamic:
|
||||
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||
// u1 tag, u2 bsm, u2 nt
|
||||
return 5;
|
||||
|
||||
@ -1674,7 +1661,6 @@ int constantPoolOopDesc::copy_cpool_bytes(int cpool_size,
|
||||
DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1));
|
||||
break;
|
||||
}
|
||||
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||
case JVM_CONSTANT_InvokeDynamic: {
|
||||
*bytes = tag;
|
||||
idx1 = extract_low_short_from_int(*int_at_addr(idx));
|
||||
|
@ -244,12 +244,6 @@ class constantPoolOopDesc : public oopDesc {
|
||||
*int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_specifier_index;
|
||||
}
|
||||
|
||||
void invoke_dynamic_trans_at_put(int which, int bootstrap_method_index, int name_and_type_index) {
|
||||
tag_at_put(which, JVM_CONSTANT_InvokeDynamicTrans);
|
||||
*int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_method_index;
|
||||
assert(AllowTransitionalJSR292, "");
|
||||
}
|
||||
|
||||
// Temporary until actual use
|
||||
void unresolved_string_at_put(int which, Symbol* s) {
|
||||
release_tag_at_put(which, JVM_CONSTANT_UnresolvedString);
|
||||
@ -570,15 +564,11 @@ class constantPoolOopDesc : public oopDesc {
|
||||
};
|
||||
int invoke_dynamic_bootstrap_method_ref_index_at(int which) {
|
||||
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
|
||||
if (tag_at(which).value() == JVM_CONSTANT_InvokeDynamicTrans)
|
||||
return extract_low_short_from_int(*int_at_addr(which));
|
||||
int op_base = invoke_dynamic_operand_base(which);
|
||||
return operands()->short_at(op_base + _indy_bsm_offset);
|
||||
}
|
||||
int invoke_dynamic_argument_count_at(int which) {
|
||||
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
|
||||
if (tag_at(which).value() == JVM_CONSTANT_InvokeDynamicTrans)
|
||||
return 0;
|
||||
int op_base = invoke_dynamic_operand_base(which);
|
||||
int argc = operands()->short_at(op_base + _indy_argc_offset);
|
||||
DEBUG_ONLY(int end_offset = op_base + _indy_argv_offset + argc;
|
||||
|
@ -185,7 +185,7 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
|
||||
this->print(tty, 0);
|
||||
}
|
||||
assert(method->can_be_statically_bound(), "must be a MH invoker method");
|
||||
assert(AllowTransitionalJSR292 || _f2 >= constantPoolOopDesc::CPCACHE_INDEX_TAG, "BSM index initialized");
|
||||
assert(_f2 >= constantPoolOopDesc::CPCACHE_INDEX_TAG, "BSM index initialized");
|
||||
// SystemDictionary::find_method_handle_invoke only caches
|
||||
// methods which signature classes are on the boot classpath,
|
||||
// otherwise the newly created method is returned. To avoid
|
||||
|
@ -191,8 +191,6 @@ class instanceKlass: public Klass {
|
||||
typeArrayOop _inner_classes;
|
||||
// Implementors of this interface (not valid if it overflows)
|
||||
klassOop _implementors[implementors_limit];
|
||||
// invokedynamic bootstrap method (a java.lang.invoke.MethodHandle)
|
||||
oop _bootstrap_method; // AllowTransitionalJSR292 ONLY
|
||||
// Annotations for this class, or null if none.
|
||||
typeArrayOop _class_annotations;
|
||||
// Annotation objects (byte arrays) for fields, or null if no annotations.
|
||||
@ -526,10 +524,6 @@ class instanceKlass: public Klass {
|
||||
u2 method_index) { _enclosing_method_class_index = class_index;
|
||||
_enclosing_method_method_index = method_index; }
|
||||
|
||||
// JSR 292 support
|
||||
oop bootstrap_method() const { return _bootstrap_method; } // AllowTransitionalJSR292 ONLY
|
||||
void set_bootstrap_method(oop mh) { oop_store(&_bootstrap_method, mh); }
|
||||
|
||||
// jmethodID support
|
||||
static jmethodID get_jmethod_id(instanceKlassHandle ik_h,
|
||||
methodHandle method_h);
|
||||
@ -793,7 +787,6 @@ private:
|
||||
oop* adr_signers() const { return (oop*)&this->_signers;}
|
||||
oop* adr_inner_classes() const { return (oop*)&this->_inner_classes;}
|
||||
oop* adr_implementors() const { return (oop*)&this->_implementors[0];}
|
||||
oop* adr_bootstrap_method() const { return (oop*)&this->_bootstrap_method;} // AllowTransitionalJSR292 ONLY
|
||||
oop* adr_methods_jmethod_ids() const { return (oop*)&this->_methods_jmethod_ids;}
|
||||
oop* adr_methods_cached_itable_indices() const { return (oop*)&this->_methods_cached_itable_indices;}
|
||||
oop* adr_class_annotations() const { return (oop*)&this->_class_annotations;}
|
||||
|
@ -105,7 +105,6 @@ void instanceKlassKlass::oop_follow_contents(oop obj) {
|
||||
MarkSweep::mark_and_push(ik->adr_protection_domain());
|
||||
MarkSweep::mark_and_push(ik->adr_host_klass());
|
||||
MarkSweep::mark_and_push(ik->adr_signers());
|
||||
MarkSweep::mark_and_push(ik->adr_bootstrap_method());
|
||||
MarkSweep::mark_and_push(ik->adr_class_annotations());
|
||||
MarkSweep::mark_and_push(ik->adr_fields_annotations());
|
||||
MarkSweep::mark_and_push(ik->adr_methods_annotations());
|
||||
@ -142,7 +141,6 @@ void instanceKlassKlass::oop_follow_contents(ParCompactionManager* cm,
|
||||
PSParallelCompact::mark_and_push(cm, ik->adr_protection_domain());
|
||||
PSParallelCompact::mark_and_push(cm, ik->adr_host_klass());
|
||||
PSParallelCompact::mark_and_push(cm, ik->adr_signers());
|
||||
PSParallelCompact::mark_and_push(cm, ik->adr_bootstrap_method());
|
||||
PSParallelCompact::mark_and_push(cm, ik->adr_class_annotations());
|
||||
PSParallelCompact::mark_and_push(cm, ik->adr_fields_annotations());
|
||||
PSParallelCompact::mark_and_push(cm, ik->adr_methods_annotations());
|
||||
@ -185,7 +183,6 @@ int instanceKlassKlass::oop_oop_iterate(oop obj, OopClosure* blk) {
|
||||
for (int i = 0; i < instanceKlass::implementors_limit; i++) {
|
||||
blk->do_oop(&ik->adr_implementors()[i]);
|
||||
}
|
||||
blk->do_oop(ik->adr_bootstrap_method());
|
||||
blk->do_oop(ik->adr_class_annotations());
|
||||
blk->do_oop(ik->adr_fields_annotations());
|
||||
blk->do_oop(ik->adr_methods_annotations());
|
||||
@ -239,8 +236,6 @@ int instanceKlassKlass::oop_oop_iterate_m(oop obj, OopClosure* blk,
|
||||
for (int i = 0; i < instanceKlass::implementors_limit; i++) {
|
||||
if (mr.contains(&adr[i])) blk->do_oop(&adr[i]);
|
||||
}
|
||||
adr = ik->adr_bootstrap_method();
|
||||
if (mr.contains(adr)) blk->do_oop(adr);
|
||||
adr = ik->adr_class_annotations();
|
||||
if (mr.contains(adr)) blk->do_oop(adr);
|
||||
adr = ik->adr_fields_annotations();
|
||||
@ -281,7 +276,6 @@ int instanceKlassKlass::oop_adjust_pointers(oop obj) {
|
||||
for (int i = 0; i < instanceKlass::implementors_limit; i++) {
|
||||
MarkSweep::adjust_pointer(&ik->adr_implementors()[i]);
|
||||
}
|
||||
MarkSweep::adjust_pointer(ik->adr_bootstrap_method());
|
||||
MarkSweep::adjust_pointer(ik->adr_class_annotations());
|
||||
MarkSweep::adjust_pointer(ik->adr_fields_annotations());
|
||||
MarkSweep::adjust_pointer(ik->adr_methods_annotations());
|
||||
@ -317,11 +311,6 @@ void instanceKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
|
||||
pm->claim_or_forward_depth(sg_addr);
|
||||
}
|
||||
|
||||
oop* bsm_addr = ik->adr_bootstrap_method();
|
||||
if (PSScavenge::should_scavenge(bsm_addr)) {
|
||||
pm->claim_or_forward_depth(bsm_addr);
|
||||
}
|
||||
|
||||
klassKlass::oop_push_contents(pm, obj);
|
||||
}
|
||||
|
||||
@ -420,7 +409,6 @@ instanceKlassKlass::allocate_instance_klass(Symbol* name, int vtable_len, int it
|
||||
ik->set_breakpoints(NULL);
|
||||
ik->init_previous_versions();
|
||||
ik->set_generic_signature(NULL);
|
||||
ik->set_bootstrap_method(NULL);
|
||||
ik->release_set_methods_jmethod_ids(NULL);
|
||||
ik->release_set_methods_cached_itable_indices(NULL);
|
||||
ik->set_class_annotations(NULL);
|
||||
@ -542,11 +530,6 @@ void instanceKlassKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
} // pvw is cleaned up
|
||||
} // rm is cleaned up
|
||||
|
||||
if (ik->bootstrap_method() != NULL) {
|
||||
st->print(BULLET"bootstrap method: ");
|
||||
ik->bootstrap_method()->print_value_on(st);
|
||||
st->cr();
|
||||
}
|
||||
if (ik->generic_signature() != NULL) {
|
||||
st->print(BULLET"generic signature: ");
|
||||
ik->generic_signature()->print_value_on(st);
|
||||
|
@ -852,11 +852,11 @@ bool methodOopDesc::should_not_be_cached() const {
|
||||
bool methodOopDesc::is_method_handle_invoke_name(vmSymbols::SID name_sid) {
|
||||
switch (name_sid) {
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name):
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name):
|
||||
return true;
|
||||
}
|
||||
if ((AllowTransitionalJSR292 || AllowInvokeForInvokeGeneric)
|
||||
&& name_sid == vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name))
|
||||
if (AllowInvokeGeneric
|
||||
&& name_sid == vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@ -921,6 +921,10 @@ methodHandle methodOopDesc::make_invoke_method(KlassHandle holder,
|
||||
tty->cr();
|
||||
}
|
||||
|
||||
// invariant: cp->symbol_at_put is preceded by a refcount increment (more usually a lookup)
|
||||
name->increment_refcount();
|
||||
signature->increment_refcount();
|
||||
|
||||
constantPoolHandle cp;
|
||||
{
|
||||
constantPoolOop cp_oop = oopFactory::new_constantPool(_imcp_limit, IsSafeConc, CHECK_(empty));
|
||||
@ -1092,7 +1096,6 @@ void methodOopDesc::init_intrinsic_id() {
|
||||
if (name_id == vmSymbols::NO_SID) return;
|
||||
vmSymbols::SID sig_id = vmSymbols::find_sid(signature());
|
||||
if (klass_id != vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_MethodHandle)
|
||||
&& !(klass_id == vmSymbols::VM_SYMBOL_ENUM_NAME(java_dyn_MethodHandle) && AllowTransitionalJSR292)
|
||||
&& sig_id == vmSymbols::NO_SID) return;
|
||||
jshort flags = access_flags().as_short();
|
||||
|
||||
@ -1118,20 +1121,17 @@ void methodOopDesc::init_intrinsic_id() {
|
||||
break;
|
||||
|
||||
// Signature-polymorphic methods: MethodHandle.invoke*, InvokeDynamic.*.
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_dyn_MethodHandle): // AllowTransitionalJSR292 ONLY
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_MethodHandle):
|
||||
if (is_static() || !is_native()) break;
|
||||
switch (name_id) {
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeGeneric_name):
|
||||
if (!AllowInvokeGeneric) break;
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name):
|
||||
id = vmIntrinsics::_invokeGeneric;
|
||||
break;
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(invokeExact_name):
|
||||
id = vmIntrinsics::_invokeExact;
|
||||
break;
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(invoke_name):
|
||||
if (AllowInvokeForInvokeGeneric) id = vmIntrinsics::_invokeGeneric;
|
||||
else if (AllowTransitionalJSR292) id = vmIntrinsics::_invokeExact;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_InvokeDynamic):
|
||||
|
@ -978,31 +978,19 @@ WarmCallInfo* WarmCallInfo::remove_from(WarmCallInfo* head) {
|
||||
return head;
|
||||
}
|
||||
|
||||
WarmCallInfo* WarmCallInfo::_always_hot = NULL;
|
||||
WarmCallInfo* WarmCallInfo::_always_cold = NULL;
|
||||
WarmCallInfo WarmCallInfo::_always_hot(WarmCallInfo::MAX_VALUE(), WarmCallInfo::MAX_VALUE(),
|
||||
WarmCallInfo::MIN_VALUE(), WarmCallInfo::MIN_VALUE());
|
||||
WarmCallInfo WarmCallInfo::_always_cold(WarmCallInfo::MIN_VALUE(), WarmCallInfo::MIN_VALUE(),
|
||||
WarmCallInfo::MAX_VALUE(), WarmCallInfo::MAX_VALUE());
|
||||
|
||||
WarmCallInfo* WarmCallInfo::always_hot() {
|
||||
if (_always_hot == NULL) {
|
||||
static double bits[sizeof(WarmCallInfo) / sizeof(double) + 1] = {0};
|
||||
WarmCallInfo* ci = (WarmCallInfo*) bits;
|
||||
ci->_profit = ci->_count = MAX_VALUE();
|
||||
ci->_work = ci->_size = MIN_VALUE();
|
||||
_always_hot = ci;
|
||||
}
|
||||
assert(_always_hot->is_hot(), "must always be hot");
|
||||
return _always_hot;
|
||||
assert(_always_hot.is_hot(), "must always be hot");
|
||||
return &_always_hot;
|
||||
}
|
||||
|
||||
WarmCallInfo* WarmCallInfo::always_cold() {
|
||||
if (_always_cold == NULL) {
|
||||
static double bits[sizeof(WarmCallInfo) / sizeof(double) + 1] = {0};
|
||||
WarmCallInfo* ci = (WarmCallInfo*) bits;
|
||||
ci->_profit = ci->_count = MIN_VALUE();
|
||||
ci->_work = ci->_size = MAX_VALUE();
|
||||
_always_cold = ci;
|
||||
}
|
||||
assert(_always_cold->is_cold(), "must always be cold");
|
||||
return _always_cold;
|
||||
assert(_always_cold.is_cold(), "must always be cold");
|
||||
return &_always_cold;
|
||||
}
|
||||
|
||||
|
||||
|
@ -215,8 +215,20 @@ class WarmCallInfo : public ResourceObj {
|
||||
WarmCallInfo* next() const { return _next; }
|
||||
void set_next(WarmCallInfo* n) { _next = n; }
|
||||
|
||||
static WarmCallInfo* _always_hot;
|
||||
static WarmCallInfo* _always_cold;
|
||||
static WarmCallInfo _always_hot;
|
||||
static WarmCallInfo _always_cold;
|
||||
|
||||
// Constructor intitialization of always_hot and always_cold
|
||||
WarmCallInfo(float c, float p, float w, float s) {
|
||||
_call = NULL;
|
||||
_hot_cg = NULL;
|
||||
_next = NULL;
|
||||
_count = c;
|
||||
_profit = p;
|
||||
_work = w;
|
||||
_size = s;
|
||||
_heat = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
// Because WarmInfo objects live over the entire lifetime of the
|
||||
|
@ -1349,9 +1349,17 @@ static Node* is_absolute( PhaseGVN *phase, PhiNode *phi_root, int true_path) {
|
||||
static void split_once(PhaseIterGVN *igvn, Node *phi, Node *val, Node *n, Node *newn) {
|
||||
igvn->hash_delete(n); // Remove from hash before hacking edges
|
||||
|
||||
Node* predicate_proj = NULL;
|
||||
uint j = 1;
|
||||
for( uint i = phi->req()-1; i > 0; i-- ) {
|
||||
if( phi->in(i) == val ) { // Found a path with val?
|
||||
for (uint i = phi->req()-1; i > 0; i--) {
|
||||
if (phi->in(i) == val) { // Found a path with val?
|
||||
if (n->is_Region()) {
|
||||
Node* proj = PhaseIdealLoop::find_predicate(n->in(i));
|
||||
if (proj != NULL) {
|
||||
assert(predicate_proj == NULL, "only one predicate entry expected");
|
||||
predicate_proj = proj;
|
||||
}
|
||||
}
|
||||
// Add to NEW Region/Phi, no DU info
|
||||
newn->set_req( j++, n->in(i) );
|
||||
// Remove from OLD Region/Phi
|
||||
@ -1362,6 +1370,12 @@ static void split_once(PhaseIterGVN *igvn, Node *phi, Node *val, Node *n, Node *
|
||||
// Register the new node but do not transform it. Cannot transform until the
|
||||
// entire Region/Phi conglomerate has been hacked as a single huge transform.
|
||||
igvn->register_new_node_with_optimizer( newn );
|
||||
|
||||
// Clone loop predicates
|
||||
if (predicate_proj != NULL) {
|
||||
newn = igvn->clone_loop_predicates(predicate_proj, newn);
|
||||
}
|
||||
|
||||
// Now I can point to the new node.
|
||||
n->add_req(newn);
|
||||
igvn->_worklist.push(n);
|
||||
|
@ -1632,7 +1632,6 @@ void Compile::cleanup_loop_predicates(PhaseIterGVN &igvn) {
|
||||
igvn.replace_node(n, n->in(1));
|
||||
}
|
||||
assert(predicate_count()==0, "should be clean!");
|
||||
igvn.optimize();
|
||||
}
|
||||
|
||||
//------------------------------Optimize---------------------------------------
|
||||
@ -1689,7 +1688,7 @@ void Compile::Optimize() {
|
||||
if((loop_opts_cnt > 0) && (has_loops() || has_split_ifs())) {
|
||||
{
|
||||
TracePhase t2("idealLoop", &_t_idealLoop, true);
|
||||
PhaseIdealLoop ideal_loop( igvn, true, UseLoopPredicate);
|
||||
PhaseIdealLoop ideal_loop( igvn, true );
|
||||
loop_opts_cnt--;
|
||||
if (major_progress()) print_method("PhaseIdealLoop 1", 2);
|
||||
if (failing()) return;
|
||||
@ -1697,7 +1696,7 @@ void Compile::Optimize() {
|
||||
// Loop opts pass if partial peeling occurred in previous pass
|
||||
if(PartialPeelLoop && major_progress() && (loop_opts_cnt > 0)) {
|
||||
TracePhase t3("idealLoop", &_t_idealLoop, true);
|
||||
PhaseIdealLoop ideal_loop( igvn, false, UseLoopPredicate);
|
||||
PhaseIdealLoop ideal_loop( igvn, false );
|
||||
loop_opts_cnt--;
|
||||
if (major_progress()) print_method("PhaseIdealLoop 2", 2);
|
||||
if (failing()) return;
|
||||
@ -1705,7 +1704,7 @@ void Compile::Optimize() {
|
||||
// Loop opts pass for loop-unrolling before CCP
|
||||
if(major_progress() && (loop_opts_cnt > 0)) {
|
||||
TracePhase t4("idealLoop", &_t_idealLoop, true);
|
||||
PhaseIdealLoop ideal_loop( igvn, false, UseLoopPredicate);
|
||||
PhaseIdealLoop ideal_loop( igvn, false );
|
||||
loop_opts_cnt--;
|
||||
if (major_progress()) print_method("PhaseIdealLoop 3", 2);
|
||||
}
|
||||
@ -1743,21 +1742,13 @@ void Compile::Optimize() {
|
||||
// peeling, unrolling, etc.
|
||||
if(loop_opts_cnt > 0) {
|
||||
debug_only( int cnt = 0; );
|
||||
bool loop_predication = UseLoopPredicate;
|
||||
while(major_progress() && (loop_opts_cnt > 0)) {
|
||||
TracePhase t2("idealLoop", &_t_idealLoop, true);
|
||||
assert( cnt++ < 40, "infinite cycle in loop optimization" );
|
||||
PhaseIdealLoop ideal_loop( igvn, true, loop_predication);
|
||||
PhaseIdealLoop ideal_loop( igvn, true);
|
||||
loop_opts_cnt--;
|
||||
if (major_progress()) print_method("PhaseIdealLoop iterations", 2);
|
||||
if (failing()) return;
|
||||
// Perform loop predication optimization during first iteration after CCP.
|
||||
// After that switch it off and cleanup unused loop predicates.
|
||||
if (loop_predication) {
|
||||
loop_predication = false;
|
||||
cleanup_loop_predicates(igvn);
|
||||
if (failing()) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,6 +489,9 @@ class Compile : public Phase {
|
||||
// remove the opaque nodes that protect the predicates so that the unused checks and
|
||||
// uncommon traps will be eliminated from the graph.
|
||||
void cleanup_loop_predicates(PhaseIterGVN &igvn);
|
||||
bool is_predicate_opaq(Node * n) {
|
||||
return _predicate_opaqs->contains(n);
|
||||
}
|
||||
|
||||
// Compilation environment.
|
||||
Arena* comp_arena() { return &_comp_arena; }
|
||||
|
@ -63,6 +63,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
||||
JVMState* jvms, bool allow_inline,
|
||||
float prof_factor) {
|
||||
CallGenerator* cg;
|
||||
guarantee(call_method != NULL, "failed method resolution");
|
||||
|
||||
// Dtrace currently doesn't work unless all calls are vanilla
|
||||
if (env()->dtrace_method_probes()) {
|
||||
@ -130,8 +131,9 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
||||
|
||||
// Get an adapter for the MethodHandle.
|
||||
ciMethod* target_method = method_handle->get_method_handle_adapter();
|
||||
|
||||
CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
|
||||
CallGenerator* hit_cg = NULL;
|
||||
if (target_method != NULL)
|
||||
hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
|
||||
if (hit_cg != NULL && hit_cg->is_inline())
|
||||
return hit_cg;
|
||||
}
|
||||
@ -152,8 +154,9 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
|
||||
|
||||
// Get an adapter for the MethodHandle.
|
||||
ciMethod* target_method = method_handle->get_invokedynamic_adapter();
|
||||
|
||||
CallGenerator* hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
|
||||
CallGenerator* hit_cg = NULL;
|
||||
if (target_method != NULL)
|
||||
hit_cg = this->call_generator(target_method, vtable_index, false, jvms, true, prof_factor);
|
||||
if (hit_cg != NULL && hit_cg->is_inline()) {
|
||||
CallGenerator* miss_cg = CallGenerator::for_dynamic_call(call_method);
|
||||
return CallGenerator::for_predicted_dynamic_call(method_handle, miss_cg, hit_cg, prof_factor);
|
||||
|
@ -594,7 +594,7 @@ bool ConnectionGraph::split_AddP(Node *addp, Node *base, PhaseGVN *igvn) {
|
||||
|
||||
//
|
||||
// Create a new version of orig_phi if necessary. Returns either the newly
|
||||
// created phi or an existing phi. Sets create_new to indicate wheter a new
|
||||
// created phi or an existing phi. Sets create_new to indicate whether a new
|
||||
// phi was created. Cache the last newly created phi in the node map.
|
||||
//
|
||||
PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn, bool &new_created) {
|
||||
@ -649,7 +649,7 @@ PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, Gro
|
||||
}
|
||||
|
||||
//
|
||||
// Return a new version of Memory Phi "orig_phi" with the inputs having the
|
||||
// Return a new version of Memory Phi "orig_phi" with the inputs having the
|
||||
// specified alias index.
|
||||
//
|
||||
PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn) {
|
||||
@ -828,11 +828,15 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
|
||||
break; // hit one of our sentinels
|
||||
if (result->is_Mem()) {
|
||||
const Type *at = phase->type(result->in(MemNode::Address));
|
||||
if (at != Type::TOP) {
|
||||
assert (at->isa_ptr() != NULL, "pointer type required.");
|
||||
int idx = C->get_alias_index(at->is_ptr());
|
||||
if (idx == alias_idx)
|
||||
break;
|
||||
if (at == Type::TOP)
|
||||
break; // Dead
|
||||
assert (at->isa_ptr() != NULL, "pointer type required.");
|
||||
int idx = C->get_alias_index(at->is_ptr());
|
||||
if (idx == alias_idx)
|
||||
break; // Found
|
||||
if (!is_instance && (at->isa_oopptr() == NULL ||
|
||||
!at->is_oopptr()->is_known_instance())) {
|
||||
break; // Do not skip store to general memory slice.
|
||||
}
|
||||
result = result->in(MemNode::Memory);
|
||||
}
|
||||
@ -902,13 +906,13 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
|
||||
PhiNode *mphi = result->as_Phi();
|
||||
assert(mphi->bottom_type() == Type::MEMORY, "memory phi required");
|
||||
const TypePtr *t = mphi->adr_type();
|
||||
if (C->get_alias_index(t) != alias_idx) {
|
||||
// Create a new Phi with the specified alias index type.
|
||||
result = split_memory_phi(mphi, alias_idx, orig_phis, phase);
|
||||
} else if (!is_instance) {
|
||||
if (!is_instance) {
|
||||
// Push all non-instance Phis on the orig_phis worklist to update inputs
|
||||
// during Phase 4 if needed.
|
||||
orig_phis.append_if_missing(mphi);
|
||||
} else if (C->get_alias_index(t) != alias_idx) {
|
||||
// Create a new Phi with the specified alias index type.
|
||||
result = split_memory_phi(mphi, alias_idx, orig_phis, phase);
|
||||
}
|
||||
}
|
||||
// the result is either MemNode, PhiNode, InitializeNode.
|
||||
|
@ -3385,10 +3385,15 @@ void GraphKit::add_predicate(int nargs) {
|
||||
#define __ ideal.
|
||||
|
||||
void GraphKit::sync_kit(IdealKit& ideal) {
|
||||
set_all_memory(__ merged_memory());
|
||||
set_i_o(__ i_o());
|
||||
set_control(__ ctrl());
|
||||
}
|
||||
|
||||
void GraphKit::final_sync(IdealKit& ideal) {
|
||||
// Final sync IdealKit and graphKit.
|
||||
__ drain_delay_transform();
|
||||
set_all_memory(__ merged_memory());
|
||||
set_control(__ ctrl());
|
||||
sync_kit(ideal);
|
||||
}
|
||||
|
||||
// vanilla/CMS post barrier
|
||||
@ -3435,7 +3440,7 @@ void GraphKit::write_barrier_post(Node* oop_store,
|
||||
// (Else it's an array (or unknown), and we want more precise card marks.)
|
||||
assert(adr != NULL, "");
|
||||
|
||||
IdealKit ideal(gvn(), control(), merged_memory(), true);
|
||||
IdealKit ideal(this, true);
|
||||
|
||||
// Convert the pointer to an int prior to doing math on it
|
||||
Node* cast = __ CastPX(__ ctrl(), adr);
|
||||
@ -3461,7 +3466,7 @@ void GraphKit::write_barrier_post(Node* oop_store,
|
||||
}
|
||||
|
||||
// Final sync IdealKit and GraphKit.
|
||||
sync_kit(ideal);
|
||||
final_sync(ideal);
|
||||
}
|
||||
|
||||
// G1 pre/post barriers
|
||||
@ -3471,7 +3476,7 @@ void GraphKit::g1_write_barrier_pre(Node* obj,
|
||||
Node* val,
|
||||
const TypeOopPtr* val_type,
|
||||
BasicType bt) {
|
||||
IdealKit ideal(gvn(), control(), merged_memory(), true);
|
||||
IdealKit ideal(this, true);
|
||||
|
||||
Node* tls = __ thread(); // ThreadLocalStorage
|
||||
|
||||
@ -3548,7 +3553,7 @@ void GraphKit::g1_write_barrier_pre(Node* obj,
|
||||
} __ end_if(); // (!marking)
|
||||
|
||||
// Final sync IdealKit and GraphKit.
|
||||
sync_kit(ideal);
|
||||
final_sync(ideal);
|
||||
}
|
||||
|
||||
//
|
||||
@ -3614,7 +3619,7 @@ void GraphKit::g1_write_barrier_post(Node* oop_store,
|
||||
// (Else it's an array (or unknown), and we want more precise card marks.)
|
||||
assert(adr != NULL, "");
|
||||
|
||||
IdealKit ideal(gvn(), control(), merged_memory(), true);
|
||||
IdealKit ideal(this, true);
|
||||
|
||||
Node* tls = __ thread(); // ThreadLocalStorage
|
||||
|
||||
@ -3688,6 +3693,6 @@ void GraphKit::g1_write_barrier_post(Node* oop_store,
|
||||
}
|
||||
|
||||
// Final sync IdealKit and GraphKit.
|
||||
sync_kit(ideal);
|
||||
final_sync(ideal);
|
||||
}
|
||||
#undef __
|
||||
|
@ -662,7 +662,9 @@ class GraphKit : public Phase {
|
||||
&& Universe::heap()->can_elide_tlab_store_barriers());
|
||||
}
|
||||
|
||||
// Sync Ideal and Graph kits.
|
||||
void sync_kit(IdealKit& ideal);
|
||||
void final_sync(IdealKit& ideal);
|
||||
|
||||
// vanilla/CMS post barrier
|
||||
void write_barrier_post(Node *store, Node* obj,
|
||||
|
@ -38,15 +38,16 @@
|
||||
const uint IdealKit::first_var = TypeFunc::Parms + 1;
|
||||
|
||||
//----------------------------IdealKit-----------------------------------------
|
||||
IdealKit::IdealKit(PhaseGVN &gvn, Node* control, Node* mem, bool delay_all_transforms, bool has_declarations) :
|
||||
_gvn(gvn), C(gvn.C) {
|
||||
_initial_ctrl = control;
|
||||
_initial_memory = mem;
|
||||
IdealKit::IdealKit(GraphKit* gkit, bool delay_all_transforms, bool has_declarations) :
|
||||
_gvn(gkit->gvn()), C(gkit->C) {
|
||||
_initial_ctrl = gkit->control();
|
||||
_initial_memory = gkit->merged_memory();
|
||||
_initial_i_o = gkit->i_o();
|
||||
_delay_all_transforms = delay_all_transforms;
|
||||
_var_ct = 0;
|
||||
_cvstate = NULL;
|
||||
// We can go memory state free or else we need the entire memory state
|
||||
assert(mem == NULL || mem->Opcode() == Op_MergeMem, "memory must be pre-split");
|
||||
assert(_initial_memory == NULL || _initial_memory->Opcode() == Op_MergeMem, "memory must be pre-split");
|
||||
int init_size = 5;
|
||||
_pending_cvstates = new (C->node_arena()) GrowableArray<Node*>(C->node_arena(), init_size, 0, 0);
|
||||
_delay_transform = new (C->node_arena()) GrowableArray<Node*>(C->node_arena(), init_size, 0, 0);
|
||||
@ -56,6 +57,13 @@ IdealKit::IdealKit(PhaseGVN &gvn, Node* control, Node* mem, bool delay_all_trans
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------sync_kit-----------------------------------------
|
||||
void IdealKit::sync_kit(GraphKit* gkit) {
|
||||
set_all_memory(gkit->merged_memory());
|
||||
set_i_o(gkit->i_o());
|
||||
set_ctrl(gkit->control());
|
||||
}
|
||||
|
||||
//-------------------------------if_then-------------------------------------
|
||||
// Create: if(left relop right)
|
||||
// / \
|
||||
@ -156,16 +164,14 @@ void IdealKit::end_if() {
|
||||
// onto the stack.
|
||||
void IdealKit::loop(GraphKit* gkit, int nargs, IdealVariable& iv, Node* init, BoolTest::mask relop, Node* limit, float prob, float cnt) {
|
||||
assert((state() & (BlockS|LoopS|IfThenS|ElseS)), "bad state for new loop");
|
||||
|
||||
// Sync IdealKit and graphKit.
|
||||
gkit->set_all_memory(this->merged_memory());
|
||||
gkit->set_control(this->ctrl());
|
||||
// Add loop predicate.
|
||||
gkit->add_predicate(nargs);
|
||||
// Update IdealKit memory.
|
||||
this->set_all_memory(gkit->merged_memory());
|
||||
this->set_ctrl(gkit->control());
|
||||
|
||||
if (UseLoopPredicate) {
|
||||
// Sync IdealKit and graphKit.
|
||||
gkit->sync_kit(*this);
|
||||
// Add loop predicate.
|
||||
gkit->add_predicate(nargs);
|
||||
// Update IdealKit memory.
|
||||
sync_kit(gkit);
|
||||
}
|
||||
set(iv, init);
|
||||
Node* head = make_label(1);
|
||||
bind(head);
|
||||
@ -280,6 +286,7 @@ void IdealKit::declarations_done() {
|
||||
_cvstate = new_cvstate(); // initialize current cvstate
|
||||
set_ctrl(_initial_ctrl); // initialize control in current cvstate
|
||||
set_all_memory(_initial_memory);// initialize memory in current cvstate
|
||||
set_i_o(_initial_i_o); // initialize i_o in current cvstate
|
||||
DEBUG_ONLY(_state->push(BlockS));
|
||||
}
|
||||
|
||||
@ -421,6 +428,9 @@ void IdealKit::do_memory_merge(Node* merging, Node* join) {
|
||||
// Get the region for the join state
|
||||
Node* join_region = join->in(TypeFunc::Control);
|
||||
assert(join_region != NULL, "join region must exist");
|
||||
if (join->in(TypeFunc::I_O) == NULL ) {
|
||||
join->set_req(TypeFunc::I_O, merging->in(TypeFunc::I_O));
|
||||
}
|
||||
if (join->in(TypeFunc::Memory) == NULL ) {
|
||||
join->set_req(TypeFunc::Memory, merging->in(TypeFunc::Memory));
|
||||
return;
|
||||
@ -467,6 +477,20 @@ void IdealKit::do_memory_merge(Node* merging, Node* join) {
|
||||
mms.set_memory(phi);
|
||||
}
|
||||
}
|
||||
|
||||
Node* join_io = join->in(TypeFunc::I_O);
|
||||
Node* merging_io = merging->in(TypeFunc::I_O);
|
||||
if (join_io != merging_io) {
|
||||
PhiNode* phi;
|
||||
if (join_io->is_Phi() && join_io->as_Phi()->region() == join_region) {
|
||||
phi = join_io->as_Phi();
|
||||
} else {
|
||||
phi = PhiNode::make(join_region, join_io, Type::ABIO);
|
||||
phi = (PhiNode*) delay_transform(phi);
|
||||
join->set_req(TypeFunc::I_O, phi);
|
||||
}
|
||||
phi->set_req(slot, merging_io);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -477,7 +501,8 @@ void IdealKit::make_leaf_call(const TypeFunc *slow_call_type,
|
||||
const char *leaf_name,
|
||||
Node* parm0,
|
||||
Node* parm1,
|
||||
Node* parm2) {
|
||||
Node* parm2,
|
||||
Node* parm3) {
|
||||
|
||||
// We only handle taking in RawMem and modifying RawMem
|
||||
const TypePtr* adr_type = TypeRawPtr::BOTTOM;
|
||||
@ -498,6 +523,55 @@ void IdealKit::make_leaf_call(const TypeFunc *slow_call_type,
|
||||
if (parm0 != NULL) call->init_req(TypeFunc::Parms+0, parm0);
|
||||
if (parm1 != NULL) call->init_req(TypeFunc::Parms+1, parm1);
|
||||
if (parm2 != NULL) call->init_req(TypeFunc::Parms+2, parm2);
|
||||
if (parm3 != NULL) call->init_req(TypeFunc::Parms+3, parm3);
|
||||
|
||||
// Node *c = _gvn.transform(call);
|
||||
call = (CallNode *) _gvn.transform(call);
|
||||
Node *c = call; // dbx gets confused with call call->dump()
|
||||
|
||||
// Slow leaf call has no side-effects, sets few values
|
||||
|
||||
set_ctrl(transform( new (C, 1) ProjNode(call,TypeFunc::Control) ));
|
||||
|
||||
// Make memory for the call
|
||||
Node* mem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) );
|
||||
|
||||
// Set the RawPtr memory state only.
|
||||
set_memory(mem, adr_idx);
|
||||
|
||||
assert(C->alias_type(call->adr_type()) == C->alias_type(adr_type),
|
||||
"call node must be constructed correctly");
|
||||
}
|
||||
|
||||
|
||||
void IdealKit::make_leaf_call_no_fp(const TypeFunc *slow_call_type,
|
||||
address slow_call,
|
||||
const char *leaf_name,
|
||||
const TypePtr* adr_type,
|
||||
Node* parm0,
|
||||
Node* parm1,
|
||||
Node* parm2,
|
||||
Node* parm3) {
|
||||
|
||||
// We only handle taking in RawMem and modifying RawMem
|
||||
uint adr_idx = C->get_alias_index(adr_type);
|
||||
|
||||
// Slow-path leaf call
|
||||
int size = slow_call_type->domain()->cnt();
|
||||
CallNode *call = (CallNode*)new (C, size) CallLeafNoFPNode( slow_call_type, slow_call, leaf_name, adr_type);
|
||||
|
||||
// Set fixed predefined input arguments
|
||||
call->init_req( TypeFunc::Control, ctrl() );
|
||||
call->init_req( TypeFunc::I_O , top() ) ; // does no i/o
|
||||
// Narrow memory as only memory input
|
||||
call->init_req( TypeFunc::Memory , memory(adr_idx));
|
||||
call->init_req( TypeFunc::FramePtr, top() /* frameptr() */ );
|
||||
call->init_req( TypeFunc::ReturnAdr, top() );
|
||||
|
||||
if (parm0 != NULL) call->init_req(TypeFunc::Parms+0, parm0);
|
||||
if (parm1 != NULL) call->init_req(TypeFunc::Parms+1, parm1);
|
||||
if (parm2 != NULL) call->init_req(TypeFunc::Parms+2, parm2);
|
||||
if (parm3 != NULL) call->init_req(TypeFunc::Parms+3, parm3);
|
||||
|
||||
// Node *c = _gvn.transform(call);
|
||||
call = (CallNode *) _gvn.transform(call);
|
||||
|
@ -108,6 +108,7 @@ class IdealKit: public StackObj {
|
||||
bool _delay_all_transforms; // flag forcing all transforms to be delayed
|
||||
Node* _initial_ctrl; // saves initial control until variables declared
|
||||
Node* _initial_memory; // saves initial memory until variables declared
|
||||
Node* _initial_i_o; // saves initial i_o until variables declared
|
||||
|
||||
PhaseGVN& gvn() const { return _gvn; }
|
||||
// Create a new cvstate filled with nulls
|
||||
@ -142,17 +143,21 @@ class IdealKit: public StackObj {
|
||||
Node* memory(uint alias_idx);
|
||||
|
||||
public:
|
||||
IdealKit(PhaseGVN &gvn, Node* control, Node* memory, bool delay_all_transforms = false, bool has_declarations = false);
|
||||
IdealKit(GraphKit* gkit, bool delay_all_transforms = false, bool has_declarations = false);
|
||||
~IdealKit() {
|
||||
stop();
|
||||
drain_delay_transform();
|
||||
}
|
||||
void sync_kit(GraphKit* gkit);
|
||||
|
||||
// Control
|
||||
Node* ctrl() { return _cvstate->in(TypeFunc::Control); }
|
||||
void set_ctrl(Node* ctrl) { _cvstate->set_req(TypeFunc::Control, ctrl); }
|
||||
Node* top() { return C->top(); }
|
||||
MergeMemNode* merged_memory() { return _cvstate->in(TypeFunc::Memory)->as_MergeMem(); }
|
||||
void set_all_memory(Node* mem) { _cvstate->set_req(TypeFunc::Memory, mem); }
|
||||
Node* i_o() { return _cvstate->in(TypeFunc::I_O); }
|
||||
void set_i_o(Node* c) { _cvstate->set_req(TypeFunc::I_O, c); }
|
||||
void set(IdealVariable& v, Node* rhs) { _cvstate->set_req(first_var + v.id(), rhs); }
|
||||
Node* value(IdealVariable& v) { return _cvstate->in(first_var + v.id()); }
|
||||
void dead(IdealVariable& v) { set(v, (Node*)NULL); }
|
||||
@ -239,7 +244,18 @@ class IdealKit: public StackObj {
|
||||
const char *leaf_name,
|
||||
Node* parm0,
|
||||
Node* parm1 = NULL,
|
||||
Node* parm2 = NULL);
|
||||
Node* parm2 = NULL,
|
||||
Node* parm3 = NULL);
|
||||
|
||||
void make_leaf_call_no_fp(const TypeFunc *slow_call_type,
|
||||
address slow_call,
|
||||
const char *leaf_name,
|
||||
const TypePtr* adr_type,
|
||||
Node* parm0,
|
||||
Node* parm1,
|
||||
Node* parm2,
|
||||
Node* parm3);
|
||||
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_OPTO_IDEALKIT_HPP
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "opto/addnode.hpp"
|
||||
#include "opto/cfgnode.hpp"
|
||||
#include "opto/connode.hpp"
|
||||
#include "opto/loopnode.hpp"
|
||||
#include "opto/phaseX.hpp"
|
||||
#include "opto/runtime.hpp"
|
||||
#include "opto/subnode.hpp"
|
||||
@ -222,22 +223,35 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) {
|
||||
|
||||
// Make a region merging constants and a region merging the rest
|
||||
uint req_c = 0;
|
||||
Node* predicate_proj = NULL;
|
||||
for (uint ii = 1; ii < r->req(); ii++) {
|
||||
if( phi->in(ii) == con1 ) {
|
||||
if (phi->in(ii) == con1) {
|
||||
req_c++;
|
||||
}
|
||||
Node* proj = PhaseIdealLoop::find_predicate(r->in(ii));
|
||||
if (proj != NULL) {
|
||||
assert(predicate_proj == NULL, "only one predicate entry expected");
|
||||
predicate_proj = proj;
|
||||
}
|
||||
}
|
||||
Node* predicate_c = NULL;
|
||||
Node* predicate_x = NULL;
|
||||
|
||||
Node *region_c = new (igvn->C, req_c + 1) RegionNode(req_c + 1);
|
||||
Node *phi_c = con1;
|
||||
uint len = r->req();
|
||||
Node *region_x = new (igvn->C, len - req_c + 1) RegionNode(len - req_c + 1);
|
||||
Node *region_x = new (igvn->C, len - req_c) RegionNode(len - req_c);
|
||||
Node *phi_x = PhiNode::make_blank(region_x, phi);
|
||||
for (uint i = 1, i_c = 1, i_x = 1; i < len; i++) {
|
||||
if( phi->in(i) == con1 ) {
|
||||
if (phi->in(i) == con1) {
|
||||
region_c->init_req( i_c++, r ->in(i) );
|
||||
if (r->in(i) == predicate_proj)
|
||||
predicate_c = predicate_proj;
|
||||
} else {
|
||||
region_x->init_req( i_x, r ->in(i) );
|
||||
phi_x ->init_req( i_x++, phi->in(i) );
|
||||
if (r->in(i) == predicate_proj)
|
||||
predicate_x = predicate_proj;
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,8 +291,20 @@ static Node* split_if(IfNode *iff, PhaseIterGVN *igvn) {
|
||||
// Make the true/false arms
|
||||
Node *iff_c_t = phase->transform(new (igvn->C, 1) IfTrueNode (iff_c));
|
||||
Node *iff_c_f = phase->transform(new (igvn->C, 1) IfFalseNode(iff_c));
|
||||
if (predicate_c != NULL) {
|
||||
assert(predicate_x == NULL, "only one predicate entry expected");
|
||||
// Clone loop predicates to each path
|
||||
iff_c_t = igvn->clone_loop_predicates(predicate_c, iff_c_t);
|
||||
iff_c_f = igvn->clone_loop_predicates(predicate_c, iff_c_f);
|
||||
}
|
||||
Node *iff_x_t = phase->transform(new (igvn->C, 1) IfTrueNode (iff_x));
|
||||
Node *iff_x_f = phase->transform(new (igvn->C, 1) IfFalseNode(iff_x));
|
||||
if (predicate_x != NULL) {
|
||||
assert(predicate_c == NULL, "only one predicate entry expected");
|
||||
// Clone loop predicates to each path
|
||||
iff_x_t = igvn->clone_loop_predicates(predicate_x, iff_x_t);
|
||||
iff_x_f = igvn->clone_loop_predicates(predicate_x, iff_x_f);
|
||||
}
|
||||
|
||||
// Merge the TRUE paths
|
||||
Node *region_s = new (igvn->C, 3) RegionNode(3);
|
||||
|
@ -1120,7 +1120,7 @@ Node* LibraryCallKit::string_indexOf(Node* string_object, ciTypeArray* target_ar
|
||||
const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin));
|
||||
const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot);
|
||||
|
||||
IdealKit kit(gvn(), control(), merged_memory(), false, true);
|
||||
IdealKit kit(this, false, true);
|
||||
#define __ kit.
|
||||
Node* zero = __ ConI(0);
|
||||
Node* one = __ ConI(1);
|
||||
@ -1171,7 +1171,7 @@ Node* LibraryCallKit::string_indexOf(Node* string_object, ciTypeArray* target_ar
|
||||
__ bind(return_);
|
||||
|
||||
// Final sync IdealKit and GraphKit.
|
||||
sync_kit(kit);
|
||||
final_sync(kit);
|
||||
Node* result = __ value(rtn);
|
||||
#undef __
|
||||
C->set_has_loops(true);
|
||||
@ -2318,22 +2318,20 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas
|
||||
// of it. So we need to emit code to conditionally do the proper type of
|
||||
// store.
|
||||
|
||||
IdealKit ideal(gvn(), control(), merged_memory());
|
||||
IdealKit ideal(this);
|
||||
#define __ ideal.
|
||||
// QQQ who knows what probability is here??
|
||||
__ if_then(heap_base_oop, BoolTest::ne, null(), PROB_UNLIKELY(0.999)); {
|
||||
// Sync IdealKit and graphKit.
|
||||
set_all_memory( __ merged_memory());
|
||||
set_control(__ ctrl());
|
||||
sync_kit(ideal);
|
||||
Node* st = store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type);
|
||||
// Update IdealKit memory.
|
||||
__ set_all_memory(merged_memory());
|
||||
__ set_ctrl(control());
|
||||
__ sync_kit(this);
|
||||
} __ else_(); {
|
||||
__ store(__ ctrl(), adr, val, type, alias_type->index(), is_volatile);
|
||||
} __ end_if();
|
||||
// Final sync IdealKit and GraphKit.
|
||||
sync_kit(ideal);
|
||||
final_sync(ideal);
|
||||
#undef __
|
||||
}
|
||||
}
|
||||
@ -4294,81 +4292,6 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// constants for computing the copy function
|
||||
enum {
|
||||
COPYFUNC_UNALIGNED = 0,
|
||||
COPYFUNC_ALIGNED = 1, // src, dest aligned to HeapWordSize
|
||||
COPYFUNC_CONJOINT = 0,
|
||||
COPYFUNC_DISJOINT = 2 // src != dest, or transfer can descend
|
||||
};
|
||||
|
||||
// Note: The condition "disjoint" applies also for overlapping copies
|
||||
// where an descending copy is permitted (i.e., dest_offset <= src_offset).
|
||||
static address
|
||||
select_arraycopy_function(BasicType t, bool aligned, bool disjoint, const char* &name, bool dest_uninitialized) {
|
||||
int selector =
|
||||
(aligned ? COPYFUNC_ALIGNED : COPYFUNC_UNALIGNED) +
|
||||
(disjoint ? COPYFUNC_DISJOINT : COPYFUNC_CONJOINT);
|
||||
|
||||
#define RETURN_STUB(xxx_arraycopy) { \
|
||||
name = #xxx_arraycopy; \
|
||||
return StubRoutines::xxx_arraycopy(); }
|
||||
|
||||
#define RETURN_STUB_PARM(xxx_arraycopy, parm) { \
|
||||
name = #xxx_arraycopy; \
|
||||
return StubRoutines::xxx_arraycopy(parm); }
|
||||
|
||||
switch (t) {
|
||||
case T_BYTE:
|
||||
case T_BOOLEAN:
|
||||
switch (selector) {
|
||||
case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jbyte_arraycopy);
|
||||
case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jbyte_arraycopy);
|
||||
case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jbyte_disjoint_arraycopy);
|
||||
case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jbyte_disjoint_arraycopy);
|
||||
}
|
||||
case T_CHAR:
|
||||
case T_SHORT:
|
||||
switch (selector) {
|
||||
case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jshort_arraycopy);
|
||||
case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jshort_arraycopy);
|
||||
case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jshort_disjoint_arraycopy);
|
||||
case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jshort_disjoint_arraycopy);
|
||||
}
|
||||
case T_INT:
|
||||
case T_FLOAT:
|
||||
switch (selector) {
|
||||
case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jint_arraycopy);
|
||||
case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jint_arraycopy);
|
||||
case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jint_disjoint_arraycopy);
|
||||
case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jint_disjoint_arraycopy);
|
||||
}
|
||||
case T_DOUBLE:
|
||||
case T_LONG:
|
||||
switch (selector) {
|
||||
case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jlong_arraycopy);
|
||||
case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jlong_arraycopy);
|
||||
case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB(jlong_disjoint_arraycopy);
|
||||
case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB(arrayof_jlong_disjoint_arraycopy);
|
||||
}
|
||||
case T_ARRAY:
|
||||
case T_OBJECT:
|
||||
switch (selector) {
|
||||
case COPYFUNC_CONJOINT | COPYFUNC_UNALIGNED: RETURN_STUB_PARM(oop_arraycopy, dest_uninitialized);
|
||||
case COPYFUNC_CONJOINT | COPYFUNC_ALIGNED: RETURN_STUB_PARM(arrayof_oop_arraycopy, dest_uninitialized);
|
||||
case COPYFUNC_DISJOINT | COPYFUNC_UNALIGNED: RETURN_STUB_PARM(oop_disjoint_arraycopy, dest_uninitialized);
|
||||
case COPYFUNC_DISJOINT | COPYFUNC_ALIGNED: RETURN_STUB_PARM(arrayof_oop_disjoint_arraycopy, dest_uninitialized);
|
||||
}
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#undef RETURN_STUB
|
||||
#undef RETURN_STUB_PARM
|
||||
}
|
||||
|
||||
//------------------------------basictype2arraycopy----------------------------
|
||||
address LibraryCallKit::basictype2arraycopy(BasicType t,
|
||||
Node* src_offset,
|
||||
@ -4401,7 +4324,7 @@ address LibraryCallKit::basictype2arraycopy(BasicType t,
|
||||
disjoint = true;
|
||||
}
|
||||
|
||||
return select_arraycopy_function(t, aligned, disjoint, name, dest_uninitialized);
|
||||
return StubRoutines::select_arraycopy_function(t, aligned, disjoint, name, dest_uninitialized);
|
||||
}
|
||||
|
||||
|
||||
|
960
hotspot/src/share/vm/opto/loopPredicate.cpp
Normal file
960
hotspot/src/share/vm/opto/loopPredicate.cpp
Normal file
@ -0,0 +1,960 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "opto/loopnode.hpp"
|
||||
#include "opto/addnode.hpp"
|
||||
#include "opto/callnode.hpp"
|
||||
#include "opto/connode.hpp"
|
||||
#include "opto/loopnode.hpp"
|
||||
#include "opto/mulnode.hpp"
|
||||
#include "opto/rootnode.hpp"
|
||||
#include "opto/subnode.hpp"
|
||||
|
||||
/*
|
||||
* The general idea of Loop Predication is to insert a predicate on the entry
|
||||
* path to a loop, and raise a uncommon trap if the check of the condition fails.
|
||||
* The condition checks are promoted from inside the loop body, and thus
|
||||
* the checks inside the loop could be eliminated. Currently, loop predication
|
||||
* optimization has been applied to remove array range check and loop invariant
|
||||
* checks (such as null checks).
|
||||
*/
|
||||
|
||||
//-------------------------------is_uncommon_trap_proj----------------------------
|
||||
// Return true if proj is the form of "proj->[region->..]call_uct"
|
||||
bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason) {
|
||||
int path_limit = 10;
|
||||
assert(proj, "invalid argument");
|
||||
Node* out = proj;
|
||||
for (int ct = 0; ct < path_limit; ct++) {
|
||||
out = out->unique_ctrl_out();
|
||||
if (out == NULL)
|
||||
return false;
|
||||
if (out->is_CallStaticJava()) {
|
||||
int req = out->as_CallStaticJava()->uncommon_trap_request();
|
||||
if (req != 0) {
|
||||
Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req);
|
||||
if (trap_reason == reason || reason == Deoptimization::Reason_none) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // don't do further after call
|
||||
}
|
||||
if (out->Opcode() != Op_Region)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------is_uncommon_trap_if_pattern-------------------------
|
||||
// Return true for "if(test)-> proj -> ...
|
||||
// |
|
||||
// V
|
||||
// other_proj->[region->..]call_uct"
|
||||
//
|
||||
// "must_reason_predicate" means the uct reason must be Reason_predicate
|
||||
bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, Deoptimization::DeoptReason reason) {
|
||||
Node *in0 = proj->in(0);
|
||||
if (!in0->is_If()) return false;
|
||||
// Variation of a dead If node.
|
||||
if (in0->outcnt() < 2) return false;
|
||||
IfNode* iff = in0->as_If();
|
||||
|
||||
// we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate
|
||||
if (reason != Deoptimization::Reason_none) {
|
||||
if (iff->in(1)->Opcode() != Op_Conv2B ||
|
||||
iff->in(1)->in(1)->Opcode() != Op_Opaque1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj();
|
||||
if (is_uncommon_trap_proj(other_proj, reason)) {
|
||||
assert(reason == Deoptimization::Reason_none ||
|
||||
Compile::current()->is_predicate_opaq(iff->in(1)->in(1)), "should be on the list");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------register_control-------------------------
|
||||
void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred) {
|
||||
assert(n->is_CFG(), "must be control node");
|
||||
_igvn.register_new_node_with_optimizer(n);
|
||||
loop->_body.push(n);
|
||||
set_loop(n, loop);
|
||||
// When called from beautify_loops() idom is not constructed yet.
|
||||
if (_idom != NULL) {
|
||||
set_idom(n, pred, dom_depth(pred));
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------create_new_if_for_predicate------------------------
|
||||
// create a new if above the uct_if_pattern for the predicate to be promoted.
|
||||
//
|
||||
// before after
|
||||
// ---------- ----------
|
||||
// ctrl ctrl
|
||||
// | |
|
||||
// | |
|
||||
// v v
|
||||
// iff new_iff
|
||||
// / \ / \
|
||||
// / \ / \
|
||||
// v v v v
|
||||
// uncommon_proj cont_proj if_uct if_cont
|
||||
// \ | | | |
|
||||
// \ | | | |
|
||||
// v v v | v
|
||||
// rgn loop | iff
|
||||
// | | / \
|
||||
// | | / \
|
||||
// v | v v
|
||||
// uncommon_trap | uncommon_proj cont_proj
|
||||
// \ \ | |
|
||||
// \ \ | |
|
||||
// v v v v
|
||||
// rgn loop
|
||||
// |
|
||||
// |
|
||||
// v
|
||||
// uncommon_trap
|
||||
//
|
||||
//
|
||||
// We will create a region to guard the uct call if there is no one there.
|
||||
// The true projecttion (if_cont) of the new_iff is returned.
|
||||
// This code is also used to clone predicates to clonned loops.
|
||||
ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
|
||||
Deoptimization::DeoptReason reason) {
|
||||
assert(is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!");
|
||||
IfNode* iff = cont_proj->in(0)->as_If();
|
||||
|
||||
ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con);
|
||||
Node *rgn = uncommon_proj->unique_ctrl_out();
|
||||
assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct");
|
||||
|
||||
uint proj_index = 1; // region's edge corresponding to uncommon_proj
|
||||
if (!rgn->is_Region()) { // create a region to guard the call
|
||||
assert(rgn->is_Call(), "must be call uct");
|
||||
CallNode* call = rgn->as_Call();
|
||||
IdealLoopTree* loop = get_loop(call);
|
||||
rgn = new (C, 1) RegionNode(1);
|
||||
rgn->add_req(uncommon_proj);
|
||||
register_control(rgn, loop, uncommon_proj);
|
||||
_igvn.hash_delete(call);
|
||||
call->set_req(0, rgn);
|
||||
// When called from beautify_loops() idom is not constructed yet.
|
||||
if (_idom != NULL) {
|
||||
set_idom(call, rgn, dom_depth(rgn));
|
||||
}
|
||||
} else {
|
||||
// Find region's edge corresponding to uncommon_proj
|
||||
for (; proj_index < rgn->req(); proj_index++)
|
||||
if (rgn->in(proj_index) == uncommon_proj) break;
|
||||
assert(proj_index < rgn->req(), "sanity");
|
||||
}
|
||||
|
||||
Node* entry = iff->in(0);
|
||||
if (new_entry != NULL) {
|
||||
// Clonning the predicate to new location.
|
||||
entry = new_entry;
|
||||
}
|
||||
// Create new_iff
|
||||
IdealLoopTree* lp = get_loop(entry);
|
||||
IfNode *new_iff = iff->clone()->as_If();
|
||||
new_iff->set_req(0, entry);
|
||||
register_control(new_iff, lp, entry);
|
||||
Node *if_cont = new (C, 1) IfTrueNode(new_iff);
|
||||
Node *if_uct = new (C, 1) IfFalseNode(new_iff);
|
||||
if (cont_proj->is_IfFalse()) {
|
||||
// Swap
|
||||
Node* tmp = if_uct; if_uct = if_cont; if_cont = tmp;
|
||||
}
|
||||
register_control(if_cont, lp, new_iff);
|
||||
register_control(if_uct, get_loop(rgn), new_iff);
|
||||
|
||||
// if_uct to rgn
|
||||
_igvn.hash_delete(rgn);
|
||||
rgn->add_req(if_uct);
|
||||
// When called from beautify_loops() idom is not constructed yet.
|
||||
if (_idom != NULL) {
|
||||
Node* ridom = idom(rgn);
|
||||
Node* nrdom = dom_lca(ridom, new_iff);
|
||||
set_idom(rgn, nrdom, dom_depth(rgn));
|
||||
}
|
||||
|
||||
// If rgn has phis add new edges which has the same
|
||||
// value as on original uncommon_proj pass.
|
||||
assert(rgn->in(rgn->req() -1) == if_uct, "new edge should be last");
|
||||
bool has_phi = false;
|
||||
for (DUIterator_Fast imax, i = rgn->fast_outs(imax); i < imax; i++) {
|
||||
Node* use = rgn->fast_out(i);
|
||||
if (use->is_Phi() && use->outcnt() > 0) {
|
||||
assert(use->in(0) == rgn, "");
|
||||
_igvn.hash_delete(use);
|
||||
use->add_req(use->in(proj_index));
|
||||
_igvn._worklist.push(use);
|
||||
has_phi = true;
|
||||
}
|
||||
}
|
||||
assert(!has_phi || rgn->req() > 3, "no phis when region is created");
|
||||
|
||||
if (new_entry == NULL) {
|
||||
// Attach if_cont to iff
|
||||
_igvn.hash_delete(iff);
|
||||
iff->set_req(0, if_cont);
|
||||
if (_idom != NULL) {
|
||||
set_idom(iff, if_cont, dom_depth(iff));
|
||||
}
|
||||
}
|
||||
return if_cont->as_Proj();
|
||||
}
|
||||
|
||||
//------------------------------create_new_if_for_predicate------------------------
|
||||
// Create a new if below new_entry for the predicate to be cloned (IGVN optimization)
|
||||
ProjNode* PhaseIterGVN::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
|
||||
Deoptimization::DeoptReason reason) {
|
||||
assert(new_entry != 0, "only used for clone predicate");
|
||||
assert(PhaseIdealLoop::is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!");
|
||||
IfNode* iff = cont_proj->in(0)->as_If();
|
||||
|
||||
ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con);
|
||||
Node *rgn = uncommon_proj->unique_ctrl_out();
|
||||
assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct");
|
||||
|
||||
uint proj_index = 1; // region's edge corresponding to uncommon_proj
|
||||
if (!rgn->is_Region()) { // create a region to guard the call
|
||||
assert(rgn->is_Call(), "must be call uct");
|
||||
CallNode* call = rgn->as_Call();
|
||||
rgn = new (C, 1) RegionNode(1);
|
||||
register_new_node_with_optimizer(rgn);
|
||||
rgn->add_req(uncommon_proj);
|
||||
hash_delete(call);
|
||||
call->set_req(0, rgn);
|
||||
} else {
|
||||
// Find region's edge corresponding to uncommon_proj
|
||||
for (; proj_index < rgn->req(); proj_index++)
|
||||
if (rgn->in(proj_index) == uncommon_proj) break;
|
||||
assert(proj_index < rgn->req(), "sanity");
|
||||
}
|
||||
|
||||
// Create new_iff in new location.
|
||||
IfNode *new_iff = iff->clone()->as_If();
|
||||
new_iff->set_req(0, new_entry);
|
||||
|
||||
register_new_node_with_optimizer(new_iff);
|
||||
Node *if_cont = new (C, 1) IfTrueNode(new_iff);
|
||||
Node *if_uct = new (C, 1) IfFalseNode(new_iff);
|
||||
if (cont_proj->is_IfFalse()) {
|
||||
// Swap
|
||||
Node* tmp = if_uct; if_uct = if_cont; if_cont = tmp;
|
||||
}
|
||||
register_new_node_with_optimizer(if_cont);
|
||||
register_new_node_with_optimizer(if_uct);
|
||||
|
||||
// if_uct to rgn
|
||||
hash_delete(rgn);
|
||||
rgn->add_req(if_uct);
|
||||
|
||||
// If rgn has phis add corresponding new edges which has the same
|
||||
// value as on original uncommon_proj pass.
|
||||
assert(rgn->in(rgn->req() -1) == if_uct, "new edge should be last");
|
||||
bool has_phi = false;
|
||||
for (DUIterator_Fast imax, i = rgn->fast_outs(imax); i < imax; i++) {
|
||||
Node* use = rgn->fast_out(i);
|
||||
if (use->is_Phi() && use->outcnt() > 0) {
|
||||
hash_delete(use);
|
||||
use->add_req(use->in(proj_index));
|
||||
_worklist.push(use);
|
||||
has_phi = true;
|
||||
}
|
||||
}
|
||||
assert(!has_phi || rgn->req() > 3, "no phis when region is created");
|
||||
|
||||
return if_cont->as_Proj();
|
||||
}
|
||||
|
||||
//--------------------------clone_predicate-----------------------
|
||||
ProjNode* PhaseIdealLoop::clone_predicate(ProjNode* predicate_proj, Node* new_entry,
|
||||
Deoptimization::DeoptReason reason,
|
||||
PhaseIdealLoop* loop_phase,
|
||||
PhaseIterGVN* igvn) {
|
||||
ProjNode* new_predicate_proj;
|
||||
if (loop_phase != NULL) {
|
||||
new_predicate_proj = loop_phase->create_new_if_for_predicate(predicate_proj, new_entry, reason);
|
||||
} else {
|
||||
new_predicate_proj = igvn->create_new_if_for_predicate(predicate_proj, new_entry, reason);
|
||||
}
|
||||
IfNode* iff = new_predicate_proj->in(0)->as_If();
|
||||
Node* ctrl = iff->in(0);
|
||||
|
||||
// Match original condition since predicate's projections could be swapped.
|
||||
assert(predicate_proj->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be");
|
||||
Node* opq = new (igvn->C, 2) Opaque1Node(igvn->C, predicate_proj->in(0)->in(1)->in(1)->in(1));
|
||||
igvn->C->add_predicate_opaq(opq);
|
||||
|
||||
Node* bol = new (igvn->C, 2) Conv2BNode(opq);
|
||||
if (loop_phase != NULL) {
|
||||
loop_phase->register_new_node(opq, ctrl);
|
||||
loop_phase->register_new_node(bol, ctrl);
|
||||
} else {
|
||||
igvn->register_new_node_with_optimizer(opq);
|
||||
igvn->register_new_node_with_optimizer(bol);
|
||||
}
|
||||
igvn->hash_delete(iff);
|
||||
iff->set_req(1, bol);
|
||||
return new_predicate_proj;
|
||||
}
|
||||
|
||||
//--------------------------move_predicate-----------------------
|
||||
// Cut predicate from old place and move it to new.
|
||||
ProjNode* PhaseIdealLoop::move_predicate(ProjNode* predicate_proj, Node* new_entry,
|
||||
Deoptimization::DeoptReason reason,
|
||||
PhaseIdealLoop* loop_phase,
|
||||
PhaseIterGVN* igvn) {
|
||||
assert(new_entry != NULL, "must be");
|
||||
assert(predicate_proj->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be");
|
||||
IfNode* iff = predicate_proj->in(0)->as_If();
|
||||
Node* old_entry = iff->in(0);
|
||||
|
||||
// Cut predicate from old place.
|
||||
Node* old = predicate_proj;
|
||||
igvn->_worklist.push(old);
|
||||
for (DUIterator_Last imin, i = old->last_outs(imin); i >= imin; ) {
|
||||
Node* use = old->last_out(i); // for each use...
|
||||
igvn->hash_delete(use);
|
||||
igvn->_worklist.push(use);
|
||||
// Update use-def info
|
||||
uint uses_found = 0;
|
||||
for (uint j = 0; j < use->req(); j++) {
|
||||
if (use->in(j) == old) {
|
||||
use->set_req(j, old_entry);
|
||||
uses_found++;
|
||||
if (loop_phase != NULL) {
|
||||
if (use->is_CFG()) {
|
||||
// When called from beautify_loops() idom is not constructed yet.
|
||||
if (loop_phase->_idom != NULL)
|
||||
loop_phase->set_idom(use, old_entry, loop_phase->dom_depth(use));
|
||||
} else {
|
||||
loop_phase->set_ctrl(use, old_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i -= uses_found; // we deleted 1 or more copies of this edge
|
||||
}
|
||||
|
||||
// Move predicate.
|
||||
igvn->hash_delete(iff);
|
||||
iff->set_req(0, new_entry);
|
||||
igvn->_worklist.push(iff);
|
||||
|
||||
if (loop_phase != NULL) {
|
||||
// Fix up idom and ctrl.
|
||||
loop_phase->set_ctrl(iff->in(1), new_entry);
|
||||
loop_phase->set_ctrl(iff->in(1)->in(1), new_entry);
|
||||
// When called from beautify_loops() idom is not constructed yet.
|
||||
if (loop_phase->_idom != NULL)
|
||||
loop_phase->set_idom(iff, new_entry, loop_phase->dom_depth(iff));
|
||||
}
|
||||
|
||||
return predicate_proj;
|
||||
}
|
||||
|
||||
//--------------------------clone_loop_predicates-----------------------
|
||||
// Interface from IGVN
|
||||
Node* PhaseIterGVN::clone_loop_predicates(Node* old_entry, Node* new_entry) {
|
||||
return PhaseIdealLoop::clone_loop_predicates(old_entry, new_entry, false, NULL, this);
|
||||
}
|
||||
Node* PhaseIterGVN::move_loop_predicates(Node* old_entry, Node* new_entry) {
|
||||
return PhaseIdealLoop::clone_loop_predicates(old_entry, new_entry, true, NULL, this);
|
||||
}
|
||||
|
||||
// Interface from PhaseIdealLoop
|
||||
Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry) {
|
||||
return clone_loop_predicates(old_entry, new_entry, false, this, &this->_igvn);
|
||||
}
|
||||
Node* PhaseIdealLoop::move_loop_predicates(Node* old_entry, Node* new_entry) {
|
||||
return clone_loop_predicates(old_entry, new_entry, true, this, &this->_igvn);
|
||||
}
|
||||
|
||||
// Clone loop predicates to cloned loops (peeled, unswitched, split_if).
|
||||
Node* PhaseIdealLoop::clone_loop_predicates(Node* old_entry, Node* new_entry,
|
||||
bool move_predicates,
|
||||
PhaseIdealLoop* loop_phase,
|
||||
PhaseIterGVN* igvn) {
|
||||
#ifdef ASSERT
|
||||
if (new_entry == NULL || !(new_entry->is_Proj() || new_entry->is_Region() || new_entry->is_SafePoint())) {
|
||||
if (new_entry != NULL)
|
||||
new_entry->dump();
|
||||
assert(false, "not IfTrue, IfFalse, Region or SafePoint");
|
||||
}
|
||||
#endif
|
||||
// Search original predicates
|
||||
Node* entry = old_entry;
|
||||
if (UseLoopPredicate) {
|
||||
ProjNode* predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
|
||||
if (predicate_proj != NULL) { // right pattern that can be used by loop predication
|
||||
assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be");
|
||||
if (move_predicates) {
|
||||
new_entry = move_predicate(predicate_proj, new_entry,
|
||||
Deoptimization::Reason_predicate,
|
||||
loop_phase, igvn);
|
||||
assert(new_entry == predicate_proj, "old predicate fall through projection");
|
||||
} else {
|
||||
// clone predicate
|
||||
new_entry = clone_predicate(predicate_proj, new_entry,
|
||||
Deoptimization::Reason_predicate,
|
||||
loop_phase, igvn);
|
||||
assert(new_entry != NULL && new_entry->is_Proj(), "IfTrue or IfFalse after clone predicate");
|
||||
}
|
||||
if (TraceLoopPredicate) {
|
||||
tty->print_cr("Loop Predicate %s: ", move_predicates ? "moved" : "cloned");
|
||||
debug_only( new_entry->in(0)->dump(); )
|
||||
}
|
||||
}
|
||||
}
|
||||
return new_entry;
|
||||
}
|
||||
|
||||
//--------------------------eliminate_loop_predicates-----------------------
|
||||
void PhaseIdealLoop::eliminate_loop_predicates(Node* entry) {
|
||||
if (UseLoopPredicate) {
|
||||
ProjNode* predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
|
||||
if (predicate_proj != NULL) { // right pattern that can be used by loop predication
|
||||
Node* n = entry->in(0)->in(1)->in(1);
|
||||
assert(n->Opcode()==Op_Opaque1, "must be");
|
||||
// Remove Opaque1 node from predicates list.
|
||||
// IGVN will remove this predicate check.
|
||||
_igvn.replace_node(n, n->in(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------skip_loop_predicates------------------------------
|
||||
// Skip related predicates.
|
||||
Node* PhaseIdealLoop::skip_loop_predicates(Node* entry) {
|
||||
Node* predicate = NULL;
|
||||
if (UseLoopPredicate) {
|
||||
predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
|
||||
if (predicate != NULL) { // right pattern that can be used by loop predication
|
||||
assert(entry->is_Proj() && entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be");
|
||||
IfNode* iff = entry->in(0)->as_If();
|
||||
ProjNode* uncommon_proj = iff->proj_out(1 - entry->as_Proj()->_con);
|
||||
Node* rgn = uncommon_proj->unique_ctrl_out();
|
||||
assert(rgn->is_Region() || rgn->is_Call(), "must be a region or call uct");
|
||||
entry = entry->in(0)->in(0);
|
||||
while (entry != NULL && entry->is_Proj() && entry->in(0)->is_If()) {
|
||||
uncommon_proj = entry->in(0)->as_If()->proj_out(1 - entry->as_Proj()->_con);
|
||||
if (uncommon_proj->unique_ctrl_out() != rgn)
|
||||
break;
|
||||
entry = entry->in(0)->in(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
//--------------------------find_predicate_insertion_point-------------------
|
||||
// Find a good location to insert a predicate
|
||||
ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason) {
|
||||
if (start_c == NULL || !start_c->is_Proj())
|
||||
return NULL;
|
||||
if (is_uncommon_trap_if_pattern(start_c->as_Proj(), reason)) {
|
||||
return start_c->as_Proj();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//--------------------------find_predicate------------------------------------
|
||||
// Find a predicate
|
||||
Node* PhaseIdealLoop::find_predicate(Node* entry) {
|
||||
Node* predicate = NULL;
|
||||
if (UseLoopPredicate) {
|
||||
predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
|
||||
if (predicate != NULL) { // right pattern that can be used by loop predication
|
||||
assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be");
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------Invariance-----------------------------------
|
||||
// Helper class for loop_predication_impl to compute invariance on the fly and
|
||||
// clone invariants.
|
||||
class Invariance : public StackObj {
|
||||
VectorSet _visited, _invariant;
|
||||
Node_Stack _stack;
|
||||
VectorSet _clone_visited;
|
||||
Node_List _old_new; // map of old to new (clone)
|
||||
IdealLoopTree* _lpt;
|
||||
PhaseIdealLoop* _phase;
|
||||
|
||||
// Helper function to set up the invariance for invariance computation
|
||||
// If n is a known invariant, set up directly. Otherwise, look up the
|
||||
// the possibility to push n onto the stack for further processing.
|
||||
void visit(Node* use, Node* n) {
|
||||
if (_lpt->is_invariant(n)) { // known invariant
|
||||
_invariant.set(n->_idx);
|
||||
} else if (!n->is_CFG()) {
|
||||
Node *n_ctrl = _phase->ctrl_or_self(n);
|
||||
Node *u_ctrl = _phase->ctrl_or_self(use); // self if use is a CFG
|
||||
if (_phase->is_dominator(n_ctrl, u_ctrl)) {
|
||||
_stack.push(n, n->in(0) == NULL ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute invariance for "the_node" and (possibly) all its inputs recursively
|
||||
// on the fly
|
||||
void compute_invariance(Node* n) {
|
||||
assert(_visited.test(n->_idx), "must be");
|
||||
visit(n, n);
|
||||
while (_stack.is_nonempty()) {
|
||||
Node* n = _stack.node();
|
||||
uint idx = _stack.index();
|
||||
if (idx == n->req()) { // all inputs are processed
|
||||
_stack.pop();
|
||||
// n is invariant if it's inputs are all invariant
|
||||
bool all_inputs_invariant = true;
|
||||
for (uint i = 0; i < n->req(); i++) {
|
||||
Node* in = n->in(i);
|
||||
if (in == NULL) continue;
|
||||
assert(_visited.test(in->_idx), "must have visited input");
|
||||
if (!_invariant.test(in->_idx)) { // bad guy
|
||||
all_inputs_invariant = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all_inputs_invariant) {
|
||||
_invariant.set(n->_idx); // I am a invariant too
|
||||
}
|
||||
} else { // process next input
|
||||
_stack.set_index(idx + 1);
|
||||
Node* m = n->in(idx);
|
||||
if (m != NULL && !_visited.test_set(m->_idx)) {
|
||||
visit(n, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to set up _old_new map for clone_nodes.
|
||||
// If n is a known invariant, set up directly ("clone" of n == n).
|
||||
// Otherwise, push n onto the stack for real cloning.
|
||||
void clone_visit(Node* n) {
|
||||
assert(_invariant.test(n->_idx), "must be invariant");
|
||||
if (_lpt->is_invariant(n)) { // known invariant
|
||||
_old_new.map(n->_idx, n);
|
||||
} else { // to be cloned
|
||||
assert(!n->is_CFG(), "should not see CFG here");
|
||||
_stack.push(n, n->in(0) == NULL ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Clone "n" and (possibly) all its inputs recursively
|
||||
void clone_nodes(Node* n, Node* ctrl) {
|
||||
clone_visit(n);
|
||||
while (_stack.is_nonempty()) {
|
||||
Node* n = _stack.node();
|
||||
uint idx = _stack.index();
|
||||
if (idx == n->req()) { // all inputs processed, clone n!
|
||||
_stack.pop();
|
||||
// clone invariant node
|
||||
Node* n_cl = n->clone();
|
||||
_old_new.map(n->_idx, n_cl);
|
||||
_phase->register_new_node(n_cl, ctrl);
|
||||
for (uint i = 0; i < n->req(); i++) {
|
||||
Node* in = n_cl->in(i);
|
||||
if (in == NULL) continue;
|
||||
n_cl->set_req(i, _old_new[in->_idx]);
|
||||
}
|
||||
} else { // process next input
|
||||
_stack.set_index(idx + 1);
|
||||
Node* m = n->in(idx);
|
||||
if (m != NULL && !_clone_visited.test_set(m->_idx)) {
|
||||
clone_visit(m); // visit the input
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Invariance(Arena* area, IdealLoopTree* lpt) :
|
||||
_lpt(lpt), _phase(lpt->_phase),
|
||||
_visited(area), _invariant(area), _stack(area, 10 /* guess */),
|
||||
_clone_visited(area), _old_new(area)
|
||||
{}
|
||||
|
||||
// Map old to n for invariance computation and clone
|
||||
void map_ctrl(Node* old, Node* n) {
|
||||
assert(old->is_CFG() && n->is_CFG(), "must be");
|
||||
_old_new.map(old->_idx, n); // "clone" of old is n
|
||||
_invariant.set(old->_idx); // old is invariant
|
||||
_clone_visited.set(old->_idx);
|
||||
}
|
||||
|
||||
// Driver function to compute invariance
|
||||
bool is_invariant(Node* n) {
|
||||
if (!_visited.test_set(n->_idx))
|
||||
compute_invariance(n);
|
||||
return (_invariant.test(n->_idx) != 0);
|
||||
}
|
||||
|
||||
// Driver function to clone invariant
|
||||
Node* clone(Node* n, Node* ctrl) {
|
||||
assert(ctrl->is_CFG(), "must be");
|
||||
assert(_invariant.test(n->_idx), "must be an invariant");
|
||||
if (!_clone_visited.test(n->_idx))
|
||||
clone_nodes(n, ctrl);
|
||||
return _old_new[n->_idx];
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------is_range_check_if -----------------------------------
|
||||
// Returns true if the predicate of iff is in "scale*iv + offset u< load_range(ptr)" format
|
||||
// Note: this function is particularly designed for loop predication. We require load_range
|
||||
// and offset to be loop invariant computed on the fly by "invar"
|
||||
bool IdealLoopTree::is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const {
|
||||
if (!is_loop_exit(iff)) {
|
||||
return false;
|
||||
}
|
||||
if (!iff->in(1)->is_Bool()) {
|
||||
return false;
|
||||
}
|
||||
const BoolNode *bol = iff->in(1)->as_Bool();
|
||||
if (bol->_test._test != BoolTest::lt) {
|
||||
return false;
|
||||
}
|
||||
if (!bol->in(1)->is_Cmp()) {
|
||||
return false;
|
||||
}
|
||||
const CmpNode *cmp = bol->in(1)->as_Cmp();
|
||||
if (cmp->Opcode() != Op_CmpU) {
|
||||
return false;
|
||||
}
|
||||
Node* range = cmp->in(2);
|
||||
if (range->Opcode() != Op_LoadRange) {
|
||||
const TypeInt* tint = phase->_igvn.type(range)->isa_int();
|
||||
if (!OptimizeFill || tint == NULL || tint->empty() || tint->_lo < 0) {
|
||||
// Allow predication on positive values that aren't LoadRanges.
|
||||
// This allows optimization of loops where the length of the
|
||||
// array is a known value and doesn't need to be loaded back
|
||||
// from the array.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!invar.is_invariant(range)) {
|
||||
return false;
|
||||
}
|
||||
Node *iv = _head->as_CountedLoop()->phi();
|
||||
int scale = 0;
|
||||
Node *offset = NULL;
|
||||
if (!phase->is_scaled_iv_plus_offset(cmp->in(1), iv, &scale, &offset)) {
|
||||
return false;
|
||||
}
|
||||
if (offset && !invar.is_invariant(offset)) { // offset must be invariant
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------rc_predicate-----------------------------------
|
||||
// Create a range check predicate
|
||||
//
|
||||
// for (i = init; i < limit; i += stride) {
|
||||
// a[scale*i+offset]
|
||||
// }
|
||||
//
|
||||
// Compute max(scale*i + offset) for init <= i < limit and build the predicate
|
||||
// as "max(scale*i + offset) u< a.length".
|
||||
//
|
||||
// There are two cases for max(scale*i + offset):
|
||||
// (1) stride*scale > 0
|
||||
// max(scale*i + offset) = scale*(limit-stride) + offset
|
||||
// (2) stride*scale < 0
|
||||
// max(scale*i + offset) = scale*init + offset
|
||||
BoolNode* PhaseIdealLoop::rc_predicate(Node* ctrl,
|
||||
int scale, Node* offset,
|
||||
Node* init, Node* limit, Node* stride,
|
||||
Node* range, bool upper) {
|
||||
DEBUG_ONLY(ttyLocker ttyl);
|
||||
if (TraceLoopPredicate) tty->print("rc_predicate ");
|
||||
|
||||
Node* max_idx_expr = init;
|
||||
int stride_con = stride->get_int();
|
||||
if ((stride_con > 0) == (scale > 0) == upper) {
|
||||
max_idx_expr = new (C, 3) SubINode(limit, stride);
|
||||
register_new_node(max_idx_expr, ctrl);
|
||||
if (TraceLoopPredicate) tty->print("(limit - stride) ");
|
||||
} else {
|
||||
if (TraceLoopPredicate) tty->print("init ");
|
||||
}
|
||||
|
||||
if (scale != 1) {
|
||||
ConNode* con_scale = _igvn.intcon(scale);
|
||||
max_idx_expr = new (C, 3) MulINode(max_idx_expr, con_scale);
|
||||
register_new_node(max_idx_expr, ctrl);
|
||||
if (TraceLoopPredicate) tty->print("* %d ", scale);
|
||||
}
|
||||
|
||||
if (offset && (!offset->is_Con() || offset->get_int() != 0)){
|
||||
max_idx_expr = new (C, 3) AddINode(max_idx_expr, offset);
|
||||
register_new_node(max_idx_expr, ctrl);
|
||||
if (TraceLoopPredicate)
|
||||
if (offset->is_Con()) tty->print("+ %d ", offset->get_int());
|
||||
else tty->print("+ offset ");
|
||||
}
|
||||
|
||||
CmpUNode* cmp = new (C, 3) CmpUNode(max_idx_expr, range);
|
||||
register_new_node(cmp, ctrl);
|
||||
BoolNode* bol = new (C, 2) BoolNode(cmp, BoolTest::lt);
|
||||
register_new_node(bol, ctrl);
|
||||
|
||||
if (TraceLoopPredicate) tty->print_cr("<u range");
|
||||
return bol;
|
||||
}
|
||||
|
||||
//------------------------------ loop_predication_impl--------------------------
|
||||
// Insert loop predicates for null checks and range checks
|
||||
bool PhaseIdealLoop::loop_predication_impl(IdealLoopTree *loop) {
|
||||
if (!UseLoopPredicate) return false;
|
||||
|
||||
if (!loop->_head->is_Loop()) {
|
||||
// Could be a simple region when irreducible loops are present.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (loop->_head->unique_ctrl_out()->Opcode() == Op_NeverBranch) {
|
||||
// do nothing for infinite loops
|
||||
return false;
|
||||
}
|
||||
|
||||
CountedLoopNode *cl = NULL;
|
||||
if (loop->_head->is_CountedLoop()) {
|
||||
cl = loop->_head->as_CountedLoop();
|
||||
// do nothing for iteration-splitted loops
|
||||
if (!cl->is_normal_loop()) return false;
|
||||
}
|
||||
|
||||
LoopNode *lpn = loop->_head->as_Loop();
|
||||
Node* entry = lpn->in(LoopNode::EntryControl);
|
||||
|
||||
ProjNode *predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate);
|
||||
if (!predicate_proj) {
|
||||
#ifndef PRODUCT
|
||||
if (TraceLoopPredicate) {
|
||||
tty->print("missing predicate:");
|
||||
loop->dump_head();
|
||||
lpn->dump(1);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
ConNode* zero = _igvn.intcon(0);
|
||||
set_ctrl(zero, C->root());
|
||||
|
||||
ResourceArea *area = Thread::current()->resource_area();
|
||||
Invariance invar(area, loop);
|
||||
|
||||
// Create list of if-projs such that a newer proj dominates all older
|
||||
// projs in the list, and they all dominate loop->tail()
|
||||
Node_List if_proj_list(area);
|
||||
LoopNode *head = loop->_head->as_Loop();
|
||||
Node *current_proj = loop->tail(); //start from tail
|
||||
while (current_proj != head) {
|
||||
if (loop == get_loop(current_proj) && // still in the loop ?
|
||||
current_proj->is_Proj() && // is a projection ?
|
||||
current_proj->in(0)->Opcode() == Op_If) { // is a if projection ?
|
||||
if_proj_list.push(current_proj);
|
||||
}
|
||||
current_proj = idom(current_proj);
|
||||
}
|
||||
|
||||
bool hoisted = false; // true if at least one proj is promoted
|
||||
while (if_proj_list.size() > 0) {
|
||||
// Following are changed to nonnull when a predicate can be hoisted
|
||||
ProjNode* new_predicate_proj = NULL;
|
||||
|
||||
ProjNode* proj = if_proj_list.pop()->as_Proj();
|
||||
IfNode* iff = proj->in(0)->as_If();
|
||||
|
||||
if (!is_uncommon_trap_if_pattern(proj, Deoptimization::Reason_none)) {
|
||||
if (loop->is_loop_exit(iff)) {
|
||||
// stop processing the remaining projs in the list because the execution of them
|
||||
// depends on the condition of "iff" (iff->in(1)).
|
||||
break;
|
||||
} else {
|
||||
// Both arms are inside the loop. There are two cases:
|
||||
// (1) there is one backward branch. In this case, any remaining proj
|
||||
// in the if_proj list post-dominates "iff". So, the condition of "iff"
|
||||
// does not determine the execution the remining projs directly, and we
|
||||
// can safely continue.
|
||||
// (2) both arms are forwarded, i.e. a diamond shape. In this case, "proj"
|
||||
// does not dominate loop->tail(), so it can not be in the if_proj list.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Node* test = iff->in(1);
|
||||
if (!test->is_Bool()){ //Conv2B, ...
|
||||
continue;
|
||||
}
|
||||
BoolNode* bol = test->as_Bool();
|
||||
if (invar.is_invariant(bol)) {
|
||||
// Invariant test
|
||||
new_predicate_proj = create_new_if_for_predicate(predicate_proj, NULL,
|
||||
Deoptimization::Reason_predicate);
|
||||
Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0);
|
||||
BoolNode* new_predicate_bol = invar.clone(bol, ctrl)->as_Bool();
|
||||
|
||||
// Negate test if necessary
|
||||
bool negated = false;
|
||||
if (proj->_con != predicate_proj->_con) {
|
||||
new_predicate_bol = new (C, 2) BoolNode(new_predicate_bol->in(1), new_predicate_bol->_test.negate());
|
||||
register_new_node(new_predicate_bol, ctrl);
|
||||
negated = true;
|
||||
}
|
||||
IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If();
|
||||
_igvn.hash_delete(new_predicate_iff);
|
||||
new_predicate_iff->set_req(1, new_predicate_bol);
|
||||
#ifndef PRODUCT
|
||||
if (TraceLoopPredicate) {
|
||||
tty->print("Predicate invariant if%s: %d ", negated ? " negated" : "", new_predicate_iff->_idx);
|
||||
loop->dump_head();
|
||||
} else if (TraceLoopOpts) {
|
||||
tty->print("Predicate IC ");
|
||||
loop->dump_head();
|
||||
}
|
||||
#endif
|
||||
} else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) {
|
||||
assert(proj->_con == predicate_proj->_con, "must match");
|
||||
|
||||
// Range check for counted loops
|
||||
const Node* cmp = bol->in(1)->as_Cmp();
|
||||
Node* idx = cmp->in(1);
|
||||
assert(!invar.is_invariant(idx), "index is variant");
|
||||
assert(cmp->in(2)->Opcode() == Op_LoadRange || OptimizeFill, "must be");
|
||||
Node* rng = cmp->in(2);
|
||||
assert(invar.is_invariant(rng), "range must be invariant");
|
||||
int scale = 1;
|
||||
Node* offset = zero;
|
||||
bool ok = is_scaled_iv_plus_offset(idx, cl->phi(), &scale, &offset);
|
||||
assert(ok, "must be index expression");
|
||||
|
||||
Node* init = cl->init_trip();
|
||||
Node* limit = cl->limit();
|
||||
Node* stride = cl->stride();
|
||||
|
||||
// Build if's for the upper and lower bound tests. The
|
||||
// lower_bound test will dominate the upper bound test and all
|
||||
// cloned or created nodes will use the lower bound test as
|
||||
// their declared control.
|
||||
ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate);
|
||||
ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate);
|
||||
assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate");
|
||||
Node *ctrl = lower_bound_proj->in(0)->as_If()->in(0);
|
||||
|
||||
// Perform cloning to keep Invariance state correct since the
|
||||
// late schedule will place invariant things in the loop.
|
||||
rng = invar.clone(rng, ctrl);
|
||||
if (offset && offset != zero) {
|
||||
assert(invar.is_invariant(offset), "offset must be loop invariant");
|
||||
offset = invar.clone(offset, ctrl);
|
||||
}
|
||||
|
||||
// Test the lower bound
|
||||
Node* lower_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, false);
|
||||
IfNode* lower_bound_iff = lower_bound_proj->in(0)->as_If();
|
||||
_igvn.hash_delete(lower_bound_iff);
|
||||
lower_bound_iff->set_req(1, lower_bound_bol);
|
||||
if (TraceLoopPredicate) tty->print_cr("lower bound check if: %d", lower_bound_iff->_idx);
|
||||
|
||||
// Test the upper bound
|
||||
Node* upper_bound_bol = rc_predicate(ctrl, scale, offset, init, limit, stride, rng, true);
|
||||
IfNode* upper_bound_iff = upper_bound_proj->in(0)->as_If();
|
||||
_igvn.hash_delete(upper_bound_iff);
|
||||
upper_bound_iff->set_req(1, upper_bound_bol);
|
||||
if (TraceLoopPredicate) tty->print_cr("upper bound check if: %d", lower_bound_iff->_idx);
|
||||
|
||||
// Fall through into rest of the clean up code which will move
|
||||
// any dependent nodes onto the upper bound test.
|
||||
new_predicate_proj = upper_bound_proj;
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceLoopOpts && !TraceLoopPredicate) {
|
||||
tty->print("Predicate RC ");
|
||||
loop->dump_head();
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// Loop variant check (for example, range check in non-counted loop)
|
||||
// with uncommon trap.
|
||||
continue;
|
||||
}
|
||||
assert(new_predicate_proj != NULL, "sanity");
|
||||
// Success - attach condition (new_predicate_bol) to predicate if
|
||||
invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate
|
||||
|
||||
// Eliminate the old If in the loop body
|
||||
dominated_by( new_predicate_proj, iff, proj->_con != new_predicate_proj->_con );
|
||||
|
||||
hoisted = true;
|
||||
C->set_major_progress();
|
||||
} // end while
|
||||
|
||||
#ifndef PRODUCT
|
||||
// report that the loop predication has been actually performed
|
||||
// for this loop
|
||||
if (TraceLoopPredicate && hoisted) {
|
||||
tty->print("Loop Predication Performed:");
|
||||
loop->dump_head();
|
||||
}
|
||||
#endif
|
||||
|
||||
return hoisted;
|
||||
}
|
||||
|
||||
//------------------------------loop_predication--------------------------------
|
||||
// driver routine for loop predication optimization
|
||||
bool IdealLoopTree::loop_predication( PhaseIdealLoop *phase) {
|
||||
bool hoisted = false;
|
||||
// Recursively promote predicates
|
||||
if (_child) {
|
||||
hoisted = _child->loop_predication( phase);
|
||||
}
|
||||
|
||||
// self
|
||||
if (!_irreducible && !tail()->is_top()) {
|
||||
hoisted |= phase->loop_predication_impl(this);
|
||||
}
|
||||
|
||||
if (_next) { //sibling
|
||||
hoisted |= _next->loop_predication( phase);
|
||||
}
|
||||
|
||||
return hoisted;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user