Merge
This commit is contained in:
commit
da51c5b9c3
@ -92,3 +92,4 @@ c1df968c4527bfab5f97662a89245f15d12d378b jdk7-b113
|
||||
e8ebdf41b9c01a26642848f4134f5504e8fb3233 jdk7-b115
|
||||
94e9a1bfba8b8d1fe0bfd43b88629b1f27b02a76 jdk7-b116
|
||||
7220e60b097fa027e922f1aeecdd330f3e37409f jdk7-b117
|
||||
a12a9e78df8a9d534da0b4a244ed68f0de0bd58e jdk7-b118
|
||||
|
@ -129,3 +129,5 @@ bdbc48857210a509b3c50a3291ecb9dd6a72e016 jdk7-b115
|
||||
96b3f2a7add0b445b8aa421f6823cff5a2e2fe03 jdk7-b116
|
||||
52f19c724d9634af79044a2e0defbe4a5f1adbda hs20-b02
|
||||
806d0c037e6bbb88dac0699673f4ba55ee8c02da jdk7-b117
|
||||
698b7b727e12de44139d8cca6ab9a494ead13253 jdk7-b118
|
||||
3ef7426b4deac5dcfd4afb35cabe9ab3d666df91 hs20-b02
|
||||
|
@ -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 @@ public class BytecodeLoadConstant extends BytecodeWithCPIndex {
|
||||
} 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);
|
||||
|
@ -53,11 +53,19 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||
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 class ConstantPool extends Oop implements ClassConstants {
|
||||
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 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||
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 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||
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 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||
|
||||
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
|
||||
|
@ -42,7 +42,8 @@ public interface ClassConstants
|
||||
public static final int JVM_CONSTANT_NameAndType = 12;
|
||||
public static final int JVM_CONSTANT_MethodHandle = 15;
|
||||
public static final int JVM_CONSTANT_MethodType = 16;
|
||||
public static final int JVM_CONSTANT_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;
|
||||
|
@ -303,12 +303,12 @@ public class ClassWriter implements /* imports */ ClassConstants
|
||||
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 @@ public class ClassWriter implements /* imports */ ClassConstants
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -460,6 +460,18 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
|
||||
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 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
|
||||
|
||||
case JVM_CONSTANT_InvokeDynamic:
|
||||
buf.cell("JVM_CONSTANT_InvokeDynamic");
|
||||
buf.cell(genLowHighShort(cpool.getIntAt(index)));
|
||||
buf.cell(genListOfShort(cpool.getMultiOperandsAt(index)));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -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 @@ public class ConstantTag {
|
||||
private static int JVM_CONSTANT_NameAndType = 12;
|
||||
private static int JVM_CONSTANT_MethodHandle = 15; // JSR 292
|
||||
private static int JVM_CONSTANT_MethodType = 16; // JSR 292
|
||||
private static int JVM_CONSTANT_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
|
||||
|
@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2010
|
||||
|
||||
HS_MAJOR_VER=20
|
||||
HS_MINOR_VER=0
|
||||
HS_BUILD_NUMBER=02
|
||||
HS_BUILD_NUMBER=03
|
||||
|
||||
JDK_MAJOR_VER=1
|
||||
JDK_MINOR_VER=7
|
||||
|
@ -62,7 +62,9 @@ endif
|
||||
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 @@ $(SUBDIRS_TIERED): $(BUILDTREE_MAKE)
|
||||
$(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
|
||||
|
@ -53,7 +53,9 @@ endif
|
||||
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 @@ $(SUBDIRS_TIERED): $(BUILDTREE_MAKE)
|
||||
$(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
|
||||
|
@ -74,9 +74,11 @@ BUILDARCH=ia64
|
||||
|
||||
!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 @@ VARIANT_TEXT=Core
|
||||
!if "$(Variant)" == "compiler1"
|
||||
VARIANT_TEXT=Client
|
||||
!elseif "$(Variant)" == "compiler2"
|
||||
!ifdef FORCE_TIERED
|
||||
!if "$(FORCE_TIERED)" == "1"
|
||||
VARIANT_TEXT=Server
|
||||
realVariant=tiered
|
||||
!else
|
||||
|
@ -1126,7 +1126,7 @@ public:
|
||||
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) ); }
|
||||
|
@ -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::ld( Register s1, RegisterOrConstant s2, Register d) { ld
|
||||
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; }
|
||||
|
@ -70,17 +70,29 @@ MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _mas
|
||||
|
||||
// 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 @@ address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler*
|
||||
__ 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);
|
||||
|
||||
__ check_method_handle_type(G5_method_type, G3_method_handle, O1_scratch, wrong_method_type);
|
||||
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
|
||||
|
||||
// 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,10 +693,16 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
|
||||
switch (ek) {
|
||||
case _adapter_opt_i2i:
|
||||
case _adapter_opt_l2i:
|
||||
__ unimplemented(entry_name(ek));
|
||||
value = vmarg;
|
||||
break;
|
||||
case _adapter_opt_l2i:
|
||||
{
|
||||
// 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:
|
||||
{
|
||||
// Load the value up from the heap.
|
||||
|
@ -1843,6 +1843,12 @@ bool Matcher::is_spillable_arg( int reg ) {
|
||||
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 @@ instruct countLeadingZerosI(iRegI dst, iRegI src, iRegI tmp, flagsReg cr) %{
|
||||
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 @@ instruct countLeadingZerosI(iRegI dst, iRegI src, iRegI tmp, flagsReg cr) %{
|
||||
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 @@ instruct countLeadingZerosL(iRegI dst, iRegL src, iRegL tmp, flagsReg cr) %{
|
||||
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);
|
||||
|
@ -341,6 +341,26 @@ void TemplateTable::fast_aldc(bool wide) {
|
||||
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() {
|
||||
|
@ -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 @@ void VM_Version::initialize() {
|
||||
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 @@ void VM_Version::initialize() {
|
||||
#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" : ""));
|
||||
|
@ -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 @@ protected:
|
||||
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 @@ protected:
|
||||
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 @@ protected:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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; }
|
||||
|
||||
|
@ -1275,6 +1275,12 @@ void Assembler::idivl(Register src) {
|
||||
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 @@ void Assembler::imull(Register dst, Register src, int value) {
|
||||
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 @@ void Assembler::imulq(Register dst, Register src, int value) {
|
||||
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);
|
||||
|
@ -1011,6 +1011,7 @@ private:
|
||||
void hlt();
|
||||
|
||||
void idivl(Register src);
|
||||
void divl(Register src); // Unsigned division
|
||||
|
||||
void idivq(Register src);
|
||||
|
||||
|
@ -399,6 +399,23 @@ void TemplateTable::fast_aldc(bool wide) {
|
||||
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() {
|
||||
|
@ -413,6 +413,25 @@ void TemplateTable::fast_aldc(bool wide) {
|
||||
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() {
|
||||
|
@ -446,6 +446,10 @@ public:
|
||||
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; }
|
||||
|
@ -1508,6 +1508,16 @@ bool Matcher::is_spillable_arg( int reg ) {
|
||||
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 @@ bool is_operand_hi32_zero(Node* n) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (opc == Op_ConL && (n->get_long() & 0xFFFFFFFF00000000LL) == 0LL) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2309,9 +2322,11 @@ encode %{
|
||||
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 @@ instruct modL_eReg( eADXRegL dst, eRegL src1, eRegL src2, eFlagsReg cr, eCXRegI
|
||||
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) %{
|
||||
|
@ -2065,6 +2065,13 @@ bool Matcher::is_spillable_arg(int reg)
|
||||
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;
|
||||
|
@ -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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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(", 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]);
|
||||
|
||||
st->print(", CR2=" INTPTR_FORMAT, uc->uc_mcontext.cr2);
|
||||
#endif // AMD64
|
||||
st->cr();
|
||||
st->cr();
|
||||
@ -868,7 +773,52 @@ void os::print_context(outputStream *st, void *context) {
|
||||
// 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() {
|
||||
|
@ -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 @@ int JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, int abort_
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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) {
|
||||
|
@ -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 @@ int VM_Version::platform_features(int features) {
|
||||
// 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 @@ int VM_Version::platform_features(int features) {
|
||||
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 @@ int VM_Version::platform_features(int features) {
|
||||
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;
|
||||
|
@ -719,11 +719,6 @@ void os::print_context(outputStream *st, void *context) {
|
||||
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -387,8 +387,8 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
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 @@ void os::print_context(outputStream *st, void *context) {
|
||||
// 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();
|
||||
}
|
||||
|
||||
|
@ -178,15 +178,11 @@ class Compilation: public StackObj {
|
||||
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);
|
||||
|
@ -321,7 +321,7 @@ class UseCountComputer: public ValueVisitor, BlockClosure {
|
||||
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");
|
||||
}
|
||||
|
@ -415,28 +415,26 @@ bool Constant::is_equal(Value v) const {
|
||||
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 @@ BlockBegin* Constant::compare(Instruction::Condition cond, Value right,
|
||||
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 @@ BlockBegin* Constant::compare(Instruction::Condition cond, Value right,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -443,7 +443,7 @@ class Instruction: public CompilationResourceObj {
|
||||
|
||||
// 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 @@ LEAF(Constant, Instruction)
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -38,18 +38,20 @@ class CE_Eliminator: public BlockClosure {
|
||||
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 @@ class CE_Eliminator: public BlockClosure {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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;
|
||||
|
||||
BlockBegin* t_block = if_->tsux();
|
||||
BlockBegin* f_block = if_->fsux();
|
||||
Instruction* t_cur = t_block->next();
|
||||
Instruction* f_cur = f_block->next();
|
||||
|
||||
// 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 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 both gotos merge into the same block
|
||||
BlockBegin* sux = t_goto->default_sux();
|
||||
if (sux != f_goto->default_sux()) 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 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());
|
||||
|
||||
// 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 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
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());
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
_hir->verify();
|
||||
}
|
||||
private:
|
||||
Value make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval);
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
BlockBegin* t_block = if_->tsux();
|
||||
BlockBegin* f_block = if_->fsux();
|
||||
Instruction* t_cur = t_block->next();
|
||||
Instruction* f_cur = f_block->next();
|
||||
|
||||
// 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 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 both gotos merge into the same block
|
||||
BlockBegin* sux = t_goto->default_sux();
|
||||
if (sux != f_goto->default_sux()) 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 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());
|
||||
|
||||
// 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 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);
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
_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();
|
||||
|
||||
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;
|
||||
|
||||
_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
@ -107,7 +107,6 @@ static void deopt_caller() {
|
||||
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 @@ JRT_BLOCK_ENTRY(address, Runtime1::counter_overflow(JavaThread* thread, int bci,
|
||||
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 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||
// 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 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
|
||||
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.
|
||||
}
|
||||
|
@ -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") \
|
||||
\
|
||||
|
@ -564,7 +564,7 @@ bool ciInstanceKlass::is_leaf_type() {
|
||||
// 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];
|
||||
|
@ -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 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
|
||||
unsigned int hashValues[SymbolTable::symbol_alloc_batch_size];
|
||||
int names_count = 0;
|
||||
|
||||
// Side buffer for operands of variable-sized (InvokeDynamic) entries.
|
||||
GrowableArray<int>* operands = NULL;
|
||||
#ifdef ASSERT
|
||||
GrowableArray<int>* indy_instructions = new GrowableArray<int>(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 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
break;
|
||||
case JVM_CONSTANT_InvokeDynamicTrans : // this tag appears only in old classfiles
|
||||
case JVM_CONSTANT_InvokeDynamic :
|
||||
{
|
||||
if (!EnableInvokeDynamic ||
|
||||
@ -151,10 +158,36 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
|
||||
"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 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
|
||||
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 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
|
||||
cfs0->set_current(cfs1.current());
|
||||
}
|
||||
|
||||
int ClassFileParser::start_operand_group(GrowableArray<int>* &operands, int op_count, TRAPS) {
|
||||
if (operands == NULL) {
|
||||
operands = new GrowableArray<int>(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<int>* 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 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
|
||||
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 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
|
||||
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 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
|
||||
"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:
|
||||
@ -2505,18 +2604,6 @@ void ClassFileParser::java_lang_ref_Reference_fix_pre(typeArrayHandle* fields_pt
|
||||
// the check for the "discovered" field should issue a warning if
|
||||
// the field is not found. For 1.6 this code should be issue a
|
||||
// fatal error if the "discovered" field is not found.
|
||||
//
|
||||
// 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.
|
||||
|
||||
//
|
||||
// Increment fac.nonstatic_oop_count so that the start of the
|
||||
// next type of non-static oops leaves room for the fake oop.
|
||||
@ -2663,7 +2750,7 @@ void ClassFileParser::java_lang_Class_fix_post(int* next_nonstatic_oop_offset_pt
|
||||
// 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 @@ void ClassFileParser::java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
|
||||
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;
|
||||
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;
|
||||
|
||||
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);
|
||||
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;
|
||||
|
||||
found_vmentry = true;
|
||||
break;
|
||||
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 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
|
||||
|
||||
// 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
|
||||
|
@ -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 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
constantPoolHandle parse_constant_pool(TRAPS);
|
||||
|
||||
static int start_operand_group(GrowableArray<int>* &operands, int op_count, TRAPS);
|
||||
static void store_operand_array(GrowableArray<int>* operands, constantPoolHandle cp, TRAPS);
|
||||
|
||||
// Interface parsing
|
||||
objArrayHandle parse_interfaces(constantPoolHandle cp,
|
||||
int length,
|
||||
@ -151,7 +154,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
// 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
|
||||
|
@ -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 @@ void SystemDictionary::always_strong_classes_do(OopClosure* blk) {
|
||||
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 @@ void SystemDictionary::oops_do(OopClosure* f) {
|
||||
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::placeholders_do(void f(symbolOop, oop)) {
|
||||
|
||||
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 @@ void SystemDictionary::initialize(TRAPS) {
|
||||
// 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 @@ methodOop SystemDictionary::find_method_handle_invoke(symbolHandle name,
|
||||
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::make_dynamic_call_site(Handle bootstrap_method,
|
||||
}
|
||||
|
||||
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 @@ Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int c
|
||||
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 @@ Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int c
|
||||
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 @@ Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int c
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -496,6 +496,7 @@ public:
|
||||
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
|
||||
|
@ -1909,7 +1909,7 @@ void ClassVerifier::verify_invoke_instructions(
|
||||
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));
|
||||
|
@ -914,3 +914,14 @@ void CodeCache::print() {
|
||||
}
|
||||
|
||||
#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());
|
||||
}
|
||||
|
@ -137,6 +137,7 @@ class CodeCache : AllStatic {
|
||||
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(); }
|
||||
|
@ -133,6 +133,7 @@ parallelScavengeHeap.cpp psMarkSweep.hpp
|
||||
parallelScavengeHeap.cpp psParallelCompact.hpp
|
||||
parallelScavengeHeap.cpp psPromotionManager.hpp
|
||||
parallelScavengeHeap.cpp psScavenge.hpp
|
||||
parallelScavengeHeap.cpp vmError.hpp
|
||||
parallelScavengeHeap.cpp vmThread.hpp
|
||||
parallelScavengeHeap.cpp vmPSOperations.hpp
|
||||
|
||||
|
@ -805,7 +805,8 @@ HeapWord* ParallelScavengeHeap::block_start(const void* addr) const {
|
||||
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),
|
||||
|
@ -1272,6 +1272,7 @@ constantPoolOop.cpp javaClasses.hpp
|
||||
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
|
||||
|
@ -154,6 +154,7 @@ jvmtiExtensions.hpp allocation.hpp
|
||||
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
|
||||
|
@ -89,6 +89,7 @@ jvmtiEnv.cpp vmThread.hpp
|
||||
jvmtiEnv.hpp jvmtiEnvBase.hpp
|
||||
|
||||
jvmtiEnvBase.cpp biasedLocking.hpp
|
||||
jvmtiEnvBase.cpp deoptimization.hpp
|
||||
jvmtiEnvBase.cpp interfaceSupport.hpp
|
||||
jvmtiEnvBase.cpp jfieldIDWorkaround.hpp
|
||||
jvmtiEnvBase.cpp jvmtiEnv.hpp
|
||||
|
@ -716,12 +716,13 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
|
||||
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 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
|
||||
// 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 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
|
||||
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 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
|
||||
|
||||
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:
|
||||
|
@ -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 @@ class CodeHeap : public CHeapObj {
|
||||
|
||||
// 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
|
||||
|
@ -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 @@ class Universe: AllStatic {
|
||||
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; }
|
||||
|
@ -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 @@ constantPoolOop constantPoolKlass::allocate(int length, bool is_conc_safe, TRAPS
|
||||
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 @@ void constantPoolKlass::oop_follow_contents(oop obj) {
|
||||
// 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 @@ void constantPoolKlass::oop_follow_contents(ParCompactionManager* cm,
|
||||
// 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 @@ int constantPoolKlass::oop_adjust_pointers(oop obj) {
|
||||
}
|
||||
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 @@ int constantPoolKlass::oop_oop_iterate(oop obj, OopClosure* blk) {
|
||||
}
|
||||
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 @@ int constantPoolKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr)
|
||||
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 @@ int constantPoolKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) {
|
||||
}
|
||||
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 @@ constantPoolKlass::oop_update_pointers(ParCompactionManager* cm, oop obj,
|
||||
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 @@ void constantPoolKlass::oop_print_on(oop obj, outputStream* st) {
|
||||
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 @@ void constantPoolKlass::oop_print_value_on(oop obj, outputStream* st) {
|
||||
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 @@ void constantPoolKlass::oop_verify_on(oop obj, outputStream* st) {
|
||||
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
|
||||
|
@ -265,10 +265,9 @@ int constantPoolOopDesc::impl_name_and_type_ref_index_at(int which, bool uncache
|
||||
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 @@ int constantPoolOopDesc::impl_name_and_type_ref_index_at(int which, bool uncache
|
||||
// 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 @@ void constantPoolOopDesc::resolve_string_constants_impl(constantPoolHandle this_
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, i
|
||||
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 @@ oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, i
|
||||
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:
|
||||
case JVM_CONSTANT_Float:
|
||||
case JVM_CONSTANT_Long:
|
||||
case JVM_CONSTANT_Double:
|
||||
result_oop = java_lang_boxing_object::create(...);
|
||||
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:
|
||||
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 @@ oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, i
|
||||
|
||||
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_symbols_iterate(OopClosure* closure) {
|
||||
|
||||
void constantPoolOopDesc::shared_tags_iterate(OopClosure* closure) {
|
||||
closure->do_oop(tags_addr());
|
||||
closure->do_oop(operands_addr());
|
||||
}
|
||||
|
||||
|
||||
@ -838,13 +921,19 @@ bool constantPoolOopDesc::compare_entry_to(int index1, constantPoolHandle cp2,
|
||||
|
||||
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 @@ bool constantPoolOopDesc::compare_entry_to(int index1, constantPoolHandle cp2,
|
||||
} // 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 @@ void constantPoolOopDesc::copy_cp_to(int start_i, int end_i,
|
||||
|
||||
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 @@ void constantPoolOopDesc::copy_entry_to(int from_i, constantPoolHandle to_cp,
|
||||
|
||||
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,9 +1389,12 @@ jint constantPoolOopDesc::cpool_entry_size(jint idx) {
|
||||
case JVM_CONSTANT_Methodref:
|
||||
case JVM_CONSTANT_InterfaceMethodref:
|
||||
case JVM_CONSTANT_NameAndType:
|
||||
case JVM_CONSTANT_InvokeDynamic:
|
||||
return 5;
|
||||
|
||||
case JVM_CONSTANT_InvokeDynamic:
|
||||
// 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:
|
||||
return 9;
|
||||
@ -1475,9 +1610,15 @@ int constantPoolOopDesc::copy_cpool_bytes(int cpool_size,
|
||||
*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;
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ class constantPoolOopDesc : public oopDesc {
|
||||
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 @@ class constantPoolOopDesc : public oopDesc {
|
||||
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 @@ class constantPoolOopDesc : public oopDesc {
|
||||
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 @@ class constantPoolOopDesc : public oopDesc {
|
||||
|
||||
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 @@ class constantPoolOopDesc : public oopDesc {
|
||||
// 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 @@ class constantPoolOopDesc : public oopDesc {
|
||||
*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 @@ class constantPoolOopDesc : public oopDesc {
|
||||
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 @@ class constantPoolOopDesc : public oopDesc {
|
||||
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 @@ class constantPoolOopDesc : public oopDesc {
|
||||
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); }
|
||||
|
@ -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 @@ void ConstantPoolCacheEntry::set_bytecode_2(Bytecodes::Code code) {
|
||||
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 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
|
||||
}
|
||||
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
|
||||
|
@ -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 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||
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 @@ class constantPoolCacheOopDesc: public oopDesc {
|
||||
|
||||
// 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; }
|
||||
|
@ -1254,7 +1254,7 @@ void GenerateOopMap::print_current_state(outputStream *os,
|
||||
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 @@ void GenerateOopMap::print_current_state(outputStream *os,
|
||||
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 @@ void GenerateOopMap::interp1(BytecodeStream *itr) {
|
||||
|
||||
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_jsr(int targ_bci) {
|
||||
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -389,7 +389,7 @@ class GenerateOopMap VALUE_OBJ_CLASS_SPEC {
|
||||
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);
|
||||
|
@ -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 @@ static Node *transform_long_divide( PhaseGVN *phase, Node *dividend, jlong divis
|
||||
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 @@ Node *DivLNode::Ideal( PhaseGVN *phase, bool can_reshape) {
|
||||
|
||||
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 @@ Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
// 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 @@ Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
|
||||
// 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 @@ Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
// 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);
|
||||
|
@ -85,6 +85,7 @@ ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
|
||||
_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 @@ void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) {
|
||||
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 @@ void ConnectionGraph::add_deferred_edge(uint from_i, uint to_i) {
|
||||
// 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 @@ void ConnectionGraph::add_field_edge(uint from_i, uint to_i, int offset) {
|
||||
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 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
|
||||
GrowableArray<Node *> memnode_worklist;
|
||||
GrowableArray<PhiNode *> 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 @@ bool ConnectionGraph::compute_escape() {
|
||||
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 @@ bool ConnectionGraph::compute_escape() {
|
||||
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<uint> 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 @@ bool ConnectionGraph::compute_escape() {
|
||||
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<uint> 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 @@ bool ConnectionGraph::compute_escape() {
|
||||
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 @@ bool ConnectionGraph::compute_escape() {
|
||||
}
|
||||
|
||||
// 6. Propagate escape states.
|
||||
GrowableArray<int> worklist;
|
||||
worklist.clear();
|
||||
bool has_non_escaping_obj = false;
|
||||
|
||||
// push all GlobalEscape nodes on the worklist
|
||||
@ -2444,13 +2489,14 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -219,6 +219,9 @@ private:
|
||||
// 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 @@ private:
|
||||
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
|
||||
|
@ -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 @@ public:
|
||||
// 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
|
||||
|
@ -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 @@ enum {
|
||||
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 */
|
||||
|
@ -1407,8 +1407,7 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) {
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1322,8 +1322,7 @@ JvmtiEnvBase::check_top_frame(JavaThread* current_thread, JavaThread* java_threa
|
||||
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
|
||||
|
@ -728,8 +728,7 @@ void VM_GetOrSetLocal::doit() {
|
||||
|
||||
// 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
|
||||
|
@ -147,10 +147,9 @@ bool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) {
|
||||
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 @@ bool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) {
|
||||
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 @@ bool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) {
|
||||
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 @@ bool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) {
|
||||
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()) {
|
||||
|
@ -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 @@ class MethodComparator {
|
||||
static GrowableArray<int> *_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:
|
||||
|
@ -974,6 +974,8 @@ bool MethodHandles::same_basic_type_for_arguments(BasicType src,
|
||||
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
|
||||
|
@ -978,17 +978,6 @@ void Arguments::check_compressed_oops_compat() {
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -1065,7 +1065,9 @@ void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map)
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
}
|
||||
|
||||
|
||||
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))
|
||||
{
|
||||
|
@ -216,6 +216,10 @@ class Deoptimization : AllStatic {
|
||||
// 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
|
||||
|
@ -878,7 +878,7 @@ void frame::oops_interpreted_do(OopClosure* f, const RegisterMap* map, bool quer
|
||||
|
||||
#endif /* CC_INTERP */
|
||||
|
||||
#ifndef PPC
|
||||
#if !defined(PPC) || defined(ZERO)
|
||||
if (m->is_native()) {
|
||||
#ifdef CC_INTERP
|
||||
f->do_oop((oop*)&istate->_oop_temp);
|
||||
|
@ -198,7 +198,7 @@ void print_statistics() {
|
||||
if (CountCompiledCalls) {
|
||||
print_method_invocation_histogram();
|
||||
}
|
||||
if (ProfileInterpreter || C1UpdateMethodData) {
|
||||
if (ProfileInterpreter COMPILER1_PRESENT(|| C1UpdateMethodData)) {
|
||||
print_method_profiling_data();
|
||||
}
|
||||
if (TimeCompiler) {
|
||||
|
@ -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 @@ void os::print_date_and_time(outputStream *st) {
|
||||
}
|
||||
|
||||
// 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 @@ void os::print_location(outputStream* st, intptr_t x, bool print_pc) {
|
||||
// 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 @@ void os::print_location(outputStream* st, intptr_t x, bool print_pc) {
|
||||
}
|
||||
//
|
||||
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 @@ void os::print_location(outputStream* st, intptr_t x, bool print_pc) {
|
||||
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 @@ void os::print_location(outputStream* st, intptr_t x, bool print_pc) {
|
||||
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 @@ void os::print_location(outputStream* st, intptr_t x, bool print_pc) {
|
||||
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 @@ void os::print_location(outputStream* st, intptr_t x, bool print_pc) {
|
||||
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 @@ void os::print_location(outputStream* st, intptr_t x, bool print_pc) {
|
||||
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 @@ void os::print_location(outputStream* st, intptr_t x, bool print_pc) {
|
||||
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
|
||||
|
@ -450,11 +450,12 @@ class os: AllStatic {
|
||||
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
|
||||
|
@ -940,8 +940,7 @@ void ThreadSafepointState::handle_polling_page_exception() {
|
||||
// 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
|
||||
|
@ -1199,6 +1199,7 @@ void JavaThread::initialize() {
|
||||
_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;
|
||||
|
@ -86,6 +86,7 @@ static inline uint64_t cast_uint64_t(size_t x)
|
||||
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 @@ static inline uint64_t cast_uint64_t(size_t x)
|
||||
\
|
||||
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 */ \
|
||||
/*********************************************/ \
|
||||
|
@ -100,7 +100,7 @@ VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id) {
|
||||
|
||||
|
||||
void VM_DeoptimizeFrame::doit() {
|
||||
Deoptimization::deoptimize_frame(_thread, _id);
|
||||
Deoptimization::deoptimize_frame_internal(_thread, _id);
|
||||
}
|
||||
|
||||
|
||||
|
@ -231,12 +231,18 @@ class VM_Deoptimize: public VM_Operation {
|
||||
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;
|
||||
public:
|
||||
VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id);
|
||||
|
||||
public:
|
||||
VMOp_Type type() const { return VMOp_DeoptimizeFrame; }
|
||||
void doit();
|
||||
bool allow_nested_vm_operations() const { return true; }
|
||||
|
@ -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 @@ class constantTag VALUE_OBJ_CLASS_SPEC {
|
||||
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;
|
||||
}
|
||||
|
@ -455,6 +455,14 @@ void VMError::report(outputStream* st) {
|
||||
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 @@ void VMError::report(outputStream* st) {
|
||||
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 @@ void VMError::report(outputStream* st) {
|
||||
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) {
|
||||
|
@ -78,7 +78,11 @@ ZIP = zip
|
||||
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)
|
||||
|
@ -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 @@ public class Test implements Runnable {
|
||||
|
||||
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 @@ public class Test implements Runnable {
|
||||
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
|
||||
|
@ -54,7 +54,7 @@ public class Test6857159 extends Thread {
|
||||
}
|
||||
|
||||
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;
|
||||
|
447
hotspot/test/compiler/6991596/Test6991596.java
Normal file
447
hotspot/test/compiler/6991596/Test6991596.java
Normal file
@ -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.<boolean>invokeExact((boolean) x);
|
||||
boolean b = mh2.<boolean>invokeExact(x);
|
||||
//boolean c = mh3.<boolean>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.<byte>invokeExact((byte) (x ? 1 : 0));
|
||||
byte b = mh2.<byte>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.<char>invokeExact((char) (x ? 1 : 0));
|
||||
char b = mh2.<char>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.<short>invokeExact((short) (x ? 1 : 0));
|
||||
short b = mh2.<short>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.<boolean>invokeExact((x & 1) == 1);
|
||||
boolean b = mh2.<boolean>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.<byte>invokeExact((byte) x);
|
||||
byte b = mh2.<byte>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.<char>invokeExact((char) x);
|
||||
char b = mh2.<char>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.<short>invokeExact((short) x);
|
||||
short b = mh2.<short>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.<boolean>invokeExact((x & 1) == 1);
|
||||
boolean b = mh2.<boolean>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.<byte>invokeExact((byte) x);
|
||||
byte b = mh2.<byte>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.<char>invokeExact((char) x);
|
||||
char b = mh2.<char>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.<short>invokeExact((short) x);
|
||||
short b = mh2.<short>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.<boolean>invokeExact((x & 1) == 1);
|
||||
boolean b = mh2.<boolean>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.<byte>invokeExact((byte) x);
|
||||
byte b = mh2.<byte>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.<char>invokeExact((char) x);
|
||||
char b = mh2.<char>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.<short>invokeExact((short) x);
|
||||
short b = mh2.<short>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.<boolean>invokeExact((x & 1) == 1);
|
||||
boolean b = mh2.<boolean>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.<byte>invokeExact((byte) x);
|
||||
byte b = mh2.<byte>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.<char>invokeExact((char) x);
|
||||
char b = mh2.<char>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.<short>invokeExact((short) x);
|
||||
short b = mh2.<short>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.<int>invokeExact((int) x);
|
||||
int b = mh2.<int>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.<boolean>invokeExact((x & 1L) == 1L);
|
||||
boolean b = mh2.<boolean>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.<byte>invokeExact((byte) x);
|
||||
byte b = mh2.<byte>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.<char>invokeExact((char) x);
|
||||
char b = mh2.<char>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.<short>invokeExact((short) x);
|
||||
short b = mh2.<short>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.<int>invokeExact((int) x);
|
||||
int b = mh2.<int>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; }
|
||||
}
|
@ -92,3 +92,4 @@ e250cef36ea05e627e7e6f7d75e5e19f529e2ba3 jdk7-b114
|
||||
449bad8d67b5808ecf0f927683acc0a5940f8c85 jdk7-b115
|
||||
1657ed4e1d86c8aa2028ab5a41f9da1ac4a369f8 jdk7-b116
|
||||
3e6726bbf80a4254ecd01051c8ed77ee19325e46 jdk7-b117
|
||||
b357910aa04aead2a16b6d6ff395a8df4b51d1dd jdk7-b118
|
||||
|
Loading…
Reference in New Issue
Block a user