aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java5
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java2
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java1
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java1
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java3
-rw-r--r--src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp207
-rw-r--r--src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp2
-rw-r--r--src/cpu/x86/vm/assembler_x86.cpp15
-rw-r--r--src/cpu/x86/vm/assembler_x86.hpp13
-rw-r--r--src/cpu/x86/vm/c1_CodeStubs_x86.cpp4
-rw-r--r--src/cpu/x86/vm/c1_LIRAssembler_x86.cpp261
-rw-r--r--src/cpu/zero/vm/globals_zero.hpp4
-rw-r--r--src/cpu/zero/vm/relocInfo_zero.cpp4
-rw-r--r--src/cpu/zero/vm/sharedRuntime_zero.cpp14
-rw-r--r--src/share/vm/c1/c1_GraphBuilder.cpp4
-rw-r--r--src/share/vm/c1/c1_Instruction.cpp39
-rw-r--r--src/share/vm/c1/c1_Instruction.hpp31
-rw-r--r--src/share/vm/c1/c1_LIR.hpp6
-rw-r--r--src/share/vm/c1/c1_LIRAssembler.cpp3
-rw-r--r--src/share/vm/c1/c1_LIRGenerator.cpp119
-rw-r--r--src/share/vm/c1/c1_Optimizer.cpp8
-rw-r--r--src/share/vm/c1/c1_Runtime1.cpp39
-rw-r--r--src/share/vm/c1/c1_Runtime1.hpp6
-rw-r--r--src/share/vm/ci/ciInstance.cpp4
-rw-r--r--src/share/vm/ci/ciMethodHandle.cpp17
-rw-r--r--src/share/vm/ci/ciTypeFlow.hpp1
-rw-r--r--src/share/vm/classfile/classFileParser.cpp30
-rw-r--r--src/share/vm/classfile/javaClasses.cpp23
-rw-r--r--src/share/vm/classfile/systemDictionary.cpp129
-rw-r--r--src/share/vm/classfile/systemDictionary.hpp7
-rw-r--r--src/share/vm/classfile/verifier.cpp13
-rw-r--r--src/share/vm/classfile/vmSymbols.hpp31
-rw-r--r--src/share/vm/code/codeCache.cpp13
-rw-r--r--src/share/vm/code/codeCache.hpp2
-rw-r--r--src/share/vm/code/relocInfo.cpp18
-rw-r--r--src/share/vm/code/relocInfo.hpp10
-rw-r--r--src/share/vm/compiler/compileBroker.cpp6
-rw-r--r--src/share/vm/interpreter/bytecodeInterpreter.cpp2
-rw-r--r--src/share/vm/interpreter/bytecodeTracer.cpp1
-rw-r--r--src/share/vm/interpreter/interpreterRuntime.cpp5
-rw-r--r--src/share/vm/interpreter/linkResolver.cpp4
-rw-r--r--src/share/vm/interpreter/rewriter.cpp16
-rw-r--r--src/share/vm/oops/constantPoolKlass.cpp1
-rw-r--r--src/share/vm/oops/constantPoolOop.cpp16
-rw-r--r--src/share/vm/oops/constantPoolOop.hpp10
-rw-r--r--src/share/vm/oops/cpCacheOop.cpp2
-rw-r--r--src/share/vm/oops/instanceKlass.hpp7
-rw-r--r--src/share/vm/oops/instanceKlassKlass.cpp17
-rw-r--r--src/share/vm/oops/methodOop.cpp14
-rw-r--r--src/share/vm/opto/callGenerator.cpp28
-rw-r--r--src/share/vm/opto/callGenerator.hpp16
-rw-r--r--src/share/vm/opto/cfgnode.cpp18
-rw-r--r--src/share/vm/opto/compile.cpp17
-rw-r--r--src/share/vm/opto/compile.hpp3
-rw-r--r--src/share/vm/opto/doCall.cpp11
-rw-r--r--src/share/vm/opto/escape.cpp26
-rw-r--r--src/share/vm/opto/graphKit.cpp21
-rw-r--r--src/share/vm/opto/graphKit.hpp2
-rw-r--r--src/share/vm/opto/idealKit.cpp106
-rw-r--r--src/share/vm/opto/idealKit.hpp20
-rw-r--r--src/share/vm/opto/ifnode.cpp32
-rw-r--r--src/share/vm/opto/library_call.cpp91
-rw-r--r--src/share/vm/opto/loopPredicate.cpp960
-rw-r--r--src/share/vm/opto/loopTransform.cpp1037
-rw-r--r--src/share/vm/opto/loopUnswitch.cpp32
-rw-r--r--src/share/vm/opto/loopnode.cpp67
-rw-r--r--src/share/vm/opto/loopnode.hpp90
-rw-r--r--src/share/vm/opto/loopopts.cpp27
-rw-r--r--src/share/vm/opto/phaseX.hpp7
-rw-r--r--src/share/vm/opto/split_if.cpp3
-rw-r--r--src/share/vm/opto/superword.cpp7
-rw-r--r--src/share/vm/opto/vectornode.hpp1
-rw-r--r--src/share/vm/prims/jvm.h2
-rw-r--r--src/share/vm/prims/jvmtiManageCapabilities.cpp7
-rw-r--r--src/share/vm/prims/methodHandleWalk.cpp6
-rw-r--r--src/share/vm/prims/methodHandles.cpp171
-rw-r--r--src/share/vm/prims/nativeLookup.cpp2
-rw-r--r--src/share/vm/runtime/arguments.cpp11
-rw-r--r--src/share/vm/runtime/globals.cpp6
-rw-r--r--src/share/vm/runtime/globals.hpp8
-rw-r--r--src/share/vm/runtime/sharedRuntime.cpp33
-rw-r--r--src/share/vm/runtime/stubRoutines.cpp74
-rw-r--r--src/share/vm/runtime/stubRoutines.hpp2
-rw-r--r--src/share/vm/shark/sharkCompiler.cpp4
-rw-r--r--src/share/vm/shark/sharkCompiler.hpp6
-rw-r--r--src/share/vm/utilities/constantTag.cpp2
-rw-r--r--src/share/vm/utilities/constantTag.hpp3
-rw-r--r--src/share/vm/utilities/globalDefinitions.hpp6
-rw-r--r--src/share/vm/utilities/globalDefinitions_gcc.hpp2
89 files changed, 2607 insertions, 1550 deletions
diff --git a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java
index 9bb918b87..f297e3281 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java
@@ -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);
diff --git a/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java b/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java
index 3a008c0b0..722496e3c 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java
@@ -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
diff --git a/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java b/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java
index e9202edb8..91739eff5 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java
@@ -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);
diff --git a/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java b/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java
index 1b01316cb..8e3cbb7f8 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java
@@ -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)) +
diff --git a/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java b/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java
index 1ee547be3..60a2172a5 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java
@@ -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; }
diff --git a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
index 89ec0ef20..b45043776 100644
--- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
+++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
@@ -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());
}
diff --git a/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp b/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp
index 2905687eb..35e70e996 100644
--- a/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp
+++ b/src/cpu/sparc/vm/c1_MacroAssembler_sparc.cpp
@@ -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);
diff --git a/src/cpu/x86/vm/assembler_x86.cpp b/src/cpu/x86/vm/assembler_x86.cpp
index 0e96e8d42..34b0fffdd 100644
--- a/src/cpu/x86/vm/assembler_x86.cpp
+++ b/src/cpu/x86/vm/assembler_x86.cpp
@@ -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) {
diff --git a/src/cpu/x86/vm/assembler_x86.hpp b/src/cpu/x86/vm/assembler_x86.hpp
index 6ef01cbb4..1407248b1 100644
--- a/src/cpu/x86/vm/assembler_x86.hpp
+++ b/src/cpu/x86/vm/assembler_x86.hpp
@@ -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
diff --git a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
index 360383115..120570c64 100644
--- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
+++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp
@@ -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);
diff --git a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
index 7ee339126..bcec4d4d7 100644
--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
@@ -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());
}
diff --git a/src/cpu/zero/vm/globals_zero.hpp b/src/cpu/zero/vm/globals_zero.hpp
index 88c7d0888..c45f1f576 100644
--- a/src/cpu/zero/vm/globals_zero.hpp
+++ b/src/cpu/zero/vm/globals_zero.hpp
@@ -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
diff --git a/src/cpu/zero/vm/relocInfo_zero.cpp b/src/cpu/zero/vm/relocInfo_zero.cpp
index e04acad8f..13f095e47 100644
--- a/src/cpu/zero/vm/relocInfo_zero.cpp
+++ b/src/cpu/zero/vm/relocInfo_zero.cpp
@@ -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();
}
diff --git a/src/cpu/zero/vm/sharedRuntime_zero.cpp b/src/cpu/zero/vm/sharedRuntime_zero.cpp
index b88c5e810..6e7643ae5 100644
--- a/src/cpu/zero/vm/sharedRuntime_zero.cpp
+++ b/src/cpu/zero/vm/sharedRuntime_zero.cpp
@@ -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();
diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp
index e956b6bb4..9bac474f5 100644
--- a/src/share/vm/c1/c1_GraphBuilder.cpp
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp
@@ -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();
}
diff --git a/src/share/vm/c1/c1_Instruction.cpp b/src/share/vm/c1/c1_Instruction.cpp
index 7f578cb05..a5ee2b564 100644
--- a/src/share/vm/c1/c1_Instruction.cpp
+++ b/src/share/vm/c1/c1_Instruction.cpp
@@ -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 {
diff --git a/src/share/vm/c1/c1_Instruction.hpp b/src/share/vm/c1/c1_Instruction.hpp
index d997c572c..719c1f2fb 100644
--- a/src/share/vm/c1/c1_Instruction.hpp
+++ b/src/share/vm/c1/c1_Instruction.hpp
@@ -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) {
diff --git a/src/share/vm/c1/c1_LIR.hpp b/src/share/vm/c1/c1_LIR.hpp
index c5c5d91c7..a2770e402 100644
--- a/src/share/vm/c1/c1_LIR.hpp
+++ b/src/share/vm/c1/c1_LIR.hpp
@@ -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,
diff --git a/src/share/vm/c1/c1_LIRAssembler.cpp b/src/share/vm/c1/c1_LIRAssembler.cpp
index 3417bda78..d3b853bed 100644
--- a/src/share/vm/c1/c1_LIRAssembler.cpp
+++ b/src/share/vm/c1/c1_LIRAssembler.cpp
@@ -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;
diff --git a/src/share/vm/c1/c1_LIRGenerator.cpp b/src/share/vm/c1/c1_LIRGenerator.cpp
index ae3773bcc..33278ef50 100644
--- a/src/share/vm/c1/c1_LIRGenerator.cpp
+++ b/src/share/vm/c1/c1_LIRGenerator.cpp
@@ -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 {
diff --git a/src/share/vm/c1/c1_Optimizer.cpp b/src/share/vm/c1/c1_Optimizer.cpp
index 93d610e62..f07494d37 100644
--- a/src/share/vm/c1/c1_Optimizer.cpp
+++ b/src/share/vm/c1/c1_Optimizer.cpp
@@ -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;
diff --git a/src/share/vm/c1/c1_Runtime1.cpp b/src/share/vm/c1/c1_Runtime1.cpp
index 63fe9c0a2..03e83420d 100644
--- a/src/share/vm/c1/c1_Runtime1.cpp
+++ b/src/share/vm/c1/c1_Runtime1.cpp
@@ -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);
diff --git a/src/share/vm/c1/c1_Runtime1.hpp b/src/share/vm/c1/c1_Runtime1.hpp
index 1d6782c6a..78f73bf62 100644
--- a/src/share/vm/c1/c1_Runtime1.hpp
+++ b/src/share/vm/c1/c1_Runtime1.hpp
@@ -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
diff --git a/src/share/vm/ci/ciInstance.cpp b/src/share/vm/ci/ciInstance.cpp
index d249caa2e..0c671082b 100644
--- a/src/share/vm/ci/ciInstance.cpp
+++ b/src/share/vm/ci/ciInstance.cpp
@@ -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();
diff --git a/src/share/vm/ci/ciMethodHandle.cpp b/src/share/vm/ci/ciMethodHandle.cpp
index 1355b504c..ef57f800c 100644
--- a/src/share/vm/ci/ciMethodHandle.cpp
+++ b/src/share/vm/ci/ciMethodHandle.cpp
@@ -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;
}
diff --git a/src/share/vm/ci/ciTypeFlow.hpp b/src/share/vm/ci/ciTypeFlow.hpp
index e83487d19..5cc5c90c8 100644
--- a/src/share/vm/ci/ciTypeFlow.hpp
+++ b/src/share/vm/ci/ciTypeFlow.hpp
@@ -34,6 +34,7 @@
#include "ci/ciEnv.hpp"
#include "ci/ciKlass.hpp"
#include "ci/ciMethodBlocks.hpp"
+#include "shark/shark_globals.hpp"
#endif
diff --git a/src/share/vm/classfile/classFileParser.cpp b/src/share/vm/classfile/classFileParser.cpp
index 3f71a2b43..cd4ef079f 100644
--- a/src/share/vm/classfile/classFileParser.cpp
+++ b/src/share/vm/classfile/classFileParser.cpp
@@ -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.
diff --git a/src/share/vm/classfile/javaClasses.cpp b/src/share/vm/classfile/javaClasses.cpp
index 9294a58fb..5fad095b4 100644
--- a/src/share/vm/classfile/javaClasses.cpp
+++ b/src/share/vm/classfile/javaClasses.cpp
@@ -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,
@@ -2333,7 +2311,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);
diff --git a/src/share/vm/classfile/systemDictionary.cpp b/src/share/vm/classfile/systemDictionary.cpp
index 9ed92f835..17a9f7406 100644
--- a/src/share/vm/classfile/systemDictionary.cpp
+++ b/src/share/vm/classfile/systemDictionary.cpp
@@ -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;
}
diff --git a/src/share/vm/classfile/systemDictionary.hpp b/src/share/vm/classfile/systemDictionary.hpp
index 6db5a5048..ab84ebf59 100644
--- a/src/share/vm/classfile/systemDictionary.hpp
+++ b/src/share/vm/classfile/systemDictionary.hpp
@@ -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; }
diff --git a/src/share/vm/classfile/verifier.cpp b/src/share/vm/classfile/verifier.cpp
index 67a2a66db..9ab47f7b6 100644
--- a/src/share/vm/classfile/verifier.cpp
+++ b/src/share/vm/classfile/verifier.cpp
@@ -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));
diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp
index 81376926f..00bd191c8 100644
--- a/src/share/vm/classfile/vmSymbols.hpp
+++ b/src/share/vm/classfile/vmSymbols.hpp
@@ -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) ) \
\
@@ -910,8 +881,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) \
diff --git a/src/share/vm/code/codeCache.cpp b/src/share/vm/code/codeCache.cpp
index ce3b4dc95..4dba8927b 100644
--- a/src/share/vm/code/codeCache.cpp
+++ b/src/share/vm/code/codeCache.cpp
@@ -964,3 +964,16 @@ 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 {
+ // Avoid lock ordering problems with ttyLock.
+ ttyUnlocker ttyul;
+ MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+ return _heap->largest_free_block();
+ }
+}
diff --git a/src/share/vm/code/codeCache.hpp b/src/share/vm/code/codeCache.hpp
index 9107bbcc1..bdd128e98 100644
--- a/src/share/vm/code/codeCache.hpp
+++ b/src/share/vm/code/codeCache.hpp
@@ -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; }
diff --git a/src/share/vm/code/relocInfo.cpp b/src/share/vm/code/relocInfo.cpp
index 43a8eef06..4fd82dfaa 100644
--- a/src/share/vm/code/relocInfo.cpp
+++ b/src/share/vm/code/relocInfo.cpp
@@ -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;
diff --git a/src/share/vm/code/relocInfo.hpp b/src/share/vm/code/relocInfo.hpp
index 9f5ad21d9..1d14b4450 100644
--- a/src/share/vm/code/relocInfo.hpp
+++ b/src/share/vm/code/relocInfo.hpp
@@ -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
diff --git a/src/share/vm/compiler/compileBroker.cpp b/src/share/vm/compiler/compileBroker.cpp
index 506836476..47def8af8 100644
--- a/src/share/vm/compiler/compileBroker.cpp
+++ b/src/share/vm/compiler/compileBroker.cpp
@@ -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.
diff --git a/src/share/vm/interpreter/bytecodeInterpreter.cpp b/src/share/vm/interpreter/bytecodeInterpreter.cpp
index 9428ab967..2826809f5 100644
--- a/src/share/vm/interpreter/bytecodeInterpreter.cpp
+++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp
@@ -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_default, &&opc_default, &&opc_return_register_finalizer,
/* 0xE8 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default,
/* 0xEC */ &&opc_default, &&opc_default, &&opc_default, &&opc_default,
diff --git a/src/share/vm/interpreter/bytecodeTracer.cpp b/src/share/vm/interpreter/bytecodeTracer.cpp
index ff28656b3..1309d0cf9 100644
--- a/src/share/vm/interpreter/bytecodeTracer.cpp
+++ b/src/share/vm/interpreter/bytecodeTracer.cpp
@@ -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:
diff --git a/src/share/vm/interpreter/interpreterRuntime.cpp b/src/share/vm/interpreter/interpreterRuntime.cpp
index 66cb27edf..499a66046 100644
--- a/src/share/vm/interpreter/interpreterRuntime.cpp
+++ b/src/share/vm/interpreter/interpreterRuntime.cpp
@@ -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
diff --git a/src/share/vm/interpreter/linkResolver.cpp b/src/share/vm/interpreter/linkResolver.cpp
index 746d86fd2..ee61e5795 100644
--- a/src/share/vm/interpreter/linkResolver.cpp
+++ b/src/share/vm/interpreter/linkResolver.cpp
@@ -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,
diff --git a/src/share/vm/interpreter/rewriter.cpp b/src/share/vm/interpreter/rewriter.cpp
index 3bdebda09..5be2df24b 100644
--- a/src/share/vm/interpreter/rewriter.cpp
+++ b/src/share/vm/interpreter/rewriter.cpp
@@ -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);
}
}
}
diff --git a/src/share/vm/oops/constantPoolKlass.cpp b/src/share/vm/oops/constantPoolKlass.cpp
index 87a771bfe..627a2017e 100644
--- a/src/share/vm/oops/constantPoolKlass.cpp
+++ b/src/share/vm/oops/constantPoolKlass.cpp
@@ -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));
diff --git a/src/share/vm/oops/constantPoolOop.cpp b/src/share/vm/oops/constantPoolOop.cpp
index 91ab822d0..00aa94f20 100644
--- a/src/share/vm/oops/constantPoolOop.cpp
+++ b/src/share/vm/oops/constantPoolOop.cpp
@@ -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));
diff --git a/src/share/vm/oops/constantPoolOop.hpp b/src/share/vm/oops/constantPoolOop.hpp
index d53de40e0..d8dd7844d 100644
--- a/src/share/vm/oops/constantPoolOop.hpp
+++ b/src/share/vm/oops/constantPoolOop.hpp
@@ -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;
diff --git a/src/share/vm/oops/cpCacheOop.cpp b/src/share/vm/oops/cpCacheOop.cpp
index 24855ce75..953ac789f 100644
--- a/src/share/vm/oops/cpCacheOop.cpp
+++ b/src/share/vm/oops/cpCacheOop.cpp
@@ -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
diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp
index a1701e438..e0d70ae68 100644
--- a/src/share/vm/oops/instanceKlass.hpp
+++ b/src/share/vm/oops/instanceKlass.hpp
@@ -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;}
diff --git a/src/share/vm/oops/instanceKlassKlass.cpp b/src/share/vm/oops/instanceKlassKlass.cpp
index 897c5157c..aa12d13a8 100644
--- a/src/share/vm/oops/instanceKlassKlass.cpp
+++ b/src/share/vm/oops/instanceKlassKlass.cpp
@@ -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);
diff --git a/src/share/vm/oops/methodOop.cpp b/src/share/vm/oops/methodOop.cpp
index 16d42b026..5e470ac35 100644
--- a/src/share/vm/oops/methodOop.cpp
+++ b/src/share/vm/oops/methodOop.cpp
@@ -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;
}
@@ -1092,7 +1092,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 +1117,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):
diff --git a/src/share/vm/opto/callGenerator.cpp b/src/share/vm/opto/callGenerator.cpp
index 6d201139e..ed02629d6 100644
--- a/src/share/vm/opto/callGenerator.cpp
+++ b/src/share/vm/opto/callGenerator.cpp
@@ -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;
}
diff --git a/src/share/vm/opto/callGenerator.hpp b/src/share/vm/opto/callGenerator.hpp
index 75e8ba004..4a50f990e 100644
--- a/src/share/vm/opto/callGenerator.hpp
+++ b/src/share/vm/opto/callGenerator.hpp
@@ -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
diff --git a/src/share/vm/opto/cfgnode.cpp b/src/share/vm/opto/cfgnode.cpp
index f6ca3ce7f..90f0234f0 100644
--- a/src/share/vm/opto/cfgnode.cpp
+++ b/src/share/vm/opto/cfgnode.cpp
@@ -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);
diff --git a/src/share/vm/opto/compile.cpp b/src/share/vm/opto/compile.cpp
index 39bcf30bd..e6084be0e 100644
--- a/src/share/vm/opto/compile.cpp
+++ b/src/share/vm/opto/compile.cpp
@@ -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;
- }
}
}
diff --git a/src/share/vm/opto/compile.hpp b/src/share/vm/opto/compile.hpp
index 5b562ecee..b2d81897a 100644
--- a/src/share/vm/opto/compile.hpp
+++ b/src/share/vm/opto/compile.hpp
@@ -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; }
diff --git a/src/share/vm/opto/doCall.cpp b/src/share/vm/opto/doCall.cpp
index e7cdaf47e..de066e992 100644
--- a/src/share/vm/opto/doCall.cpp
+++ b/src/share/vm/opto/doCall.cpp
@@ -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);
diff --git a/src/share/vm/opto/escape.cpp b/src/share/vm/opto/escape.cpp
index 788a79785..a7b509e34 100644
--- a/src/share/vm/opto/escape.cpp
+++ b/src/share/vm/opto/escape.cpp
@@ -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.
diff --git a/src/share/vm/opto/graphKit.cpp b/src/share/vm/opto/graphKit.cpp
index 794a0f717..afa2efff9 100644
--- a/src/share/vm/opto/graphKit.cpp
+++ b/src/share/vm/opto/graphKit.cpp
@@ -3385,12 +3385,17 @@ void GraphKit::add_predicate(int nargs) {
#define __ ideal.
void GraphKit::sync_kit(IdealKit& ideal) {
- // Final sync IdealKit and graphKit.
- __ drain_delay_transform();
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();
+ sync_kit(ideal);
+}
+
// vanilla/CMS post barrier
// Insert a write-barrier store. This is to let generational GC work; we have
// to flag all oop-stores before the next GC point.
@@ -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 __
diff --git a/src/share/vm/opto/graphKit.hpp b/src/share/vm/opto/graphKit.hpp
index 1302184fc..4523326db 100644
--- a/src/share/vm/opto/graphKit.hpp
+++ b/src/share/vm/opto/graphKit.hpp
@@ -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,
diff --git a/src/share/vm/opto/idealKit.cpp b/src/share/vm/opto/idealKit.cpp
index a143a6492..c9cb0f855 100644
--- a/src/share/vm/opto/idealKit.cpp
+++ b/src/share/vm/opto/idealKit.cpp
@@ -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);
diff --git a/src/share/vm/opto/idealKit.hpp b/src/share/vm/opto/idealKit.hpp
index 1ece14259..6787e533a 100644
--- a/src/share/vm/opto/idealKit.hpp
+++ b/src/share/vm/opto/idealKit.hpp
@@ -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
diff --git a/src/share/vm/opto/ifnode.cpp b/src/share/vm/opto/ifnode.cpp
index 25f2e3151..bcdf5ad64 100644
--- a/src/share/vm/opto/ifnode.cpp
+++ b/src/share/vm/opto/ifnode.cpp
@@ -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);
diff --git a/src/share/vm/opto/library_call.cpp b/src/share/vm/opto/library_call.cpp
index be8136bf5..0f73e144d 100644
--- a/src/share/vm/opto/library_call.cpp
+++ b/src/share/vm/opto/library_call.cpp
@@ -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);
}
diff --git a/src/share/vm/opto/loopPredicate.cpp b/src/share/vm/opto/loopPredicate.cpp
new file mode 100644
index 000000000..c5ac2c682
--- /dev/null
+++ b/src/share/vm/opto/loopPredicate.cpp
@@ -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;
+}
+
diff --git a/src/share/vm/opto/loopTransform.cpp b/src/share/vm/opto/loopTransform.cpp
index 9c5a7e034..b182f4e4f 100644
--- a/src/share/vm/opto/loopTransform.cpp
+++ b/src/share/vm/opto/loopTransform.cpp
@@ -63,6 +63,46 @@ void IdealLoopTree::record_for_igvn() {
}
}
+//------------------------------compute_exact_trip_count-----------------------
+// Compute loop exact trip count if possible. Do not recalculate trip count for
+// split loops (pre-main-post) which have their limits and inits behind Opaque node.
+void IdealLoopTree::compute_exact_trip_count( PhaseIdealLoop *phase ) {
+ if (!_head->as_Loop()->is_valid_counted_loop()) {
+ return;
+ }
+ CountedLoopNode* cl = _head->as_CountedLoop();
+ // Trip count may become nonexact for iteration split loops since
+ // RCE modifies limits. Note, _trip_count value is not reset since
+ // it is used to limit unrolling of main loop.
+ cl->set_nonexact_trip_count();
+
+ // Loop's test should be part of loop.
+ if (!phase->is_member(this, phase->get_ctrl(cl->loopexit()->in(CountedLoopEndNode::TestValue))))
+ return; // Infinite loop
+
+#ifdef ASSERT
+ BoolTest::mask bt = cl->loopexit()->test_trip();
+ assert(bt == BoolTest::lt || bt == BoolTest::gt ||
+ bt == BoolTest::ne, "canonical test is expected");
+#endif
+
+ Node* init_n = cl->init_trip();
+ Node* limit_n = cl->limit();
+ if (init_n != NULL && init_n->is_Con() &&
+ limit_n != NULL && limit_n->is_Con()) {
+ // Use longs to avoid integer overflow.
+ int stride_con = cl->stride_con();
+ long init_con = cl->init_trip()->get_int();
+ long limit_con = cl->limit()->get_int();
+ int stride_m = stride_con - (stride_con > 0 ? 1 : -1);
+ long trip_count = (limit_con - init_con + stride_m)/stride_con;
+ if (trip_count > 0 && (julong)trip_count < (julong)max_juint) {
+ // Set exact trip count.
+ cl->set_exact_trip_count((uint)trip_count);
+ }
+ }
+}
+
//------------------------------compute_profile_trip_cnt----------------------------
// Compute loop trip count from profile data as
// (backedge_count + loop_exit_count) / loop_exit_count
@@ -301,6 +341,132 @@ void PhaseIdealLoop::peeled_dom_test_elim( IdealLoopTree *loop, Node_List &old_n
// peeled-loop backedge has 2 users.
// Step 3: Cut the backedge on the clone (so its not a loop) and remove the
// extra backedge user.
+//
+// orig
+//
+// stmt1
+// |
+// v
+// loop predicate
+// |
+// v
+// loop<----+
+// | |
+// stmt2 |
+// | |
+// v |
+// if ^
+// / \ |
+// / \ |
+// v v |
+// false true |
+// / \ |
+// / ----+
+// |
+// v
+// exit
+//
+//
+// after clone loop
+//
+// stmt1
+// |
+// v
+// loop predicate
+// / \
+// clone / \ orig
+// / \
+// / \
+// v v
+// +---->loop clone loop<----+
+// | | | |
+// | stmt2 clone stmt2 |
+// | | | |
+// | v v |
+// ^ if clone If ^
+// | / \ / \ |
+// | / \ / \ |
+// | v v v v |
+// | true false false true |
+// | / \ / \ |
+// +---- \ / ----+
+// \ /
+// 1v v2
+// region
+// |
+// v
+// exit
+//
+//
+// after peel and predicate move
+//
+// stmt1
+// /
+// /
+// clone / orig
+// /
+// / +----------+
+// / | |
+// / loop predicate |
+// / | |
+// v v |
+// TOP-->loop clone loop<----+ |
+// | | | |
+// stmt2 clone stmt2 | |
+// | | | ^
+// v v | |
+// if clone If ^ |
+// / \ / \ | |
+// / \ / \ | |
+// v v v v | |
+// true false false true | |
+// | \ / \ | |
+// | \ / ----+ ^
+// | \ / |
+// | 1v v2 |
+// v region |
+// | | |
+// | v |
+// | exit |
+// | |
+// +--------------->-----------------+
+//
+//
+// final graph
+//
+// stmt1
+// |
+// v
+// stmt2 clone
+// |
+// v
+// if clone
+// / |
+// / |
+// v v
+// false true
+// | |
+// | v
+// | loop predicate
+// | |
+// | v
+// | loop<----+
+// | | |
+// | stmt2 |
+// | | |
+// | v |
+// v if ^
+// | / \ |
+// | / \ |
+// | v v |
+// | false true |
+// | | \ |
+// v v --+
+// region
+// |
+// v
+// exit
+//
void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
C->set_major_progress();
@@ -315,9 +481,10 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
loop->dump_head();
}
#endif
- Node *h = loop->_head;
- if (h->is_CountedLoop()) {
- CountedLoopNode *cl = h->as_CountedLoop();
+ Node* head = loop->_head;
+ bool counted_loop = head->is_CountedLoop();
+ if (counted_loop) {
+ CountedLoopNode *cl = head->as_CountedLoop();
assert(cl->trip_count() > 0, "peeling a fully unrolled loop");
cl->set_trip_count(cl->trip_count() - 1);
if (cl->is_main_loop()) {
@@ -330,11 +497,11 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
#endif
}
}
+ Node* entry = head->in(LoopNode::EntryControl);
// Step 1: Clone the loop body. The clone becomes the peeled iteration.
// The pre-loop illegally has 2 control users (old & new loops).
- clone_loop( loop, old_new, dom_depth(loop->_head) );
-
+ clone_loop( loop, old_new, dom_depth(head) );
// Step 2: Make the old-loop fall-in edges point to the peeled iteration.
// Do this by making the old-loop fall-in edges act as if they came
@@ -342,12 +509,15 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
// backedges) and then map to the new peeled iteration. This leaves
// the pre-loop with only 1 user (the new peeled iteration), but the
// peeled-loop backedge has 2 users.
- for (DUIterator_Fast jmax, j = loop->_head->fast_outs(jmax); j < jmax; j++) {
- Node* old = loop->_head->fast_out(j);
- if( old->in(0) == loop->_head && old->req() == 3 &&
- (old->is_Loop() || old->is_Phi()) ) {
- Node *new_exit_value = old_new[old->in(LoopNode::LoopBackControl)->_idx];
- if( !new_exit_value ) // Backedge value is ALSO loop invariant?
+ Node* new_exit_value = old_new[head->in(LoopNode::LoopBackControl)->_idx];
+ new_exit_value = move_loop_predicates(entry, new_exit_value);
+ _igvn.hash_delete(head);
+ head->set_req(LoopNode::EntryControl, new_exit_value);
+ for (DUIterator_Fast jmax, j = head->fast_outs(jmax); j < jmax; j++) {
+ Node* old = head->fast_out(j);
+ if (old->in(0) == loop->_head && old->req() == 3 && old->is_Phi()) {
+ new_exit_value = old_new[old->in(LoopNode::LoopBackControl)->_idx];
+ if (!new_exit_value ) // Backedge value is ALSO loop invariant?
// Then loop body backedge value remains the same.
new_exit_value = old->in(LoopNode::LoopBackControl);
_igvn.hash_delete(old);
@@ -358,12 +528,12 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
// Step 3: Cut the backedge on the clone (so its not a loop) and remove the
// extra backedge user.
- Node *nnn = old_new[loop->_head->_idx];
- _igvn.hash_delete(nnn);
- nnn->set_req(LoopNode::LoopBackControl, C->top());
- for (DUIterator_Fast j2max, j2 = nnn->fast_outs(j2max); j2 < j2max; j2++) {
- Node* use = nnn->fast_out(j2);
- if( use->in(0) == nnn && use->req() == 3 && use->is_Phi() ) {
+ Node* new_head = old_new[head->_idx];
+ _igvn.hash_delete(new_head);
+ new_head->set_req(LoopNode::LoopBackControl, C->top());
+ for (DUIterator_Fast j2max, j2 = new_head->fast_outs(j2max); j2 < j2max; j2++) {
+ Node* use = new_head->fast_out(j2);
+ if (use->in(0) == new_head && use->req() == 3 && use->is_Phi()) {
_igvn.hash_delete(use);
use->set_req(LoopNode::LoopBackControl, C->top());
}
@@ -371,15 +541,15 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
// Step 4: Correct dom-depth info. Set to loop-head depth.
- int dd = dom_depth(loop->_head);
- set_idom(loop->_head, loop->_head->in(1), dd);
+ int dd = dom_depth(head);
+ set_idom(head, head->in(1), dd);
for (uint j3 = 0; j3 < loop->_body.size(); j3++) {
Node *old = loop->_body.at(j3);
Node *nnn = old_new[old->_idx];
if (!has_ctrl(nnn))
set_idom(nnn, idom(nnn), dd-1);
// While we're at it, remove any SafePoints from the peeled code
- if( old->Opcode() == Op_SafePoint ) {
+ if (old->Opcode() == Op_SafePoint) {
Node *nnn = old_new[old->_idx];
lazy_replace(nnn,nnn->in(TypeFunc::Control));
}
@@ -392,34 +562,26 @@ void PhaseIdealLoop::do_peeling( IdealLoopTree *loop, Node_List &old_new ) {
loop->record_for_igvn();
}
+#define EMPTY_LOOP_SIZE 7 // number of nodes in an empty loop
+
//------------------------------policy_maximally_unroll------------------------
-// Return exact loop trip count, or 0 if not maximally unrolling
+// Calculate exact loop trip count and return true if loop can be maximally
+// unrolled.
bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const {
CountedLoopNode *cl = _head->as_CountedLoop();
assert(cl->is_normal_loop(), "");
+ if (!cl->is_valid_counted_loop())
+ return false; // Malformed counted loop
- Node *init_n = cl->init_trip();
- Node *limit_n = cl->limit();
-
- // Non-constant bounds
- if (init_n == NULL || !init_n->is_Con() ||
- limit_n == NULL || !limit_n->is_Con() ||
- // protect against stride not being a constant
- !cl->stride_is_con()) {
+ if (!cl->has_exact_trip_count()) {
+ // Trip count is not exact.
return false;
}
- int init = init_n->get_int();
- int limit = limit_n->get_int();
- int span = limit - init;
- int stride = cl->stride_con();
- if (init >= limit || stride > span) {
- // return a false (no maximally unroll) and the regular unroll/peel
- // route will make a small mess which CCP will fold away.
- return false;
- }
- uint trip_count = span/stride; // trip_count can be greater than 2 Gig.
- assert( (int)trip_count*stride == span, "must divide evenly" );
+ uint trip_count = cl->trip_count();
+ // Note, max_juint is used to indicate unknown trip count.
+ assert(trip_count > 1, "one iteration loop should be optimized out already");
+ assert(trip_count < max_juint, "exact trip_count should be less than max_uint.");
// Real policy: if we maximally unroll, does it get too big?
// Allow the unrolled mess to get larger than standard loop
@@ -427,15 +589,29 @@ bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const {
uint body_size = _body.size();
uint unroll_limit = (uint)LoopUnrollLimit * 4;
assert( (intx)unroll_limit == LoopUnrollLimit * 4, "LoopUnrollLimit must fit in 32bits");
- cl->set_trip_count(trip_count);
if (trip_count > unroll_limit || body_size > unroll_limit) {
return false;
}
+ // Take into account that after unroll conjoined heads and tails will fold,
+ // otherwise policy_unroll() may allow more unrolling than max unrolling.
+ uint new_body_size = EMPTY_LOOP_SIZE + (body_size - EMPTY_LOOP_SIZE) * trip_count;
+ uint tst_body_size = (new_body_size - EMPTY_LOOP_SIZE) / trip_count + EMPTY_LOOP_SIZE;
+ if (body_size != tst_body_size) // Check for int overflow
+ return false;
+ if (new_body_size > unroll_limit ||
+ // Unrolling can result in a large amount of node construction
+ new_body_size >= MaxNodeLimit - phase->C->unique()) {
+ return false;
+ }
+
// Currently we don't have policy to optimize one iteration loops.
// Maximally unrolling transformation is used for that:
// it is peeled and the original loop become non reachable (dead).
- if (trip_count == 1)
+ // Also fully unroll a loop with few iterations regardless next
+ // conditions since following loop optimizations will split
+ // such loop anyway (pre-main-post).
+ if (trip_count <= 3)
return true;
// Do not unroll a loop with String intrinsics code.
@@ -452,17 +628,7 @@ bool IdealLoopTree::policy_maximally_unroll( PhaseIdealLoop *phase ) const {
} // switch
}
- if (body_size <= unroll_limit) {
- uint new_body_size = body_size * trip_count;
- if (new_body_size <= unroll_limit &&
- body_size == new_body_size / trip_count &&
- // Unrolling can result in a large amount of node construction
- new_body_size < MaxNodeLimit - phase->C->unique()) {
- return true; // maximally unroll
- }
- }
-
- return false; // Do not maximally unroll
+ return true; // Do maximally unroll
}
@@ -474,12 +640,15 @@ bool IdealLoopTree::policy_unroll( PhaseIdealLoop *phase ) const {
CountedLoopNode *cl = _head->as_CountedLoop();
assert(cl->is_normal_loop() || cl->is_main_loop(), "");
- // protect against stride not being a constant
- if (!cl->stride_is_con()) return false;
+ if (!cl->is_valid_counted_loop())
+ return false; // Malformed counted loop
// protect against over-unrolling
if (cl->trip_count() <= 1) return false;
+ // Check for stride being a small enough constant
+ if (abs(cl->stride_con()) > (1<<3)) return false;
+
int future_unroll_ct = cl->unrolled_count() * 2;
// Don't unroll if the next round of unrolling would push us
@@ -560,9 +729,6 @@ bool IdealLoopTree::policy_unroll( PhaseIdealLoop *phase ) const {
return false;
}
- // Check for stride being a small enough constant
- if (abs(cl->stride_con()) > (1<<3)) return false;
-
// Unroll once! (Each trip will soon do double iterations)
return true;
}
@@ -956,7 +1122,11 @@ void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool ad
tty->print("Unrolling ");
loop->dump_head();
} else if (TraceLoopOpts) {
- tty->print("Unroll %d ", loop_head->unrolled_count()*2);
+ if (loop_head->trip_count() < (uint)LoopUnrollLimit) {
+ tty->print("Unroll %d(%2d) ", loop_head->unrolled_count()*2, loop_head->trip_count());
+ } else {
+ tty->print("Unroll %d ", loop_head->unrolled_count()*2);
+ }
loop->dump_head();
}
#endif
@@ -1631,7 +1801,7 @@ void IdealLoopTree::adjust_loop_exit_prob( PhaseIdealLoop *phase ) {
// have on the last iteration. This will break the loop.
bool IdealLoopTree::policy_do_remove_empty_loop( PhaseIdealLoop *phase ) {
// Minimum size must be empty loop
- if (_body.size() > 7/*number of nodes in an empty loop*/)
+ if (_body.size() > EMPTY_LOOP_SIZE)
return false;
if (!_head->is_CountedLoop())
@@ -1658,8 +1828,19 @@ bool IdealLoopTree::policy_do_remove_empty_loop( PhaseIdealLoop *phase ) {
// main and post loops have explicitly created zero trip guard
bool needs_guard = !cl->is_main_loop() && !cl->is_post_loop();
if (needs_guard) {
+ // Skip guard if values not overlap.
+ const TypeInt* init_t = phase->_igvn.type(cl->init_trip())->is_int();
+ const TypeInt* limit_t = phase->_igvn.type(cl->limit())->is_int();
+ int stride_con = cl->stride_con();
+ if (stride_con > 0) {
+ needs_guard = (init_t->_hi >= limit_t->_lo);
+ } else {
+ needs_guard = (init_t->_lo <= limit_t->_hi);
+ }
+ }
+ if (needs_guard) {
// Check for an obvious zero trip guard.
- Node* inctrl = cl->in(LoopNode::EntryControl);
+ Node* inctrl = PhaseIdealLoop::skip_loop_predicates(cl->in(LoopNode::EntryControl));
if (inctrl->Opcode() == Op_IfTrue) {
// The test should look like just the backedge of a CountedLoop
Node* iff = inctrl->in(0);
@@ -1702,12 +1883,49 @@ bool IdealLoopTree::policy_do_remove_empty_loop( PhaseIdealLoop *phase ) {
return true;
}
+//------------------------------policy_do_one_iteration_loop-------------------
+// Convert one iteration loop into normal code.
+bool IdealLoopTree::policy_do_one_iteration_loop( PhaseIdealLoop *phase ) {
+ if (!_head->as_Loop()->is_valid_counted_loop())
+ return false; // Only for counted loop
+
+ CountedLoopNode *cl = _head->as_CountedLoop();
+ if (!cl->has_exact_trip_count() || cl->trip_count() != 1) {
+ return false;
+ }
+
+#ifndef PRODUCT
+ if(TraceLoopOpts) {
+ tty->print("OneIteration ");
+ this->dump_head();
+ }
+#endif
+
+ Node *init_n = cl->init_trip();
+#ifdef ASSERT
+ // Loop boundaries should be constant since trip count is exact.
+ assert(init_n->get_int() + cl->stride_con() >= cl->limit()->get_int(), "should be one iteration");
+#endif
+ // Replace the phi at loop head with the value of the init_trip.
+ // Then the CountedLoopEnd will collapse (backedge will not be taken)
+ // and all loop-invariant uses of the exit values will be correct.
+ phase->_igvn.replace_node(cl->phi(), cl->init_trip());
+ phase->C->set_major_progress();
+ return true;
+}
//=============================================================================
//------------------------------iteration_split_impl---------------------------
bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_new ) {
+ // Compute exact loop trip count if possible.
+ compute_exact_trip_count(phase);
+
+ // Convert one iteration loop into normal code.
+ if (policy_do_one_iteration_loop(phase))
+ return true;
+
// Check and remove empty loops (spam micro-benchmarks)
- if( policy_do_remove_empty_loop(phase) )
+ if (policy_do_remove_empty_loop(phase))
return true; // Here we removed an empty loop
bool should_peel = policy_peeling(phase); // Should we peel?
@@ -1716,40 +1934,40 @@ bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_
// Non-counted loops may be peeled; exactly 1 iteration is peeled.
// This removes loop-invariant tests (usually null checks).
- if( !_head->is_CountedLoop() ) { // Non-counted loop
+ if (!_head->is_CountedLoop()) { // Non-counted loop
if (PartialPeelLoop && phase->partial_peel(this, old_new)) {
// Partial peel succeeded so terminate this round of loop opts
return false;
}
- if( should_peel ) { // Should we peel?
+ if (should_peel) { // Should we peel?
#ifndef PRODUCT
if (PrintOpto) tty->print_cr("should_peel");
#endif
phase->do_peeling(this,old_new);
- } else if( should_unswitch ) {
+ } else if (should_unswitch) {
phase->do_unswitching(this, old_new);
}
return true;
}
CountedLoopNode *cl = _head->as_CountedLoop();
- if( !cl->loopexit() ) return true; // Ignore various kinds of broken loops
+ if (!cl->loopexit()) return true; // Ignore various kinds of broken loops
// Do nothing special to pre- and post- loops
- if( cl->is_pre_loop() || cl->is_post_loop() ) return true;
+ if (cl->is_pre_loop() || cl->is_post_loop()) return true;
// Compute loop trip count from profile data
compute_profile_trip_cnt(phase);
// Before attempting fancy unrolling, RCE or alignment, see if we want
// to completely unroll this loop or do loop unswitching.
- if( cl->is_normal_loop() ) {
+ if (cl->is_normal_loop()) {
if (should_unswitch) {
phase->do_unswitching(this, old_new);
return true;
}
bool should_maximally_unroll = policy_maximally_unroll(phase);
- if( should_maximally_unroll ) {
+ if (should_maximally_unroll) {
// Here we did some unrolling and peeling. Eventually we will
// completely unroll this loop and it will no longer be a loop.
phase->do_maximally_unroll(this,old_new);
@@ -1757,6 +1975,12 @@ bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_
}
}
+ // Skip next optimizations if running low on nodes. Note that
+ // policy_unswitching and policy_maximally_unroll have this check.
+ uint nodes_left = MaxNodeLimit - phase->C->unique();
+ if ((2 * _body.size()) > nodes_left) {
+ return true;
+ }
// Counted loops may be peeled, may need some iterations run up
// front for RCE, and may want to align loop refs to a cache
@@ -1787,14 +2011,14 @@ bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_
// If we have any of these conditions (RCE, alignment, unrolling) met, then
// we switch to the pre-/main-/post-loop model. This model also covers
// peeling.
- if( should_rce || should_align || should_unroll ) {
- if( cl->is_normal_loop() ) // Convert to 'pre/main/post' loops
+ if (should_rce || should_align || should_unroll) {
+ if (cl->is_normal_loop()) // Convert to 'pre/main/post' loops
phase->insert_pre_post_loops(this,old_new, !may_rce_align);
// Adjust the pre- and main-loop limits to let the pre and post loops run
// with full checks, but the main-loop with no checks. Remove said
// checks from the main body.
- if( should_rce )
+ if (should_rce)
phase->do_range_check(this,old_new);
// Double loop body for unrolling. Adjust the minimum-trip test (will do
@@ -1802,16 +2026,16 @@ bool IdealLoopTree::iteration_split_impl( PhaseIdealLoop *phase, Node_List &old_
// an even number of trips). If we are peeling, we might enable some RCE
// and we'd rather unroll the post-RCE'd loop SO... do not unroll if
// peeling.
- if( should_unroll && !should_peel )
- phase->do_unroll(this,old_new, true);
+ if (should_unroll && !should_peel)
+ phase->do_unroll(this,old_new, true);
// Adjust the pre-loop limits to align the main body
// iterations.
- if( should_align )
+ if (should_align)
Unimplemented();
} else { // Else we have an unchanged counted loop
- if( should_peel ) // Might want to peel but do nothing else
+ if (should_peel) // Might want to peel but do nothing else
phase->do_peeling(this,old_new);
}
return true;
@@ -1861,651 +2085,8 @@ bool IdealLoopTree::iteration_split( PhaseIdealLoop *phase, Node_List &old_new )
return true;
}
-//-------------------------------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 || out->is_Root() || out->is_Start())
- 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
- }
- }
- 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();
- return is_uncommon_trap_proj(other_proj, reason);
-}
-
-//-------------------------------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");
-
- 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));
- }
- }
-
- 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 = new (C, 2) IfNode(entry, NULL, iff->_prob, iff->_fcnt);
- 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));
- }
- // rgn must have no phis
- assert(!rgn->as_Region()->has_phi(), "region must have no phis");
-
- 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();
-}
-
-//--------------------------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;
-}
-
+//=============================================================================
// Process all the loops in the loop tree and replace any fill
// patterns with an intrisc version.
bool PhaseIdealLoop::do_intrinsify_fill() {
@@ -2625,9 +2206,12 @@ bool PhaseIdealLoop::match_fill_loop(IdealLoopTree* lpt, Node*& store, Node*& st
if (value != head->phi()) {
msg = "unhandled shift in address";
} else {
- found_index = true;
- shift = n;
- assert(type2aelembytes(store->as_Mem()->memory_type(), true) == 1 << shift->in(2)->get_int(), "scale should match");
+ if (type2aelembytes(store->as_Mem()->memory_type(), true) != (1 << n->in(2)->get_int())) {
+ msg = "scale doesn't match";
+ } else {
+ found_index = true;
+ shift = n;
+ }
}
} else if (n->Opcode() == Op_ConvI2L && conv == NULL) {
if (n->in(1) == head->phi()) {
@@ -2762,6 +2346,13 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) {
return false;
}
+#ifndef PRODUCT
+ if (TraceLoopOpts) {
+ tty->print("ArrayFill ");
+ lpt->dump_head();
+ }
+#endif
+
// Now replace the whole loop body by a call to a fill routine that
// covers the same region as the loop.
Node* base = store->in(MemNode::Address)->as_AddP()->in(AddPNode::Base);
diff --git a/src/share/vm/opto/loopUnswitch.cpp b/src/share/vm/opto/loopUnswitch.cpp
index 544b845f8..8a103b228 100644
--- a/src/share/vm/opto/loopUnswitch.cpp
+++ b/src/share/vm/opto/loopUnswitch.cpp
@@ -32,15 +32,17 @@
//
// orig: transformed:
// if (invariant-test) then
+// predicate predicate
// loop loop
// stmt1 stmt1
// if (invariant-test) then stmt2
// stmt2 stmt4
// else endloop
// stmt3 else
-// endif loop [clone]
-// stmt4 stmt1 [clone]
-// endloop stmt3
+// endif predicate [clone]
+// stmt4 loop [clone]
+// endloop stmt1 [clone]
+// stmt3
// stmt4 [clone]
// endloop
// endif
@@ -124,8 +126,15 @@ void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) {
ProjNode* proj_true = create_slow_version_of_loop(loop, old_new);
- assert(proj_true->is_IfTrue() && proj_true->unique_ctrl_out() == head, "by construction");
-
+#ifdef ASSERT
+ Node* uniqc = proj_true->unique_ctrl_out();
+ Node* entry = head->in(LoopNode::EntryControl);
+ Node* predicate = find_predicate(entry);
+ if (predicate != NULL) predicate = predicate->in(0);
+ assert(proj_true->is_IfTrue() &&
+ (predicate == NULL && uniqc == head ||
+ predicate != NULL && uniqc == predicate), "by construction");
+#endif
// Increment unswitch count
LoopNode* head_clone = old_new[head->_idx]->as_Loop();
int nct = head->unswitch_count() + 1;
@@ -227,21 +236,24 @@ ProjNode* PhaseIdealLoop::create_slow_version_of_loop(IdealLoopTree *loop,
register_node(ifslow, outer_loop, iff, dom_depth(iff));
// Clone the loop body. The clone becomes the fast loop. The
- // original pre-header will (illegally) have 2 control users (old & new loops).
+ // original pre-header will (illegally) have 3 control users
+ // (old & new loops & new if).
clone_loop(loop, old_new, dom_depth(head), iff);
assert(old_new[head->_idx]->is_Loop(), "" );
// Fast (true) control
+ Node* iffast_pred = clone_loop_predicates(entry, iffast);
_igvn.hash_delete(head);
- head->set_req(LoopNode::EntryControl, iffast);
- set_idom(head, iffast, dom_depth(head));
+ head->set_req(LoopNode::EntryControl, iffast_pred);
+ set_idom(head, iffast_pred, dom_depth(head));
_igvn._worklist.push(head);
// Slow (false) control
+ Node* ifslow_pred = move_loop_predicates(entry, ifslow);
LoopNode* slow_head = old_new[head->_idx]->as_Loop();
_igvn.hash_delete(slow_head);
- slow_head->set_req(LoopNode::EntryControl, ifslow);
- set_idom(slow_head, ifslow, dom_depth(slow_head));
+ slow_head->set_req(LoopNode::EntryControl, ifslow_pred);
+ set_idom(slow_head, ifslow_pred, dom_depth(slow_head));
_igvn._worklist.push(slow_head);
recompute_dom_depth();
diff --git a/src/share/vm/opto/loopnode.cpp b/src/share/vm/opto/loopnode.cpp
index 894a105e8..cd6948712 100644
--- a/src/share/vm/opto/loopnode.cpp
+++ b/src/share/vm/opto/loopnode.cpp
@@ -341,7 +341,12 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
//
assert(x->Opcode() == Op_Loop, "regular loops only");
C->print_method("Before CountedLoop", 3);
-
+#ifndef PRODUCT
+ if (TraceLoopOpts) {
+ tty->print("Counted ");
+ loop->dump_head();
+ }
+#endif
// If compare points to incr, we are ok. Otherwise the compare
// can directly point to the phi; in this case adjust the compare so that
// it points to the incr by adjusting the limit.
@@ -864,8 +869,10 @@ void IdealLoopTree::split_outer_loop( PhaseIdealLoop *phase ) {
Node *outer = new (phase->C, 3) LoopNode( ctl, _head->in(outer_idx) );
outer = igvn.register_new_node_with_optimizer(outer, _head);
phase->set_created_loop_node();
+
+ Node* pred = phase->clone_loop_predicates(ctl, outer);
// Outermost loop falls into '_head' loop
- _head->set_req(LoopNode::EntryControl, outer);
+ _head->set_req(LoopNode::EntryControl, pred);
_head->del_req(outer_idx);
// Split all the Phis up between '_head' loop and 'outer' loop.
for (DUIterator_Fast jmax, j = _head->fast_outs(jmax); j < jmax; j++) {
@@ -1103,12 +1110,13 @@ bool IdealLoopTree::beautify_loops( PhaseIdealLoop *phase ) {
// backedges into a private merge point and use the merge point as
// the one true backedge.
if( _head->req() > 3 ) {
- // Merge the many backedges into a single backedge.
+ // Merge the many backedges into a single backedge but leave
+ // the hottest backedge as separate edge for the following peel.
merge_many_backedges( phase );
result = true;
}
- // If I am a shared header (multiple backedges), peel off myself loop.
+ // If I have one hot backedge, peel off myself loop.
// I better be the outermost loop.
if( _head->req() > 3 ) {
split_outer_loop( phase );
@@ -1433,15 +1441,30 @@ void IdealLoopTree::dump_head( ) const {
tty->print("Loop: N%d/N%d ",_head->_idx,_tail->_idx);
if (_irreducible) tty->print(" IRREDUCIBLE");
if (UseLoopPredicate) {
- Node* entry = _head->in(LoopNode::EntryControl);
- if (entry != NULL && entry->is_Proj() &&
- PhaseIdealLoop::is_uncommon_trap_if_pattern(entry->as_Proj(), Deoptimization::Reason_predicate)) {
+ Node* entry = PhaseIdealLoop::find_predicate_insertion_point(_head->in(LoopNode::EntryControl),
+ Deoptimization::Reason_predicate);
+ if (entry != NULL) {
tty->print(" predicated");
}
}
if (_head->is_CountedLoop()) {
CountedLoopNode *cl = _head->as_CountedLoop();
tty->print(" counted");
+
+ Node* init_n = cl->init_trip();
+ if (init_n != NULL && init_n->is_Con())
+ tty->print(" [%d,", cl->init_trip()->get_int());
+ else
+ tty->print(" [int,");
+ Node* limit_n = cl->limit();
+ if (limit_n != NULL && limit_n->is_Con())
+ tty->print("%d),", cl->limit()->get_int());
+ else
+ tty->print("int),");
+ int stride_con = cl->stride_con();
+ if (stride_con > 0) tty->print("+");
+ tty->print("%d", stride_con);
+
if (cl->is_pre_loop ()) tty->print(" pre" );
if (cl->is_main_loop()) tty->print(" main");
if (cl->is_post_loop()) tty->print(" post");
@@ -1541,7 +1564,7 @@ void PhaseIdealLoop::eliminate_useless_predicates() {
//----------------------------build_and_optimize-------------------------------
// Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to
// its corresponding LoopNode. If 'optimize' is true, do some loop cleanups.
-void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
+void PhaseIdealLoop::build_and_optimize(bool do_split_ifs) {
ResourceMark rm;
int old_progress = C->major_progress();
@@ -1573,6 +1596,13 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
// Do not need a safepoint at the top level
_ltree_root->_has_sfpt = 1;
+ // Initialize Dominators.
+ // Checked in clone_loop_predicate() during beautify_loops().
+ _idom_size = 0;
+ _idom = NULL;
+ _dom_depth = NULL;
+ _dom_stk = NULL;
+
// Empty pre-order array
allocate_preorders();
@@ -1698,8 +1728,9 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
return;
}
- // some parser-inserted loop predicates could never be used by loop
- // predication. Eliminate them before loop optimization
+ // Some parser-inserted loop predicates could never be used by loop
+ // predication or they were moved away from loop during some optimizations.
+ // For example, peeling. Eliminate them before next loop optimizations.
if (UseLoopPredicate) {
eliminate_useless_predicates();
}
@@ -1750,7 +1781,7 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
}
// Perform loop predication before iteration splitting
- if (do_loop_pred && C->has_loops() && !C->major_progress()) {
+ if (C->has_loops() && !C->major_progress() && (C->predicate_count() > 0)) {
_ltree_root->_child->loop_predication(this);
}
@@ -1793,8 +1824,20 @@ void PhaseIdealLoop::build_and_optimize(bool do_split_ifs, bool do_loop_pred) {
C->set_major_progress();
}
- // Convert scalar to superword operations
+ // Keep loop predicates and perform optimizations with them
+ // until no more loop optimizations could be done.
+ // After that switch predicates off and do more loop optimizations.
+ if (!C->major_progress() && (C->predicate_count() > 0)) {
+ C->cleanup_loop_predicates(_igvn);
+#ifndef PRODUCT
+ if (TraceLoopOpts) {
+ tty->print_cr("PredicatesOff");
+ }
+#endif
+ C->set_major_progress();
+ }
+ // Convert scalar to superword operations at the end of all loop opts.
if (UseSuperWord && C->has_loops() && !C->major_progress()) {
// SuperWord transform
SuperWord sw(this);
diff --git a/src/share/vm/opto/loopnode.hpp b/src/share/vm/opto/loopnode.hpp
index 9edcdf292..2b6ea369a 100644
--- a/src/share/vm/opto/loopnode.hpp
+++ b/src/share/vm/opto/loopnode.hpp
@@ -57,7 +57,12 @@ class LoopNode : public RegionNode {
protected:
short _loop_flags;
// Names for flag bitfields
- enum { pre_post_main=0, inner_loop=8, partial_peel_loop=16, partial_peel_failed=32 };
+ enum { Normal=0, Pre=1, Main=2, Post=3, PreMainPostFlagsMask=3,
+ MainHasNoPreLoop=4,
+ HasExactTripCount=8,
+ InnerLoop=16,
+ PartialPeelLoop=32,
+ PartialPeelFailed=64 };
char _unswitch_count;
enum { _unswitch_max=3 };
@@ -65,13 +70,13 @@ public:
// Names for edge indices
enum { Self=0, EntryControl, LoopBackControl };
- int is_inner_loop() const { return _loop_flags & inner_loop; }
- void set_inner_loop() { _loop_flags |= inner_loop; }
+ int is_inner_loop() const { return _loop_flags & InnerLoop; }
+ void set_inner_loop() { _loop_flags |= InnerLoop; }
- int is_partial_peel_loop() const { return _loop_flags & partial_peel_loop; }
- void set_partial_peel_loop() { _loop_flags |= partial_peel_loop; }
- int partial_peel_has_failed() const { return _loop_flags & partial_peel_failed; }
- void mark_partial_peel_failed() { _loop_flags |= partial_peel_failed; }
+ int is_partial_peel_loop() const { return _loop_flags & PartialPeelLoop; }
+ void set_partial_peel_loop() { _loop_flags |= PartialPeelLoop; }
+ int partial_peel_has_failed() const { return _loop_flags & PartialPeelFailed; }
+ void mark_partial_peel_failed() { _loop_flags |= PartialPeelFailed; }
int unswitch_max() { return _unswitch_max; }
int unswitch_count() { return _unswitch_count; }
@@ -137,8 +142,8 @@ class CountedLoopNode : public LoopNode {
// the Main CountedLoop. Used to assert that we understand the graph shape.
node_idx_t _main_idx;
- // Known trip count calculated by policy_maximally_unroll
- int _trip_count;
+ // Known trip count calculated by compute_exact_trip_count()
+ uint _trip_count;
// Expected trip count from profile data
float _profile_trip_cnt;
@@ -152,7 +157,7 @@ class CountedLoopNode : public LoopNode {
public:
CountedLoopNode( Node *entry, Node *backedge )
- : LoopNode(entry, backedge), _trip_count(max_jint),
+ : LoopNode(entry, backedge), _main_idx(0), _trip_count(max_juint),
_profile_trip_cnt(COUNT_UNKNOWN), _unrolled_count_log2(0),
_node_count_before_unroll(0) {
init_class_id(Class_CountedLoop);
@@ -194,13 +199,12 @@ public:
// A 'main' loop that is ONLY unrolled or peeled, never RCE'd or
// Aligned, may be missing it's pre-loop.
- enum { Normal=0, Pre=1, Main=2, Post=3, PrePostFlagsMask=3, Main_Has_No_Pre_Loop=4 };
- int is_normal_loop() const { return (_loop_flags&PrePostFlagsMask) == Normal; }
- int is_pre_loop () const { return (_loop_flags&PrePostFlagsMask) == Pre; }
- int is_main_loop () const { return (_loop_flags&PrePostFlagsMask) == Main; }
- int is_post_loop () const { return (_loop_flags&PrePostFlagsMask) == Post; }
- int is_main_no_pre_loop() const { return _loop_flags & Main_Has_No_Pre_Loop; }
- void set_main_no_pre_loop() { _loop_flags |= Main_Has_No_Pre_Loop; }
+ int is_normal_loop() const { return (_loop_flags&PreMainPostFlagsMask) == Normal; }
+ int is_pre_loop () const { return (_loop_flags&PreMainPostFlagsMask) == Pre; }
+ int is_main_loop () const { return (_loop_flags&PreMainPostFlagsMask) == Main; }
+ int is_post_loop () const { return (_loop_flags&PreMainPostFlagsMask) == Post; }
+ int is_main_no_pre_loop() const { return _loop_flags & MainHasNoPreLoop; }
+ void set_main_no_pre_loop() { _loop_flags |= MainHasNoPreLoop; }
int main_idx() const { return _main_idx; }
@@ -208,10 +212,19 @@ public:
void set_pre_loop (CountedLoopNode *main) { assert(is_normal_loop(),""); _loop_flags |= Pre ; _main_idx = main->_idx; }
void set_main_loop ( ) { assert(is_normal_loop(),""); _loop_flags |= Main; }
void set_post_loop (CountedLoopNode *main) { assert(is_normal_loop(),""); _loop_flags |= Post; _main_idx = main->_idx; }
- void set_normal_loop( ) { _loop_flags &= ~PrePostFlagsMask; }
+ void set_normal_loop( ) { _loop_flags &= ~PreMainPostFlagsMask; }
- void set_trip_count(int tc) { _trip_count = tc; }
- int trip_count() { return _trip_count; }
+ void set_trip_count(uint tc) { _trip_count = tc; }
+ uint trip_count() { return _trip_count; }
+
+ bool has_exact_trip_count() const { return (_loop_flags & HasExactTripCount) != 0; }
+ void set_exact_trip_count(uint tc) {
+ _trip_count = tc;
+ _loop_flags |= HasExactTripCount;
+ }
+ void set_nonexact_trip_count() {
+ _loop_flags &= ~HasExactTripCount;
+ }
void set_profile_trip_cnt(float ptc) { _profile_trip_cnt = ptc; }
float profile_trip_cnt() { return _profile_trip_cnt; }
@@ -384,6 +397,9 @@ public:
// Micro-benchmark spamming. Remove empty loops.
bool policy_do_remove_empty_loop( PhaseIdealLoop *phase );
+ // Convert one iteration loop into normal code.
+ bool policy_do_one_iteration_loop( PhaseIdealLoop *phase );
+
// Return TRUE or FALSE if the loop should be peeled or not. Peel if we can
// make some loop-invariant test (usually a null-check) happen before the
// loop.
@@ -412,6 +428,9 @@ public:
// Return TRUE if "iff" is a range check.
bool is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const;
+ // Compute loop exact trip count if possible
+ void compute_exact_trip_count( PhaseIdealLoop *phase );
+
// Compute loop trip count from profile data
void compute_profile_trip_cnt( PhaseIdealLoop *phase );
@@ -706,11 +725,11 @@ private:
_dom_lca_tags(arena()), // Thread::resource_area
_verify_me(NULL),
_verify_only(true) {
- build_and_optimize(false, false);
+ build_and_optimize(false);
}
// build the loop tree and perform any requested optimizations
- void build_and_optimize(bool do_split_if, bool do_loop_pred);
+ void build_and_optimize(bool do_split_if);
public:
// Dominators for the sea of nodes
@@ -721,13 +740,13 @@ public:
Node *dom_lca_internal( Node *n1, Node *n2 ) const;
// Compute the Ideal Node to Loop mapping
- PhaseIdealLoop( PhaseIterGVN &igvn, bool do_split_ifs, bool do_loop_pred) :
+ PhaseIdealLoop( PhaseIterGVN &igvn, bool do_split_ifs) :
PhaseTransform(Ideal_Loop),
_igvn(igvn),
_dom_lca_tags(arena()), // Thread::resource_area
_verify_me(NULL),
_verify_only(false) {
- build_and_optimize(do_split_ifs, do_loop_pred);
+ build_and_optimize(do_split_ifs);
}
// Verify that verify_me made the same decisions as a fresh run.
@@ -737,7 +756,7 @@ public:
_dom_lca_tags(arena()), // Thread::resource_area
_verify_me(verify_me),
_verify_only(false) {
- build_and_optimize(false, false);
+ build_and_optimize(false);
}
// Build and verify the loop tree without modifying the graph. This
@@ -830,7 +849,26 @@ public:
Deoptimization::DeoptReason reason);
void register_control(Node* n, IdealLoopTree *loop, Node* pred);
- // Find a good location to insert a predicate
+ // Clone loop predicates to cloned loops (peeled, unswitched)
+ static ProjNode* clone_predicate(ProjNode* predicate_proj, Node* new_entry,
+ Deoptimization::DeoptReason reason,
+ PhaseIdealLoop* loop_phase,
+ PhaseIterGVN* igvn);
+ static ProjNode* move_predicate(ProjNode* predicate_proj, Node* new_entry,
+ Deoptimization::DeoptReason reason,
+ PhaseIdealLoop* loop_phase,
+ PhaseIterGVN* igvn);
+ static Node* clone_loop_predicates(Node* old_entry, Node* new_entry,
+ bool move_predicates,
+ PhaseIdealLoop* loop_phase,
+ PhaseIterGVN* igvn);
+ Node* clone_loop_predicates(Node* old_entry, Node* new_entry);
+ Node* move_loop_predicates(Node* old_entry, Node* new_entry);
+
+ void eliminate_loop_predicates(Node* entry);
+ static Node* skip_loop_predicates(Node* entry);
+
+ // Find a good location to insert a predicate
static ProjNode* find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason);
// Find a predicate
static Node* find_predicate(Node* entry);
diff --git a/src/share/vm/opto/loopopts.cpp b/src/share/vm/opto/loopopts.cpp
index 831c6cb6e..1be374206 100644
--- a/src/share/vm/opto/loopopts.cpp
+++ b/src/share/vm/opto/loopopts.cpp
@@ -2139,9 +2139,12 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
//
// orig
//
-// stmt1
-// |
-// v
+// stmt1
+// |
+// v
+// loop predicate
+// |
+// v
// loop<----+
// | |
// stmt2 |
@@ -2172,6 +2175,9 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
// after clone loop
//
// stmt1
+// |
+// v
+// loop predicate
// / \
// clone / \ orig
// / \
@@ -2210,12 +2216,15 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
// after partial peel
//
// stmt1
+// |
+// v
+// loop predicate
// /
// clone / orig
// / TOP
// / \
// v v
-// TOP->region region----+
+// TOP->loop loop----+
// | | |
// stmt2 stmt2 |
// | | |
@@ -2253,13 +2262,17 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
// stmt1
// |
// v
+// stmt2 clone
+// |
+// v
// ........> ifA clone
// : / |
// dom / |
// : v v
// : false true
// : | |
-// : | stmt2 clone
+// : | v
+// : | loop predicate
// : | |
// : | v
// : | newloop<-----+
@@ -2289,6 +2302,7 @@ bool PhaseIdealLoop::is_valid_clone_loop_form( IdealLoopTree *loop, Node_List& p
//
bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
+ assert(!loop->_head->is_CountedLoop(), "Non-counted loop only");
if (!loop->_head->is_Loop()) {
return false; }
@@ -2316,6 +2330,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
}
}
+ Node* entry = head->in(LoopNode::EntryControl);
int dd = dom_depth(head);
// Step 1: find cut point
@@ -2612,6 +2627,8 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
// Backedge of the surviving new_head (the clone) is original last_peel
_igvn.hash_delete(new_head_clone);
+ Node* new_entry = move_loop_predicates(entry, new_head_clone->in(LoopNode::EntryControl));
+ new_head_clone->set_req(LoopNode::EntryControl, new_entry);
new_head_clone->set_req(LoopNode::LoopBackControl, last_peel);
_igvn._worklist.push(new_head_clone);
diff --git a/src/share/vm/opto/phaseX.hpp b/src/share/vm/opto/phaseX.hpp
index 7f1060c05..4d19708ed 100644
--- a/src/share/vm/opto/phaseX.hpp
+++ b/src/share/vm/opto/phaseX.hpp
@@ -471,6 +471,13 @@ public:
_delay_transform = delay;
}
+ // Clone loop predicates. Defined in loopTransform.cpp.
+ Node* clone_loop_predicates(Node* old_entry, Node* new_entry);
+ Node* move_loop_predicates(Node* old_entry, Node* new_entry);
+ // Create a new if below new_entry for the predicate to be cloned
+ ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
+ Deoptimization::DeoptReason reason);
+
#ifndef PRODUCT
protected:
// Sub-quadratic implementation of VerifyIterativeGVN.
diff --git a/src/share/vm/opto/split_if.cpp b/src/share/vm/opto/split_if.cpp
index 91792368f..dba6ed1f2 100644
--- a/src/share/vm/opto/split_if.cpp
+++ b/src/share/vm/opto/split_if.cpp
@@ -399,6 +399,9 @@ void PhaseIdealLoop::do_split_if( Node *iff ) {
#ifndef PRODUCT
if( PrintOpto && VerifyLoopOptimizations )
tty->print_cr("Split-if");
+ if (TraceLoopOpts) {
+ tty->print_cr("SplitIf");
+ }
#endif
C->set_major_progress();
Node *region = iff->in(0);
diff --git a/src/share/vm/opto/superword.cpp b/src/share/vm/opto/superword.cpp
index 1230ebe51..6e1be24dd 100644
--- a/src/share/vm/opto/superword.cpp
+++ b/src/share/vm/opto/superword.cpp
@@ -1132,6 +1132,13 @@ void SuperWord::co_locate_pack(Node_List* pk) {
void SuperWord::output() {
if (_packset.length() == 0) return;
+#ifndef PRODUCT
+ if (TraceLoopOpts) {
+ tty->print("SuperWord ");
+ lpt()->dump_head();
+ }
+#endif
+
// MUST ENSURE main loop's initial value is properly aligned:
// (iv_initial_value + min_iv_offset) % vector_width_in_bytes() == 0
diff --git a/src/share/vm/opto/vectornode.hpp b/src/share/vm/opto/vectornode.hpp
index b4915ddfd..4d28703c8 100644
--- a/src/share/vm/opto/vectornode.hpp
+++ b/src/share/vm/opto/vectornode.hpp
@@ -32,6 +32,7 @@
//------------------------------VectorNode--------------------------------------
// Vector Operation
class VectorNode : public Node {
+ virtual uint size_of() const { return sizeof(*this); }
protected:
uint _length; // vector length
virtual BasicType elt_basic_type() const = 0; // Vector element basic type
diff --git a/src/share/vm/prims/jvm.h b/src/share/vm/prims/jvm.h
index 07097af3c..f37d83342 100644
--- a/src/share/vm/prims/jvm.h
+++ b/src/share/vm/prims/jvm.h
@@ -1062,7 +1062,7 @@ enum {
JVM_CONSTANT_NameAndType,
JVM_CONSTANT_MethodHandle = 15, // JSR 292
JVM_CONSTANT_MethodType = 16, // JSR 292
- JVM_CONSTANT_InvokeDynamicTrans = 17, // JSR 292, only occurs in old class files
+ //JVM_CONSTANT_(unused) = 17, // JSR 292 early drafts only
JVM_CONSTANT_InvokeDynamic = 18, // JSR 292
JVM_CONSTANT_ExternalMax = 18 // Last tag found in classfiles
};
diff --git a/src/share/vm/prims/jvmtiManageCapabilities.cpp b/src/share/vm/prims/jvmtiManageCapabilities.cpp
index cca51ef2b..cd18199aa 100644
--- a/src/share/vm/prims/jvmtiManageCapabilities.cpp
+++ b/src/share/vm/prims/jvmtiManageCapabilities.cpp
@@ -319,8 +319,11 @@ void JvmtiManageCapabilities::update() {
bool enter_all_methods =
interp_events ||
avail.can_generate_breakpoint_events;
- UseFastEmptyMethods = !enter_all_methods;
- UseFastAccessorMethods = !enter_all_methods;
+ if (enter_all_methods) {
+ // Disable these when tracking the bytecodes
+ UseFastEmptyMethods = false;
+ UseFastAccessorMethods = false;
+ }
if (avail.can_generate_breakpoint_events) {
RewriteFrequentPairs = false;
diff --git a/src/share/vm/prims/methodHandleWalk.cpp b/src/share/vm/prims/methodHandleWalk.cpp
index 915cf3599..3570d2db4 100644
--- a/src/share/vm/prims/methodHandleWalk.cpp
+++ b/src/share/vm/prims/methodHandleWalk.cpp
@@ -959,12 +959,6 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
if (m == NULL) {
// Get the intrinsic methodOop.
m = vmIntrinsics::method_for(iid);
- if (m == NULL && iid == vmIntrinsics::_checkSpreadArgument && AllowTransitionalJSR292) {
- m = vmIntrinsics::method_for(vmIntrinsics::_checkSpreadArgument_TRANS);
- if (m == NULL)
- // sun.dyn.MethodHandleImpl not found, look for java.dyn.MethodHandleNatives:
- m = vmIntrinsics::method_for(vmIntrinsics::_checkSpreadArgument_TRANS2);
- }
if (m == NULL) {
ArgToken zero;
lose(vmIntrinsics::name_at(iid), CHECK_(zero));
diff --git a/src/share/vm/prims/methodHandles.cpp b/src/share/vm/prims/methodHandles.cpp
index 2aae1f7f3..e882c8562 100644
--- a/src/share/vm/prims/methodHandles.cpp
+++ b/src/share/vm/prims/methodHandles.cpp
@@ -2488,74 +2488,21 @@ JVM_ENTRY(jint, MHN_getMembers(JNIEnv *env, jobject igcls,
}
JVM_END
-JVM_ENTRY(void, MHN_registerBootstrap(JNIEnv *env, jobject igcls, jclass caller_jh, jobject bsm_jh)) {
- instanceKlassHandle ik = MethodHandles::resolve_instance_klass(caller_jh, THREAD);
- if (!AllowTransitionalJSR292) {
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
- "registerBootstrapMethod is only supported in JSR 292 EDR");
- }
- ik->link_class(CHECK);
- if (!java_lang_invoke_MethodHandle::is_instance(JNIHandles::resolve(bsm_jh))) {
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "method handle");
- }
- const char* err = NULL;
- if (ik->is_initialized() || ik->is_in_error_state()) {
- err = "too late: class is already initialized";
- } else {
- ObjectLocker ol(ik, THREAD); // note: this should be a recursive lock
- if (ik->is_not_initialized() ||
- (ik->is_being_initialized() && ik->is_reentrant_initialization(THREAD))) {
- if (ik->bootstrap_method() != NULL) {
- err = "class is already equipped with a bootstrap method";
- } else {
- ik->set_bootstrap_method(JNIHandles::resolve_non_null(bsm_jh));
- err = NULL;
- }
- } else {
- err = "class is already initialized";
- if (ik->is_being_initialized())
- err = "class is already being initialized in a different thread";
- }
- }
- if (err != NULL) {
- THROW_MSG(vmSymbols::java_lang_IllegalStateException(), err);
- }
-}
-JVM_END
-
-JVM_ENTRY(jobject, MHN_getBootstrap(JNIEnv *env, jobject igcls, jclass caller_jh)) {
- if (!AllowTransitionalJSR292)
- THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "getBootstrap: transitional only");
- instanceKlassHandle ik = MethodHandles::resolve_instance_klass(caller_jh, THREAD);
- return JNIHandles::make_local(THREAD, ik->bootstrap_method());
-}
-JVM_END
-
-JVM_ENTRY(void, MHN_setCallSiteTarget(JNIEnv *env, jobject igcls, jobject site_jh, jobject target_jh)) {
- if (!AllowTransitionalJSR292)
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "setCallSite: transitional only");
-}
-JVM_END
-
/// JVM_RegisterMethodHandleMethods
#define LANG "Ljava/lang/"
-#define JLINV "Ljava/lang/invoke/" /* standard package */
-#define JDYN "Ljava/dyn/" /* alternative package to JLINV if AllowTransitionalJSR292 */
-#define IDYN "Lsun/dyn/" /* alternative package to JDYN if AllowTransitionalJSR292 */
-// FIXME: After AllowTransitionalJSR292 is removed, replace JDYN and IDYN by JLINV.
+#define JLINV "Ljava/lang/invoke/"
#define OBJ LANG"Object;"
#define CLS LANG"Class;"
#define STRG LANG"String;"
-#define CST JDYN"CallSite;"
-#define MT JDYN"MethodType;"
-#define MH JDYN"MethodHandle;"
-#define MEM IDYN"MemberName;"
-#define AMH IDYN"AdapterMethodHandle;"
-#define BMH IDYN"BoundMethodHandle;"
-#define DMH IDYN"DirectMethodHandle;"
+#define MT JLINV"MethodType;"
+#define MH JLINV"MethodHandle;"
+#define MEM JLINV"MemberName;"
+#define AMH JLINV"AdapterMethodHandle;"
+#define BMH JLINV"BoundMethodHandle;"
+#define DMH JLINV"DirectMethodHandle;"
#define CC (char*) /*cast a literal from (const char*)*/
#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
@@ -2579,39 +2526,6 @@ static JNINativeMethod methods[] = {
{CC"getMembers", CC"("CLS""STRG""STRG"I"CLS"I["MEM")I", FN_PTR(MHN_getMembers)}
};
-// FIXME: Remove methods2 after AllowTransitionalJSR292 is removed.
-static JNINativeMethod methods2[] = {
- {CC"registerBootstrap", CC"("CLS MH")V", FN_PTR(MHN_registerBootstrap)},
- {CC"getBootstrap", CC"("CLS")"MH, FN_PTR(MHN_getBootstrap)},
- {CC"setCallSiteTarget", CC"("CST MH")V", FN_PTR(MHN_setCallSiteTarget)}
-};
-
-static void hack_signatures(JNINativeMethod* methods, jint num_methods, const char* from_sig, const char* to_sig) {
- for (int i = 0; i < num_methods; i++) {
- const char* sig = methods[i].signature;
- if (!strstr(sig, from_sig)) continue;
- size_t buflen = strlen(sig) + 100;
- char* buf = NEW_C_HEAP_ARRAY(char, buflen);
- char* bufp = buf;
- const char* sigp = sig;
- size_t from_len = strlen(from_sig), to_len = strlen(to_sig);
- while (*sigp != '\0') {
- assert(bufp < buf + buflen - to_len - 1, "oob");
- if (strncmp(sigp, from_sig, from_len) != 0) {
- *bufp++ = *sigp++;
- } else {
- strcpy(bufp, to_sig);
- bufp += to_len;
- sigp += from_len;
- }
- }
- *bufp = '\0';
- methods[i].signature = buf; // replace with new signature
- if (TraceMethodHandles)
- tty->print_cr("MethodHandleNatives: %s: change signature %s => %s", methods[i].name, sig, buf);
- }
-}
-
// This one function is exported, used by NativeLookup.
JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) {
@@ -2622,92 +2536,41 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class))
return; // bind nothing
}
- if (SystemDictionary::MethodHandleNatives_klass() != NULL &&
- SystemDictionary::MethodHandleNatives_klass() != java_lang_Class::as_klassOop(JNIHandles::resolve(MHN_class))) {
- warning("multiple versions of MethodHandleNatives in boot classpath; consider using -XX:+PreferTransitionalJSR292");
- THROW_MSG(vmSymbols::java_lang_InternalError(), "multiple versions of MethodHandleNatives in boot classpath; consider using -XX:+PreferTransitionalJSR292");
- }
-
bool enable_MH = true;
- // Loop control. FIXME: Replace by dead reckoning after AllowTransitionalJSR292 is removed.
- bool registered_natives = false;
- bool try_plain = true, try_JDYN = true, try_IDYN = true;
- for (;;) {
+ {
ThreadToNativeFromVM ttnfv(thread);
- if (try_plain) { try_plain = false; }
- else if (try_JDYN) { try_JDYN = false; hack_signatures(methods, sizeof(methods)/sizeof(JNINativeMethod), IDYN, JDYN); }
- else if (try_IDYN) { try_IDYN = false; hack_signatures(methods, sizeof(methods)/sizeof(JNINativeMethod), JDYN, JLINV); }
- else { break; }
int status = env->RegisterNatives(MHN_class, methods, sizeof(methods)/sizeof(JNINativeMethod));
if (env->ExceptionOccurred()) {
+ MethodHandles::set_enabled(false);
+ warning("JSR 292 method handle code is mismatched to this JVM. Disabling support.");
+ enable_MH = false;
env->ExceptionClear();
- // and try again...
- } else {
- registered_natives = true;
- break;
}
}
- if (!registered_natives) {
- MethodHandles::set_enabled(false);
- warning("JSR 292 method handle code is mismatched to this JVM. Disabling support.");
- enable_MH = false;
- }
if (enable_MH) {
- bool found_raise_exception = false;
KlassHandle MHN_klass = SystemDictionaryHandles::MethodHandleNatives_klass();
- KlassHandle MHI_klass = SystemDictionaryHandles::MethodHandleImpl_klass();
- // Loop control. FIXME: Replace by dead reckoning after AllowTransitionalJSR292 is removed.
- bool try_MHN = true, try_MHI = AllowTransitionalJSR292;
- for (;;) {
- KlassHandle try_klass;
- if (try_MHN) { try_MHN = false; try_klass = MHN_klass; }
- else if (try_MHI) { try_MHI = false; try_klass = MHI_klass; }
- else { break; }
- if (try_klass.is_null()) continue;
+ if (MHN_klass.not_null()) {
TempNewSymbol raiseException_name = SymbolTable::new_symbol("raiseException", CHECK);
TempNewSymbol raiseException_sig = SymbolTable::new_symbol("(ILjava/lang/Object;Ljava/lang/Object;)V", CHECK);
- methodOop raiseException_method = instanceKlass::cast(try_klass->as_klassOop())
+ methodOop raiseException_method = instanceKlass::cast(MHN_klass->as_klassOop())
->find_method(raiseException_name, raiseException_sig);
if (raiseException_method != NULL && raiseException_method->is_static()) {
MethodHandles::set_raise_exception_method(raiseException_method);
- found_raise_exception = true;
- break;
+ } else {
+ warning("JSR 292 method handle code is mismatched to this JVM. Disabling support.");
+ enable_MH = false;
}
- }
- if (!found_raise_exception) {
- warning("JSR 292 method handle code is mismatched to this JVM. Disabling support.");
+ } else {
enable_MH = false;
}
}
if (enable_MH) {
- if (AllowTransitionalJSR292) {
- // We need to link the MethodHandleImpl klass before we generate
- // the method handle adapters as the _raise_exception adapter uses
- // one of its methods (and its c2i-adapter).
- klassOop k = SystemDictionary::MethodHandleImpl_klass();
- if (k != NULL) {
- instanceKlass* ik = instanceKlass::cast(k);
- ik->link_class(CHECK);
- }
- }
-
MethodHandles::generate_adapters();
MethodHandles::set_enabled(true);
}
-
- if (AllowTransitionalJSR292) {
- ThreadToNativeFromVM ttnfv(thread);
-
- int status = env->RegisterNatives(MHN_class, methods2, sizeof(methods2)/sizeof(JNINativeMethod));
- if (env->ExceptionOccurred()) {
- // Don't do this, since it's too late:
- // MethodHandles::set_enabled(false)
- env->ExceptionClear();
- }
- }
}
JVM_END
diff --git a/src/share/vm/prims/nativeLookup.cpp b/src/share/vm/prims/nativeLookup.cpp
index f05061bd0..af625937e 100644
--- a/src/share/vm/prims/nativeLookup.cpp
+++ b/src/share/vm/prims/nativeLookup.cpp
@@ -117,8 +117,6 @@ static JNINativeMethod lookup_special_native_methods[] = {
{ CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) },
{ CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) },
- { CC"Java_sun_dyn_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, // AllowTransitionalJSR292
- { CC"Java_java_dyn_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, // AllowTransitionalJSR292
{ CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) }
};
diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp
index 550559e06..fdf271c80 100644
--- a/src/share/vm/runtime/arguments.cpp
+++ b/src/share/vm/runtime/arguments.cpp
@@ -243,6 +243,7 @@ static ObsoleteFlag obsolete_jvm_flags[] = {
{ "MaxLiveObjectEvacuationRatio",
JDK_Version::jdk_update(6,24), JDK_Version::jdk(8) },
{ "ForceSharedSpaces", JDK_Version::jdk_update(6,25), JDK_Version::jdk(8) },
+ { "AllowTransitionalJSR292", JDK_Version::jdk(7), JDK_Version::jdk(8) },
{ NULL, JDK_Version(0), JDK_Version(0) }
};
@@ -962,6 +963,16 @@ void Arguments::set_mode_flags(Mode mode) {
UseCompiler = true;
UseLoopCounter = true;
+#ifndef ZERO
+ // Turn these off for mixed and comp. Leave them on for Zero.
+ if (FLAG_IS_DEFAULT(UseFastAccessorMethods)) {
+ UseFastAccessorMethods = mode == _int;
+ }
+ if (FLAG_IS_DEFAULT(UseFastEmptyMethods)) {
+ UseFastEmptyMethods = mode == _int;
+ }
+#endif
+
// Default values may be platform/compiler dependent -
// use the saved values
ClipInlining = Arguments::_ClipInlining;
diff --git a/src/share/vm/runtime/globals.cpp b/src/share/vm/runtime/globals.cpp
index e0f99c300..efce31ac0 100644
--- a/src/share/vm/runtime/globals.cpp
+++ b/src/share/vm/runtime/globals.cpp
@@ -63,6 +63,12 @@ bool Flag::is_unlocker() const {
bool Flag::is_unlocked() const {
if (strcmp(kind, "{diagnostic}") == 0) {
+ if (strcmp(name, "EnableInvokeDynamic") == 0 && UnlockExperimentalVMOptions && !UnlockDiagnosticVMOptions) {
+ // transitional logic to allow tests to run until they are changed
+ static int warned;
+ if (++warned == 1) warning("Use -XX:+UnlockDiagnosticVMOptions before EnableInvokeDynamic flag");
+ return true;
+ }
return UnlockDiagnosticVMOptions;
} else if (strcmp(kind, "{experimental}") == 0 ||
strcmp(kind, "{C2 experimental}") == 0) {
diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp
index 32bd45794..96f0abbb0 100644
--- a/src/share/vm/runtime/globals.hpp
+++ b/src/share/vm/runtime/globals.hpp
@@ -3718,13 +3718,7 @@ class CommandLineFlags {
experimental(bool, TrustFinalNonStaticFields, false, \
"trust final non-static declarations for constant folding") \
\
- experimental(bool, AllowTransitionalJSR292, true, \
- "recognize pre-PFD formats of invokedynamic") \
- \
- experimental(bool, PreferTransitionalJSR292, false, \
- "prefer pre-PFD APIs on boot class path, if they exist") \
- \
- experimental(bool, AllowInvokeForInvokeGeneric, false, \
+ experimental(bool, AllowInvokeGeneric, true, \
"accept MethodHandle.invoke and MethodHandle.invokeGeneric " \
"as equivalent methods") \
\
diff --git a/src/share/vm/runtime/sharedRuntime.cpp b/src/share/vm/runtime/sharedRuntime.cpp
index 8e8e2eb81..820678701 100644
--- a/src/share/vm/runtime/sharedRuntime.cpp
+++ b/src/share/vm/runtime/sharedRuntime.cpp
@@ -1700,9 +1700,11 @@ char* SharedRuntime::generate_wrong_method_type_message(JavaThread* thread,
message = generate_class_cast_message(objName, targetKlass->external_name());
} else {
// %%% need to get the MethodType string, without messing around too much
+ const char* desc = NULL;
// Get a signature from the invoke instruction
const char* mhName = "method handle";
const char* targetType = "the required signature";
+ int targetArity = -1, mhArity = -1;
vframeStream vfst(thread, true);
if (!vfst.at_end()) {
Bytecode_invoke call(vfst.method(), vfst.bci());
@@ -1716,20 +1718,35 @@ char* SharedRuntime::generate_wrong_method_type_message(JavaThread* thread,
&& target->is_method_handle_invoke()
&& required == target->method_handle_type()) {
targetType = target->signature()->as_C_string();
+ targetArity = ArgumentCount(target->signature()).size();
}
}
- klassOop kignore; int fignore;
- methodOop actual_method = MethodHandles::decode_method(actual,
- kignore, fignore);
+ klassOop kignore; int dmf_flags = 0;
+ methodOop actual_method = MethodHandles::decode_method(actual, kignore, dmf_flags);
+ if ((dmf_flags & ~(MethodHandles::_dmf_has_receiver |
+ MethodHandles::_dmf_does_dispatch |
+ MethodHandles::_dmf_from_interface)) != 0)
+ actual_method = NULL; // MH does extra binds, drops, etc.
+ bool has_receiver = ((dmf_flags & MethodHandles::_dmf_has_receiver) != 0);
if (actual_method != NULL) {
- if (methodOopDesc::is_method_handle_invoke_name(actual_method->name()))
- mhName = "$";
+ mhName = actual_method->signature()->as_C_string();
+ mhArity = ArgumentCount(actual_method->signature()).size();
+ if (!actual_method->is_static()) mhArity += 1;
+ } else if (java_lang_invoke_MethodHandle::is_instance(actual)) {
+ oopDesc* mhType = java_lang_invoke_MethodHandle::type(actual);
+ mhArity = java_lang_invoke_MethodType::ptype_count(mhType);
+ stringStream st;
+ java_lang_invoke_MethodType::print_signature(mhType, &st);
+ mhName = st.as_string();
+ }
+ if (targetArity != -1 && targetArity != mhArity) {
+ if (has_receiver && targetArity == mhArity-1)
+ desc = " cannot be called without a receiver argument as ";
else
- mhName = actual_method->signature()->as_C_string();
- if (mhName[0] == '$')
- mhName = actual_method->signature()->as_C_string();
+ desc = " cannot be called with a different arity as ";
}
message = generate_class_cast_message(mhName, targetType,
+ desc != NULL ? desc :
" cannot be called as ");
}
if (TraceMethodHandles) {
diff --git a/src/share/vm/runtime/stubRoutines.cpp b/src/share/vm/runtime/stubRoutines.cpp
index 69aee24e0..6511ce31f 100644
--- a/src/share/vm/runtime/stubRoutines.cpp
+++ b/src/share/vm/runtime/stubRoutines.cpp
@@ -433,3 +433,77 @@ address StubRoutines::select_fill_function(BasicType t, bool aligned, const char
#undef RETURN_STUB
}
+
+// 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).
+address
+StubRoutines::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
+}
diff --git a/src/share/vm/runtime/stubRoutines.hpp b/src/share/vm/runtime/stubRoutines.hpp
index 4f3a770eb..b62727d82 100644
--- a/src/share/vm/runtime/stubRoutines.hpp
+++ b/src/share/vm/runtime/stubRoutines.hpp
@@ -282,6 +282,8 @@ class StubRoutines: AllStatic {
static address addr_fpu_subnormal_bias2() { return (address)&_fpu_subnormal_bias2; }
+ static address select_arraycopy_function(BasicType t, bool aligned, bool disjoint, const char* &name, bool dest_uninitialized);
+
static address jbyte_arraycopy() { return _jbyte_arraycopy; }
static address jshort_arraycopy() { return _jshort_arraycopy; }
static address jint_arraycopy() { return _jint_arraycopy; }
diff --git a/src/share/vm/shark/sharkCompiler.cpp b/src/share/vm/shark/sharkCompiler.cpp
index 97ec78c49..53851770f 100644
--- a/src/share/vm/shark/sharkCompiler.cpp
+++ b/src/share/vm/shark/sharkCompiler.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2008, 2009, 2010 Red Hat, Inc.
+ * Copyright 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
@@ -218,6 +218,7 @@ void SharkCompiler::compile_method(ciEnv* env,
nmethod* SharkCompiler::generate_native_wrapper(MacroAssembler* masm,
methodHandle target,
+ int compile_id,
BasicType* arg_types,
BasicType return_type) {
assert(is_initialized(), "should be");
@@ -241,6 +242,7 @@ nmethod* SharkCompiler::generate_native_wrapper(MacroAssembler* masm,
// Return the nmethod for installation in the VM
return nmethod::new_native_nmethod(target,
+ compile_id,
masm->code(),
0,
0,
diff --git a/src/share/vm/shark/sharkCompiler.hpp b/src/share/vm/shark/sharkCompiler.hpp
index d6ddd3d60..828a783a8 100644
--- a/src/share/vm/shark/sharkCompiler.hpp
+++ b/src/share/vm/shark/sharkCompiler.hpp
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2008, 2009 Red Hat, Inc.
+ * Copyright 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
@@ -60,6 +60,7 @@ class SharkCompiler : public AbstractCompiler {
// Generate a wrapper for a native (JNI) method
nmethod* generate_native_wrapper(MacroAssembler* masm,
methodHandle target,
+ int compile_id,
BasicType* arg_types,
BasicType return_type);
@@ -113,7 +114,8 @@ class SharkCompiler : public AbstractCompiler {
// Global access
public:
static SharkCompiler* compiler() {
- AbstractCompiler *compiler = CompileBroker::compiler(CompLevel_simple);
+ AbstractCompiler *compiler =
+ CompileBroker::compiler(CompLevel_full_optimization);
assert(compiler->is_shark() && compiler->is_initialized(), "should be");
return (SharkCompiler *) compiler;
}
diff --git a/src/share/vm/utilities/constantTag.cpp b/src/share/vm/utilities/constantTag.cpp
index 0d2744666..49e374e89 100644
--- a/src/share/vm/utilities/constantTag.cpp
+++ b/src/share/vm/utilities/constantTag.cpp
@@ -93,8 +93,6 @@ const char* constantTag::internal_name() const {
return "MethodType";
case JVM_CONSTANT_InvokeDynamic :
return "InvokeDynamic";
- case JVM_CONSTANT_InvokeDynamicTrans :
- return "InvokeDynamic/transitional";
case JVM_CONSTANT_Object :
return "Object";
case JVM_CONSTANT_Utf8 :
diff --git a/src/share/vm/utilities/constantTag.hpp b/src/share/vm/utilities/constantTag.hpp
index 43f5a8218..bbd02462e 100644
--- a/src/share/vm/utilities/constantTag.hpp
+++ b/src/share/vm/utilities/constantTag.hpp
@@ -86,8 +86,7 @@ class constantTag VALUE_OBJ_CLASS_SPEC {
bool is_method_type() const { return _tag == JVM_CONSTANT_MethodType; }
bool is_method_handle() const { return _tag == JVM_CONSTANT_MethodHandle; }
- bool is_invoke_dynamic() const { return (_tag == JVM_CONSTANT_InvokeDynamic ||
- _tag == JVM_CONSTANT_InvokeDynamicTrans); }
+ bool is_invoke_dynamic() const { return _tag == JVM_CONSTANT_InvokeDynamic; }
bool is_loadable_constant() const {
return ((_tag >= JVM_CONSTANT_Integer && _tag <= JVM_CONSTANT_String) ||
diff --git a/src/share/vm/utilities/globalDefinitions.hpp b/src/share/vm/utilities/globalDefinitions.hpp
index a742d2214..8607a3e03 100644
--- a/src/share/vm/utilities/globalDefinitions.hpp
+++ b/src/share/vm/utilities/globalDefinitions.hpp
@@ -746,9 +746,9 @@ enum CompLevel {
CompLevel_simple = 1, // C1
CompLevel_limited_profile = 2, // C1, invocation & backedge counters
CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo
- CompLevel_full_optimization = 4, // C2
+ CompLevel_full_optimization = 4, // C2 or Shark
-#if defined(COMPILER2)
+#if defined(COMPILER2) || defined(SHARK)
CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered
#elif defined(COMPILER1)
CompLevel_highest_tier = CompLevel_simple, // pure C1
@@ -760,7 +760,7 @@ enum CompLevel {
CompLevel_initial_compile = CompLevel_full_profile // tiered
#elif defined(COMPILER1)
CompLevel_initial_compile = CompLevel_simple // pure C1
-#elif defined(COMPILER2)
+#elif defined(COMPILER2) || defined(SHARK)
CompLevel_initial_compile = CompLevel_full_optimization // pure C2
#else
CompLevel_initial_compile = CompLevel_none
diff --git a/src/share/vm/utilities/globalDefinitions_gcc.hpp b/src/share/vm/utilities/globalDefinitions_gcc.hpp
index 4ba099ace..ac7fdf878 100644
--- a/src/share/vm/utilities/globalDefinitions_gcc.hpp
+++ b/src/share/vm/utilities/globalDefinitions_gcc.hpp
@@ -77,7 +77,9 @@
# endif
#ifdef LINUX
+#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
+#endif // __STDC_LIMIT_MACROS
#include <inttypes.h>
#include <signal.h>
#include <ucontext.h>