--- old/src/cpu/aarch64/vm/interp_masm_aarch64.cpp 2017-04-16 02:30:18.688580566 -0700 +++ new/src/cpu/aarch64/vm/interp_masm_aarch64.cpp 2017-04-16 02:30:18.512573966 -0700 @@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -270,7 +270,8 @@ get_constant_pool(result); // 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); ldr(result, Address(result, 0)); // Add in the index --- old/src/cpu/aarch64/vm/templateTable_aarch64.cpp 2017-04-16 02:30:19.560613264 -0700 +++ new/src/cpu/aarch64/vm/templateTable_aarch64.cpp 2017-04-16 02:30:19.380606514 -0700 @@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -3583,8 +3583,16 @@ // Get superklass in r0 and subklass in r3 __ bind(quicked); __ load_klass(r3, r0); - __ lea(r0, Address(r2, r19, Address::lsl(3))); - __ ldr(r0, Address(r0, sizeof(ConstantPool))); + //__ load_resolved_klass_at_offset(r2, r19, r0); + Register cpool = r2; + Register index = r19; + Register klass = r0; + Register tmp = klass; + __ lea(tmp, Address(cpool, index, Address::lsl(3))); + __ ldrh(index, Address(tmp, sizeof(ConstantPool))); // index = resolved_klass_index + __ ldr(tmp, Address(cpool, ConstantPool::resolved_klasses_offset_in_bytes())); // tmp = cpool->_resolved_klasses + __ lea(tmp, Address(tmp, index, Address::lsl(3))); + __ ldr(klass, Address(tmp, Array::base_offset_in_bytes())); __ bind(resolved); --- old/src/cpu/arm/vm/interp_masm_arm.cpp 2017-04-16 02:30:20.504648662 -0700 +++ new/src/cpu/arm/vm/interp_masm_arm.cpp 2017-04-16 02:30:20.312641462 -0700 @@ -298,7 +298,8 @@ Register cache = result; // 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) ldr(cache, Address(cache, 0)); // Add in the index @@ -308,6 +309,15 @@ 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::base_offset_in_bytes())); +} + // Generate a subtype check: branch to not_subtype if sub_klass is // not a subtype of super_klass. // Profiling code for the subtype check failure (profile_typecheck_failed) --- old/src/cpu/arm/vm/interp_masm_arm.hpp 2017-04-16 02:30:21.420683010 -0700 +++ new/src/cpu/arm/vm/interp_masm_arm.hpp 2017-04-16 02:30:21.228675810 -0700 @@ -141,6 +141,9 @@ // Load object from cpool->resolved_references(*bcp+1) 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_part2(Register obj, Register card_table_base, Register tmp); --- old/src/cpu/arm/vm/templateTable_arm.cpp 2017-04-16 02:30:22.272714958 -0700 +++ new/src/cpu/arm/vm/templateTable_arm.cpp 2017-04-16 02:30:22.088708059 -0700 @@ -4372,10 +4372,9 @@ #endif // AARCH64 // get InstanceKlass - __ add(Rklass, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord)); - __ ldr(Rklass, Address(Rklass, sizeof(ConstantPool))); __ cmp(Rtemp, JVM_CONSTANT_Class); __ 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 fully initialized @@ -4647,8 +4646,7 @@ // Get superklass in Rsuper and subklass in Rsub __ bind(quicked); - __ add(Rtemp, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord)); - __ ldr(Rsuper, Address(Rtemp, sizeof(ConstantPool))); + __ load_resolved_klass_at_offset(Rcpool, Rindex, Rsuper); __ bind(resolved); __ load_klass(Rsub, Robj); @@ -4721,8 +4719,7 @@ // Get superklass in Rsuper and subklass in Rsub __ bind(quicked); - __ add(Rtemp, Rcpool, AsmOperand(Rindex, lsl, LogBytesPerWord)); - __ ldr(Rsuper, Address(Rtemp, sizeof(ConstantPool))); + __ load_resolved_klass_at_offset(Rcpool, Rindex, Rsuper); __ bind(resolved); __ load_klass(Rsub, Robj); --- old/src/cpu/ppc/vm/interp_masm_ppc_64.cpp 2017-04-16 02:30:23.276752606 -0700 +++ new/src/cpu/ppc/vm/interp_masm_ppc_64.cpp 2017-04-16 02:30:23.092745706 -0700 @@ -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) 2012, 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -454,7 +454,8 @@ Register tmp = index; // reuse sldi(tmp, index, LogBytesPerHeapOop); // 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) ld(result, 0, result); #ifdef ASSERT --- old/src/cpu/s390/vm/interp_masm_s390.cpp 2017-04-16 02:30:24.216787854 -0700 +++ new/src/cpu/s390/vm/interp_masm_s390.cpp 2017-04-16 02:30:24.024780654 -0700 @@ -1,5 +1,5 @@ /* - * 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -371,7 +371,8 @@ Register tmp = index; // reuse z_sllg(index, index, LogBytesPerHeapOop); // Offset into resolved references array. // 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) z_lg(result, 0, result); // Load resolved references array itself. #ifdef ASSERT --- old/src/cpu/sparc/vm/interp_masm_sparc.cpp 2017-04-16 02:30:25.172823701 -0700 +++ new/src/cpu/sparc/vm/interp_masm_sparc.cpp 2017-04-16 02:30:24.980816502 -0700 @@ -755,7 +755,8 @@ sll(index, LogBytesPerHeapOop, tmp); get_constant_pool(result); // 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) ld_ptr(result, 0, result); // Add in the index @@ -764,6 +765,24 @@ } +// 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::base_offset_in_bytes(), Roffset); + ld_ptr(Rresolved_klasses, Roffset, Rklass); +} + + // 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. void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, --- old/src/cpu/sparc/vm/interp_masm_sparc.hpp 2017-04-16 02:30:26.052856700 -0700 +++ new/src/cpu/sparc/vm/interp_masm_sparc.hpp 2017-04-16 02:30:25.880850250 -0700 @@ -196,6 +196,9 @@ // load cpool->resolved_references(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 void field_offset_at(int n, Register tmp, Register dest, Register base); --- old/src/cpu/sparc/vm/templateTable_sparc.cpp 2017-04-16 02:30:26.948890298 -0700 +++ new/src/cpu/sparc/vm/templateTable_sparc.cpp 2017-04-16 02:30:26.756883098 -0700 @@ -3241,9 +3241,7 @@ __ br(Assembler::notEqual, false, Assembler::pn, slow_case); __ delayed()->sll(Roffset, LogBytesPerWord, Roffset); // get InstanceKlass - //__ sll(Roffset, LogBytesPerWord, Roffset); // executed in delay slot - __ add(Roffset, sizeof(ConstantPool), Roffset); - __ ld_ptr(Rscratch, Roffset, RinstanceKlass); + __ load_resolved_klass_at_offset(Rscratch, Roffset, RinstanceKlass); // make sure klass is fully initialized: __ ldub(RinstanceKlass, in_bytes(InstanceKlass::init_state_offset()), G3_scratch); @@ -3465,8 +3463,9 @@ // Extract target class from constant pool __ bind(quicked); - __ add(Roffset, sizeof(ConstantPool), Roffset); - __ ld_ptr(Lscratch, Roffset, RspecifiedKlass); + __ load_resolved_klass_at_offset(Lscratch, Roffset, RspecifiedKlass); + + __ bind(resolved); __ load_klass(Otos_i, RobjKlass); // get value klass @@ -3522,9 +3521,9 @@ // Extract target class from constant pool __ bind(quicked); - __ add(Roffset, sizeof(ConstantPool), Roffset); __ get_constant_pool(Lscratch); - __ ld_ptr(Lscratch, Roffset, RspecifiedKlass); + __ load_resolved_klass_at_offset(Lscratch, Roffset, RspecifiedKlass); + __ bind(resolved); __ load_klass(Otos_i, RobjKlass); // get value klass --- old/src/cpu/x86/vm/interp_masm_x86.cpp 2017-04-16 02:30:27.936927345 -0700 +++ new/src/cpu/x86/vm/interp_masm_x86.cpp 2017-04-16 02:30:27.744920145 -0700 @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -509,7 +509,8 @@ get_constant_pool(result); // 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); movptr(result, Address(result, 0)); // Add in the index @@ -517,6 +518,14 @@ 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::base_offset_in_bytes())); +} // Generate a subtype check: branch to ok_is_subtype if sub_klass is a // subtype of super_klass. --- old/src/cpu/x86/vm/interp_masm_x86.hpp 2017-04-16 02:30:28.852961693 -0700 +++ new/src/cpu/x86/vm/interp_masm_x86.hpp 2017-04-16 02:30:28.656954343 -0700 @@ -123,6 +123,11 @@ // load cpool->resolved_references(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 d2ieee();) // truncate dtos to 64bits --- old/src/cpu/x86/vm/templateTable_x86.cpp 2017-04-16 02:30:29.768996041 -0700 +++ new/src/cpu/x86/vm/templateTable_x86.cpp 2017-04-16 02:30:29.568988541 -0700 @@ -3846,7 +3846,7 @@ __ jcc(Assembler::notEqual, slow_case_no_pop); // 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 // make sure klass is initialized & doesn't have finalizer @@ -4061,8 +4061,7 @@ // Get superklass in rax and subklass in rbx __ bind(quicked); __ mov(rdx, rax); // Save object in rdx; rax needed for subtype check - __ movptr(rax, Address(rcx, rbx, - Address::times_ptr, sizeof(ConstantPool))); + __ load_resolved_klass_at_index(rcx, rbx, rax); __ bind(resolved); __ load_klass(rbx, rdx); @@ -4128,8 +4127,7 @@ // Get superklass in rax and subklass in rdx __ bind(quicked); __ load_klass(rdx, rax); - __ movptr(rax, Address(rcx, rbx, - Address::times_ptr, sizeof(ConstantPool))); + __ load_resolved_klass_at_index(rcx, rbx, rax); __ bind(resolved); --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java 2017-04-16 02:30:30.729032039 -0700 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java 2017-04-16 02:30:30.541024989 -0700 @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -84,8 +84,6 @@ cache = type.getAddressField("_cache"); poolHolder = new MetadataField(type.getAddressField("_pool_holder"), 0); length = new CIntField(type.getCIntegerField("_length"), 0); - resolvedReferences = type.getAddressField("_resolved_references"); - referenceMap = type.getAddressField("_reference_map"); headerSize = type.getSize(); elementSize = 0; // fetch constants: @@ -105,8 +103,6 @@ private static AddressField cache; private static MetadataField poolHolder; private static CIntField length; // number of elements in oop - private static AddressField resolvedReferences; - private static AddressField referenceMap; private static long headerSize; private static long elementSize; @@ -124,17 +120,11 @@ public InstanceKlass getPoolHolder() { return (InstanceKlass)poolHolder.getValue(this); } public int getLength() { return (int)length.getValue(getAddress()); } 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; + return getCache().getResolvedReferences(); } public U2Array referenceMap() { - return new U2Array(referenceMap.getValue(getAddress())); + return getCache().referenceMap(); } public int objectToCPIndex(int index) { --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java 2017-04-16 02:30:31.625065636 -0700 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java 2017-04-16 02:30:31.441058737 -0700 @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -51,6 +51,8 @@ elementSize = elType.getSize(); length = new CIntField(type.getCIntegerField("_length"), 0); intSize = VM.getVM().getObjectHeap().getIntSize(); + resolvedReferences = type.getAddressField("_resolved_references"); + referenceMap = type.getAddressField("_reference_map"); } public ConstantPoolCache(Address addr) { @@ -65,7 +67,8 @@ private static long elementSize; private static CIntField length; private static long intSize; - + private static AddressField resolvedReferences; + private static AddressField referenceMap; public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); } @@ -100,4 +103,18 @@ 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())); + } }; --- old/src/share/vm/classfile/bytecodeAssembler.cpp 2017-04-16 02:30:32.505098634 -0700 +++ new/src/share/vm/classfile/bytecodeAssembler.cpp 2017-04-16 02:30:32.313091435 -0700 @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -64,8 +64,8 @@ cp->symbol_at_put(idx, entry._u.utf8); break; case BytecodeCPEntry::KLASS: - cp->unresolved_klass_at_put( - idx, cp->symbol_at(entry._u.klass)); + cp->klass_index_at_put( + idx, entry._u.klass); break; case BytecodeCPEntry::STRING: cp->unresolved_string_at_put( @@ -85,6 +85,9 @@ ShouldNotReachHere(); } } + + cp->initialize_unresolved_klasses(_orig->pool_holder()->class_loader_data(), + CHECK_NULL); return cp; } --- old/src/share/vm/classfile/classFileParser.cpp 2017-04-16 02:30:33.393131932 -0700 +++ new/src/share/vm/classfile/classFileParser.cpp 2017-04-16 02:30:33.197124583 -0700 @@ -391,6 +391,7 @@ } int index = 1; // declared outside of loops for portability + int num_klasses = 0; // first verification pass - validate cross references // and fixup class and string constants @@ -459,7 +460,7 @@ check_property(valid_symbol_at(class_index), "Invalid constant pool index %u in class file %s", 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; } case JVM_CONSTANT_StringIndex: { @@ -550,8 +551,19 @@ } // switch(tag) } // 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) { // 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; nlength(); n++) { + cp->symbol_at_put(n, s); + } + int this_class_index; { stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len @@ -701,6 +713,14 @@ } // 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, int index, Handle patch, @@ -718,13 +738,14 @@ guarantee_property(!java_lang_Class::is_primitive(patch()), "Illegal class patch at %d in class file %s", 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 { guarantee_property(java_lang_String::is_instance(patch()), "Illegal class patch at %d in class file %s", index, 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; } @@ -5340,8 +5361,14 @@ ik->set_name(_class_name); if (is_anonymous()) { - // I am well known to myself - ik->constants()->klass_at_put(_this_class_index, ik); // eagerly resolve + // _this_class_index is a CONSTANT_Class entry that refers to this + // 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); @@ -5577,6 +5604,10 @@ _loader_data(loader_data), _host_klass(host_klass), _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(), _cp(NULL), _fields(NULL), @@ -5647,6 +5678,25 @@ _need_verify = Verifier::should_verify_for(_loader_data->class_loader(), stream->need_verify()); } + if (_cp_patches != NULL) { + int len = _cp_patches->length(); + for (int i=0; iset_verify(_need_verify); @@ -5776,19 +5826,25 @@ } 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( cp_size >= 1, "Illegal constant pool size %u in class file %s", 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_size, CHECK); 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"); --- old/src/share/vm/classfile/classFileParser.hpp 2017-04-16 02:30:34.413170180 -0700 +++ new/src/share/vm/classfile/classFileParser.hpp 2017-04-16 02:30:34.229163280 -0700 @@ -81,6 +81,10 @@ mutable ClassLoaderData* _loader_data; const InstanceKlass* _host_klass; GrowableArray* _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 // if not transferred to the InstanceKlass upon successful class loading @@ -434,6 +438,7 @@ return patch; } + void patch_class(ConstantPool* cp, int class_index, Klass* k, Symbol* name); void patch_constant_pool(ConstantPool* cp, int index, Handle patch, --- old/src/share/vm/interpreter/bytecodeInterpreter.cpp 2017-04-16 02:30:35.301203477 -0700 +++ new/src/share/vm/interpreter/bytecodeInterpreter.cpp 2017-04-16 02:30:35.101195978 -0700 @@ -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. * * This code is free software; you can redistribute it and/or modify it @@ -2168,7 +2168,7 @@ ConstantPool* constants = istate->method()->constants(); if (!constants->tag_at(index).is_unresolved_klass()) { // 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); if (ik->is_initialized() && ik->can_be_fastpath_allocated() ) { size_t obj_size = ik->size_helper(); @@ -2268,7 +2268,7 @@ if (METHOD->constants()->tag_at(index).is_unresolved_klass()) { 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 // // Check for compatibilty. This check must not GC!! @@ -2303,7 +2303,7 @@ if (METHOD->constants()->tag_at(index).is_unresolved_klass()) { 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(); // // Check for compatibilty. This check must not GC!! --- old/src/share/vm/interpreter/rewriter.cpp 2017-04-16 02:30:36.277240075 -0700 +++ new/src/share/vm/interpreter/rewriter.cpp 2017-04-16 02:30:36.085232876 -0700 @@ -94,11 +94,14 @@ _invokedynamic_references_map, CHECK); // 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, _resolved_reference_limit, CHECK); - _pool->set_cache(cache); - cache->set_constant_pool(_pool()); } --- old/src/share/vm/memory/metaspaceShared.hpp 2017-04-16 02:30:37.173273673 -0700 +++ new/src/share/vm/memory/metaspaceShared.hpp 2017-04-16 02:30:36.981266473 -0700 @@ -35,8 +35,8 @@ #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 DEFAULT_SHARED_READ_ONLY_SIZE (NOT_LP64(6*M) LP64_ONLY(10*M)) -#define MIN_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(8*M) LP64_ONLY(13*M)) // 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 @@ -61,8 +61,8 @@ #define LargeSharedArchiveSize (300*M) #define HugeSharedArchiveSize (800*M) -#define ReadOnlyRegionPercentage 0.4 -#define ReadWriteRegionPercentage 0.55 +#define ReadOnlyRegionPercentage 0.52 +#define ReadWriteRegionPercentage 0.43 #define MiscDataRegionPercentage 0.03 #define MiscCodeRegionPercentage 0.02 #define LargeThresholdClassCount 5000 --- old/src/share/vm/oops/constantPool.cpp 2017-04-16 02:30:38.057306821 -0700 +++ new/src/share/vm/oops/constantPool.cpp 2017-04-16 02:30:37.869299771 -0700 @@ -47,18 +47,9 @@ #include "utilities/copy.hpp" ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) { - // Tags are RW but comment below applies to tags also. Array* tags = MetadataFactory::new_writeable_array(loader_data, length, 0, CHECK_NULL); - int size = ConstantPool::size(length); - - // 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); + return new (loader_data, size, true, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags); } #ifdef ASSERT @@ -80,22 +71,26 @@ ConstantPool::ConstantPool(Array* tags) : _tags(tags), - _length(tags->length()), - _flags(0) { + _length(tags->length()) { assert(_tags != NULL, "invariant"); assert(tags->length() == _length, "invariant"); assert(tag_array_is_zero_initialized(tags), "invariant"); - assert(0 == _flags, "invariant"); + assert(0 == flags(), "invariant"); assert(0 == version(), "invariant"); assert(NULL == _pool_holder, "invariant"); } void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) { - MetadataFactory::free_metadata(loader_data, cache()); - set_cache(NULL); - MetadataFactory::free_array(loader_data, reference_map()); - set_reference_map(NULL); + if (cache() != NULL) { + MetadataFactory::free_array(loader_data, reference_map()); + set_reference_map(NULL); + MetadataFactory::free_metadata(loader_data, cache()); + set_cache(NULL); + } + + MetadataFactory::free_array(loader_data, resolved_klasses()); + set_resolved_klasses(NULL); MetadataFactory::free_array(loader_data, operands()); set_operands(NULL); @@ -113,7 +108,7 @@ } 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 @@ -150,9 +145,81 @@ } } +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* rk = MetadataFactory::new_writeable_array(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 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) { + CPKlassSlot kslot = klass_slot_at(class_index); + int resolved_klass_index = kslot.resolved_klass_index(); + int name_index = kslot.name_index(); + Symbol* name = symbol_at(name_index); + guarantee(name == k->name(), "Invalid class name for anonymous"); + + Klass** adr = resolved_klasses()->adr_at(resolved_klass_index); + OrderAccess::release_store_ptr((Klass* volatile *)adr, k); +} + // CDS support. Create a new resolved_references array. void ConstantPool::restore_unshareable_info(TRAPS) { 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 if (resolved_references() != NULL) return; @@ -180,6 +247,12 @@ set_resolved_reference_length( resolved_references() != NULL ? resolved_references()->length() : 0); 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) { @@ -229,11 +302,14 @@ // 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 = this_cp->slot_at(which); - if (entry.is_resolved()) { - assert(entry.get_klass()->is_klass(), "must be"); - // Already resolved - return entry. - return entry.get_klass(); + CPKlassSlot kslot = this_cp->klass_slot_at(which); + int resolved_klass_index = kslot.resolved_klass_index(); + int name_index = kslot.name_index(); + assert(this_cp->tag_at(name_index).is_symbol(), "sanity"); + + 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. @@ -251,7 +327,7 @@ } 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 protection_domain (THREAD, this_cp->pool_holder()->protection_domain()); Klass* k = SystemDictionary::resolve_or_fail(name, loader, protection_domain, true, THREAD); @@ -270,10 +346,9 @@ // If CHECK_NULL above doesn't return the exception, that means that // some other thread has beaten us and has resolved the class. // To preserve old behavior, we return the resolved class. - entry = this_cp->resolved_klass_at(which); - assert(entry.is_resolved(), "must be resolved if exception was cleared"); - assert(entry.get_klass()->is_klass(), "must be resolved to a klass"); - return entry.get_klass(); + klass = this_cp->resolved_klasses()->at(resolved_klass_index); + assert(klass != NULL, "must be resolved if exception was cleared"); + return klass; } else { return NULL; // return the pending exception } @@ -287,10 +362,13 @@ if (log_is_enabled(Debug, class, resolve)){ trace_class_resolution(this_cp, k); } - this_cp->klass_at_put(which, k); - entry = this_cp->resolved_klass_at(which); - assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point"); - return entry.get_klass(); + Klass** adr = this_cp->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* 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 +377,17 @@ // instanceof operations. Returns NULL if the class has not been loaded or // if the verification of constant pool failed Klass* ConstantPool::klass_at_if_loaded(const constantPoolHandle& this_cp, int which) { - CPSlot entry = this_cp->slot_at(which); - if (entry.is_resolved()) { - assert(entry.get_klass()->is_klass(), "must be"); - return entry.get_klass(); + CPKlassSlot kslot = this_cp->klass_slot_at(which); + int resolved_klass_index = kslot.resolved_klass_index(); + int name_index = kslot.name_index(); + 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 { - assert(entry.is_unresolved(), "must be either symbol or klass"); 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 protection_domain = this_cp->pool_holder()->protection_domain(); Handle h_prot (thread, protection_domain); @@ -484,22 +565,8 @@ return klass_at(klass_ref_index_at(which), THREAD); } - Symbol* ConstantPool::klass_name_at(int which) const { - assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(), - "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(); - } + return symbol_at(klass_slot_at(which).name_index()); } Symbol* ConstantPool::klass_ref_at_noresolve(int which) { @@ -850,7 +917,7 @@ // Iterate over symbols and decrement ones which are Symbol*s // 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. void ConstantPool::unreference_symbols() { for (int index = 1; index < length(); index++) { // Index 0 is unused @@ -1231,12 +1298,6 @@ int tag = from_cp->tag_at(from_i).value(); 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: { jint ki = from_cp->klass_index_at(from_i); @@ -1305,18 +1366,14 @@ to_cp->string_index_at_put(to_i, si); } break; + case JVM_CONSTANT_Class: case JVM_CONSTANT_UnresolvedClass: case JVM_CONSTANT_UnresolvedClassInError: { - // Can be resolved after checking tag, so check the slot first. - CPSlot entry = from_cp->slot_at(from_i); - if (entry.is_resolved()) { - assert(entry.get_klass()->is_klass(), "must be"); - // Already resolved - to_cp->klass_at_put(to_i, entry.get_klass()); - } else { - to_cp->unresolved_klass_at_put(to_i, entry.get_symbol()); - } + // Revert to JVM_CONSTANT_ClassIndex + int name_index = from_cp->klass_slot_at(from_i).name_index(); + assert(from_cp->tag_at(name_index).is_symbol(), "sanity"); + to_cp->klass_index_at_put(to_i, name_index); } break; case JVM_CONSTANT_String: @@ -1368,7 +1425,6 @@ } } // end copy_entry_to() - // Search constant pool search_cp for an entry that matches this // constant pool's entry at pattern_i. Returns the index of a // matching entry or zero (0) if there is no matching entry. @@ -1824,12 +1880,15 @@ if (value) { // Only record if it's not already set. if (!on_stack()) { + assert(!is_shared(), "should always be set for shared constant pools"); _flags |= _on_stack; MetadataOnStackMark::record(this); } } else { // Clearing is done single-threadedly. - _flags &= ~_on_stack; + if (!is_shared()) { + _flags &= ~_on_stack; + } } } @@ -1905,6 +1964,7 @@ st->print_cr(" - cache: " INTPTR_FORMAT, p2i(cache())); st->print_cr(" - resolved_references: " INTPTR_FORMAT, p2i(resolved_references())); 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 ((ConstantPool*)this)->print_entry_on(index, st); @@ -1966,14 +2026,25 @@ case JVM_CONSTANT_Utf8 : symbol_at(index)->print_value_on(st); 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_UnresolvedClassInError: { - CPSlot entry = slot_at(index); - if (entry.is_resolved()) { - entry.get_klass()->print_value_on(st); - } else { - entry.get_symbol()->print_value_on(st); - } + CPKlassSlot kslot = klass_slot_at(index); + int resolved_klass_index = kslot.resolved_klass_index(); + 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 { + symbol_at(name_index)->print_value_on(st); + } } break; case JVM_CONSTANT_MethodHandle : @@ -2044,18 +2115,13 @@ guarantee(is_constantPool(), "object must be constant pool"); for (int i = 0; i< length(); i++) { constantTag tag = tag_at(i); - CPSlot entry = slot_at(i); - if (tag.is_klass()) { - 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"); - } + if (tag.is_klass() || tag.is_unresolved_klass()) { + guarantee(klass_name_at(i)->refcount() != 0, "should have nonzero reference count"); } else if (tag.is_symbol()) { + CPSlot entry = slot_at(i); guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count"); } else if (tag.is_string()) { + CPSlot entry = slot_at(i); guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count"); } } --- old/src/share/vm/oops/constantPool.hpp 2017-04-16 02:30:39.017342818 -0700 +++ new/src/share/vm/oops/constantPool.hpp 2017-04-16 02:30:38.825335619 -0700 @@ -46,27 +46,47 @@ class SymbolHashMap; class CPSlot VALUE_OBJ_CLASS_SPEC { + friend class ConstantPool; intptr_t _ptr; + enum TagBits {_pseudo_bit = 1}; public: - enum TagBits { _resolved_value = 0, _symbol_bit = 1, _pseudo_bit = 2, _symbol_mask = 3 }; CPSlot(intptr_t ptr): _ptr(ptr) {} - CPSlot(Klass* ptr): _ptr((intptr_t)ptr) {} - CPSlot(Symbol* ptr): _ptr((intptr_t)ptr | _symbol_bit) {} - CPSlot(Symbol* ptr, int tag_bits): _ptr((intptr_t)ptr | tag_bits) {} + CPSlot(Symbol* ptr, int tag_bits = 0): _ptr((intptr_t)ptr | tag_bits) {} intptr_t value() { return _ptr; } - bool is_resolved() { return (_ptr & _symbol_bit ) == _resolved_value; } - bool is_unresolved() { return (_ptr & _symbol_bit ) != _resolved_value; } - bool is_pseudo_string() { return (_ptr & _symbol_mask) == _symbol_bit + _pseudo_bit; } + bool is_pseudo_string() { return (_ptr & _pseudo_bit) != 0; } Symbol* get_symbol() { - assert(is_unresolved(), "bad call"); - return (Symbol*)(_ptr & ~_symbol_mask); + return (Symbol*)(_ptr & ~_pseudo_bit); } - 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,13 @@ InstanceKlass* _pool_holder; // the corresponding class Array* _operands; // for variable-sized (InvokeDynamic) nodes, usually empty - // Array of resolved objects from the constant pool and map from resolved - // object index to original constant pool index - jobject _resolved_references; - Array* _reference_map; + // ... will be changed to support compressed pointers + Array* _resolved_klasses; enum { _has_preresolution = 1, // Flags - _on_stack = 2 + _on_stack = 2, + _is_shared = 4 }; int _flags; // old fashioned bit twiddling @@ -119,6 +138,7 @@ CPSlot slot_at(int which) const { 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. 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"); @@ -166,7 +186,10 @@ Array* operands() const { return _operands; } 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 // is on the executing stack, or as a handle in vm code, this constant pool @@ -175,6 +198,9 @@ bool on_stack() const { return (_flags &_on_stack) != 0; } 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 InstanceKlass* pool_holder() const { return _pool_holder; } void set_pool_holder(InstanceKlass* k) { _pool_holder = k; } @@ -193,9 +219,14 @@ // resolved strings, methodHandles and callsite objects from the constant pool objArrayOop resolved_references() const; // 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); + void set_resolved_klasses(Array* rk) { _resolved_klasses = rk; } + Array* 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. // They must look completely different from normal indexes. // The main reason is that byte swapping is sometimes done on normal indexes. @@ -223,30 +254,27 @@ static int tags_offset_in_bytes() { return offset_of(ConstantPool, _tags); } 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 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 - 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 void klass_index_at_put(int which, int name_index) { tag_at_put(which, JVM_CONSTANT_ClassIndex); *int_at_addr(which) = name_index; } - // Temporary until actual use - void unresolved_klass_at_put(int which, Symbol* s) { + // Anonymous class support: + 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); - 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) { @@ -266,7 +294,7 @@ void unresolved_string_at_put(int which, Symbol* s) { 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) { @@ -348,17 +376,38 @@ 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. + 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 guarantee(tag_at(which).is_klass(), "Corrupted constant pool"); // Must do an acquire here in case another thread resolved the klass // 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: 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) { assert(tag_at(which).is_int(), "Corrupted constant pool"); @@ -428,7 +477,7 @@ void pseudo_string_at_put(int which, int obj_index, oop x) { assert(tag_at(which).is_string(), "Corrupted constant pool"); 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 } @@ -759,9 +808,9 @@ private: - void set_resolved_references(jobject s) { _resolved_references = s; } - Array* reference_map() const { return _reference_map; } - void set_reference_map(Array* o) { _reference_map = o; } + void set_resolved_references(jobject s) { _cache->set_resolved_references(s); } + Array* reference_map() const { return (_cache == NULL) ? NULL : _cache->reference_map(); } + void set_reference_map(Array* o) { _cache->set_reference_map(o); } // patch JSR 292 resolved references after the class is linked. void patch_resolved_references(GrowableArray* cp_patches); --- old/src/share/vm/oops/cpCache.hpp 2017-04-16 02:30:39.953377916 -0700 +++ new/src/share/vm/oops/cpCache.hpp 2017-04-16 02:30:39.769371016 -0700 @@ -402,6 +402,13 @@ int _length; 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* _reference_map; + // Sizing debug_only(friend class ClassVerifier;) @@ -431,6 +438,15 @@ bool is_constantPoolCache() const { return true; } int length() const { return _length; } + + jobject resolved_references() { return _resolved_references; } + void set_resolved_references(jobject s) { _resolved_references = s; } + Array* reference_map() const { return _reference_map; } + void set_reference_map(Array* o) { _reference_map = o; } + + // Assembly code support + static int resolved_references_offset_in_bytes() { return offset_of(ConstantPoolCache, _resolved_references); } + private: void set_length(int length) { _length = length; } --- old/src/share/vm/prims/jvmtiRedefineClasses.cpp 2017-04-16 02:30:40.817410314 -0700 +++ new/src/share/vm/prims/jvmtiRedefineClasses.cpp 2017-04-16 02:30:40.633403414 -0700 @@ -292,12 +292,22 @@ // entries in the input constant pool. We revert the appended copy // back to UnresolvedClass so that either verifier will be happy // with the constant pool entry. + // + // this is an indirect CP entry so it needs special handling case JVM_CONSTANT_Class: + case JVM_CONSTANT_UnresolvedClass: { - // revert the copy to JVM_CONSTANT_UnresolvedClass - (*merge_cp_p)->unresolved_klass_at_put(*merge_cp_length_p, - scratch_cp->klass_name_at(scratch_i)); + int name_i = scratch_cp->klass_name_index_at(scratch_i); + int new_name_i = find_or_append_indirect_entry(scratch_cp, name_i, merge_cp_p, + 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) { // 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. @@ -330,10 +340,6 @@ // This was an indirect CP entry, but it has been changed into // Symbol*s so this entry can be directly appended. 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, THREAD); @@ -504,7 +510,7 @@ (*merge_cp_length_p)++; } 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 case JVM_CONSTANT_ClassIndex: // fall through @@ -1270,8 +1276,8 @@ // revert the copy to JVM_CONSTANT_UnresolvedClass // May be resolving while calling this so do the same for // JVM_CONSTANT_UnresolvedClass (klass_name_at() deals with transition) - (*merge_cp_p)->unresolved_klass_at_put(old_i, - old_cp->klass_name_at(old_i)); + (*merge_cp_p)->temp_unresolved_klass_at_put(old_i, + old_cp->klass_name_index_at(old_i)); break; case JVM_CONSTANT_Double: @@ -3102,6 +3108,7 @@ // attach new constant pool to klass scratch_class->set_constants(scratch_cp()); + scratch_cp->initialize_unresolved_klasses(loader_data, CHECK); int i; // for portability --- old/src/share/vm/runtime/vmStructs.cpp 2017-04-16 02:30:41.809447559 -0700 +++ new/src/share/vm/runtime/vmStructs.cpp 2017-04-16 02:30:41.621440497 -0700 @@ -237,8 +237,8 @@ nonstatic_field(ConstantPool, _pool_holder, InstanceKlass*) \ nonstatic_field(ConstantPool, _operands, Array*) \ nonstatic_field(ConstantPool, _length, int) \ - nonstatic_field(ConstantPool, _resolved_references, jobject) \ - nonstatic_field(ConstantPool, _reference_map, Array*) \ + nonstatic_field(ConstantPoolCache, _resolved_references, jobject) \ + nonstatic_field(ConstantPoolCache, _reference_map, Array*) \ nonstatic_field(ConstantPoolCache, _length, int) \ nonstatic_field(ConstantPoolCache, _constant_pool, ConstantPool*) \ volatile_nonstatic_field(InstanceKlass, _array_klasses, Klass*) \ --- old/test/runtime/SharedArchiveFile/LimitSharedSizes.java 2017-04-16 02:30:42.769483612 -0700 +++ new/test/runtime/SharedArchiveFile/LimitSharedSizes.java 2017-04-16 02:30:42.577476401 -0700 @@ -127,7 +127,7 @@ // test with sizes which just meet the minimum required sizes // 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.MD, Platform.is64bit() ? "4M":"2M", Result.VALID_ARCHIVE), new SharedSizeTestData(Region.MC, "120k", Result.VALID_ARCHIVE),