mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
7001379: bootstrap method data needs to be moved from constant pool to a classfile attribute
Reviewed-by: twisti
This commit is contained in:
parent
f74039fd41
commit
cc7c58e166
17 changed files with 361 additions and 328 deletions
|
@ -60,10 +60,7 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||||
headerSize = type.getSize();
|
headerSize = type.getSize();
|
||||||
elementSize = 0;
|
elementSize = 0;
|
||||||
// fetch constants:
|
// 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_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_ARGC_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_argc_offset").intValue();
|
||||||
INDY_ARGV_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_argv_offset").intValue();
|
INDY_ARGV_OFFSET = db.lookupIntConstant("constantPoolOopDesc::_indy_argv_offset").intValue();
|
||||||
}
|
}
|
||||||
|
@ -83,10 +80,7 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||||
private static long headerSize;
|
private static long headerSize;
|
||||||
private static long elementSize;
|
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_BSM_OFFSET;
|
||||||
private static int INDY_NT_OFFSET;
|
|
||||||
private static int INDY_ARGC_OFFSET;
|
private static int INDY_ARGC_OFFSET;
|
||||||
private static int INDY_ARGV_OFFSET;
|
private static int INDY_ARGV_OFFSET;
|
||||||
|
|
||||||
|
@ -296,20 +290,23 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Lookup for multi-operand (InvokeDynamic) entries. */
|
/** Lookup for multi-operand (InvokeDynamic) entries. */
|
||||||
public int[] getMultiOperandsAt(int i) {
|
public short[] getBootstrapSpecifierAt(int i) {
|
||||||
if (Assert.ASSERTS_ENABLED) {
|
if (Assert.ASSERTS_ENABLED) {
|
||||||
Assert.that(getTagAt(i).isInvokeDynamic(), "Corrupted constant pool");
|
Assert.that(getTagAt(i).isInvokeDynamic(), "Corrupted constant pool");
|
||||||
}
|
}
|
||||||
int pos = this.getIntAt(i);
|
if (getTagAt(i).value() == JVM_CONSTANT_InvokeDynamicTrans)
|
||||||
int countPos = pos + MULTI_OPERAND_COUNT_OFFSET; // == pos-1
|
return null;
|
||||||
int basePos = pos + MULTI_OPERAND_BASE_OFFSET; // == pos
|
int bsmSpec = extractLowShortFromInt(this.getIntAt(i));
|
||||||
if (countPos < 0) return null; // safety first
|
|
||||||
TypeArray operands = getOperands();
|
TypeArray operands = getOperands();
|
||||||
if (operands == null) return null; // safety first
|
if (operands == null) return null; // safety first
|
||||||
int length = operands.getIntAt(countPos);
|
int basePos = VM.getVM().buildIntFromShorts(operands.getShortAt(bsmSpec * 2 + 0),
|
||||||
int[] values = new int[length];
|
operands.getShortAt(bsmSpec * 2 + 1));
|
||||||
for (int j = 0; j < length; j++) {
|
int argv = basePos + INDY_ARGV_OFFSET;
|
||||||
values[j] = operands.getIntAt(basePos+j);
|
int argc = operands.getShortAt(basePos + INDY_ARGC_OFFSET);
|
||||||
|
int endPos = argv + argc;
|
||||||
|
short[] values = new short[endPos - basePos];
|
||||||
|
for (int j = 0; j < values.length; j++) {
|
||||||
|
values[j] = operands.getShortAt(basePos+j);
|
||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
@ -334,6 +331,7 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||||
case JVM_CONSTANT_MethodHandle: return "JVM_CONSTANT_MethodHandle";
|
case JVM_CONSTANT_MethodHandle: return "JVM_CONSTANT_MethodHandle";
|
||||||
case JVM_CONSTANT_MethodType: return "JVM_CONSTANT_MethodType";
|
case JVM_CONSTANT_MethodType: return "JVM_CONSTANT_MethodType";
|
||||||
case JVM_CONSTANT_InvokeDynamic: return "JVM_CONSTANT_InvokeDynamic";
|
case JVM_CONSTANT_InvokeDynamic: return "JVM_CONSTANT_InvokeDynamic";
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans: return "JVM_CONSTANT_InvokeDynamic/transitional";
|
||||||
case JVM_CONSTANT_Invalid: return "JVM_CONSTANT_Invalid";
|
case JVM_CONSTANT_Invalid: return "JVM_CONSTANT_Invalid";
|
||||||
case JVM_CONSTANT_UnresolvedClass: return "JVM_CONSTANT_UnresolvedClass";
|
case JVM_CONSTANT_UnresolvedClass: return "JVM_CONSTANT_UnresolvedClass";
|
||||||
case JVM_CONSTANT_UnresolvedClassInError: return "JVM_CONSTANT_UnresolvedClassInError";
|
case JVM_CONSTANT_UnresolvedClassInError: return "JVM_CONSTANT_UnresolvedClassInError";
|
||||||
|
@ -393,6 +391,7 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||||
case JVM_CONSTANT_MethodHandle:
|
case JVM_CONSTANT_MethodHandle:
|
||||||
case JVM_CONSTANT_MethodType:
|
case JVM_CONSTANT_MethodType:
|
||||||
case JVM_CONSTANT_InvokeDynamic:
|
case JVM_CONSTANT_InvokeDynamic:
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||||
visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
|
visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -556,19 +555,16 @@ public class ConstantPool extends Oop implements ClassConstants {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||||
case JVM_CONSTANT_InvokeDynamic: {
|
case JVM_CONSTANT_InvokeDynamic: {
|
||||||
dos.writeByte(cpConstType);
|
dos.writeByte(cpConstType);
|
||||||
int[] values = getMultiOperandsAt(ci);
|
int value = getIntAt(ci);
|
||||||
for (int vn = 0; vn < values.length; vn++) {
|
short bsmIndex = (short) extractLowShortFromInt(value);
|
||||||
dos.writeShort(values[vn]);
|
short nameAndTypeIndex = (short) extractHighShortFromInt(value);
|
||||||
}
|
dos.writeShort(bsmIndex);
|
||||||
int bootstrapMethodIndex = values[INDY_BSM_OFFSET];
|
dos.writeShort(nameAndTypeIndex);
|
||||||
int nameAndTypeIndex = values[INDY_NT_OFFSET];
|
if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " + bsmIndex
|
||||||
int argumentCount = values[INDY_ARGC_OFFSET];
|
+ ", N&T = " + nameAndTypeIndex);
|
||||||
assert(INDY_ARGV_OFFSET + argumentCount == values.length);
|
|
||||||
if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " + bootstrapMethodIndex
|
|
||||||
+ ", N&T = " + nameAndTypeIndex
|
|
||||||
+ ", argc = " + argumentCount);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -321,13 +321,16 @@ public class ClassWriter implements /* imports */ ClassConstants
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||||
case JVM_CONSTANT_InvokeDynamic: {
|
case JVM_CONSTANT_InvokeDynamic: {
|
||||||
dos.writeByte(cpConstType);
|
dos.writeByte(cpConstType);
|
||||||
int[] values = cpool.getMultiOperandsAt(ci);
|
int value = cpool.getIntAt(ci);
|
||||||
for (int vn = 0; vn < values.length; vn++) {
|
short bsmIndex = (short) extractLowShortFromInt(value);
|
||||||
dos.writeShort(values[vn]);
|
short nameAndTypeIndex = (short) extractHighShortFromInt(value);
|
||||||
}
|
dos.writeShort(bsmIndex);
|
||||||
if (DEBUG) debugMessage("CP[" + ci + "] = INDY indexes = " + Arrays.toString(values));
|
dos.writeShort(nameAndTypeIndex);
|
||||||
|
if (DEBUG) debugMessage("CP[" + ci + "] = INDY bsm = " +
|
||||||
|
bsmIndex + ", N&T = " + nameAndTypeIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -460,7 +460,8 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
|
||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String genListOfShort(int[] values) {
|
private String genListOfShort(short[] values) {
|
||||||
|
if (values == null || values.length == 0) return "";
|
||||||
Formatter buf = new Formatter(genHTML);
|
Formatter buf = new Formatter(genHTML);
|
||||||
buf.append('[');
|
buf.append('[');
|
||||||
for (int i = 0; i < values.length; i++) {
|
for (int i = 0; i < values.length; i++) {
|
||||||
|
@ -594,9 +595,11 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
|
||||||
buf.cell(Integer.toString(cpool.getIntAt(index)));
|
buf.cell(Integer.toString(cpool.getIntAt(index)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||||
case JVM_CONSTANT_InvokeDynamic:
|
case JVM_CONSTANT_InvokeDynamic:
|
||||||
buf.cell("JVM_CONSTANT_InvokeDynamic");
|
buf.cell("JVM_CONSTANT_InvokeDynamic");
|
||||||
buf.cell(genListOfShort(cpool.getMultiOperandsAt(index)));
|
buf.cell(genLowHighShort(cpool.getIntAt(index)) +
|
||||||
|
genListOfShort(cpool.getBootstrapSpecifierAt(index)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class ConstantTag {
|
||||||
private static int JVM_CONSTANT_NameAndType = 12;
|
private static int JVM_CONSTANT_NameAndType = 12;
|
||||||
private static int JVM_CONSTANT_MethodHandle = 15; // JSR 292
|
private static int JVM_CONSTANT_MethodHandle = 15; // JSR 292
|
||||||
private static int JVM_CONSTANT_MethodType = 16; // JSR 292
|
private static int JVM_CONSTANT_MethodType = 16; // JSR 292
|
||||||
// static int JVM_CONSTANT_InvokeDynamicTrans = 17; // JSR 292, only occurs in old class files
|
private 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_InvokeDynamic = 18; // JSR 292
|
||||||
private static int JVM_CONSTANT_Invalid = 0; // For bad value initialization
|
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_UnresolvedClass = 100; // Temporary tag until actual use
|
||||||
|
@ -67,6 +67,8 @@ public class ConstantTag {
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int value() { return tag; }
|
||||||
|
|
||||||
public boolean isKlass() { return tag == JVM_CONSTANT_Class; }
|
public boolean isKlass() { return tag == JVM_CONSTANT_Class; }
|
||||||
public boolean isField () { return tag == JVM_CONSTANT_Fieldref; }
|
public boolean isField () { return tag == JVM_CONSTANT_Fieldref; }
|
||||||
public boolean isMethod() { return tag == JVM_CONSTANT_Methodref; }
|
public boolean isMethod() { return tag == JVM_CONSTANT_Methodref; }
|
||||||
|
@ -81,6 +83,7 @@ public class ConstantTag {
|
||||||
public boolean isMethodHandle() { return tag == JVM_CONSTANT_MethodHandle; }
|
public boolean isMethodHandle() { return tag == JVM_CONSTANT_MethodHandle; }
|
||||||
public boolean isMethodType() { return tag == JVM_CONSTANT_MethodType; }
|
public boolean isMethodType() { return tag == JVM_CONSTANT_MethodType; }
|
||||||
public boolean isInvokeDynamic() { return tag == JVM_CONSTANT_InvokeDynamic; }
|
public boolean isInvokeDynamic() { return tag == JVM_CONSTANT_InvokeDynamic; }
|
||||||
|
public boolean isInvokeDynamicTrans() { return tag == JVM_CONSTANT_InvokeDynamicTrans; }
|
||||||
|
|
||||||
public boolean isInvalid() { return tag == JVM_CONSTANT_Invalid; }
|
public boolean isInvalid() { return tag == JVM_CONSTANT_Invalid; }
|
||||||
|
|
||||||
|
|
|
@ -99,12 +99,6 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
|
||||||
unsigned int hashValues[SymbolTable::symbol_alloc_batch_size];
|
unsigned int hashValues[SymbolTable::symbol_alloc_batch_size];
|
||||||
int names_count = 0;
|
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
|
// parsing Index 0 is unused
|
||||||
for (int index = 1; index < length; index++) {
|
for (int index = 1; index < length; index++) {
|
||||||
// Each of the following case guarantees one more byte in the stream
|
// Each of the following case guarantees one more byte in the stream
|
||||||
|
@ -184,36 +178,20 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
|
||||||
"Class file version does not support constant tag %u in class file %s"),
|
"Class file version does not support constant tag %u in class file %s"),
|
||||||
tag, CHECK);
|
tag, CHECK);
|
||||||
}
|
}
|
||||||
if (!AllowTransitionalJSR292 && tag == JVM_CONSTANT_InvokeDynamicTrans) {
|
cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags
|
||||||
classfile_parse_error(
|
u2 bootstrap_specifier_index = cfs->get_u2_fast();
|
||||||
|
u2 name_and_type_index = cfs->get_u2_fast();
|
||||||
|
if (tag == JVM_CONSTANT_InvokeDynamicTrans) {
|
||||||
|
if (!AllowTransitionalJSR292)
|
||||||
|
classfile_parse_error(
|
||||||
"This JVM does not support transitional InvokeDynamic tag %u in class file %s",
|
"This JVM does not support transitional InvokeDynamic tag %u in class file %s",
|
||||||
tag, CHECK);
|
tag, CHECK);
|
||||||
|
cp->invoke_dynamic_trans_at_put(index, bootstrap_specifier_index, name_and_type_index);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
bool trans_no_argc = AllowTransitionalJSR292 && (tag == JVM_CONSTANT_InvokeDynamicTrans);
|
if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index)
|
||||||
cfs->guarantee_more(7, CHECK); // bsm_index, nt, argc, ..., tag/access_flags
|
_max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later
|
||||||
u2 bootstrap_method_index = cfs->get_u2_fast();
|
cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index);
|
||||||
u2 name_and_type_index = cfs->get_u2_fast();
|
|
||||||
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;
|
break;
|
||||||
case JVM_CONSTANT_Integer :
|
case JVM_CONSTANT_Integer :
|
||||||
|
@ -316,23 +294,6 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
|
||||||
oopFactory::new_symbols(cp, names_count, names, lengths, indices, hashValues, CHECK);
|
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().
|
// Copy _current pointer of local copy back to stream().
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
assert(cfs0->current() == old_current, "non-exclusive use of stream()");
|
assert(cfs0->current() == old_current, "non-exclusive use of stream()");
|
||||||
|
@ -340,41 +301,6 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
|
||||||
cfs0->set_current(cfs1.current());
|
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); }
|
bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); }
|
||||||
|
|
||||||
constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
|
constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
|
||||||
|
@ -401,7 +327,8 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
|
||||||
|
|
||||||
// first verification pass - validate cross references and fixup class and string constants
|
// first verification pass - validate cross references and fixup class and string constants
|
||||||
for (index = 1; index < length; index++) { // Index 0 is unused
|
for (index = 1; index < length; index++) { // Index 0 is unused
|
||||||
switch (cp->tag_at(index).value()) {
|
jbyte tag = cp->tag_at(index).value();
|
||||||
|
switch (tag) {
|
||||||
case JVM_CONSTANT_Class :
|
case JVM_CONSTANT_Class :
|
||||||
ShouldNotReachHere(); // Only JVM_CONSTANT_ClassIndex should be present
|
ShouldNotReachHere(); // Only JVM_CONSTANT_ClassIndex should be present
|
||||||
break;
|
break;
|
||||||
|
@ -543,35 +470,23 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case JVM_CONSTANT_InvokeDynamicTrans :
|
case JVM_CONSTANT_InvokeDynamicTrans :
|
||||||
ShouldNotReachHere(); // this tag does not appear in the heap
|
|
||||||
case JVM_CONSTANT_InvokeDynamic :
|
case JVM_CONSTANT_InvokeDynamic :
|
||||||
{
|
{
|
||||||
int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index);
|
|
||||||
int name_and_type_ref_index = cp->invoke_dynamic_name_and_type_ref_index_at(index);
|
int name_and_type_ref_index = cp->invoke_dynamic_name_and_type_ref_index_at(index);
|
||||||
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())),
|
|
||||||
"Invalid constant pool index %u in class file %s",
|
|
||||||
bootstrap_method_ref_index,
|
|
||||||
CHECK_(nullHandle));
|
|
||||||
check_property(valid_cp_range(name_and_type_ref_index, length) &&
|
check_property(valid_cp_range(name_and_type_ref_index, length) &&
|
||||||
cp->tag_at(name_and_type_ref_index).is_name_and_type(),
|
cp->tag_at(name_and_type_ref_index).is_name_and_type(),
|
||||||
"Invalid constant pool index %u in class file %s",
|
"Invalid constant pool index %u in class file %s",
|
||||||
name_and_type_ref_index,
|
name_and_type_ref_index,
|
||||||
CHECK_(nullHandle));
|
CHECK_(nullHandle));
|
||||||
int argc = cp->invoke_dynamic_argument_count_at(index);
|
if (tag == JVM_CONSTANT_InvokeDynamicTrans) {
|
||||||
for (int arg_i = 0; arg_i < argc; arg_i++) {
|
int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index);
|
||||||
int arg = cp->invoke_dynamic_argument_index_at(index, arg_i);
|
check_property(valid_cp_range(bootstrap_method_ref_index, length) &&
|
||||||
check_property(valid_cp_range(arg, length) &&
|
cp->tag_at(bootstrap_method_ref_index).is_method_handle(),
|
||||||
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",
|
"Invalid constant pool index %u in class file %s",
|
||||||
arg,
|
bootstrap_method_ref_index,
|
||||||
CHECK_(nullHandle));
|
CHECK_(nullHandle));
|
||||||
}
|
}
|
||||||
|
// bootstrap specifier index must be checked later, when BootstrapMethods attr is available
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -2429,6 +2344,76 @@ void ClassFileParser::parse_classfile_signature_attribute(constantPoolHandle cp,
|
||||||
k->set_generic_signature(cp->symbol_at(signature_index));
|
k->set_generic_signature(cp->symbol_at(signature_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClassFileParser::parse_classfile_bootstrap_methods_attribute(constantPoolHandle cp, instanceKlassHandle k,
|
||||||
|
u4 attribute_byte_length, TRAPS) {
|
||||||
|
ClassFileStream* cfs = stream();
|
||||||
|
u1* current_start = cfs->current();
|
||||||
|
|
||||||
|
cfs->guarantee_more(2, CHECK); // length
|
||||||
|
int attribute_array_length = cfs->get_u2_fast();
|
||||||
|
|
||||||
|
guarantee_property(_max_bootstrap_specifier_index < attribute_array_length,
|
||||||
|
"Short length on BootstrapMethods in class file %s",
|
||||||
|
CHECK);
|
||||||
|
|
||||||
|
// The attribute contains a counted array of counted tuples of shorts,
|
||||||
|
// represending bootstrap specifiers:
|
||||||
|
// length*{bootstrap_method_index, argument_count*{argument_index}}
|
||||||
|
int operand_count = (attribute_byte_length - sizeof(u2)) / sizeof(u2);
|
||||||
|
// operand_count = number of shorts in attr, except for leading length
|
||||||
|
|
||||||
|
// The attribute is copied into a short[] array.
|
||||||
|
// The array begins with a series of short[2] pairs, one for each tuple.
|
||||||
|
int index_size = (attribute_array_length * 2);
|
||||||
|
|
||||||
|
typeArrayOop operands_oop = oopFactory::new_permanent_intArray(index_size + operand_count, CHECK);
|
||||||
|
typeArrayHandle operands(THREAD, operands_oop);
|
||||||
|
operands_oop = NULL; // tidy
|
||||||
|
|
||||||
|
int operand_fill_index = index_size;
|
||||||
|
int cp_size = cp->length();
|
||||||
|
|
||||||
|
for (int n = 0; n < attribute_array_length; n++) {
|
||||||
|
// Store a 32-bit offset into the header of the operand array.
|
||||||
|
assert(constantPoolOopDesc::operand_offset_at(operands(), n) == 0, "");
|
||||||
|
constantPoolOopDesc::operand_offset_at_put(operands(), n, operand_fill_index);
|
||||||
|
|
||||||
|
// Read a bootstrap specifier.
|
||||||
|
cfs->guarantee_more(sizeof(u2) * 2, CHECK); // bsm, argc
|
||||||
|
u2 bootstrap_method_index = cfs->get_u2_fast();
|
||||||
|
u2 argument_count = cfs->get_u2_fast();
|
||||||
|
check_property(
|
||||||
|
valid_cp_range(bootstrap_method_index, cp_size) &&
|
||||||
|
cp->tag_at(bootstrap_method_index).is_method_handle(),
|
||||||
|
"bootstrap_method_index %u has bad constant type in class file %s",
|
||||||
|
CHECK);
|
||||||
|
operands->short_at_put(operand_fill_index++, bootstrap_method_index);
|
||||||
|
operands->short_at_put(operand_fill_index++, argument_count);
|
||||||
|
|
||||||
|
cfs->guarantee_more(sizeof(u2) * argument_count, CHECK); // argv[argc]
|
||||||
|
for (int j = 0; j < argument_count; j++) {
|
||||||
|
u2 arg_index = cfs->get_u2_fast();
|
||||||
|
check_property(
|
||||||
|
valid_cp_range(arg_index, cp_size) &&
|
||||||
|
cp->tag_at(arg_index).is_loadable_constant(),
|
||||||
|
"argument_index %u has bad constant type in class file %s",
|
||||||
|
CHECK);
|
||||||
|
operands->short_at_put(operand_fill_index++, arg_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(operand_fill_index == operands()->length(), "exact fill");
|
||||||
|
assert(constantPoolOopDesc::operand_array_length(operands()) == attribute_array_length, "correct decode");
|
||||||
|
|
||||||
|
u1* current_end = cfs->current();
|
||||||
|
guarantee_property(current_end == current_start + attribute_byte_length,
|
||||||
|
"Bad length on BootstrapMethods in class file %s",
|
||||||
|
CHECK);
|
||||||
|
|
||||||
|
cp->set_operands(operands());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ClassFileParser::parse_classfile_attributes(constantPoolHandle cp, instanceKlassHandle k, TRAPS) {
|
void ClassFileParser::parse_classfile_attributes(constantPoolHandle cp, instanceKlassHandle k, TRAPS) {
|
||||||
ClassFileStream* cfs = stream();
|
ClassFileStream* cfs = stream();
|
||||||
// Set inner classes attribute to default sentinel
|
// Set inner classes attribute to default sentinel
|
||||||
|
@ -2438,6 +2423,7 @@ void ClassFileParser::parse_classfile_attributes(constantPoolHandle cp, instance
|
||||||
bool parsed_sourcefile_attribute = false;
|
bool parsed_sourcefile_attribute = false;
|
||||||
bool parsed_innerclasses_attribute = false;
|
bool parsed_innerclasses_attribute = false;
|
||||||
bool parsed_enclosingmethod_attribute = false;
|
bool parsed_enclosingmethod_attribute = false;
|
||||||
|
bool parsed_bootstrap_methods_attribute = false;
|
||||||
u1* runtime_visible_annotations = NULL;
|
u1* runtime_visible_annotations = NULL;
|
||||||
int runtime_visible_annotations_length = 0;
|
int runtime_visible_annotations_length = 0;
|
||||||
u1* runtime_invisible_annotations = NULL;
|
u1* runtime_invisible_annotations = NULL;
|
||||||
|
@ -2536,6 +2522,12 @@ void ClassFileParser::parse_classfile_attributes(constantPoolHandle cp, instance
|
||||||
classfile_parse_error("Invalid or out-of-bounds method index in EnclosingMethod attribute in class file %s", CHECK);
|
classfile_parse_error("Invalid or out-of-bounds method index in EnclosingMethod attribute in class file %s", CHECK);
|
||||||
}
|
}
|
||||||
k->set_enclosing_method_indices(class_index, method_index);
|
k->set_enclosing_method_indices(class_index, method_index);
|
||||||
|
} else if (tag == vmSymbols::tag_bootstrap_methods() &&
|
||||||
|
_major_version >= Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
|
||||||
|
if (parsed_bootstrap_methods_attribute)
|
||||||
|
classfile_parse_error("Multiple BootstrapMethods attributes in class file %s", CHECK);
|
||||||
|
parsed_bootstrap_methods_attribute = true;
|
||||||
|
parse_classfile_bootstrap_methods_attribute(cp, k, attribute_length, CHECK);
|
||||||
} else {
|
} else {
|
||||||
// Unknown attribute
|
// Unknown attribute
|
||||||
cfs->skip_u1(attribute_length, CHECK);
|
cfs->skip_u1(attribute_length, CHECK);
|
||||||
|
@ -2551,6 +2543,11 @@ void ClassFileParser::parse_classfile_attributes(constantPoolHandle cp, instance
|
||||||
runtime_invisible_annotations_length,
|
runtime_invisible_annotations_length,
|
||||||
CHECK);
|
CHECK);
|
||||||
k->set_class_annotations(annotations());
|
k->set_class_annotations(annotations());
|
||||||
|
|
||||||
|
if (_max_bootstrap_specifier_index >= 0) {
|
||||||
|
guarantee_property(parsed_bootstrap_methods_attribute,
|
||||||
|
"Missing BootstrapMethods attribute in class file %s", CHECK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2868,6 +2865,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
|
||||||
PerfClassTraceTime::PARSE_CLASS);
|
PerfClassTraceTime::PARSE_CLASS);
|
||||||
|
|
||||||
_has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false;
|
_has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false;
|
||||||
|
_max_bootstrap_specifier_index = -1;
|
||||||
|
|
||||||
if (JvmtiExport::should_post_class_file_load_hook()) {
|
if (JvmtiExport::should_post_class_file_load_hook()) {
|
||||||
unsigned char* ptr = cfs->buffer();
|
unsigned char* ptr = cfs->buffer();
|
||||||
|
|
|
@ -50,6 +50,8 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||||
bool _has_empty_finalizer;
|
bool _has_empty_finalizer;
|
||||||
bool _has_vanilla_constructor;
|
bool _has_vanilla_constructor;
|
||||||
|
|
||||||
|
int _max_bootstrap_specifier_index;
|
||||||
|
|
||||||
enum { fixed_buffer_size = 128 };
|
enum { fixed_buffer_size = 128 };
|
||||||
u_char linenumbertable_buffer[fixed_buffer_size];
|
u_char linenumbertable_buffer[fixed_buffer_size];
|
||||||
|
|
||||||
|
@ -66,9 +68,6 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||||
|
|
||||||
constantPoolHandle parse_constant_pool(TRAPS);
|
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
|
// Interface parsing
|
||||||
objArrayHandle parse_interfaces(constantPoolHandle cp,
|
objArrayHandle parse_interfaces(constantPoolHandle cp,
|
||||||
int length,
|
int length,
|
||||||
|
@ -130,6 +129,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||||
void parse_classfile_attributes(constantPoolHandle cp, instanceKlassHandle k, TRAPS);
|
void parse_classfile_attributes(constantPoolHandle cp, instanceKlassHandle k, TRAPS);
|
||||||
void parse_classfile_synthetic_attribute(constantPoolHandle cp, instanceKlassHandle k, TRAPS);
|
void parse_classfile_synthetic_attribute(constantPoolHandle cp, instanceKlassHandle k, TRAPS);
|
||||||
void parse_classfile_signature_attribute(constantPoolHandle cp, instanceKlassHandle k, TRAPS);
|
void parse_classfile_signature_attribute(constantPoolHandle cp, instanceKlassHandle k, TRAPS);
|
||||||
|
void parse_classfile_bootstrap_methods_attribute(constantPoolHandle cp, instanceKlassHandle k, u4 attribute_length, TRAPS);
|
||||||
|
|
||||||
// Annotations handling
|
// Annotations handling
|
||||||
typeArrayHandle assemble_annotations(u1* runtime_visible_annotations,
|
typeArrayHandle assemble_annotations(u1* runtime_visible_annotations,
|
||||||
|
|
|
@ -132,6 +132,7 @@
|
||||||
template(tag_runtime_invisible_parameter_annotations,"RuntimeInvisibleParameterAnnotations") \
|
template(tag_runtime_invisible_parameter_annotations,"RuntimeInvisibleParameterAnnotations") \
|
||||||
template(tag_annotation_default, "AnnotationDefault") \
|
template(tag_annotation_default, "AnnotationDefault") \
|
||||||
template(tag_enclosing_method, "EnclosingMethod") \
|
template(tag_enclosing_method, "EnclosingMethod") \
|
||||||
|
template(tag_bootstrap_methods, "BootstrapMethods") \
|
||||||
\
|
\
|
||||||
/* exception klasses: at least all exceptions thrown by the VM have entries here */ \
|
/* exception klasses: at least all exceptions thrown by the VM have entries here */ \
|
||||||
template(java_lang_ArithmeticException, "java/lang/ArithmeticException") \
|
template(java_lang_ArithmeticException, "java/lang/ArithmeticException") \
|
||||||
|
|
|
@ -346,6 +346,7 @@ void BytecodePrinter::print_field_or_method(int orig_i, int i, outputStream* st)
|
||||||
break;
|
break;
|
||||||
case JVM_CONSTANT_NameAndType:
|
case JVM_CONSTANT_NameAndType:
|
||||||
case JVM_CONSTANT_InvokeDynamic:
|
case JVM_CONSTANT_InvokeDynamic:
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||||
has_klass = false;
|
has_klass = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -52,6 +52,7 @@ void Rewriter::compute_index_maps() {
|
||||||
case JVM_CONSTANT_MethodHandle : // fall through
|
case JVM_CONSTANT_MethodHandle : // fall through
|
||||||
case JVM_CONSTANT_MethodType : // fall through
|
case JVM_CONSTANT_MethodType : // fall through
|
||||||
case JVM_CONSTANT_InvokeDynamic : // fall through
|
case JVM_CONSTANT_InvokeDynamic : // fall through
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans: // fall through
|
||||||
add_cp_cache_entry(i);
|
add_cp_cache_entry(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +62,7 @@ void Rewriter::compute_index_maps() {
|
||||||
"all cp cache indexes fit in a u2");
|
"all cp cache indexes fit in a u2");
|
||||||
|
|
||||||
_have_invoke_dynamic = ((tag_mask & (1 << JVM_CONSTANT_InvokeDynamic)) != 0);
|
_have_invoke_dynamic = ((tag_mask & (1 << JVM_CONSTANT_InvokeDynamic)) != 0);
|
||||||
|
_have_invoke_dynamic |= ((tag_mask & (1 << JVM_CONSTANT_InvokeDynamicTrans)) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,7 +76,7 @@ void Rewriter::make_constant_pool_cache(TRAPS) {
|
||||||
oopFactory::new_constantPoolCache(length, methodOopDesc::IsUnsafeConc, CHECK);
|
oopFactory::new_constantPoolCache(length, methodOopDesc::IsUnsafeConc, CHECK);
|
||||||
cache->initialize(_cp_cache_map);
|
cache->initialize(_cp_cache_map);
|
||||||
|
|
||||||
// Don't bother to the next pass if there is no JVM_CONSTANT_InvokeDynamic.
|
// Don't bother with the next pass if there is no JVM_CONSTANT_InvokeDynamic.
|
||||||
if (_have_invoke_dynamic) {
|
if (_have_invoke_dynamic) {
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
int pool_index = cp_cache_entry_pool_index(i);
|
int pool_index = cp_cache_entry_pool_index(i);
|
||||||
|
|
|
@ -399,6 +399,7 @@ void constantPoolKlass::oop_print_on(oop obj, outputStream* st) {
|
||||||
case JVM_CONSTANT_MethodType :
|
case JVM_CONSTANT_MethodType :
|
||||||
st->print("signature_index=%d", cp->method_type_index_at(index));
|
st->print("signature_index=%d", cp->method_type_index_at(index));
|
||||||
break;
|
break;
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans :
|
||||||
case JVM_CONSTANT_InvokeDynamic :
|
case JVM_CONSTANT_InvokeDynamic :
|
||||||
{
|
{
|
||||||
st->print("bootstrap_method_index=%d", cp->invoke_dynamic_bootstrap_method_ref_index_at(index));
|
st->print("bootstrap_method_index=%d", cp->invoke_dynamic_bootstrap_method_ref_index_at(index));
|
||||||
|
|
|
@ -915,7 +915,8 @@ bool constantPoolOopDesc::compare_entry_to(int index1, constantPoolHandle cp2,
|
||||||
{
|
{
|
||||||
int k1 = method_type_index_at(index1);
|
int k1 = method_type_index_at(index1);
|
||||||
int k2 = cp2->method_type_index_at(index2);
|
int k2 = cp2->method_type_index_at(index2);
|
||||||
if (k1 == k2) {
|
bool match = compare_entry_to(k1, cp2, k2, CHECK_false);
|
||||||
|
if (match) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
@ -927,28 +928,33 @@ bool constantPoolOopDesc::compare_entry_to(int index1, constantPoolHandle cp2,
|
||||||
if (k1 == k2) {
|
if (k1 == k2) {
|
||||||
int i1 = method_handle_index_at(index1);
|
int i1 = method_handle_index_at(index1);
|
||||||
int i2 = cp2->method_handle_index_at(index2);
|
int i2 = cp2->method_handle_index_at(index2);
|
||||||
if (i1 == i2) {
|
bool match = compare_entry_to(i1, cp2, i2, CHECK_false);
|
||||||
|
if (match) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_InvokeDynamic:
|
case JVM_CONSTANT_InvokeDynamic:
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||||
{
|
{
|
||||||
int op_count = multi_operand_count_at(index1);
|
int k1 = invoke_dynamic_bootstrap_method_ref_index_at(index1);
|
||||||
if (op_count == cp2->multi_operand_count_at(index2)) {
|
int k2 = cp2->invoke_dynamic_bootstrap_method_ref_index_at(index2);
|
||||||
bool all_equal = true;
|
bool match = compare_entry_to(k1, cp2, k2, CHECK_false);
|
||||||
for (int op_i = 0; op_i < op_count; op_i++) {
|
if (!match) return false;
|
||||||
int k1 = multi_operand_ref_at(index1, op_i);
|
k1 = invoke_dynamic_name_and_type_ref_index_at(index1);
|
||||||
int k2 = cp2->multi_operand_ref_at(index2, op_i);
|
k2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2);
|
||||||
if (k1 != k2) {
|
match = compare_entry_to(k1, cp2, k2, CHECK_false);
|
||||||
all_equal = false;
|
if (!match) return false;
|
||||||
break;
|
int argc = invoke_dynamic_argument_count_at(index1);
|
||||||
}
|
if (argc == cp2->invoke_dynamic_argument_count_at(index2)) {
|
||||||
}
|
for (int j = 0; j < argc; j++) {
|
||||||
if (all_equal) {
|
k1 = invoke_dynamic_argument_index_at(index1, j);
|
||||||
return true; // got through loop; all elements equal
|
k2 = cp2->invoke_dynamic_argument_index_at(index2, j);
|
||||||
|
match = compare_entry_to(k1, cp2, k2, CHECK_false);
|
||||||
|
if (!match) return false;
|
||||||
}
|
}
|
||||||
|
return true; // got through loop; all elements equal
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -984,44 +990,18 @@ bool constantPoolOopDesc::compare_entry_to(int index1, constantPoolHandle cp2,
|
||||||
} // end compare_entry_to()
|
} // 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)
|
// 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
|
// to the constant pool to_cp's entries starting at to_i. A total of
|
||||||
// (end_i - start_i) + 1 entries are copied.
|
// (end_i - start_i) + 1 entries are copied.
|
||||||
void constantPoolOopDesc::copy_cp_to(int start_i, int end_i,
|
void constantPoolOopDesc::copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int end_i,
|
||||||
constantPoolHandle to_cp, int to_i, TRAPS) {
|
constantPoolHandle to_cp, int to_i, TRAPS) {
|
||||||
|
|
||||||
int dest_i = to_i; // leave original alone for debug purposes
|
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 */ ) {
|
for (int src_i = start_i; src_i <= end_i; /* see loop bottom */ ) {
|
||||||
copy_entry_to(src_i, to_cp, dest_i, CHECK);
|
copy_entry_to(from_cp, src_i, to_cp, dest_i, CHECK);
|
||||||
|
|
||||||
switch (tag_at(src_i).value()) {
|
switch (from_cp->tag_at(src_i).value()) {
|
||||||
case JVM_CONSTANT_Double:
|
case JVM_CONSTANT_Double:
|
||||||
case JVM_CONSTANT_Long:
|
case JVM_CONSTANT_Long:
|
||||||
// double and long take two constant pool entries
|
// double and long take two constant pool entries
|
||||||
|
@ -1036,30 +1016,81 @@ void constantPoolOopDesc::copy_cp_to(int start_i, int end_i,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int from_oplen = operand_array_length(from_cp->operands());
|
||||||
|
int old_oplen = operand_array_length(to_cp->operands());
|
||||||
|
if (from_oplen != 0) {
|
||||||
|
// append my operands to the target's operands array
|
||||||
|
if (old_oplen == 0) {
|
||||||
|
to_cp->set_operands(from_cp->operands()); // reuse; do not merge
|
||||||
|
} else {
|
||||||
|
int old_len = to_cp->operands()->length();
|
||||||
|
int from_len = from_cp->operands()->length();
|
||||||
|
int old_off = old_oplen * sizeof(u2);
|
||||||
|
int from_off = from_oplen * sizeof(u2);
|
||||||
|
typeArrayHandle new_operands = oopFactory::new_permanent_shortArray(old_len + from_len, CHECK);
|
||||||
|
int fillp = 0, len = 0;
|
||||||
|
// first part of dest
|
||||||
|
Copy::conjoint_memory_atomic(to_cp->operands()->short_at_addr(0),
|
||||||
|
new_operands->short_at_addr(fillp),
|
||||||
|
(len = old_off) * sizeof(u2));
|
||||||
|
fillp += len;
|
||||||
|
// first part of src
|
||||||
|
Copy::conjoint_memory_atomic(to_cp->operands()->short_at_addr(0),
|
||||||
|
new_operands->short_at_addr(fillp),
|
||||||
|
(len = from_off) * sizeof(u2));
|
||||||
|
fillp += len;
|
||||||
|
// second part of dest
|
||||||
|
Copy::conjoint_memory_atomic(to_cp->operands()->short_at_addr(old_off),
|
||||||
|
new_operands->short_at_addr(fillp),
|
||||||
|
(len = old_len - old_off) * sizeof(u2));
|
||||||
|
fillp += len;
|
||||||
|
// second part of src
|
||||||
|
Copy::conjoint_memory_atomic(to_cp->operands()->short_at_addr(from_off),
|
||||||
|
new_operands->short_at_addr(fillp),
|
||||||
|
(len = from_len - from_off) * sizeof(u2));
|
||||||
|
fillp += len;
|
||||||
|
assert(fillp == new_operands->length(), "");
|
||||||
|
|
||||||
|
// Adjust indexes in the first part of the copied operands array.
|
||||||
|
for (int j = 0; j < from_oplen; j++) {
|
||||||
|
int offset = operand_offset_at(new_operands(), old_oplen + j);
|
||||||
|
assert(offset == operand_offset_at(from_cp->operands(), j), "correct copy");
|
||||||
|
offset += old_len; // every new tuple is preceded by old_len extra u2's
|
||||||
|
operand_offset_at_put(new_operands(), old_oplen + j, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace target operands array with combined array
|
||||||
|
to_cp->set_operands(new_operands());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // end copy_cp_to()
|
} // end copy_cp_to()
|
||||||
|
|
||||||
|
|
||||||
// Copy this constant pool's entry at from_i to the constant pool
|
// Copy this constant pool's entry at from_i to the constant pool
|
||||||
// to_cp's entry at to_i.
|
// to_cp's entry at to_i.
|
||||||
void constantPoolOopDesc::copy_entry_to(int from_i, constantPoolHandle to_cp,
|
void constantPoolOopDesc::copy_entry_to(constantPoolHandle from_cp, int from_i,
|
||||||
int to_i, TRAPS) {
|
constantPoolHandle to_cp, int to_i,
|
||||||
|
TRAPS) {
|
||||||
|
|
||||||
switch (tag_at(from_i).value()) {
|
int tag = from_cp->tag_at(from_i).value();
|
||||||
|
switch (tag) {
|
||||||
case JVM_CONSTANT_Class:
|
case JVM_CONSTANT_Class:
|
||||||
{
|
{
|
||||||
klassOop k = klass_at(from_i, CHECK);
|
klassOop k = from_cp->klass_at(from_i, CHECK);
|
||||||
to_cp->klass_at_put(to_i, k);
|
to_cp->klass_at_put(to_i, k);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_ClassIndex:
|
case JVM_CONSTANT_ClassIndex:
|
||||||
{
|
{
|
||||||
jint ki = klass_index_at(from_i);
|
jint ki = from_cp->klass_index_at(from_i);
|
||||||
to_cp->klass_index_at_put(to_i, ki);
|
to_cp->klass_index_at_put(to_i, ki);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_Double:
|
case JVM_CONSTANT_Double:
|
||||||
{
|
{
|
||||||
jdouble d = double_at(from_i);
|
jdouble d = from_cp->double_at(from_i);
|
||||||
to_cp->double_at_put(to_i, d);
|
to_cp->double_at_put(to_i, d);
|
||||||
// double takes two constant pool entries so init second entry's tag
|
// double takes two constant pool entries so init second entry's tag
|
||||||
to_cp->tag_at_put(to_i + 1, JVM_CONSTANT_Invalid);
|
to_cp->tag_at_put(to_i + 1, JVM_CONSTANT_Invalid);
|
||||||
|
@ -1067,33 +1098,33 @@ void constantPoolOopDesc::copy_entry_to(int from_i, constantPoolHandle to_cp,
|
||||||
|
|
||||||
case JVM_CONSTANT_Fieldref:
|
case JVM_CONSTANT_Fieldref:
|
||||||
{
|
{
|
||||||
int class_index = uncached_klass_ref_index_at(from_i);
|
int class_index = from_cp->uncached_klass_ref_index_at(from_i);
|
||||||
int name_and_type_index = uncached_name_and_type_ref_index_at(from_i);
|
int name_and_type_index = from_cp->uncached_name_and_type_ref_index_at(from_i);
|
||||||
to_cp->field_at_put(to_i, class_index, name_and_type_index);
|
to_cp->field_at_put(to_i, class_index, name_and_type_index);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_Float:
|
case JVM_CONSTANT_Float:
|
||||||
{
|
{
|
||||||
jfloat f = float_at(from_i);
|
jfloat f = from_cp->float_at(from_i);
|
||||||
to_cp->float_at_put(to_i, f);
|
to_cp->float_at_put(to_i, f);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_Integer:
|
case JVM_CONSTANT_Integer:
|
||||||
{
|
{
|
||||||
jint i = int_at(from_i);
|
jint i = from_cp->int_at(from_i);
|
||||||
to_cp->int_at_put(to_i, i);
|
to_cp->int_at_put(to_i, i);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_InterfaceMethodref:
|
case JVM_CONSTANT_InterfaceMethodref:
|
||||||
{
|
{
|
||||||
int class_index = uncached_klass_ref_index_at(from_i);
|
int class_index = from_cp->uncached_klass_ref_index_at(from_i);
|
||||||
int name_and_type_index = uncached_name_and_type_ref_index_at(from_i);
|
int name_and_type_index = from_cp->uncached_name_and_type_ref_index_at(from_i);
|
||||||
to_cp->interface_method_at_put(to_i, class_index, name_and_type_index);
|
to_cp->interface_method_at_put(to_i, class_index, name_and_type_index);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_Long:
|
case JVM_CONSTANT_Long:
|
||||||
{
|
{
|
||||||
jlong l = long_at(from_i);
|
jlong l = from_cp->long_at(from_i);
|
||||||
to_cp->long_at_put(to_i, l);
|
to_cp->long_at_put(to_i, l);
|
||||||
// long takes two constant pool entries so init second entry's tag
|
// long takes two constant pool entries so init second entry's tag
|
||||||
to_cp->tag_at_put(to_i + 1, JVM_CONSTANT_Invalid);
|
to_cp->tag_at_put(to_i + 1, JVM_CONSTANT_Invalid);
|
||||||
|
@ -1101,39 +1132,39 @@ void constantPoolOopDesc::copy_entry_to(int from_i, constantPoolHandle to_cp,
|
||||||
|
|
||||||
case JVM_CONSTANT_Methodref:
|
case JVM_CONSTANT_Methodref:
|
||||||
{
|
{
|
||||||
int class_index = uncached_klass_ref_index_at(from_i);
|
int class_index = from_cp->uncached_klass_ref_index_at(from_i);
|
||||||
int name_and_type_index = uncached_name_and_type_ref_index_at(from_i);
|
int name_and_type_index = from_cp->uncached_name_and_type_ref_index_at(from_i);
|
||||||
to_cp->method_at_put(to_i, class_index, name_and_type_index);
|
to_cp->method_at_put(to_i, class_index, name_and_type_index);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_NameAndType:
|
case JVM_CONSTANT_NameAndType:
|
||||||
{
|
{
|
||||||
int name_ref_index = name_ref_index_at(from_i);
|
int name_ref_index = from_cp->name_ref_index_at(from_i);
|
||||||
int signature_ref_index = signature_ref_index_at(from_i);
|
int signature_ref_index = from_cp->signature_ref_index_at(from_i);
|
||||||
to_cp->name_and_type_at_put(to_i, name_ref_index, signature_ref_index);
|
to_cp->name_and_type_at_put(to_i, name_ref_index, signature_ref_index);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_String:
|
case JVM_CONSTANT_String:
|
||||||
{
|
{
|
||||||
oop s = string_at(from_i, CHECK);
|
oop s = from_cp->string_at(from_i, CHECK);
|
||||||
to_cp->string_at_put(to_i, s);
|
to_cp->string_at_put(to_i, s);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_StringIndex:
|
case JVM_CONSTANT_StringIndex:
|
||||||
{
|
{
|
||||||
jint si = string_index_at(from_i);
|
jint si = from_cp->string_index_at(from_i);
|
||||||
to_cp->string_index_at_put(to_i, si);
|
to_cp->string_index_at_put(to_i, si);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_UnresolvedClass:
|
case JVM_CONSTANT_UnresolvedClass:
|
||||||
{
|
{
|
||||||
symbolOop k = unresolved_klass_at(from_i);
|
symbolOop k = from_cp->unresolved_klass_at(from_i);
|
||||||
to_cp->unresolved_klass_at_put(to_i, k);
|
to_cp->unresolved_klass_at_put(to_i, k);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_UnresolvedClassInError:
|
case JVM_CONSTANT_UnresolvedClassInError:
|
||||||
{
|
{
|
||||||
symbolOop k = unresolved_klass_at(from_i);
|
symbolOop k = from_cp->unresolved_klass_at(from_i);
|
||||||
to_cp->unresolved_klass_at_put(to_i, k);
|
to_cp->unresolved_klass_at_put(to_i, k);
|
||||||
to_cp->tag_at_put(to_i, JVM_CONSTANT_UnresolvedClassInError);
|
to_cp->tag_at_put(to_i, JVM_CONSTANT_UnresolvedClassInError);
|
||||||
} break;
|
} break;
|
||||||
|
@ -1141,51 +1172,42 @@ void constantPoolOopDesc::copy_entry_to(int from_i, constantPoolHandle to_cp,
|
||||||
|
|
||||||
case JVM_CONSTANT_UnresolvedString:
|
case JVM_CONSTANT_UnresolvedString:
|
||||||
{
|
{
|
||||||
symbolOop s = unresolved_string_at(from_i);
|
symbolOop s = from_cp->unresolved_string_at(from_i);
|
||||||
to_cp->unresolved_string_at_put(to_i, s);
|
to_cp->unresolved_string_at_put(to_i, s);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_Utf8:
|
case JVM_CONSTANT_Utf8:
|
||||||
{
|
{
|
||||||
symbolOop s = symbol_at(from_i);
|
symbolOop s = from_cp->symbol_at(from_i);
|
||||||
to_cp->symbol_at_put(to_i, s);
|
to_cp->symbol_at_put(to_i, s);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_MethodType:
|
case JVM_CONSTANT_MethodType:
|
||||||
{
|
{
|
||||||
jint k = method_type_index_at(from_i);
|
jint k = from_cp->method_type_index_at(from_i);
|
||||||
to_cp->method_type_index_at_put(to_i, k);
|
to_cp->method_type_index_at_put(to_i, k);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_MethodHandle:
|
case JVM_CONSTANT_MethodHandle:
|
||||||
{
|
{
|
||||||
int k1 = method_handle_ref_kind_at(from_i);
|
int k1 = from_cp->method_handle_ref_kind_at(from_i);
|
||||||
int k2 = method_handle_index_at(from_i);
|
int k2 = from_cp->method_handle_index_at(from_i);
|
||||||
to_cp->method_handle_index_at_put(to_i, k1, k2);
|
to_cp->method_handle_index_at_put(to_i, k1, k2);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||||
|
{
|
||||||
|
int k1 = from_cp->invoke_dynamic_bootstrap_method_ref_index_at(from_i);
|
||||||
|
int k2 = from_cp->invoke_dynamic_name_and_type_ref_index_at(from_i);
|
||||||
|
to_cp->invoke_dynamic_trans_at_put(to_i, k1, k2);
|
||||||
|
} break;
|
||||||
|
|
||||||
case JVM_CONSTANT_InvokeDynamic:
|
case JVM_CONSTANT_InvokeDynamic:
|
||||||
{
|
{
|
||||||
int op_count = multi_operand_count_at(from_i);
|
int k1 = from_cp->invoke_dynamic_bootstrap_specifier_index(from_i);
|
||||||
int fillp = to_cp->multi_operand_buffer_fill_pointer();
|
int k2 = from_cp->invoke_dynamic_name_and_type_ref_index_at(from_i);
|
||||||
int to_op_base = fillp - _multi_operand_count_offset; // fillp is count offset; get to base
|
k1 += operand_array_length(to_cp->operands()); // to_cp might already have operands
|
||||||
to_cp->multi_operand_buffer_grow(to_op_base + op_count, CHECK);
|
to_cp->invoke_dynamic_at_put(to_i, k1, k2);
|
||||||
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);
|
|
||||||
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;
|
} break;
|
||||||
|
|
||||||
// Invalid is used as the tag for the second constant pool entry
|
// Invalid is used as the tag for the second constant pool entry
|
||||||
|
@ -1195,7 +1217,6 @@ void constantPoolOopDesc::copy_entry_to(int from_i, constantPoolHandle to_cp,
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
jbyte bad_value = tag_at(from_i).value(); // leave a breadcrumb
|
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -1406,8 +1427,9 @@ jint constantPoolOopDesc::cpool_entry_size(jint idx) {
|
||||||
return 5;
|
return 5;
|
||||||
|
|
||||||
case JVM_CONSTANT_InvokeDynamic:
|
case JVM_CONSTANT_InvokeDynamic:
|
||||||
// u1 tag, u2 bsm, u2 nt, u2 argc, u2 argv[argc]
|
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||||
return 7 + 2 * invoke_dynamic_argument_count_at(idx);
|
// u1 tag, u2 bsm, u2 nt
|
||||||
|
return 5;
|
||||||
|
|
||||||
case JVM_CONSTANT_Long:
|
case JVM_CONSTANT_Long:
|
||||||
case JVM_CONSTANT_Double:
|
case JVM_CONSTANT_Double:
|
||||||
|
@ -1620,19 +1642,15 @@ int constantPoolOopDesc::copy_cpool_bytes(int cpool_size,
|
||||||
DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1));
|
DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans:
|
||||||
case JVM_CONSTANT_InvokeDynamic: {
|
case JVM_CONSTANT_InvokeDynamic: {
|
||||||
*bytes = JVM_CONSTANT_InvokeDynamic;
|
*bytes = tag;
|
||||||
idx1 = invoke_dynamic_bootstrap_method_ref_index_at(idx);
|
idx1 = extract_low_short_from_int(*int_at_addr(idx));
|
||||||
idx2 = invoke_dynamic_name_and_type_ref_index_at(idx);
|
idx2 = extract_high_short_from_int(*int_at_addr(idx));
|
||||||
int argc = invoke_dynamic_argument_count_at(idx);
|
assert(idx2 == invoke_dynamic_name_and_type_ref_index_at(idx), "correct half of u4");
|
||||||
Bytes::put_Java_u2((address) (bytes+1), idx1);
|
Bytes::put_Java_u2((address) (bytes+1), idx1);
|
||||||
Bytes::put_Java_u2((address) (bytes+3), idx2);
|
Bytes::put_Java_u2((address) (bytes+3), idx2);
|
||||||
Bytes::put_Java_u2((address) (bytes+5), argc);
|
DBG(printf("JVM_CONSTANT_InvokeDynamic: %hd %hd", idx1, idx2));
|
||||||
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,28 +179,16 @@ class constantPoolOopDesc : public oopDesc {
|
||||||
*int_at_addr(which) = ref_index;
|
*int_at_addr(which) = ref_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void invoke_dynamic_at_put(int which, int operand_base, int operand_count) {
|
void invoke_dynamic_at_put(int which, int bootstrap_specifier_index, int name_and_type_index) {
|
||||||
tag_at_put(which, JVM_CONSTANT_InvokeDynamic);
|
tag_at_put(which, JVM_CONSTANT_InvokeDynamic);
|
||||||
*int_at_addr(which) = operand_base; // this is the real information
|
*int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_specifier_index;
|
||||||
}
|
}
|
||||||
#ifdef ASSERT
|
|
||||||
bool check_invoke_dynamic_at(int which,
|
void invoke_dynamic_trans_at_put(int which, int bootstrap_method_index, int name_and_type_index) {
|
||||||
int bootstrap_method_index,
|
tag_at_put(which, JVM_CONSTANT_InvokeDynamicTrans);
|
||||||
int name_and_type_index,
|
*int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_method_index;
|
||||||
int argument_count) {
|
assert(AllowTransitionalJSR292, "");
|
||||||
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
|
// Temporary until actual use
|
||||||
void unresolved_string_at_put(int which, symbolOop s) {
|
void unresolved_string_at_put(int which, symbolOop s) {
|
||||||
|
@ -443,75 +431,90 @@ class constantPoolOopDesc : public oopDesc {
|
||||||
return symbol_at(sym);
|
return symbol_at(sym);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
int invoke_dynamic_name_and_type_ref_index_at(int which) {
|
||||||
// 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");
|
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
|
||||||
int op_base = *int_at_addr(which);
|
return extract_high_short_from_int(*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 invoke_dynamic_bootstrap_specifier_index(int which) {
|
||||||
int op_base = multi_operand_base_at(which);
|
assert(tag_at(which).value() == JVM_CONSTANT_InvokeDynamic, "Corrupted constant pool");
|
||||||
assert((uint)(op_base + _multi_operand_count_offset) < (uint)operands()->length(), "oob");
|
return extract_low_short_from_int(*int_at_addr(which));
|
||||||
int count = operands()->int_at(op_base + _multi_operand_count_offset);
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
int multi_operand_ref_at(int which, int i) {
|
int invoke_dynamic_operand_base(int which) {
|
||||||
int op_base = multi_operand_base_at(which);
|
int bootstrap_specifier_index = invoke_dynamic_bootstrap_specifier_index(which);
|
||||||
assert((uint)i < (uint)multi_operand_count_at(which), "oob");
|
return operand_offset_at(operands(), bootstrap_specifier_index);
|
||||||
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) {
|
// The first part of the operands array consists of an index into the second part.
|
||||||
DEBUG_ONLY(multi_operand_ref_at(which, i)); // trigger asserts
|
// Extract a 32-bit index value from the first part.
|
||||||
int op_base = multi_operand_base_at(which);
|
static int operand_offset_at(typeArrayOop operands, int bootstrap_specifier_index) {
|
||||||
operands()->int_at_put(op_base + _multi_operand_base_offset + i, ref);
|
int n = (bootstrap_specifier_index * 2);
|
||||||
|
assert(n >= 0 && n+2 <= operands->length(), "oob");
|
||||||
|
// The first 32-bit index points to the beginning of the second part
|
||||||
|
// of the operands array. Make sure this index is in the first part.
|
||||||
|
DEBUG_ONLY(int second_part = build_int_from_shorts(operands->short_at(0),
|
||||||
|
operands->short_at(1)));
|
||||||
|
assert(second_part == 0 || n+2 <= second_part, "oob (2)");
|
||||||
|
int offset = build_int_from_shorts(operands->short_at(n+0),
|
||||||
|
operands->short_at(n+1));
|
||||||
|
// The offset itself must point into the second part of the array.
|
||||||
|
assert(offset == 0 || offset >= second_part && offset <= operands->length(), "oob (3)");
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
static void operand_offset_at_put(typeArrayOop operands, int bootstrap_specifier_index, int offset) {
|
||||||
|
int n = bootstrap_specifier_index * 2;
|
||||||
|
assert(n >= 0 && n+2 <= operands->length(), "oob");
|
||||||
|
operands->short_at_put(n+0, extract_low_short_from_int(offset));
|
||||||
|
operands->short_at_put(n+1, extract_high_short_from_int(offset));
|
||||||
|
}
|
||||||
|
static int operand_array_length(typeArrayOop operands) {
|
||||||
|
if (operands == NULL || operands->length() == 0) return 0;
|
||||||
|
int second_part = operand_offset_at(operands, 0);
|
||||||
|
return (second_part / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
#ifdef ASSERT
|
||||||
// layout of InvokeDynamic:
|
// operand tuples fit together exactly, end to end
|
||||||
|
static int operand_limit_at(typeArrayOop operands, int bootstrap_specifier_index) {
|
||||||
|
int nextidx = bootstrap_specifier_index + 1;
|
||||||
|
if (nextidx == operand_array_length(operands))
|
||||||
|
return operands->length();
|
||||||
|
else
|
||||||
|
return operand_offset_at(operands, nextidx);
|
||||||
|
}
|
||||||
|
int invoke_dynamic_operand_limit(int which) {
|
||||||
|
int bootstrap_specifier_index = invoke_dynamic_bootstrap_specifier_index(which);
|
||||||
|
return operand_limit_at(operands(), bootstrap_specifier_index);
|
||||||
|
}
|
||||||
|
#endif //ASSERT
|
||||||
|
|
||||||
|
// layout of InvokeDynamic bootstrap method specifier (in second part of operands array):
|
||||||
enum {
|
enum {
|
||||||
_indy_bsm_offset = 0, // CONSTANT_MethodHandle bsm
|
_indy_bsm_offset = 0, // CONSTANT_MethodHandle bsm
|
||||||
_indy_nt_offset = 1, // CONSTANT_NameAndType descr
|
_indy_argc_offset = 1, // u2 argc
|
||||||
_indy_argc_offset = 2, // u2 argc
|
_indy_argv_offset = 2 // u2 argv[argc]
|
||||||
_indy_argv_offset = 3 // u2 argv[argc]
|
|
||||||
};
|
};
|
||||||
int invoke_dynamic_bootstrap_method_ref_index_at(int which) {
|
int invoke_dynamic_bootstrap_method_ref_index_at(int which) {
|
||||||
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
|
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
|
||||||
return multi_operand_ref_at(which, _indy_bsm_offset);
|
if (tag_at(which).value() == JVM_CONSTANT_InvokeDynamicTrans)
|
||||||
}
|
return extract_low_short_from_int(*int_at_addr(which));
|
||||||
int invoke_dynamic_name_and_type_ref_index_at(int which) {
|
int op_base = invoke_dynamic_operand_base(which);
|
||||||
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
|
return operands()->short_at(op_base + _indy_bsm_offset);
|
||||||
return multi_operand_ref_at(which, _indy_nt_offset);
|
|
||||||
}
|
}
|
||||||
int invoke_dynamic_argument_count_at(int which) {
|
int invoke_dynamic_argument_count_at(int which) {
|
||||||
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
|
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
|
||||||
int argc = multi_operand_ref_at(which, _indy_argc_offset);
|
if (tag_at(which).value() == JVM_CONSTANT_InvokeDynamicTrans)
|
||||||
DEBUG_ONLY(int op_count = multi_operand_count_at(which));
|
return 0;
|
||||||
assert(_indy_argv_offset + argc == op_count, "consistent inner and outer counts");
|
int op_base = invoke_dynamic_operand_base(which);
|
||||||
|
int argc = operands()->short_at(op_base + _indy_argc_offset);
|
||||||
|
DEBUG_ONLY(int end_offset = op_base + _indy_argv_offset + argc;
|
||||||
|
int next_offset = invoke_dynamic_operand_limit(which));
|
||||||
|
assert(end_offset == next_offset, "matched ending");
|
||||||
return argc;
|
return argc;
|
||||||
}
|
}
|
||||||
int invoke_dynamic_argument_index_at(int which, int j) {
|
int invoke_dynamic_argument_index_at(int which, int j) {
|
||||||
assert((uint)j < (uint)invoke_dynamic_argument_count_at(which), "oob");
|
int op_base = invoke_dynamic_operand_base(which);
|
||||||
return multi_operand_ref_at(which, _indy_argv_offset + j);
|
DEBUG_ONLY(int argc = operands()->short_at(op_base + _indy_argc_offset));
|
||||||
|
assert((uint)j < (uint)argc, "oob");
|
||||||
|
return operands()->short_at(op_base + _indy_argv_offset + j);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve,
|
// The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve,
|
||||||
|
@ -659,9 +662,12 @@ class constantPoolOopDesc : public oopDesc {
|
||||||
public:
|
public:
|
||||||
// Merging constantPoolOop support:
|
// Merging constantPoolOop support:
|
||||||
bool compare_entry_to(int index1, constantPoolHandle cp2, int index2, TRAPS);
|
bool compare_entry_to(int index1, constantPoolHandle cp2, int index2, TRAPS);
|
||||||
void copy_cp_to(int start_i, int end_i, constantPoolHandle to_cp, int to_i,
|
void copy_cp_to(int start_i, int end_i, constantPoolHandle to_cp, int to_i, TRAPS) {
|
||||||
TRAPS);
|
constantPoolHandle h_this(THREAD, this);
|
||||||
void copy_entry_to(int from_i, constantPoolHandle to_cp, int to_i, TRAPS);
|
copy_cp_to_impl(h_this, start_i, end_i, to_cp, to_i, THREAD);
|
||||||
|
}
|
||||||
|
static void copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int end_i, constantPoolHandle to_cp, int to_i, TRAPS);
|
||||||
|
static void copy_entry_to(constantPoolHandle from_cp, int from_i, constantPoolHandle to_cp, int to_i, TRAPS);
|
||||||
int find_matching_entry(int pattern_i, constantPoolHandle search_cp, TRAPS);
|
int find_matching_entry(int pattern_i, constantPoolHandle search_cp, TRAPS);
|
||||||
int orig_length() const { return _orig_length; }
|
int orig_length() const { return _orig_length; }
|
||||||
void set_orig_length(int orig_length) { _orig_length = orig_length; }
|
void set_orig_length(int orig_length) { _orig_length = orig_length; }
|
||||||
|
|
|
@ -1064,7 +1064,8 @@ enum {
|
||||||
JVM_CONSTANT_MethodHandle = 15, // JSR 292
|
JVM_CONSTANT_MethodHandle = 15, // JSR 292
|
||||||
JVM_CONSTANT_MethodType = 16, // JSR 292
|
JVM_CONSTANT_MethodType = 16, // JSR 292
|
||||||
JVM_CONSTANT_InvokeDynamicTrans = 17, // JSR 292, only occurs in old class files
|
JVM_CONSTANT_InvokeDynamicTrans = 17, // JSR 292, only occurs in old class files
|
||||||
JVM_CONSTANT_InvokeDynamic = 18 // JSR 292
|
JVM_CONSTANT_InvokeDynamic = 18, // JSR 292
|
||||||
|
JVM_CONSTANT_ExternalMax = 18 // Last tag found in classfiles
|
||||||
};
|
};
|
||||||
|
|
||||||
/* JVM_CONSTANT_MethodHandle subtypes */
|
/* JVM_CONSTANT_MethodHandle subtypes */
|
||||||
|
|
|
@ -214,7 +214,7 @@ void VM_RedefineClasses::append_entry(constantPoolHandle scratch_cp,
|
||||||
case JVM_CONSTANT_Double: // fall through
|
case JVM_CONSTANT_Double: // fall through
|
||||||
case JVM_CONSTANT_Long:
|
case JVM_CONSTANT_Long:
|
||||||
{
|
{
|
||||||
scratch_cp->copy_entry_to(scratch_i, *merge_cp_p, *merge_cp_length_p,
|
constantPoolOopDesc::copy_entry_to(scratch_cp, scratch_i, *merge_cp_p, *merge_cp_length_p,
|
||||||
THREAD);
|
THREAD);
|
||||||
|
|
||||||
if (scratch_i != *merge_cp_length_p) {
|
if (scratch_i != *merge_cp_length_p) {
|
||||||
|
@ -239,7 +239,7 @@ void VM_RedefineClasses::append_entry(constantPoolHandle scratch_cp,
|
||||||
case JVM_CONSTANT_UnresolvedClass: // fall through
|
case JVM_CONSTANT_UnresolvedClass: // fall through
|
||||||
case JVM_CONSTANT_UnresolvedString:
|
case JVM_CONSTANT_UnresolvedString:
|
||||||
{
|
{
|
||||||
scratch_cp->copy_entry_to(scratch_i, *merge_cp_p, *merge_cp_length_p,
|
constantPoolOopDesc::copy_entry_to(scratch_cp, scratch_i, *merge_cp_p, *merge_cp_length_p,
|
||||||
THREAD);
|
THREAD);
|
||||||
|
|
||||||
if (scratch_i != *merge_cp_length_p) {
|
if (scratch_i != *merge_cp_length_p) {
|
||||||
|
@ -1093,13 +1093,13 @@ bool VM_RedefineClasses::merge_constant_pools(constantPoolHandle old_cp,
|
||||||
case JVM_CONSTANT_Long:
|
case JVM_CONSTANT_Long:
|
||||||
// just copy the entry to *merge_cp_p, but double and long take
|
// just copy the entry to *merge_cp_p, but double and long take
|
||||||
// two constant pool entries
|
// two constant pool entries
|
||||||
old_cp->copy_entry_to(old_i, *merge_cp_p, old_i, CHECK_0);
|
constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0);
|
||||||
old_i++;
|
old_i++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// just copy the entry to *merge_cp_p
|
// just copy the entry to *merge_cp_p
|
||||||
old_cp->copy_entry_to(old_i, *merge_cp_p, old_i, CHECK_0);
|
constantPoolOopDesc::copy_entry_to(old_cp, old_i, *merge_cp_p, old_i, CHECK_0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} // end for each old_cp entry
|
} // end for each old_cp entry
|
||||||
|
|
|
@ -1676,10 +1676,7 @@ static inline uint64_t cast_uint64_t(size_t x)
|
||||||
/* constantPoolOop layout enum for InvokeDynamic */ \
|
/* 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_bsm_offset) \
|
||||||
declare_constant(constantPoolOopDesc::_indy_nt_offset) \
|
|
||||||
declare_constant(constantPoolOopDesc::_indy_argc_offset) \
|
declare_constant(constantPoolOopDesc::_indy_argc_offset) \
|
||||||
declare_constant(constantPoolOopDesc::_indy_argv_offset) \
|
declare_constant(constantPoolOopDesc::_indy_argv_offset) \
|
||||||
\
|
\
|
||||||
|
|
|
@ -93,6 +93,8 @@ const char* constantTag::internal_name() const {
|
||||||
return "MethodType";
|
return "MethodType";
|
||||||
case JVM_CONSTANT_InvokeDynamic :
|
case JVM_CONSTANT_InvokeDynamic :
|
||||||
return "InvokeDynamic";
|
return "InvokeDynamic";
|
||||||
|
case JVM_CONSTANT_InvokeDynamicTrans :
|
||||||
|
return "InvokeDynamic/transitional";
|
||||||
case JVM_CONSTANT_Object :
|
case JVM_CONSTANT_Object :
|
||||||
return "Object";
|
return "Object";
|
||||||
case JVM_CONSTANT_Utf8 :
|
case JVM_CONSTANT_Utf8 :
|
||||||
|
|
|
@ -86,7 +86,8 @@ class constantTag VALUE_OBJ_CLASS_SPEC {
|
||||||
|
|
||||||
bool is_method_type() const { return _tag == JVM_CONSTANT_MethodType; }
|
bool is_method_type() const { return _tag == JVM_CONSTANT_MethodType; }
|
||||||
bool is_method_handle() const { return _tag == JVM_CONSTANT_MethodHandle; }
|
bool is_method_handle() const { return _tag == JVM_CONSTANT_MethodHandle; }
|
||||||
bool is_invoke_dynamic() const { return _tag == JVM_CONSTANT_InvokeDynamic; }
|
bool is_invoke_dynamic() const { return (_tag == JVM_CONSTANT_InvokeDynamic ||
|
||||||
|
_tag == JVM_CONSTANT_InvokeDynamicTrans); }
|
||||||
|
|
||||||
bool is_loadable_constant() const {
|
bool is_loadable_constant() const {
|
||||||
return ((_tag >= JVM_CONSTANT_Integer && _tag <= JVM_CONSTANT_String) ||
|
return ((_tag >= JVM_CONSTANT_Integer && _tag <= JVM_CONSTANT_String) ||
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue