8171392: Move Klass pointers outside of ConstantPool entries so ConstantPool can be read-only

Added _resolved_klasses; moved _resolved_references to ConstantPoolCache, etc.

Reviewed-by: coleenp, lfoltan, simonis, aph
This commit is contained in:
Ioi Lam 2017-03-03 23:08:35 -08:00
parent 0c74ceb12d
commit c386cec7b1
32 changed files with 527 additions and 231 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
@ -270,7 +270,8 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(
get_constant_pool(result); get_constant_pool(result);
// load pointer for resolved_references[] objArray // load pointer for resolved_references[] objArray
ldr(result, Address(result, ConstantPool::resolved_references_offset_in_bytes())); ldr(result, Address(result, ConstantPool::cache_offset_in_bytes()));
ldr(result, Address(result, ConstantPoolCache::resolved_references_offset_in_bytes()));
// JNIHandles::resolve(obj); // JNIHandles::resolve(obj);
ldr(result, Address(result, 0)); ldr(result, Address(result, 0));
// Add in the index // Add in the index
@ -278,6 +279,15 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(
load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
} }
void InterpreterMacroAssembler::load_resolved_klass_at_offset(
Register cpool, Register index, Register klass, Register temp) {
add(temp, cpool, index, LSL, LogBytesPerWord);
ldrh(temp, Address(temp, sizeof(ConstantPool))); // temp = resolved_klass_index
ldr(klass, Address(cpool, ConstantPool::resolved_klasses_offset_in_bytes())); // klass = cpool->_resolved_klasses
add(klass, klass, temp, LSL, LogBytesPerWord);
ldr(klass, Address(klass, Array<Klass*>::base_offset_in_bytes()));
}
// Generate a subtype check: branch to ok_is_subtype if sub_klass is a // Generate a subtype check: branch to ok_is_subtype if sub_klass is a
// subtype of super_klass. // subtype of super_klass.
// //

View file

