mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 06:14:49 +02:00
6984311: JSR 292 needs optional bootstrap method parameters
Allow CONSTANT_InvokeDynamic nodes to have any number of extra operands. Reviewed-by: twisti
This commit is contained in:
parent
fb2011ac04
commit
ce0125e7f2
26 changed files with 689 additions and 126 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -2555,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;
|
||||
|
@ -2569,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) {
|
||||
|
@ -2585,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()) {
|
||||
|
@ -2600,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));
|
||||
|
|
|
@ -1265,6 +1265,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
|
||||
|
|
|
@ -716,6 +716,7 @@ 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)) {
|
||||
|
@ -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, 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));
|
||||
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
|
||||
|
|
|
@ -267,7 +267,7 @@ int constantPoolOopDesc::impl_name_and_type_ref_index_at(int which, bool uncache
|
|||
if (constantPoolCacheOopDesc::is_secondary_index(which)) {
|
||||
// Invokedynamic index.
|
||||
int pool_index = cache()->main_entry_at(which)->constant_pool_index();
|
||||
if (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;
|
||||
|
@ -275,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);
|
||||
}
|
||||
|
@ -393,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) {
|
||||
|
||||
|
@ -448,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;
|
||||
}
|
||||
|
||||
|
@ -467,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",
|
||||
|
@ -491,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;
|
||||
}
|
||||
}
|
||||
|
@ -620,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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -837,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;
|
||||
|
@ -880,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.
|
||||
|
@ -888,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);
|
||||
|
||||
|
@ -1036,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
|
||||
|
@ -1256,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;
|
||||
|
@ -1474,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,15 +425,76 @@ 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,
|
||||
|
@ -448,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
|
||||
|
|
|
@ -319,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; }
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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())
|
||||
if (!pool_constants_same(cpi_old, cpi_new))
|
||||
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
|
||||
}
|
||||
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:
|
||||
|
|
|
@ -1527,6 +1527,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 */ \
|
||||
/*********************************************/ \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue