Merge
This commit is contained in:
commit
83e14b24a2
@ -112,3 +112,4 @@ ddc2fcb3682ffd27f44354db666128827be7e3c3 jdk7-b134
|
||||
783bd02b4ab4596059c74b10a1793d7bd2f1c157 jdk7-b135
|
||||
2fe76e73adaa5133ac559f0b3c2c0707eca04580 jdk7-b136
|
||||
7654afc6a29e43cb0a1343ce7f1287bf690d5e5f jdk7-b137
|
||||
fc47c97bbbd91b1f774d855c48a7e285eb1a351a jdk7-b138
|
||||
|
@ -112,3 +112,4 @@ d7532bcd3742f1576dd07ff9fbb535c9c9a276e9 jdk7-b126
|
||||
e0b72ae5dc5e824b342801c8d1d336a55eb54e2c jdk7-b135
|
||||
48ef0c712e7cbf272f47f9224db92a3c6a9e2612 jdk7-b136
|
||||
a66c01d8bf895261715955df0b95545c000ed6a8 jdk7-b137
|
||||
78d8cf04697e9df54f7f11e195b7da29b8e345a2 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;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user