@ -123,6 +123,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
// load cpool->resolved_references(index); // load cpool->resolved_references(index);
void load_resolved_reference_at_index(Register result, Register index); void load_resolved_reference_at_index(Register result, Register index);
// load cpool->resolved_klass_at(index);
void load_resolved_klass_at_offset(Register cpool, Register index, Register klass, Register temp);
void pop_ptr(Register r = r0); void pop_ptr(Register r = r0);
void pop_i(Register r = r0); void pop_i(Register r = r0);
void pop_l(Register r = r0); void pop_l(Register r = r0);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
@ -3372,8 +3372,7 @@ void TemplateTable::_new() {
__ br(Assembler::NE, slow_case); __ br(Assembler::NE, slow_case);
// get InstanceKlass // get InstanceKlass
__ lea(r4, Address(r4, r3, Address::lsl(3))); __ load_resolved_klass_at_offset(r4, r3, r4, rscratch1);
__ ldr(r4, Address(r4, sizeof(ConstantPool)));
// make sure klass is initialized & doesn't have finalizer // make sure klass is initialized & doesn't have finalizer
// make sure klass is fully initialized // make sure klass is fully initialized
@ -3526,8 +3525,7 @@ void TemplateTable::checkcast()
// Get superklass in r0 and subklass in r3 // Get superklass in r0 and subklass in r3
__ bind(quicked); __ bind(quicked);
__ mov(r3, r0); // Save object in r3; r0 needed for subtype check __ mov(r3, r0); // Save object in r3; r0 needed for subtype check
__ lea(r0, Address(r2, r19, Address::lsl(3))); __ load_resolved_klass_at_offset(r2, r19, r0, rscratch1); // r0 = klass
__ ldr(r0, Address(r0, sizeof(ConstantPool)));
__ bind(resolved); __ bind(resolved);
__ load_klass(r19, r3); __ load_klass(r19, r3);
@ -3583,8 +3581,7 @@ void TemplateTable::instanceof() {
// Get superklass in r0 and subklass in r3 // Get superklass in r0 and subklass in r3
__ bind(quicked); __ bind(quicked);
__ load_klass(r3, r0); __ load_klass(r3, r0);
__ lea(r0, Address(r2, r19, Address::lsl(3))); __ load_resolved_klass_at_offset(r2, r19, r0, rscratch1);
__ ldr(r0, Address(r0, sizeof(ConstantPool)));
__ bind(resolved); __ bind(resolved);

View file

@ -298,7 +298,8 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(
Register cache = result; Register cache = result;
// load pointer for resolved_references[] objArray // load pointer for resolved_references[] objArray
ldr(cache, Address(result, ConstantPool::resolved_references_offset_in_bytes())); ldr(cache, Address(result, ConstantPool::cache_offset_in_bytes()));
ldr(cache, Address(result, ConstantPoolCache::resolved_references_offset_in_bytes()));
// JNIHandles::resolve(result) // JNIHandles::resolve(result)
ldr(cache, Address(cache, 0)); ldr(cache, Address(cache, 0));
// Add in the index // Add in the index
@ -308,6 +309,15 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(
load_heap_oop(result, Address(cache, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); load_heap_oop(result, Address(cache, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
} }
void InterpreterMacroAssembler::load_resolved_klass_at_offset(
Register Rcpool, Register Rindex, Register Rklass) {
add(Rtemp, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord));
ldrh(Rtemp, Address(Rtemp, sizeof(ConstantPool))); // Rtemp = resolved_klass_index
ldr(Rklass, Address(Rcpool, ConstantPool::resolved_klasses_offset_in_bytes())); // Rklass = cpool->_resolved_klasses
add(Rklass, Rklass, AsmOperand(Rtemp, lsl, LogBytesPerWord));
ldr(Rklass, Address(Rklass, Array<Klass*>::base_offset_in_bytes()));
}
// Generate a subtype check: branch to not_subtype if sub_klass is // Generate a subtype check: branch to not_subtype if sub_klass is
// not a subtype of super_klass. // not a subtype of super_klass.
// Profiling code for the subtype check failure (profile_typecheck_failed) // Profiling code for the subtype check failure (profile_typecheck_failed)

View file

@ -141,6 +141,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
// Load object from cpool->resolved_references(*bcp+1) // Load object from cpool->resolved_references(*bcp+1)
void load_resolved_reference_at_index(Register result, Register tmp); void load_resolved_reference_at_index(Register result, Register tmp);
// load cpool->resolved_klass_at(index); Rtemp is corrupted upon return
void load_resolved_klass_at_offset(Register Rcpool, Register Rindex, Register Rklass);
void store_check_part1(Register card_table_base); // Sets card_table_base register. void store_check_part1(Register card_table_base); // Sets card_table_base register.
void store_check_part2(Register obj, Register card_table_base, Register tmp); void store_check_part2(Register obj, Register card_table_base, Register tmp);

View file

@ -4372,10 +4372,9 @@ void TemplateTable::_new() {
#endif // AARCH64 #endif // AARCH64
// get InstanceKlass // get InstanceKlass
__ add(Rklass, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord));
__ ldr(Rklass, Address(Rklass, sizeof(ConstantPool)));
__ cmp(Rtemp, JVM_CONSTANT_Class); __ cmp(Rtemp, JVM_CONSTANT_Class);
__ b(slow_case, ne); __ b(slow_case, ne);
__ load_resolved_klass_at_offset(Rcpool, Rindex, Rklass);
// make sure klass is initialized & doesn't have finalizer // make sure klass is initialized & doesn't have finalizer
// make sure klass is fully initialized // make sure klass is fully initialized
@ -4647,8 +4646,7 @@ void TemplateTable::checkcast() {
// Get superklass in Rsuper and subklass in Rsub // Get superklass in Rsuper and subklass in Rsub
__ bind(quicked); __ bind(quicked);
__ add(Rtemp, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord)); __ load_resolved_klass_at_offset(Rcpool, Rindex, Rsuper);
__ ldr(Rsuper, Address(Rtemp, sizeof(ConstantPool)));
__ bind(resolved); __ bind(resolved);
__ load_klass(Rsub, Robj); __ load_klass(Rsub, Robj);
@ -4721,8 +4719,7 @@ void TemplateTable::instanceof() {
// Get superklass in Rsuper and subklass in Rsub // Get superklass in Rsuper and subklass in Rsub
__ bind(quicked); __ bind(quicked);
__ add(Rtemp, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord)); __ load_resolved_klass_at_offset(Rcpool, Rindex, Rsuper);
__ ldr(Rsuper, Address(Rtemp, sizeof(ConstantPool)));
__ bind(resolved); __ bind(resolved);
__ load_klass(Rsub, Robj); __ load_klass(Rsub, Robj);

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016 SAP SE. All rights reserved. * Copyright (c) 2012, 2017 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -79,6 +79,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
// Load object from cpool->resolved_references(index). // Load object from cpool->resolved_references(index).
void load_resolved_reference_at_index(Register result, Register index, Label *is_null = NULL); void load_resolved_reference_at_index(Register result, Register index, Label *is_null = NULL);
// load cpool->resolved_klass_at(index)
void load_resolved_klass_at_offset(Register Rcpool, Register Roffset, Register Rklass);
void load_receiver(Register Rparam_count, Register Rrecv_dst); void load_receiver(Register Rparam_count, Register Rrecv_dst);
// helpers for expression stack // helpers for expression stack

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016 SAP SE. All rights reserved. * Copyright (c) 2012, 2017 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -454,7 +454,8 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result
Register tmp = index; // reuse Register tmp = index; // reuse
sldi(tmp, index, LogBytesPerHeapOop); sldi(tmp, index, LogBytesPerHeapOop);
// Load pointer for resolved_references[] objArray. // Load pointer for resolved_references[] objArray.
ld(result, ConstantPool::resolved_references_offset_in_bytes(), result); ld(result, ConstantPool::cache_offset_in_bytes(), result);
ld(result, ConstantPoolCache::resolved_references_offset_in_bytes(), result);
// JNIHandles::resolve(result) // JNIHandles::resolve(result)
ld(result, 0, result); ld(result, 0, result);
#ifdef ASSERT #ifdef ASSERT
@ -471,6 +472,25 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result
load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result, is_null); load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result, is_null);
} }
// load cpool->resolved_klass_at(index)
void InterpreterMacroAssembler::load_resolved_klass_at_offset(Register Rcpool, Register Roffset, Register Rklass) {
// int value = *(Rcpool->int_at_addr(which));
// int resolved_klass_index = extract_low_short_from_int(value);
add(Roffset, Rcpool, Roffset);
#if defined(VM_LITTLE_ENDIAN)
lhz(Roffset, sizeof(ConstantPool), Roffset); // Roffset = resolved_klass_index
#else
lhz(Roffset, sizeof(ConstantPool) + 2, Roffset); // Roffset = resolved_klass_index
#endif
ld(Rklass, ConstantPool::resolved_klasses_offset_in_bytes(), Rcpool); // Rklass = Rcpool->_resolved_klasses
sldi(Roffset, Roffset, LogBytesPerWord);
addi(Roffset, Roffset, Array<Klass*>::base_offset_in_bytes());
isync(); // Order load of instance Klass wrt. tags.
ldx(Rklass, Rklass, Roffset);
}
// Generate a subtype check: branch to ok_is_subtype if sub_klass is // Generate a subtype check: branch to ok_is_subtype if sub_klass is
// a subtype of super_klass. Blows registers Rsub_klass, tmp1, tmp2. // a subtype of super_klass. Blows registers Rsub_klass, tmp1, tmp2.
void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, Register Rsuper_klass, Register Rtmp1, void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, Register Rsuper_klass, Register Rtmp1,

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2016 SAP SE. All rights reserved. * Copyright (c) 2013, 2017 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -3660,11 +3660,9 @@ void TemplateTable::_new() {
__ cmpdi(CCR0, Rtags, JVM_CONSTANT_Class); __ cmpdi(CCR0, Rtags, JVM_CONSTANT_Class);
__ bne(CCR0, Lslow_case); __ bne(CCR0, Lslow_case);
// Get instanceKlass (load from Rcpool + sizeof(ConstantPool) + Rindex*BytesPerWord). // Get instanceKlass
__ sldi(Roffset, Rindex, LogBytesPerWord); __ sldi(Roffset, Rindex, LogBytesPerWord);
__ addi(Rscratch, Rcpool, sizeof(ConstantPool)); __ load_resolved_klass_at_offset(Rcpool, Roffset, RinstanceKlass);
__ isync(); // Order load of instance Klass wrt. tags.
__ ldx(RinstanceKlass, Roffset, Rscratch);
// Make sure klass is fully initialized and get instance_size. // Make sure klass is fully initialized and get instance_size.
__ lbz(Rscratch, in_bytes(InstanceKlass::init_state_offset()), RinstanceKlass); __ lbz(Rscratch, in_bytes(InstanceKlass::init_state_offset()), RinstanceKlass);
@ -3875,9 +3873,7 @@ void TemplateTable::checkcast() {
// Extract target class from constant pool. // Extract target class from constant pool.
__ bind(Lquicked); __ bind(Lquicked);
__ sldi(Roffset, Roffset, LogBytesPerWord); __ sldi(Roffset, Roffset, LogBytesPerWord);
__ addi(Rcpool, Rcpool, sizeof(ConstantPool)); __ load_resolved_klass_at_offset(Rcpool, Roffset, RspecifiedKlass);
__ isync(); // Order load of specified Klass wrt. tags.
__ ldx(RspecifiedKlass, Rcpool, Roffset);
// Do the checkcast. // Do the checkcast.
__ bind(Lresolved); __ bind(Lresolved);
@ -3939,9 +3935,7 @@ void TemplateTable::instanceof() {
// Extract target class from constant pool. // Extract target class from constant pool.
__ bind(Lquicked); __ bind(Lquicked);
__ sldi(Roffset, Roffset, LogBytesPerWord); __ sldi(Roffset, Roffset, LogBytesPerWord);
__ addi(Rcpool, Rcpool, sizeof(ConstantPool)); __ load_resolved_klass_at_offset(Rcpool, Roffset, RspecifiedKlass);
__ isync(); // Order load of specified Klass wrt. tags.
__ ldx(RspecifiedKlass, Rcpool, Roffset);
// Do the checkcast. // Do the checkcast.
__ bind(Lresolved); __ bind(Lresolved);

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved. * Copyright (c) 2016, 2017 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -371,7 +371,8 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result
Register tmp = index; // reuse Register tmp = index; // reuse
z_sllg(index, index, LogBytesPerHeapOop); // Offset into resolved references array. z_sllg(index, index, LogBytesPerHeapOop); // Offset into resolved references array.
// Load pointer for resolved_references[] objArray. // Load pointer for resolved_references[] objArray.
z_lg(result, ConstantPool::resolved_references_offset_in_bytes(), result); z_lg(result, ConstantPool::cache_offset_in_bytes(), result);
z_lg(result, ConstantPoolCache::resolved_references_offset_in_bytes(), result);
// JNIHandles::resolve(result) // JNIHandles::resolve(result)
z_lg(result, 0, result); // Load resolved references array itself. z_lg(result, 0, result); // Load resolved references array itself.
#ifdef ASSERT #ifdef ASSERT
@ -386,6 +387,16 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result
load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result); load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result);
} }
// load cpool->resolved_klass_at(index)
void InterpreterMacroAssembler::load_resolved_klass_at_offset(Register cpool, Register offset, Register iklass) {
// int value = *(Rcpool->int_at_addr(which));
// int resolved_klass_index = extract_low_short_from_int(value);
z_llgh(offset, Address(cpool, offset, sizeof(ConstantPool) + 2)); // offset = resolved_klass_index (s390 is big-endian)
z_sllg(offset, offset, LogBytesPerWord); // Convert 'index' to 'offset'
z_lg(iklass, Address(cpool, ConstantPool::resolved_klasses_offset_in_bytes())); // iklass = cpool->_resolved_klasses
z_lg(iklass, Address(iklass, offset, Array<Klass*>::base_offset_in_bytes()));
}
void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache,
Register tmp, Register tmp,
int bcp_offset, int bcp_offset,

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved. * Copyright (c) 2016, 2017 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -115,6 +115,8 @@ class InterpreterMacroAssembler: public MacroAssembler {
void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2)); void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2));
void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2)); void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2));
void load_resolved_reference_at_index(Register result, Register index); void load_resolved_reference_at_index(Register result, Register index);
// load cpool->resolved_klass_at(index)
void load_resolved_klass_at_offset(Register cpool, Register offset, Register iklass);
// Pop topmost element from stack. It just disappears. Useful if // Pop topmost element from stack. It just disappears. Useful if
// consumed previously by access via stackTop(). // consumed previously by access via stackTop().

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved. * Copyright (c) 2016, 2017 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -3708,7 +3708,7 @@ void TemplateTable::_new() {
__ z_sllg(offset, offset, LogBytesPerWord); // Convert to to offset. __ z_sllg(offset, offset, LogBytesPerWord); // Convert to to offset.
// Get InstanceKlass. // Get InstanceKlass.
Register iklass = cpool; Register iklass = cpool;
__ z_lg(iklass, Address(cpool, offset, sizeof(ConstantPool))); __ load_resolved_klass_at_offset(cpool, offset, iklass);
// Make sure klass is initialized & doesn't have finalizer. // Make sure klass is initialized & doesn't have finalizer.
// Make sure klass is fully initialized. // Make sure klass is fully initialized.
@ -3895,7 +3895,7 @@ void TemplateTable::checkcast() {
__ z_lgr(Z_ARG4, Z_tos); // Save receiver. __ z_lgr(Z_ARG4, Z_tos); // Save receiver.
__ z_sllg(index, index, LogBytesPerWord); // index2bytes for addressing __ z_sllg(index, index, LogBytesPerWord); // index2bytes for addressing
__ mem2reg_opt(klass, Address(cpool, index, sizeof(ConstantPool))); __ load_resolved_klass_at_offset(cpool, index, klass);
__ bind(resolved); __ bind(resolved);
@ -3969,8 +3969,7 @@ void TemplateTable::instanceof() {
__ load_klass(subklass, Z_tos); __ load_klass(subklass, Z_tos);
__ z_sllg(index, index, LogBytesPerWord); // index2bytes for addressing __ z_sllg(index, index, LogBytesPerWord); // index2bytes for addressing
__ mem2reg_opt(klass, __ load_resolved_klass_at_offset(cpool, index, klass);
Address(cpool, index, sizeof(ConstantPool)));
__ bind(resolved); __ bind(resolved);

View file

@ -755,7 +755,8 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(
sll(index, LogBytesPerHeapOop, tmp); sll(index, LogBytesPerHeapOop, tmp);
get_constant_pool(result); get_constant_pool(result);
// load pointer for resolved_references[] objArray // load pointer for resolved_references[] objArray
ld_ptr(result, ConstantPool::resolved_references_offset_in_bytes(), result); ld_ptr(result, ConstantPool::cache_offset_in_bytes(), result);
ld_ptr(result, ConstantPoolCache::resolved_references_offset_in_bytes(), result);
// JNIHandles::resolve(result) // JNIHandles::resolve(result)
ld_ptr(result, 0, result); ld_ptr(result, 0, result);
// Add in the index // Add in the index
@ -764,6 +765,24 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(
} }
// load cpool->resolved_klass_at(index)
void InterpreterMacroAssembler::load_resolved_klass_at_offset(Register Rcpool,
Register Roffset, Register Rklass) {
// int value = *this_cp->int_at_addr(which);
// int resolved_klass_index = extract_low_short_from_int(value);
//
// Because SPARC is big-endian, the low_short is at (cpool->int_at_addr(which) + 2 bytes)
add(Roffset, Rcpool, Roffset);
lduh(Roffset, sizeof(ConstantPool) + 2, Roffset); // Roffset = resolved_klass_index
Register Rresolved_klasses = Rklass;
ld_ptr(Rcpool, ConstantPool::resolved_klasses_offset_in_bytes(), Rresolved_klasses);
sll(Roffset, LogBytesPerWord, Roffset);
add(Roffset, Array<Klass*>::base_offset_in_bytes(), Roffset);
ld_ptr(Rresolved_klasses, Roffset, Rklass);
}
// Generate a subtype check: branch to ok_is_subtype if sub_klass is // Generate a subtype check: branch to ok_is_subtype if sub_klass is
// a subtype of super_klass. Blows registers Rsuper_klass, Rsub_klass, tmp1, tmp2. // a subtype of super_klass. Blows registers Rsuper_klass, Rsub_klass, tmp1, tmp2.
void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass,

View file

@ -196,6 +196,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
// load cpool->resolved_references(index); // load cpool->resolved_references(index);
void load_resolved_reference_at_index(Register result, Register index); void load_resolved_reference_at_index(Register result, Register index);
// load cpool->resolved_klass_at(index)
void load_resolved_klass_at_offset(Register Rcpool, Register Roffset, Register Rklass);
// common code // common code
void field_offset_at(int n, Register tmp, Register dest, Register base); void field_offset_at(int n, Register tmp, Register dest, Register base);

View file

@ -3241,9 +3241,7 @@ void TemplateTable::_new() {
__ br(Assembler::notEqual, false, Assembler::pn, slow_case); __ br(Assembler::notEqual, false, Assembler::pn, slow_case);
__ delayed()->sll(Roffset, LogBytesPerWord, Roffset); __ delayed()->sll(Roffset, LogBytesPerWord, Roffset);
// get InstanceKlass // get InstanceKlass
//__ sll(Roffset, LogBytesPerWord, Roffset); // executed in delay slot __ load_resolved_klass_at_offset(Rscratch, Roffset, RinstanceKlass);
__ add(Roffset, sizeof(ConstantPool), Roffset);
__ ld_ptr(Rscratch, Roffset, RinstanceKlass);
// make sure klass is fully initialized: // make sure klass is fully initialized:
__ ldub(RinstanceKlass, in_bytes(InstanceKlass::init_state_offset()), G3_scratch); __ ldub(RinstanceKlass, in_bytes(InstanceKlass::init_state_offset()), G3_scratch);
@ -3465,8 +3463,9 @@ void TemplateTable::checkcast() {
// Extract target class from constant pool // Extract target class from constant pool
__ bind(quicked); __ bind(quicked);
__ add(Roffset, sizeof(ConstantPool), Roffset); __ load_resolved_klass_at_offset(Lscratch, Roffset, RspecifiedKlass);
__ ld_ptr(Lscratch, Roffset, RspecifiedKlass);
__ bind(resolved); __ bind(resolved);
__ load_klass(Otos_i, RobjKlass); // get value klass __ load_klass(Otos_i, RobjKlass); // get value klass
@ -3522,9 +3521,9 @@ void TemplateTable::instanceof() {
// Extract target class from constant pool // Extract target class from constant pool
__ bind(quicked); __ bind(quicked);
__ add(Roffset, sizeof(ConstantPool), Roffset);
__ get_constant_pool(Lscratch); __ get_constant_pool(Lscratch);
__ ld_ptr(Lscratch, Roffset, RspecifiedKlass); __ load_resolved_klass_at_offset(Lscratch, Roffset, RspecifiedKlass);
__ bind(resolved); __ bind(resolved);
__ load_klass(Otos_i, RobjKlass); // get value klass __ load_klass(Otos_i, RobjKlass); // get value klass

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -509,7 +509,8 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(
get_constant_pool(result); get_constant_pool(result);
// load pointer for resolved_references[] objArray // load pointer for resolved_references[] objArray
movptr(result, Address(result, ConstantPool::resolved_references_offset_in_bytes())); movptr(result, Address(result, ConstantPool::cache_offset_in_bytes()));
movptr(result, Address(result, ConstantPoolCache::resolved_references_offset_in_bytes()));
// JNIHandles::resolve(obj); // JNIHandles::resolve(obj);
movptr(result, Address(result, 0)); movptr(result, Address(result, 0));
// Add in the index // Add in the index
@ -517,6 +518,14 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(
load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
} }
// load cpool->resolved_klass_at(index)
void InterpreterMacroAssembler::load_resolved_klass_at_index(Register cpool,
Register index, Register klass) {
movw(index, Address(cpool, index, Address::times_ptr, sizeof(ConstantPool)));
Register resolved_klasses = cpool;
movptr(resolved_klasses, Address(cpool, ConstantPool::resolved_klasses_offset_in_bytes()));
movptr(klass, Address(resolved_klasses, index, Address::times_ptr, Array<Klass*>::base_offset_in_bytes()));
}
// Generate a subtype check: branch to ok_is_subtype if sub_klass is a // Generate a subtype check: branch to ok_is_subtype if sub_klass is a
// subtype of super_klass. // subtype of super_klass.

View file

@ -123,6 +123,11 @@ class InterpreterMacroAssembler: public MacroAssembler {
// load cpool->resolved_references(index); // load cpool->resolved_references(index);
void load_resolved_reference_at_index(Register result, Register index); void load_resolved_reference_at_index(Register result, Register index);
// load cpool->resolved_klass_at(index)
void load_resolved_klass_at_index(Register cpool, // the constant pool (corrupted on return)
Register index, // the constant pool index (corrupted on return)
Register klass); // contains the Klass on return
NOT_LP64(void f2ieee();) // truncate ftos to 32bits NOT_LP64(void f2ieee();) // truncate ftos to 32bits
NOT_LP64(void d2ieee();) // truncate dtos to 64bits NOT_LP64(void d2ieee();) // truncate dtos to 64bits

View file

@ -3846,7 +3846,7 @@ void TemplateTable::_new() {
__ jcc(Assembler::notEqual, slow_case_no_pop); __ jcc(Assembler::notEqual, slow_case_no_pop);
// get InstanceKlass // get InstanceKlass
__ movptr(rcx, Address(rcx, rdx, Address::times_ptr, sizeof(ConstantPool))); __ load_resolved_klass_at_index(rcx, rdx, rcx);
__ push(rcx); // save the contexts of klass for initializing the header __ push(rcx); // save the contexts of klass for initializing the header
// make sure klass is initialized & doesn't have finalizer // make sure klass is initialized & doesn't have finalizer
@ -4061,8 +4061,7 @@ void TemplateTable::checkcast() {
// Get superklass in rax and subklass in rbx // Get superklass in rax and subklass in rbx
__ bind(quicked); __ bind(quicked);
__ mov(rdx, rax); // Save object in rdx; rax needed for subtype check __ mov(rdx, rax); // Save object in rdx; rax needed for subtype check
__ movptr(rax, Address(rcx, rbx, __ load_resolved_klass_at_index(rcx, rbx, rax);
Address::times_ptr, sizeof(ConstantPool)));
__ bind(resolved); __ bind(resolved);
__ load_klass(rbx, rdx); __ load_klass(rbx, rdx);
@ -4128,8 +4127,7 @@ void TemplateTable::instanceof() {
// Get superklass in rax and subklass in rdx // Get superklass in rax and subklass in rdx
__ bind(quicked); __ bind(quicked);
__ load_klass(rdx, rax); __ load_klass(rdx, rax);
__ movptr(rax, Address(rcx, rbx, __ load_resolved_klass_at_index(rcx, rbx, rax);
Address::times_ptr, sizeof(ConstantPool)));
__ bind(resolved); __ bind(resolved);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -84,8 +84,6 @@ public class ConstantPool extends Metadata implements ClassConstants {
cache = type.getAddressField("_cache"); cache = type.getAddressField("_cache");
poolHolder = new MetadataField(type.getAddressField("_pool_holder"), 0); poolHolder = new MetadataField(type.getAddressField("_pool_holder"), 0);
length = new CIntField(type.getCIntegerField("_length"), 0); length = new CIntField(type.getCIntegerField("_length"), 0);
resolvedReferences = type.getAddressField("_resolved_references");
referenceMap = type.getAddressField("_reference_map");
headerSize = type.getSize(); headerSize = type.getSize();
elementSize = 0; elementSize = 0;
// fetch constants: // fetch constants:
@ -105,8 +103,6 @@ public class ConstantPool extends Metadata implements ClassConstants {
private static AddressField cache; private static AddressField cache;
private static MetadataField poolHolder; private static MetadataField poolHolder;
private static CIntField length; // number of elements in oop private static CIntField length; // number of elements in oop
private static AddressField resolvedReferences;
private static AddressField referenceMap;
private static long headerSize; private static long headerSize;
private static long elementSize; private static long elementSize;
@ -124,17 +120,11 @@ public class ConstantPool extends Metadata implements ClassConstants {
public InstanceKlass getPoolHolder() { return (InstanceKlass)poolHolder.getValue(this); } public InstanceKlass getPoolHolder() { return (InstanceKlass)poolHolder.getValue(this); }
public int getLength() { return (int)length.getValue(getAddress()); } public int getLength() { return (int)length.getValue(getAddress()); }
public Oop getResolvedReferences() { public Oop getResolvedReferences() {
Address handle = resolvedReferences.getValue(getAddress()); return getCache().getResolvedReferences();
if (handle != null) {
// Load through the handle
OopHandle refs = handle.getOopHandleAt(0);
return VM.getVM().getObjectHeap().newOop(refs);
}
return null;
} }
public U2Array referenceMap() { public U2Array referenceMap() {
return new U2Array(referenceMap.getValue(getAddress())); return getCache().referenceMap();
} }
public int objectToCPIndex(int index) { public int objectToCPIndex(int index) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -51,6 +51,8 @@ public class ConstantPoolCache extends Metadata {
elementSize = elType.getSize(); elementSize = elType.getSize();
length = new CIntField(type.getCIntegerField("_length"), 0); length = new CIntField(type.getCIntegerField("_length"), 0);
intSize = VM.getVM().getObjectHeap().getIntSize(); intSize = VM.getVM().getObjectHeap().getIntSize();
resolvedReferences = type.getAddressField("_resolved_references");
referenceMap = type.getAddressField("_reference_map");
} }
public ConstantPoolCache(Address addr) { public ConstantPoolCache(Address addr) {
@ -65,7 +67,8 @@ public class ConstantPoolCache extends Metadata {
private static long elementSize; private static long elementSize;
private static CIntField length; private static CIntField length;
private static long intSize; private static long intSize;
private static AddressField resolvedReferences;
private static AddressField referenceMap;
public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); } public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); }
@ -100,4 +103,18 @@ public class ConstantPoolCache extends Metadata {
entry.iterateFields(visitor); entry.iterateFields(visitor);
} }
} }
public Oop getResolvedReferences() {
Address handle = resolvedReferences.getValue(getAddress());
if (handle != null) {
// Load through the handle
OopHandle refs = handle.getOopHandleAt(0);
return VM.getVM().getObjectHeap().newOop(refs);
}
return null;
}
public U2Array referenceMap() {
return new U2Array(referenceMap.getValue(getAddress()));
}
}; };

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -64,8 +64,8 @@ ConstantPool* BytecodeConstantPool::create_constant_pool(TRAPS) const {
cp->symbol_at_put(idx, entry._u.utf8); cp->symbol_at_put(idx, entry._u.utf8);
break; break;
case BytecodeCPEntry::KLASS: case BytecodeCPEntry::KLASS:
cp->unresolved_klass_at_put( cp->klass_index_at_put(
idx, cp->symbol_at(entry._u.klass)); idx, entry._u.klass);
break; break;
case BytecodeCPEntry::STRING: case BytecodeCPEntry::STRING:
cp->unresolved_string_at_put( cp->unresolved_string_at_put(
@ -85,6 +85,9 @@ ConstantPool* BytecodeConstantPool::create_constant_pool(TRAPS) const {
ShouldNotReachHere(); ShouldNotReachHere();
} }
} }
cp->initialize_unresolved_klasses(_orig->pool_holder()->class_loader_data(),
CHECK_NULL);
return cp; return cp;
} }

View file

@ -391,6 +391,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
} }
int index = 1; // declared outside of loops for portability int index = 1; // declared outside of loops for portability
int num_klasses = 0;
// first verification pass - validate cross references // first verification pass - validate cross references
// and fixup class and string constants // and fixup class and string constants
@ -459,7 +460,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
check_property(valid_symbol_at(class_index), check_property(valid_symbol_at(class_index),
"Invalid constant pool index %u in class file %s", "Invalid constant pool index %u in class file %s",
class_index, CHECK); class_index, CHECK);
cp->unresolved_klass_at_put(index, cp->symbol_at(class_index)); cp->unresolved_klass_at_put(index, class_index, num_klasses++);
break; break;
} }
case JVM_CONSTANT_StringIndex: { case JVM_CONSTANT_StringIndex: {
@ -550,8 +551,19 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
} // switch(tag) } // switch(tag)
} // end of for } // end of for
_first_patched_klass_resolved_index = num_klasses;
cp->allocate_resolved_klasses(_loader_data, num_klasses + _max_num_patched_klasses, CHECK);
if (_cp_patches != NULL) { if (_cp_patches != NULL) {
// need to treat this_class specially... // need to treat this_class specially...
// Add dummy utf8 entries in the space reserved for names of patched classes. We'll use "*"
// for now. These will be replaced with actual names of the patched classes in patch_class().
Symbol* s = vmSymbols::star_name();
for (int n=_orig_cp_size; n<cp->length(); n++) {
cp->symbol_at_put(n, s);
}
int this_class_index; int this_class_index;
{ {
stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len
@ -701,6 +713,14 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
} // end of for } // end of for
} }
void ClassFileParser::patch_class(ConstantPool* cp, int class_index, Klass* k, Symbol* name) {
int name_index = _orig_cp_size + _num_patched_klasses;
int resolved_klass_index = _first_patched_klass_resolved_index + _num_patched_klasses;
cp->klass_at_put(class_index, name_index, resolved_klass_index, k, name);
_num_patched_klasses ++;
}
void ClassFileParser::patch_constant_pool(ConstantPool* cp, void ClassFileParser::patch_constant_pool(ConstantPool* cp,
int index, int index,
Handle patch, Handle patch,
@ -718,13 +738,14 @@ void ClassFileParser::patch_constant_pool(ConstantPool* cp,
guarantee_property(!java_lang_Class::is_primitive(patch()), guarantee_property(!java_lang_Class::is_primitive(patch()),
"Illegal class patch at %d in class file %s", "Illegal class patch at %d in class file %s",
index, CHECK); index, CHECK);
cp->klass_at_put(index, java_lang_Class::as_Klass(patch())); Klass* k = java_lang_Class::as_Klass(patch());
patch_class(cp, index, k, k->name());
} else { } else {
guarantee_property(java_lang_String::is_instance(patch()), guarantee_property(java_lang_String::is_instance(patch()),
"Illegal class patch at %d in class file %s", "Illegal class patch at %d in class file %s",
index, CHECK); index, CHECK);
Symbol* const name = java_lang_String::as_symbol(patch(), CHECK); Symbol* const name = java_lang_String::as_symbol(patch(), CHECK);
cp->unresolved_klass_at_put(index, name); patch_class(cp, index, NULL, name);
} }
break; break;
} }
@ -5340,8 +5361,14 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
ik->set_name(_class_name); ik->set_name(_class_name);
if (is_anonymous()) { if (is_anonymous()) {
// I am well known to myself // _this_class_index is a CONSTANT_Class entry that refers to this
ik->constants()->klass_at_put(_this_class_index, ik); // eagerly resolve // anonymous class itself. If this class needs to refer to its own methods or
// fields, it would use a CONSTANT_MethodRef, etc, which would reference
// _this_class_index. However, because this class is anonymous (it's
// not stored in SystemDictionary), _this_class_index cannot be resolved
// with ConstantPool::klass_at_impl, which does a SystemDictionary lookup.
// Therefore, we must eagerly resolve _this_class_index now.
ik->constants()->klass_at_put(_this_class_index, ik);
} }
ik->set_minor_version(_minor_version); ik->set_minor_version(_minor_version);
@ -5577,6 +5604,10 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_loader_data(loader_data), _loader_data(loader_data),
_host_klass(host_klass), _host_klass(host_klass),
_cp_patches(cp_patches), _cp_patches(cp_patches),
_num_patched_klasses(0),
_max_num_patched_klasses(0),
_orig_cp_size(0),
_first_patched_klass_resolved_index(0),
_super_klass(), _super_klass(),
_cp(NULL), _cp(NULL),
_fields(NULL), _fields(NULL),
@ -5647,6 +5678,25 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_need_verify = Verifier::should_verify_for(_loader_data->class_loader(), _need_verify = Verifier::should_verify_for(_loader_data->class_loader(),
stream->need_verify()); stream->need_verify());
} }
if (_cp_patches != NULL) {
int len = _cp_patches->length();
for (int i=0; i<len; i++) {
if (has_cp_patch_at(i)) {
Handle patch = cp_patch_at(i);
if (java_lang_String::is_instance(patch()) || java_lang_Class::is_instance(patch())) {
// We need to append the names of the patched classes to the end of the constant pool,
// because a patched class may have a Utf8 name that's not already included in the
// original constant pool. These class names are used when patch_constant_pool()
// calls patch_class().
//
// Note that a String in cp_patch_at(i) may be used to patch a Utf8, a String, or a Class.
// At this point, we don't know the tag for index i yet, because we haven't parsed the
// constant pool. So we can only assume the worst -- every String is used to patch a Class.
_max_num_patched_klasses++;
}
}
}
}
// synch back verification state to stream // synch back verification state to stream
stream->set_verify(_need_verify); stream->set_verify(_need_verify);
@ -5776,19 +5826,25 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
} }
stream->guarantee_more(3, CHECK); // length, first cp tag stream->guarantee_more(3, CHECK); // length, first cp tag
const u2 cp_size = stream->get_u2_fast(); u2 cp_size = stream->get_u2_fast();
guarantee_property( guarantee_property(
cp_size >= 1, "Illegal constant pool size %u in class file %s", cp_size >= 1, "Illegal constant pool size %u in class file %s",
cp_size, CHECK); cp_size, CHECK);
_orig_cp_size = cp_size;
if (int(cp_size) + _max_num_patched_klasses > 0xffff) {
THROW_MSG(vmSymbols::java_lang_InternalError(), "not enough space for patched classes");
}
cp_size += _max_num_patched_klasses;
_cp = ConstantPool::allocate(_loader_data, _cp = ConstantPool::allocate(_loader_data,
cp_size, cp_size,
CHECK); CHECK);
ConstantPool* const cp = _cp; ConstantPool* const cp = _cp;
parse_constant_pool(stream, cp, cp_size, CHECK); parse_constant_pool(stream, cp, _orig_cp_size, CHECK);
assert(cp_size == (const u2)cp->length(), "invariant"); assert(cp_size == (const u2)cp->length(), "invariant");

