# HG changeset patch # User duke # Date 1499268449 -7200 # Node ID 4951967a61b4dbbf514828879f57bd1a0d4b420b # Parent 9e8a93011290dcf66fc01f5ba9ebc306fff97fb8# Parent dad682f1a84a15bebc59678426ad813b77a9dc29 Merge diff -r dad682f1a84a -r 4951967a61b4 .hgtags-top-repo --- a/.hgtags-top-repo Wed Jul 05 17:26:57 2017 +0200 +++ b/.hgtags-top-repo Wed Jul 05 17:27:29 2017 +0200 @@ -92,3 +92,4 @@ e8ebdf41b9c01a26642848f4134f5504e8fb3233 jdk7-b115 94e9a1bfba8b8d1fe0bfd43b88629b1f27b02a76 jdk7-b116 7220e60b097fa027e922f1aeecdd330f3e37409f jdk7-b117 +a12a9e78df8a9d534da0b4a244ed68f0de0bd58e jdk7-b118 diff -r dad682f1a84a -r 4951967a61b4 corba/.hgtags --- a/corba/.hgtags Wed Jul 05 17:26:57 2017 +0200 +++ b/corba/.hgtags Wed Jul 05 17:27:29 2017 +0200 @@ -92,3 +92,4 @@ da7561d479e0ddaa4650d8023ac0fc7294e014e3 jdk7-b115 98c028de4301106f2285ac0e128a1bb9b4c24f5c jdk7-b116 fa502e4834dac2176499cc1f44794d5dc32a11b9 jdk7-b117 +42e77836fded7c2a3080d27316b96634ea9e33c6 jdk7-b118 diff -r dad682f1a84a -r 4951967a61b4 hotspot/.hgtags --- a/hotspot/.hgtags Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/.hgtags Wed Jul 05 17:27:29 2017 +0200 @@ -129,3 +129,5 @@ 96b3f2a7add0b445b8aa421f6823cff5a2e2fe03 jdk7-b116 52f19c724d9634af79044a2e0defbe4a5f1adbda hs20-b02 806d0c037e6bbb88dac0699673f4ba55ee8c02da jdk7-b117 +698b7b727e12de44139d8cca6ab9a494ead13253 jdk7-b118 +3ef7426b4deac5dcfd4afb35cabe9ab3d666df91 hs20-b02 diff -r dad682f1a84a -r 4951967a61b4 hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/interpreter/BytecodeLoadConstant.java Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -188,7 +188,7 @@ } else { throw new RuntimeException("should not reach here"); } - } else if (ctag.isMethodHandle() || ctag.isMethodType()) { + } else if (ctag.isMethodHandle()) { Oop x = getCachedConstant(); int refidx = cpool.getMethodHandleIndexAt(cpIndex); int refkind = cpool.getMethodHandleRefKindAt(cpIndex); diff -r dad682f1a84a -r 4951967a61b4 hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Wed Jul 05 17:27:29 2017 +0200 @@ -53,11 +53,19 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("constantPoolOopDesc"); tags = new OopField(type.getOopField("_tags"), 0); + operands = new OopField(type.getOopField("_operands"), 0); cache = new OopField(type.getOopField("_cache"), 0); poolHolder = new OopField(type.getOopField("_pool_holder"), 0); length = new CIntField(type.getCIntegerField("_length"), 0); headerSize = type.getSize(); elementSize = 0; + // fetch constants: + MULTI_OPERAND_COUNT_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_multi_operand_count_offset").intValue(); + MULTI_OPERAND_BASE_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_multi_operand_base_offset").intValue(); + INDY_BSM_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_bsm_offset").intValue(); + INDY_NT_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_nt_offset").intValue(); + INDY_ARGC_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_argc_offset").intValue(); + INDY_ARGV_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_argv_offset").intValue(); } ConstantPool(OopHandle handle, ObjectHeap heap) { @@ -67,6 +75,7 @@ public boolean isConstantPool() { return true; } private static OopField tags; + private static OopField operands; private static OopField cache; private static OopField poolHolder; private static CIntField length; // number of elements in oop @@ -74,7 +83,15 @@ private static long headerSize; private static long elementSize; + private static int MULTI_OPERAND_COUNT_OFFSET; + private static int MULTI_OPERAND_BASE_OFFSET; + private static int INDY_BSM_OFFSET; + private static int INDY_NT_OFFSET; + private static int INDY_ARGC_OFFSET; + private static int INDY_ARGV_OFFSET; + public TypeArray getTags() { return (TypeArray) tags.getValue(this); } + public TypeArray getOperands() { return (TypeArray) operands.getValue(this); } public ConstantPoolCache getCache() { return (ConstantPoolCache) cache.getValue(this); } public Klass getPoolHolder() { return (Klass) poolHolder.getValue(this); } public int getLength() { return (int)length.getValue(this); } @@ -278,6 +295,25 @@ return res; } + /** Lookup for multi-operand (InvokeDynamic) entries. */ + public int[] getMultiOperandsAt(int i) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(getTagAt(i).isInvokeDynamic(), "Corrupted constant pool"); + } + int pos = this.getIntAt(i); + int countPos = pos + MULTI_OPERAND_COUNT_OFFSET; // == pos-1 + int basePos = pos + MULTI_OPERAND_BASE_OFFSET; // == pos + if (countPos < 0) return null; // safety first + TypeArray operands = getOperands(); + if (operands == null) return null; // safety first + int length = operands.getIntAt(countPos); + int[] values = new int[length]; + for (int j = 0; j < length; j++) { + values[j] = operands.getIntAt(basePos+j); + } + return values; + } + final private static String[] nameForTag = new String[] { }; @@ -522,15 +558,20 @@ case JVM_CONSTANT_InvokeDynamic: { dos.writeByte(cpConstType); - int value = getIntAt(ci); - short bootstrapMethodIndex = (short) extractLowShortFromInt(value); - short nameAndTypeIndex = (short) extractHighShortFromInt(value); - dos.writeShort(bootstrapMethodIndex); - dos.writeShort(nameAndTypeIndex); + int[] values = getMultiOperandsAt(ci); + for (int vn = 0; vn < values.length; vn++) { + dos.writeShort(values[vn]); + } + int bootstrapMethodIndex = values[INDY_BSM_OFFSET]; + int nameAndTypeIndex = values[INDY_NT_OFFSET]; + int argumentCount = values[INDY_ARGC_OFFSET]; + assert(INDY_ARGV_OFFSET + argumentCount == values.length); if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " + bootstrapMethodIndex - + ", N&T = " + nameAndTypeIndex); + + ", N&T = " + nameAndTypeIndex + + ", argc = " + argumentCount); break; } + default: throw new InternalError("unknown tag: " + cpConstType); } // switch diff -r dad682f1a84a -r 4951967a61b4 hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java Wed Jul 05 17:27:29 2017 +0200 @@ -42,7 +42,8 @@ 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_InvokeDynamic = 17; + public static final int JVM_CONSTANT_InvokeDynamicTrans = 17; // only occurs in old class files + public static final int JVM_CONSTANT_InvokeDynamic = 18; // JVM_CONSTANT_MethodHandle subtypes public static final int JVM_REF_getField = 1; diff -r dad682f1a84a -r 4951967a61b4 hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java Wed Jul 05 17:27:29 2017 +0200 @@ -303,12 +303,12 @@ case JVM_CONSTANT_MethodHandle: { dos.writeByte(cpConstType); int value = cpool.getIntAt(ci); - short bootstrapMethodIndex = (short) extractLowShortFromInt(value); - short nameAndTypeIndex = (short) extractHighShortFromInt(value); - dos.writeShort(bootstrapMethodIndex); - dos.writeShort(nameAndTypeIndex); - if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " + - bootstrapMethodIndex + ", N&T = " + nameAndTypeIndex); + byte refKind = (byte) extractLowShortFromInt(value); + short memberIndex = (short) extractHighShortFromInt(value); + dos.writeByte(refKind); + dos.writeShort(memberIndex); + if (DEBUG) debugMessage("CP[" + ci + "] = MH kind = " + + refKind + ", mem = " + memberIndex); break; } @@ -323,10 +323,11 @@ case JVM_CONSTANT_InvokeDynamic: { dos.writeByte(cpConstType); - int value = cpool.getIntAt(ci); - short refIndex = (short) value; - dos.writeShort(refIndex); - if (DEBUG) debugMessage("CP[" + ci + "] = MT index = " + refIndex); + int[] values = cpool.getMultiOperandsAt(ci); + for (int vn = 0; vn < values.length; vn++) { + dos.writeShort(values[vn]); + } + if (DEBUG) debugMessage("CP[" + ci + "] = INDY indexes = " + Arrays.toString(values)); break; } diff -r dad682f1a84a -r 4951967a61b4 hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Wed Jul 05 17:27:29 2017 +0200 @@ -460,6 +460,18 @@ return buf.toString(); } + private String genListOfShort(int[] values) { + Formatter buf = new Formatter(genHTML); + buf.append('['); + for (int i = 0; i < values.length; i++) { + if (i > 0) buf.append(' '); + buf.append('#'); + buf.append(Integer.toString(values[i])); + } + buf.append(']'); + return buf.toString(); + } + protected String genHTMLTableForConstantPool(ConstantPool cpool) { Formatter buf = new Formatter(genHTML); buf.beginTable(1); @@ -584,7 +596,7 @@ case JVM_CONSTANT_InvokeDynamic: buf.cell("JVM_CONSTANT_InvokeDynamic"); - buf.cell(genLowHighShort(cpool.getIntAt(index))); + buf.cell(genListOfShort(cpool.getMultiOperandsAt(index))); break; default: diff -r dad682f1a84a -r 4951967a61b4 hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,8 @@ 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_InvokeDynamic = 17; // JSR 292 + // static int JVM_CONSTANT_InvokeDynamicTrans = 17; // JSR 292, only occurs in old class files + 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 private static int JVM_CONSTANT_ClassIndex = 101; // Temporary tag while constructing constant pool diff -r dad682f1a84a -r 4951967a61b4 hotspot/make/hotspot_version --- a/hotspot/make/hotspot_version Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/make/hotspot_version Wed Jul 05 17:27:29 2017 +0200 @@ -35,7 +35,7 @@ HS_MAJOR_VER=20 HS_MINOR_VER=0 -HS_BUILD_NUMBER=02 +HS_BUILD_NUMBER=03 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff -r dad682f1a84a -r 4951967a61b4 hotspot/make/linux/Makefile --- a/hotspot/make/linux/Makefile Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/make/linux/Makefile Wed Jul 05 17:27:29 2017 +0200 @@ -62,7 +62,9 @@ include $(GAMMADIR)/make/$(OSNAME)/makefiles/rules.make ifndef CC_INTERP -FORCE_TIERED=1 + ifndef FORCE_TIERED + FORCE_TIERED=1 + endif endif ifdef LP64 @@ -254,7 +256,7 @@ $(BUILDTREE) VARIANT=tiered $(SUBDIRS_C2): $(BUILDTREE_MAKE) -ifdef FORCE_TIERED +ifeq ($(FORCE_TIERED),1) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks $(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 else diff -r dad682f1a84a -r 4951967a61b4 hotspot/make/solaris/Makefile --- a/hotspot/make/solaris/Makefile Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/make/solaris/Makefile Wed Jul 05 17:27:29 2017 +0200 @@ -53,7 +53,9 @@ include $(GAMMADIR)/make/$(OSNAME)/makefiles/rules.make ifndef CC_INTERP -FORCE_TIERED=1 + ifndef FORCE_TIERED + FORCE_TIERED=1 + endif endif ifdef LP64 @@ -210,7 +212,7 @@ $(BUILDTREE) VARIANT=tiered $(SUBDIRS_C2): $(BUILDTREE_MAKE) -ifdef FORCE_TIERED +ifeq ($(FORCE_TIERED),1) $(QUIETLY) $(MAKE) -f $(GAMMADIR)/make/$(OSNAME)/Makefile checks $(BUILDTREE) VARIANT=tiered FORCE_TIERED=1 else diff -r dad682f1a84a -r 4951967a61b4 hotspot/make/windows/build.make --- a/hotspot/make/windows/build.make Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/make/windows/build.make Wed Jul 05 17:27:29 2017 +0200 @@ -74,9 +74,11 @@ !if "$(BUILDARCH)" != "ia64" !ifndef CC_INTERP +!ifndef FORCE_TIERED FORCE_TIERED=1 !endif !endif +!endif !if "$(BUILDARCH)" == "amd64" Platform_arch=x86 @@ -100,7 +102,7 @@ !if "$(Variant)" == "compiler1" VARIANT_TEXT=Client !elseif "$(Variant)" == "compiler2" -!ifdef FORCE_TIERED +!if "$(FORCE_TIERED)" == "1" VARIANT_TEXT=Server realVariant=tiered !else diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/sparc/vm/assembler_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -1126,7 +1126,7 @@ inline void add(Register s1, int simm13a, Register d, relocInfo::relocType rtype = relocInfo::none); inline void add(Register s1, int simm13a, Register d, RelocationHolder const& rspec); inline void add(Register s1, RegisterOrConstant s2, Register d, int offset = 0); - inline void add(const Address& a, Register d, int offset = 0) { add( a.base(), a.disp() + offset, d, a.rspec(offset)); } + inline void add(const Address& a, Register d, int offset = 0); void addcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } void addcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,6 +206,11 @@ inline void Assembler::ldd( Register s1, RegisterOrConstant s2, Register d) { ldd( Address(s1, s2), d); } // form effective addresses this way: +inline void Assembler::add(const Address& a, Register d, int offset) { + if (a.has_index()) add(a.base(), a.index(), d); + else { add(a.base(), a.disp() + offset, d, a.rspec(offset)); offset = 0; } + if (offset != 0) add(d, offset, d); +} inline void Assembler::add(Register s1, RegisterOrConstant s2, Register d, int offset) { if (s2.is_register()) add(s1, s2.as_register(), d); else { add(s1, s2.as_constant() + offset, d); offset = 0; } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -70,17 +70,29 @@ // Code generation address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) { - // I5_savedSP: sender SP (must preserve) + // I5_savedSP/O5_savedSP: sender SP (must preserve) // G4 (Gargs): incoming argument list (must preserve) - // G5_method: invoke methodOop; becomes method type. + // G5_method: invoke methodOop // G3_method_handle: receiver method handle (must load from sp[MethodTypeForm.vmslots]) - // O0, O1: garbage temps, blown away - Register O0_argslot = O0; + // O0, O1, O2, O3, O4: garbage temps, blown away + Register O0_mtype = O0; Register O1_scratch = O1; + Register O2_scratch = O2; + Register O3_scratch = O3; + Register O4_argslot = O4; + Register O4_argbase = O4; // emit WrongMethodType path first, to enable back-branch from main path Label wrong_method_type; __ bind(wrong_method_type); + Label invoke_generic_slow_path; + assert(methodOopDesc::intrinsic_id_size_in_bytes() == sizeof(u1), "");; + __ ldub(Address(G5_method, methodOopDesc::intrinsic_id_offset_in_bytes()), O1_scratch); + __ cmp(O1_scratch, (int) vmIntrinsics::_invokeExact); + __ brx(Assembler::notEqual, false, Assembler::pt, invoke_generic_slow_path); + __ delayed()->nop(); + __ mov(O0_mtype, G5_method_type); // required by throw_WrongMethodType + // mov(G3_method_handle, G3_method_handle); // already in this register __ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch); __ delayed()->nop(); @@ -88,23 +100,74 @@ __ align(CodeEntryAlignment); address entry_point = __ pc(); - // fetch the MethodType from the method handle into G5_method_type + // fetch the MethodType from the method handle { Register tem = G5_method; - assert(tem == G5_method_type, "yes, it's the same register"); for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) { - __ ld_ptr(Address(tem, *pchase), G5_method_type); + __ ld_ptr(Address(tem, *pchase), O0_mtype); + tem = O0_mtype; // in case there is another indirection } } // given the MethodType, find out where the MH argument is buried - __ load_heap_oop(Address(G5_method_type, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O0_argslot); - __ ldsw( Address(O0_argslot, __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch)), O0_argslot); - __ ld_ptr(__ argument_address(O0_argslot), G3_method_handle); + __ load_heap_oop(Address(O0_mtype, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O4_argslot); + __ ldsw( Address(O4_argslot, __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, O1_scratch)), O4_argslot); + __ add(Gargs, __ argument_offset(O4_argslot, 1), O4_argbase); + // Note: argument_address uses its input as a scratch register! + __ ld_ptr(Address(O4_argbase, -Interpreter::stackElementSize), G3_method_handle); + + trace_method_handle(_masm, "invokeExact"); + + __ check_method_handle_type(O0_mtype, G3_method_handle, O1_scratch, wrong_method_type); + __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); + + // for invokeGeneric (only), apply argument and result conversions on the fly + __ bind(invoke_generic_slow_path); +#ifdef ASSERT + { Label L; + __ ldub(Address(G5_method, methodOopDesc::intrinsic_id_offset_in_bytes()), O1_scratch); + __ cmp(O1_scratch, (int) vmIntrinsics::_invokeGeneric); + __ brx(Assembler::equal, false, Assembler::pt, L); + __ delayed()->nop(); + __ stop("bad methodOop::intrinsic_id"); + __ bind(L); + } +#endif //ASSERT - __ check_method_handle_type(G5_method_type, G3_method_handle, O1_scratch, wrong_method_type); + // make room on the stack for another pointer: + insert_arg_slots(_masm, 2 * stack_move_unit(), _INSERT_REF_MASK, O4_argbase, O1_scratch, O2_scratch, O3_scratch); + // load up an adapter from the calling type (Java weaves this) + Register O2_form = O2_scratch; + Register O3_adapter = O3_scratch; + __ load_heap_oop(Address(O0_mtype, __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, O1_scratch)), O2_form); + // load_heap_oop(Address(O2_form, __ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter); + // deal with old JDK versions: + __ add( Address(O2_form, __ delayed_value(java_dyn_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter); + __ cmp(O3_adapter, O2_form); + Label sorry_no_invoke_generic; + __ brx(Assembler::lessUnsigned, false, Assembler::pn, sorry_no_invoke_generic); + __ delayed()->nop(); + + __ load_heap_oop(Address(O3_adapter, 0), O3_adapter); + __ tst(O3_adapter); + __ brx(Assembler::zero, false, Assembler::pn, sorry_no_invoke_generic); + __ delayed()->nop(); + __ st_ptr(O3_adapter, Address(O4_argbase, 1 * Interpreter::stackElementSize)); + // As a trusted first argument, pass the type being called, so the adapter knows + // the actual types of the arguments and return values. + // (Generic invokers are shared among form-families of method-type.) + __ st_ptr(O0_mtype, Address(O4_argbase, 0 * Interpreter::stackElementSize)); + // FIXME: assert that O3_adapter is of the right method-type. + __ mov(O3_adapter, G3_method_handle); + trace_method_handle(_masm, "invokeGeneric"); __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); + __ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available! + __ mov(O0_mtype, G5_method_type); // required by throw_WrongMethodType + // mov(G3_method_handle, G3_method_handle); // already in this register + __ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch); + __ delayed()->nop(); + return entry_point; } @@ -630,9 +693,15 @@ switch (ek) { case _adapter_opt_i2i: + value = vmarg; + break; case _adapter_opt_l2i: - __ unimplemented(entry_name(ek)); - value = vmarg; + { + // just delete the extra slot + __ add(Gargs, __ argument_offset(O0_argslot), O0_argslot); + remove_arg_slots(_masm, -stack_move_unit(), O0_argslot, O1_scratch, O2_scratch, O3_scratch); + value = vmarg = Address(O0_argslot, 0); + } break; case _adapter_opt_unboxi: { diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/sparc/vm/sparc.ad --- a/hotspot/src/cpu/sparc/vm/sparc.ad Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/sparc.ad Wed Jul 05 17:27:29 2017 +0200 @@ -1843,6 +1843,12 @@ return can_be_java_arg(reg); } +bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) { + // Use hardware SDIVX instruction when it is + // faster than a code which use multiply. + return VM_Version::has_fast_idiv(); +} + // Register for DIVI projection of divmodI RegMask Matcher::divI_proj_mask() { ShouldNotReachHere(); @@ -9510,16 +9516,16 @@ Register Rdst = $dst$$Register; Register Rsrc = $src$$Register; Register Rtmp = $tmp$$Register; - __ srl(Rsrc, 1, Rtmp); - __ srl(Rsrc, 0, Rdst); + __ srl(Rsrc, 1, Rtmp); + __ srl(Rsrc, 0, Rdst); __ or3(Rdst, Rtmp, Rdst); - __ srl(Rdst, 2, Rtmp); + __ srl(Rdst, 2, Rtmp); __ or3(Rdst, Rtmp, Rdst); - __ srl(Rdst, 4, Rtmp); + __ srl(Rdst, 4, Rtmp); __ or3(Rdst, Rtmp, Rdst); - __ srl(Rdst, 8, Rtmp); + __ srl(Rdst, 8, Rtmp); __ or3(Rdst, Rtmp, Rdst); - __ srl(Rdst, 16, Rtmp); + __ srl(Rdst, 16, Rtmp); __ or3(Rdst, Rtmp, Rdst); __ popc(Rdst, Rdst); __ mov(BitsPerInt, Rtmp); @@ -9528,7 +9534,7 @@ ins_pipe(ialu_reg); %} -instruct countLeadingZerosL(iRegI dst, iRegL src, iRegL tmp, flagsReg cr) %{ +instruct countLeadingZerosL(iRegIsafe dst, iRegL src, iRegL tmp, flagsReg cr) %{ predicate(UsePopCountInstruction); // See Matcher::match_rule_supported match(Set dst (CountLeadingZerosL src)); effect(TEMP dst, TEMP tmp, KILL cr); @@ -9559,18 +9565,18 @@ Register Rdst = $dst$$Register; Register Rsrc = $src$$Register; Register Rtmp = $tmp$$Register; - __ srlx(Rsrc, 1, Rtmp); - __ or3(Rsrc, Rtmp, Rdst); - __ srlx(Rdst, 2, Rtmp); - __ or3(Rdst, Rtmp, Rdst); - __ srlx(Rdst, 4, Rtmp); - __ or3(Rdst, Rtmp, Rdst); - __ srlx(Rdst, 8, Rtmp); - __ or3(Rdst, Rtmp, Rdst); - __ srlx(Rdst, 16, Rtmp); - __ or3(Rdst, Rtmp, Rdst); - __ srlx(Rdst, 32, Rtmp); - __ or3(Rdst, Rtmp, Rdst); + __ srlx(Rsrc, 1, Rtmp); + __ or3( Rsrc, Rtmp, Rdst); + __ srlx(Rdst, 2, Rtmp); + __ or3( Rdst, Rtmp, Rdst); + __ srlx(Rdst, 4, Rtmp); + __ or3( Rdst, Rtmp, Rdst); + __ srlx(Rdst, 8, Rtmp); + __ or3( Rdst, Rtmp, Rdst); + __ srlx(Rdst, 16, Rtmp); + __ or3( Rdst, Rtmp, Rdst); + __ srlx(Rdst, 32, Rtmp); + __ or3( Rdst, Rtmp, Rdst); __ popc(Rdst, Rdst); __ mov(BitsPerLong, Rtmp); __ sub(Rtmp, Rdst, Rdst); diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -341,6 +341,26 @@ resolve_cache_and_index(f1_oop, Otos_i, Rcache, Rscratch, wide ? sizeof(u2) : sizeof(u1)); __ verify_oop(Otos_i); + + Label L_done; + const Register Rcon_klass = G3_scratch; // same as Rcache + const Register Rarray_klass = G4_scratch; // same as Rscratch + __ load_klass(Otos_i, Rcon_klass); + AddressLiteral array_klass_addr((address)Universe::systemObjArrayKlassObj_addr()); + __ load_contents(array_klass_addr, Rarray_klass); + __ cmp(Rarray_klass, Rcon_klass); + __ brx(Assembler::notEqual, false, Assembler::pt, L_done); + __ delayed()->nop(); + __ ld(Address(Otos_i, arrayOopDesc::length_offset_in_bytes()), Rcon_klass); + __ tst(Rcon_klass); + __ brx(Assembler::zero, true, Assembler::pt, L_done); + __ delayed()->clr(Otos_i); // executed only if branch is taken + + // Load the exception from the system-array which wraps it: + __ load_heap_oop(Otos_i, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Otos_i); + __ throw_if_not_x(Assembler::never, Interpreter::throw_exception_entry(), G3_scratch); + + __ bind(L_done); } void TemplateTable::ldc2_w() { diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,7 +80,8 @@ FLAG_SET_DEFAULT(InteriorEntryAlignment, 4); } if (is_niagara1_plus()) { - if (AllocatePrefetchStyle > 0 && FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { + if (has_blk_init() && AllocatePrefetchStyle > 0 && + FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { // Use BIS instruction for allocation prefetch. FLAG_SET_DEFAULT(AllocatePrefetchStyle, 3); if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) { @@ -118,16 +119,18 @@ #endif char buf[512]; - jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", (has_v8() ? ", has_v8" : ""), (has_v9() ? ", has_v9" : ""), (has_hardware_popc() ? ", popc" : ""), (has_vis1() ? ", has_vis1" : ""), (has_vis2() ? ", has_vis2" : ""), + (has_blk_init() ? ", has_blk_init" : ""), (is_ultra3() ? ", is_ultra3" : ""), (is_sun4v() ? ", is_sun4v" : ""), (is_niagara1() ? ", is_niagara1" : ""), (is_niagara1_plus() ? ", is_niagara1_plus" : ""), + (is_sparc64() ? ", is_sparc64" : ""), (!has_hardware_mul32() ? ", no-mul32" : ""), (!has_hardware_div32() ? ", no-div32" : ""), (!has_hardware_fsmuld() ? ", no-fsmuld" : "")); diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,9 @@ v9_instructions = 5, vis1_instructions = 6, vis2_instructions = 7, - sun4v_instructions = 8 + sun4v_instructions = 8, + blk_init_instructions = 9, + fmaf_instructions = 10 }; enum Feature_Flag_Set { @@ -49,6 +51,8 @@ vis1_instructions_m = 1 << vis1_instructions, vis2_instructions_m = 1 << vis2_instructions, sun4v_m = 1 << sun4v_instructions, + blk_init_instructions_m = 1 << blk_init_instructions, + fmaf_instructions_m = 1 << fmaf_instructions, generic_v8_m = v8_instructions_m | hardware_mul32_m | hardware_div32_m | hardware_fsmuld_m, generic_v9_m = generic_v8_m | v9_instructions_m, @@ -67,6 +71,7 @@ static int platform_features(int features); static bool is_niagara1(int features) { return (features & sun4v_m) != 0; } + static bool is_sparc64(int features) { return (features & fmaf_instructions_m) != 0; } static int maximum_niagara1_processor_count() { return 32; } // Returns true if the platform is in the niagara line and @@ -86,6 +91,7 @@ static bool has_hardware_popc() { return (_features & hardware_popc_m) != 0; } static bool has_vis1() { return (_features & vis1_instructions_m) != 0; } static bool has_vis2() { return (_features & vis2_instructions_m) != 0; } + static bool has_blk_init() { return (_features & blk_init_instructions_m) != 0; } static bool supports_compare_and_exchange() { return has_v9(); } @@ -93,8 +99,10 @@ static bool is_ultra3() { return (_features & ultra3_m) == ultra3_m; } static bool is_sun4v() { return (_features & sun4v_m) != 0; } static bool is_niagara1() { return is_niagara1(_features); } + static bool is_sparc64() { return is_sparc64(_features); } static bool has_fast_fxtof() { return has_v9() && !is_ultra3(); } + static bool has_fast_idiv() { return is_niagara1_plus() || is_sparc64(); } static const char* cpu_features() { return _features_str; } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/x86/vm/assembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1275,6 +1275,12 @@ emit_byte(0xF8 | encode); } +void Assembler::divl(Register src) { // Unsigned + int encode = prefix_and_encode(src->encoding()); + emit_byte(0xF7); + emit_byte(0xF0 | encode); +} + void Assembler::imull(Register dst, Register src) { int encode = prefix_and_encode(dst->encoding(), src->encoding()); emit_byte(0x0F); @@ -1288,7 +1294,7 @@ if (is8bit(value)) { emit_byte(0x6B); emit_byte(0xC0 | encode); - emit_byte(value); + emit_byte(value & 0xFF); } else { emit_byte(0x69); emit_byte(0xC0 | encode); @@ -3903,7 +3909,7 @@ if (is8bit(value)) { emit_byte(0x6B); emit_byte(0xC0 | encode); - emit_byte(value); + emit_byte(value & 0xFF); } else { emit_byte(0x69); emit_byte(0xC0 | encode); diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/x86/vm/assembler_x86.hpp --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -1011,6 +1011,7 @@ void hlt(); void idivl(Register src); + void divl(Register src); // Unsigned division void idivq(Register src); diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -399,6 +399,23 @@ if (VerifyOops) { __ verify_oop(rax); } + + Label L_done, L_throw_exception; + const Register con_klass_temp = rcx; // same as Rcache + __ movptr(con_klass_temp, Address(rax, oopDesc::klass_offset_in_bytes())); + __ cmpptr(con_klass_temp, ExternalAddress((address)Universe::systemObjArrayKlassObj_addr())); + __ jcc(Assembler::notEqual, L_done); + __ cmpl(Address(rax, arrayOopDesc::length_offset_in_bytes()), 0); + __ jcc(Assembler::notEqual, L_throw_exception); + __ xorptr(rax, rax); + __ jmp(L_done); + + // Load the exception from the system-array which wraps it: + __ bind(L_throw_exception); + __ movptr(rax, Address(rax, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); + __ jump(ExternalAddress(Interpreter::throw_exception_entry())); + + __ bind(L_done); } void TemplateTable::ldc2_w() { diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -413,6 +413,25 @@ if (VerifyOops) { __ verify_oop(rax); } + + Label L_done, L_throw_exception; + const Register con_klass_temp = rcx; // same as cache + const Register array_klass_temp = rdx; // same as index + __ movptr(con_klass_temp, Address(rax, oopDesc::klass_offset_in_bytes())); + __ lea(array_klass_temp, ExternalAddress((address)Universe::systemObjArrayKlassObj_addr())); + __ cmpptr(con_klass_temp, Address(array_klass_temp, 0)); + __ jcc(Assembler::notEqual, L_done); + __ cmpl(Address(rax, arrayOopDesc::length_offset_in_bytes()), 0); + __ jcc(Assembler::notEqual, L_throw_exception); + __ xorptr(rax, rax); + __ jmp(L_done); + + // Load the exception from the system-array which wraps it: + __ bind(L_throw_exception); + __ movptr(rax, Address(rax, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); + __ jump(ExternalAddress(Interpreter::throw_exception_entry())); + + __ bind(L_done); } void TemplateTable::ldc2_w() { diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/x86/vm/vm_version_x86.hpp --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -446,6 +446,10 @@ static bool supports_lzcnt() { return (_cpuFeatures & CPU_LZCNT) != 0; } static bool supports_sse4a() { return (_cpuFeatures & CPU_SSE4A) != 0; } + // Intel Core and newer cpus have fast IDIV instruction (excluding Atom). + static bool has_fast_idiv() { return is_intel() && cpu_family() == 6 && + supports_sse3() && _model != 0x1C; } + static bool supports_compare_and_exchange() { return true; } static const char* cpu_features() { return _features_str; } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/x86/vm/x86_32.ad --- a/hotspot/src/cpu/x86/vm/x86_32.ad Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/x86_32.ad Wed Jul 05 17:27:29 2017 +0200 @@ -1508,6 +1508,16 @@ return can_be_java_arg(reg); } +bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) { + // Use hardware integer DIV instruction when + // it is faster than a code which use multiply. + // Only when constant divisor fits into 32 bit + // (min_jint is excluded to get only correct + // positive 32 bit values from negative). + return VM_Version::has_fast_idiv() && + (divisor == (int)divisor && divisor != min_jint); +} + // Register for DIVI projection of divmodI RegMask Matcher::divI_proj_mask() { return EAX_REG_mask; @@ -1546,6 +1556,9 @@ return true; } } + if (opc == Op_ConL && (n->get_long() & 0xFFFFFFFF00000000LL) == 0LL) { + return true; + } return false; } @@ -2309,9 +2322,11 @@ enc_class move_long_big_shift_sign( eRegL dst, immI_32_63 cnt ) %{ emit_opcode( cbuf, 0x8B ); // Move emit_rm(cbuf, 0x3, $dst$$reg, HIGH_FROM_LOW($dst$$reg)); - emit_d8(cbuf,$primary); - emit_rm(cbuf, 0x3, $secondary, $dst$$reg); - emit_d8(cbuf,$cnt$$constant-32); + if( $cnt$$constant > 32 ) { // Shift, if not by zero + emit_d8(cbuf,$primary); + emit_rm(cbuf, 0x3, $secondary, $dst$$reg); + emit_d8(cbuf,$cnt$$constant-32); + } emit_d8(cbuf,$primary); emit_rm(cbuf, 0x3, $secondary, HIGH_FROM_LOW($dst$$reg)); emit_d8(cbuf,31); @@ -8842,6 +8857,144 @@ ins_pipe( pipe_slow ); %} +// Divide Register Long (no special case since divisor != -1) +instruct divL_eReg_imm32( eADXRegL dst, immL32 imm, eRegI tmp, eRegI tmp2, eFlagsReg cr ) %{ + match(Set dst (DivL dst imm)); + effect( TEMP tmp, TEMP tmp2, KILL cr ); + ins_cost(1000); + format %{ "MOV $tmp,abs($imm) # ldiv EDX:EAX,$imm\n\t" + "XOR $tmp2,$tmp2\n\t" + "CMP $tmp,EDX\n\t" + "JA,s fast\n\t" + "MOV $tmp2,EAX\n\t" + "MOV EAX,EDX\n\t" + "MOV EDX,0\n\t" + "JLE,s pos\n\t" + "LNEG EAX : $tmp2\n\t" + "DIV $tmp # unsigned division\n\t" + "XCHG EAX,$tmp2\n\t" + "DIV $tmp\n\t" + "LNEG $tmp2 : EAX\n\t" + "JMP,s done\n" + "pos:\n\t" + "DIV $tmp\n\t" + "XCHG EAX,$tmp2\n" + "fast:\n\t" + "DIV $tmp\n" + "done:\n\t" + "MOV EDX,$tmp2\n\t" + "NEG EDX:EAX # if $imm < 0" %} + ins_encode %{ + int con = (int)$imm$$constant; + assert(con != 0 && con != -1 && con != min_jint, "wrong divisor"); + int pcon = (con > 0) ? con : -con; + Label Lfast, Lpos, Ldone; + + __ movl($tmp$$Register, pcon); + __ xorl($tmp2$$Register,$tmp2$$Register); + __ cmpl($tmp$$Register, HIGH_FROM_LOW($dst$$Register)); + __ jccb(Assembler::above, Lfast); // result fits into 32 bit + + __ movl($tmp2$$Register, $dst$$Register); // save + __ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register)); + __ movl(HIGH_FROM_LOW($dst$$Register),0); // preserve flags + __ jccb(Assembler::lessEqual, Lpos); // result is positive + + // Negative dividend. + // convert value to positive to use unsigned division + __ lneg($dst$$Register, $tmp2$$Register); + __ divl($tmp$$Register); + __ xchgl($dst$$Register, $tmp2$$Register); + __ divl($tmp$$Register); + // revert result back to negative + __ lneg($tmp2$$Register, $dst$$Register); + __ jmpb(Ldone); + + __ bind(Lpos); + __ divl($tmp$$Register); // Use unsigned division + __ xchgl($dst$$Register, $tmp2$$Register); + // Fallthrow for final divide, tmp2 has 32 bit hi result + + __ bind(Lfast); + // fast path: src is positive + __ divl($tmp$$Register); // Use unsigned division + + __ bind(Ldone); + __ movl(HIGH_FROM_LOW($dst$$Register),$tmp2$$Register); + if (con < 0) { + __ lneg(HIGH_FROM_LOW($dst$$Register), $dst$$Register); + } + %} + ins_pipe( pipe_slow ); +%} + +// Remainder Register Long (remainder fit into 32 bits) +instruct modL_eReg_imm32( eADXRegL dst, immL32 imm, eRegI tmp, eRegI tmp2, eFlagsReg cr ) %{ + match(Set dst (ModL dst imm)); + effect( TEMP tmp, TEMP tmp2, KILL cr ); + ins_cost(1000); + format %{ "MOV $tmp,abs($imm) # lrem EDX:EAX,$imm\n\t" + "CMP $tmp,EDX\n\t" + "JA,s fast\n\t" + "MOV $tmp2,EAX\n\t" + "MOV EAX,EDX\n\t" + "MOV EDX,0\n\t" + "JLE,s pos\n\t" + "LNEG EAX : $tmp2\n\t" + "DIV $tmp # unsigned division\n\t" + "MOV EAX,$tmp2\n\t" + "DIV $tmp\n\t" + "NEG EDX\n\t" + "JMP,s done\n" + "pos:\n\t" + "DIV $tmp\n\t" + "MOV EAX,$tmp2\n" + "fast:\n\t" + "DIV $tmp\n" + "done:\n\t" + "MOV EAX,EDX\n\t" + "SAR EDX,31\n\t" %} + ins_encode %{ + int con = (int)$imm$$constant; + assert(con != 0 && con != -1 && con != min_jint, "wrong divisor"); + int pcon = (con > 0) ? con : -con; + Label Lfast, Lpos, Ldone; + + __ movl($tmp$$Register, pcon); + __ cmpl($tmp$$Register, HIGH_FROM_LOW($dst$$Register)); + __ jccb(Assembler::above, Lfast); // src is positive and result fits into 32 bit + + __ movl($tmp2$$Register, $dst$$Register); // save + __ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register)); + __ movl(HIGH_FROM_LOW($dst$$Register),0); // preserve flags + __ jccb(Assembler::lessEqual, Lpos); // result is positive + + // Negative dividend. + // convert value to positive to use unsigned division + __ lneg($dst$$Register, $tmp2$$Register); + __ divl($tmp$$Register); + __ movl($dst$$Register, $tmp2$$Register); + __ divl($tmp$$Register); + // revert remainder back to negative + __ negl(HIGH_FROM_LOW($dst$$Register)); + __ jmpb(Ldone); + + __ bind(Lpos); + __ divl($tmp$$Register); + __ movl($dst$$Register, $tmp2$$Register); + + __ bind(Lfast); + // fast path: src is positive + __ divl($tmp$$Register); + + __ bind(Ldone); + __ movl($dst$$Register, HIGH_FROM_LOW($dst$$Register)); + __ sarl(HIGH_FROM_LOW($dst$$Register), 31); // result sign + + %} + ins_pipe( pipe_slow ); +%} + // Integer Shift Instructions // Shift Left by one instruct shlI_eReg_1(eRegI dst, immI1 shift, eFlagsReg cr) %{ diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/cpu/x86/vm/x86_64.ad --- a/hotspot/src/cpu/x86/vm/x86_64.ad Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/x86_64.ad Wed Jul 05 17:27:29 2017 +0200 @@ -2065,6 +2065,13 @@ return can_be_java_arg(reg); } +bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) { + // In 64 bit mode a code which use multiply when + // devisor is constant is faster than hardware + // DIV instruction (it uses MulHiL). + return false; +} + // Register for DIVI projection of divmodI RegMask Matcher::divI_proj_mask() { return INT_RAX_REG_mask; diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp --- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -200,6 +200,18 @@ sigcontext* sc = (sigcontext*)context; st->print_cr("Registers:"); + st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT + " G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT, + SIG_REGS(sc).u_regs[CON_G1], + SIG_REGS(sc).u_regs[CON_G2], + SIG_REGS(sc).u_regs[CON_G3], + SIG_REGS(sc).u_regs[CON_G4]); + st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT + " G7=" INTPTR_FORMAT " Y=" INTPTR_FORMAT, + SIG_REGS(sc).u_regs[CON_G5], + SIG_REGS(sc).u_regs[CON_G6], + SIG_REGS(sc).u_regs[CON_G7], + SIG_REGS(sc).y); st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT " O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT, SIG_REGS(sc).u_regs[CON_O0], @@ -213,18 +225,32 @@ SIG_REGS(sc).u_regs[CON_O6], SIG_REGS(sc).u_regs[CON_O7]); - st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT - " G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT, - SIG_REGS(sc).u_regs[CON_G1], - SIG_REGS(sc).u_regs[CON_G2], - SIG_REGS(sc).u_regs[CON_G3], - SIG_REGS(sc).u_regs[CON_G4]); - st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT - " G7=" INTPTR_FORMAT " Y=" INTPTR_FORMAT, - SIG_REGS(sc).u_regs[CON_G5], - SIG_REGS(sc).u_regs[CON_G6], - SIG_REGS(sc).u_regs[CON_G7], - SIG_REGS(sc).y); + + intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); + st->print_cr(" L0=" INTPTR_FORMAT " L1=" INTPTR_FORMAT + " L2=" INTPTR_FORMAT " L3=" INTPTR_FORMAT, + sp[L0->sp_offset_in_saved_window()], + sp[L1->sp_offset_in_saved_window()], + sp[L2->sp_offset_in_saved_window()], + sp[L3->sp_offset_in_saved_window()]); + st->print_cr(" L4=" INTPTR_FORMAT " L5=" INTPTR_FORMAT + " L6=" INTPTR_FORMAT " L7=" INTPTR_FORMAT, + sp[L4->sp_offset_in_saved_window()], + sp[L5->sp_offset_in_saved_window()], + sp[L6->sp_offset_in_saved_window()], + sp[L7->sp_offset_in_saved_window()]); + st->print_cr(" I0=" INTPTR_FORMAT " I1=" INTPTR_FORMAT + " I2=" INTPTR_FORMAT " I3=" INTPTR_FORMAT, + sp[I0->sp_offset_in_saved_window()], + sp[I1->sp_offset_in_saved_window()], + sp[I2->sp_offset_in_saved_window()], + sp[I3->sp_offset_in_saved_window()]); + st->print_cr(" I4=" INTPTR_FORMAT " I5=" INTPTR_FORMAT + " I6=" INTPTR_FORMAT " I7=" INTPTR_FORMAT, + sp[I4->sp_offset_in_saved_window()], + sp[I5->sp_offset_in_saved_window()], + sp[I6->sp_offset_in_saved_window()], + sp[I7->sp_offset_in_saved_window()]); st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT, SIG_PC(sc), @@ -232,7 +258,6 @@ st->cr(); st->cr(); - intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp); print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t)); st->cr(); @@ -242,7 +267,58 @@ // this at the end, and hope for the best. address pc = os::Linux::ucontext_get_pc(uc); st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); - print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); + print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); +} + + +void os::print_register_info(outputStream *st, void *context) { + if (context == NULL) return; + + ucontext_t *uc = (ucontext_t*)context; + intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is only for the "general purpose" registers + st->print("G1="); print_location(st, SIG_REGS(sc).u_regs[CON__G1]); + st->print("G2="); print_location(st, SIG_REGS(sc).u_regs[CON__G2]); + st->print("G3="); print_location(st, SIG_REGS(sc).u_regs[CON__G3]); + st->print("G4="); print_location(st, SIG_REGS(sc).u_regs[CON__G4]); + st->print("G5="); print_location(st, SIG_REGS(sc).u_regs[CON__G5]); + st->print("G6="); print_location(st, SIG_REGS(sc).u_regs[CON__G6]); + st->print("G7="); print_location(st, SIG_REGS(sc).u_regs[CON__G7]); + st->cr(); + + st->print("O0="); print_location(st, SIG_REGS(sc).u_regs[CON__O0]); + st->print("O1="); print_location(st, SIG_REGS(sc).u_regs[CON__O1]); + st->print("O2="); print_location(st, SIG_REGS(sc).u_regs[CON__O2]); + st->print("O3="); print_location(st, SIG_REGS(sc).u_regs[CON__O3]); + st->print("O4="); print_location(st, SIG_REGS(sc).u_regs[CON__O4]); + st->print("O5="); print_location(st, SIG_REGS(sc).u_regs[CON__O5]); + st->print("O6="); print_location(st, SIG_REGS(sc).u_regs[CON__O6]); + st->print("O7="); print_location(st, SIG_REGS(sc).u_regs[CON__O7]); + st->cr(); + + st->print("L0="); print_location(st, sp[L0->sp_offset_in_saved_window()]); + st->print("L1="); print_location(st, sp[L1->sp_offset_in_saved_window()]); + st->print("L2="); print_location(st, sp[L2->sp_offset_in_saved_window()]); + st->print("L3="); print_location(st, sp[L3->sp_offset_in_saved_window()]); + st->print("L4="); print_location(st, sp[L4->sp_offset_in_saved_window()]); + st->print("L5="); print_location(st, sp[L5->sp_offset_in_saved_window()]); + st->print("L6="); print_location(st, sp[L6->sp_offset_in_saved_window()]); + st->print("L7="); print_location(st, sp[L7->sp_offset_in_saved_window()]); + st->cr(); + + st->print("I0="); print_location(st, sp[I0->sp_offset_in_saved_window()]); + st->print("I1="); print_location(st, sp[I1->sp_offset_in_saved_window()]); + st->print("I2="); print_location(st, sp[I2->sp_offset_in_saved_window()]); + st->print("I3="); print_location(st, sp[I3->sp_offset_in_saved_window()]); + st->print("I4="); print_location(st, sp[I4->sp_offset_in_saved_window()]); + st->print("I5="); print_location(st, sp[I5->sp_offset_in_saved_window()]); + st->print("I6="); print_location(st, sp[I6->sp_offset_in_saved_window()]); + st->print("I7="); print_location(st, sp[I7->sp_offset_in_saved_window()]); + st->cr(); } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp --- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -718,11 +718,6 @@ ucontext_t *uc = (ucontext_t*)context; st->print_cr("Registers:"); - - // this is horrendously verbose but the layout of the registers in the - // context does not match how we defined our abstract Register set, so - // we can't just iterate through the gregs area - #ifdef AMD64 st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); @@ -745,68 +740,11 @@ st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]); st->cr(); st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]); - st->print(", EFL=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); + st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); st->print(", CSGSFS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_CSGSFS]); st->print(", ERR=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ERR]); st->cr(); st->print(" TRAPNO=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_TRAPNO]); - - st->cr(); - st->cr(); - - st->print_cr("Register to memory mapping:"); - st->cr(); - - // this is only for the "general purpose" registers - - st->print_cr("RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); - print_location(st, uc->uc_mcontext.gregs[REG_RAX]); - st->cr(); - st->print_cr("RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); - print_location(st, uc->uc_mcontext.gregs[REG_RBX]); - st->cr(); - st->print_cr("RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]); - print_location(st, uc->uc_mcontext.gregs[REG_RCX]); - st->cr(); - st->print_cr("RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]); - print_location(st, uc->uc_mcontext.gregs[REG_RDX]); - st->cr(); - st->print_cr("RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]); - print_location(st, uc->uc_mcontext.gregs[REG_RSP]); - st->cr(); - st->print_cr("RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]); - print_location(st, uc->uc_mcontext.gregs[REG_RBP]); - st->cr(); - st->print_cr("RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]); - print_location(st, uc->uc_mcontext.gregs[REG_RSI]); - st->cr(); - st->print_cr("RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]); - print_location(st, uc->uc_mcontext.gregs[REG_RDI]); - st->cr(); - st->print_cr("R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); - print_location(st, uc->uc_mcontext.gregs[REG_R8]); - st->cr(); - st->print_cr("R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); - print_location(st, uc->uc_mcontext.gregs[REG_R9]); - st->cr(); - st->print_cr("R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]); - print_location(st, uc->uc_mcontext.gregs[REG_R10]); - st->cr(); - st->print_cr("R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]); - print_location(st, uc->uc_mcontext.gregs[REG_R11]); - st->cr(); - st->print_cr("R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]); - print_location(st, uc->uc_mcontext.gregs[REG_R12]); - st->cr(); - st->print_cr("R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]); - print_location(st, uc->uc_mcontext.gregs[REG_R13]); - st->cr(); - st->print_cr("R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]); - print_location(st, uc->uc_mcontext.gregs[REG_R14]); - st->cr(); - st->print_cr("R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]); - print_location(st, uc->uc_mcontext.gregs[REG_R15]); - #else st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]); st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]); @@ -819,41 +757,8 @@ st->print(", EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDI]); st->cr(); st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EIP]); + st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); st->print(", CR2=" INTPTR_FORMAT, uc->uc_mcontext.cr2); - st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EFL]); - - st->cr(); - st->cr(); - - st->print_cr("Register to memory mapping:"); - st->cr(); - - // this is only for the "general purpose" registers - - st->print_cr("EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EAX]); - print_location(st, uc->uc_mcontext.gregs[REG_EAX]); - st->cr(); - st->print_cr("EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBX]); - print_location(st, uc->uc_mcontext.gregs[REG_EBX]); - st->cr(); - st->print_cr("ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ECX]); - print_location(st, uc->uc_mcontext.gregs[REG_ECX]); - st->cr(); - st->print_cr("EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDX]); - print_location(st, uc->uc_mcontext.gregs[REG_EDX]); - st->cr(); - st->print_cr("ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ESP]); - print_location(st, uc->uc_mcontext.gregs[REG_ESP]); - st->cr(); - st->print_cr("EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EBP]); - print_location(st, uc->uc_mcontext.gregs[REG_EBP]); - st->cr(); - st->print_cr("ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_ESI]); - print_location(st, uc->uc_mcontext.gregs[REG_ESI]); - st->cr(); - st->print_cr("EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_EDI]); - print_location(st, uc->uc_mcontext.gregs[REG_EDI]); - #endif // AMD64 st->cr(); st->cr(); @@ -868,7 +773,52 @@ // this at the end, and hope for the best. address pc = os::Linux::ucontext_get_pc(uc); st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); - print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); + print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); +} + +void os::print_register_info(outputStream *st, void *context) { + if (context == NULL) return; + + ucontext_t *uc = (ucontext_t*)context; + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is horrendously verbose but the layout of the registers in the + // context does not match how we defined our abstract Register set, so + // we can't just iterate through the gregs area + + // this is only for the "general purpose" registers + +#ifdef AMD64 + st->print("RAX="); print_location(st, uc->uc_mcontext.gregs[REG_RAX]); + st->print("RBX="); print_location(st, uc->uc_mcontext.gregs[REG_RBX]); + st->print("RCX="); print_location(st, uc->uc_mcontext.gregs[REG_RCX]); + st->print("RDX="); print_location(st, uc->uc_mcontext.gregs[REG_RDX]); + st->print("RSP="); print_location(st, uc->uc_mcontext.gregs[REG_RSP]); + st->print("RBP="); print_location(st, uc->uc_mcontext.gregs[REG_RBP]); + st->print("RSI="); print_location(st, uc->uc_mcontext.gregs[REG_RSI]); + st->print("RDI="); print_location(st, uc->uc_mcontext.gregs[REG_RDI]); + st->print("R8 ="); print_location(st, uc->uc_mcontext.gregs[REG_R8]); + st->print("R9 ="); print_location(st, uc->uc_mcontext.gregs[REG_R9]); + st->print("R10="); print_location(st, uc->uc_mcontext.gregs[REG_R10]); + st->print("R11="); print_location(st, uc->uc_mcontext.gregs[REG_R11]); + st->print("R12="); print_location(st, uc->uc_mcontext.gregs[REG_R12]); + st->print("R13="); print_location(st, uc->uc_mcontext.gregs[REG_R13]); + st->print("R14="); print_location(st, uc->uc_mcontext.gregs[REG_R14]); + st->print("R15="); print_location(st, uc->uc_mcontext.gregs[REG_R15]); +#else + st->print("EAX="); print_location(st, uc->uc_mcontext.gregs[REG_EAX]); + st->print("EBX="); print_location(st, uc->uc_mcontext.gregs[REG_EBX]); + st->print("ECX="); print_location(st, uc->uc_mcontext.gregs[REG_ECX]); + st->print("EDX="); print_location(st, uc->uc_mcontext.gregs[REG_EDX]); + st->print("ESP="); print_location(st, uc->uc_mcontext.gregs[REG_ESP]); + st->print("EBP="); print_location(st, uc->uc_mcontext.gregs[REG_EBP]); + st->print("ESI="); print_location(st, uc->uc_mcontext.gregs[REG_ESI]); + st->print("EDI="); print_location(st, uc->uc_mcontext.gregs[REG_EDI]); +#endif // AMD64 + + st->cr(); } void os::setup_fpu() { diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -540,6 +540,11 @@ pc = (address) uc->uc_mcontext.gregs[REG_PC]; } + // Sometimes the register windows are not properly flushed. + if(uc->uc_mcontext.gwins != NULL) { + ::handle_unflushed_register_windows(uc->uc_mcontext.gwins); + } + // unmask current signal sigset_t newset; sigemptyset(&newset); @@ -558,6 +563,18 @@ ucontext_t *uc = (ucontext_t*)context; st->print_cr("Registers:"); + st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT + " G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT, + uc->uc_mcontext.gregs[REG_G1], + uc->uc_mcontext.gregs[REG_G2], + uc->uc_mcontext.gregs[REG_G3], + uc->uc_mcontext.gregs[REG_G4]); + st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT + " G7=" INTPTR_FORMAT " Y=" INTPTR_FORMAT, + uc->uc_mcontext.gregs[REG_G5], + uc->uc_mcontext.gregs[REG_G6], + uc->uc_mcontext.gregs[REG_G7], + uc->uc_mcontext.gregs[REG_Y]); st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT " O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O0], @@ -571,81 +588,39 @@ uc->uc_mcontext.gregs[REG_O6], uc->uc_mcontext.gregs[REG_O7]); - st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT - " G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT, - uc->uc_mcontext.gregs[REG_G1], - uc->uc_mcontext.gregs[REG_G2], - uc->uc_mcontext.gregs[REG_G3], - uc->uc_mcontext.gregs[REG_G4]); - st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT - " G7=" INTPTR_FORMAT " Y=" INTPTR_FORMAT, - uc->uc_mcontext.gregs[REG_G5], - uc->uc_mcontext.gregs[REG_G6], - uc->uc_mcontext.gregs[REG_G7], - uc->uc_mcontext.gregs[REG_Y]); + + intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc); + st->print_cr(" L0=" INTPTR_FORMAT " L1=" INTPTR_FORMAT + " L2=" INTPTR_FORMAT " L3=" INTPTR_FORMAT, + sp[L0->sp_offset_in_saved_window()], + sp[L1->sp_offset_in_saved_window()], + sp[L2->sp_offset_in_saved_window()], + sp[L3->sp_offset_in_saved_window()]); + st->print_cr(" L4=" INTPTR_FORMAT " L5=" INTPTR_FORMAT + " L6=" INTPTR_FORMAT " L7=" INTPTR_FORMAT, + sp[L4->sp_offset_in_saved_window()], + sp[L5->sp_offset_in_saved_window()], + sp[L6->sp_offset_in_saved_window()], + sp[L7->sp_offset_in_saved_window()]); + st->print_cr(" I0=" INTPTR_FORMAT " I1=" INTPTR_FORMAT + " I2=" INTPTR_FORMAT " I3=" INTPTR_FORMAT, + sp[I0->sp_offset_in_saved_window()], + sp[I1->sp_offset_in_saved_window()], + sp[I2->sp_offset_in_saved_window()], + sp[I3->sp_offset_in_saved_window()]); + st->print_cr(" I4=" INTPTR_FORMAT " I5=" INTPTR_FORMAT + " I6=" INTPTR_FORMAT " I7=" INTPTR_FORMAT, + sp[I4->sp_offset_in_saved_window()], + sp[I5->sp_offset_in_saved_window()], + sp[I6->sp_offset_in_saved_window()], + sp[I7->sp_offset_in_saved_window()]); st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_PC], uc->uc_mcontext.gregs[REG_nPC]); - st->cr(); st->cr(); - st->print_cr("Register to memory mapping:"); - st->cr(); - - // this is only for the "general purpose" registers - - st->print_cr("O0=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O0]); - print_location(st, uc->uc_mcontext.gregs[REG_O0]); - st->cr(); - st->print_cr("O1=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O1]); - print_location(st, uc->uc_mcontext.gregs[REG_O1]); - st->cr(); - st->print_cr("O2=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O2]); - print_location(st, uc->uc_mcontext.gregs[REG_O2]); - st->cr(); - st->print_cr("O3=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O3]); - print_location(st, uc->uc_mcontext.gregs[REG_O3]); - st->cr(); - st->print_cr("O4=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O4]); - print_location(st, uc->uc_mcontext.gregs[REG_O4]); - st->cr(); - st->print_cr("O5=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O5]); - print_location(st, uc->uc_mcontext.gregs[REG_O5]); - st->cr(); - st->print_cr("O6=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O6]); - print_location(st, uc->uc_mcontext.gregs[REG_O6]); - st->cr(); - st->print_cr("O7=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_O7]); - print_location(st, uc->uc_mcontext.gregs[REG_O7]); - st->cr(); - - st->print_cr("G1=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G1]); - print_location(st, uc->uc_mcontext.gregs[REG_G1]); - st->cr(); - st->print_cr("G2=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G2]); - print_location(st, uc->uc_mcontext.gregs[REG_G2]); - st->cr(); - st->print_cr("G3=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G3]); - print_location(st, uc->uc_mcontext.gregs[REG_G3]); - st->cr(); - st->print_cr("G4=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G4]); - print_location(st, uc->uc_mcontext.gregs[REG_G4]); - st->cr(); - st->print_cr("G5=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G5]); - print_location(st, uc->uc_mcontext.gregs[REG_G5]); - st->cr(); - st->print_cr("G6=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G6]); - print_location(st, uc->uc_mcontext.gregs[REG_G6]); - st->cr(); - st->print_cr("G7=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_G7]); - print_location(st, uc->uc_mcontext.gregs[REG_G7]); - - st->cr(); - st->cr(); - - intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc); st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp); print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t)); st->cr(); @@ -656,7 +631,57 @@ ExtendedPC epc = os::Solaris::ucontext_get_ExtendedPC(uc); address pc = epc.pc(); st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); - print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); + print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); +} + +void os::print_register_info(outputStream *st, void *context) { + if (context == NULL) return; + + ucontext_t *uc = (ucontext_t*)context; + intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc); + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is only for the "general purpose" registers + st->print("G1="); print_location(st, uc->uc_mcontext.gregs[REG_G1]); + st->print("G2="); print_location(st, uc->uc_mcontext.gregs[REG_G2]); + st->print("G3="); print_location(st, uc->uc_mcontext.gregs[REG_G3]); + st->print("G4="); print_location(st, uc->uc_mcontext.gregs[REG_G4]); + st->print("G5="); print_location(st, uc->uc_mcontext.gregs[REG_G5]); + st->print("G6="); print_location(st, uc->uc_mcontext.gregs[REG_G6]); + st->print("G7="); print_location(st, uc->uc_mcontext.gregs[REG_G7]); + st->cr(); + + st->print("O0="); print_location(st, uc->uc_mcontext.gregs[REG_O0]); + st->print("O1="); print_location(st, uc->uc_mcontext.gregs[REG_O1]); + st->print("O2="); print_location(st, uc->uc_mcontext.gregs[REG_O2]); + st->print("O3="); print_location(st, uc->uc_mcontext.gregs[REG_O3]); + st->print("O4="); print_location(st, uc->uc_mcontext.gregs[REG_O4]); + st->print("O5="); print_location(st, uc->uc_mcontext.gregs[REG_O5]); + st->print("O6="); print_location(st, uc->uc_mcontext.gregs[REG_O6]); + st->print("O7="); print_location(st, uc->uc_mcontext.gregs[REG_O7]); + st->cr(); + + st->print("L0="); print_location(st, sp[L0->sp_offset_in_saved_window()]); + st->print("L1="); print_location(st, sp[L1->sp_offset_in_saved_window()]); + st->print("L2="); print_location(st, sp[L2->sp_offset_in_saved_window()]); + st->print("L3="); print_location(st, sp[L3->sp_offset_in_saved_window()]); + st->print("L4="); print_location(st, sp[L4->sp_offset_in_saved_window()]); + st->print("L5="); print_location(st, sp[L5->sp_offset_in_saved_window()]); + st->print("L6="); print_location(st, sp[L6->sp_offset_in_saved_window()]); + st->print("L7="); print_location(st, sp[L7->sp_offset_in_saved_window()]); + st->cr(); + + st->print("I0="); print_location(st, sp[I0->sp_offset_in_saved_window()]); + st->print("I1="); print_location(st, sp[I1->sp_offset_in_saved_window()]); + st->print("I2="); print_location(st, sp[I2->sp_offset_in_saved_window()]); + st->print("I3="); print_location(st, sp[I3->sp_offset_in_saved_window()]); + st->print("I4="); print_location(st, sp[I4->sp_offset_in_saved_window()]); + st->print("I5="); print_location(st, sp[I5->sp_offset_in_saved_window()]); + st->print("I6="); print_location(st, sp[I6->sp_offset_in_saved_window()]); + st->print("I7="); print_location(st, sp[I7->sp_offset_in_saved_window()]); + st->cr(); } void os::Solaris::init_thread_fpu_state(void) { diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp --- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,10 +65,6 @@ // getisax(2), SI_ARCHITECTURE_32, and SI_ARCHITECTURE_64 are // supported on Solaris 10 and later. if (os::Solaris::supports_getisax()) { -#ifndef PRODUCT - if (PrintMiscellaneous && Verbose) - tty->print_cr("getisax(2) supported."); -#endif // Check 32-bit architecture. do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m); @@ -81,6 +77,11 @@ uint_t avn = os::Solaris::getisax(&av, 1); assert(avn == 1, "should only return one av"); +#ifndef PRODUCT + if (PrintMiscellaneous && Verbose) + tty->print_cr("getisax(2) returned: " PTR32_FORMAT, av); +#endif + if (av & AV_SPARC_MUL32) features |= hardware_mul32_m; if (av & AV_SPARC_DIV32) features |= hardware_div32_m; if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m; @@ -88,11 +89,22 @@ if (av & AV_SPARC_POPC) features |= hardware_popc_m; if (av & AV_SPARC_VIS) features |= vis1_instructions_m; if (av & AV_SPARC_VIS2) features |= vis2_instructions_m; + + // Next values are not defined before Solaris 10 + // but Solaris 8 is used for jdk6 update builds. +#ifndef AV_SPARC_ASI_BLK_INIT +#define AV_SPARC_ASI_BLK_INIT 0x0080 /* ASI_BLK_INIT_xxx ASI */ +#endif +#ifndef AV_SPARC_FMAF +#define AV_SPARC_FMAF 0x0100 /* Sparc64 Fused Multiply-Add */ +#endif + if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m; + if (av & AV_SPARC_FMAF) features |= fmaf_instructions_m; } else { // getisax(2) failed, use the old legacy code. #ifndef PRODUCT if (PrintMiscellaneous && Verbose) - tty->print_cr("getisax(2) not supported."); + tty->print_cr("getisax(2) is not supported."); #endif char tmp; diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -719,11 +719,6 @@ ucontext_t *uc = (ucontext_t*)context; st->print_cr("Registers:"); - - // this is horrendously verbose but the layout of the registers in the - // context does not match how we defined our abstract Register set, so - // we can't just iterate through the gregs area - #ifdef AMD64 st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); @@ -735,8 +730,8 @@ st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]); st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]); st->cr(); - st->print( "R8=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); - st->print(", R9=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); + st->print( "R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); + st->print(", R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]); st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]); st->cr(); @@ -747,63 +742,6 @@ st->cr(); st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]); st->print(", RFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RFL]); - - st->cr(); - st->cr(); - - st->print_cr("Register to memory mapping:"); - st->cr(); - - // this is only for the "general purpose" registers - - st->print_cr("RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); - print_location(st, uc->uc_mcontext.gregs[REG_RAX]); - st->cr(); - st->print_cr("RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); - print_location(st, uc->uc_mcontext.gregs[REG_RBX]); - st->cr(); - st->print_cr("RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]); - print_location(st, uc->uc_mcontext.gregs[REG_RCX]); - st->cr(); - st->print_cr("RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]); - print_location(st, uc->uc_mcontext.gregs[REG_RDX]); - st->cr(); - st->print_cr("RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]); - print_location(st, uc->uc_mcontext.gregs[REG_RSP]); - st->cr(); - st->print_cr("RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]); - print_location(st, uc->uc_mcontext.gregs[REG_RSP]); - st->cr(); - st->print_cr("RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]); - print_location(st, uc->uc_mcontext.gregs[REG_RSI]); - st->cr(); - st->print_cr("RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]); - print_location(st, uc->uc_mcontext.gregs[REG_RDI]); - st->cr(); - st->print_cr("R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); - print_location(st, uc->uc_mcontext.gregs[REG_R8]); - st->cr(); - st->print_cr("R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); - print_location(st, uc->uc_mcontext.gregs[REG_R9]); - st->cr(); - st->print_cr("R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]); - print_location(st, uc->uc_mcontext.gregs[REG_R10]); - st->cr(); - st->print_cr("R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]); - print_location(st, uc->uc_mcontext.gregs[REG_R11]); - st->cr(); - st->print_cr("R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]); - print_location(st, uc->uc_mcontext.gregs[REG_R12]); - st->cr(); - st->print_cr("R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]); - print_location(st, uc->uc_mcontext.gregs[REG_R13]); - st->cr(); - st->print_cr("R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]); - print_location(st, uc->uc_mcontext.gregs[REG_R14]); - st->cr(); - st->print_cr("R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]); - print_location(st, uc->uc_mcontext.gregs[REG_R15]); - #else st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]); st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]); @@ -817,39 +755,6 @@ st->cr(); st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EIP]); st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EFL]); - - st->cr(); - st->cr(); - - st->print_cr("Register to memory mapping:"); - st->cr(); - - // this is only for the "general purpose" registers - - st->print_cr("EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]); - print_location(st, uc->uc_mcontext.gregs[EAX]); - st->cr(); - st->print_cr("EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]); - print_location(st, uc->uc_mcontext.gregs[EBX]); - st->cr(); - st->print_cr("ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ECX]); - print_location(st, uc->uc_mcontext.gregs[ECX]); - st->cr(); - st->print_cr("EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDX]); - print_location(st, uc->uc_mcontext.gregs[EDX]); - st->cr(); - st->print_cr("ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[UESP]); - print_location(st, uc->uc_mcontext.gregs[UESP]); - st->cr(); - st->print_cr("EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBP]); - print_location(st, uc->uc_mcontext.gregs[EBP]); - st->cr(); - st->print_cr("ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ESI]); - print_location(st, uc->uc_mcontext.gregs[ESI]); - st->cr(); - st->print_cr("EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDI]); - print_location(st, uc->uc_mcontext.gregs[EDI]); - #endif // AMD64 st->cr(); st->cr(); @@ -865,7 +770,52 @@ ExtendedPC epc = os::Solaris::ucontext_get_ExtendedPC(uc); address pc = epc.pc(); st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); - print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); + print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); +} + +void os::print_register_info(outputStream *st, void *context) { + if (context == NULL) return; + + ucontext_t *uc = (ucontext_t*)context; + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is horrendously verbose but the layout of the registers in the + // context does not match how we defined our abstract Register set, so + // we can't just iterate through the gregs area + + // this is only for the "general purpose" registers + +#ifdef AMD64 + st->print("RAX="); print_location(st, uc->uc_mcontext.gregs[REG_RAX]); + st->print("RBX="); print_location(st, uc->uc_mcontext.gregs[REG_RBX]); + st->print("RCX="); print_location(st, uc->uc_mcontext.gregs[REG_RCX]); + st->print("RDX="); print_location(st, uc->uc_mcontext.gregs[REG_RDX]); + st->print("RSP="); print_location(st, uc->uc_mcontext.gregs[REG_RSP]); + st->print("RBP="); print_location(st, uc->uc_mcontext.gregs[REG_RBP]); + st->print("RSI="); print_location(st, uc->uc_mcontext.gregs[REG_RSI]); + st->print("RDI="); print_location(st, uc->uc_mcontext.gregs[REG_RDI]); + st->print("R8 ="); print_location(st, uc->uc_mcontext.gregs[REG_R8]); + st->print("R9 ="); print_location(st, uc->uc_mcontext.gregs[REG_R9]); + st->print("R10="); print_location(st, uc->uc_mcontext.gregs[REG_R10]); + st->print("R11="); print_location(st, uc->uc_mcontext.gregs[REG_R11]); + st->print("R12="); print_location(st, uc->uc_mcontext.gregs[REG_R12]); + st->print("R13="); print_location(st, uc->uc_mcontext.gregs[REG_R13]); + st->print("R14="); print_location(st, uc->uc_mcontext.gregs[REG_R14]); + st->print("R15="); print_location(st, uc->uc_mcontext.gregs[REG_R15]); +#else + st->print("EAX="); print_location(st, uc->uc_mcontext.gregs[EAX]); + st->print("EBX="); print_location(st, uc->uc_mcontext.gregs[EBX]); + st->print("ECX="); print_location(st, uc->uc_mcontext.gregs[ECX]); + st->print("EDX="); print_location(st, uc->uc_mcontext.gregs[EDX]); + st->print("ESP="); print_location(st, uc->uc_mcontext.gregs[UESP]); + st->print("EBP="); print_location(st, uc->uc_mcontext.gregs[EBP]); + st->print("ESI="); print_location(st, uc->uc_mcontext.gregs[ESI]); + st->print("EDI="); print_location(st, uc->uc_mcontext.gregs[EDI]); +#endif + + st->cr(); } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -387,8 +387,8 @@ st->print(", RSI=" INTPTR_FORMAT, uc->Rsi); st->print(", RDI=" INTPTR_FORMAT, uc->Rdi); st->cr(); - st->print( "R8=" INTPTR_FORMAT, uc->R8); - st->print(", R9=" INTPTR_FORMAT, uc->R9); + st->print( "R8 =" INTPTR_FORMAT, uc->R8); + st->print(", R9 =" INTPTR_FORMAT, uc->R9); st->print(", R10=" INTPTR_FORMAT, uc->R10); st->print(", R11=" INTPTR_FORMAT, uc->R11); st->cr(); @@ -399,62 +399,6 @@ st->cr(); st->print( "RIP=" INTPTR_FORMAT, uc->Rip); st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags); - - st->cr(); - st->cr(); - - st->print_cr("Register to memory mapping:"); - st->cr(); - - // this is only for the "general purpose" registers - - st->print_cr("RAX=" INTPTR_FORMAT, uc->Rax); - print_location(st, uc->Rax); - st->cr(); - st->print_cr("RBX=" INTPTR_FORMAT, uc->Rbx); - print_location(st, uc->Rbx); - st->cr(); - st->print_cr("RCX=" INTPTR_FORMAT, uc->Rcx); - print_location(st, uc->Rcx); - st->cr(); - st->print_cr("RDX=" INTPTR_FORMAT, uc->Rdx); - print_location(st, uc->Rdx); - st->cr(); - st->print_cr("RSP=" INTPTR_FORMAT, uc->Rsp); - print_location(st, uc->Rsp); - st->cr(); - st->print_cr("RBP=" INTPTR_FORMAT, uc->Rbp); - print_location(st, uc->Rbp); - st->cr(); - st->print_cr("RSI=" INTPTR_FORMAT, uc->Rsi); - print_location(st, uc->Rsi); - st->cr(); - st->print_cr("RDI=" INTPTR_FORMAT, uc->Rdi); - print_location(st, uc->Rdi); - st->cr(); - st->print_cr("R8 =" INTPTR_FORMAT, uc->R8); - print_location(st, uc->R8); - st->cr(); - st->print_cr("R9 =" INTPTR_FORMAT, uc->R9); - print_location(st, uc->R9); - st->cr(); - st->print_cr("R10=" INTPTR_FORMAT, uc->R10); - print_location(st, uc->R10); - st->cr(); - st->print_cr("R11=" INTPTR_FORMAT, uc->R11); - print_location(st, uc->R11); - st->cr(); - st->print_cr("R12=" INTPTR_FORMAT, uc->R12); - print_location(st, uc->R12); - st->cr(); - st->print_cr("R13=" INTPTR_FORMAT, uc->R13); - print_location(st, uc->R13); - st->cr(); - st->print_cr("R14=" INTPTR_FORMAT, uc->R14); - print_location(st, uc->R14); - st->cr(); - st->print_cr("R15=" INTPTR_FORMAT, uc->R15); - print_location(st, uc->R15); #else st->print( "EAX=" INTPTR_FORMAT, uc->Eax); st->print(", EBX=" INTPTR_FORMAT, uc->Ebx); @@ -468,38 +412,6 @@ st->cr(); st->print( "EIP=" INTPTR_FORMAT, uc->Eip); st->print(", EFLAGS=" INTPTR_FORMAT, uc->EFlags); - - st->cr(); - st->cr(); - - st->print_cr("Register to memory mapping:"); - st->cr(); - - // this is only for the "general purpose" registers - - st->print_cr("EAX=" INTPTR_FORMAT, uc->Eax); - print_location(st, uc->Eax); - st->cr(); - st->print_cr("EBX=" INTPTR_FORMAT, uc->Ebx); - print_location(st, uc->Ebx); - st->cr(); - st->print_cr("ECX=" INTPTR_FORMAT, uc->Ecx); - print_location(st, uc->Ecx); - st->cr(); - st->print_cr("EDX=" INTPTR_FORMAT, uc->Edx); - print_location(st, uc->Edx); - st->cr(); - st->print_cr("ESP=" INTPTR_FORMAT, uc->Esp); - print_location(st, uc->Esp); - st->cr(); - st->print_cr("EBP=" INTPTR_FORMAT, uc->Ebp); - print_location(st, uc->Ebp); - st->cr(); - st->print_cr("ESI=" INTPTR_FORMAT, uc->Esi); - print_location(st, uc->Esi); - st->cr(); - st->print_cr("EDI=" INTPTR_FORMAT, uc->Edi); - print_location(st, uc->Edi); #endif // AMD64 st->cr(); st->cr(); @@ -514,7 +426,49 @@ // this at the end, and hope for the best. address pc = (address)uc->REG_PC; st->print_cr("Instructions: (pc=" PTR_FORMAT ")", pc); - print_hex_dump(st, pc - 16, pc + 16, sizeof(char)); + print_hex_dump(st, pc - 32, pc + 32, sizeof(char)); + st->cr(); +} + + +void os::print_register_info(outputStream *st, void *context) { + if (context == NULL) return; + + CONTEXT* uc = (CONTEXT*)context; + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is only for the "general purpose" registers + +#ifdef AMD64 + st->print("RAX="); print_location(st, uc->Rax); + st->print("RBX="); print_location(st, uc->Rbx); + st->print("RCX="); print_location(st, uc->Rcx); + st->print("RDX="); print_location(st, uc->Rdx); + st->print("RSP="); print_location(st, uc->Rsp); + st->print("RBP="); print_location(st, uc->Rbp); + st->print("RSI="); print_location(st, uc->Rsi); + st->print("RDI="); print_location(st, uc->Rdi); + st->print("R8 ="); print_location(st, uc->R8); + st->print("R9 ="); print_location(st, uc->R9); + st->print("R10="); print_location(st, uc->R10); + st->print("R11="); print_location(st, uc->R11); + st->print("R12="); print_location(st, uc->R12); + st->print("R13="); print_location(st, uc->R13); + st->print("R14="); print_location(st, uc->R14); + st->print("R15="); print_location(st, uc->R15); +#else + st->print("EAX="); print_location(st, uc->Eax); + st->print("EBX="); print_location(st, uc->Ebx); + st->print("ECX="); print_location(st, uc->Ecx); + st->print("EDX="); print_location(st, uc->Edx); + st->print("ESP="); print_location(st, uc->Esp); + st->print("EBP="); print_location(st, uc->Ebp); + st->print("ESI="); print_location(st, uc->Esi); + st->print("EDI="); print_location(st, uc->Edi); +#endif + st->cr(); } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/c1/c1_Compilation.hpp --- a/hotspot/src/share/vm/c1/c1_Compilation.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_Compilation.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -178,15 +178,11 @@ return (int) NMethodSizeLimit; // default 256K or 512K #else // conditional branches on PPC are restricted to 16 bit signed - return MAX2((unsigned int)NMethodSizeLimit,32*K); + return MIN2((unsigned int)NMethodSizeLimit,32*K); #endif } static int desired_max_constant_size() { -#ifndef PPC - return (int) NMethodSizeLimit / 10; // about 25K -#else - return (MAX2((unsigned int)NMethodSizeLimit, 32*K)) / 10; -#endif + return desired_max_code_buffer_size() / 10; } static void setup_code_buffer(CodeBuffer* cb, int call_stub_estimate); diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/c1/c1_IR.cpp --- a/hotspot/src/share/vm/c1/c1_IR.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_IR.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -321,7 +321,7 @@ void visit(Value* n) { // Local instructions and Phis for expression stack values at the // start of basic blocks are not added to the instruction list - if (!(*n)->is_linked()&& (*n)->can_be_linked()) { + if (!(*n)->is_linked() && (*n)->can_be_linked()) { assert(false, "a node was not appended to the graph"); Compilation::current()->bailout("a node was not appended to the graph"); } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/c1/c1_Instruction.cpp --- a/hotspot/src/share/vm/c1/c1_Instruction.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_Instruction.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -415,28 +415,26 @@ return false; } - -BlockBegin* Constant::compare(Instruction::Condition cond, Value right, - BlockBegin* true_sux, BlockBegin* false_sux) { +Constant::CompareResult Constant::compare(Instruction::Condition cond, Value right) const { Constant* rc = right->as_Constant(); // other is not a constant - if (rc == NULL) return NULL; + if (rc == NULL) return not_comparable; ValueType* lt = type(); ValueType* rt = rc->type(); // different types - if (lt->base() != rt->base()) return NULL; + if (lt->base() != rt->base()) return not_comparable; switch (lt->tag()) { case intTag: { int x = lt->as_IntConstant()->value(); int y = rt->as_IntConstant()->value(); switch (cond) { - case If::eql: return x == y ? true_sux : false_sux; - case If::neq: return x != y ? true_sux : false_sux; - case If::lss: return x < y ? true_sux : false_sux; - case If::leq: return x <= y ? true_sux : false_sux; - case If::gtr: return x > y ? true_sux : false_sux; - case If::geq: return x >= y ? true_sux : false_sux; + case If::eql: return x == y ? cond_true : cond_false; + case If::neq: return x != y ? cond_true : cond_false; + case If::lss: return x < y ? cond_true : cond_false; + case If::leq: return x <= y ? cond_true : cond_false; + case If::gtr: return x > y ? cond_true : cond_false; + case If::geq: return x >= y ? cond_true : cond_false; } break; } @@ -444,12 +442,12 @@ jlong x = lt->as_LongConstant()->value(); jlong y = rt->as_LongConstant()->value(); switch (cond) { - case If::eql: return x == y ? true_sux : false_sux; - case If::neq: return x != y ? true_sux : false_sux; - case If::lss: return x < y ? true_sux : false_sux; - case If::leq: return x <= y ? true_sux : false_sux; - case If::gtr: return x > y ? true_sux : false_sux; - case If::geq: return x >= y ? true_sux : false_sux; + case If::eql: return x == y ? cond_true : cond_false; + case If::neq: return x != y ? cond_true : cond_false; + case If::lss: return x < y ? cond_true : cond_false; + case If::leq: return x <= y ? cond_true : cond_false; + case If::gtr: return x > y ? cond_true : cond_false; + case If::geq: return x >= y ? cond_true : cond_false; } break; } @@ -459,14 +457,14 @@ assert(xvalue != NULL && yvalue != NULL, "not constants"); if (xvalue->is_loaded() && yvalue->is_loaded()) { switch (cond) { - case If::eql: return xvalue == yvalue ? true_sux : false_sux; - case If::neq: return xvalue != yvalue ? true_sux : false_sux; + case If::eql: return xvalue == yvalue ? cond_true : cond_false; + case If::neq: return xvalue != yvalue ? cond_true : cond_false; } } break; } } - return NULL; + return not_comparable; } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/c1/c1_Instruction.hpp --- a/hotspot/src/share/vm/c1/c1_Instruction.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_Instruction.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -443,7 +443,7 @@ // generic virtual Instruction* as_Instruction() { return this; } // to satisfy HASHING1 macro - virtual Phi* as_Phi() { return NULL; } + virtual Phi* as_Phi() { return NULL; } virtual Local* as_Local() { return NULL; } virtual Constant* as_Constant() { return NULL; } virtual AccessField* as_AccessField() { return NULL; } @@ -650,8 +650,24 @@ virtual intx hash() const; virtual bool is_equal(Value v) const; - virtual BlockBegin* compare(Instruction::Condition condition, Value right, - BlockBegin* true_sux, BlockBegin* false_sux); + + enum CompareResult { not_comparable = -1, cond_false, cond_true }; + + virtual CompareResult compare(Instruction::Condition condition, Value right) const; + BlockBegin* compare(Instruction::Condition cond, Value right, + BlockBegin* true_sux, BlockBegin* false_sux) const { + switch (compare(cond, right)) { + case not_comparable: + return NULL; + case cond_false: + return false_sux; + case cond_true: + return true_sux; + default: + ShouldNotReachHere(); + return NULL; + } + } }; diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/c1/c1_Optimizer.cpp --- a/hotspot/src/share/vm/c1/c1_Optimizer.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_Optimizer.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -38,18 +38,20 @@ private: IR* _hir; int _cee_count; // the number of CEs successfully eliminated + int _ifop_count; // the number of IfOps successfully simplified int _has_substitution; public: - CE_Eliminator(IR* hir) : _cee_count(0), _hir(hir) { + CE_Eliminator(IR* hir) : _cee_count(0), _ifop_count(0), _hir(hir) { _has_substitution = false; _hir->iterate_preorder(this); if (_has_substitution) { - // substituted some phis so resolve the substitution + // substituted some ifops/phis, so resolve the substitution SubstitutionResolver sr(_hir); } } int cee_count() const { return _cee_count; } + int ifop_count() const { return _ifop_count; } void adjust_exception_edges(BlockBegin* block, BlockBegin* sux) { int e = sux->number_of_exception_handlers(); @@ -68,156 +70,214 @@ } } - virtual void block_do(BlockBegin* block) { - // 1) find conditional expression - // check if block ends with an If - If* if_ = block->end()->as_If(); - if (if_ == NULL) return; + virtual void block_do(BlockBegin* block); + + private: + Value make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval); +}; - // check if If works on int or object types - // (we cannot handle If's working on long, float or doubles yet, - // since IfOp doesn't support them - these If's show up if cmp - // operations followed by If's are eliminated) - ValueType* if_type = if_->x()->type(); - if (!if_type->is_int() && !if_type->is_object()) return; +void CE_Eliminator::block_do(BlockBegin* block) { + // 1) find conditional expression + // check if block ends with an If + If* if_ = block->end()->as_If(); + if (if_ == NULL) return; - BlockBegin* t_block = if_->tsux(); - BlockBegin* f_block = if_->fsux(); - Instruction* t_cur = t_block->next(); - Instruction* f_cur = f_block->next(); + // check if If works on int or object types + // (we cannot handle If's working on long, float or doubles yet, + // since IfOp doesn't support them - these If's show up if cmp + // operations followed by If's are eliminated) + ValueType* if_type = if_->x()->type(); + if (!if_type->is_int() && !if_type->is_object()) return; - // one Constant may be present between BlockBegin and BlockEnd - Value t_const = NULL; - Value f_const = NULL; - if (t_cur->as_Constant() != NULL && !t_cur->can_trap()) { - t_const = t_cur; - t_cur = t_cur->next(); - } - if (f_cur->as_Constant() != NULL && !f_cur->can_trap()) { - f_const = f_cur; - f_cur = f_cur->next(); - } + BlockBegin* t_block = if_->tsux(); + BlockBegin* f_block = if_->fsux(); + Instruction* t_cur = t_block->next(); + Instruction* f_cur = f_block->next(); - // check if both branches end with a goto - Goto* t_goto = t_cur->as_Goto(); - if (t_goto == NULL) return; - Goto* f_goto = f_cur->as_Goto(); - if (f_goto == NULL) return; + // one Constant may be present between BlockBegin and BlockEnd + Value t_const = NULL; + Value f_const = NULL; + if (t_cur->as_Constant() != NULL && !t_cur->can_trap()) { + t_const = t_cur; + t_cur = t_cur->next(); + } + if (f_cur->as_Constant() != NULL && !f_cur->can_trap()) { + f_const = f_cur; + f_cur = f_cur->next(); + } - // check if both gotos merge into the same block - BlockBegin* sux = t_goto->default_sux(); - if (sux != f_goto->default_sux()) return; + // check if both branches end with a goto + Goto* t_goto = t_cur->as_Goto(); + if (t_goto == NULL) return; + Goto* f_goto = f_cur->as_Goto(); + if (f_goto == NULL) return; - // check if at least one word was pushed on sux_state - ValueStack* sux_state = sux->state(); - if (sux_state->stack_size() <= if_->state()->stack_size()) return; + // check if both gotos merge into the same block + BlockBegin* sux = t_goto->default_sux(); + if (sux != f_goto->default_sux()) return; - // check if phi function is present at end of successor stack and that - // only this phi was pushed on the stack - Value sux_phi = sux_state->stack_at(if_->state()->stack_size()); - if (sux_phi == NULL || sux_phi->as_Phi() == NULL || sux_phi->as_Phi()->block() != sux) return; - if (sux_phi->type()->size() != sux_state->stack_size() - if_->state()->stack_size()) return; - - // get the values that were pushed in the true- and false-branch - Value t_value = t_goto->state()->stack_at(if_->state()->stack_size()); - Value f_value = f_goto->state()->stack_at(if_->state()->stack_size()); + // check if at least one word was pushed on sux_state + ValueStack* sux_state = sux->state(); + if (sux_state->stack_size() <= if_->state()->stack_size()) return; - // backend does not support floats - assert(t_value->type()->base() == f_value->type()->base(), "incompatible types"); - if (t_value->type()->is_float_kind()) return; + // check if phi function is present at end of successor stack and that + // only this phi was pushed on the stack + Value sux_phi = sux_state->stack_at(if_->state()->stack_size()); + if (sux_phi == NULL || sux_phi->as_Phi() == NULL || sux_phi->as_Phi()->block() != sux) return; + if (sux_phi->type()->size() != sux_state->stack_size() - if_->state()->stack_size()) return; - // check that successor has no other phi functions but sux_phi - // this can happen when t_block or f_block contained additonal stores to local variables - // that are no longer represented by explicit instructions - for_each_phi_fun(sux, phi, - if (phi != sux_phi) return; - ); - // true and false blocks can't have phis - for_each_phi_fun(t_block, phi, return; ); - for_each_phi_fun(f_block, phi, return; ); + // get the values that were pushed in the true- and false-branch + Value t_value = t_goto->state()->stack_at(if_->state()->stack_size()); + Value f_value = f_goto->state()->stack_at(if_->state()->stack_size()); + + // backend does not support floats + assert(t_value->type()->base() == f_value->type()->base(), "incompatible types"); + if (t_value->type()->is_float_kind()) return; - // 2) substitute conditional expression - // with an IfOp followed by a Goto - // cut if_ away and get node before - Instruction* cur_end = if_->prev(block); + // check that successor has no other phi functions but sux_phi + // this can happen when t_block or f_block contained additonal stores to local variables + // that are no longer represented by explicit instructions + for_each_phi_fun(sux, phi, + if (phi != sux_phi) return; + ); + // true and false blocks can't have phis + for_each_phi_fun(t_block, phi, return; ); + for_each_phi_fun(f_block, phi, return; ); + + // 2) substitute conditional expression + // with an IfOp followed by a Goto + // cut if_ away and get node before + Instruction* cur_end = if_->prev(block); - // append constants of true- and false-block if necessary - // clone constants because original block must not be destroyed - assert((t_value != f_const && f_value != t_const) || t_const == f_const, "mismatch"); - if (t_value == t_const) { - t_value = new Constant(t_const->type()); - NOT_PRODUCT(t_value->set_printable_bci(if_->printable_bci())); - cur_end = cur_end->set_next(t_value); - } - if (f_value == f_const) { - f_value = new Constant(f_const->type()); - NOT_PRODUCT(f_value->set_printable_bci(if_->printable_bci())); - cur_end = cur_end->set_next(f_value); - } + // append constants of true- and false-block if necessary + // clone constants because original block must not be destroyed + assert((t_value != f_const && f_value != t_const) || t_const == f_const, "mismatch"); + if (t_value == t_const) { + t_value = new Constant(t_const->type()); + NOT_PRODUCT(t_value->set_printable_bci(if_->printable_bci())); + cur_end = cur_end->set_next(t_value); + } + if (f_value == f_const) { + f_value = new Constant(f_const->type()); + NOT_PRODUCT(f_value->set_printable_bci(if_->printable_bci())); + cur_end = cur_end->set_next(f_value); + } - // it is very unlikely that the condition can be statically decided - // (this was checked previously by the Canonicalizer), so always - // append IfOp - Value result = new IfOp(if_->x(), if_->cond(), if_->y(), t_value, f_value); + Value result = make_ifop(if_->x(), if_->cond(), if_->y(), t_value, f_value); + assert(result != NULL, "make_ifop must return a non-null instruction"); + if (!result->is_linked() && result->can_be_linked()) { NOT_PRODUCT(result->set_printable_bci(if_->printable_bci())); cur_end = cur_end->set_next(result); + } - // append Goto to successor - ValueStack* state_before = if_->is_safepoint() ? if_->state_before() : NULL; - Goto* goto_ = new Goto(sux, state_before, if_->is_safepoint() || t_goto->is_safepoint() || f_goto->is_safepoint()); + // append Goto to successor + ValueStack* state_before = if_->is_safepoint() ? if_->state_before() : NULL; + Goto* goto_ = new Goto(sux, state_before, if_->is_safepoint() || t_goto->is_safepoint() || f_goto->is_safepoint()); + + // prepare state for Goto + ValueStack* goto_state = if_->state(); + while (sux_state->scope() != goto_state->scope()) { + goto_state = goto_state->caller_state(); + assert(goto_state != NULL, "states do not match up"); + } + goto_state = goto_state->copy(ValueStack::StateAfter, goto_state->bci()); + goto_state->push(result->type(), result); + assert(goto_state->is_same(sux_state), "states must match now"); + goto_->set_state(goto_state); + + cur_end = cur_end->set_next(goto_, goto_state->bci()); + + // Adjust control flow graph + BlockBegin::disconnect_edge(block, t_block); + BlockBegin::disconnect_edge(block, f_block); + if (t_block->number_of_preds() == 0) { + BlockBegin::disconnect_edge(t_block, sux); + } + adjust_exception_edges(block, t_block); + if (f_block->number_of_preds() == 0) { + BlockBegin::disconnect_edge(f_block, sux); + } + adjust_exception_edges(block, f_block); + + // update block end + block->set_end(goto_); + + // substitute the phi if possible + if (sux_phi->as_Phi()->operand_count() == 1) { + assert(sux_phi->as_Phi()->operand_at(0) == result, "screwed up phi"); + sux_phi->set_subst(result); + _has_substitution = true; + } + + // 3) successfully eliminated a conditional expression + _cee_count++; + if (PrintCEE) { + tty->print_cr("%d. CEE in B%d (B%d B%d)", cee_count(), block->block_id(), t_block->block_id(), f_block->block_id()); + tty->print_cr("%d. IfOp in B%d", ifop_count(), block->block_id()); + } - // prepare state for Goto - ValueStack* goto_state = if_->state(); - while (sux_state->scope() != goto_state->scope()) { - goto_state = goto_state->caller_state(); - assert(goto_state != NULL, "states do not match up"); - } - goto_state = goto_state->copy(ValueStack::StateAfter, goto_state->bci()); - goto_state->push(result->type(), result); - assert(goto_state->is_same(sux_state), "states must match now"); - goto_->set_state(goto_state); + _hir->verify(); +} + +Value CE_Eliminator::make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval) { + if (!OptimizeIfOps) { + return new IfOp(x, cond, y, tval, fval); + } + + tval = tval->subst(); + fval = fval->subst(); + if (tval == fval) { + _ifop_count++; + return tval; + } + + x = x->subst(); + y = y->subst(); + + Constant* y_const = y->as_Constant(); + if (y_const != NULL) { + IfOp* x_ifop = x->as_IfOp(); + if (x_ifop != NULL) { // x is an ifop, y is a constant + Constant* x_tval_const = x_ifop->tval()->subst()->as_Constant(); + Constant* x_fval_const = x_ifop->fval()->subst()->as_Constant(); - cur_end = cur_end->set_next(goto_, goto_state->bci()); + if (x_tval_const != NULL && x_fval_const != NULL) { + Instruction::Condition x_ifop_cond = x_ifop->cond(); + + Constant::CompareResult t_compare_res = x_tval_const->compare(cond, y_const); + Constant::CompareResult f_compare_res = x_fval_const->compare(cond, y_const); + + guarantee(t_compare_res != Constant::not_comparable && f_compare_res != Constant::not_comparable, "incomparable constants in IfOp"); + + Value new_tval = t_compare_res == Constant::cond_true ? tval : fval; + Value new_fval = f_compare_res == Constant::cond_true ? tval : fval; - // Adjust control flow graph - BlockBegin::disconnect_edge(block, t_block); - BlockBegin::disconnect_edge(block, f_block); - if (t_block->number_of_preds() == 0) { - BlockBegin::disconnect_edge(t_block, sux); + _ifop_count++; + if (new_tval == new_fval) { + return new_tval; + } else { + return new IfOp(x_ifop->x(), x_ifop_cond, x_ifop->y(), new_tval, new_fval); + } + } + } else { + Constant* x_const = x->as_Constant(); + if (x_const != NULL) { // x and y are constants + Constant::CompareResult x_compare_res = x_const->compare(cond, y_const); + guarantee(x_compare_res != Constant::not_comparable, "incomparable constants in IfOp"); + + _ifop_count++; + return x_compare_res == Constant::cond_true ? tval : fval; + } } - adjust_exception_edges(block, t_block); - if (f_block->number_of_preds() == 0) { - BlockBegin::disconnect_edge(f_block, sux); - } - adjust_exception_edges(block, f_block); - - // update block end - block->set_end(goto_); - - // substitute the phi if possible - if (sux_phi->as_Phi()->operand_count() == 1) { - assert(sux_phi->as_Phi()->operand_at(0) == result, "screwed up phi"); - sux_phi->set_subst(result); - _has_substitution = true; - } - - // 3) successfully eliminated a conditional expression - _cee_count++; - if (PrintCEE) { - tty->print_cr("%d. CEE in B%d (B%d B%d)", cee_count(), block->block_id(), t_block->block_id(), f_block->block_id()); - } - - _hir->verify(); } -}; - + return new IfOp(x, cond, y, tval, fval); +} void Optimizer::eliminate_conditional_expressions() { // find conditional expressions & replace them with IfOps CE_Eliminator ce(ir()); } - class BlockMerger: public BlockClosure { private: IR* _hir; diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/c1/c1_Runtime1.cpp --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -107,7 +107,6 @@ RegisterMap reg_map(thread, false); frame runtime_frame = thread->last_frame(); frame caller_frame = runtime_frame.sender(®_map); - // bypass VM_DeoptimizeFrame and deoptimize the frame directly Deoptimization::deoptimize_frame(thread, caller_frame.id()); assert(caller_is_deopted(), "Must be deoptimized"); } @@ -368,8 +367,7 @@ if (osr_nm != NULL) { RegisterMap map(thread, false); frame fr = thread->last_frame().sender(&map); - VM_DeoptimizeFrame deopt(thread, fr.id()); - VMThread::execute(&deopt); + Deoptimization::deoptimize_frame(thread, fr.id()); } JRT_BLOCK_END return NULL; @@ -441,8 +439,8 @@ // We don't really want to deoptimize the nmethod itself since we // can actually continue in the exception handler ourselves but I // don't see an easy way to have the desired effect. - VM_DeoptimizeFrame deopt(thread, caller_frame.id()); - VMThread::execute(&deopt); + Deoptimization::deoptimize_frame(thread, caller_frame.id()); + assert(caller_is_deopted(), "Must be deoptimized"); return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); } @@ -835,8 +833,7 @@ nm->make_not_entrant(); } - VM_DeoptimizeFrame deopt(thread, caller_frame.id()); - VMThread::execute(&deopt); + Deoptimization::deoptimize_frame(thread, caller_frame.id()); // Return to the now deoptimized frame. } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/c1/c1_globals.hpp --- a/hotspot/src/share/vm/c1/c1_globals.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/c1/c1_globals.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -75,6 +75,9 @@ develop(bool, SelectivePhiFunctions, true, \ "create phi functions at loop headers only when necessary") \ \ + develop(bool, OptimizeIfOps, true, \ + "Optimize multiple IfOps") \ + \ develop(bool, DoCEE, true, \ "Do Conditional Expression Elimination to simplify CFG") \ \ diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/ci/ciInstanceKlass.cpp --- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -564,7 +564,7 @@ // This is OK, since any dependencies we decide to assert // will be checked later under the Compile_lock. ciInstanceKlass* ciInstanceKlass::implementor(int n) { - if (n > implementors_limit) { + if (n >= implementors_limit) { return NULL; } ciInstanceKlass* impl = _implementors[n]; diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,6 +73,12 @@ unsigned int hashValues[SymbolTable::symbol_alloc_batch_size]; int names_count = 0; + // Side buffer for operands of variable-sized (InvokeDynamic) entries. + GrowableArray* operands = NULL; +#ifdef ASSERT + GrowableArray* indy_instructions = new GrowableArray(THREAD, 10); +#endif + // parsing Index 0 is unused for (int index = 1; index < length; index++) { // Each of the following case guarantees one more byte in the stream @@ -141,6 +147,7 @@ ShouldNotReachHere(); } break; + case JVM_CONSTANT_InvokeDynamicTrans : // this tag appears only in old classfiles case JVM_CONSTANT_InvokeDynamic : { if (!EnableInvokeDynamic || @@ -151,10 +158,36 @@ "Class file version does not support constant tag %u in class file %s"), tag, CHECK); } - cfs->guarantee_more(5, CHECK); // bsm_index, name_and_type_index, tag/access_flags + if (!AllowTransitionalJSR292 && tag == JVM_CONSTANT_InvokeDynamicTrans) { + classfile_parse_error( + "This JVM does not support transitional InvokeDynamic tag %u in class file %s", + tag, CHECK); + } + bool trans_no_argc = AllowTransitionalJSR292 && (tag == JVM_CONSTANT_InvokeDynamicTrans); + cfs->guarantee_more(7, CHECK); // bsm_index, nt, argc, ..., tag/access_flags u2 bootstrap_method_index = cfs->get_u2_fast(); u2 name_and_type_index = cfs->get_u2_fast(); - cp->invoke_dynamic_at_put(index, bootstrap_method_index, name_and_type_index); + int argument_count = trans_no_argc ? 0 : cfs->get_u2_fast(); + cfs->guarantee_more(2*argument_count + 1, CHECK); // argv[argc]..., tag/access_flags + int argv_offset = constantPoolOopDesc::_indy_argv_offset; + int op_count = argv_offset + argument_count; // bsm, nt, argc, argv[]... + int op_base = start_operand_group(operands, op_count, CHECK); + assert(argv_offset == 3, "else adjust next 3 assignments"); + operands->at_put(op_base + constantPoolOopDesc::_indy_bsm_offset, bootstrap_method_index); + operands->at_put(op_base + constantPoolOopDesc::_indy_nt_offset, name_and_type_index); + operands->at_put(op_base + constantPoolOopDesc::_indy_argc_offset, argument_count); + for (int arg_i = 0; arg_i < argument_count; arg_i++) { + int arg = cfs->get_u2_fast(); + operands->at_put(op_base + constantPoolOopDesc::_indy_argv_offset + arg_i, arg); + } + cp->invoke_dynamic_at_put(index, op_base, op_count); +#ifdef ASSERT + // Record the steps just taken for later checking. + indy_instructions->append(index); + indy_instructions->append(bootstrap_method_index); + indy_instructions->append(name_and_type_index); + indy_instructions->append(argument_count); +#endif //ASSERT } break; case JVM_CONSTANT_Integer : @@ -257,6 +290,23 @@ oopFactory::new_symbols(cp, names_count, names, lengths, indices, hashValues, CHECK); } + if (operands != NULL && operands->length() > 0) { + store_operand_array(operands, cp, CHECK); + } +#ifdef ASSERT + // Re-assert the indy structures, now that assertion checking can work. + for (int indy_i = 0; indy_i < indy_instructions->length(); ) { + int index = indy_instructions->at(indy_i++); + int bootstrap_method_index = indy_instructions->at(indy_i++); + int name_and_type_index = indy_instructions->at(indy_i++); + int argument_count = indy_instructions->at(indy_i++); + assert(cp->check_invoke_dynamic_at(index, + bootstrap_method_index, name_and_type_index, + argument_count), + "indy structure is OK"); + } +#endif //ASSERT + // Copy _current pointer of local copy back to stream(). #ifdef ASSERT assert(cfs0->current() == old_current, "non-exclusive use of stream()"); @@ -264,6 +314,41 @@ cfs0->set_current(cfs1.current()); } +int ClassFileParser::start_operand_group(GrowableArray* &operands, int op_count, TRAPS) { + if (operands == NULL) { + operands = new GrowableArray(THREAD, 100); + int fillp_offset = constantPoolOopDesc::_multi_operand_buffer_fill_pointer_offset; + while (operands->length() <= fillp_offset) + operands->append(0); // force op_base > 0, for an error check + DEBUG_ONLY(operands->at_put(fillp_offset, (int)badHeapWordVal)); + } + int cnt_pos = operands->append(op_count); + int arg_pos = operands->length(); + operands->at_grow(arg_pos + op_count - 1); // grow to include the operands + assert(operands->length() == arg_pos + op_count, ""); + int op_base = cnt_pos - constantPoolOopDesc::_multi_operand_count_offset; + return op_base; +} + +void ClassFileParser::store_operand_array(GrowableArray* operands, constantPoolHandle cp, TRAPS) { + // Collect the buffer of operands from variable-sized entries into a permanent array. + int arraylen = operands->length(); + int fillp_offset = constantPoolOopDesc::_multi_operand_buffer_fill_pointer_offset; + assert(operands->at(fillp_offset) == (int)badHeapWordVal, "value unused so far"); + operands->at_put(fillp_offset, arraylen); + cp->multi_operand_buffer_grow(arraylen, CHECK); + typeArrayOop operands_oop = cp->operands(); + assert(operands_oop->length() == arraylen, ""); + for (int i = 0; i < arraylen; i++) { + operands_oop->int_at_put(i, operands->at(i)); + } + cp->set_operands(operands_oop); + // The fill_pointer is used only by constantPoolOop::copy_entry_to and friends, + // when constant pools need to be merged. Make sure it is sane now. + assert(cp->multi_operand_buffer_fill_pointer() == arraylen, ""); +} + + bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); } constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) { @@ -431,6 +516,8 @@ ref_index, CHECK_(nullHandle)); } break; + case JVM_CONSTANT_InvokeDynamicTrans : + ShouldNotReachHere(); // this tag does not appear in the heap case JVM_CONSTANT_InvokeDynamic : { int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index); @@ -438,7 +525,7 @@ check_property((bootstrap_method_ref_index == 0 && AllowTransitionalJSR292) || (valid_cp_range(bootstrap_method_ref_index, length) && - cp->tag_at(bootstrap_method_ref_index).is_method_handle()), + (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)); @@ -447,6 +534,18 @@ "Invalid constant pool index %u in class file %s", name_and_type_ref_index, CHECK_(nullHandle)); + int argc = cp->invoke_dynamic_argument_count_at(index); + for (int arg_i = 0; arg_i < argc; arg_i++) { + int arg = cp->invoke_dynamic_argument_index_at(index, arg_i); + check_property(valid_cp_range(arg, length) && + cp->tag_at(arg).is_loadable_constant() || + // temporary early forms of string and class: + cp->tag_at(arg).is_klass_index() || + cp->tag_at(arg).is_string_index(), + "Invalid constant pool index %u in class file %s", + arg, + CHECK_(nullHandle)); + } break; } default: @@ -2516,18 +2615,6 @@ // field. If it is not present, artifically create a field for it. // This allows this VM to run on early JDK where the field is not // present. - - // - // Increment fac.nonstatic_oop_count so that the start of the - // next type of non-static oops leaves room for the fake oop. - // Do not increment next_nonstatic_oop_offset so that the - // fake oop is place after the java.lang.ref.Reference oop - // fields. - // - // Check the fields in java.lang.ref.Reference for the "discovered" - // field. If it is not present, artifically create a field for it. - // This allows this VM to run on early JDK where the field is not - // present. int reference_sig_index = 0; int reference_name_index = 0; int reference_index = 0; @@ -2663,7 +2750,7 @@ // Force MethodHandle.vmentry to be an unmanaged pointer. // There is no way for a classfile to express this, so we must help it. void ClassFileParser::java_dyn_MethodHandle_fix_pre(constantPoolHandle cp, - typeArrayHandle* fields_ptr, + typeArrayHandle fields, FieldAllocationCount *fac_ptr, TRAPS) { // Add fake fields for java.dyn.MethodHandle instances @@ -2687,41 +2774,45 @@ THROW_MSG(vmSymbols::java_lang_VirtualMachineError(), "missing I or J signature (for vmentry) in java.dyn.MethodHandle"); + // Find vmentry field and change the signature. bool found_vmentry = false; - - const int n = (*fields_ptr)()->length(); - for (int i = 0; i < n; i += instanceKlass::next_offset) { - int name_index = (*fields_ptr)->ushort_at(i + instanceKlass::name_index_offset); - int sig_index = (*fields_ptr)->ushort_at(i + instanceKlass::signature_index_offset); - int acc_flags = (*fields_ptr)->ushort_at(i + instanceKlass::access_flags_offset); + for (int i = 0; i < fields->length(); i += instanceKlass::next_offset) { + int name_index = fields->ushort_at(i + instanceKlass::name_index_offset); + int sig_index = fields->ushort_at(i + instanceKlass::signature_index_offset); + int acc_flags = fields->ushort_at(i + instanceKlass::access_flags_offset); symbolOop f_name = cp->symbol_at(name_index); symbolOop f_sig = cp->symbol_at(sig_index); - if (f_sig == vmSymbols::byte_signature() && - f_name == vmSymbols::vmentry_name() && - (acc_flags & JVM_ACC_STATIC) == 0) { - // Adjust the field type from byte to an unmanaged pointer. - assert(fac_ptr->nonstatic_byte_count > 0, ""); - fac_ptr->nonstatic_byte_count -= 1; - - (*fields_ptr)->ushort_at_put(i + instanceKlass::signature_index_offset, word_sig_index); - assert(wordSize == longSize || wordSize == jintSize, "ILP32 or LP64"); - if (wordSize == longSize) fac_ptr->nonstatic_double_count += 1; - else fac_ptr->nonstatic_word_count += 1; - - FieldAllocationType atype = (FieldAllocationType) (*fields_ptr)->ushort_at(i + instanceKlass::low_offset); - assert(atype == NONSTATIC_BYTE, ""); - FieldAllocationType new_atype = (wordSize == longSize) ? NONSTATIC_DOUBLE : NONSTATIC_WORD; - (*fields_ptr)->ushort_at_put(i + instanceKlass::low_offset, new_atype); - - found_vmentry = true; - break; + + if (f_name == vmSymbols::vmentry_name() && (acc_flags & JVM_ACC_STATIC) == 0) { + if (f_sig == vmSymbols::machine_word_signature()) { + // If the signature of vmentry is already changed, we're done. + found_vmentry = true; + break; + } + else if (f_sig == vmSymbols::byte_signature()) { + // Adjust the field type from byte to an unmanaged pointer. + assert(fac_ptr->nonstatic_byte_count > 0, ""); + fac_ptr->nonstatic_byte_count -= 1; + + fields->ushort_at_put(i + instanceKlass::signature_index_offset, word_sig_index); + assert(wordSize == longSize || wordSize == jintSize, "ILP32 or LP64"); + if (wordSize == longSize) fac_ptr->nonstatic_double_count += 1; + else fac_ptr->nonstatic_word_count += 1; + + FieldAllocationType atype = (FieldAllocationType) fields->ushort_at(i + instanceKlass::low_offset); + assert(atype == NONSTATIC_BYTE, ""); + FieldAllocationType new_atype = (wordSize == longSize) ? NONSTATIC_DOUBLE : NONSTATIC_WORD; + fields->ushort_at_put(i + instanceKlass::low_offset, new_atype); + + found_vmentry = true; + break; + } } } if (!found_vmentry) THROW_MSG(vmSymbols::java_lang_VirtualMachineError(), "missing vmentry byte field in java.dyn.MethodHandle"); - } @@ -3082,7 +3173,7 @@ // adjust the vmentry field declaration in java.dyn.MethodHandle if (EnableMethodHandles && class_name() == vmSymbols::sun_dyn_MethodHandleImpl() && class_loader.is_null()) { - java_dyn_MethodHandle_fix_pre(cp, &fields, &fac, CHECK_(nullHandle)); + java_dyn_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle)); } // Add a fake "discovered" field if it is not present diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/classfile/classFileParser.hpp --- a/hotspot/src/share/vm/classfile/classFileParser.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,9 @@ constantPoolHandle parse_constant_pool(TRAPS); + static int start_operand_group(GrowableArray* &operands, int op_count, TRAPS); + static void store_operand_array(GrowableArray* operands, constantPoolHandle cp, TRAPS); + // Interface parsing objArrayHandle parse_interfaces(constantPoolHandle cp, int length, @@ -151,7 +154,7 @@ // Adjust the field allocation counts for java.dyn.MethodHandle to add // a fake address (void*) field. void java_dyn_MethodHandle_fix_pre(constantPoolHandle cp, - typeArrayHandle* fields_ptr, + typeArrayHandle fields, FieldAllocationCount *fac_ptr, TRAPS); // Format checker methods diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,12 +26,12 @@ # include "incls/_systemDictionary.cpp.incl" -Dictionary* SystemDictionary::_dictionary = NULL; -PlaceholderTable* SystemDictionary::_placeholders = NULL; -Dictionary* SystemDictionary::_shared_dictionary = NULL; -LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL; -ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL; -SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL; +Dictionary* SystemDictionary::_dictionary = NULL; +PlaceholderTable* SystemDictionary::_placeholders = NULL; +Dictionary* SystemDictionary::_shared_dictionary = NULL; +LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL; +ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL; +SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL; int SystemDictionary::_number_of_modifications = 0; @@ -1727,8 +1727,7 @@ placeholders_do(blk); // Visit extra methods - if (invoke_method_table() != NULL) - invoke_method_table()->oops_do(blk); + invoke_method_table()->oops_do(blk); // Loader constraints. We must keep the symbolOop used in the name alive. constraints()->always_strong_classes_do(blk); @@ -1766,8 +1765,7 @@ dictionary()->oops_do(f); // Visit extra methods - if (invoke_method_table() != NULL) - invoke_method_table()->oops_do(f); + invoke_method_table()->oops_do(f); // Partially loaded classes placeholders()->oops_do(f); @@ -1841,8 +1839,7 @@ void SystemDictionary::methods_do(void f(methodOop)) { dictionary()->methods_do(f); - if (invoke_method_table() != NULL) - invoke_method_table()->methods_do(f); + invoke_method_table()->methods_do(f); } // ---------------------------------------------------------------------------- @@ -1870,12 +1867,12 @@ // Allocate arrays assert(dictionary() == NULL, "SystemDictionary should only be initialized once"); - _dictionary = new Dictionary(_nof_buckets); - _placeholders = new PlaceholderTable(_nof_buckets); + _dictionary = new Dictionary(_nof_buckets); + _placeholders = new PlaceholderTable(_nof_buckets); _number_of_modifications = 0; - _loader_constraints = new LoaderConstraintTable(_loader_constraint_size); - _resolution_errors = new ResolutionErrorTable(_resolution_error_size); - // _invoke_method_table is allocated lazily in find_method_handle_invoke() + _loader_constraints = new LoaderConstraintTable(_loader_constraint_size); + _resolution_errors = new ResolutionErrorTable(_resolution_error_size); + _invoke_method_table = new SymbolPropertyTable(_invoke_method_size); // Allocate private object used as system class loader lock _system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK); @@ -2346,10 +2343,6 @@ KlassHandle accessing_klass, TRAPS) { if (!EnableMethodHandles) return NULL; - if (invoke_method_table() == NULL) { - // create this side table lazily - _invoke_method_table = new SymbolPropertyTable(_invoke_method_size); - } vmSymbols::SID name_id = vmSymbols::find_sid(name()); assert(name_id != vmSymbols::NO_SID, "must be a known name"); unsigned int hash = invoke_method_table()->compute_hash(signature, name_id); @@ -2562,7 +2555,9 @@ } Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int caller_bci, - int cache_index, TRAPS) { + int cache_index, + Handle& argument_info_result, + TRAPS) { Handle empty; constantPoolHandle pool; @@ -2576,7 +2571,7 @@ constantTag tag = pool->tag_at(constant_pool_index); if (tag.is_invoke_dynamic()) { - // JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type] + // JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type], plus optional arguments // The bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry. int bsm_index = pool->invoke_dynamic_bootstrap_method_ref_index_at(constant_pool_index); if (bsm_index != 0) { @@ -2592,9 +2587,38 @@ tty->print_cr("bootstrap method for "PTR_FORMAT" at %d retrieved as "PTR_FORMAT":", (intptr_t) caller_method(), caller_bci, (intptr_t) bsm_oop); } - assert(bsm_oop->is_oop() - && java_dyn_MethodHandle::is_instance(bsm_oop), "must be sane"); - return Handle(THREAD, bsm_oop); + assert(bsm_oop->is_oop(), "must be sane"); + // caller must verify that it is of type MethodHandle + Handle bsm(THREAD, bsm_oop); + bsm_oop = NULL; // safety + + // Extract the optional static arguments. + Handle argument_info; // either null, or one arg, or Object[]{arg...} + int argc = pool->invoke_dynamic_argument_count_at(constant_pool_index); + if (TraceInvokeDynamic) { + tty->print_cr("find_bootstrap_method: [%d/%d] CONSTANT_InvokeDynamic: %d[%d]", + constant_pool_index, cache_index, bsm_index, argc); + } + if (argc > 0) { + objArrayHandle arg_array; + if (argc > 1) { + objArrayOop arg_array_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), argc, CHECK_(empty)); + arg_array = objArrayHandle(THREAD, arg_array_oop); + argument_info = arg_array; + } + for (int arg_i = 0; arg_i < argc; arg_i++) { + int arg_index = pool->invoke_dynamic_argument_index_at(constant_pool_index, arg_i); + oop arg_oop = pool->resolve_possibly_cached_constant_at(arg_index, CHECK_(empty)); + if (arg_array.is_null()) { + argument_info = Handle(THREAD, arg_oop); + } else { + arg_array->obj_at_put(arg_i, arg_oop); + } + } + } + + argument_info_result = argument_info; // return argument_info to caller + return bsm; } // else null BSM; fall through } else if (tag.is_name_and_type()) { @@ -2607,14 +2631,14 @@ // 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() - && java_dyn_MethodHandle::is_instance(bsm_oop), "must be sane"); + assert(bsm_oop->is_oop(), "must be sane"); return Handle(THREAD, bsm_oop); } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/classfile/systemDictionary.hpp --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -496,6 +496,7 @@ static Handle find_bootstrap_method(methodHandle caller_method, int caller_bci, // N.B. must be an invokedynamic int cache_index, // must be corresponding main_entry + Handle &argument_info_result, // static BSM arguments, if any TRAPS); // Utility for printing loader "name" as part of tracing constraints diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/classfile/verifier.cpp --- a/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1909,7 +1909,7 @@ unsigned int types = (opcode == Bytecodes::_invokeinterface ? 1 << JVM_CONSTANT_InterfaceMethodref : opcode == Bytecodes::_invokedynamic - ? (1 << JVM_CONSTANT_NameAndType + ? ((AllowTransitionalJSR292 ? 1 << JVM_CONSTANT_NameAndType : 0) |1 << JVM_CONSTANT_InvokeDynamic) : 1 << JVM_CONSTANT_Methodref); verify_cp_type(index, cp, types, CHECK_VERIFY(this)); diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/code/codeCache.cpp --- a/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -914,3 +914,14 @@ } #endif // PRODUCT + +void CodeCache::print_bounds(outputStream* st) { + st->print_cr("Code Cache [" INTPTR_FORMAT ", " INTPTR_FORMAT ", " INTPTR_FORMAT ")", + _heap->low_boundary(), + _heap->high(), + _heap->high_boundary()); + st->print_cr(" total_blobs=" UINT32_FORMAT " nmethods=" UINT32_FORMAT + " adapters=" UINT32_FORMAT " free_code_cache=" SIZE_FORMAT, + CodeCache::nof_blobs(), CodeCache::nof_nmethods(), + CodeCache::nof_adapters(), CodeCache::unallocated_capacity()); +} diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/code/codeCache.hpp --- a/hotspot/src/share/vm/code/codeCache.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/code/codeCache.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -137,6 +137,7 @@ static void print_internals(); static void verify(); // verifies the code cache static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN; + static void print_bounds(outputStream* st); // Prints a summary of the bounds of the code cache // The full limits of the codeCache static address low_bound() { return (address) _heap->low_boundary(); } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge --- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Wed Jul 05 17:27:29 2017 +0200 @@ -133,6 +133,7 @@ parallelScavengeHeap.cpp psParallelCompact.hpp parallelScavengeHeap.cpp psPromotionManager.hpp parallelScavengeHeap.cpp psScavenge.hpp +parallelScavengeHeap.cpp vmError.hpp parallelScavengeHeap.cpp vmThread.hpp parallelScavengeHeap.cpp vmPSOperations.hpp diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -805,7 +805,8 @@ if (young_gen()->is_in_reserved(addr)) { assert(young_gen()->is_in(addr), "addr should be in allocated part of young gen"); - if (Debugging) return NULL; // called from find() in debug.cpp + // called from os::print_location by find or VMError + if (Debugging || VMError::fatal_error_in_progress()) return NULL; Unimplemented(); } else if (old_gen()->is_in_reserved(addr)) { assert(old_gen()->is_in(addr), diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/includeDB_core --- a/hotspot/src/share/vm/includeDB_core Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/includeDB_core Wed Jul 05 17:27:29 2017 +0200 @@ -1272,6 +1272,7 @@ constantPoolOop.cpp linkResolver.hpp constantPoolOop.cpp objArrayKlass.hpp constantPoolOop.cpp oop.inline.hpp +constantPoolOop.cpp oopFactory.hpp constantPoolOop.cpp signature.hpp constantPoolOop.cpp symbolTable.hpp constantPoolOop.cpp systemDictionary.hpp diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/includeDB_features --- a/hotspot/src/share/vm/includeDB_features Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/includeDB_features Wed Jul 05 17:27:29 2017 +0200 @@ -154,6 +154,7 @@ jvmtiExtensions.hpp jvmti.h jvmtiExtensions.hpp jvmtiEnv.hpp +jvmtiImpl.cpp deoptimization.hpp jvmtiImpl.cpp exceptions.hpp jvmtiImpl.cpp handles.hpp jvmtiImpl.cpp handles.inline.hpp diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/includeDB_jvmti --- a/hotspot/src/share/vm/includeDB_jvmti Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/includeDB_jvmti Wed Jul 05 17:27:29 2017 +0200 @@ -89,6 +89,7 @@ jvmtiEnv.hpp jvmtiEnvBase.hpp jvmtiEnvBase.cpp biasedLocking.hpp +jvmtiEnvBase.cpp deoptimization.hpp jvmtiEnvBase.cpp interfaceSupport.hpp jvmtiEnvBase.cpp jfieldIDWorkaround.hpp jvmtiEnvBase.cpp jvmtiEnv.hpp diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/interpreter/interpreterRuntime.cpp --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -716,12 +716,13 @@ assert(constantPoolCacheOopDesc::is_secondary_index(site_index), "proper format"); // there is a second CPC entries that is of interest; it caches signature info: int main_index = pool->cache()->secondary_entry_at(site_index)->main_entry_index(); + int pool_index = pool->cache()->entry_at(main_index)->constant_pool_index(); // first resolve the signature to a MH.invoke methodOop if (!pool->cache()->entry_at(main_index)->is_resolved(bytecode)) { JvmtiHideSingleStepping jhss(thread); - CallInfo info; - LinkResolver::resolve_invoke(info, Handle(), pool, + CallInfo callinfo; + LinkResolver::resolve_invoke(callinfo, Handle(), pool, site_index, bytecode, CHECK); // The main entry corresponds to a JVM_CONSTANT_InvokeDynamic, and serves // as a common reference point for all invokedynamic call sites with @@ -729,8 +730,8 @@ // as if it were an invokevirtual of MethodHandle.invoke. pool->cache()->entry_at(main_index)->set_method( bytecode, - info.resolved_method(), - info.vtable_index()); + callinfo.resolved_method(), + callinfo.vtable_index()); } // The method (f2 entry) of the main entry is the MH.invoke for the @@ -740,9 +741,10 @@ assert(signature_invoker.not_null() && signature_invoker->is_method() && signature_invoker->is_method_handle_invoke(), "correct result from LinkResolver::resolve_invokedynamic"); + Handle info; // optional argument(s) in JVM_CONSTANT_InvokeDynamic Handle bootm = SystemDictionary::find_bootstrap_method(caller_method, caller_bci, - main_index, CHECK); - if (bootm.is_null()) { + main_index, info, CHECK); + if (!java_dyn_MethodHandle::is_instance(bootm())) { THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "no bootstrap method found for invokedynamic"); } @@ -753,8 +755,6 @@ symbolHandle call_site_name(THREAD, pool->name_ref_at(site_index)); - Handle info; // NYI: Other metadata from a new kind of CP entry. (Annotations?) - Handle call_site = SystemDictionary::make_dynamic_call_site(bootm, // Callee information: diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/memory/heap.hpp --- a/hotspot/src/share/vm/memory/heap.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/memory/heap.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -140,6 +140,7 @@ // Returns reserved area high and low addresses char *low_boundary() const { return _memory.low_boundary (); } + char *high() const { return _memory.high(); } char *high_boundary() const { return _memory.high_boundary(); } // Iteration diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/memory/universe.hpp --- a/hotspot/src/share/vm/memory/universe.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/memory/universe.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -340,6 +340,7 @@ static klassOop* longArrayKlassObj_addr() { return &_longArrayKlassObj; } static klassOop* singleArrayKlassObj_addr() { return &_singleArrayKlassObj; } static klassOop* doubleArrayKlassObj_addr() { return &_doubleArrayKlassObj; } + static klassOop* systemObjArrayKlassObj_addr() { return &_systemObjArrayKlassObj; } // The particular choice of collected heap. static CollectedHeap* heap() { return _collectedHeap; } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/oops/constantPoolKlass.cpp --- a/hotspot/src/share/vm/oops/constantPoolKlass.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/oops/constantPoolKlass.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ c->set_length(length); c->set_tags(NULL); c->set_cache(NULL); + c->set_operands(NULL); c->set_pool_holder(NULL); c->set_flags(0); // only set to non-zero if constant pool is merged by RedefineClasses @@ -92,6 +93,7 @@ // gc of constant pool instance variables MarkSweep::mark_and_push(cp->tags_addr()); MarkSweep::mark_and_push(cp->cache_addr()); + MarkSweep::mark_and_push(cp->operands_addr()); MarkSweep::mark_and_push(cp->pool_holder_addr()); } } @@ -118,6 +120,7 @@ // gc of constant pool instance variables PSParallelCompact::mark_and_push(cm, cp->tags_addr()); PSParallelCompact::mark_and_push(cm, cp->cache_addr()); + PSParallelCompact::mark_and_push(cm, cp->operands_addr()); PSParallelCompact::mark_and_push(cm, cp->pool_holder_addr()); } } @@ -146,6 +149,7 @@ } MarkSweep::adjust_pointer(cp->tags_addr()); MarkSweep::adjust_pointer(cp->cache_addr()); + MarkSweep::adjust_pointer(cp->operands_addr()); MarkSweep::adjust_pointer(cp->pool_holder_addr()); return size; } @@ -173,6 +177,7 @@ } blk->do_oop(cp->tags_addr()); blk->do_oop(cp->cache_addr()); + blk->do_oop(cp->operands_addr()); blk->do_oop(cp->pool_holder_addr()); return size; } @@ -205,6 +210,8 @@ blk->do_oop(addr); addr = cp->cache_addr(); blk->do_oop(addr); + addr = cp->operands_addr(); + blk->do_oop(addr); addr = cp->pool_holder_addr(); blk->do_oop(addr); return size; @@ -232,6 +239,7 @@ } PSParallelCompact::adjust_pointer(cp->tags_addr()); PSParallelCompact::adjust_pointer(cp->cache_addr()); + PSParallelCompact::adjust_pointer(cp->operands_addr()); PSParallelCompact::adjust_pointer(cp->pool_holder_addr()); return cp->object_size(); } @@ -262,6 +270,8 @@ PSParallelCompact::adjust_pointer(p, beg_addr, end_addr); p = cp->cache_addr(); PSParallelCompact::adjust_pointer(p, beg_addr, end_addr); + p = cp->operands_addr(); + PSParallelCompact::adjust_pointer(p, beg_addr, end_addr); p = cp->pool_holder_addr(); PSParallelCompact::adjust_pointer(p, beg_addr, end_addr); @@ -363,8 +373,18 @@ st->print("signature_index=%d", cp->method_type_index_at(index)); break; case JVM_CONSTANT_InvokeDynamic : - st->print("bootstrap_method_index=%d", cp->invoke_dynamic_bootstrap_method_ref_index_at(index)); - st->print(" name_and_type_index=%d", cp->invoke_dynamic_name_and_type_ref_index_at(index)); + { + st->print("bootstrap_method_index=%d", cp->invoke_dynamic_bootstrap_method_ref_index_at(index)); + st->print(" name_and_type_index=%d", cp->invoke_dynamic_name_and_type_ref_index_at(index)); + int argc = cp->invoke_dynamic_argument_count_at(index); + if (argc > 0) { + for (int arg_i = 0; arg_i < argc; arg_i++) { + int arg = cp->invoke_dynamic_argument_index_at(index, arg_i); + st->print((arg_i == 0 ? " arguments={%d" : ", %d"), arg); + } + st->print("}"); + } + } break; default: ShouldNotReachHere(); @@ -381,6 +401,7 @@ st->print("constant pool [%d]", cp->length()); if (cp->has_pseudo_string()) st->print("/pseudo_string"); if (cp->has_invokedynamic()) st->print("/invokedynamic"); + if (cp->operands() != NULL) st->print("/operands[%d]", cp->operands()->length()); cp->print_address_on(st); st->print(" for "); cp->pool_holder()->print_value_on(st); @@ -440,6 +461,10 @@ guarantee(cp->cache()->is_perm(), "should be in permspace"); guarantee(cp->cache()->is_constantPoolCache(), "should be constant pool cache"); } + if (cp->operands() != NULL) { + guarantee(cp->operands()->is_perm(), "should be in permspace"); + guarantee(cp->operands()->is_typeArray(), "should be type array"); + } if (cp->pool_holder() != NULL) { // Note: pool_holder() can be NULL in temporary constant pools // used during constant pool merging diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/oops/constantPoolOop.cpp --- a/hotspot/src/share/vm/oops/constantPoolOop.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -265,10 +265,9 @@ int i = which; if (!uncached && cache() != NULL) { if (constantPoolCacheOopDesc::is_secondary_index(which)) { - // Invokedynamic indexes are always processed in native order - // so there is no question of reading a native u2 in Java order here. + // Invokedynamic index. int pool_index = cache()->main_entry_at(which)->constant_pool_index(); - if (tag_at(pool_index).is_invoke_dynamic()) + if (!AllowTransitionalJSR292 || tag_at(pool_index).is_invoke_dynamic()) pool_index = invoke_dynamic_name_and_type_ref_index_at(pool_index); assert(tag_at(pool_index).is_name_and_type(), ""); return pool_index; @@ -276,11 +275,17 @@ // change byte-ordering and go via cache i = remap_instruction_operand_from_cache(which); } else { - if (tag_at(which).is_name_and_type()) + 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(), ""); + return pool_index; + } } assert(tag_at(i).is_field_or_method(), "Corrupted constant pool"); + assert(!tag_at(i).is_invoke_dynamic(), "Must be handled above"); jint ref_index = *int_at_addr(i); return extract_high_short_from_int(ref_index); } @@ -394,18 +399,61 @@ } } +// A resolved constant value in the CP cache is represented as a non-null +// value. As a special case, this value can be a 'systemObjArray' +// which masks an exception object to throw. +// This allows a MethodHandle constant reference to throw a consistent +// exception every time, if it fails to resolve. +static oop decode_exception_from_f1(oop result_oop, TRAPS) { + if (result_oop->klass() != Universe::systemObjArrayKlassObj()) + return result_oop; + + // Special cases here: Masked null, saved exception. + objArrayOop sys_array = (objArrayOop) result_oop; + assert(sys_array->length() == 1, "bad system array"); + if (sys_array->length() == 1) { + THROW_OOP_(sys_array->obj_at(0), NULL); + } + return NULL; +} + oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS) { oop result_oop = NULL; + Handle throw_exception; + + if (cache_index == _possible_index_sentinel) { + // It is possible that this constant is one which is cached in the CP cache. + // We'll do a linear search. This should be OK because this usage is rare. + assert(index > 0, "valid index"); + constantPoolCacheOop cache = this_oop()->cache(); + for (int i = 0, len = cache->length(); i < len; i++) { + ConstantPoolCacheEntry* cpc_entry = cache->entry_at(i); + if (!cpc_entry->is_secondary_entry() && cpc_entry->constant_pool_index() == index) { + // Switch the query to use this CPC entry. + cache_index = i; + index = _no_index_sentinel; + break; + } + } + if (cache_index == _possible_index_sentinel) + cache_index = _no_index_sentinel; // not found + } + assert(cache_index == _no_index_sentinel || cache_index >= 0, ""); + assert(index == _no_index_sentinel || index >= 0, ""); + if (cache_index >= 0) { - assert(index < 0, "only one kind of index at a time"); + assert(index == _no_index_sentinel, "only one kind of index at a time"); ConstantPoolCacheEntry* cpc_entry = this_oop->cache()->entry_at(cache_index); result_oop = cpc_entry->f1(); if (result_oop != NULL) { - return result_oop; // that was easy... + return decode_exception_from_f1(result_oop, THREAD); + // That was easy... } index = cpc_entry->constant_pool_index(); } + jvalue prim_value; // temp used only in a few cases below + int tag_value = this_oop->tag_at(index).value(); switch (tag_value) { @@ -449,9 +497,14 @@ KlassHandle klass(THREAD, this_oop->pool_holder()); Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind, callee, name, signature, - CHECK_NULL); + THREAD); + if (HAS_PENDING_EXCEPTION) { + throw_exception = Handle(THREAD, PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; + break; + } result_oop = value(); - // FIXME: Uniquify errors, using SystemDictionary::find_resolution_error. + assert(result_oop != NULL, ""); break; } @@ -468,20 +521,36 @@ klass, false, ignore_is_on_bcp, - CHECK_NULL); + THREAD); + if (HAS_PENDING_EXCEPTION) { + throw_exception = Handle(THREAD, PENDING_EXCEPTION); + CLEAR_PENDING_EXCEPTION; + break; + } result_oop = value(); - // FIXME: Uniquify errors, using SystemDictionary::find_resolution_error. + assert(result_oop != NULL, ""); break; } - /* maybe some day case JVM_CONSTANT_Integer: + prim_value.i = this_oop->int_at(index); + result_oop = java_lang_boxing_object::create(T_INT, &prim_value, CHECK_NULL); + break; + case JVM_CONSTANT_Float: + prim_value.f = this_oop->float_at(index); + result_oop = java_lang_boxing_object::create(T_FLOAT, &prim_value, CHECK_NULL); + break; + case JVM_CONSTANT_Long: + prim_value.j = this_oop->long_at(index); + result_oop = java_lang_boxing_object::create(T_LONG, &prim_value, CHECK_NULL); + break; + case JVM_CONSTANT_Double: - result_oop = java_lang_boxing_object::create(...); + prim_value.d = this_oop->double_at(index); + result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL); break; - */ default: DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d", @@ -492,18 +561,31 @@ if (cache_index >= 0) { // Cache the oop here also. - Handle result(THREAD, result_oop); + if (throw_exception.not_null()) { + objArrayOop sys_array = oopFactory::new_system_objArray(1, CHECK_NULL); + sys_array->obj_at_put(0, throw_exception()); + result_oop = sys_array; + throw_exception = Handle(); // be tidy + } + Handle result_handle(THREAD, result_oop); result_oop = NULL; // safety ObjectLocker ol(this_oop, THREAD); ConstantPoolCacheEntry* cpc_entry = this_oop->cache()->entry_at(cache_index); - oop result_oop2 = cpc_entry->f1(); - if (result_oop2 != NULL) { - // Race condition: May already be filled in while we were trying to lock. - return result_oop2; + result_oop = cpc_entry->f1(); + // Benign race condition: f1 may already be filled in while we were trying to lock. + // The important thing here is that all threads pick up the same result. + // It doesn't matter which racing thread wins, as long as only one + // result is used by all threads, and all future queries. + // That result may be either a resolved constant or a failure exception. + if (result_oop == NULL) { + result_oop = result_handle(); + cpc_entry->set_f1(result_oop); } - cpc_entry->set_f1(result()); - return result(); + return decode_exception_from_f1(result_oop, THREAD); } else { + if (throw_exception.not_null()) { + THROW_HANDLE_(throw_exception, NULL); + } return result_oop; } } @@ -621,6 +703,7 @@ void constantPoolOopDesc::shared_tags_iterate(OopClosure* closure) { closure->do_oop(tags_addr()); + closure->do_oop(operands_addr()); } @@ -838,13 +921,19 @@ case JVM_CONSTANT_InvokeDynamic: { - int k1 = invoke_dynamic_bootstrap_method_ref_index_at(index1); - int k2 = cp2->invoke_dynamic_bootstrap_method_ref_index_at(index2); - if (k1 == k2) { - int i1 = invoke_dynamic_name_and_type_ref_index_at(index1); - int i2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2); - if (i1 == i2) { - return true; + int op_count = multi_operand_count_at(index1); + if (op_count == cp2->multi_operand_count_at(index2)) { + bool all_equal = true; + for (int op_i = 0; op_i < op_count; op_i++) { + int k1 = multi_operand_ref_at(index1, op_i); + int k2 = cp2->multi_operand_ref_at(index2, op_i); + if (k1 != k2) { + all_equal = false; + break; + } + } + if (all_equal) { + return true; // got through loop; all elements equal } } } break; @@ -881,6 +970,25 @@ } // end compare_entry_to() +// Grow this->operands() to the indicated length, unless it is already at least that long. +void constantPoolOopDesc::multi_operand_buffer_grow(int min_length, TRAPS) { + int old_length = multi_operand_buffer_fill_pointer(); + if (old_length >= min_length) return; + int new_length = min_length; + assert(new_length > _multi_operand_buffer_fill_pointer_offset, ""); + typeArrayHandle new_operands = oopFactory::new_permanent_intArray(new_length, CHECK); + if (operands() == NULL) { + new_operands->int_at_put(_multi_operand_buffer_fill_pointer_offset, old_length); + } else { + // copy fill pointer and everything else + for (int i = 0; i < old_length; i++) { + new_operands->int_at_put(i, operands()->int_at(i)); + } + } + set_operands(new_operands()); +} + + // Copy this constant pool's entries at start_i to end_i (inclusive) // to the constant pool to_cp's entries starting at to_i. A total of // (end_i - start_i) + 1 entries are copied. @@ -889,6 +997,13 @@ int dest_i = to_i; // leave original alone for debug purposes + if (operands() != NULL) { + // pre-grow the target CP's operand buffer + int nops = this->multi_operand_buffer_fill_pointer(); + nops += to_cp->multi_operand_buffer_fill_pointer(); + to_cp->multi_operand_buffer_grow(nops, CHECK); + } + for (int src_i = start_i; src_i <= end_i; /* see loop bottom */ ) { copy_entry_to(src_i, to_cp, dest_i, CHECK); @@ -1037,9 +1152,26 @@ case JVM_CONSTANT_InvokeDynamic: { + int op_count = multi_operand_count_at(from_i); + int fillp = to_cp->multi_operand_buffer_fill_pointer(); + int to_op_base = fillp - _multi_operand_count_offset; // fillp is count offset; get to base + to_cp->multi_operand_buffer_grow(to_op_base + op_count, CHECK); + to_cp->operands()->int_at_put(fillp++, op_count); + assert(fillp == to_op_base + _multi_operand_base_offset, "just wrote count, will now write args"); + for (int op_i = 0; op_i < op_count; op_i++) { + int op = multi_operand_ref_at(from_i, op_i); + to_cp->operands()->int_at_put(fillp++, op); + } + assert(fillp <= to_cp->operands()->length(), "oob"); + to_cp->set_multi_operand_buffer_fill_pointer(fillp); + to_cp->invoke_dynamic_at_put(to_i, to_op_base, op_count); +#ifdef ASSERT int k1 = invoke_dynamic_bootstrap_method_ref_index_at(from_i); int k2 = invoke_dynamic_name_and_type_ref_index_at(from_i); - to_cp->invoke_dynamic_at_put(to_i, k1, k2); + int k3 = invoke_dynamic_argument_count_at(from_i); + assert(to_cp->check_invoke_dynamic_at(to_i, k1, k2, k3), + "indy structure is OK"); +#endif //ASSERT } break; // Invalid is used as the tag for the second constant pool entry @@ -1257,8 +1389,11 @@ case JVM_CONSTANT_Methodref: case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_NameAndType: + return 5; + case JVM_CONSTANT_InvokeDynamic: - return 5; + // u1 tag, u2 bsm, u2 nt, u2 argc, u2 argv[argc] + return 7 + 2 * invoke_dynamic_argument_count_at(idx); case JVM_CONSTANT_Long: case JVM_CONSTANT_Double: @@ -1475,9 +1610,15 @@ *bytes = JVM_CONSTANT_InvokeDynamic; idx1 = invoke_dynamic_bootstrap_method_ref_index_at(idx); idx2 = invoke_dynamic_name_and_type_ref_index_at(idx); + int argc = invoke_dynamic_argument_count_at(idx); Bytes::put_Java_u2((address) (bytes+1), idx1); Bytes::put_Java_u2((address) (bytes+3), idx2); - DBG(printf("JVM_CONSTANT_InvokeDynamic: %hd %hd", idx1, idx2)); + Bytes::put_Java_u2((address) (bytes+5), argc); + for (int arg_i = 0; arg_i < argc; arg_i++) { + int arg = invoke_dynamic_argument_index_at(idx, arg_i); + Bytes::put_Java_u2((address) (bytes+7+2*arg_i), arg); + } + DBG(printf("JVM_CONSTANT_InvokeDynamic: %hd %hd [%d]", idx1, idx2, argc)); break; } } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/oops/constantPoolOop.hpp --- a/hotspot/src/share/vm/oops/constantPoolOop.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/oops/constantPoolOop.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -41,6 +41,7 @@ typeArrayOop _tags; // the tag array describing the constant pool's contents constantPoolCacheOop _cache; // the cache holding interpreter runtime information klassOop _pool_holder; // the corresponding class + typeArrayOop _operands; // for variable-sized (InvokeDynamic) nodes, usually empty int _flags; // a few header bits to describe contents for GC int _length; // number of elements in the array volatile bool _is_conc_safe; // if true, safe for concurrent @@ -52,6 +53,8 @@ void tag_at_put(int which, jbyte t) { tags()->byte_at_put(which, t); } void release_tag_at_put(int which, jbyte t) { tags()->release_byte_at_put(which, t); } + void set_operands(typeArrayOop operands) { oop_store_without_check((oop*)&_operands, operands); } + enum FlagBit { FB_has_invokedynamic = 1, FB_has_pseudo_string = 2 @@ -67,6 +70,7 @@ intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(constantPoolOopDesc)); } oop* tags_addr() { return (oop*)&_tags; } oop* cache_addr() { return (oop*)&_cache; } + oop* operands_addr() { return (oop*)&_operands; } oop* obj_at_addr(int which) const { assert(is_within_bounds(which), "index out of bounds"); @@ -95,6 +99,7 @@ public: typeArrayOop tags() const { return _tags; } + typeArrayOop operands() const { return _operands; } bool has_pseudo_string() const { return flag_at(FB_has_pseudo_string); } bool has_invokedynamic() const { return flag_at(FB_has_invokedynamic); } @@ -113,6 +118,7 @@ // Assembly code support static int tags_offset_in_bytes() { return offset_of(constantPoolOopDesc, _tags); } static int cache_offset_in_bytes() { return offset_of(constantPoolOopDesc, _cache); } + static int operands_offset_in_bytes() { return offset_of(constantPoolOopDesc, _operands); } static int pool_holder_offset_in_bytes() { return offset_of(constantPoolOopDesc, _pool_holder); } // Storing constants @@ -156,10 +162,28 @@ *int_at_addr(which) = ref_index; } - void invoke_dynamic_at_put(int which, int bootstrap_method_index, int name_and_type_index) { + void invoke_dynamic_at_put(int which, int operand_base, int operand_count) { tag_at_put(which, JVM_CONSTANT_InvokeDynamic); - *int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_method_index; + *int_at_addr(which) = operand_base; // this is the real information } +#ifdef ASSERT + bool check_invoke_dynamic_at(int which, + int bootstrap_method_index, + int name_and_type_index, + int argument_count) { + assert(invoke_dynamic_bootstrap_method_ref_index_at(which) == bootstrap_method_index, + "already stored by caller"); + assert(invoke_dynamic_name_and_type_ref_index_at(which) == name_and_type_index, + "already stored by caller"); + assert(invoke_dynamic_argument_count_at(which) == argument_count, + "consistent argument count"); + if (argument_count != 0) { + invoke_dynamic_argument_index_at(which, 0); + invoke_dynamic_argument_index_at(which, argument_count - 1); + } + return true; + } +#endif //ASSERT // Temporary until actual use void unresolved_string_at_put(int which, symbolOop s) { @@ -401,27 +425,93 @@ int sym = method_type_index_at(which); return symbol_at(sym); } + + private: + // some nodes (InvokeDynamic) have a variable number of operands, each a u2 value + enum { _multi_operand_count_offset = -1, + _multi_operand_base_offset = 0, + _multi_operand_buffer_fill_pointer_offset = 0 // shared at front of operands array + }; + int multi_operand_buffer_length() { + return operands() == NULL ? 0 : operands()->length(); + } + int multi_operand_buffer_fill_pointer() { + return operands() == NULL + ? _multi_operand_buffer_fill_pointer_offset + 1 + : operands()->int_at(_multi_operand_buffer_fill_pointer_offset); + } + void multi_operand_buffer_grow(int min_length, TRAPS); + void set_multi_operand_buffer_fill_pointer(int fillp) { + assert(operands() != NULL, ""); + operands()->int_at_put(_multi_operand_buffer_fill_pointer_offset, fillp); + } + int multi_operand_base_at(int which) { + assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool"); + int op_base = *int_at_addr(which); + assert(op_base > _multi_operand_buffer_fill_pointer_offset, "Corrupted operand base"); + return op_base; + } + int multi_operand_count_at(int which) { + int op_base = multi_operand_base_at(which); + assert((uint)(op_base + _multi_operand_count_offset) < (uint)operands()->length(), "oob"); + int count = operands()->int_at(op_base + _multi_operand_count_offset); + return count; + } + int multi_operand_ref_at(int which, int i) { + int op_base = multi_operand_base_at(which); + assert((uint)i < (uint)multi_operand_count_at(which), "oob"); + assert((uint)(op_base + _multi_operand_base_offset + i) < (uint)operands()->length(), "oob"); + return operands()->int_at(op_base + _multi_operand_base_offset + i); + } + void set_multi_operand_ref_at(int which, int i, int ref) { + DEBUG_ONLY(multi_operand_ref_at(which, i)); // trigger asserts + int op_base = multi_operand_base_at(which); + operands()->int_at_put(op_base + _multi_operand_base_offset + i, ref); + } + + public: + // layout of InvokeDynamic: + enum { + _indy_bsm_offset = 0, // CONSTANT_MethodHandle bsm + _indy_nt_offset = 1, // CONSTANT_NameAndType descr + _indy_argc_offset = 2, // u2 argc + _indy_argv_offset = 3 // u2 argv[argc] + }; int invoke_dynamic_bootstrap_method_ref_index_at(int which) { assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool"); - jint ref_index = *int_at_addr(which); - return extract_low_short_from_int(ref_index); + return multi_operand_ref_at(which, _indy_bsm_offset); } int invoke_dynamic_name_and_type_ref_index_at(int which) { assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool"); - jint ref_index = *int_at_addr(which); - return extract_high_short_from_int(ref_index); + return multi_operand_ref_at(which, _indy_nt_offset); + } + int invoke_dynamic_argument_count_at(int which) { + assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool"); + int argc = multi_operand_ref_at(which, _indy_argc_offset); + DEBUG_ONLY(int op_count = multi_operand_count_at(which)); + assert(_indy_argv_offset + argc == op_count, "consistent inner and outer counts"); + return argc; + } + int invoke_dynamic_argument_index_at(int which, int j) { + assert((uint)j < (uint)invoke_dynamic_argument_count_at(which), "oob"); + return multi_operand_ref_at(which, _indy_argv_offset + j); } // The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve, // name_and_type_ref_index_at) all expect to be passed indices obtained - // directly from the bytecode, and extracted according to java byte order. + // directly from the bytecode. // If the indices are meant to refer to fields or methods, they are - // actually potentially byte-swapped, rewritten constant pool cache indices. + // actually rewritten constant pool cache indices. // The routine remap_instruction_operand_from_cache manages the adjustment // of these values back to constant pool indices. // There are also "uncached" versions which do not adjust the operand index; see below. + // FIXME: Consider renaming these with a prefix "cached_" to make the distinction clear. + // In a few cases (the verifier) there are uses before a cpcache has been built, + // which are handled by a dynamic check in remap_instruction_operand_from_cache. + // FIXME: Remove the dynamic check, and adjust all callers to specify the correct mode. + // Lookup for entries consisting of (klass_index, name_and_type index) klassOop klass_ref_at(int which, TRAPS); symbolOop klass_ref_at_noresolve(int which); @@ -443,15 +533,24 @@ resolve_string_constants_impl(h_this, CHECK); } + private: + enum { _no_index_sentinel = -1, _possible_index_sentinel = -2 }; + public: + // Resolve late bound constants. oop resolve_constant_at(int index, TRAPS) { constantPoolHandle h_this(THREAD, this); - return resolve_constant_at_impl(h_this, index, -1, THREAD); + return resolve_constant_at_impl(h_this, index, _no_index_sentinel, THREAD); } oop resolve_cached_constant_at(int cache_index, TRAPS) { constantPoolHandle h_this(THREAD, this); - return resolve_constant_at_impl(h_this, -1, cache_index, THREAD); + return resolve_constant_at_impl(h_this, _no_index_sentinel, cache_index, THREAD); + } + + oop resolve_possibly_cached_constant_at(int pool_index, TRAPS) { + constantPoolHandle h_this(THREAD, this); + return resolve_constant_at_impl(h_this, pool_index, _possible_index_sentinel, THREAD); } // Klass name matches name at offset @@ -484,7 +583,7 @@ static klassOop klass_ref_at_if_loaded_check(constantPoolHandle this_oop, int which, TRAPS); // Routines currently used for annotations (only called by jvm.cpp) but which might be used in the - // future by other Java code. These take constant pool indices rather than possibly-byte-swapped + // future by other Java code. These take constant pool indices rather than // constant pool cache indices as do the peer methods above. symbolOop uncached_klass_ref_at_noresolve(int which); symbolOop uncached_name_ref_at(int which) { return impl_name_ref_at(which, true); } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/oops/cpCacheOop.cpp --- a/hotspot/src/share/vm/oops/cpCacheOop.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/oops/cpCacheOop.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,19 @@ OrderAccess::release_store_ptr(&_indices, _indices | ((u_char)code << 24)); } +// Atomically sets f1 if it is still NULL, otherwise it keeps the +// current value. +void ConstantPoolCacheEntry::set_f1_if_null_atomic(oop f1) { + // Use barriers as in oop_store + HeapWord* f1_addr = (HeapWord*) &_f1; + update_barrier_set_pre(f1_addr, f1); + void* result = Atomic::cmpxchg_ptr(f1, f1_addr, NULL); + bool success = (result == NULL); + if (success) { + update_barrier_set((void*) f1_addr, f1); + } + } + #ifdef ASSERT // It is possible to have two different dummy methodOops created // when the resolve code for invoke interface executes concurrently @@ -165,7 +178,12 @@ } assert(method->can_be_statically_bound(), "must be a MH invoker method"); assert(AllowTransitionalJSR292 || _f2 >= constantPoolOopDesc::CPCACHE_INDEX_TAG, "BSM index initialized"); - set_f1(method()); + // 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 + // races in that case we store the first one coming in into the + // cp-cache atomically if it's still unset. + set_f1_if_null_atomic(method()); needs_vfinal_flag = false; // _f2 is not an oop assert(!is_vfinal(), "f2 not an oop"); byte_no = 1; // coordinate this with bytecode_number & is_resolved diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/oops/cpCacheOop.hpp --- a/hotspot/src/share/vm/oops/cpCacheOop.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/oops/cpCacheOop.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,6 +130,7 @@ assert(existing_f1 == NULL || existing_f1 == f1, "illegal field change"); oop_store(&_f1, f1); } + void set_f1_if_null_atomic(oop f1); void set_f2(intx f2) { assert(_f2 == 0 || _f2 == f2, "illegal field change"); _f2 = f2; } int as_flags(TosState state, bool is_final, bool is_vfinal, bool is_volatile, bool is_method_interface, bool is_method); @@ -318,7 +319,9 @@ // Sizing debug_only(friend class ClassVerifier;) + public: int length() const { return _length; } + private: void set_length(int length) { _length = length; } static int header_size() { return sizeof(constantPoolCacheOopDesc) / HeapWordSize; } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/oops/generateOopMap.cpp --- a/hotspot/src/share/vm/oops/generateOopMap.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/oops/generateOopMap.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1254,7 +1254,7 @@ case Bytecodes::_invokestatic: case Bytecodes::_invokedynamic: case Bytecodes::_invokeinterface: - int idx = currentBC->has_index_u4() ? currentBC->get_index_u4() : currentBC->get_index_u2(); + int idx = currentBC->has_index_u4() ? currentBC->get_index_u4() : currentBC->get_index_u2_cpcache(); constantPoolOop cp = method()->constants(); int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx); int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx); @@ -1286,7 +1286,7 @@ case Bytecodes::_invokestatic: case Bytecodes::_invokedynamic: case Bytecodes::_invokeinterface: - int idx = currentBC->has_index_u4() ? currentBC->get_index_u4() : currentBC->get_index_u2(); + int idx = currentBC->has_index_u4() ? currentBC->get_index_u4() : currentBC->get_index_u2_cpcache(); constantPoolOop cp = method()->constants(); int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx); int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx); @@ -1356,8 +1356,8 @@ case Bytecodes::_ldc2_w: ppush(vvCTS); break; - case Bytecodes::_ldc: do_ldc(itr->get_index(), itr->bci()); break; - case Bytecodes::_ldc_w: do_ldc(itr->get_index_u2(), itr->bci()); break; + case Bytecodes::_ldc: // fall through: + case Bytecodes::_ldc_w: do_ldc(itr->bci()); break; case Bytecodes::_iload: case Bytecodes::_fload: ppload(vCTS, itr->get_index()); break; @@ -1829,9 +1829,16 @@ -void GenerateOopMap::do_ldc(int idx, int bci) { +void GenerateOopMap::do_ldc(int bci) { + Bytecode_loadconstant* ldc = Bytecode_loadconstant_at(method(), bci); constantPoolOop cp = method()->constants(); - CellTypeState cts = cp->is_pointer_entry(idx) ? CellTypeState::make_line_ref(bci) : valCTS; + BasicType bt = ldc->result_type(); + CellTypeState cts = (bt == T_OBJECT) ? CellTypeState::make_line_ref(bci) : valCTS; + // Make sure bt==T_OBJECT is the same as old code (is_pointer_entry). + // Note that CONSTANT_MethodHandle entries are u2 index pairs, not pointer-entries, + // and they are processed by _fast_aldc and the CP cache. + assert((ldc->has_cache_index() || cp->is_pointer_entry(ldc->pool_index())) + ? (bt == T_OBJECT) : true, "expected object type"); ppush1(cts); } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/oops/generateOopMap.hpp --- a/hotspot/src/share/vm/oops/generateOopMap.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/oops/generateOopMap.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -389,7 +389,7 @@ void pp (CellTypeState *in, CellTypeState *out); void pp_new_ref (CellTypeState *in, int bci); void ppdupswap (int poplen, const char *out); - void do_ldc (int idx, int bci); + void do_ldc (int bci); void do_astore (int idx); void do_jsr (int delta); void do_field (int is_get, int is_static, int idx, int bci); diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/opto/divnode.cpp --- a/hotspot/src/share/vm/opto/divnode.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/opto/divnode.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -388,7 +388,8 @@ if (!d_pos) { q = new (phase->C, 3) SubLNode(phase->longcon(0), phase->transform(q)); } - } else { + } else if ( !Matcher::use_asm_for_ldiv_by_con(d) ) { // Use hardware DIV instruction when + // it is faster than code generated below. // Attempt the jlong constant divide -> multiply transform found in // "Division by Invariant Integers using Multiplication" // by Granlund and Montgomery @@ -558,7 +559,7 @@ set_req(0,NULL); // Dividing by a not-zero constant; no faulting - // Dividing by MININT does not optimize as a power-of-2 shift. + // Dividing by MINLONG does not optimize as a power-of-2 shift. if( l == min_jlong ) return NULL; return transform_long_divide( phase, in(1), l ); @@ -1062,7 +1063,7 @@ // Fell thru, the unroll case is not appropriate. Transform the modulo // into a long multiply/int multiply/subtract case - // Cannot handle mod 0, and min_jint isn't handled by the transform + // Cannot handle mod 0, and min_jlong isn't handled by the transform if( con == 0 || con == min_jlong ) return NULL; // Get the absolute value of the constant; at this point, we can use this @@ -1075,7 +1076,7 @@ // If this is a power of two, then maybe we can mask it if( is_power_of_2_long(pos_con) ) { - log2_con = log2_long(pos_con); + log2_con = exact_log2_long(pos_con); const Type *dt = phase->type(in(1)); const TypeLong *dtl = dt->isa_long(); @@ -1088,7 +1089,7 @@ // Save in(1) so that it cannot be changed or deleted hook->init_req(0, in(1)); - // Divide using the transform from DivI to MulL + // Divide using the transform from DivL to MulL Node *result = transform_long_divide( phase, in(1), pos_con ); if (result != NULL) { Node *divide = phase->transform(result); diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/opto/escape.cpp --- a/hotspot/src/share/vm/opto/escape.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/opto/escape.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -85,6 +85,7 @@ _nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()), _processed(C->comp_arena()), _collecting(true), + _progress(false), _compile(C), _igvn(igvn), _node_map(C->comp_arena()) { @@ -113,7 +114,7 @@ assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); assert(f->node_type() == PointsToNode::LocalVar || f->node_type() == PointsToNode::Field, "invalid source of PointsTo edge"); assert(t->node_type() == PointsToNode::JavaObject, "invalid destination of PointsTo edge"); - f->add_edge(to_i, PointsToNode::PointsToEdge); + add_edge(f, to_i, PointsToNode::PointsToEdge); } void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) { @@ -126,7 +127,7 @@ // don't add a self-referential edge, this can occur during removal of // deferred edges if (from_i != to_i) - f->add_edge(to_i, PointsToNode::DeferredEdge); + add_edge(f, to_i, PointsToNode::DeferredEdge); } int ConnectionGraph::address_offset(Node* adr, PhaseTransform *phase) { @@ -157,7 +158,7 @@ assert (t->offset() == -1 || t->offset() == offset, "conflicting field offsets"); t->set_offset(offset); - f->add_edge(to_i, PointsToNode::FieldEdge); + add_edge(f, to_i, PointsToNode::FieldEdge); } void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) { @@ -995,7 +996,7 @@ GrowableArray memnode_worklist; GrowableArray orig_phis; - PhaseGVN *igvn = _igvn; + PhaseIterGVN *igvn = _igvn; uint new_index_start = (uint) _compile->num_alias_types(); Arena* arena = Thread::current()->resource_area(); VectorSet visited(arena); @@ -1531,14 +1532,9 @@ has_allocations = true; } if(n->is_AddP()) { - // Collect address nodes which directly reference an allocation. - // Use them during stage 3 below to build initial connection graph - // field edges. Other field edges could be added after StoreP/LoadP - // nodes are processed during stage 4 below. - Node* base = get_addp_base(n); - if(base->is_Proj() && base->in(0)->is_Allocate()) { - cg_worklist.append(n->_idx); - } + // Collect address nodes. Use them during stage 3 below + // to build initial connection graph field edges. + cg_worklist.append(n->_idx); } else if (n->is_MergeMem()) { // Collect all MergeMem nodes to add memory slices for // scalar replaceable objects in split_unique_types(). @@ -1562,18 +1558,28 @@ build_connection_graph(n, igvn); } - // 3. Pass to create fields edges (Allocate -F-> AddP). + // 3. Pass to create initial fields edges (JavaObject -F-> AddP) + // to reduce number of iterations during stage 4 below. uint cg_length = cg_worklist.length(); for( uint next = 0; next < cg_length; ++next ) { int ni = cg_worklist.at(next); - build_connection_graph(ptnode_adr(ni)->_node, igvn); + Node* n = ptnode_adr(ni)->_node; + Node* base = get_addp_base(n); + if (base->is_Proj()) + base = base->in(0); + PointsToNode::NodeType nt = ptnode_adr(base->_idx)->node_type(); + if (nt == PointsToNode::JavaObject) { + build_connection_graph(n, igvn); + } } cg_worklist.clear(); cg_worklist.append(_phantom_object); + GrowableArray worklist; // 4. Build Connection Graph which need // to walk the connection graph. + _progress = false; for (uint ni = 0; ni < nodes_size(); ni++) { PointsToNode* ptn = ptnode_adr(ni); Node *n = ptn->_node; @@ -1581,13 +1587,52 @@ build_connection_graph(n, igvn); if (ptn->node_type() != PointsToNode::UnknownType) cg_worklist.append(n->_idx); // Collect CG nodes + if (!_processed.test(n->_idx)) + worklist.append(n->_idx); // Collect C/A/L/S nodes } } + // After IGVN user nodes may have smaller _idx than + // their inputs so they will be processed first in + // previous loop. Because of that not all Graph + // edges will be created. Walk over interesting + // nodes again until no new edges are created. + // + // Normally only 1-3 passes needed to build + // Connection Graph depending on graph complexity. + // Set limit to 10 to catch situation when something + // did go wrong and recompile the method without EA. + +#define CG_BUILD_ITER_LIMIT 10 + + uint length = worklist.length(); + int iterations = 0; + while(_progress && (iterations++ < CG_BUILD_ITER_LIMIT)) { + _progress = false; + for( uint next = 0; next < length; ++next ) { + int ni = worklist.at(next); + PointsToNode* ptn = ptnode_adr(ni); + Node* n = ptn->_node; + assert(n != NULL, "should be known node"); + build_connection_graph(n, igvn); + } + } + if (iterations >= CG_BUILD_ITER_LIMIT) { + assert(iterations < CG_BUILD_ITER_LIMIT, + err_msg("infinite EA connection graph build with %d nodes and worklist size %d", + nodes_size(), length)); + // Possible infinite build_connection_graph loop, + // retry compilation without escape analysis. + C->record_failure(C2Compiler::retry_no_escape_analysis()); + _collecting = false; + return false; + } +#undef CG_BUILD_ITER_LIMIT + Arena* arena = Thread::current()->resource_area(); VectorSet ptset(arena); - GrowableArray deferred_edges; VectorSet visited(arena); + worklist.clear(); // 5. Remove deferred edges from the graph and adjust // escape state of nonescaping objects. @@ -1597,7 +1642,7 @@ PointsToNode* ptn = ptnode_adr(ni); PointsToNode::NodeType nt = ptn->node_type(); if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { - remove_deferred(ni, &deferred_edges, &visited); + remove_deferred(ni, &worklist, &visited); Node *n = ptn->_node; if (n->is_AddP()) { // Search for objects which are not scalar replaceable @@ -1608,7 +1653,7 @@ } // 6. Propagate escape states. - GrowableArray worklist; + worklist.clear(); bool has_non_escaping_obj = false; // push all GlobalEscape nodes on the worklist @@ -2444,13 +2489,14 @@ // Don't set processed bit for AddP, LoadP, StoreP since // they may need more then one pass to process. + // Also don't mark as processed Call nodes since their + // arguments may need more then one pass to process. if (_processed.test(n_idx)) return; // No need to redefine node's state. if (n->is_Call()) { CallNode *call = n->as_Call(); process_call_arguments(call, phase); - _processed.set(n_idx); return; } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/opto/escape.hpp --- a/hotspot/src/share/vm/opto/escape.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/opto/escape.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -219,6 +219,9 @@ // is still being collected. If false, // no new nodes will be processed. + bool _progress; // Indicates whether new Graph's edges + // were created. + uint _phantom_object; // Index of globally escaping object // that pointer values loaded from // a field which has not been set @@ -266,6 +269,13 @@ void add_deferred_edge(uint from_i, uint to_i); void add_field_edge(uint from_i, uint to_i, int offs); + // Add an edge of the specified type pointing to the specified target. + // Set _progress if new edge is added. + void add_edge(PointsToNode *f, uint to_i, PointsToNode::EdgeType et) { + uint e_cnt = f->edge_count(); + f->add_edge(to_i, et); + _progress |= (f->edge_count() != e_cnt); + } // Add an edge to node given by "to_i" from any field of adr_i whose offset // matches "offset" A deferred edge is added if to_i is a LocalVar, and diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/opto/matcher.hpp --- a/hotspot/src/share/vm/opto/matcher.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/opto/matcher.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -298,6 +298,10 @@ // Register for MODL projection of divmodL static RegMask modL_proj_mask(); + // Use hardware DIV instruction when it is faster than + // a code which use multiply for division by constant. + static bool use_asm_for_ldiv_by_con( jlong divisor ); + static const RegMask method_handle_invoke_SP_save_mask(); // Java-Interpreter calling convention diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/prims/jvm.h --- a/hotspot/src/share/vm/prims/jvm.h Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvm.h Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1047,7 +1047,8 @@ JVM_CONSTANT_NameAndType, JVM_CONSTANT_MethodHandle = 15, // JSR 292 JVM_CONSTANT_MethodType = 16, // JSR 292 - JVM_CONSTANT_InvokeDynamic = 17 // JSR 292 + JVM_CONSTANT_InvokeDynamicTrans = 17, // JSR 292, only occurs in old class files + JVM_CONSTANT_InvokeDynamic = 18 // JSR 292 }; /* JVM_CONSTANT_MethodHandle subtypes */ diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/prims/jvmtiEnv.cpp --- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1407,8 +1407,7 @@ // If any of the top 2 frames is a compiled one, need to deoptimize it for (int i = 0; i < 2; i++) { if (!is_interpreted[i]) { - VM_DeoptimizeFrame op(java_thread, frame_sp[i]); - VMThread::execute(&op); + Deoptimization::deoptimize_frame(java_thread, frame_sp[i]); } } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/prims/jvmtiEnvBase.cpp --- a/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvmtiEnvBase.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1322,8 +1322,7 @@ if (!vf->fr().can_be_deoptimized()) { return JVMTI_ERROR_OPAQUE_FRAME; } - VM_DeoptimizeFrame deopt(java_thread, jvf->fr().id()); - VMThread::execute(&deopt); + Deoptimization::deoptimize_frame(java_thread, jvf->fr().id()); } // Get information about method return type diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/prims/jvmtiImpl.cpp --- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -728,8 +728,7 @@ // Schedule deoptimization so that eventually the local // update will be written to an interpreter frame. - VM_DeoptimizeFrame deopt(_jvf->thread(), _jvf->fr().id()); - VMThread::execute(&deopt); + Deoptimization::deoptimize_frame(_jvf->thread(), _jvf->fr().id()); // Now store a new value for the local which will be applied // once deoptimization occurs. Note however that while this diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/prims/methodComparator.cpp --- a/hotspot/src/share/vm/prims/methodComparator.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/prims/methodComparator.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -147,10 +147,9 @@ case Bytecodes::_invokevirtual : // fall through case Bytecodes::_invokespecial : // fall through case Bytecodes::_invokestatic : // fall through - case Bytecodes::_invokedynamic : // fall through case Bytecodes::_invokeinterface : { - int cpci_old = _s_old->has_index_u4() ? _s_old->get_index_u4() : _s_old->get_index_u2_cpcache(); - int cpci_new = _s_new->has_index_u4() ? _s_new->get_index_u4() : _s_new->get_index_u2_cpcache(); + int cpci_old = _s_old->get_index_u2_cpcache(); + int cpci_new = _s_new->get_index_u2_cpcache(); // Check if the names of classes, field/method names and signatures at these indexes // are the same. Indices which are really into constantpool cache (rather than constant // pool itself) are accepted by the constantpool query routines below. @@ -160,6 +159,33 @@ return false; break; } + case Bytecodes::_invokedynamic: { + int cpci_old = _s_old->get_index_u4(); + int cpci_new = _s_new->get_index_u4(); + // Check if the names of classes, field/method names and signatures at these indexes + // are the same. Indices which are really into constantpool cache (rather than constant + // pool itself) are accepted by the constantpool query routines below. + if ((_old_cp->name_ref_at(cpci_old) != _new_cp->name_ref_at(cpci_new)) || + (_old_cp->signature_ref_at(cpci_old) != _new_cp->signature_ref_at(cpci_new))) + return false; + int cpi_old = _old_cp->cache()->main_entry_at(cpci_old)->constant_pool_index(); + int cpi_new = _new_cp->cache()->main_entry_at(cpci_new)->constant_pool_index(); + int bsm_old = _old_cp->invoke_dynamic_bootstrap_method_ref_index_at(cpi_old); + int bsm_new = _new_cp->invoke_dynamic_bootstrap_method_ref_index_at(cpi_new); + if (!pool_constants_same(bsm_old, bsm_new)) + return false; + int cnt_old = _old_cp->invoke_dynamic_argument_count_at(cpi_old); + int cnt_new = _new_cp->invoke_dynamic_argument_count_at(cpi_new); + if (cnt_old != cnt_new) + return false; + for (int arg_i = 0; arg_i < cnt_old; arg_i++) { + int idx_old = _old_cp->invoke_dynamic_argument_index_at(cpi_old, arg_i); + int idx_new = _new_cp->invoke_dynamic_argument_index_at(cpi_new, arg_i); + if (!pool_constants_same(idx_old, idx_new)) + return false; + } + break; + } case Bytecodes::_ldc : // fall through case Bytecodes::_ldc_w : { @@ -167,51 +193,8 @@ Bytecode_loadconstant* ldc_new = Bytecode_loadconstant_at(_s_new->method(), _s_new->bci()); int cpi_old = ldc_old->pool_index(); int cpi_new = ldc_new->pool_index(); - constantTag tag_old = _old_cp->tag_at(cpi_old); - constantTag tag_new = _new_cp->tag_at(cpi_new); - if (tag_old.is_int() || tag_old.is_float()) { - if (tag_old.value() != tag_new.value()) - return false; - if (tag_old.is_int()) { - if (_old_cp->int_at(cpi_old) != _new_cp->int_at(cpi_new)) - return false; - } else { - // Use jint_cast to compare the bits rather than numerical values. - // This makes a difference for NaN constants. - if (jint_cast(_old_cp->float_at(cpi_old)) != jint_cast(_new_cp->float_at(cpi_new))) - return false; - } - } else if (tag_old.is_string() || tag_old.is_unresolved_string()) { - if (! (tag_new.is_unresolved_string() || tag_new.is_string())) - return false; - if (strcmp(_old_cp->string_at_noresolve(cpi_old), - _new_cp->string_at_noresolve(cpi_new)) != 0) - return false; - } else if (tag_old.is_klass() || tag_old.is_unresolved_klass()) { - // tag_old should be klass - 4881222 - if (! (tag_new.is_unresolved_klass() || tag_new.is_klass())) - return false; - if (_old_cp->klass_at_noresolve(cpi_old) != - _new_cp->klass_at_noresolve(cpi_new)) - return false; - } else if (tag_old.is_method_type() && tag_new.is_method_type()) { - int mti_old = _old_cp->method_type_index_at(cpi_old); - int mti_new = _new_cp->method_type_index_at(cpi_new); - if ((_old_cp->symbol_at(mti_old) != _new_cp->symbol_at(mti_new))) - return false; - } else if (tag_old.is_method_handle() && tag_new.is_method_handle()) { - if (_old_cp->method_handle_ref_kind_at(cpi_old) != - _new_cp->method_handle_ref_kind_at(cpi_new)) - return false; - int mhi_old = _old_cp->method_handle_index_at(cpi_old); - int mhi_new = _new_cp->method_handle_index_at(cpi_new); - if ((_old_cp->uncached_klass_ref_at_noresolve(mhi_old) != _new_cp->uncached_klass_ref_at_noresolve(mhi_new)) || - (_old_cp->uncached_name_ref_at(mhi_old) != _new_cp->uncached_name_ref_at(mhi_new)) || - (_old_cp->uncached_signature_ref_at(mhi_old) != _new_cp->uncached_signature_ref_at(mhi_new))) - return false; - } else { - return false; // unknown tag - } + if (!pool_constants_same(cpi_old, cpi_new)) + return false; break; } @@ -392,6 +375,55 @@ return true; } +bool MethodComparator::pool_constants_same(int cpi_old, int cpi_new) { + constantTag tag_old = _old_cp->tag_at(cpi_old); + constantTag tag_new = _new_cp->tag_at(cpi_new); + if (tag_old.is_int() || tag_old.is_float()) { + if (tag_old.value() != tag_new.value()) + return false; + if (tag_old.is_int()) { + if (_old_cp->int_at(cpi_old) != _new_cp->int_at(cpi_new)) + return false; + } else { + // Use jint_cast to compare the bits rather than numerical values. + // This makes a difference for NaN constants. + if (jint_cast(_old_cp->float_at(cpi_old)) != jint_cast(_new_cp->float_at(cpi_new))) + return false; + } + } else if (tag_old.is_string() || tag_old.is_unresolved_string()) { + if (! (tag_new.is_unresolved_string() || tag_new.is_string())) + return false; + if (strcmp(_old_cp->string_at_noresolve(cpi_old), + _new_cp->string_at_noresolve(cpi_new)) != 0) + return false; + } else if (tag_old.is_klass() || tag_old.is_unresolved_klass()) { + // tag_old should be klass - 4881222 + if (! (tag_new.is_unresolved_klass() || tag_new.is_klass())) + return false; + if (_old_cp->klass_at_noresolve(cpi_old) != + _new_cp->klass_at_noresolve(cpi_new)) + return false; + } else if (tag_old.is_method_type() && tag_new.is_method_type()) { + int mti_old = _old_cp->method_type_index_at(cpi_old); + int mti_new = _new_cp->method_type_index_at(cpi_new); + if ((_old_cp->symbol_at(mti_old) != _new_cp->symbol_at(mti_new))) + return false; + } else if (tag_old.is_method_handle() && tag_new.is_method_handle()) { + if (_old_cp->method_handle_ref_kind_at(cpi_old) != + _new_cp->method_handle_ref_kind_at(cpi_new)) + return false; + int mhi_old = _old_cp->method_handle_index_at(cpi_old); + int mhi_new = _new_cp->method_handle_index_at(cpi_new); + if ((_old_cp->uncached_klass_ref_at_noresolve(mhi_old) != _new_cp->uncached_klass_ref_at_noresolve(mhi_new)) || + (_old_cp->uncached_name_ref_at(mhi_old) != _new_cp->uncached_name_ref_at(mhi_new)) || + (_old_cp->uncached_signature_ref_at(mhi_old) != _new_cp->uncached_signature_ref_at(mhi_new))) + return false; + } else { + return false; // unknown tag + } + return true; +} + int MethodComparator::check_stack_and_locals_size(methodOop old_method, methodOop new_method) { if (old_method->max_stack() != new_method->max_stack()) { diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/prims/methodComparator.hpp --- a/hotspot/src/share/vm/prims/methodComparator.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/prims/methodComparator.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ static GrowableArray *_fwd_jmps; static bool args_same(Bytecodes::Code c_old, Bytecodes::Code c_new); + static bool pool_constants_same(int cpi_old, int cpi_new); static int check_stack_and_locals_size(methodOop old_method, methodOop new_method); public: diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/prims/methodHandles.cpp --- a/hotspot/src/share/vm/prims/methodHandles.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/prims/methodHandles.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -974,6 +974,8 @@ assert(src != T_VOID && dst != T_VOID, "should not be here"); if (src == dst) return true; if (type2size[src] != type2size[dst]) return false; + if (src == T_OBJECT || dst == T_OBJECT) return false; + if (raw) return true; // bitwise reinterpretation; caller guarantees safety // allow reinterpretation casts for integral widening if (is_subword_type(src)) { // subwords can fit in int or other subwords if (dst == T_INT) // any subword fits in an int diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -978,17 +978,6 @@ } } - // XXX JSR 292 currently does not support compressed oops - if (EnableMethodHandles) { - if (is_on_by_default) { - FLAG_SET_DEFAULT(UseCompressedOops, false); - return; - } else { - vm_exit_during_initialization( - "JSR292 is not supported with compressed oops yet", NULL); - } - } - // If dumping an archive or forcing its use, disable compressed oops if possible if (DumpSharedSpaces || RequireSharedSpaces) { if (is_on_by_default) { diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/deoptimization.cpp --- a/hotspot/src/share/vm/runtime/deoptimization.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1065,7 +1065,9 @@ } -void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) { +void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id) { + assert(thread == Thread::current() || SafepointSynchronize::is_at_safepoint(), + "can only deoptimize other thread at a safepoint"); // Compute frame and register map based on thread and sp. RegisterMap reg_map(thread, UseBiasedLocking); frame fr = thread->last_frame(); @@ -1076,6 +1078,16 @@ } +void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) { + if (thread == Thread::current()) { + Deoptimization::deoptimize_frame_internal(thread, id); + } else { + VM_DeoptimizeFrame deopt(thread, id); + VMThread::execute(&deopt); + } +} + + // JVMTI PopFrame support JRT_LEAF(void, Deoptimization::popframe_preserve_args(JavaThread* thread, int bytes_to_save, void* start_address)) { diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/deoptimization.hpp --- a/hotspot/src/share/vm/runtime/deoptimization.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -216,6 +216,10 @@ // Only called from VMDeoptimizeFrame // @argument thread. Thread where stub_frame resides. // @argument id. id of frame that should be deoptimized. + static void deoptimize_frame_internal(JavaThread* thread, intptr_t* id); + + // If thread is not the current thread then execute + // VM_DeoptimizeFrame otherwise deoptimize directly. static void deoptimize_frame(JavaThread* thread, intptr_t* id); // Statistics diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/frame.cpp --- a/hotspot/src/share/vm/runtime/frame.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/frame.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -878,7 +878,7 @@ #endif /* CC_INTERP */ -#ifndef PPC +#if !defined(PPC) || defined(ZERO) if (m->is_native()) { #ifdef CC_INTERP f->do_oop((oop*)&istate->_oop_temp); diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/java.cpp --- a/hotspot/src/share/vm/runtime/java.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/java.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -198,7 +198,7 @@ if (CountCompiledCalls) { print_method_invocation_histogram(); } - if (ProfileInterpreter || C1UpdateMethodData) { + if (ProfileInterpreter COMPILER1_PRESENT(|| C1UpdateMethodData)) { print_method_profiling_data(); } if (TimeCompiler) { diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/os.cpp --- a/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -736,8 +736,8 @@ } // moved from debug.cpp (used to be find()) but still called from there -// The print_pc parameter is only set by the debug code in one case -void os::print_location(outputStream* st, intptr_t x, bool print_pc) { +// The verbose parameter is only set by the debug code in one case +void os::print_location(outputStream* st, intptr_t x, bool verbose) { address addr = (address)x; CodeBlob* b = CodeCache::find_blob_unsafe(addr); if (b != NULL) { @@ -745,6 +745,7 @@ // the interpreter is generated into a buffer blob InterpreterCodelet* i = Interpreter::codelet_containing(addr); if (i != NULL) { + st->print_cr(INTPTR_FORMAT " is an Interpreter codelet", addr); i->print_on(st); return; } @@ -755,14 +756,14 @@ } // if (AdapterHandlerLibrary::contains(b)) { - st->print_cr("Printing AdapterHandler"); + st->print_cr(INTPTR_FORMAT " is an AdapterHandler", addr); AdapterHandlerLibrary::print_handler_on(st, b); } // the stubroutines are generated into a buffer blob StubCodeDesc* d = StubCodeDesc::desc_for(addr); if (d != NULL) { d->print_on(st); - if (print_pc) st->cr(); + if (verbose) st->cr(); return; } if (StubRoutines::contains(addr)) { @@ -781,7 +782,7 @@ return; } } - if (print_pc && b->is_nmethod()) { + if (verbose && b->is_nmethod()) { ResourceMark rm; st->print("%#p: Compiled ", addr); ((nmethod*)b)->method()->print_value_on(st); @@ -789,11 +790,12 @@ st->cr(); return; } + st->print(INTPTR_FORMAT " ", b); if ( b->is_nmethod()) { if (b->is_zombie()) { - st->print_cr(INTPTR_FORMAT " is zombie nmethod", b); + st->print_cr("is zombie nmethod"); } else if (b->is_not_entrant()) { - st->print_cr(INTPTR_FORMAT " is non-entrant nmethod", b); + st->print_cr("is non-entrant nmethod"); } } b->print_on(st); @@ -812,6 +814,7 @@ print = true; } if (print) { + st->print_cr(INTPTR_FORMAT " is an oop", addr); oop(p)->print_on(st); if (p != (HeapWord*)x && oop(p)->is_constMethod() && constMethodOop(p)->contains(addr)) { @@ -855,12 +858,16 @@ thread->privileged_stack_top()->contains(addr)) { st->print_cr(INTPTR_FORMAT " is pointing into the privilege stack " "for thread: " INTPTR_FORMAT, addr, thread); - thread->print_on(st); + if (verbose) thread->print_on(st); return; } // If the addr is a java thread print information about that. if (addr == (address)thread) { - thread->print_on(st); + if (verbose) { + thread->print_on(st); + } else { + st->print_cr(INTPTR_FORMAT " is a thread", addr); + } return; } // If the addr is in the stack region for this thread then report that @@ -869,7 +876,7 @@ addr > (thread->stack_base() - thread->stack_size())) { st->print_cr(INTPTR_FORMAT " is pointing into the stack for thread: " INTPTR_FORMAT, addr, thread); - thread->print_on(st); + if (verbose) thread->print_on(st); return; } @@ -879,7 +886,7 @@ return; } - st->print_cr(INTPTR_FORMAT " is pointing to unknown location", addr); + st->print_cr(INTPTR_FORMAT " is an unknown value", addr); } // Looks like all platforms except IA64 can use the same function to check diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/os.hpp --- a/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/os.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -450,11 +450,12 @@ static void print_dll_info(outputStream* st); static void print_environment_variables(outputStream* st, const char** env_list, char* buffer, int len); static void print_context(outputStream* st, void* context); + static void print_register_info(outputStream* st, void* context); static void print_siginfo(outputStream* st, void* siginfo); static void print_signal_handlers(outputStream* st, char* buf, size_t buflen); static void print_date_and_time(outputStream* st); - static void print_location(outputStream* st, intptr_t x, bool print_pc = false); + static void print_location(outputStream* st, intptr_t x, bool verbose = false); // The following two functions are used by fatal error handler to trace // native (C) frames. They are not part of frame.hpp/frame.cpp because diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/safepoint.cpp --- a/hotspot/src/share/vm/runtime/safepoint.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/safepoint.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -940,8 +940,7 @@ // as otherwise we may never deliver it. if (thread()->has_async_condition()) { ThreadInVMfromJavaNoAsyncException __tiv(thread()); - VM_DeoptimizeFrame deopt(thread(), caller_fr.id()); - VMThread::execute(&deopt); + Deoptimization::deoptimize_frame(thread(), caller_fr.id()); } // If an exception has been installed we must check for a pending deoptimization diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -1199,6 +1199,7 @@ _exception_pc = 0; _exception_handler_pc = 0; _exception_stack_size = 0; + _is_method_handle_return = 0; _jvmti_thread_state= NULL; _should_post_on_exceptions_flag = JNI_FALSE; _jvmti_get_loaded_classes_closure = NULL; diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/vmStructs.cpp --- a/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -86,6 +86,7 @@ nonstatic_field(constantPoolOopDesc, _tags, typeArrayOop) \ nonstatic_field(constantPoolOopDesc, _cache, constantPoolCacheOop) \ nonstatic_field(constantPoolOopDesc, _pool_holder, klassOop) \ + nonstatic_field(constantPoolOopDesc, _operands, typeArrayOop) \ nonstatic_field(constantPoolOopDesc, _length, int) \ nonstatic_field(constantPoolCacheOopDesc, _length, int) \ nonstatic_field(constantPoolCacheOopDesc, _constant_pool, constantPoolOop) \ @@ -1527,6 +1528,17 @@ \ declare_constant(symbolOopDesc::max_symbol_length) \ \ + /*************************************************/ \ + /* constantPoolOop layout enum for InvokeDynamic */ \ + /*************************************************/ \ + \ + declare_constant(constantPoolOopDesc::_multi_operand_count_offset) \ + declare_constant(constantPoolOopDesc::_multi_operand_base_offset) \ + declare_constant(constantPoolOopDesc::_indy_bsm_offset) \ + declare_constant(constantPoolOopDesc::_indy_nt_offset) \ + declare_constant(constantPoolOopDesc::_indy_argc_offset) \ + declare_constant(constantPoolOopDesc::_indy_argv_offset) \ + \ /*********************************************/ \ /* ConstantPoolCacheEntry FlagBitValues enum */ \ /*********************************************/ \ diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/vm_operations.cpp --- a/hotspot/src/share/vm/runtime/vm_operations.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -100,7 +100,7 @@ void VM_DeoptimizeFrame::doit() { - Deoptimization::deoptimize_frame(_thread, _id); + Deoptimization::deoptimize_frame_internal(_thread, _id); } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/runtime/vm_operations.hpp --- a/hotspot/src/share/vm/runtime/vm_operations.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -231,12 +231,18 @@ bool allow_nested_vm_operations() const { return true; } }; + +// Deopt helper that can deoptimize frames in threads other than the +// current thread. Only used through Deoptimization::deoptimize_frame. class VM_DeoptimizeFrame: public VM_Operation { + friend class Deoptimization; + private: JavaThread* _thread; intptr_t* _id; + VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id); + public: - VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id); VMOp_Type type() const { return VMOp_DeoptimizeFrame; } void doit(); bool allow_nested_vm_operations() const { return true; } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/utilities/constantTag.hpp --- a/hotspot/src/share/vm/utilities/constantTag.hpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/utilities/constantTag.hpp Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,13 @@ bool is_method_handle() const { return _tag == JVM_CONSTANT_MethodHandle; } bool is_invoke_dynamic() const { return _tag == JVM_CONSTANT_InvokeDynamic; } + bool is_loadable_constant() const { + return ((_tag >= JVM_CONSTANT_Integer && _tag <= JVM_CONSTANT_String) || + is_method_type() || is_method_handle() || + is_unresolved_klass() || is_unresolved_string() || + is_object()); + } + constantTag() { _tag = JVM_CONSTANT_Invalid; } diff -r dad682f1a84a -r 4951967a61b4 hotspot/src/share/vm/utilities/vmError.cpp --- a/hotspot/src/share/vm/utilities/vmError.cpp Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/src/share/vm/utilities/vmError.cpp Wed Jul 05 17:27:29 2017 +0200 @@ -455,6 +455,14 @@ st->cr(); } + STEP(105, "(printing register info)") + + // decode register contents if possible + if (_verbose && _context && Universe::is_fully_initialized()) { + os::print_register_info(st, _context); + st->cr(); + } + STEP(110, "(printing stack bounds)" ) if (_verbose) { @@ -522,7 +530,7 @@ STEP(135, "(printing target Java thread stack)" ) // printing Java thread stack trace if it is involved in GC crash - if (_verbose && (_thread->is_Named_thread())) { + if (_verbose && _thread && (_thread->is_Named_thread())) { JavaThread* jt = ((NamedThread *)_thread)->processed_thread(); if (jt != NULL) { st->print_cr("JavaThread " PTR_FORMAT " (nid = " UINTX_FORMAT ") was being processed", jt, jt->osthread()->thread_id()); @@ -608,6 +616,14 @@ st->cr(); } + STEP(195, "(printing code cache information)" ) + + if (_verbose && Universe::is_fully_initialized()) { + // print code cache information before vm abort + CodeCache::print_bounds(st); + st->cr(); + } + STEP(200, "(printing dynamic libraries)" ) if (_verbose) { diff -r dad682f1a84a -r 4951967a61b4 hotspot/test/Makefile --- a/hotspot/test/Makefile Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/test/Makefile Wed Jul 05 17:27:29 2017 +0200 @@ -78,7 +78,11 @@ TEST_ROOT := $(shell pwd) # Root of all test results -ABS_BUILD_ROOT = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH) +ifdef ALT_OUTPUTDIR + ABS_BUILD_ROOT = $(ALT_OUTPUTDIR)/$(PLATFORM)-$(ARCH) +else + ABS_BUILD_ROOT = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH) +endif ABS_TEST_OUTPUT_DIR = $(ABS_BUILD_ROOT)/testoutput # Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test) diff -r dad682f1a84a -r 4951967a61b4 hotspot/test/compiler/6603011/Test.java --- a/hotspot/test/compiler/6603011/Test.java Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/test/compiler/6603011/Test.java Wed Jul 05 17:27:29 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,8 +108,10 @@ if (quo != quo0 || rem != rem0) { if (VERBOSE) { - System.out.println(" " + dividend + " / " + divisor() + " = " + - quo + ", " + dividend + " % " + divisor() + " = " + rem); + System.out.println("Computed: " + dividend + " / " + divisor() + " = " + + quo + ", " + dividend + " % " + divisor() + " = " + rem ); + System.out.println("expected: " + dividend + " / " + divisor() + " = " + + quo0 + ", " + dividend + " % " + divisor() + " = " + rem0); // Report sign of rem failure if (rem != 0 && (rem ^ dividend) < 0) { System.out.println(" rem & dividend have different signs"); @@ -168,7 +170,7 @@ for (int i = start; i <= end; i++) { for (int s = 0; s < 64; s += 4) { total++; - long dividend = i << s; + long dividend = ((long)i) << s; if (!checkL(dividend)) { wrong++; // Stop on the first failure diff -r dad682f1a84a -r 4951967a61b4 hotspot/test/compiler/6857159/Test6857159.java --- a/hotspot/test/compiler/6857159/Test6857159.java Wed Jul 05 17:26:57 2017 +0200 +++ b/hotspot/test/compiler/6857159/Test6857159.java Wed Jul 05 17:27:29 2017 +0200 @@ -54,7 +54,7 @@ } public static void main(String[] args) throws Exception { - for (int i = 0; i < 100000; i++) { + for (int i = 0; i < 20000; i++) { Thread t = null; switch (i % 3) { case 0: t = new ct0(); break; diff -r dad682f1a84a -r 4951967a61b4 hotspot/test/compiler/6991596/Test6991596.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/6991596/Test6991596.java Wed Jul 05 17:27:29 2017 +0200 @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 6991596 + * @summary JSR 292 unimplemented adapter_opt_i2i and adapter_opt_l2i on SPARC + * + * @run main/othervm -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6991596 + */ + +import java.dyn.*; + +public class Test6991596 { + private static final Class CLASS = Test6991596.class; + private static final String NAME = "foo"; + private static final boolean DEBUG = false; + + public static void main(String[] args) throws Throwable { + testboolean(); + testbyte(); + testchar(); + testshort(); + testint(); + testlong(); + } + + // Helpers to get various methods. + static MethodHandle getmh1(Class ret, Class arg) { + return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg)); + } + static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) { + return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); + } + static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) { + return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); + } + + // test adapter_opt_i2i + static void testboolean() throws Throwable { + boolean[] a = new boolean[] { + true, + false + }; + for (int i = 0; i < a.length; i++) { + doboolean(a[i]); + } + } + static void doboolean(boolean x) throws Throwable { + if (DEBUG) System.out.println("boolean=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, boolean.class); + // TODO add this for all cases when the bugs are fixed. + //MethodHandle mh3 = getmh3(mh1, boolean.class, boolean.class); + boolean a = mh1.invokeExact((boolean) x); + boolean b = mh2.invokeExact(x); + //boolean c = mh3.invokeExact((boolean) x); + assert a == b : a + " != " + b; + //assert c == x : c + " != " + x; + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class ); + MethodHandle mh2 = getmh2(mh1, byte.class, boolean.class); + byte a = mh1.invokeExact((byte) (x ? 1 : 0)); + byte b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, boolean.class); + char a = mh1.invokeExact((char) (x ? 1 : 0)); + char b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, boolean.class); + short a = mh1.invokeExact((short) (x ? 1 : 0)); + short b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + } + + static void testbyte() throws Throwable { + byte[] a = new byte[] { + Byte.MIN_VALUE, + Byte.MIN_VALUE + 1, + -0x0F, + -1, + 0, + 1, + 0x0F, + Byte.MAX_VALUE - 1, + Byte.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + dobyte(a[i]); + } + } + static void dobyte(byte x) throws Throwable { + if (DEBUG) System.out.println("byte=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, byte.class); + boolean a = mh1.invokeExact((x & 1) == 1); + boolean b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class); + MethodHandle mh2 = getmh2(mh1, byte.class, byte.class); + byte a = mh1.invokeExact((byte) x); + byte b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, byte.class); + char a = mh1.invokeExact((char) x); + char b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, byte.class); + short a = mh1.invokeExact((short) x); + short b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + } + + static void testchar() throws Throwable { + char[] a = new char[] { + Character.MIN_VALUE, + Character.MIN_VALUE + 1, + 0x000F, + 0x00FF, + 0x0FFF, + Character.MAX_VALUE - 1, + Character.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + dochar(a[i]); + } + } + static void dochar(char x) throws Throwable { + if (DEBUG) System.out.println("char=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, char.class); + boolean a = mh1.invokeExact((x & 1) == 1); + boolean b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class); + MethodHandle mh2 = getmh2(mh1, byte.class, char.class); + byte a = mh1.invokeExact((byte) x); + byte b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, char.class); + char a = mh1.invokeExact((char) x); + char b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, char.class); + short a = mh1.invokeExact((short) x); + short b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + } + + static void testshort() throws Throwable { + short[] a = new short[] { + Short.MIN_VALUE, + Short.MIN_VALUE + 1, + -0x0FFF, + -0x00FF, + -0x000F, + -1, + 0, + 1, + 0x000F, + 0x00FF, + 0x0FFF, + Short.MAX_VALUE - 1, + Short.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + doshort(a[i]); + } + } + static void doshort(short x) throws Throwable { + if (DEBUG) System.out.println("short=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, short.class); + boolean a = mh1.invokeExact((x & 1) == 1); + boolean b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class); + MethodHandle mh2 = getmh2(mh1, byte.class, short.class); + byte a = mh1.invokeExact((byte) x); + byte b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, short.class); + char a = mh1.invokeExact((char) x); + char b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, short.class); + short a = mh1.invokeExact((short) x); + short b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + } + + static void testint() throws Throwable { + int[] a = new int[] { + Integer.MIN_VALUE, + Integer.MIN_VALUE + 1, + -0x0FFFFFFF, + -0x00FFFFFF, + -0x000FFFFF, + -0x0000FFFF, + -0x00000FFF, + -0x000000FF, + -0x0000000F, + -1, + 0, + 1, + 0x0000000F, + 0x000000FF, + 0x00000FFF, + 0x0000FFFF, + 0x000FFFFF, + 0x00FFFFFF, + 0x0FFFFFFF, + Integer.MAX_VALUE - 1, + Integer.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + doint(a[i]); + } + } + static void doint(int x) throws Throwable { + if (DEBUG) System.out.println("int=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, int.class); + boolean a = mh1.invokeExact((x & 1) == 1); + boolean b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class); + MethodHandle mh2 = getmh2(mh1, byte.class, int.class); + byte a = mh1.invokeExact((byte) x); + byte b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, int.class); + char a = mh1.invokeExact((char) x); + char b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, int.class); + short a = mh1.invokeExact((short) x); + short b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // int + { + MethodHandle mh1 = getmh1( int.class, int.class); + MethodHandle mh2 = getmh2(mh1, int.class, int.class); + int a = mh1.invokeExact((int) x); + int b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + } + + // test adapter_opt_l2i + static void testlong() throws Throwable { + long[] a = new long[] { + Long.MIN_VALUE, + Long.MIN_VALUE + 1, + -0x000000000FFFFFFFL, + -0x0000000000FFFFFFL, + -0x00000000000FFFFFL, + -0x000000000000FFFFL, + -0x0000000000000FFFL, + -0x00000000000000FFL, + -0x000000000000000FL, + -1L, + 0L, + 1L, + 0x000000000000000FL, + 0x00000000000000FFL, + 0x0000000000000FFFL, + 0x0000000000000FFFL, + 0x000000000000FFFFL, + 0x00000000000FFFFFL, + 0x0000000000FFFFFFL, + 0x000000000FFFFFFFL, + Long.MAX_VALUE - 1, + Long.MAX_VALUE + }; + for (int i = 0; i < a.length; i++) { + dolong(a[i]); + } + } + static void dolong(long x) throws Throwable { + if (DEBUG) System.out.println("long=" + x); + + // boolean + { + MethodHandle mh1 = getmh1( boolean.class, boolean.class); + MethodHandle mh2 = getmh2(mh1, boolean.class, long.class); + boolean a = mh1.invokeExact((x & 1L) == 1L); + boolean b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // byte + { + MethodHandle mh1 = getmh1( byte.class, byte.class); + MethodHandle mh2 = getmh2(mh1, byte.class, long.class); + byte a = mh1.invokeExact((byte) x); + byte b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // char + { + MethodHandle mh1 = getmh1( char.class, char.class); + MethodHandle mh2 = getmh2(mh1, char.class, long.class); + char a = mh1.invokeExact((char) x); + char b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // short + { + MethodHandle mh1 = getmh1( short.class, short.class); + MethodHandle mh2 = getmh2(mh1, short.class, long.class); + short a = mh1.invokeExact((short) x); + short b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + // int + { + MethodHandle mh1 = getmh1( int.class, int.class); + MethodHandle mh2 = getmh2(mh1, int.class, long.class); + int a = mh1.invokeExact((int) x); + int b = mh2.invokeExact(x); + assert a == b : a + " != " + b; + } + + } + + // to int + public static boolean foo(boolean i) { return i; } + public static byte foo(byte i) { return i; } + public static char foo(char i) { return i; } + public static short foo(short i) { return i; } + public static int foo(int i) { return i; } +} diff -r dad682f1a84a -r 4951967a61b4 jaxp/.hgtags --- a/jaxp/.hgtags Wed Jul 05 17:26:57 2017 +0200 +++ b/jaxp/.hgtags Wed Jul 05 17:27:29 2017 +0200 @@ -92,3 +92,4 @@ dc1612e1d3ac08eb8fcad764daff21c9247d33c9 jdk7-b115 f8d4e6c6cfce1cda23fcbd144628a9791a9e1a63 jdk7-b116 9ee4d96e893436a48607924227dadd2d93b9b00d jdk7-b117 +b2f6d9c4f12ffd307a5de40455b2b61b31a5cb79 jdk7-b118 diff -r dad682f1a84a -r 4951967a61b4 jaxws/.hgtags --- a/jaxws/.hgtags Wed Jul 05 17:26:57 2017 +0200 +++ b/jaxws/.hgtags Wed Jul 05 17:27:29 2017 +0200 @@ -92,3 +92,4 @@ 824cc44bd6eba9abae07cc420f7fe3926c1adbd9 jdk7-b115 376ac153078dd3b5f6d4a0981feee092c1492c96 jdk7-b116 1320fb3bb588298c79716bd2d10b5b4afacb9370 jdk7-b117 +19a2fab3f91a275f90791c15d1c21a24e820ff2d jdk7-b118 diff -r dad682f1a84a -r 4951967a61b4 jdk/.hgtags --- a/jdk/.hgtags Wed Jul 05 17:26:57 2017 +0200 +++ b/jdk/.hgtags Wed Jul 05 17:27:29 2017 +0200 @@ -92,3 +92,4 @@ 449bad8d67b5808ecf0f927683acc0a5940f8c85 jdk7-b115 1657ed4e1d86c8aa2028ab5a41f9da1ac4a369f8 jdk7-b116 3e6726bbf80a4254ecd01051c8ed77ee19325e46 jdk7-b117 +b357910aa04aead2a16b6d6ff395a8df4b51d1dd jdk7-b118 diff -r dad682f1a84a -r 4951967a61b4 langtools/.hgtags --- a/langtools/.hgtags Wed Jul 05 17:26:57 2017 +0200 +++ b/langtools/.hgtags Wed Jul 05 17:27:29 2017 +0200 @@ -92,3 +92,4 @@ 01e8ac5fbefd35d2d9a0996213cf2390fd164e57 jdk7-b115 857bfcea3f30cb5f4ae96f46a53ae1c772f9b0e5 jdk7-b116 2129a046f117547fc8a5cb3397a767e6d528f5b6 jdk7-b117 +c491eec0acc73fa41b77e1619ed03e56d8a75b83 jdk7-b118