View file

@ -81,6 +81,10 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
mutable ClassLoaderData* _loader_data; mutable ClassLoaderData* _loader_data;
const InstanceKlass* _host_klass; const InstanceKlass* _host_klass;
GrowableArray<Handle>* _cp_patches; // overrides for CP entries GrowableArray<Handle>* _cp_patches; // overrides for CP entries
int _num_patched_klasses;
int _max_num_patched_klasses;
int _orig_cp_size;
int _first_patched_klass_resolved_index;
// Metadata created before the instance klass is created. Must be deallocated // Metadata created before the instance klass is created. Must be deallocated
// if not transferred to the InstanceKlass upon successful class loading // if not transferred to the InstanceKlass upon successful class loading
@ -434,6 +438,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
return patch; return patch;
} }
void patch_class(ConstantPool* cp, int class_index, Klass* k, Symbol* name);
void patch_constant_pool(ConstantPool* cp, void patch_constant_pool(ConstantPool* cp,
int index, int index,
Handle patch, Handle patch,

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -2168,7 +2168,7 @@ run:
ConstantPool* constants = istate->method()->constants(); ConstantPool* constants = istate->method()->constants();
if (!constants->tag_at(index).is_unresolved_klass()) { if (!constants->tag_at(index).is_unresolved_klass()) {
// Make sure klass is initialized and doesn't have a finalizer // Make sure klass is initialized and doesn't have a finalizer
Klass* entry = constants->slot_at(index).get_klass(); Klass* entry = constants->resolved_klass_at(index);
InstanceKlass* ik = InstanceKlass::cast(entry); InstanceKlass* ik = InstanceKlass::cast(entry);
if (ik->is_initialized() && ik->can_be_fastpath_allocated() ) { if (ik->is_initialized() && ik->can_be_fastpath_allocated() ) {
size_t obj_size = ik->size_helper(); size_t obj_size = ik->size_helper();
@ -2268,7 +2268,7 @@ run:
if (METHOD->constants()->tag_at(index).is_unresolved_klass()) { if (METHOD->constants()->tag_at(index).is_unresolved_klass()) {
CALL_VM(InterpreterRuntime::quicken_io_cc(THREAD), handle_exception); CALL_VM(InterpreterRuntime::quicken_io_cc(THREAD), handle_exception);
} }
Klass* klassOf = (Klass*) METHOD->constants()->slot_at(index).get_klass(); Klass* klassOf = (Klass*) METHOD->constants()->resolved_klass_at(index);
Klass* objKlass = STACK_OBJECT(-1)->klass(); // ebx Klass* objKlass = STACK_OBJECT(-1)->klass(); // ebx
// //
// Check for compatibilty. This check must not GC!! // Check for compatibilty. This check must not GC!!
@ -2303,7 +2303,7 @@ run:
if (METHOD->constants()->tag_at(index).is_unresolved_klass()) { if (METHOD->constants()->tag_at(index).is_unresolved_klass()) {
CALL_VM(InterpreterRuntime::quicken_io_cc(THREAD), handle_exception); CALL_VM(InterpreterRuntime::quicken_io_cc(THREAD), handle_exception);
} }
Klass* klassOf = (Klass*) METHOD->constants()->slot_at(index).get_klass(); Klass* klassOf = (Klass*) METHOD->constants()->resolved_klass_at(index);
Klass* objKlass = STACK_OBJECT(-1)->klass(); Klass* objKlass = STACK_OBJECT(-1)->klass();
// //
// Check for compatibilty. This check must not GC!! // Check for compatibilty. This check must not GC!!

View file

@ -94,11 +94,14 @@ void Rewriter::make_constant_pool_cache(TRAPS) {
_invokedynamic_references_map, CHECK); _invokedynamic_references_map, CHECK);
// initialize object cache in constant pool // initialize object cache in constant pool
_pool->set_cache(cache);
cache->set_constant_pool(_pool());
// _resolved_references is stored in pool->cache(), so need to be done after
// the above lines.
_pool->initialize_resolved_references(loader_data, _resolved_references_map, _pool->initialize_resolved_references(loader_data, _resolved_references_map,
_resolved_reference_limit, _resolved_reference_limit,
CHECK); CHECK);
_pool->set_cache(cache);
cache->set_constant_pool(_pool());
} }

View file

@ -35,8 +35,8 @@
#define DEFAULT_SHARED_READ_WRITE_SIZE (NOT_LP64(6*M) LP64_ONLY(10*M)) #define DEFAULT_SHARED_READ_WRITE_SIZE (NOT_LP64(6*M) LP64_ONLY(10*M))
#define MIN_SHARED_READ_WRITE_SIZE (NOT_LP64(6*M) LP64_ONLY(10*M)) #define MIN_SHARED_READ_WRITE_SIZE (NOT_LP64(6*M) LP64_ONLY(10*M))
#define DEFAULT_SHARED_READ_ONLY_SIZE (NOT_LP64(6*M) LP64_ONLY(10*M)) #define DEFAULT_SHARED_READ_ONLY_SIZE (NOT_LP64(8*M) LP64_ONLY(13*M))
#define MIN_SHARED_READ_ONLY_SIZE (NOT_LP64(6*M) LP64_ONLY(10*M)) #define MIN_SHARED_READ_ONLY_SIZE (NOT_LP64(8*M) LP64_ONLY(13*M))
// the MIN_SHARED_MISC_DATA_SIZE and MIN_SHARED_MISC_CODE_SIZE estimates are based on // the MIN_SHARED_MISC_DATA_SIZE and MIN_SHARED_MISC_CODE_SIZE estimates are based on
// the sizes required for dumping the archive using the default classlist. The sizes // the sizes required for dumping the archive using the default classlist. The sizes
@ -61,8 +61,8 @@
#define LargeSharedArchiveSize (300*M) #define LargeSharedArchiveSize (300*M)
#define HugeSharedArchiveSize (800*M) #define HugeSharedArchiveSize (800*M)
#define ReadOnlyRegionPercentage 0.4 #define ReadOnlyRegionPercentage 0.52
#define ReadWriteRegionPercentage 0.55 #define ReadWriteRegionPercentage 0.43
#define MiscDataRegionPercentage 0.03 #define MiscDataRegionPercentage 0.03
#define MiscCodeRegionPercentage 0.02 #define MiscCodeRegionPercentage 0.02
#define LargeThresholdClassCount 5000 #define LargeThresholdClassCount 5000

View file

@ -47,18 +47,9 @@
#include "utilities/copy.hpp" #include "utilities/copy.hpp"
ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) { ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) {
// Tags are RW but comment below applies to tags also.
Array<u1>* tags = MetadataFactory::new_writeable_array<u1>(loader_data, length, 0, CHECK_NULL); Array<u1>* tags = MetadataFactory::new_writeable_array<u1>(loader_data, length, 0, CHECK_NULL);
int size = ConstantPool::size(length); int size = ConstantPool::size(length);
return new (loader_data, size, true, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags);
// CDS considerations:
// Allocate read-write but may be able to move to read-only at dumping time
// if all the klasses are resolved. The only other field that is writable is
// the resolved_references array, which is recreated at startup time.
// But that could be moved to InstanceKlass (although a pain to access from
// assembly code). Maybe it could be moved to the cpCache which is RW.
return new (loader_data, size, false, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags);
} }
#ifdef ASSERT #ifdef ASSERT
@ -80,22 +71,26 @@ static bool tag_array_is_zero_initialized(Array<u1>* tags) {
ConstantPool::ConstantPool(Array<u1>* tags) : ConstantPool::ConstantPool(Array<u1>* tags) :
_tags(tags), _tags(tags),
_length(tags->length()), _length(tags->length()) {
_flags(0) {
assert(_tags != NULL, "invariant"); assert(_tags != NULL, "invariant");
assert(tags->length() == _length, "invariant"); assert(tags->length() == _length, "invariant");
assert(tag_array_is_zero_initialized(tags), "invariant"); assert(tag_array_is_zero_initialized(tags), "invariant");
assert(0 == _flags, "invariant"); assert(0 == flags(), "invariant");
assert(0 == version(), "invariant"); assert(0 == version(), "invariant");
assert(NULL == _pool_holder, "invariant"); assert(NULL == _pool_holder, "invariant");
} }
void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) { void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) {
MetadataFactory::free_metadata(loader_data, cache()); if (cache() != NULL) {
set_cache(NULL);
MetadataFactory::free_array<u2>(loader_data, reference_map()); MetadataFactory::free_array<u2>(loader_data, reference_map());
set_reference_map(NULL); set_reference_map(NULL);
MetadataFactory::free_metadata(loader_data, cache());
set_cache(NULL);
}
MetadataFactory::free_array<Klass*>(loader_data, resolved_klasses());
set_resolved_klasses(NULL);
MetadataFactory::free_array<jushort>(loader_data, operands()); MetadataFactory::free_array<jushort>(loader_data, operands());
set_operands(NULL); set_operands(NULL);
@ -113,7 +108,7 @@ void ConstantPool::release_C_heap_structures() {
} }
objArrayOop ConstantPool::resolved_references() const { objArrayOop ConstantPool::resolved_references() const {
return (objArrayOop)JNIHandles::resolve(_resolved_references); return (objArrayOop)JNIHandles::resolve(_cache->resolved_references());
} }
// Create resolved_references array and mapping array for original cp indexes // Create resolved_references array and mapping array for original cp indexes
@ -150,9 +145,82 @@ void ConstantPool::initialize_resolved_references(ClassLoaderData* loader_data,
} }
} }
void ConstantPool::allocate_resolved_klasses(ClassLoaderData* loader_data, int num_klasses, TRAPS) {
// A ConstantPool can't possibly have 0xffff valid class entries,
// because entry #0 must be CONSTANT_Invalid, and each class entry must refer to a UTF8
// entry for the class's name. So at most we will have 0xfffe class entries.
// This allows us to use 0xffff (ConstantPool::_temp_resolved_klass_index) to indicate
// UnresolvedKlass entries that are temporarily created during class redefinition.
assert(num_klasses < CPKlassSlot::_temp_resolved_klass_index, "sanity");
assert(resolved_klasses() == NULL, "sanity");
Array<Klass*>* rk = MetadataFactory::new_writeable_array<Klass*>(loader_data, num_klasses, CHECK);
set_resolved_klasses(rk);
}
void ConstantPool::initialize_unresolved_klasses(ClassLoaderData* loader_data, TRAPS) {
int len = length();
int num_klasses = 0;
for (int i = 1; i <len; i++) {
switch (tag_at(i).value()) {
case JVM_CONSTANT_ClassIndex:
{
const int class_index = klass_index_at(i);
unresolved_klass_at_put(i, class_index, num_klasses++);
}
break;
#ifndef PRODUCT
case JVM_CONSTANT_Class:
case JVM_CONSTANT_UnresolvedClass:
case JVM_CONSTANT_UnresolvedClassInError:
// All of these should have been reverted back to ClassIndex before calling
// this function.
ShouldNotReachHere();
#endif
}
}
allocate_resolved_klasses(loader_data, num_klasses, THREAD);
}
// Anonymous class support:
void ConstantPool::klass_at_put(int class_index, int name_index, int resolved_klass_index, Klass* k, Symbol* name) {
assert(is_within_bounds(class_index), "index out of bounds");
assert(is_within_bounds(name_index), "index out of bounds");
assert((resolved_klass_index & 0xffff0000) == 0, "must be");
*int_at_addr(class_index) =
build_int_from_shorts((jushort)resolved_klass_index, (jushort)name_index);
symbol_at_put(name_index, name);
name->increment_refcount();
Klass** adr = resolved_klasses()->adr_at(resolved_klass_index);
OrderAccess::release_store_ptr((Klass* volatile *)adr, k);
// The interpreter assumes when the tag is stored, the klass is resolved
// and the Klass* non-NULL, so we need hardware store ordering here.
if (k != NULL) {
release_tag_at_put(class_index, JVM_CONSTANT_Class);
} else {
release_tag_at_put(class_index, JVM_CONSTANT_UnresolvedClass);
}
}
// Anonymous class support:
void ConstantPool::klass_at_put(int class_index, Klass* k) {
assert(k != NULL, "must be valid klass");
CPKlassSlot kslot = klass_slot_at(class_index);
int resolved_klass_index = kslot.resolved_klass_index();
Klass** adr = resolved_klasses()->adr_at(resolved_klass_index);
OrderAccess::release_store_ptr((Klass* volatile *)adr, k);
// The interpreter assumes when the tag is stored, the klass is resolved
// and the Klass* non-NULL, so we need hardware store ordering here.
release_tag_at_put(class_index, JVM_CONSTANT_Class);
}
// CDS support. Create a new resolved_references array. // CDS support. Create a new resolved_references array.
void ConstantPool::restore_unshareable_info(TRAPS) { void ConstantPool::restore_unshareable_info(TRAPS) {
assert(is_constantPool(), "ensure C++ vtable is restored"); assert(is_constantPool(), "ensure C++ vtable is restored");
assert(on_stack(), "should always be set for shared constant pools");
assert(is_shared(), "should always be set for shared constant pools");
// Only create the new resolved references array if it hasn't been attempted before // Only create the new resolved references array if it hasn't been attempted before
if (resolved_references() != NULL) return; if (resolved_references() != NULL) return;
@ -180,6 +248,12 @@ void ConstantPool::remove_unshareable_info() {
set_resolved_reference_length( set_resolved_reference_length(
resolved_references() != NULL ? resolved_references()->length() : 0); resolved_references() != NULL ? resolved_references()->length() : 0);
set_resolved_references(NULL); set_resolved_references(NULL);
// Shared ConstantPools are in the RO region, so the _flags cannot be modified.
// The _on_stack flag is used to prevent ConstantPools from deallocation during
// class redefinition. Since shared ConstantPools cannot be deallocated anyway,
// we always set _on_stack to true to avoid having to change _flags during runtime.
_flags |= (_on_stack | _is_shared);
} }
int ConstantPool::cp_to_object_index(int cp_index) { int ConstantPool::cp_to_object_index(int cp_index) {
@ -229,11 +303,14 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which,
// A resolved constantPool entry will contain a Klass*, otherwise a Symbol*. // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*.
// It is not safe to rely on the tag bit's here, since we don't have a lock, and // It is not safe to rely on the tag bit's here, since we don't have a lock, and
// the entry and tag is not updated atomicly. // the entry and tag is not updated atomicly.
CPSlot entry = this_cp->slot_at(which); CPKlassSlot kslot = this_cp->klass_slot_at(which);
if (entry.is_resolved()) { int resolved_klass_index = kslot.resolved_klass_index();
assert(entry.get_klass()->is_klass(), "must be"); int name_index = kslot.name_index();
// Already resolved - return entry. assert(this_cp->tag_at(name_index).is_symbol(), "sanity");
return entry.get_klass();
Klass* klass = this_cp->resolved_klasses()->at(resolved_klass_index);
if (klass != NULL) {
return klass;
} }
// This tag doesn't change back to unresolved class unless at a safepoint. // This tag doesn't change back to unresolved class unless at a safepoint.
@ -251,7 +328,7 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which,
} }
Handle mirror_handle; Handle mirror_handle;
Symbol* name = entry.get_symbol(); Symbol* name = this_cp->symbol_at(name_index);
Handle loader (THREAD, this_cp->pool_holder()->class_loader()); Handle loader (THREAD, this_cp->pool_holder()->class_loader());
Handle protection_domain (THREAD, this_cp->pool_holder()->protection_domain()); Handle protection_domain (THREAD, this_cp->pool_holder()->protection_domain());
Klass* k = SystemDictionary::resolve_or_fail(name, loader, protection_domain, true, THREAD); Klass* k = SystemDictionary::resolve_or_fail(name, loader, protection_domain, true, THREAD);
@ -270,10 +347,9 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which,
// If CHECK_NULL above doesn't return the exception, that means that // If CHECK_NULL above doesn't return the exception, that means that
// some other thread has beaten us and has resolved the class. // some other thread has beaten us and has resolved the class.
// To preserve old behavior, we return the resolved class. // To preserve old behavior, we return the resolved class.
entry = this_cp->resolved_klass_at(which); klass = this_cp->resolved_klasses()->at(resolved_klass_index);
assert(entry.is_resolved(), "must be resolved if exception was cleared"); assert(klass != NULL, "must be resolved if exception was cleared");
assert(entry.get_klass()->is_klass(), "must be resolved to a klass"); return klass;
return entry.get_klass();
} else { } else {
return NULL; // return the pending exception return NULL; // return the pending exception
} }
@ -287,10 +363,13 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which,
if (log_is_enabled(Debug, class, resolve)){ if (log_is_enabled(Debug, class, resolve)){
trace_class_resolution(this_cp, k); trace_class_resolution(this_cp, k);
} }
this_cp->klass_at_put(which, k); Klass** adr = this_cp->resolved_klasses()->adr_at(resolved_klass_index);
entry = this_cp->resolved_klass_at(which); OrderAccess::release_store_ptr((Klass* volatile *)adr, k);
assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point"); // The interpreter assumes when the tag is stored, the klass is resolved
return entry.get_klass(); // and the Klass* stored in _resolved_klasses is non-NULL, so we need
// hardware store ordering here.
this_cp->release_tag_at_put(which, JVM_CONSTANT_Class);
return k;
} }
@ -299,14 +378,17 @@ Klass* ConstantPool::klass_at_impl(const constantPoolHandle& this_cp, int which,
// instanceof operations. Returns NULL if the class has not been loaded or // instanceof operations. Returns NULL if the class has not been loaded or
// if the verification of constant pool failed // if the verification of constant pool failed
Klass* ConstantPool::klass_at_if_loaded(const constantPoolHandle& this_cp, int which) { Klass* ConstantPool::klass_at_if_loaded(const constantPoolHandle& this_cp, int which) {
CPSlot entry = this_cp->slot_at(which); CPKlassSlot kslot = this_cp->klass_slot_at(which);
if (entry.is_resolved()) { int resolved_klass_index = kslot.resolved_klass_index();
assert(entry.get_klass()->is_klass(), "must be"); int name_index = kslot.name_index();
return entry.get_klass(); assert(this_cp->tag_at(name_index).is_symbol(), "sanity");
Klass* k = this_cp->resolved_klasses()->at(resolved_klass_index);
if (k != NULL) {
return k;
} else { } else {
assert(entry.is_unresolved(), "must be either symbol or klass");
Thread *thread = Thread::current(); Thread *thread = Thread::current();
Symbol* name = entry.get_symbol(); Symbol* name = this_cp->symbol_at(name_index);
oop loader = this_cp->pool_holder()->class_loader(); oop loader = this_cp->pool_holder()->class_loader();
oop protection_domain = this_cp->pool_holder()->protection_domain(); oop protection_domain = this_cp->pool_holder()->protection_domain();
Handle h_prot (thread, protection_domain); Handle h_prot (thread, protection_domain);
@ -484,22 +566,8 @@ Klass* ConstantPool::klass_ref_at(int which, TRAPS) {
return klass_at(klass_ref_index_at(which), THREAD); return klass_at(klass_ref_index_at(which), THREAD);
} }
Symbol* ConstantPool::klass_name_at(int which) const { Symbol* ConstantPool::klass_name_at(int which) const {
assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(), return symbol_at(klass_slot_at(which).name_index());
"Corrupted constant pool");
// A resolved constantPool entry will contain a Klass*, otherwise a Symbol*.
// It is not safe to rely on the tag bit's here, since we don't have a lock, and the entry and
// tag is not updated atomicly.
CPSlot entry = slot_at(which);
if (entry.is_resolved()) {
// Already resolved - return entry's name.
assert(entry.get_klass()->is_klass(), "must be");
return entry.get_klass()->name();
} else {
assert(entry.is_unresolved(), "must be either symbol or klass");
return entry.get_symbol();
}
} }
Symbol* ConstantPool::klass_ref_at_noresolve(int which) { Symbol* ConstantPool::klass_ref_at_noresolve(int which) {
@ -850,7 +918,7 @@ bool ConstantPool::klass_name_at_matches(const InstanceKlass* k, int which) {
// Iterate over symbols and decrement ones which are Symbol*s // Iterate over symbols and decrement ones which are Symbol*s
// This is done during GC. // This is done during GC.
// Only decrement the UTF8 symbols. Unresolved classes and strings point to // Only decrement the UTF8 symbols. Strings point to
// these symbols but didn't increment the reference count. // these symbols but didn't increment the reference count.
void ConstantPool::unreference_symbols() { void ConstantPool::unreference_symbols() {
for (int index = 1; index < length(); index++) { // Index 0 is unused for (int index = 1; index < length(); index++) { // Index 0 is unused
@ -1231,12 +1299,6 @@ void ConstantPool::copy_entry_to(const constantPoolHandle& from_cp, int from_i,
int tag = from_cp->tag_at(from_i).value(); int tag = from_cp->tag_at(from_i).value();
switch (tag) { switch (tag) {
case JVM_CONSTANT_Class:
{
Klass* k = from_cp->klass_at(from_i, CHECK);
to_cp->klass_at_put(to_i, k);
} break;
case JVM_CONSTANT_ClassIndex: case JVM_CONSTANT_ClassIndex:
{ {
jint ki = from_cp->klass_index_at(from_i); jint ki = from_cp->klass_index_at(from_i);
@ -1305,18 +1367,14 @@ void ConstantPool::copy_entry_to(const constantPoolHandle& from_cp, int 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_Class:
case JVM_CONSTANT_UnresolvedClass: case JVM_CONSTANT_UnresolvedClass:
case JVM_CONSTANT_UnresolvedClassInError: case JVM_CONSTANT_UnresolvedClassInError:
{ {
// Can be resolved after checking tag, so check the slot first. // Revert to JVM_CONSTANT_ClassIndex
CPSlot entry = from_cp->slot_at(from_i); int name_index = from_cp->klass_slot_at(from_i).name_index();
if (entry.is_resolved()) { assert(from_cp->tag_at(name_index).is_symbol(), "sanity");
assert(entry.get_klass()->is_klass(), "must be"); to_cp->klass_index_at_put(to_i, name_index);
// Already resolved
to_cp->klass_at_put(to_i, entry.get_klass());
} else {
to_cp->unresolved_klass_at_put(to_i, entry.get_symbol());
}
} break; } break;
case JVM_CONSTANT_String: case JVM_CONSTANT_String:
@ -1368,7 +1426,6 @@ void ConstantPool::copy_entry_to(const constantPoolHandle& from_cp, int from_i,
} }
} // end copy_entry_to() } // end copy_entry_to()
// Search constant pool search_cp for an entry that matches this // Search constant pool search_cp for an entry that matches this
// constant pool's entry at pattern_i. Returns the index of a // constant pool's entry at pattern_i. Returns the index of a
// matching entry or zero (0) if there is no matching entry. // matching entry or zero (0) if there is no matching entry.
@ -1824,13 +1881,16 @@ void ConstantPool::set_on_stack(const bool value) {
if (value) { if (value) {
// Only record if it's not already set. // Only record if it's not already set.
if (!on_stack()) { if (!on_stack()) {
assert(!is_shared(), "should always be set for shared constant pools");
_flags |= _on_stack; _flags |= _on_stack;
MetadataOnStackMark::record(this); MetadataOnStackMark::record(this);
} }
} else { } else {
// Clearing is done single-threadedly. // Clearing is done single-threadedly.
if (!is_shared()) {
_flags &= ~_on_stack; _flags &= ~_on_stack;
} }
}
} }
// JSR 292 support for patching constant pool oops after the class is linked and // JSR 292 support for patching constant pool oops after the class is linked and
@ -1905,6 +1965,7 @@ void ConstantPool::print_on(outputStream* st) const {
st->print_cr(" - cache: " INTPTR_FORMAT, p2i(cache())); st->print_cr(" - cache: " INTPTR_FORMAT, p2i(cache()));
st->print_cr(" - resolved_references: " INTPTR_FORMAT, p2i(resolved_references())); st->print_cr(" - resolved_references: " INTPTR_FORMAT, p2i(resolved_references()));
st->print_cr(" - reference_map: " INTPTR_FORMAT, p2i(reference_map())); st->print_cr(" - reference_map: " INTPTR_FORMAT, p2i(reference_map()));
st->print_cr(" - resolved_klasses: " INTPTR_FORMAT, p2i(resolved_klasses()));
for (int index = 1; index < length(); index++) { // Index 0 is unused for (int index = 1; index < length(); index++) { // Index 0 is unused
((ConstantPool*)this)->print_entry_on(index, st); ((ConstantPool*)this)->print_entry_on(index, st);
@ -1966,13 +2027,24 @@ void ConstantPool::print_entry_on(const int index, outputStream* st) {
case JVM_CONSTANT_Utf8 : case JVM_CONSTANT_Utf8 :
symbol_at(index)->print_value_on(st); symbol_at(index)->print_value_on(st);
break; break;
case JVM_CONSTANT_ClassIndex: {
int name_index = *int_at_addr(index);
st->print("klass_index=%d ", name_index);
symbol_at(name_index)->print_value_on(st);
}
break;
case JVM_CONSTANT_UnresolvedClass : // fall-through case JVM_CONSTANT_UnresolvedClass : // fall-through
case JVM_CONSTANT_UnresolvedClassInError: { case JVM_CONSTANT_UnresolvedClassInError: {
CPSlot entry = slot_at(index); CPKlassSlot kslot = klass_slot_at(index);
if (entry.is_resolved()) { int resolved_klass_index = kslot.resolved_klass_index();
entry.get_klass()->print_value_on(st); int name_index = kslot.name_index();
assert(tag_at(name_index).is_symbol(), "sanity");
Klass* klass = resolved_klasses()->at(resolved_klass_index);
if (klass != NULL) {
klass->print_value_on(st);
} else { } else {
entry.get_symbol()->print_value_on(st); symbol_at(name_index)->print_value_on(st);
} }
} }
break; break;
@ -2044,18 +2116,13 @@ void ConstantPool::verify_on(outputStream* st) {
guarantee(is_constantPool(), "object must be constant pool"); guarantee(is_constantPool(), "object must be constant pool");
for (int i = 0; i< length(); i++) { for (int i = 0; i< length(); i++) {
constantTag tag = tag_at(i); constantTag tag = tag_at(i);
CPSlot entry = slot_at(i); if (tag.is_klass() || tag.is_unresolved_klass()) {
if (tag.is_klass()) { guarantee(klass_name_at(i)->refcount() != 0, "should have nonzero reference count");
if (entry.is_resolved()) {
guarantee(entry.get_klass()->is_klass(), "should be klass");
}
} else if (tag.is_unresolved_klass()) {
if (entry.is_resolved()) {
guarantee(entry.get_klass()->is_klass(), "should be klass");
}
} else if (tag.is_symbol()) { } else if (tag.is_symbol()) {
CPSlot entry = slot_at(i);
guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count"); guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count");
} else if (tag.is_string()) { } else if (tag.is_string()) {
CPSlot entry = slot_at(i);
guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count"); guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count");
} }
} }

View file

@ -46,27 +46,47 @@
class SymbolHashMap; class SymbolHashMap;
class CPSlot VALUE_OBJ_CLASS_SPEC { class CPSlot VALUE_OBJ_CLASS_SPEC {
friend class ConstantPool;
intptr_t _ptr; intptr_t _ptr;
enum TagBits {_pseudo_bit = 1};
public: public:
enum TagBits { _resolved_value = 0, _symbol_bit = 1, _pseudo_bit = 2, _symbol_mask = 3 };
CPSlot(intptr_t ptr): _ptr(ptr) {} CPSlot(intptr_t ptr): _ptr(ptr) {}
CPSlot(Klass* ptr): _ptr((intptr_t)ptr) {} CPSlot(Symbol* ptr, int tag_bits = 0): _ptr((intptr_t)ptr | tag_bits) {}
CPSlot(Symbol* ptr): _ptr((intptr_t)ptr | _symbol_bit) {}
CPSlot(Symbol* ptr, int tag_bits): _ptr((intptr_t)ptr | tag_bits) {}
intptr_t value() { return _ptr; } intptr_t value() { return _ptr; }
bool is_resolved() { return (_ptr & _symbol_bit ) == _resolved_value; } bool is_pseudo_string() { return (_ptr & _pseudo_bit) != 0; }
bool is_unresolved() { return (_ptr & _symbol_bit ) != _resolved_value; }
bool is_pseudo_string() { return (_ptr & _symbol_mask) == _symbol_bit + _pseudo_bit; }
Symbol* get_symbol() { Symbol* get_symbol() {
assert(is_unresolved(), "bad call"); return (Symbol*)(_ptr & ~_pseudo_bit);
return (Symbol*)(_ptr & ~_symbol_mask);
} }
Klass* get_klass() { };
assert(is_resolved(), "bad call");
return (Klass*)_ptr; // This represents a JVM_CONSTANT_Class, JVM_CONSTANT_UnresolvedClass, or
// JVM_CONSTANT_UnresolvedClassInError slot in the constant pool.
class CPKlassSlot VALUE_OBJ_CLASS_SPEC {
// cp->symbol_at(_name_index) gives the name of the class.
int _name_index;
// cp->_resolved_klasses->at(_resolved_klass_index) gives the Klass* for the class.
int _resolved_klass_index;
public:
enum {
// This is used during constant pool merging where the resolved klass index is
// not yet known, and will be computed at a later stage (during a call to
// initialize_unresolved_klasses()).
_temp_resolved_klass_index = 0xffff
};
CPKlassSlot(int n, int rk) {
_name_index = n;
_resolved_klass_index = rk;
}
int name_index() const {
return _name_index;
}
int resolved_klass_index() const {
assert(_resolved_klass_index != _temp_resolved_klass_index, "constant pool merging was incomplete");
return _resolved_klass_index;
} }
}; };
@ -83,14 +103,14 @@ class ConstantPool : public Metadata {
InstanceKlass* _pool_holder; // the corresponding class InstanceKlass* _pool_holder; // the corresponding class
Array<u2>* _operands; // for variable-sized (InvokeDynamic) nodes, usually empty Array<u2>* _operands; // for variable-sized (InvokeDynamic) nodes, usually empty
// Array of resolved objects from the constant pool and map from resolved // Consider using an array of compressed klass pointers to
// object index to original constant pool index // save space on 64-bit platforms.
jobject _resolved_references; Array<Klass*>* _resolved_klasses;
Array<u2>* _reference_map;
enum { enum {
_has_preresolution = 1, // Flags _has_preresolution = 1, // Flags
_on_stack = 2 _on_stack = 2,
_is_shared = 4
}; };
int _flags; // old fashioned bit twiddling int _flags; // old fashioned bit twiddling
@ -119,6 +139,7 @@ class ConstantPool : public Metadata {
CPSlot slot_at(int which) const { CPSlot slot_at(int which) const {
assert(is_within_bounds(which), "index out of bounds"); assert(is_within_bounds(which), "index out of bounds");
assert(!tag_at(which).is_unresolved_klass() && !tag_at(which).is_unresolved_klass_in_error(), "Corrupted constant pool");
// Uses volatile because the klass slot changes without a lock. // Uses volatile because the klass slot changes without a lock.
volatile intptr_t adr = (intptr_t)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which)); volatile intptr_t adr = (intptr_t)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which));
assert(adr != 0 || which == 0, "cp entry for klass should not be zero"); assert(adr != 0 || which == 0, "cp entry for klass should not be zero");
@ -166,7 +187,10 @@ class ConstantPool : public Metadata {
Array<u2>* operands() const { return _operands; } Array<u2>* operands() const { return _operands; }
bool has_preresolution() const { return (_flags & _has_preresolution) != 0; } bool has_preresolution() const { return (_flags & _has_preresolution) != 0; }
void set_has_preresolution() { _flags |= _has_preresolution; } void set_has_preresolution() {
assert(!is_shared(), "should never be called on shared ConstantPools");
_flags |= _has_preresolution;
}
// Redefine classes support. If a method refering to this constant pool // Redefine classes support. If a method refering to this constant pool
// is on the executing stack, or as a handle in vm code, this constant pool // is on the executing stack, or as a handle in vm code, this constant pool
@ -175,6 +199,9 @@ class ConstantPool : public Metadata {
bool on_stack() const { return (_flags &_on_stack) != 0; } bool on_stack() const { return (_flags &_on_stack) != 0; }
void set_on_stack(const bool value); void set_on_stack(const bool value);
// Faster than MetaspaceObj::is_shared() - used by set_on_stack()
bool is_shared() const { return (_flags & _is_shared) != 0; }
// Klass holding pool // Klass holding pool
InstanceKlass* pool_holder() const { return _pool_holder; } InstanceKlass* pool_holder() const { return _pool_holder; }
void set_pool_holder(InstanceKlass* k) { _pool_holder = k; } void set_pool_holder(InstanceKlass* k) { _pool_holder = k; }
@ -193,9 +220,14 @@ class ConstantPool : public Metadata {
// resolved strings, methodHandles and callsite objects from the constant pool // resolved strings, methodHandles and callsite objects from the constant pool
objArrayOop resolved_references() const; objArrayOop resolved_references() const;
// mapping resolved object array indexes to cp indexes and back. // mapping resolved object array indexes to cp indexes and back.
int object_to_cp_index(int index) { return _reference_map->at(index); } int object_to_cp_index(int index) { return reference_map()->at(index); }
int cp_to_object_index(int index); int cp_to_object_index(int index);
void set_resolved_klasses(Array<Klass*>* rk) { _resolved_klasses = rk; }
Array<Klass*>* resolved_klasses() const { return _resolved_klasses; }
void allocate_resolved_klasses(ClassLoaderData* loader_data, int num_klasses, TRAPS);
void initialize_unresolved_klasses(ClassLoaderData* loader_data, TRAPS);
// Invokedynamic indexes. // Invokedynamic indexes.
// They must look completely different from normal indexes. // They must look completely different from normal indexes.
// The main reason is that byte swapping is sometimes done on normal indexes. // The main reason is that byte swapping is sometimes done on normal indexes.
@ -223,30 +255,27 @@ class ConstantPool : public Metadata {
static int tags_offset_in_bytes() { return offset_of(ConstantPool, _tags); } static int tags_offset_in_bytes() { return offset_of(ConstantPool, _tags); }
static int cache_offset_in_bytes() { return offset_of(ConstantPool, _cache); } static int cache_offset_in_bytes() { return offset_of(ConstantPool, _cache); }
static int pool_holder_offset_in_bytes() { return offset_of(ConstantPool, _pool_holder); } static int pool_holder_offset_in_bytes() { return offset_of(ConstantPool, _pool_holder); }
static int resolved_references_offset_in_bytes() { return offset_of(ConstantPool, _resolved_references); } static int resolved_klasses_offset_in_bytes() { return offset_of(ConstantPool, _resolved_klasses); }
// Storing constants // Storing constants
void klass_at_put(int which, Klass* k) {
assert(k != NULL, "resolved class shouldn't be null");
assert(is_within_bounds(which), "index out of bounds");
OrderAccess::release_store_ptr((Klass* volatile *)obj_at_addr_raw(which), k);
// The interpreter assumes when the tag is stored, the klass is resolved
// and the Klass* is a klass rather than a Symbol*, so we need
// hardware store ordering here.
release_tag_at_put(which, JVM_CONSTANT_Class);
}
// For temporary use while constructing constant pool // For temporary use while constructing constant pool
void klass_index_at_put(int which, int name_index) { void klass_index_at_put(int which, int name_index) {
tag_at_put(which, JVM_CONSTANT_ClassIndex); tag_at_put(which, JVM_CONSTANT_ClassIndex);
*int_at_addr(which) = name_index; *int_at_addr(which) = name_index;
} }
// Temporary until actual use // Anonymous class support:
void unresolved_klass_at_put(int which, Symbol* s) { void klass_at_put(int class_index, int name_index, int resolved_klass_index, Klass* k, Symbol* name);
void klass_at_put(int class_index, Klass* k);
void unresolved_klass_at_put(int which, int name_index, int resolved_klass_index) {
release_tag_at_put(which, JVM_CONSTANT_UnresolvedClass); release_tag_at_put(which, JVM_CONSTANT_UnresolvedClass);
slot_at_put(which, s);
assert((name_index & 0xffff0000) == 0, "must be");
assert((resolved_klass_index & 0xffff0000) == 0, "must be");
*int_at_addr(which) =
build_int_from_shorts((jushort)resolved_klass_index, (jushort)name_index);
} }
void method_handle_index_at_put(int which, int ref_kind, int ref_index) { void method_handle_index_at_put(int which, int ref_kind, int ref_index) {
@ -266,7 +295,7 @@ class ConstantPool : public Metadata {
void unresolved_string_at_put(int which, Symbol* s) { void unresolved_string_at_put(int which, Symbol* s) {
release_tag_at_put(which, JVM_CONSTANT_String); release_tag_at_put(which, JVM_CONSTANT_String);
slot_at_put(which, CPSlot(s, CPSlot::_symbol_bit)); slot_at_put(which, CPSlot(s));
} }
void int_at_put(int which, jint i) { void int_at_put(int which, jint i) {
@ -348,17 +377,38 @@ class ConstantPool : public Metadata {
return klass_at_impl(h_this, which, false, THREAD); return klass_at_impl(h_this, which, false, THREAD);
} }
CPKlassSlot klass_slot_at(int which) const {
assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(),
"Corrupted constant pool");
int value = *int_at_addr(which);
int name_index = extract_high_short_from_int(value);
int resolved_klass_index = extract_low_short_from_int(value);
return CPKlassSlot(name_index, resolved_klass_index);
}
Symbol* klass_name_at(int which) const; // Returns the name, w/o resolving. Symbol* klass_name_at(int which) const; // Returns the name, w/o resolving.
int klass_name_index_at(int which) const {
return klass_slot_at(which).name_index();
}
Klass* resolved_klass_at(int which) const { // Used by Compiler Klass* resolved_klass_at(int which) const { // Used by Compiler
guarantee(tag_at(which).is_klass(), "Corrupted constant pool"); guarantee(tag_at(which).is_klass(), "Corrupted constant pool");
// Must do an acquire here in case another thread resolved the klass // Must do an acquire here in case another thread resolved the klass
// behind our back, lest we later load stale values thru the oop. // behind our back, lest we later load stale values thru the oop.
return CPSlot((Klass*)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which))).get_klass(); CPKlassSlot kslot = klass_slot_at(which);
assert(tag_at(kslot.name_index()).is_symbol(), "sanity");
Klass** adr = resolved_klasses()->adr_at(kslot.resolved_klass_index());
return (Klass*)OrderAccess::load_ptr_acquire(adr);
} }
// RedefineClasses() API support: // RedefineClasses() API support:
Symbol* klass_at_noresolve(int which) { return klass_name_at(which); } Symbol* klass_at_noresolve(int which) { return klass_name_at(which); }
void temp_unresolved_klass_at_put(int which, int name_index) {
// Used only during constant pool merging for class redefinition. The resolved klass index
// will be initialized later by a call to initialize_unresolved_klasses().
unresolved_klass_at_put(which, name_index, CPKlassSlot::_temp_resolved_klass_index);
}
jint int_at(int which) { jint int_at(int which) {
assert(tag_at(which).is_int(), "Corrupted constant pool"); assert(tag_at(which).is_int(), "Corrupted constant pool");
@ -428,7 +478,7 @@ class ConstantPool : public Metadata {
void pseudo_string_at_put(int which, int obj_index, oop x) { void pseudo_string_at_put(int which, int obj_index, oop x) {
assert(tag_at(which).is_string(), "Corrupted constant pool"); assert(tag_at(which).is_string(), "Corrupted constant pool");
Symbol* sym = unresolved_string_at(which); Symbol* sym = unresolved_string_at(which);
slot_at_put(which, CPSlot(sym, (CPSlot::_symbol_bit | CPSlot::_pseudo_bit))); slot_at_put(which, CPSlot(sym, CPSlot::_pseudo_bit));
string_at_put(which, obj_index, x); // this works just fine string_at_put(which, obj_index, x); // this works just fine
} }
@ -761,9 +811,9 @@ class ConstantPool : public Metadata {
private: private:
void set_resolved_references(jobject s) { _resolved_references = s; } void set_resolved_references(jobject s) { _cache->set_resolved_references(s); }
Array<u2>* reference_map() const { return _reference_map; } Array<u2>* reference_map() const { return (_cache == NULL) ? NULL : _cache->reference_map(); }
void set_reference_map(Array<u2>* o) { _reference_map = o; } void set_reference_map(Array<u2>* o) { _cache->set_reference_map(o); }
// patch JSR 292 resolved references after the class is linked. // patch JSR 292 resolved references after the class is linked.
void patch_resolved_references(GrowableArray<Handle>* cp_patches); void patch_resolved_references(GrowableArray<Handle>* cp_patches);

View file

@ -404,6 +404,13 @@ class ConstantPoolCache: public MetaspaceObj {
int _length; int _length;
ConstantPool* _constant_pool; // the corresponding constant pool ConstantPool* _constant_pool; // the corresponding constant pool
// The following fields need to be modified at runtime, so they cannot be
// stored in the ConstantPool, which is read-only.
// Array of resolved objects from the constant pool and map from resolved
// object index to original constant pool index
jobject _resolved_references;
Array<u2>* _reference_map;
// Sizing // Sizing
debug_only(friend class ClassVerifier;) debug_only(friend class ClassVerifier;)
@ -433,6 +440,15 @@ class ConstantPoolCache: public MetaspaceObj {
bool is_constantPoolCache() const { return true; } bool is_constantPoolCache() const { return true; }
int length() const { return _length; } int length() const { return _length; }
jobject resolved_references() { return _resolved_references; }
void set_resolved_references(jobject s) { _resolved_references = s; }
Array<u2>* reference_map() const { return _reference_map; }
void set_reference_map(Array<u2>* o) { _reference_map = o; }
// Assembly code support
static int resolved_references_offset_in_bytes() { return offset_of(ConstantPoolCache, _resolved_references); }
private: private:
void set_length(int length) { _length = length; } void set_length(int length) { _length = length; }

View file

@ -292,12 +292,22 @@ void VM_RedefineClasses::append_entry(const constantPoolHandle& scratch_cp,
// entries in the input constant pool. We revert the appended copy // entries in the input constant pool. We revert the appended copy
// back to UnresolvedClass so that either verifier will be happy // back to UnresolvedClass so that either verifier will be happy
// with the constant pool entry. // with the constant pool entry.
//
// this is an indirect CP entry so it needs special handling
case JVM_CONSTANT_Class: case JVM_CONSTANT_Class:
case JVM_CONSTANT_UnresolvedClass:
{ {
// revert the copy to JVM_CONSTANT_UnresolvedClass int name_i = scratch_cp->klass_name_index_at(scratch_i);
(*merge_cp_p)->unresolved_klass_at_put(*merge_cp_length_p, int new_name_i = find_or_append_indirect_entry(scratch_cp, name_i, merge_cp_p,
scratch_cp->klass_name_at(scratch_i)); merge_cp_length_p, THREAD);
if (new_name_i != name_i) {
log_trace(redefine, class, constantpool)
("Class entry@%d name_index change: %d to %d",
*merge_cp_length_p, name_i, new_name_i);
}
(*merge_cp_p)->temp_unresolved_klass_at_put(*merge_cp_length_p, new_name_i);
if (scratch_i != *merge_cp_length_p) { if (scratch_i != *merge_cp_length_p) {
// The new entry in *merge_cp_p is at a different index than // The new entry in *merge_cp_p is at a different index than
// the new entry in scratch_cp so we need to map the index values. // the new entry in scratch_cp so we need to map the index values.
@ -330,10 +340,6 @@ void VM_RedefineClasses::append_entry(const constantPoolHandle& scratch_cp,
// This was an indirect CP entry, but it has been changed into // This was an indirect CP entry, but it has been changed into
// Symbol*s so this entry can be directly appended. // Symbol*s so this entry can be directly appended.
case JVM_CONSTANT_String: // fall through case JVM_CONSTANT_String: // fall through
// These were indirect CP entries, but they have been changed into
// Symbol*s so these entries can be directly appended.
case JVM_CONSTANT_UnresolvedClass: // fall through
{ {
ConstantPool::copy_entry_to(scratch_cp, scratch_i, *merge_cp_p, *merge_cp_length_p, ConstantPool::copy_entry_to(scratch_cp, scratch_i, *merge_cp_p, *merge_cp_length_p,
THREAD); THREAD);
@ -504,7 +510,7 @@ void VM_RedefineClasses::append_entry(const constantPoolHandle& scratch_cp,
(*merge_cp_length_p)++; (*merge_cp_length_p)++;
} break; } break;
// At this stage, Class or UnresolvedClass could be here, but not // At this stage, Class or UnresolvedClass could be in scratch_cp, but not
// ClassIndex // ClassIndex
case JVM_CONSTANT_ClassIndex: // fall through case JVM_CONSTANT_ClassIndex: // fall through
@ -1270,8 +1276,8 @@ bool VM_RedefineClasses::merge_constant_pools(const constantPoolHandle& old_cp,
// revert the copy to JVM_CONSTANT_UnresolvedClass // revert the copy to JVM_CONSTANT_UnresolvedClass
// May be resolving while calling this so do the same for // May be resolving while calling this so do the same for
// JVM_CONSTANT_UnresolvedClass (klass_name_at() deals with transition) // JVM_CONSTANT_UnresolvedClass (klass_name_at() deals with transition)
(*merge_cp_p)->unresolved_klass_at_put(old_i, (*merge_cp_p)->temp_unresolved_klass_at_put(old_i,
old_cp->klass_name_at(old_i)); old_cp->klass_name_index_at(old_i));
break; break;
case JVM_CONSTANT_Double: case JVM_CONSTANT_Double:
@ -3102,6 +3108,7 @@ void VM_RedefineClasses::set_new_constant_pool(
// attach new constant pool to klass // attach new constant pool to klass
scratch_class->set_constants(scratch_cp()); scratch_class->set_constants(scratch_cp());
scratch_cp->initialize_unresolved_klasses(loader_data, CHECK);
int i; // for portability int i; // for portability

View file

@ -238,8 +238,8 @@ typedef RehashableHashtable<Symbol*, mtSymbol> RehashableSymbolHashtable;
nonstatic_field(ConstantPool, _pool_holder, InstanceKlass*) \ nonstatic_field(ConstantPool, _pool_holder, InstanceKlass*) \
nonstatic_field(ConstantPool, _operands, Array<u2>*) \ nonstatic_field(ConstantPool, _operands, Array<u2>*) \
nonstatic_field(ConstantPool, _length, int) \ nonstatic_field(ConstantPool, _length, int) \
nonstatic_field(ConstantPool, _resolved_references, jobject) \ nonstatic_field(ConstantPoolCache, _resolved_references, jobject) \
nonstatic_field(ConstantPool, _reference_map, Array<u2>*) \ nonstatic_field(ConstantPoolCache, _reference_map, Array<u2>*) \
nonstatic_field(ConstantPoolCache, _length, int) \ nonstatic_field(ConstantPoolCache, _length, int) \
nonstatic_field(ConstantPoolCache, _constant_pool, ConstantPool*) \ nonstatic_field(ConstantPoolCache, _constant_pool, ConstantPool*) \
volatile_nonstatic_field(InstanceKlass, _array_klasses, Klass*) \ volatile_nonstatic_field(InstanceKlass, _array_klasses, Klass*) \

View file

@ -128,7 +128,7 @@ public class LimitSharedSizes {
// test with sizes which just meet the minimum required sizes // test with sizes which just meet the minimum required sizes
// the following tests also attempt to use the shared archive // the following tests also attempt to use the shared archive
new SharedSizeTestData(Region.RO, Platform.is64bit() ? "10M":"9M", Result.VALID_ARCHIVE), new SharedSizeTestData(Region.RO, Platform.is64bit() ? "14M":"9M", Result.VALID_ARCHIVE),
new SharedSizeTestData(Region.RW, Platform.is64bit() ? "12M":"7M", Result.VALID_ARCHIVE), new SharedSizeTestData(Region.RW, Platform.is64bit() ? "12M":"7M", Result.VALID_ARCHIVE),
new SharedSizeTestData(Region.MD, Platform.is64bit() ? "4M":"2M", Result.VALID_ARCHIVE), new SharedSizeTestData(Region.MD, Platform.is64bit() ? "4M":"2M", Result.VALID_ARCHIVE),
new SharedSizeTestData(Region.MC, "120k", Result.VALID_ARCHIVE), new SharedSizeTestData(Region.MC, "120k", Result.VALID_ARCHIVE),