# HG changeset patch # User trims # Date 1301101485 25200 # Node ID c10b82a05d5857a2e7283fba92163a3a15659f3c # Parent 661c46a8434c3cf78705bc70f96c8194bf05076f# Parent 006b3750a4d439947e7c626ee21bfb5f5c8b4c64 Merge diff -r 661c46a8434c -r c10b82a05d58 agent/src/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java --- a/agent/src/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java Fri Mar 25 17:26:33 2011 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/jdi/FieldImpl.java Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, 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 @@ -62,7 +62,7 @@ // get the value of static field ValueImpl getValue() { - return getValue(saField.getFieldHolder()); + return getValue(saField.getFieldHolder().getJavaMirror()); } // get the value of this Field from a specific Oop diff -r 661c46a8434c -r c10b82a05d58 agent/src/share/classes/sun/jvm/hotspot/memory/StringTable.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/StringTable.java Fri Mar 25 17:26:33 2011 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/StringTable.java Fri Mar 25 18:04:45 2011 -0700 @@ -44,12 +44,10 @@ private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("StringTable"); theTableField = type.getAddressField("_the_table"); - stringTableSize = db.lookupIntConstant("StringTable::string_table_size").intValue(); } // Fields private static AddressField theTableField; - private static int stringTableSize; // Accessors public static StringTable getTheTable() { @@ -57,10 +55,6 @@ return (StringTable) VMObjectFactory.newObject(StringTable.class, tmp); } - public static int getStringTableSize() { - return stringTableSize; - } - public StringTable(Address addr) { super(addr); } diff -r 661c46a8434c -r c10b82a05d58 agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Fri Mar 25 17:26:33 2011 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,7 @@ innerClasses = new OopField(type.getOopField("_inner_classes"), Oop.getHeaderSize()); nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), Oop.getHeaderSize()); staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), Oop.getHeaderSize()); - staticOopFieldSize = new CIntField(type.getCIntegerField("_static_oop_field_size"), Oop.getHeaderSize()); + staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), Oop.getHeaderSize()); nonstaticOopMapSize = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), Oop.getHeaderSize()); isMarkedDependent = new CIntField(type.getCIntegerField("_is_marked_dependent"), Oop.getHeaderSize()); initState = new CIntField(type.getCIntegerField("_init_state"), Oop.getHeaderSize()); @@ -140,7 +140,7 @@ private static OopField innerClasses; private static CIntField nonstaticFieldSize; private static CIntField staticFieldSize; - private static CIntField staticOopFieldSize; + private static CIntField staticOopFieldCount; private static CIntField nonstaticOopMapSize; private static CIntField isMarkedDependent; private static CIntField initState; @@ -261,8 +261,7 @@ public Symbol getSourceDebugExtension(){ return getSymbol(sourceDebugExtension); } public TypeArray getInnerClasses() { return (TypeArray) innerClasses.getValue(this); } public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); } - public long getStaticFieldSize() { return staticFieldSize.getValue(this); } - public long getStaticOopFieldSize() { return staticOopFieldSize.getValue(this); } + public long getStaticOopFieldCount() { return staticOopFieldCount.getValue(this); } public long getNonstaticOopMapSize() { return nonstaticOopMapSize.getValue(this); } public boolean getIsMarkedDependent() { return isMarkedDependent.getValue(this) != 0; } public long getVtableLen() { return vtableLen.getValue(this); } @@ -453,7 +452,7 @@ visitor.doOop(innerClasses, true); visitor.doCInt(nonstaticFieldSize, true); visitor.doCInt(staticFieldSize, true); - visitor.doCInt(staticOopFieldSize, true); + visitor.doCInt(staticOopFieldCount, true); visitor.doCInt(nonstaticOopMapSize, true); visitor.doCInt(isMarkedDependent, true); visitor.doCInt(initState, true); @@ -692,7 +691,7 @@ public long getObjectSize() { long bodySize = alignObjectOffset(getVtableLen() * getHeap().getOopSize()) + alignObjectOffset(getItableLen() * getHeap().getOopSize()) - + (getStaticFieldSize() + getNonstaticOopMapSize()) * getHeap().getOopSize(); + + (getNonstaticOopMapSize()) * getHeap().getOopSize(); return alignObjectSize(headerSize + bodySize); } diff -r 661c46a8434c -r c10b82a05d58 agent/src/share/classes/sun/jvm/hotspot/oops/IntField.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/IntField.java Fri Mar 25 17:26:33 2011 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/IntField.java Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,12 @@ super(holder, fieldArrayIndex); } - public int getValue(Oop obj) { return obj.getHandle().getJIntAt(getOffset()); } + public int getValue(Oop obj) { + if (!isVMField() && !obj.isInstance() && !obj.isArray()) { + throw new InternalError(obj.toString()); + } + return obj.getHandle().getJIntAt(getOffset()); + } public void setValue(Oop obj, int value) throws MutationException { // Fix this: setJIntAt is missing in Address } diff -r 661c46a8434c -r c10b82a05d58 agent/src/share/classes/sun/jvm/hotspot/oops/OopField.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/OopField.java Fri Mar 25 17:26:33 2011 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/OopField.java Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -41,11 +41,17 @@ } public Oop getValue(Oop obj) { + if (!isVMField() && !obj.isInstance() && !obj.isArray()) { + throw new InternalError(); + } return obj.getHeap().newOop(getValueAsOopHandle(obj)); } /** Debugging support */ public OopHandle getValueAsOopHandle(Oop obj) { + if (!isVMField() && !obj.isInstance() && !obj.isArray()) { + throw new InternalError(obj.toString()); + } return obj.getHandle().getOopHandleAt(getOffset()); } diff -r 661c46a8434c -r c10b82a05d58 agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java Fri Mar 25 17:26:33 2011 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/OopUtilities.java Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -274,13 +274,7 @@ // hc_klass is a HotSpot magic field and hence we can't // find it from InstanceKlass for java.lang.Class. TypeDataBase db = VM.getVM().getTypeDataBase(); - int hcKlassOffset = (int) Instance.getHeaderSize(); - try { - hcKlassOffset += (db.lookupIntConstant("java_lang_Class::hc_klass_offset").intValue() * - VM.getVM().getHeapOopSize()); - } catch (RuntimeException re) { - // ignore, currently java_lang_Class::hc_klass_offset is zero - } + int hcKlassOffset = (int) db.lookupType("java_lang_Class").getCIntegerField("klass_offset").getValue(); if (VM.getVM().isCompressedOopsEnabled()) { hcKlassField = new NarrowOopField(new NamedFieldIdentifier("hc_klass"), hcKlassOffset, true); } else { diff -r 661c46a8434c -r c10b82a05d58 agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java --- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Fri Mar 25 17:26:33 2011 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -839,13 +839,13 @@ } private void readSystemProperties() { - InstanceKlass systemKls = getSystemDictionary().getSystemKlass(); + final InstanceKlass systemKls = getSystemDictionary().getSystemKlass(); systemKls.iterate(new DefaultOopVisitor() { ObjectReader objReader = new ObjectReader(); public void doOop(sun.jvm.hotspot.oops.OopField field, boolean isVMField) { if (field.getID().getName().equals("props")) { try { - sysProps = (Properties) objReader.readObject(field.getValue(getObj())); + sysProps = (Properties) objReader.readObject(field.getValue(systemKls.getJavaMirror())); } catch (Exception e) { if (Assert.ASSERTS_ENABLED) { e.printStackTrace(); diff -r 661c46a8434c -r c10b82a05d58 agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java --- a/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Fri Mar 25 17:26:33 2011 -0700 +++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2011, 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 @@ -746,7 +746,7 @@ out.writeByte((byte)kind); if (ik != null) { // static field - writeField(field, ik); + writeField(field, ik.getJavaMirror()); } } } diff -r 661c46a8434c -r c10b82a05d58 agent/test/jdi/sasanity.sh --- a/agent/test/jdi/sasanity.sh Fri Mar 25 17:26:33 2011 -0700 +++ b/agent/test/jdi/sasanity.sh Fri Mar 25 18:04:45 2011 -0700 @@ -43,6 +43,7 @@ fi jdk=$1 +shift OS=`uname` if [ "$OS" != "Linux" ]; then @@ -68,7 +69,7 @@ tmp=/tmp/sagsetup rm -f $tmp -$jdk/bin/java sagtarg > $tmp & +$jdk/bin/java $* sagtarg > $tmp & pid=$! while [ ! -s $tmp ] ; do # Kludge alert! diff -r 661c46a8434c -r c10b82a05d58 src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp --- a/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -301,7 +301,8 @@ // thread. assert(_obj != noreg, "must be a valid register"); assert(_oop_index >= 0, "must have oop index"); - __ ld_ptr(_obj, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc), G3); + __ load_heap_oop(_obj, java_lang_Class::klass_offset_in_bytes(), G3); + __ ld_ptr(G3, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc), G3); __ cmp(G2_thread, G3); __ br(Assembler::notEqual, false, Assembler::pn, call_patch); __ delayed()->nop(); diff -r 661c46a8434c -r c10b82a05d58 src/cpu/sparc/vm/dump_sparc.cpp --- a/src/cpu/sparc/vm/dump_sparc.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/cpu/sparc/vm/dump_sparc.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -80,13 +80,19 @@ for (int j = 0; j < num_virtuals; ++j) { dummy_vtable[num_virtuals * i + j] = (void*)masm->pc(); __ save(SP, -256, SP); + int offset = (i << 8) + j; + Register src = G0; + if (!Assembler::is_simm13(offset)) { + __ sethi(offset, L0); + src = L0; + offset = offset & ((1 << 10) - 1); + } __ brx(Assembler::always, false, Assembler::pt, common_code); // Load L0 with a value indicating vtable/offset pair. // -- bits[ 7..0] (8 bits) which virtual method in table? - // -- bits[12..8] (5 bits) which virtual method table? - // -- must fit in 13-bit instruction immediate field. - __ delayed()->set((i << 8) + j, L0); + // -- bits[13..8] (6 bits) which virtual method table? + __ delayed()->or3(src, offset, L0); } } diff -r 661c46a8434c -r c10b82a05d58 src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -775,9 +775,13 @@ switch (ek) { case _adapter_opt_i2l: { - __ ldsw(arg_lsw, O2_scratch); // Load LSW - NOT_LP64(__ srlx(O2_scratch, BitsPerInt, O3_scratch)); // Move high bits to lower bits for std - __ st_long(O2_scratch, arg_msw); // Uses O2/O3 on !_LP64 +#ifdef _LP64 + __ ldsw(arg_lsw, O2_scratch); // Load LSW sign-extended +#else + __ ldsw(arg_lsw, O3_scratch); // Load LSW sign-extended + __ srlx(O3_scratch, BitsPerInt, O2_scratch); // Move MSW value to lower 32-bits for std +#endif + __ st_long(O2_scratch, arg_msw); // Uses O2/O3 on !_LP64 } break; case _adapter_opt_unboxl: diff -r 661c46a8434c -r c10b82a05d58 src/cpu/sparc/vm/nativeInst_sparc.cpp --- a/src/cpu/sparc/vm/nativeInst_sparc.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/cpu/sparc/vm/nativeInst_sparc.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -52,6 +52,22 @@ ICache::invalidate_range(instaddr, 7 * BytesPerInstWord); } +void NativeInstruction::verify_data64_sethi(address instaddr, intptr_t x) { + ResourceMark rm; + unsigned char buffer[10 * BytesPerInstWord]; + CodeBuffer buf(buffer, 10 * BytesPerInstWord); + MacroAssembler masm(&buf); + + Register destreg = inv_rd(*(unsigned int *)instaddr); + // Generate the proper sequence into a temporary buffer and compare + // it with the original sequence. + masm.patchable_sethi(x, destreg); + int len = buffer - masm.pc(); + for (int i = 0; i < len; i++) { + assert(instaddr[i] == buffer[i], "instructions must match"); + } +} + void NativeInstruction::verify() { // make sure code pattern is actually an instruction address address addr = addr_at(0); diff -r 661c46a8434c -r c10b82a05d58 src/cpu/sparc/vm/nativeInst_sparc.hpp --- a/src/cpu/sparc/vm/nativeInst_sparc.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/cpu/sparc/vm/nativeInst_sparc.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -254,6 +254,7 @@ // sethi. This only does the sethi. The disp field (bottom 10 bits) // must be handled separately. static void set_data64_sethi(address instaddr, intptr_t x); + static void verify_data64_sethi(address instaddr, intptr_t x); // combine the fields of a sethi/simm13 pair (simm13 = or, add, jmpl, ld/st) static int data32(int sethi_insn, int arith_insn) { diff -r 661c46a8434c -r c10b82a05d58 src/cpu/sparc/vm/relocInfo_sparc.cpp --- a/src/cpu/sparc/vm/relocInfo_sparc.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/cpu/sparc/vm/relocInfo_sparc.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -30,7 +30,7 @@ #include "oops/oop.inline.hpp" #include "runtime/safepoint.hpp" -void Relocation::pd_set_data_value(address x, intptr_t o) { +void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { NativeInstruction* ip = nativeInstruction_at(addr()); jint inst = ip->long_at(0); assert(inst != NativeInstruction::illegal_instruction(), "no breakpoint"); @@ -83,7 +83,11 @@ guarantee(Assembler::is_simm13(simm13), "offset can't overflow simm13"); inst &= ~Assembler::simm( -1, 13); inst |= Assembler::simm(simm13, 13); - ip->set_long_at(0, inst); + if (verify_only) { + assert(ip->long_at(0) == inst, "instructions must match"); + } else { + ip->set_long_at(0, inst); + } } break; @@ -97,19 +101,36 @@ jint np = oopDesc::encode_heap_oop((oop)x); inst &= ~Assembler::hi22(-1); inst |= Assembler::hi22((intptr_t)np); - ip->set_long_at(0, inst); + if (verify_only) { + assert(ip->long_at(0) == inst, "instructions must match"); + } else { + ip->set_long_at(0, inst); + } inst2 = ip->long_at( NativeInstruction::nop_instruction_size ); guarantee(Assembler::inv_op(inst2)==Assembler::arith_op, "arith op"); - ip->set_long_at(NativeInstruction::nop_instruction_size, ip->set_data32_simm13( inst2, (intptr_t)np)); + if (verify_only) { + assert(ip->long_at(NativeInstruction::nop_instruction_size) == NativeInstruction::set_data32_simm13( inst2, (intptr_t)np), + "instructions must match"); + } else { + ip->set_long_at(NativeInstruction::nop_instruction_size, NativeInstruction::set_data32_simm13( inst2, (intptr_t)np)); + } break; } - ip->set_data64_sethi( ip->addr_at(0), (intptr_t)x ); + if (verify_only) { + ip->verify_data64_sethi( ip->addr_at(0), (intptr_t)x ); + } else { + ip->set_data64_sethi( ip->addr_at(0), (intptr_t)x ); + } #else guarantee(Assembler::inv_op2(inst)==Assembler::sethi_op2, "must be sethi"); inst &= ~Assembler::hi22( -1); inst |= Assembler::hi22((intptr_t)x); // (ignore offset; it doesn't play into the sethi) - ip->set_long_at(0, inst); + if (verify_only) { + assert(ip->long_at(0) == inst, "instructions must match"); + } else { + ip->set_long_at(0, inst); + } #endif } break; diff -r 661c46a8434c -r c10b82a05d58 src/cpu/x86/vm/c1_CodeStubs_x86.cpp --- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -313,10 +313,13 @@ } assert(_obj != noreg, "must be a valid register"); Register tmp = rax; - if (_obj == tmp) tmp = rbx; + Register tmp2 = rbx; __ push(tmp); + __ push(tmp2); + __ load_heap_oop(tmp2, Address(_obj, java_lang_Class::klass_offset_in_bytes())); __ get_thread(tmp); - __ cmpptr(tmp, Address(_obj, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc))); + __ cmpptr(tmp, Address(tmp2, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc))); + __ pop(tmp2); __ pop(tmp); __ jcc(Assembler::notEqual, call_patch); diff -r 661c46a8434c -r c10b82a05d58 src/cpu/x86/vm/relocInfo_x86.cpp --- a/src/cpu/x86/vm/relocInfo_x86.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/cpu/x86/vm/relocInfo_x86.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -31,7 +31,7 @@ #include "runtime/safepoint.hpp" -void Relocation::pd_set_data_value(address x, intptr_t o) { +void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { #ifdef AMD64 x += o; typedef Assembler::WhichOperand WhichOperand; @@ -40,19 +40,35 @@ which == Assembler::narrow_oop_operand || which == Assembler::imm_operand, "format unpacks ok"); if (which == Assembler::imm_operand) { - *pd_address_in_code() = x; + if (verify_only) { + assert(*pd_address_in_code() == x, "instructions must match"); + } else { + *pd_address_in_code() = x; + } } else if (which == Assembler::narrow_oop_operand) { address disp = Assembler::locate_operand(addr(), which); - *(int32_t*) disp = oopDesc::encode_heap_oop((oop)x); + if (verify_only) { + assert(*(uint32_t*) disp == oopDesc::encode_heap_oop((oop)x), "instructions must match"); + } else { + *(int32_t*) disp = oopDesc::encode_heap_oop((oop)x); + } } else { // Note: Use runtime_call_type relocations for call32_operand. address ip = addr(); address disp = Assembler::locate_operand(ip, which); address next_ip = Assembler::locate_next_instruction(ip); - *(int32_t*) disp = x - next_ip; + if (verify_only) { + assert(*(int32_t*) disp == (x - next_ip), "instructions must match"); + } else { + *(int32_t*) disp = x - next_ip; + } } #else - *pd_address_in_code() = x + o; + if (verify_only) { + assert(*pd_address_in_code() == (x + o), "instructions must match"); + } else { + *pd_address_in_code() = x + o; + } #endif // AMD64 } diff -r 661c46a8434c -r c10b82a05d58 src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/src/cpu/zero/vm/cppInterpreter_zero.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -281,7 +281,7 @@ if (method->is_static()) { istate->set_oop_temp( - method->constants()->pool_holder()->klass_part()->java_mirror()); + method->constants()->pool_holder()->java_mirror()); mirror = istate->oop_temp_addr(); *(dst++) = &mirror; } @@ -667,7 +667,7 @@ (BasicObjectLock *) stack->alloc(monitor_words * wordSize); oop object; if (method->is_static()) - object = method->constants()->pool_holder()->klass_part()->java_mirror(); + object = method->constants()->pool_holder()->java_mirror(); else object = (oop) locals[0]; monitor->set_obj(object); diff -r 661c46a8434c -r c10b82a05d58 src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/os/windows/vm/os_windows.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -3297,9 +3297,14 @@ "possibility of dangling Thread pointer"); OSThread* osthread = thread->osthread(); - bool interrupted; - interrupted = osthread->interrupted(); - if (clear_interrupted == true) { + bool interrupted = osthread->interrupted(); + // There is no synchronization between the setting of the interrupt + // and it being cleared here. It is critical - see 6535709 - that + // we only clear the interrupt state, and reset the interrupt event, + // if we are going to report that we were indeed interrupted - else + // an interrupt can be "lost", leading to spurious wakeups or lost wakeups + // depending on the timing + if (interrupted && clear_interrupted) { osthread->set_interrupted(false); ResetEvent(osthread->interrupt_event()); } // Otherwise leave the interrupted state alone diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1471,9 +1471,9 @@ if (code == Bytecodes::_getstatic || code == Bytecodes::_putstatic) { if (state_before != NULL) { // build a patching constant - obj = new Constant(new ClassConstant(holder), state_before); + obj = new Constant(new InstanceConstant(holder->java_mirror()), state_before); } else { - obj = new Constant(new ClassConstant(holder)); + obj = new Constant(new InstanceConstant(holder->java_mirror())); } } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/c1/c1_Runtime1.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -808,7 +808,7 @@ { klassOop klass = resolve_field_return_klass(caller_method, bci, CHECK); // Save a reference to the class that has to be checked for initialization init_klass = KlassHandle(THREAD, klass); - k = klass; + k = klass->java_mirror(); } break; case Bytecodes::_new: diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/ci/ciCPCache.cpp --- a/src/share/vm/ci/ciCPCache.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/ci/ciCPCache.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2011, 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 @@ -46,8 +46,7 @@ // ciCPCache::is_f1_null_at bool ciCPCache::is_f1_null_at(int index) { VM_ENTRY_MARK; - oop f1 = entry_at(index)->f1(); - return (f1 == NULL); + return entry_at(index)->is_f1_null(); } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/ci/ciField.cpp --- a/src/share/vm/ci/ciField.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/ci/ciField.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -213,7 +213,7 @@ // may change. The three examples are java.lang.System.in, // java.lang.System.out, and java.lang.System.err. - Handle k = _holder->get_klassOop(); + KlassHandle k = _holder->get_klassOop(); assert( SystemDictionary::System_klass() != NULL, "Check once per vm"); if( k() == SystemDictionary::System_klass() ) { // Check offsets for case 2: System.in, System.out, or System.err @@ -225,36 +225,38 @@ } } + Handle mirror = k->java_mirror(); + _is_constant = true; switch(type()->basic_type()) { case T_BYTE: - _constant_value = ciConstant(type()->basic_type(), k->byte_field(_offset)); + _constant_value = ciConstant(type()->basic_type(), mirror->byte_field(_offset)); break; case T_CHAR: - _constant_value = ciConstant(type()->basic_type(), k->char_field(_offset)); + _constant_value = ciConstant(type()->basic_type(), mirror->char_field(_offset)); break; case T_SHORT: - _constant_value = ciConstant(type()->basic_type(), k->short_field(_offset)); + _constant_value = ciConstant(type()->basic_type(), mirror->short_field(_offset)); break; case T_BOOLEAN: - _constant_value = ciConstant(type()->basic_type(), k->bool_field(_offset)); + _constant_value = ciConstant(type()->basic_type(), mirror->bool_field(_offset)); break; case T_INT: - _constant_value = ciConstant(type()->basic_type(), k->int_field(_offset)); + _constant_value = ciConstant(type()->basic_type(), mirror->int_field(_offset)); break; case T_FLOAT: - _constant_value = ciConstant(k->float_field(_offset)); + _constant_value = ciConstant(mirror->float_field(_offset)); break; case T_DOUBLE: - _constant_value = ciConstant(k->double_field(_offset)); + _constant_value = ciConstant(mirror->double_field(_offset)); break; case T_LONG: - _constant_value = ciConstant(k->long_field(_offset)); + _constant_value = ciConstant(mirror->long_field(_offset)); break; case T_OBJECT: case T_ARRAY: { - oop o = k->obj_field(_offset); + oop o = mirror->obj_field(_offset); // A field will be "constant" if it is known always to be // a non-null reference to an instance of a particular class, diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/ci/ciInstance.cpp --- a/src/share/vm/ci/ciInstance.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/ci/ciInstance.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, 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 @@ -138,3 +138,9 @@ st->print(" type="); klass()->print(st); } + + +ciKlass* ciInstance::java_lang_Class_klass() { + VM_ENTRY_MARK; + return CURRENT_ENV->get_object(java_lang_Class::as_klassOop(get_oop()))->as_klass(); +} diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/ci/ciInstance.hpp --- a/src/share/vm/ci/ciInstance.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/ci/ciInstance.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, 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,6 +64,8 @@ // Constant value of a field at the specified offset. ciConstant field_value_by_offset(int field_offset); + + ciKlass* java_lang_Class_klass(); }; #endif // SHARE_VM_CI_CIINSTANCE_HPP diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/ci/ciInstanceKlass.cpp --- a/src/share/vm/ci/ciInstanceKlass.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/ci/ciInstanceKlass.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, 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 @@ -85,7 +85,6 @@ if (h_k() != SystemDictionary::Object_klass()) { super(); } - java_mirror(); //compute_nonstatic_fields(); // done outside of constructor } @@ -320,6 +319,9 @@ // Get the instance of java.lang.Class corresponding to this klass. // Cache it on this->_java_mirror. ciInstance* ciInstanceKlass::java_mirror() { + if (is_shared()) { + return ciKlass::java_mirror(); + } if (_java_mirror == NULL) { _java_mirror = ciKlass::java_mirror(); } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/ci/ciObjectFactory.cpp --- a/src/share/vm/ci/ciObjectFactory.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/ci/ciObjectFactory.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -663,7 +663,7 @@ if (key->is_perm() && _non_perm_count == 0) { return emptyBucket; } else if (key->is_instance()) { - if (key->klass() == SystemDictionary::Class_klass()) { + if (key->klass() == SystemDictionary::Class_klass() && JavaObjectsInPerm) { // class mirror instances are always perm return emptyBucket; } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/classfile/classFileParser.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -37,6 +37,7 @@ #include "memory/universe.inline.hpp" #include "oops/constantPoolOop.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/klassOop.hpp" #include "oops/klassVtable.hpp" @@ -2606,54 +2607,6 @@ } -static void initialize_static_field(fieldDescriptor* fd, TRAPS) { - KlassHandle h_k (THREAD, fd->field_holder()); - assert(h_k.not_null() && fd->is_static(), "just checking"); - if (fd->has_initial_value()) { - BasicType t = fd->field_type(); - switch (t) { - case T_BYTE: - h_k()->byte_field_put(fd->offset(), fd->int_initial_value()); - break; - case T_BOOLEAN: - h_k()->bool_field_put(fd->offset(), fd->int_initial_value()); - break; - case T_CHAR: - h_k()->char_field_put(fd->offset(), fd->int_initial_value()); - break; - case T_SHORT: - h_k()->short_field_put(fd->offset(), fd->int_initial_value()); - break; - case T_INT: - h_k()->int_field_put(fd->offset(), fd->int_initial_value()); - break; - case T_FLOAT: - h_k()->float_field_put(fd->offset(), fd->float_initial_value()); - break; - case T_DOUBLE: - h_k()->double_field_put(fd->offset(), fd->double_initial_value()); - break; - case T_LONG: - h_k()->long_field_put(fd->offset(), fd->long_initial_value()); - break; - case T_OBJECT: - { - #ifdef ASSERT - TempNewSymbol sym = SymbolTable::new_symbol("Ljava/lang/String;", CHECK); - assert(fd->signature() == sym, "just checking"); - #endif - oop string = fd->string_initial_value(CHECK); - h_k()->obj_field_put(fd->offset(), string); - } - break; - default: - THROW_MSG(vmSymbols::java_lang_ClassFormatError(), - "Illegal ConstantValue attribute in class file"); - } - } -} - - void ClassFileParser::java_lang_ref_Reference_fix_pre(typeArrayHandle* fields_ptr, constantPoolHandle cp, FieldAllocationCount *fac_ptr, TRAPS) { // This code is for compatibility with earlier jdk's that do not @@ -2769,8 +2722,8 @@ } -void ClassFileParser::java_lang_Class_fix_pre(objArrayHandle* methods_ptr, - FieldAllocationCount *fac_ptr, TRAPS) { +void ClassFileParser::java_lang_Class_fix_pre(int* nonstatic_field_size, + FieldAllocationCount *fac_ptr) { // Add fake fields for java.lang.Class instances // // This is not particularly nice. We should consider adding a @@ -2787,10 +2740,13 @@ // versions because when the offsets are computed at bootstrap // time we don't know yet which version of the JDK we're running in. - // The values below are fake but will force two non-static oop fields and + // The values below are fake but will force three non-static oop fields and // a corresponding non-static oop map block to be allocated. const int extra = java_lang_Class::number_of_fake_oop_fields; fac_ptr->nonstatic_oop_count += extra; + + // Reserve some leading space for fake ints + *nonstatic_field_size += align_size_up(java_lang_Class::hc_number_of_fake_int_fields * BytesPerInt, heapOopSize) / heapOopSize; } @@ -3205,9 +3161,7 @@ int next_nonstatic_field_offset; // Calculate the starting byte offsets - next_static_oop_offset = (instanceKlass::header_size() + - align_object_offset(vtable_size) + - align_object_offset(itable_size)) * wordSize; + next_static_oop_offset = instanceMirrorKlass::offset_of_static_fields(); next_static_double_offset = next_static_oop_offset + (fac.static_oop_count * heapOopSize); if ( fac.static_double_count && @@ -3226,15 +3180,16 @@ fac.static_byte_count ), wordSize ); static_field_size = (next_static_type_offset - next_static_oop_offset) / wordSize; + + // Add fake fields for java.lang.Class instances (also see below) + if (class_name == vmSymbols::java_lang_Class() && class_loader.is_null()) { + java_lang_Class_fix_pre(&nonstatic_field_size, &fac); + } + first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size * heapOopSize; next_nonstatic_field_offset = first_nonstatic_field_offset; - // Add fake fields for java.lang.Class instances (also see below) - if (class_name == vmSymbols::java_lang_Class() && class_loader.is_null()) { - java_lang_Class_fix_pre(&methods, &fac, CHECK_(nullHandle)); - } - // adjust the vmentry field declaration in java.lang.invoke.MethodHandle if (EnableMethodHandles && class_name == vmSymbols::java_lang_invoke_MethodHandle() && class_loader.is_null()) { java_lang_invoke_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle)); @@ -3566,7 +3521,7 @@ } // We can now create the basic klassOop for this klass - klassOop ik = oopFactory::new_instanceKlass(vtable_size, itable_size, + klassOop ik = oopFactory::new_instanceKlass(name, vtable_size, itable_size, static_field_size, total_oop_map_count, rt, CHECK_(nullHandle)); @@ -3588,7 +3543,7 @@ this_klass->set_class_loader(class_loader()); this_klass->set_nonstatic_field_size(nonstatic_field_size); this_klass->set_has_nonstatic_fields(has_nonstatic_fields); - this_klass->set_static_oop_field_size(fac.static_oop_count); + this_klass->set_static_oop_field_count(fac.static_oop_count); cp->set_pool_holder(this_klass()); error_handler.set_in_error(false); // turn off error handler for cp this_klass->set_constants(cp()); @@ -3649,9 +3604,6 @@ // Make sure this is the end of class file stream guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle)); - // Initialize static fields - this_klass->do_local_static_fields(&initialize_static_field, CHECK_(nullHandle)); - // VerifyOops believes that once this has been set, the object is completely loaded. // Compute transitive closure of interfaces this class implements this_klass->set_transitive_interfaces(transitive_interfaces()); @@ -3685,6 +3637,9 @@ check_illegal_static_method(this_klass, CHECK_(nullHandle)); } + // Allocate mirror and initialize static fields + java_lang_Class::create_mirror(this_klass, CHECK_(nullHandle)); + ClassLoadingService::notify_class_loaded(instanceKlass::cast(this_klass()), false /* not shared class */); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/classfile/classFileParser.hpp --- a/src/share/vm/classfile/classFileParser.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/classfile/classFileParser.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -154,11 +154,12 @@ // Add the "discovered" field to java.lang.ref.Reference if // it does not exist. void java_lang_ref_Reference_fix_pre(typeArrayHandle* fields_ptr, - constantPoolHandle cp, FieldAllocationCount *fac_ptr, TRAPS); + constantPoolHandle cp, + FieldAllocationCount *fac_ptr, TRAPS); // Adjust the field allocation counts for java.lang.Class to add // fake fields. - void java_lang_Class_fix_pre(objArrayHandle* methods_ptr, - FieldAllocationCount *fac_ptr, TRAPS); + void java_lang_Class_fix_pre(int* nonstatic_field_size, + FieldAllocationCount *fac_ptr); // Adjust the next_nonstatic_oop_offset to place the fake fields // before any Java fields. void java_lang_Class_fix_post(int* next_nonstatic_oop_offset); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/classfile/javaClasses.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -33,6 +33,7 @@ #include "memory/resourceArea.hpp" #include "memory/universe.inline.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/klass.hpp" #include "oops/klassOop.hpp" #include "oops/methodOop.hpp" @@ -161,7 +162,7 @@ } Handle java_lang_String::create_tenured_from_unicode(jchar* unicode, int length, TRAPS) { - return basic_create_from_unicode(unicode, length, true, CHECK_NH); + return basic_create_from_unicode(unicode, length, JavaObjectsInPerm, CHECK_NH); } oop java_lang_String::create_oop_from_unicode(jchar* unicode, int length, TRAPS) { @@ -391,6 +392,75 @@ } } +static void initialize_static_field(fieldDescriptor* fd, TRAPS) { + Handle mirror (THREAD, fd->field_holder()->java_mirror()); + assert(mirror.not_null() && fd->is_static(), "just checking"); + if (fd->has_initial_value()) { + BasicType t = fd->field_type(); + switch (t) { + case T_BYTE: + mirror()->byte_field_put(fd->offset(), fd->int_initial_value()); + break; + case T_BOOLEAN: + mirror()->bool_field_put(fd->offset(), fd->int_initial_value()); + break; + case T_CHAR: + mirror()->char_field_put(fd->offset(), fd->int_initial_value()); + break; + case T_SHORT: + mirror()->short_field_put(fd->offset(), fd->int_initial_value()); + break; + case T_INT: + mirror()->int_field_put(fd->offset(), fd->int_initial_value()); + break; + case T_FLOAT: + mirror()->float_field_put(fd->offset(), fd->float_initial_value()); + break; + case T_DOUBLE: + mirror()->double_field_put(fd->offset(), fd->double_initial_value()); + break; + case T_LONG: + mirror()->long_field_put(fd->offset(), fd->long_initial_value()); + break; + case T_OBJECT: + { + #ifdef ASSERT + TempNewSymbol sym = SymbolTable::new_symbol("Ljava/lang/String;", CHECK); + assert(fd->signature() == sym, "just checking"); + #endif + oop string = fd->string_initial_value(CHECK); + mirror()->obj_field_put(fd->offset(), string); + } + break; + default: + THROW_MSG(vmSymbols::java_lang_ClassFormatError(), + "Illegal ConstantValue attribute in class file"); + } + } +} + + +// During bootstrap, java.lang.Class wasn't loaded so static field +// offsets were computed without the size added it. Go back and +// update all the static field offsets to included the size. +static void fixup_static_field(fieldDescriptor* fd, TRAPS) { + if (fd->is_static()) { + int real_offset = fd->offset() + instanceMirrorKlass::offset_of_static_fields(); + typeArrayOop fields = instanceKlass::cast(fd->field_holder())->fields(); + fields->short_at_put(fd->index() + instanceKlass::low_offset, extract_low_short_from_int(real_offset)); + fields->short_at_put(fd->index() + instanceKlass::high_offset, extract_high_short_from_int(real_offset)); + } +} + +void java_lang_Class::fixup_mirror(KlassHandle k, TRAPS) { + assert(instanceMirrorKlass::offset_of_static_fields() != 0, "must have been computed already"); + + if (k->oop_is_instance()) { + // Fixup the offsets + instanceKlass::cast(k())->do_local_static_fields(&fixup_static_field, CHECK); + } + create_mirror(k, CHECK); +} oop java_lang_Class::create_mirror(KlassHandle k, TRAPS) { assert(k->java_mirror() == NULL, "should only assign mirror once"); @@ -400,12 +470,17 @@ // class is put into the system dictionary. int computed_modifiers = k->compute_modifier_flags(CHECK_0); k->set_modifier_flags(computed_modifiers); - if (SystemDictionary::Class_klass_loaded()) { + if (SystemDictionary::Class_klass_loaded() && (k->oop_is_instance() || k->oop_is_javaArray())) { // Allocate mirror (java.lang.Class instance) - Handle mirror = instanceKlass::cast(SystemDictionary::Class_klass())->allocate_permanent_instance(CHECK_0); + Handle mirror = instanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance(k, CHECK_0); // Setup indirections mirror->obj_field_put(klass_offset, k()); k->set_java_mirror(mirror()); + + instanceMirrorKlass* mk = instanceMirrorKlass::cast(mirror->klass()); + java_lang_Class::set_oop_size(mirror(), mk->instance_size(k)); + java_lang_Class::set_static_oop_field_count(mirror(), mk->compute_static_oop_field_count(mirror())); + // It might also have a component mirror. This mirror must already exist. if (k->oop_is_javaArray()) { Handle comp_mirror; @@ -428,6 +503,9 @@ arrayKlass::cast(k->as_klassOop())->set_component_mirror(comp_mirror()); set_array_klass(comp_mirror(), k->as_klassOop()); } + } else if (k->oop_is_instance()) { + // Initialize static fields + instanceKlass::cast(k())->do_local_static_fields(&initialize_static_field, CHECK_NULL); } return mirror(); } else { @@ -436,21 +514,46 @@ } + +int java_lang_Class::oop_size(oop java_class) { + assert(oop_size_offset != 0, "must be set"); + return java_class->int_field(oop_size_offset); +} +void java_lang_Class::set_oop_size(oop java_class, int size) { + assert(oop_size_offset != 0, "must be set"); + java_class->int_field_put(oop_size_offset, size); +} +int java_lang_Class::static_oop_field_count(oop java_class) { + assert(static_oop_field_count_offset != 0, "must be set"); + return java_class->int_field(static_oop_field_count_offset); +} +void java_lang_Class::set_static_oop_field_count(oop java_class, int size) { + assert(static_oop_field_count_offset != 0, "must be set"); + java_class->int_field_put(static_oop_field_count_offset, size); +} + + + + oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) { // This should be improved by adding a field at the Java level or by // introducing a new VM klass (see comment in ClassFileParser) - oop java_class = instanceKlass::cast(SystemDictionary::Class_klass())->allocate_permanent_instance(CHECK_0); + oop java_class = instanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance((oop)NULL, CHECK_0); if (type != T_VOID) { klassOop aklass = Universe::typeArrayKlassObj(type); assert(aklass != NULL, "correct bootstrap"); set_array_klass(java_class, aklass); } + instanceMirrorKlass* mk = instanceMirrorKlass::cast(SystemDictionary::Class_klass()); + java_lang_Class::set_oop_size(java_class, mk->instance_size(oop(NULL))); + java_lang_Class::set_static_oop_field_count(java_class, 0); return java_class; } klassOop java_lang_Class::as_klassOop(oop java_class) { //%note memory_2 + assert(java_lang_Class::is_instance(java_class), "must be a Class object"); klassOop k = klassOop(java_class->obj_field(klass_offset)); assert(k == NULL || k->is_klass(), "type check"); return k; @@ -2152,7 +2255,7 @@ // Support for java_lang_ref_Reference oop java_lang_ref_Reference::pending_list_lock() { instanceKlass* ik = instanceKlass::cast(SystemDictionary::Reference_klass()); - char *addr = (((char *)ik->start_of_static_fields()) + static_lock_offset); + address addr = ik->static_field_addr(static_lock_offset); if (UseCompressedOops) { return oopDesc::load_decode_heap_oop((narrowOop *)addr); } else { @@ -2162,7 +2265,7 @@ HeapWord *java_lang_ref_Reference::pending_list_addr() { instanceKlass* ik = instanceKlass::cast(SystemDictionary::Reference_klass()); - char *addr = (((char *)ik->start_of_static_fields()) + static_pending_offset); + address addr = ik->static_field_addr(static_pending_offset); // XXX This might not be HeapWord aligned, almost rather be char *. return (HeapWord*)addr; } @@ -2185,16 +2288,14 @@ jlong java_lang_ref_SoftReference::clock() { instanceKlass* ik = instanceKlass::cast(SystemDictionary::SoftReference_klass()); - int offset = ik->offset_of_static_fields() + static_clock_offset; - - return SystemDictionary::SoftReference_klass()->long_field(offset); + jlong* offset = (jlong*)ik->static_field_addr(static_clock_offset); + return *offset; } void java_lang_ref_SoftReference::set_clock(jlong value) { instanceKlass* ik = instanceKlass::cast(SystemDictionary::SoftReference_klass()); - int offset = ik->offset_of_static_fields() + static_clock_offset; - - SystemDictionary::SoftReference_klass()->long_field_put(offset, value); + jlong* offset = (jlong*)ik->static_field_addr(static_clock_offset); + *offset = value; } @@ -2625,26 +2726,18 @@ // Support for java_lang_System - -void java_lang_System::compute_offsets() { - assert(offset_of_static_fields == 0, "offsets should be initialized only once"); - - instanceKlass* ik = instanceKlass::cast(SystemDictionary::System_klass()); - offset_of_static_fields = ik->offset_of_static_fields(); -} - int java_lang_System::in_offset_in_bytes() { - return (offset_of_static_fields + static_in_offset); + return (instanceMirrorKlass::offset_of_static_fields() + static_in_offset); } int java_lang_System::out_offset_in_bytes() { - return (offset_of_static_fields + static_out_offset); + return (instanceMirrorKlass::offset_of_static_fields() + static_out_offset); } int java_lang_System::err_offset_in_bytes() { - return (offset_of_static_fields + static_err_offset); + return (instanceMirrorKlass::offset_of_static_fields() + static_err_offset); } @@ -2657,6 +2750,8 @@ int java_lang_Class::array_klass_offset; int java_lang_Class::resolved_constructor_offset; int java_lang_Class::number_of_fake_oop_fields; +int java_lang_Class::oop_size_offset; +int java_lang_Class::static_oop_field_count_offset; int java_lang_Throwable::backtrace_offset; int java_lang_Throwable::detailMessage_offset; int java_lang_Throwable::cause_offset; @@ -2700,7 +2795,6 @@ int java_lang_ref_SoftReference::timestamp_offset; int java_lang_ref_SoftReference::static_clock_offset; int java_lang_ClassLoader::parent_offset; -int java_lang_System::offset_of_static_fields; int java_lang_System::static_in_offset; int java_lang_System::static_out_offset; int java_lang_System::static_err_offset; @@ -2817,10 +2911,19 @@ java_lang_String::count_offset = java_lang_String::offset_offset + sizeof (jint); java_lang_String::hash_offset = java_lang_String::count_offset + sizeof (jint); - // Do the Class Class - java_lang_Class::klass_offset = java_lang_Class::hc_klass_offset * x + header; - java_lang_Class::array_klass_offset = java_lang_Class::hc_array_klass_offset * x + header; - java_lang_Class::resolved_constructor_offset = java_lang_Class::hc_resolved_constructor_offset * x + header; + { + // Do the Class Class + int offset = header; + java_lang_Class::oop_size_offset = header; + offset += BytesPerInt; + java_lang_Class::static_oop_field_count_offset = offset; + offset = align_size_up(offset + BytesPerInt, x); + java_lang_Class::klass_offset = offset; + offset += x; + java_lang_Class::array_klass_offset = offset; + offset += x; + java_lang_Class::resolved_constructor_offset = offset; + } // This is NOT an offset java_lang_Class::number_of_fake_oop_fields = java_lang_Class::hc_number_of_fake_oop_fields; @@ -2877,7 +2980,6 @@ void JavaClasses::compute_offsets() { java_lang_Class::compute_offsets(); - java_lang_System::compute_offsets(); java_lang_Thread::compute_offsets(); java_lang_ThreadGroup::compute_offsets(); if (EnableMethodHandles) { @@ -2961,10 +3063,10 @@ tty->print_cr("Static field %s.%s appears to be nonstatic", klass_name, field_name); return false; } - if (fd.offset() == hardcoded_offset + h_klass->offset_of_static_fields()) { + if (fd.offset() == hardcoded_offset + instanceMirrorKlass::offset_of_static_fields()) { return true; } else { - tty->print_cr("Offset of static field %s.%s is hardcoded as %d but should really be %d.", klass_name, field_name, hardcoded_offset, fd.offset() - h_klass->offset_of_static_fields()); + tty->print_cr("Offset of static field %s.%s is hardcoded as %d but should really be %d.", klass_name, field_name, hardcoded_offset, fd.offset() - instanceMirrorKlass::offset_of_static_fields()); return false; } } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/classfile/javaClasses.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -138,10 +138,8 @@ // The fake offsets are added by the class loader when java.lang.Class is loaded enum { - hc_klass_offset = 0, - hc_array_klass_offset = 1, - hc_resolved_constructor_offset = 2, - hc_number_of_fake_oop_fields = 3 + hc_number_of_fake_oop_fields = 3, + hc_number_of_fake_int_fields = 2 }; static int klass_offset; @@ -149,6 +147,9 @@ static int array_klass_offset; static int number_of_fake_oop_fields; + static int oop_size_offset; + static int static_oop_field_count_offset; + static void compute_offsets(); static bool offsets_computed; static int classRedefinedCount_offset; @@ -157,6 +158,7 @@ public: // Instance creation static oop create_mirror(KlassHandle k, TRAPS); + static void fixup_mirror(KlassHandle k, TRAPS); static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS); // Conversion static klassOop as_klassOop(oop java_class); @@ -191,6 +193,12 @@ static void set_classRedefinedCount(oop the_class_mirror, int value); // Support for parallelCapable field static bool parallelCapable(oop the_class_mirror); + + static int oop_size(oop java_class); + static void set_oop_size(oop java_class, int size); + static int static_oop_field_count(oop java_class); + static void set_static_oop_field_count(oop java_class, int size); + // Debugging friend class JavaClasses; friend class instanceKlass; // verification code accesses offsets @@ -1165,13 +1173,10 @@ hc_static_err_offset = 2 }; - static int offset_of_static_fields; static int static_in_offset; static int static_out_offset; static int static_err_offset; - static void compute_offsets(); - public: static int in_offset_in_bytes(); static int out_offset_in_bytes(); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/classfile/symbolTable.cpp --- a/src/share/vm/classfile/symbolTable.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/classfile/symbolTable.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -530,7 +530,7 @@ Handle string; // try to reuse the string if possible - if (!string_or_null.is_null() && string_or_null()->is_perm()) { + if (!string_or_null.is_null() && (!JavaObjectsInPerm || string_or_null()->is_perm())) { string = string_or_null; } else { string = java_lang_String::create_tenured_from_unicode(name, len, CHECK_NULL); @@ -662,7 +662,7 @@ for ( ; p != NULL; p = p->next()) { oop s = p->literal(); guarantee(s != NULL, "interned string is NULL"); - guarantee(s->is_perm(), "interned string not in permspace"); + guarantee(s->is_perm() || !JavaObjectsInPerm, "interned string not in permspace"); int length; jchar* chars = java_lang_String::as_unicode_string(s, length); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/classfile/symbolTable.hpp --- a/src/share/vm/classfile/symbolTable.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/classfile/symbolTable.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -216,18 +216,14 @@ oop basic_add(int index, Handle string_or_null, jchar* name, int len, unsigned int hashValue, TRAPS); - // Table size - enum { - string_table_size = 1009 - }; - oop lookup(int index, jchar* chars, int length, unsigned int hashValue); - StringTable() : Hashtable(string_table_size, sizeof (HashtableEntry)) {} + StringTable() : Hashtable((int)StringTableSize, + sizeof (HashtableEntry)) {} StringTable(HashtableBucket* t, int number_of_entries) - : Hashtable(string_table_size, sizeof (HashtableEntry), t, - number_of_entries) {} + : Hashtable((int)StringTableSize, sizeof (HashtableEntry), t, + number_of_entries) {} public: // The string table @@ -241,7 +237,7 @@ static void create_table(HashtableBucket* t, int length, int number_of_entries) { assert(_the_table == NULL, "One string table allowed."); - assert(length == string_table_size * sizeof(HashtableBucket), + assert((size_t)length == StringTableSize * sizeof(HashtableBucket), "bad shared string size."); _the_table = new StringTable(t, number_of_entries); } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/code/codeCache.cpp --- a/src/share/vm/code/codeCache.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/code/codeCache.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -337,7 +337,6 @@ if (is_live) { // Perform cur->oops_do(f), maybe just once per nmethod. f->do_code_blob(cur); - cur->fix_oop_relocations(); } } @@ -552,6 +551,19 @@ } +void CodeCache::verify_oops() { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + VerifyOopClosure voc; + FOR_ALL_ALIVE_BLOBS(cb) { + if (cb->is_nmethod()) { + nmethod *nm = (nmethod*)cb; + nm->oops_do(&voc); + nm->verify_oop_relocations(); + } + } +} + + address CodeCache::first_address() { assert_locked_or_safepoint(CodeCache_lock); return (address)_heap->begin(); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/code/codeCache.hpp --- a/src/share/vm/code/codeCache.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/code/codeCache.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -122,6 +122,7 @@ // GC support static void gc_epilogue(); static void gc_prologue(); + static void verify_oops(); // If "unloading_occurred" is true, then unloads (i.e., breaks root links // to) any unmarked codeBlobs in the cache. Sets "marked_for_unloading" // to "true" iff some code got unloaded. diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/code/nmethod.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -653,6 +653,9 @@ _pc_desc_cache.reset_to(NULL); code_buffer->copy_oops_to(this); + if (ScavengeRootsInCode && detect_scavenge_root_oops()) { + CodeCache::add_scavenge_root_nmethod(this); + } debug_only(verify_scavenge_root_oops()); CodeCache::commit(this); } @@ -1105,6 +1108,20 @@ } +void nmethod::verify_oop_relocations() { + // Ensure sure that the code matches the current oop values + RelocIterator iter(this, NULL, NULL); + while (iter.next()) { + if (iter.type() == relocInfo::oop_type) { + oop_Relocation* reloc = iter.oop_reloc(); + if (!reloc->oop_is_immediate()) { + reloc->verify_oop_relocation(); + } + } + } +} + + ScopeDesc* nmethod::scope_desc_at(address pc) { PcDesc* pd = pc_desc_at(pc); guarantee(pd != NULL, "scope must be present"); @@ -1823,6 +1840,7 @@ assert(cur != NULL, "not NULL-terminated"); nmethod* next = cur->_oops_do_mark_link; cur->_oops_do_mark_link = NULL; + cur->fix_oop_relocations(); NOT_PRODUCT(if (TraceScavenge) cur->print_on(tty, "oops_do, unmark\n")); cur = next; } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/code/nmethod.hpp --- a/src/share/vm/code/nmethod.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/code/nmethod.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -459,6 +459,7 @@ public: void fix_oop_relocations(address begin, address end) { fix_oop_relocations(begin, end, false); } void fix_oop_relocations() { fix_oop_relocations(NULL, NULL, false); } + void verify_oop_relocations(); bool is_at_poll_return(address pc); bool is_at_poll_or_poll_return(address pc); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/code/relocInfo.cpp --- a/src/share/vm/code/relocInfo.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/code/relocInfo.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -798,6 +798,14 @@ } +void oop_Relocation::verify_oop_relocation() { + if (!oop_is_immediate()) { + // get the oop from the pool, and re-insert it into the instruction: + verify_value(value()); + } +} + + RelocIterator virtual_call_Relocation::parse_ic(nmethod* &nm, address &ic_call, address &first_oop, oop* &oop_addr, bool *is_optimized) { assert(ic_call != NULL, "ic_call address must be set"); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/code/relocInfo.hpp --- a/src/share/vm/code/relocInfo.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/code/relocInfo.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -765,7 +765,8 @@ protected: // platform-dependent utilities for decoding and patching instructions - void pd_set_data_value (address x, intptr_t off); // a set or mem-ref + void pd_set_data_value (address x, intptr_t off, bool verify_only = false); // a set or mem-ref + void pd_verify_data_value (address x, intptr_t off) { pd_set_data_value(x, off, true); } address pd_call_destination (address orig_addr = NULL); void pd_set_call_destination (address x); void pd_swap_in_breakpoint (address x, short* instrs, int instrlen); @@ -880,6 +881,12 @@ else pd_set_data_value(x, o); } + void verify_value(address x) { + if (addr_in_const()) + assert(*(address*)addr() == x, "must agree"); + else + pd_verify_data_value(x, offset()); + } // The "o" (displacement) argument is relevant only to split relocations // on RISC machines. In some CPUs (SPARC), the set-hi and set-lo ins'ns @@ -950,6 +957,8 @@ void fix_oop_relocation(); // reasserts oop value + void verify_oop_relocation(); + address value() { return (address) *oop_addr(); } bool oop_is_immediate() { return oop_index() == 0; } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -5930,14 +5930,18 @@ } { - TraceTime t("scrub symbol & string tables", PrintGCDetails, false, gclog_or_tty); - // Now clean up stale oops in StringTable - StringTable::unlink(&_is_alive_closure); + TraceTime t("scrub symbol table", PrintGCDetails, false, gclog_or_tty); // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); } } + if (should_unload_classes() || !JavaObjectsInPerm) { + TraceTime t("scrub string table", PrintGCDetails, false, gclog_or_tty); + // Now clean up stale oops in StringTable + StringTable::unlink(&_is_alive_closure); + } + verify_work_stacks_empty(); // Restore any preserved marks as a result of mark stack or // work queue overflow diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/symbolTable.hpp" #include "gc_implementation/parallelScavenge/cardTableExtension.hpp" #include "gc_implementation/parallelScavenge/gcTaskManager.hpp" #include "gc_implementation/parallelScavenge/generationSizer.hpp" @@ -439,6 +440,14 @@ reference_processor()->enqueue_discovered_references(NULL); } + if (!JavaObjectsInPerm) { + // Unlink any dead interned Strings + StringTable::unlink(&_is_alive_closure); + // Process the remaining live ones + PSScavengeRootsClosure root_closure(promotion_manager); + StringTable::oops_do(&root_closure); + } + // Finally, flush the promotion_manager's labs, and deallocate its stacks. PSPromotionManager::post_scavenge(); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.inline.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -86,4 +86,21 @@ } } +class PSScavengeRootsClosure: public OopClosure { + private: + PSPromotionManager* _promotion_manager; + + protected: + template void do_oop_work(T *p) { + if (PSScavenge::should_scavenge(p)) { + // We never card mark roots, maybe call a func without test? + PSScavenge::copy_and_push_safe_barrier(_promotion_manager, p); + } + } + public: + PSScavengeRootsClosure(PSPromotionManager* pm) : _promotion_manager(pm) { } + void do_oop(oop* p) { PSScavengeRootsClosure::do_oop_work(p); } + void do_oop(narrowOop* p) { PSScavengeRootsClosure::do_oop_work(p); } +}; + #endif // SHARE_VM_GC_IMPLEMENTATION_PARALLELSCAVENGE_PSSCAVENGE_INLINE_HPP diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -30,7 +30,7 @@ #include "gc_implementation/parallelScavenge/psMarkSweep.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.hpp" #include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" -#include "gc_implementation/parallelScavenge/psScavenge.hpp" +#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" #include "gc_implementation/parallelScavenge/psTasks.hpp" #include "memory/iterator.hpp" #include "memory/universe.hpp" @@ -46,24 +46,6 @@ // ScavengeRootsTask // -// Define before use -class PSScavengeRootsClosure: public OopClosure { - private: - PSPromotionManager* _promotion_manager; - - protected: - template void do_oop_work(T *p) { - if (PSScavenge::should_scavenge(p)) { - // We never card mark roots, maybe call a func without test? - PSScavenge::copy_and_push_safe_barrier(_promotion_manager, p); - } - } - public: - PSScavengeRootsClosure(PSPromotionManager* pm) : _promotion_manager(pm) { } - void do_oop(oop* p) { PSScavengeRootsClosure::do_oop_work(p); } - void do_oop(narrowOop* p) { PSScavengeRootsClosure::do_oop_work(p); } -}; - void ScavengeRootsTask::do_it(GCTaskManager* manager, uint which) { assert(Universe::heap()->is_gc_active(), "called outside gc"); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/interpreter/bytecodeInterpreter.cpp --- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -656,7 +656,7 @@ // oop rcvr = locals[0].j.r; oop rcvr; if (METHOD->is_static()) { - rcvr = METHOD->constants()->pool_holder()->klass_part()->java_mirror(); + rcvr = METHOD->constants()->pool_holder()->java_mirror(); } else { rcvr = LOCALS_OBJECT(0); VERIFY_OOP(rcvr); @@ -2111,8 +2111,8 @@ break; case JVM_CONSTANT_Class: - VERIFY_OOP(constants->resolved_klass_at(index)->klass_part()->java_mirror()); - SET_STACK_OBJECT(constants->resolved_klass_at(index)->klass_part()->java_mirror(), 0); + VERIFY_OOP(constants->resolved_klass_at(index)->java_mirror()); + SET_STACK_OBJECT(constants->resolved_klass_at(index)->java_mirror(), 0); break; case JVM_CONSTANT_UnresolvedString: diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -118,7 +118,7 @@ if (tag.is_unresolved_klass() || tag.is_klass()) { klassOop klass = pool->klass_at(index, CHECK); - oop java_class = klass->klass_part()->java_mirror(); + oop java_class = klass->java_mirror(); thread->set_vm_result(java_class); } else { #ifdef ASSERT @@ -983,7 +983,8 @@ ConstantPoolCacheEntry *cp_entry)) // check the access_flags for the field in the klass - instanceKlass* ik = instanceKlass::cast((klassOop)cp_entry->f1()); + + instanceKlass* ik = instanceKlass::cast(java_lang_Class::as_klassOop(cp_entry->f1())); typeArrayOop fields = ik->fields(); int index = cp_entry->field_index(); assert(index < fields->length(), "holders field index is out of range"); @@ -1009,7 +1010,7 @@ // non-static field accessors have an object, but we need a handle h_obj = Handle(thread, obj); } - instanceKlassHandle h_cp_entry_f1(thread, (klassOop)cp_entry->f1()); + instanceKlassHandle h_cp_entry_f1(thread, java_lang_Class::as_klassOop(cp_entry->f1())); jfieldID fid = jfieldIDWorkaround::to_jfieldID(h_cp_entry_f1, cp_entry->f2(), is_static); JvmtiExport::post_field_access(thread, method(thread), bcp(thread), h_cp_entry_f1, h_obj, fid); IRT_END @@ -1017,7 +1018,7 @@ IRT_ENTRY(void, InterpreterRuntime::post_field_modification(JavaThread *thread, oopDesc* obj, ConstantPoolCacheEntry *cp_entry, jvalue *value)) - klassOop k = (klassOop)cp_entry->f1(); + klassOop k = java_lang_Class::as_klassOop(cp_entry->f1()); // check the access_flags for the field in the klass instanceKlass* ik = instanceKlass::cast(k); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/memory/compactingPermGenGen.hpp --- a/src/share/vm/memory/compactingPermGenGen.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/memory/compactingPermGenGen.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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 @@ -105,7 +105,7 @@ public: enum { - vtbl_list_size = 16, // number of entries in the shared space vtable list. + vtbl_list_size = 17, // number of entries in the shared space vtable list. num_virtuals = 200 // number of virtual methods in Klass (or // subclass) objects, or greater. }; diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/memory/dump.cpp --- a/src/share/vm/memory/dump.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/memory/dump.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1561,6 +1561,7 @@ // thread because it requires object allocation. LinkClassesClosure lcc(Thread::current()); object_iterate(&lcc); + ensure_parsability(false); // arg is actually don't care tty->print_cr("done. "); // Create and dump the shared spaces. diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/memory/oopFactory.cpp --- a/src/share/vm/memory/oopFactory.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/memory/oopFactory.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -117,12 +117,12 @@ } -klassOop oopFactory::new_instanceKlass(int vtable_len, int itable_len, +klassOop oopFactory::new_instanceKlass(Symbol* name, int vtable_len, int itable_len, int static_field_size, unsigned int nonstatic_oop_map_count, ReferenceType rt, TRAPS) { instanceKlassKlass* ikk = instanceKlassKlass::cast(Universe::instanceKlassKlassObj()); - return ikk->allocate_instance_klass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_count, rt, CHECK_NULL); + return ikk->allocate_instance_klass(name, vtable_len, itable_len, static_field_size, nonstatic_oop_map_count, rt, CHECK_NULL); } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/memory/oopFactory.hpp --- a/src/share/vm/memory/oopFactory.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/memory/oopFactory.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -72,7 +72,8 @@ TRAPS); // Instance classes - static klassOop new_instanceKlass(int vtable_len, int itable_len, + static klassOop new_instanceKlass(Symbol* name, + int vtable_len, int itable_len, int static_field_size, unsigned int nonstatic_oop_map_count, ReferenceType rt, TRAPS); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/memory/sharedHeap.cpp --- a/src/share/vm/memory/sharedHeap.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/memory/sharedHeap.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -171,11 +171,13 @@ } if (!_process_strong_tasks->is_task_claimed(SH_PS_StringTable_oops_do)) { - if (so & SO_Strings) { - StringTable::oops_do(roots); - } - // Verify if the string table contents are in the perm gen - NOT_PRODUCT(StringTable::oops_do(&assert_is_perm_closure)); + if (so & SO_Strings || (!collecting_perm_gen && !JavaObjectsInPerm)) { + StringTable::oops_do(roots); + } + if (JavaObjectsInPerm) { + // Verify the string table contents are in the perm gen + NOT_PRODUCT(StringTable::oops_do(&assert_is_perm_closure)); + } } if (!_process_strong_tasks->is_task_claimed(SH_PS_CodeCache_oops_do)) { diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/memory/universe.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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,7 @@ #include "oops/cpCacheKlass.hpp" #include "oops/cpCacheOop.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/instanceKlassKlass.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/klassKlass.hpp" @@ -521,6 +522,7 @@ { objArrayKlassKlass o; add_vtable(list, &n, &o, count); } { instanceKlassKlass o; add_vtable(list, &n, &o, count); } { instanceKlass o; add_vtable(list, &n, &o, count); } + { instanceMirrorKlass o; add_vtable(list, &n, &o, count); } { instanceRefKlass o; add_vtable(list, &n, &o, count); } { typeArrayKlassKlass o; add_vtable(list, &n, &o, count); } { typeArrayKlass o; add_vtable(list, &n, &o, count); } @@ -547,7 +549,7 @@ KlassHandle k(THREAD, klassOop(obj)); // We will never reach the CATCH below since Exceptions::_throw will cause // the VM to exit if an exception is thrown during initialization - java_lang_Class::create_mirror(k, CATCH); + java_lang_Class::fixup_mirror(k, CATCH); // This call unconditionally creates a new mirror for k, // and links in k's component_mirror field if k is an array. // If k is an objArray, k's element type must already have @@ -605,6 +607,10 @@ // walk over permanent objects created so far (mostly classes) and fixup their mirrors. Note // that the number of objects allocated at this point is very small. assert(SystemDictionary::Class_klass_loaded(), "java.lang.Class should be loaded"); + + // Cache the start of the static fields + instanceMirrorKlass::init_offset_of_static_fields(); + FixupMirrorClosure blk; Universe::heap()->permanent_object_iterate(&blk); } @@ -1313,6 +1319,8 @@ JNIHandles::verify(); if (!silent) gclog_or_tty->print("C-heap "); os::check_heap(); + if (!silent) gclog_or_tty->print("code cache "); + CodeCache::verify_oops(); if (!silent) gclog_or_tty->print_cr("]"); _verify_in_progress = false; diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/arrayKlassKlass.cpp --- a/src/share/vm/oops/arrayKlassKlass.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/arrayKlassKlass.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -28,6 +28,13 @@ #include "oops/arrayKlassKlass.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" +#ifndef SERIALGC +#include "gc_implementation/parNew/parOopClosures.inline.hpp" +#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" +#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" +#include "memory/cardTableRS.hpp" +#include "oops/oop.pcgc.inline.hpp" +#endif klassOop arrayKlassKlass::create_klass(TRAPS) { @@ -104,9 +111,12 @@ int arrayKlassKlass::oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { assert(obj->is_klass(), "must be klass"); arrayKlass* ak = arrayKlass::cast(klassOop(obj)); - blk->do_oop(ak->adr_component_mirror()); - blk->do_oop(ak->adr_lower_dimension()); - blk->do_oop(ak->adr_higher_dimension()); + oop* addr = ak->adr_component_mirror(); + if (mr.contains(addr)) blk->do_oop(addr); + addr = ak->adr_lower_dimension(); + if (mr.contains(addr)) blk->do_oop(addr); + addr = ak->adr_higher_dimension(); + if (mr.contains(addr)) blk->do_oop(addr); ak->vtable()->oop_oop_iterate_m(blk, mr); return klassKlass::oop_oop_iterate_m(obj, blk, mr); } @@ -114,6 +124,12 @@ #ifndef SERIALGC void arrayKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->blueprint()->oop_is_arrayKlass(),"must be an array klass"); + arrayKlass* ak = arrayKlass::cast(klassOop(obj)); + oop* p = ak->adr_component_mirror(); + if (PSScavenge::should_scavenge(p)) { + pm->claim_or_forward_depth(p); + } + klassKlass::oop_push_contents(pm, obj); } int arrayKlassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/constantPoolKlass.cpp --- a/src/share/vm/oops/constantPoolKlass.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/constantPoolKlass.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -285,10 +285,11 @@ void constantPoolKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_constantPool(), "should be constant pool"); constantPoolOop cp = (constantPoolOop) obj; - if (AnonymousClasses && cp->has_pseudo_string() && cp->tags() != NULL) { - oop* base = (oop*)cp->base(); - for (int i = 0; i < cp->length(); ++i, ++base) { + if (cp->tags() != NULL && + (!JavaObjectsInPerm || (AnonymousClasses && cp->has_pseudo_string()))) { + for (int i = 1; i < cp->length(); ++i) { if (cp->tag_at(i).is_string()) { + oop* base = cp->obj_at_addr_raw(i); if (PSScavenge::should_scavenge(base)) { pm->claim_or_forward_depth(base); } @@ -460,7 +461,8 @@ if (cp->tag_at(i).is_string()) { if (!cp->has_pseudo_string()) { if (entry.is_oop()) { - guarantee(entry.get_oop()->is_perm(), "should be in permspace"); + guarantee(!JavaObjectsInPerm || entry.get_oop()->is_perm(), + "should be in permspace"); guarantee(entry.get_oop()->is_instance(), "should be instance"); } } else { diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/constantPoolOop.cpp --- a/src/share/vm/oops/constantPoolOop.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/constantPoolOop.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -481,7 +481,7 @@ { klassOop resolved = klass_at_impl(this_oop, index, CHECK_NULL); // ldc wants the java mirror. - result_oop = resolved->klass_part()->java_mirror(); + result_oop = resolved->java_mirror(); break; } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/cpCacheKlass.cpp --- a/src/share/vm/oops/cpCacheKlass.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/cpCacheKlass.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -168,22 +168,18 @@ void constantPoolCacheKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->is_constantPoolCache(), "should be constant pool"); - if (EnableInvokeDynamic) { + if (ScavengeRootsInCode) { constantPoolCacheOop cache = (constantPoolCacheOop)obj; // during a scavenge, it is safe to inspect my pool, since it is perm constantPoolOop pool = cache->constant_pool(); assert(pool->is_constantPool(), "should be constant pool"); - if (pool->has_invokedynamic()) { - for (int i = 0; i < cache->length(); i++) { - ConstantPoolCacheEntry* e = cache->entry_at(i); - oop* p = (oop*)&e->_f1; - if (e->is_secondary_entry()) { - if (PSScavenge::should_scavenge(p)) - pm->claim_or_forward_depth(p); - assert(!(e->is_vfinal() && PSScavenge::should_scavenge((oop*)&e->_f2)), - "no live oops here"); - } - } + for (int i = 0; i < cache->length(); i++) { + ConstantPoolCacheEntry* e = cache->entry_at(i); + oop* p = (oop*)&e->_f1; + if (PSScavenge::should_scavenge(p)) + pm->claim_or_forward_depth(p); + assert(!(e->is_vfinal() && PSScavenge::should_scavenge((oop*)&e->_f2)), + "no live oops here"); } } } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/cpCacheOop.cpp --- a/src/share/vm/oops/cpCacheOop.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/cpCacheOop.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -133,7 +133,7 @@ TosState field_type, bool is_final, bool is_volatile) { - set_f1(field_holder()); + set_f1(field_holder()->java_mirror()); set_f2(field_offset); // The field index is used by jvm/ti and is the index into fields() array // in holder instanceKlass. This is scaled by instanceKlass::next_offset. diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/instanceKlass.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -37,6 +37,7 @@ #include "memory/oopFactory.hpp" #include "memory/permGen.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/instanceOop.hpp" #include "oops/methodOop.hpp" #include "oops/objArrayKlassKlass.hpp" @@ -649,6 +650,7 @@ } instanceOop instanceKlass::allocate_instance(TRAPS) { + assert(!oop_is_instanceMirror(), "wrong allocation path"); bool has_finalizer_flag = has_finalizer(); // Query before possible GC int size = size_helper(); // Query before forming handle. @@ -669,6 +671,7 @@ // instances so simply disallow finalizable perm objects. This can // be relaxed if a need for it is found. assert(!has_finalizer(), "perm objects not allowed to have finalizers"); + assert(!oop_is_instanceMirror(), "wrong allocation path"); int size = size_helper(); // Query before forming handle. KlassHandle h_k(THREAD, as_klassOop()); instanceOop i = (instanceOop) @@ -898,6 +901,7 @@ } } + void instanceKlass::do_local_static_fields(FieldClosure* cl) { fieldDescriptor fd; int length = fields()->length(); @@ -1609,36 +1613,6 @@ // The following macros call specialized macros, passing either oop or // narrowOop as the specialization type. These test the UseCompressedOops // flag. -#define InstanceKlass_OOP_ITERATE(start_p, count, \ - do_oop, assert_fn) \ -{ \ - if (UseCompressedOops) { \ - InstanceKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \ - start_p, count, \ - do_oop, assert_fn) \ - } else { \ - InstanceKlass_SPECIALIZED_OOP_ITERATE(oop, \ - start_p, count, \ - do_oop, assert_fn) \ - } \ -} - -#define InstanceKlass_BOUNDED_OOP_ITERATE(start_p, count, low, high, \ - do_oop, assert_fn) \ -{ \ - if (UseCompressedOops) { \ - InstanceKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \ - start_p, count, \ - low, high, \ - do_oop, assert_fn) \ - } else { \ - InstanceKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop, \ - start_p, count, \ - low, high, \ - do_oop, assert_fn) \ - } \ -} - #define InstanceKlass_OOP_MAP_ITERATE(obj, do_oop, assert_fn) \ { \ /* Compute oopmap block range. The common case \ @@ -1711,38 +1685,6 @@ } \ } -void instanceKlass::follow_static_fields() { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - MarkSweep::mark_and_push(p), \ - assert_is_in_closed_subset) -} - -#ifndef SERIALGC -void instanceKlass::follow_static_fields(ParCompactionManager* cm) { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - PSParallelCompact::mark_and_push(cm, p), \ - assert_is_in) -} -#endif // SERIALGC - -void instanceKlass::adjust_static_fields() { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - MarkSweep::adjust_pointer(p), \ - assert_nothing) -} - -#ifndef SERIALGC -void instanceKlass::update_static_fields() { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - PSParallelCompact::adjust_pointer(p), \ - assert_nothing) -} -#endif // SERIALGC - void instanceKlass::oop_follow_contents(oop obj) { assert(obj != NULL, "can't follow the content of NULL object"); obj->follow_header(); @@ -1829,22 +1771,6 @@ ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) #endif // !SERIALGC -void instanceKlass::iterate_static_fields(OopClosure* closure) { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - closure->do_oop(p), \ - assert_is_in_reserved) -} - -void instanceKlass::iterate_static_fields(OopClosure* closure, - MemRegion mr) { - InstanceKlass_BOUNDED_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - mr.start(), mr.end(), \ - (closure)->do_oop_v(p), \ - assert_is_in_closed_subset) -} - int instanceKlass::oop_adjust_pointers(oop obj) { int size = size_helper(); InstanceKlass_OOP_MAP_ITERATE( \ @@ -1873,21 +1799,6 @@ return size_helper(); } -void instanceKlass::push_static_fields(PSPromotionManager* pm) { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - if (PSScavenge::should_scavenge(p)) { \ - pm->claim_or_forward_depth(p); \ - }, \ - assert_nothing ) -} - -void instanceKlass::copy_static_fields(ParCompactionManager* cm) { - InstanceKlass_OOP_ITERATE( \ - start_of_static_fields(), static_oop_field_size(), \ - PSParallelCompact::adjust_pointer(p), \ - assert_is_in) -} #endif // SERIALGC // This klass is alive but the implementor link is not followed/updated. @@ -2002,6 +1913,11 @@ if (_source_debug_extension != NULL) _source_debug_extension->increment_refcount(); } +address instanceKlass::static_field_addr(int offset) { + return (address)(offset + instanceMirrorKlass::offset_of_static_fields() + (intptr_t)java_mirror()); +} + + const char* instanceKlass::signature_name() const { const char* src = (const char*) (name()->as_C_string()); const int src_length = (int)strlen(src); @@ -2369,7 +2285,7 @@ void FieldPrinter::do_field(fieldDescriptor* fd) { _st->print(BULLET); - if (fd->is_static() || (_obj == NULL)) { + if (_obj == NULL) { fd->print_on(_st); _st->cr(); } else { @@ -2399,8 +2315,8 @@ } st->print_cr(BULLET"---- fields (total size %d words):", oop_size(obj)); - FieldPrinter print_nonstatic_field(st, obj); - do_nonstatic_fields(&print_nonstatic_field); + FieldPrinter print_field(st, obj); + do_nonstatic_fields(&print_field); if (as_klassOop() == SystemDictionary::Class_klass()) { st->print(BULLET"signature: "); @@ -2418,6 +2334,12 @@ st->print(BULLET"fake entry for array: "); array_klass->print_value_on(st); st->cr(); + st->print_cr(BULLET"fake entry for oop_size: %d", java_lang_Class::oop_size(obj)); + st->print_cr(BULLET"fake entry for static_oop_field_count: %d", java_lang_Class::static_oop_field_count(obj)); + klassOop real_klass = java_lang_Class::as_klassOop(obj); + if (real_klass && real_klass->klass_part()->oop_is_instance()) { + instanceKlass::cast(real_klass)->do_local_static_fields(&print_field); + } } else if (as_klassOop() == SystemDictionary::MethodType_klass()) { st->print(BULLET"signature: "); java_lang_invoke_MethodType::print_signature(obj, st); @@ -2560,7 +2482,7 @@ void JNIid::verify(klassOop holder) { - int first_field_offset = instanceKlass::cast(holder)->offset_of_static_fields(); + int first_field_offset = instanceMirrorKlass::offset_of_static_fields(); int end_field_offset; end_field_offset = first_field_offset + (instanceKlass::cast(holder)->static_field_size() * wordSize); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/instanceKlass.hpp --- a/src/share/vm/oops/instanceKlass.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/instanceKlass.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -75,8 +75,6 @@ // [Java vtable length ] // [oop map cache (stack maps) ] // [EMBEDDED Java vtable ] size in words = vtable_len -// [EMBEDDED static oop fields ] size in words = static_oop_fields_size -// [ static non-oop fields ] size in words = static_field_size - static_oop_fields_size // [EMBEDDED nonstatic oop-map blocks] size in words = nonstatic_oop_map_size // // The embedded nonstatic oop-map blocks are short pairs (offset, length) indicating @@ -230,7 +228,7 @@ // (including inherited fields but after header_size()). int _nonstatic_field_size; int _static_field_size; // number words used by static fields (oop and non-oop) in this klass - int _static_oop_field_size;// number of static oop fields in this klass + int _static_oop_field_count;// number of static oop fields in this klass int _nonstatic_oop_map_size;// size in words of nonstatic oop map blocks bool _is_marked_dependent; // used for marking during flushing and deoptimization bool _rewritten; // methods rewritten. @@ -281,8 +279,8 @@ int static_field_size() const { return _static_field_size; } void set_static_field_size(int size) { _static_field_size = size; } - int static_oop_field_size() const { return _static_oop_field_size; } - void set_static_oop_field_size(int size) { _static_oop_field_size = size; } + int static_oop_field_count() const { return _static_oop_field_count; } + void set_static_oop_field_count(int size) { _static_oop_field_count = size; } // Java vtable int vtable_length() const { return _vtable_len; } @@ -660,6 +658,7 @@ // Casting from klassOop static instanceKlass* cast(klassOop k) { + assert(k->is_klass(), "must be"); Klass* kp = k->klass_part(); assert(kp->null_vtbl() || kp->oop_is_instance_slow(), "cast to instanceKlass"); return (instanceKlass*) kp; @@ -667,7 +666,7 @@ // Sizing (in words) static int header_size() { return align_object_offset(oopDesc::header_size() + sizeof(instanceKlass)/HeapWordSize); } - int object_size() const { return object_size(align_object_offset(vtable_length()) + align_object_offset(itable_length()) + static_field_size() + nonstatic_oop_map_size()); } + int object_size() const { return object_size(align_object_offset(vtable_length()) + align_object_offset(itable_length()) + nonstatic_oop_map_size()); } static int vtable_start_offset() { return header_size(); } static int vtable_length_offset() { return oopDesc::header_size() + offset_of(instanceKlass, _vtable_len) / HeapWordSize; } static int object_size(int extra) { return align_object_size(header_size() + extra); } @@ -676,20 +675,12 @@ intptr_t* start_of_itable() const { return start_of_vtable() + align_object_offset(vtable_length()); } int itable_offset_in_words() const { return start_of_itable() - (intptr_t*)as_klassOop(); } - // Static field offset is an offset into the Heap, should be converted by - // based on UseCompressedOop for traversal - HeapWord* start_of_static_fields() const { - return (HeapWord*)(start_of_itable() + align_object_offset(itable_length())); - } - intptr_t* end_of_itable() const { return start_of_itable() + itable_length(); } - int offset_of_static_fields() const { - return (intptr_t)start_of_static_fields() - (intptr_t)as_klassOop(); - } + address static_field_addr(int offset); OopMapBlock* start_of_nonstatic_oop_maps() const { - return (OopMapBlock*) (start_of_static_fields() + static_field_size()); + return (OopMapBlock*)(start_of_itable() + align_object_offset(itable_length())); } // Allocation profiling support @@ -719,8 +710,6 @@ // Garbage collection void oop_follow_contents(oop obj); - void follow_static_fields(); - void adjust_static_fields(); int oop_adjust_pointers(oop obj); bool object_is_parsable() const { return _init_state != unparsable_by_gc; } // Value of _init_state must be zero (unparsable_by_gc) when klass field is set. @@ -732,16 +721,6 @@ // Parallel Scavenge and Parallel Old PARALLEL_GC_DECLS -#ifndef SERIALGC - // Parallel Scavenge - void push_static_fields(PSPromotionManager* pm); - - // Parallel Old - void follow_static_fields(ParCompactionManager* cm); - void copy_static_fields(ParCompactionManager* cm); - void update_static_fields(); -#endif // SERIALGC - // Naming const char* signature_name() const; @@ -770,9 +749,6 @@ ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) #endif // !SERIALGC - void iterate_static_fields(OopClosure* closure); - void iterate_static_fields(OopClosure* closure, MemRegion mr); - private: // initialization state #ifdef ASSERT @@ -926,6 +902,10 @@ // Identifier lookup JNIid* find(int offset); + bool find_local_field(fieldDescriptor* fd) { + return instanceKlass::cast(holder())->find_local_field_from_offset(offset(), true, fd); + } + // Garbage collection support oop* holder_addr() { return (oop*)&_holder; } void oops_do(OopClosure* f); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/instanceKlassKlass.cpp --- a/src/share/vm/oops/instanceKlassKlass.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/instanceKlassKlass.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -31,6 +31,7 @@ #include "memory/gcLocker.hpp" #include "oops/constantPoolOop.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/instanceKlassKlass.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/objArrayKlassKlass.hpp" @@ -86,7 +87,6 @@ assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); - ik->follow_static_fields(); { HandleMark hm; ik->vtable()->oop_follow_contents(); @@ -127,7 +127,6 @@ assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); - ik->follow_static_fields(cm); ik->vtable()->oop_follow_contents(cm); ik->itable()->oop_follow_contents(cm); @@ -168,7 +167,6 @@ // Don't call size() or oop_size() since that is a virtual call. int size = ik->object_size(); - ik->iterate_static_fields(blk); ik->vtable()->oop_oop_iterate(blk); ik->itable()->oop_oop_iterate(blk); @@ -209,7 +207,6 @@ // Don't call size() or oop_size() since that is a virtual call. int size = ik->object_size(); - ik->iterate_static_fields(blk, mr); ik->vtable()->oop_oop_iterate_m(blk, mr); ik->itable()->oop_oop_iterate_m(blk, mr); @@ -266,7 +263,6 @@ assert(klassOop(obj)->klass_part()->oop_is_instance_slow(), "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); - ik->adjust_static_fields(); ik->vtable()->oop_adjust_pointers(); ik->itable()->oop_adjust_pointers(); @@ -300,7 +296,6 @@ #ifndef SERIALGC void instanceKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { instanceKlass* ik = instanceKlass::cast(klassOop(obj)); - ik->push_static_fields(pm); oop* loader_addr = ik->adr_class_loader(); if (PSScavenge::should_scavenge(loader_addr)) { @@ -336,7 +331,6 @@ "must be instance klass"); instanceKlass* ik = instanceKlass::cast(klassOop(obj)); - ik->update_static_fields(); ik->vtable()->oop_update_pointers(cm); ik->itable()->oop_update_pointers(cm); @@ -356,22 +350,28 @@ #endif // SERIALGC klassOop -instanceKlassKlass::allocate_instance_klass(int vtable_len, int itable_len, +instanceKlassKlass::allocate_instance_klass(Symbol* name, int vtable_len, int itable_len, int static_field_size, unsigned nonstatic_oop_map_count, ReferenceType rt, TRAPS) { const int nonstatic_oop_map_size = instanceKlass::nonstatic_oop_map_size(nonstatic_oop_map_count); - int size = instanceKlass::object_size(align_object_offset(vtable_len) + align_object_offset(itable_len) + static_field_size + nonstatic_oop_map_size); + int size = instanceKlass::object_size(align_object_offset(vtable_len) + align_object_offset(itable_len) + nonstatic_oop_map_size); // Allocation KlassHandle h_this_klass(THREAD, as_klassOop()); KlassHandle k; if (rt == REF_NONE) { - // regular klass - instanceKlass o; - k = base_create_klass(h_this_klass, size, o.vtbl_value(), CHECK_NULL); + if (name != vmSymbols::java_lang_Class()) { + // regular klass + instanceKlass o; + k = base_create_klass(h_this_klass, size, o.vtbl_value(), CHECK_NULL); + } else { + // Class + instanceMirrorKlass o; + k = base_create_klass(h_this_klass, size, o.vtbl_value(), CHECK_NULL); + } } else { // reference klass instanceRefKlass o; @@ -408,7 +408,7 @@ ik->set_source_debug_extension(NULL); ik->set_array_name(NULL); ik->set_inner_classes(NULL); - ik->set_static_oop_field_size(0); + ik->set_static_oop_field_count(0); ik->set_nonstatic_field_size(0); ik->set_is_marked_dependent(false); ik->set_init_state(instanceKlass::allocated); @@ -442,9 +442,6 @@ // To get verify to work - must be set to partial loaded before first GC point. k()->set_partially_loaded(); } - - // GC can happen here - java_lang_Class::create_mirror(k, CHECK_NULL); // Allocate mirror return k(); } @@ -566,13 +563,6 @@ FieldPrinter print_nonstatic_field(st); ik->do_nonstatic_fields(&print_nonstatic_field); - st->print(BULLET"static oop maps: "); - if (ik->static_oop_field_size() > 0) { - int first_offset = ik->offset_of_static_fields(); - st->print("%d-%d", first_offset, first_offset + ik->static_oop_field_size() - 1); - } - st->cr(); - st->print(BULLET"non-static oop maps: "); OopMapBlock* map = ik->start_of_nonstatic_oop_maps(); OopMapBlock* end_map = map + ik->nonstatic_oop_map_count(); @@ -630,7 +620,6 @@ // Verify static fields VerifyFieldClosure blk; - ik->iterate_static_fields(&blk); // Verify vtables if (ik->is_linked()) { diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/instanceKlassKlass.hpp --- a/src/share/vm/oops/instanceKlassKlass.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/instanceKlassKlass.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -41,7 +41,8 @@ // Allocation DEFINE_ALLOCATE_PERMANENT(instanceKlassKlass); static klassOop create_klass(TRAPS); - klassOop allocate_instance_klass(int vtable_len, + klassOop allocate_instance_klass(Symbol* name, + int vtable_len, int itable_len, int static_field_size, unsigned int nonstatic_oop_map_count, diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/instanceMirrorKlass.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/oops/instanceMirrorKlass.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/systemDictionary.hpp" +#include "gc_implementation/shared/markSweep.inline.hpp" +#include "gc_interface/collectedHeap.inline.hpp" +#include "memory/genOopClosures.inline.hpp" +#include "memory/oopFactory.hpp" +#include "memory/permGen.hpp" +#include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" +#include "oops/instanceOop.hpp" +#include "oops/oop.inline.hpp" +#include "oops/symbol.hpp" +#include "runtime/handles.inline.hpp" +#ifndef SERIALGC +#include "gc_implementation/g1/g1CollectedHeap.inline.hpp" +#include "gc_implementation/g1/g1OopClosures.inline.hpp" +#include "gc_implementation/g1/g1RemSet.inline.hpp" +#include "gc_implementation/g1/heapRegionSeq.inline.hpp" +#include "gc_implementation/parNew/parOopClosures.inline.hpp" +#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" +#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" +#include "oops/oop.pcgc.inline.hpp" +#endif + +int instanceMirrorKlass::_offset_of_static_fields = 0; + +#ifdef ASSERT +template void assert_is_in(T *p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop o = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(Universe::heap()->is_in(o), "should be in heap"); + } +} +template void assert_is_in_closed_subset(T *p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop o = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(Universe::heap()->is_in_closed_subset(o), "should be in closed"); + } +} +template void assert_is_in_reserved(T *p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop o = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(Universe::heap()->is_in_reserved(o), "should be in reserved"); + } +} +template void assert_nothing(T *p) {} + +#else +template void assert_is_in(T *p) {} +template void assert_is_in_closed_subset(T *p) {} +template void assert_is_in_reserved(T *p) {} +template void assert_nothing(T *p) {} +#endif // ASSERT + +#define InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE( \ + T, start_p, count, do_oop, \ + assert_fn) \ +{ \ + T* p = (T*)(start_p); \ + T* const end = p + (count); \ + while (p < end) { \ + (assert_fn)(p); \ + do_oop; \ + ++p; \ + } \ +} + +#define InstanceMirrorKlass_SPECIALIZED_BOUNDED_OOP_ITERATE( \ + T, start_p, count, low, high, \ + do_oop, assert_fn) \ +{ \ + T* const l = (T*)(low); \ + T* const h = (T*)(high); \ + assert(mask_bits((intptr_t)l, sizeof(T)-1) == 0 && \ + mask_bits((intptr_t)h, sizeof(T)-1) == 0, \ + "bounded region must be properly aligned"); \ + T* p = (T*)(start_p); \ + T* end = p + (count); \ + if (p < l) p = l; \ + if (end > h) end = h; \ + while (p < end) { \ + (assert_fn)(p); \ + do_oop; \ + ++p; \ + } \ +} + + +#define InstanceMirrorKlass_OOP_ITERATE(start_p, count, \ + do_oop, assert_fn) \ +{ \ + if (UseCompressedOops) { \ + InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \ + start_p, count, \ + do_oop, assert_fn) \ + } else { \ + InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE(oop, \ + start_p, count, \ + do_oop, assert_fn) \ + } \ +} + +// The following macros call specialized macros, passing either oop or +// narrowOop as the specialization type. These test the UseCompressedOops +// flag. +#define InstanceMirrorKlass_BOUNDED_OOP_ITERATE(start_p, count, low, high, \ + do_oop, assert_fn) \ +{ \ + if (UseCompressedOops) { \ + InstanceMirrorKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \ + start_p, count, \ + low, high, \ + do_oop, assert_fn) \ + } else { \ + InstanceMirrorKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop, \ + start_p, count, \ + low, high, \ + do_oop, assert_fn) \ + } \ +} + + +void instanceMirrorKlass::oop_follow_contents(oop obj) { + instanceKlass::oop_follow_contents(obj); + InstanceMirrorKlass_OOP_ITERATE( \ + start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ + MarkSweep::mark_and_push(p), \ + assert_is_in_closed_subset) +} + +#ifndef SERIALGC +void instanceMirrorKlass::oop_follow_contents(ParCompactionManager* cm, + oop obj) { + instanceKlass::oop_follow_contents(cm, obj); + InstanceMirrorKlass_OOP_ITERATE( \ + start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ + PSParallelCompact::mark_and_push(cm, p), \ + assert_is_in) +} +#endif // SERIALGC + +int instanceMirrorKlass::oop_adjust_pointers(oop obj) { + int size = oop_size(obj); + instanceKlass::oop_adjust_pointers(obj); + InstanceMirrorKlass_OOP_ITERATE( \ + start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ + MarkSweep::adjust_pointer(p), \ + assert_nothing) + return size; +} + +#define InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(T, nv_suffix) \ + InstanceMirrorKlass_OOP_ITERATE( \ + start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ + (closure)->do_oop##nv_suffix(p), \ + assert_is_in_closed_subset) \ + return oop_size(obj); \ + +#define InstanceMirrorKlass_BOUNDED_SPECIALIZED_OOP_ITERATE(T, nv_suffix, mr) \ + InstanceMirrorKlass_BOUNDED_OOP_ITERATE( \ + start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj), \ + mr.start(), mr.end(), \ + (closure)->do_oop##nv_suffix(p), \ + assert_is_in_closed_subset) \ + return oop_size(obj); \ + + +// Macro to define instanceMirrorKlass::oop_oop_iterate for virtual/nonvirtual for +// all closures. Macros calling macros above for each oop size. + +#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix) \ + \ +int instanceMirrorKlass:: \ +oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \ + /* Get size before changing pointers */ \ + SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::irk); \ + \ + instanceKlass::oop_oop_iterate##nv_suffix(obj, closure); \ + \ + if (UseCompressedOops) { \ + InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(narrowOop, nv_suffix); \ + } else { \ + InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(oop, nv_suffix); \ + } \ +} + +#ifndef SERIALGC +#define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \ + \ +int instanceMirrorKlass:: \ +oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) { \ + /* Get size before changing pointers */ \ + SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::irk); \ + \ + instanceKlass::oop_oop_iterate_backwards##nv_suffix(obj, closure); \ + \ + if (UseCompressedOops) { \ + InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(narrowOop, nv_suffix); \ + } else { \ + InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE_DEFN(oop, nv_suffix); \ + } \ +} +#endif // !SERIALGC + + +#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix) \ + \ +int instanceMirrorKlass:: \ +oop_oop_iterate##nv_suffix##_m(oop obj, \ + OopClosureType* closure, \ + MemRegion mr) { \ + SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::irk); \ + \ + instanceKlass::oop_oop_iterate##nv_suffix##_m(obj, closure, mr); \ + if (UseCompressedOops) { \ + InstanceMirrorKlass_BOUNDED_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, mr); \ + } else { \ + InstanceMirrorKlass_BOUNDED_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, mr); \ + } \ +} + +ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN) +ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN) +#ifndef SERIALGC +ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) +ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN) +#endif // SERIALGC +ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) +ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m) + +#ifndef SERIALGC +void instanceMirrorKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { + instanceKlass::oop_push_contents(pm, obj); + InstanceMirrorKlass_OOP_ITERATE( \ + start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj),\ + if (PSScavenge::should_scavenge(p)) { \ + pm->claim_or_forward_depth(p); \ + }, \ + assert_nothing ) +} + +int instanceMirrorKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { + instanceKlass::oop_update_pointers(cm, obj); + InstanceMirrorKlass_OOP_ITERATE( \ + start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj),\ + PSParallelCompact::adjust_pointer(p), \ + assert_nothing) + return oop_size(obj); +} +#endif // SERIALGC + +int instanceMirrorKlass::instance_size(KlassHandle k) { + if (k() != NULL && k->oop_is_instance()) { + return align_object_size(size_helper() + instanceKlass::cast(k())->static_field_size()); + } + return size_helper(); +} + +instanceOop instanceMirrorKlass::allocate_instance(KlassHandle k, TRAPS) { + // Query before forming handle. + int size = instance_size(k); + KlassHandle h_k(THREAD, as_klassOop()); + instanceOop i; + + if (JavaObjectsInPerm) { + i = (instanceOop) CollectedHeap::permanent_obj_allocate(h_k, size, CHECK_NULL); + } else { + assert(ScavengeRootsInCode > 0, "must be"); + i = (instanceOop) CollectedHeap::obj_allocate(h_k, size, CHECK_NULL); + } + + return i; +} + +int instanceMirrorKlass::oop_size(oop obj) const { + return java_lang_Class::oop_size(obj); +} + +int instanceMirrorKlass::compute_static_oop_field_count(oop obj) { + klassOop k = java_lang_Class::as_klassOop(obj); + if (k != NULL && k->klass_part()->oop_is_instance()) { + return instanceKlass::cast(k)->static_oop_field_count(); + } + return 0; +} diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/instanceMirrorKlass.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/oops/instanceMirrorKlass.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_OOPS_INSTANCEMIRRORKLASS_HPP +#define SHARE_VM_OOPS_INSTANCEMIRRORKLASS_HPP + +#include "oops/instanceKlass.hpp" + +// An instanceMirrorKlass is a specialized instanceKlass for +// java.lang.Class instances. These instances are special because +// they contain the static fields of the class in addition to the +// normal fields of Class. This means they are variable sized +// instances and need special logic for computing their size and for +// iteration of their oops. + + +class instanceMirrorKlass: public instanceKlass { + private: + static int _offset_of_static_fields; + + public: + // Type testing + bool oop_is_instanceMirror() const { return true; } + + // Casting from klassOop + static instanceMirrorKlass* cast(klassOop k) { + assert(k->klass_part()->oop_is_instanceMirror(), "cast to instanceMirrorKlass"); + return (instanceMirrorKlass*) k->klass_part(); + } + + // Returns the size of the instance including the extra static fields. + virtual int oop_size(oop obj) const; + + // Static field offset is an offset into the Heap, should be converted by + // based on UseCompressedOop for traversal + static HeapWord* start_of_static_fields(oop obj) { + return (HeapWord*)((intptr_t)obj + offset_of_static_fields()); + } + + static void init_offset_of_static_fields() { + // Cache the offset of the static fields in the Class instance + assert(_offset_of_static_fields == 0, "once"); + _offset_of_static_fields = instanceMirrorKlass::cast(SystemDictionary::Class_klass())->size_helper() << LogHeapWordSize; + } + + static int offset_of_static_fields() { + return _offset_of_static_fields; + } + + int compute_static_oop_field_count(oop obj); + + // Given a Klass return the size of the instance + int instance_size(KlassHandle k); + + // allocation + DEFINE_ALLOCATE_PERMANENT(instanceMirrorKlass); + instanceOop allocate_instance(KlassHandle k, TRAPS); + + // Garbage collection + int oop_adjust_pointers(oop obj); + void oop_follow_contents(oop obj); + + // Parallel Scavenge and Parallel Old + PARALLEL_GC_DECLS + + int oop_oop_iterate(oop obj, OopClosure* blk) { + return oop_oop_iterate_v(obj, blk); + } + int oop_oop_iterate_m(oop obj, OopClosure* blk, MemRegion mr) { + return oop_oop_iterate_v_m(obj, blk, mr); + } + +#define InstanceMirrorKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk); \ + int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk, MemRegion mr); + + ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DECL) + +#ifndef SERIALGC +#define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \ + int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk); + + ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) + ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL) +#endif // !SERIALGC +}; + +#endif // SHARE_VM_OOPS_INSTANCEMIRRORKLASS_HPP diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/klass.hpp --- a/src/share/vm/oops/klass.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/klass.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -577,6 +577,7 @@ public: // type testing operations virtual bool oop_is_instance_slow() const { return false; } + virtual bool oop_is_instanceMirror() const { return false; } virtual bool oop_is_instanceRef() const { return false; } virtual bool oop_is_array() const { return false; } virtual bool oop_is_objArray_slow() const { return false; } @@ -811,4 +812,8 @@ #endif }; + +inline oop klassOopDesc::java_mirror() const { return klass_part()->java_mirror(); } + + #endif // SHARE_VM_OOPS_KLASS_HPP diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/klassKlass.cpp --- a/src/share/vm/oops/klassKlass.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/klassKlass.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -41,6 +41,10 @@ #include "oops/typeArrayKlass.hpp" #include "runtime/handles.inline.hpp" #ifndef SERIALGC +#include "gc_implementation/parNew/parOopClosures.inline.hpp" +#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" +#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" +#include "memory/cardTableRS.hpp" #include "oops/oop.pcgc.inline.hpp" #endif @@ -175,6 +179,12 @@ #ifndef SERIALGC void klassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { + Klass* k = Klass::cast(klassOop(obj)); + + oop* p = k->adr_java_mirror(); + if (PSScavenge::should_scavenge(p)) { + pm->claim_or_forward_depth(p); + } } int klassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { @@ -233,7 +243,7 @@ if (k->java_mirror() != NULL || (k->oop_is_instance() && instanceKlass::cast(klassOop(obj))->is_loaded())) { guarantee(k->java_mirror() != NULL, "should be allocated"); - guarantee(k->java_mirror()->is_perm(), "should be in permspace"); + guarantee(k->java_mirror()->is_perm() || !JavaObjectsInPerm, "should be in permspace"); guarantee(k->java_mirror()->is_instance(), "should be instance"); } } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/klassOop.hpp --- a/src/share/vm/oops/klassOop.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/klassOop.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -45,7 +45,73 @@ static int klass_part_offset_in_bytes() { return sizeof(klassOopDesc); } // returns the Klass part containing dispatching behavior - Klass* klass_part() { return (Klass*)((address)this + klass_part_offset_in_bytes()); } + Klass* klass_part() const { return (Klass*)((address)this + klass_part_offset_in_bytes()); } + + // Convenience wrapper + inline oop java_mirror() const; + + private: + // These have no implementation since klassOop should never be accessed in this fashion + oop obj_field(int offset) const; + void obj_field_put(int offset, oop value); + void obj_field_raw_put(int offset, oop value); + + jbyte byte_field(int offset) const; + void byte_field_put(int offset, jbyte contents); + + jchar char_field(int offset) const; + void char_field_put(int offset, jchar contents); + + jboolean bool_field(int offset) const; + void bool_field_put(int offset, jboolean contents); + + jint int_field(int offset) const; + void int_field_put(int offset, jint contents); + + jshort short_field(int offset) const; + void short_field_put(int offset, jshort contents); + + jlong long_field(int offset) const; + void long_field_put(int offset, jlong contents); + + jfloat float_field(int offset) const; + void float_field_put(int offset, jfloat contents); + + jdouble double_field(int offset) const; + void double_field_put(int offset, jdouble contents); + + address address_field(int offset) const; + void address_field_put(int offset, address contents); + + oop obj_field_acquire(int offset) const; + void release_obj_field_put(int offset, oop value); + + jbyte byte_field_acquire(int offset) const; + void release_byte_field_put(int offset, jbyte contents); + + jchar char_field_acquire(int offset) const; + void release_char_field_put(int offset, jchar contents); + + jboolean bool_field_acquire(int offset) const; + void release_bool_field_put(int offset, jboolean contents); + + jint int_field_acquire(int offset) const; + void release_int_field_put(int offset, jint contents); + + jshort short_field_acquire(int offset) const; + void release_short_field_put(int offset, jshort contents); + + jlong long_field_acquire(int offset) const; + void release_long_field_put(int offset, jlong contents); + + jfloat float_field_acquire(int offset) const; + void release_float_field_put(int offset, jfloat contents); + + jdouble double_field_acquire(int offset) const; + void release_double_field_put(int offset, jdouble contents); + + address address_field_acquire(int offset) const; + void release_address_field_put(int offset, address contents); }; #endif // SHARE_VM_OOPS_KLASSOOP_HPP diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/klassVtable.cpp --- a/src/share/vm/oops/klassVtable.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/klassVtable.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1095,7 +1095,7 @@ itableOffsetEntry* ioe = (itableOffsetEntry*)klass->start_of_itable(); itableMethodEntry* ime = (itableMethodEntry*)(ioe + nof_interfaces); intptr_t* end = klass->end_of_itable(); - assert((oop*)(ime + nof_methods) <= (oop*)klass->start_of_static_fields(), "wrong offset calculation (1)"); + assert((oop*)(ime + nof_methods) <= (oop*)klass->start_of_nonstatic_oop_maps(), "wrong offset calculation (1)"); assert((oop*)(end) == (oop*)(ime + nof_methods), "wrong offset calculation (2)"); // Visit all interfaces and initialize itable offset table diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/objArrayKlassKlass.cpp --- a/src/share/vm/oops/objArrayKlassKlass.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/objArrayKlassKlass.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -31,6 +31,13 @@ #include "oops/objArrayKlassKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/oop.inline2.hpp" +#ifndef SERIALGC +#include "gc_implementation/parNew/parOopClosures.inline.hpp" +#include "gc_implementation/parallelScavenge/psPromotionManager.inline.hpp" +#include "gc_implementation/parallelScavenge/psScavenge.inline.hpp" +#include "memory/cardTableRS.hpp" +#include "oops/oop.pcgc.inline.hpp" +#endif klassOop objArrayKlassKlass::create_klass(TRAPS) { objArrayKlassKlass o; @@ -236,12 +243,23 @@ addr = oak->bottom_klass_addr(); if (mr.contains(addr)) blk->do_oop(addr); - return arrayKlassKlass::oop_oop_iterate(obj, blk); + return arrayKlassKlass::oop_oop_iterate_m(obj, blk, mr); } #ifndef SERIALGC void objArrayKlassKlass::oop_push_contents(PSPromotionManager* pm, oop obj) { assert(obj->blueprint()->oop_is_objArrayKlass(),"must be an obj array klass"); + objArrayKlass* oak = objArrayKlass::cast((klassOop)obj); + oop* p = oak->element_klass_addr(); + if (PSScavenge::should_scavenge(p)) { + pm->claim_or_forward_depth(p); + } + p = oak->bottom_klass_addr(); + if (PSScavenge::should_scavenge(p)) { + pm->claim_or_forward_depth(p); + } + + arrayKlassKlass::oop_push_contents(pm, obj); } int objArrayKlassKlass::oop_update_pointers(ParCompactionManager* cm, oop obj) { @@ -287,7 +305,7 @@ // Verification void objArrayKlassKlass::oop_verify_on(oop obj, outputStream* st) { - klassKlass::oop_verify_on(obj, st); + arrayKlassKlass::oop_verify_on(obj, st); objArrayKlass* oak = objArrayKlass::cast((klassOop)obj); guarantee(oak->element_klass()->is_perm(), "should be in permspace"); guarantee(oak->element_klass()->is_klass(), "should be klass"); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/oop.hpp --- a/src/share/vm/oops/oop.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/oop.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -129,6 +129,7 @@ // type test operations (inlined in oop.inline.h) bool is_instance() const; + bool is_instanceMirror() const; bool is_instanceRef() const; bool is_array() const; bool is_objArray() const; diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/oop.inline.hpp --- a/src/share/vm/oops/oop.inline.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/oop.inline.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -141,6 +141,7 @@ inline bool oopDesc::is_a(klassOop k) const { return blueprint()->is_subtype_of(k); } inline bool oopDesc::is_instance() const { return blueprint()->oop_is_instance(); } +inline bool oopDesc::is_instanceMirror() const { return blueprint()->oop_is_instanceMirror(); } inline bool oopDesc::is_instanceRef() const { return blueprint()->oop_is_instanceRef(); } inline bool oopDesc::is_array() const { return blueprint()->oop_is_array(); } inline bool oopDesc::is_objArray() const { return blueprint()->oop_is_objArray(); } @@ -399,7 +400,7 @@ inline int oopDesc::size_given_klass(Klass* klass) { int lh = klass->layout_helper(); - int s = lh >> LogHeapWordSize; // deliver size scaled by wordSize + int s; // lh is now a value computed at class initialization that may hint // at the size. For instances, this is positive and equal to the @@ -412,7 +413,13 @@ // alive or dead. So the speed here is equal in importance to the // speed of allocation. - if (lh <= Klass::_lh_neutral_value) { + if (lh > Klass::_lh_neutral_value) { + if (!Klass::layout_helper_needs_slow_path(lh)) { + s = lh >> LogHeapWordSize; // deliver size scaled by wordSize + } else { + s = klass->oop_size(this); + } + } else if (lh <= Klass::_lh_neutral_value) { // The most common case is instances; fall through if so. if (lh < Klass::_lh_neutral_value) { // Second most common case is arrays. We have to fetch the diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/oops/oopsHierarchy.hpp --- a/src/share/vm/oops/oopsHierarchy.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/oops/oopsHierarchy.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -174,6 +174,7 @@ class Klass; class instanceKlass; +class instanceMirrorKlass; class instanceRefKlass; class methodKlass; class constMethodKlass; diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/c2_globals.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -180,6 +180,9 @@ develop(bool, TraceLoopPredicate, false, \ "Trace generation of loop predicates") \ \ + develop(bool, TraceLoopOpts, false, \ + "Trace executed loop optimizations") \ + \ product(bool, OptimizeFill, false, \ "convert fill/copy loops into intrinsic") \ \ diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/compile.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -1202,11 +1202,15 @@ // Oop pointers need some flattening const TypeInstPtr *to = tj->isa_instptr(); if( to && _AliasLevel >= 2 && to != TypeOopPtr::BOTTOM ) { + ciInstanceKlass *k = to->klass()->as_instance_klass(); if( ptr == TypePtr::Constant ) { - // No constant oop pointers (such as Strings); they alias with - // unknown strings. - assert(!is_known_inst, "not scalarizable allocation"); - tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset); + if (to->klass() != ciEnv::current()->Class_klass() || + offset < k->size_helper() * wordSize) { + // No constant oop pointers (such as Strings); they alias with + // unknown strings. + assert(!is_known_inst, "not scalarizable allocation"); + tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset); + } } else if( is_known_inst ) { tj = to; // Keep NotNull and klass_is_exact for instance type } else if( ptr == TypePtr::NotNull || to->klass_is_exact() ) { @@ -1216,7 +1220,6 @@ tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset); } // Canonicalize the holder of this field - ciInstanceKlass *k = to->klass()->as_instance_klass(); if (offset >= 0 && offset < instanceOopDesc::base_offset_in_bytes()) { // First handle header references such as a LoadKlassNode, even if the // object's klass is unloaded at compile time (4965979). @@ -1224,9 +1227,13 @@ tj = to = TypeInstPtr::make(TypePtr::BotPTR, env()->Object_klass(), false, NULL, offset); } } else if (offset < 0 || offset >= k->size_helper() * wordSize) { - to = NULL; - tj = TypeOopPtr::BOTTOM; - offset = tj->offset(); + // Static fields are in the space above the normal instance + // fields in the java.lang.Class instance. + if (to->klass() != ciEnv::current()->Class_klass()) { + to = NULL; + tj = TypeOopPtr::BOTTOM; + offset = tj->offset(); + } } else { ciInstanceKlass *canonical_holder = k->get_canonical_holder(offset); if (!k->equals(canonical_holder) || tj->offset() != offset) { @@ -1399,7 +1406,7 @@ //--------------------------------find_alias_type------------------------------ -Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_create) { +Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_create, ciField* original_field) { if (_AliasLevel == 0) return alias_type(AliasIdxBot); @@ -1464,22 +1471,28 @@ // but the base pointer type is not distinctive enough to identify // references into JavaThread.) - // Check for final instance fields. + // Check for final fields. const TypeInstPtr* tinst = flat->isa_instptr(); if (tinst && tinst->offset() >= instanceOopDesc::base_offset_in_bytes()) { - ciInstanceKlass *k = tinst->klass()->as_instance_klass(); - ciField* field = k->get_field_by_offset(tinst->offset(), false); + ciField* field; + if (tinst->const_oop() != NULL && + tinst->klass() == ciEnv::current()->Class_klass() && + tinst->offset() >= (tinst->klass()->as_instance_klass()->size_helper() * wordSize)) { + // static field + ciInstanceKlass* k = tinst->const_oop()->as_instance()->java_lang_Class_klass()->as_instance_klass(); + field = k->get_field_by_offset(tinst->offset(), true); + } else { + ciInstanceKlass *k = tinst->klass()->as_instance_klass(); + field = k->get_field_by_offset(tinst->offset(), false); + } + assert(field == NULL || + original_field == NULL || + (field->holder() == original_field->holder() && + field->offset() == original_field->offset() && + field->is_static() == original_field->is_static()), "wrong field?"); // Set field() and is_rewritable() attributes. if (field != NULL) alias_type(idx)->set_field(field); } - const TypeKlassPtr* tklass = flat->isa_klassptr(); - // Check for final static fields. - if (tklass && tklass->klass()->is_instance_klass()) { - ciInstanceKlass *k = tklass->klass()->as_instance_klass(); - ciField* field = k->get_field_by_offset(tklass->offset(), true); - // Set field() and is_rewritable() attributes. - if (field != NULL) alias_type(idx)->set_field(field); - } } // Fill the cache for next time. @@ -1502,10 +1515,10 @@ Compile::AliasType* Compile::alias_type(ciField* field) { const TypeOopPtr* t; if (field->is_static()) - t = TypeKlassPtr::make(field->holder()); + t = TypeInstPtr::make(field->holder()->java_mirror()); else t = TypeOopPtr::make_from_klass_raw(field->holder()); - AliasType* atp = alias_type(t->add_offset(field->offset_in_bytes())); + AliasType* atp = alias_type(t->add_offset(field->offset_in_bytes()), field); assert(field->is_final() == !atp->is_rewritable(), "must get the rewritable bits correct"); return atp; } @@ -1522,7 +1535,7 @@ if (adr_type == NULL) return true; if (adr_type == TypePtr::BOTTOM) return true; - return find_alias_type(adr_type, true) != NULL; + return find_alias_type(adr_type, true, NULL) != NULL; } //-----------------------------must_alias-------------------------------------- diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/compile.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -596,7 +596,7 @@ } AliasType* alias_type(int idx) { assert(idx < num_alias_types(), "oob"); return _alias_types[idx]; } - AliasType* alias_type(const TypePtr* adr_type) { return find_alias_type(adr_type, false); } + AliasType* alias_type(const TypePtr* adr_type, ciField* field = NULL) { return find_alias_type(adr_type, false, field); } bool have_alias_type(const TypePtr* adr_type); AliasType* alias_type(ciField* field); @@ -835,7 +835,7 @@ void grow_alias_types(); AliasCacheEntry* probe_alias_cache(const TypePtr* adr_type); const TypePtr *flatten_alias_type(const TypePtr* adr_type) const; - AliasType* find_alias_type(const TypePtr* adr_type, bool no_create); + AliasType* find_alias_type(const TypePtr* adr_type, bool no_create, ciField* field); void verify_top(Node*) const PRODUCT_RETURN; diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/graphKit.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -3338,6 +3338,49 @@ return NULL; } +//----------------------------- loop predicates --------------------------- + +//------------------------------add_predicate_impl---------------------------- +void GraphKit::add_predicate_impl(Deoptimization::DeoptReason reason, int nargs) { + // Too many traps seen? + if (too_many_traps(reason)) { +#ifdef ASSERT + if (TraceLoopPredicate) { + int tc = C->trap_count(reason); + tty->print("too many traps=%s tcount=%d in ", + Deoptimization::trap_reason_name(reason), tc); + method()->print(); // which method has too many predicate traps + tty->cr(); + } +#endif + // We cannot afford to take more traps here, + // do not generate predicate. + return; + } + + Node *cont = _gvn.intcon(1); + Node* opq = _gvn.transform(new (C, 2) Opaque1Node(C, cont)); + Node *bol = _gvn.transform(new (C, 2) Conv2BNode(opq)); + IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN); + Node* iffalse = _gvn.transform(new (C, 1) IfFalseNode(iff)); + C->add_predicate_opaq(opq); + { + PreserveJVMState pjvms(this); + set_control(iffalse); + _sp += nargs; + uncommon_trap(reason, Deoptimization::Action_maybe_recompile); + } + Node* iftrue = _gvn.transform(new (C, 1) IfTrueNode(iff)); + set_control(iftrue); +} + +//------------------------------add_predicate--------------------------------- +void GraphKit::add_predicate(int nargs) { + if (UseLoopPredicate) { + add_predicate_impl(Deoptimization::Reason_predicate, nargs); + } +} + //----------------------------- store barriers ---------------------------- #define __ ideal. diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/graphKit.hpp --- a/src/share/vm/opto/graphKit.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/graphKit.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -793,6 +793,10 @@ if (!tst->is_Con()) record_for_igvn(iff); // Range-check and Null-check removal is later return iff; } + + // Insert a loop predicate into the graph + void add_predicate(int nargs = 0); + void add_predicate_impl(Deoptimization::DeoptReason reason, int nargs); }; // Helper class to support building of control flow branches. Upon diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/idealKit.cpp --- a/src/share/vm/opto/idealKit.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/idealKit.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -154,8 +154,18 @@ // // Pushes the loop top cvstate first, then the else (loop exit) cvstate // onto the stack. -void IdealKit::loop(IdealVariable& iv, Node* init, BoolTest::mask relop, Node* limit, float prob, float cnt) { +void IdealKit::loop(GraphKit* gkit, int nargs, IdealVariable& iv, Node* init, BoolTest::mask relop, Node* limit, float prob, float cnt) { assert((state() & (BlockS|LoopS|IfThenS|ElseS)), "bad state for new loop"); + + // Sync IdealKit and graphKit. + gkit->set_all_memory(this->merged_memory()); + gkit->set_control(this->ctrl()); + // Add loop predicate. + gkit->add_predicate(nargs); + // Update IdealKit memory. + this->set_all_memory(gkit->merged_memory()); + this->set_ctrl(gkit->control()); + set(iv, init); Node* head = make_label(1); bind(head); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/idealKit.hpp --- a/src/share/vm/opto/idealKit.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/idealKit.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -29,6 +29,7 @@ #include "opto/cfgnode.hpp" #include "opto/connode.hpp" #include "opto/divnode.hpp" +#include "opto/graphKit.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" #include "opto/subnode.hpp" @@ -160,7 +161,7 @@ bool push_new_state = true); void else_(); void end_if(); - void loop(IdealVariable& iv, Node* init, BoolTest::mask cmp, Node* limit, + void loop(GraphKit* gkit, int nargs, IdealVariable& iv, Node* init, BoolTest::mask cmp, Node* limit, float prob = PROB_LIKELY(0.9), float cnt = COUNT_UNKNOWN); void end_loop(); Node* make_label(int goto_ct); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/library_call.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1101,6 +1101,8 @@ float likely = PROB_LIKELY(0.9); float unlikely = PROB_UNLIKELY(0.9); + const int nargs = 2; // number of arguments to push back for uncommon trap in predicate + const int value_offset = java_lang_String::value_offset_in_bytes(); const int count_offset = java_lang_String::count_offset_in_bytes(); const int offset_offset = java_lang_String::offset_offset_in_bytes(); @@ -1116,7 +1118,7 @@ Node* sourcea = basic_plus_adr(string_object, string_object, value_offset); Node* source = make_load(no_ctrl, sourcea, source_type, T_OBJECT, string_type->add_offset(value_offset)); - Node* target = _gvn.transform( makecon(TypeOopPtr::make_from_constant(target_array)) ); + Node* target = _gvn.transform( makecon(TypeOopPtr::make_from_constant(target_array, true)) ); jint target_length = target_array->length(); const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin)); const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot); @@ -1138,12 +1140,12 @@ Node* return_ = __ make_label(1); __ set(rtn,__ ConI(-1)); - __ loop(i, sourceOffset, BoolTest::lt, sourceEnd); { + __ loop(this, nargs, i, sourceOffset, BoolTest::lt, sourceEnd); { Node* i2 = __ AddI(__ value(i), targetCountLess1); // pin to prohibit loading of "next iteration" value which may SEGV (rare) Node* src = load_array_element(__ ctrl(), source, i2, TypeAryPtr::CHARS); __ if_then(src, BoolTest::eq, lastChar, unlikely); { - __ loop(j, zero, BoolTest::lt, targetCountLess1); { + __ loop(this, nargs, j, zero, BoolTest::lt, targetCountLess1); { Node* tpj = __ AddI(targetOffset, __ value(j)); Node* targ = load_array_element(no_ctrl, target, tpj, target_type); Node* ipj = __ AddI(__ value(i), __ value(j)); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/loopTransform.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -205,6 +205,8 @@ } phase->register_new_node(addx, phase->get_ctrl(x)); phase->_igvn.replace_node(n1, addx); + assert(phase->get_loop(phase->get_ctrl(n1)) == this, ""); + _body.yank(n1); return addx; } @@ -307,15 +309,21 @@ // iterations adjusted. Therefore, we need to declare this loop as // no longer a 'main' loop; it will need new pre and post loops before // we can do further RCE. +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("Peel "); + loop->dump_head(); + } +#endif Node *h = loop->_head; - if( h->is_CountedLoop() ) { + if (h->is_CountedLoop()) { CountedLoopNode *cl = h->as_CountedLoop(); assert(cl->trip_count() > 0, "peeling a fully unrolled loop"); cl->set_trip_count(cl->trip_count() - 1); - if( cl->is_main_loop() ) { + if (cl->is_main_loop()) { cl->set_normal_loop(); #ifndef PRODUCT - if( PrintOpto && VerifyLoopOptimizations ) { + if (PrintOpto && VerifyLoopOptimizations) { tty->print("Peeling a 'main' loop; resetting to 'normal' "); loop->dump_head(); } @@ -645,6 +653,15 @@ // alignment. Useful to unroll loops that do no array accesses. void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_new, bool peel_only ) { +#ifndef PRODUCT + if (TraceLoopOpts) { + if (peel_only) + tty->print("PeelMainPost "); + else + tty->print("PreMainPost "); + loop->dump_head(); + } +#endif C->set_major_progress(); // Find common pieces of the loop being guarded with pre & post loops @@ -897,16 +914,19 @@ //------------------------------do_unroll-------------------------------------- // Unroll the loop body one step - make each trip do 2 iterations. void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool adjust_min_trip ) { - assert( LoopUnrollLimit, "" ); + assert(LoopUnrollLimit, ""); + CountedLoopNode *loop_head = loop->_head->as_CountedLoop(); + CountedLoopEndNode *loop_end = loop_head->loopexit(); + assert(loop_end, ""); #ifndef PRODUCT - if( PrintOpto && VerifyLoopOptimizations ) { + if (PrintOpto && VerifyLoopOptimizations) { tty->print("Unrolling "); loop->dump_head(); + } else if (TraceLoopOpts) { + tty->print("Unroll %d ", loop_head->unrolled_count()*2); + loop->dump_head(); } #endif - CountedLoopNode *loop_head = loop->_head->as_CountedLoop(); - CountedLoopEndNode *loop_end = loop_head->loopexit(); - assert( loop_end, "" ); // Remember loop node count before unrolling to detect // if rounds of unroll,optimize are making progress @@ -915,7 +935,7 @@ Node *ctrl = loop_head->in(LoopNode::EntryControl); Node *limit = loop_head->limit(); Node *init = loop_head->init_trip(); - Node *strid = loop_head->stride(); + Node *stride = loop_head->stride(); Node *opaq = NULL; if( adjust_min_trip ) { // If not maximally unrolling, need adjustment @@ -955,13 +975,13 @@ // odd iteration: (trip_cnt & ~1). Then back compute a new limit. Node *span = new (C, 3) SubINode( limit, init ); register_new_node( span, ctrl ); - Node *trip = new (C, 3) DivINode( 0, span, strid ); + Node *trip = new (C, 3) DivINode( 0, span, stride ); register_new_node( trip, ctrl ); Node *mtwo = _igvn.intcon(-2); set_ctrl(mtwo, C->root()); Node *rond = new (C, 3) AndINode( trip, mtwo ); register_new_node( rond, ctrl ); - Node *spn2 = new (C, 3) MulINode( rond, strid ); + Node *spn2 = new (C, 3) MulINode( rond, stride ); register_new_node( spn2, ctrl ); Node *lim2 = new (C, 3) AddINode( spn2, init ); register_new_node( lim2, ctrl ); @@ -1040,17 +1060,23 @@ void PhaseIdealLoop::do_maximally_unroll( IdealLoopTree *loop, Node_List &old_new ) { CountedLoopNode *cl = loop->_head->as_CountedLoop(); - assert( cl->trip_count() > 0, ""); + assert(cl->trip_count() > 0, ""); +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("MaxUnroll %d ", cl->trip_count()); + loop->dump_head(); + } +#endif // If loop is tripping an odd number of times, peel odd iteration - if( (cl->trip_count() & 1) == 1 ) { - do_peeling( loop, old_new ); + if ((cl->trip_count() & 1) == 1) { + do_peeling(loop, old_new); } // Now its tripping an even number of times remaining. Double loop body. // Do not adjust pre-guards; they are not needed and do not exist. - if( cl->trip_count() > 0 ) { - do_unroll( loop, old_new, false ); + if (cl->trip_count() > 0) { + do_unroll(loop, old_new, false); } } @@ -1227,35 +1253,55 @@ // Eliminate range-checks and other trip-counter vs loop-invariant tests. void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { #ifndef PRODUCT - if( PrintOpto && VerifyLoopOptimizations ) { + if (PrintOpto && VerifyLoopOptimizations) { tty->print("Range Check Elimination "); loop->dump_head(); + } else if (TraceLoopOpts) { + tty->print("RangeCheck "); + loop->dump_head(); } #endif - assert( RangeCheckElimination, "" ); + assert(RangeCheckElimination, ""); CountedLoopNode *cl = loop->_head->as_CountedLoop(); - assert( cl->is_main_loop(), "" ); + assert(cl->is_main_loop(), ""); + + // protect against stride not being a constant + if (!cl->stride_is_con()) + return; // Find the trip counter; we are iteration splitting based on it Node *trip_counter = cl->phi(); // Find the main loop limit; we will trim it's iterations // to not ever trip end tests Node *main_limit = cl->limit(); + + // Need to find the main-loop zero-trip guard + Node *ctrl = cl->in(LoopNode::EntryControl); + assert(ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, ""); + Node *iffm = ctrl->in(0); + assert(iffm->Opcode() == Op_If, ""); + Node *bolzm = iffm->in(1); + assert(bolzm->Opcode() == Op_Bool, ""); + Node *cmpzm = bolzm->in(1); + assert(cmpzm->is_Cmp(), ""); + Node *opqzm = cmpzm->in(2); + // Can not optimize a loop if pre-loop Opaque1 node is optimized + // away and then another round of loop opts attempted. + if (opqzm->Opcode() != Op_Opaque1) + return; + assert(opqzm->in(1) == main_limit, "do not understand situation"); + // Find the pre-loop limit; we will expand it's iterations to // not ever trip low tests. - Node *ctrl = cl->in(LoopNode::EntryControl); - assert( ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, "" ); - Node *iffm = ctrl->in(0); - assert( iffm->Opcode() == Op_If, "" ); Node *p_f = iffm->in(0); - assert( p_f->Opcode() == Op_IfFalse, "" ); + assert(p_f->Opcode() == Op_IfFalse, ""); CountedLoopEndNode *pre_end = p_f->in(0)->as_CountedLoopEnd(); - assert( pre_end->loopnode()->is_pre_loop(), "" ); + assert(pre_end->loopnode()->is_pre_loop(), ""); Node *pre_opaq1 = pre_end->limit(); // Occasionally it's possible for a pre-loop Opaque1 node to be // optimized away and then another round of loop opts attempted. // We can not optimize this particular loop in that case. - if( pre_opaq1->Opcode() != Op_Opaque1 ) + if (pre_opaq1->Opcode() != Op_Opaque1) return; Opaque1Node *pre_opaq = (Opaque1Node*)pre_opaq1; Node *pre_limit = pre_opaq->in(1); @@ -1266,25 +1312,11 @@ // Ensure the original loop limit is available from the // pre-loop Opaque1 node. Node *orig_limit = pre_opaq->original_loop_limit(); - if( orig_limit == NULL || _igvn.type(orig_limit) == Type::TOP ) + if (orig_limit == NULL || _igvn.type(orig_limit) == Type::TOP) return; - // Need to find the main-loop zero-trip guard - Node *bolzm = iffm->in(1); - assert( bolzm->Opcode() == Op_Bool, "" ); - Node *cmpzm = bolzm->in(1); - assert( cmpzm->is_Cmp(), "" ); - Node *opqzm = cmpzm->in(2); - if( opqzm->Opcode() != Op_Opaque1 ) - return; - assert( opqzm->in(1) == main_limit, "do not understand situation" ); - // Must know if its a count-up or count-down loop - // protect against stride not being a constant - if ( !cl->stride_is_con() ) { - return; - } int stride_con = cl->stride_con(); Node *zero = _igvn.intcon(0); Node *one = _igvn.intcon(1); @@ -1566,16 +1598,24 @@ // have on the last iteration. This will break the loop. bool IdealLoopTree::policy_do_remove_empty_loop( PhaseIdealLoop *phase ) { // Minimum size must be empty loop - if( _body.size() > 7/*number of nodes in an empty loop*/ ) return false; + if (_body.size() > 7/*number of nodes in an empty loop*/) + return false; - if( !_head->is_CountedLoop() ) return false; // Dead loop + if (!_head->is_CountedLoop()) + return false; // Dead loop CountedLoopNode *cl = _head->as_CountedLoop(); - if( !cl->loopexit() ) return false; // Malformed loop - if( !phase->is_member(this,phase->get_ctrl(cl->loopexit()->in(CountedLoopEndNode::TestValue)) ) ) + if (!cl->loopexit()) + return false; // Malformed loop + if (!phase->is_member(this, phase->get_ctrl(cl->loopexit()->in(CountedLoopEndNode::TestValue)))) return false; // Infinite loop #ifndef PRODUCT - if( PrintOpto ) - tty->print_cr("Removing empty loop"); + if (PrintOpto) { + tty->print("Removing empty loop"); + this->dump_head(); + } else if (TraceLoopOpts) { + tty->print("Empty "); + this->dump_head(); + } #endif #ifdef ASSERT // Ensure only one phi which is the iv. @@ -1720,7 +1760,7 @@ //------------------------------iteration_split-------------------------------- bool IdealLoopTree::iteration_split( PhaseIdealLoop *phase, Node_List &old_new ) { // Recursively iteration split nested loops - if( _child && !_child->iteration_split( phase, old_new )) + if (_child && !_child->iteration_split(phase, old_new)) return false; // Clean out prior deadwood @@ -1729,21 +1769,20 @@ // Look for loop-exit tests with my 50/50 guesses from the Parsing stage. // Replace with a 1-in-10 exit guess. - if( _parent /*not the root loop*/ && + if (_parent /*not the root loop*/ && !_irreducible && // Also ignore the occasional dead backedge - !tail()->is_top() ) { + !tail()->is_top()) { adjust_loop_exit_prob(phase); } - // Gate unrolling, RCE and peeling efforts. - if( !_child && // If not an inner loop, do not split + if (!_child && // If not an inner loop, do not split !_irreducible && _allow_optimizations && - !tail()->is_top() ) { // Also ignore the occasional dead backedge + !tail()->is_top()) { // Also ignore the occasional dead backedge if (!_has_call) { - if (!iteration_split_impl( phase, old_new )) { + if (!iteration_split_impl(phase, old_new)) { return false; } } else if (policy_unswitching(phase)) { @@ -1752,16 +1791,17 @@ } // Minor offset re-organization to remove loop-fallout uses of - // trip counter. - if( _head->is_CountedLoop() ) phase->reorg_offsets( this ); - if( _next && !_next->iteration_split( phase, old_new )) + // trip counter when there was no major reshaping. + phase->reorg_offsets(this); + + if (_next && !_next->iteration_split(phase, old_new)) return false; return true; } //-------------------------------is_uncommon_trap_proj---------------------------- // Return true if proj is the form of "proj->[region->..]call_uct" -bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, bool must_reason_predicate) { +bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason) { int path_limit = 10; assert(proj, "invalid argument"); Node* out = proj; @@ -1772,8 +1812,8 @@ if (out->is_CallStaticJava()) { int req = out->as_CallStaticJava()->uncommon_trap_request(); if (req != 0) { - Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(req); - if (!must_reason_predicate || reason == Deoptimization::Reason_predicate){ + Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); + if (trap_reason == reason || reason == Deoptimization::Reason_none) { return true; } } @@ -1790,15 +1830,15 @@ // other_proj->[region->..]call_uct" // // "must_reason_predicate" means the uct reason must be Reason_predicate -bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, bool must_reason_predicate) { +bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, Deoptimization::DeoptReason reason) { Node *in0 = proj->in(0); if (!in0->is_If()) return false; // Variation of a dead If node. if (in0->outcnt() < 2) return false; IfNode* iff = in0->as_If(); - // we need "If(Conv2B(Opaque1(...)))" pattern for must_reason_predicate - if (must_reason_predicate) { + // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate + if (reason != Deoptimization::Reason_none) { if (iff->in(1)->Opcode() != Op_Conv2B || iff->in(1)->in(1)->Opcode() != Op_Opaque1) { return false; @@ -1806,7 +1846,19 @@ } ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj(); - return is_uncommon_trap_proj(other_proj, must_reason_predicate); + return is_uncommon_trap_proj(other_proj, reason); +} + +//-------------------------------register_control------------------------- +void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred) { + assert(n->is_CFG(), "must be control node"); + _igvn.register_new_node_with_optimizer(n); + loop->_body.push(n); + set_loop(n, loop); + // When called from beautify_loops() idom is not constructed yet. + if (_idom != NULL) { + set_idom(n, pred, dom_depth(pred)); + } } //------------------------------create_new_if_for_predicate------------------------ @@ -1843,8 +1895,10 @@ // // We will create a region to guard the uct call if there is no one there. // The true projecttion (if_cont) of the new_iff is returned. -ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj) { - assert(is_uncommon_trap_if_pattern(cont_proj, true), "must be a uct if pattern!"); +// This code is also used to clone predicates to clonned loops. +ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, + Deoptimization::DeoptReason reason) { + assert(is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!"); IfNode* iff = cont_proj->in(0)->as_If(); ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con); @@ -1854,57 +1908,84 @@ if (!rgn->is_Region()) { // create a region to guard the call assert(rgn->is_Call(), "must be call uct"); CallNode* call = rgn->as_Call(); + IdealLoopTree* loop = get_loop(call); rgn = new (C, 1) RegionNode(1); - _igvn.set_type(rgn, rgn->bottom_type()); rgn->add_req(uncommon_proj); - set_idom(rgn, idom(uncommon_proj), dom_depth(uncommon_proj)+1); + register_control(rgn, loop, uncommon_proj); _igvn.hash_delete(call); call->set_req(0, rgn); + // When called from beautify_loops() idom is not constructed yet. + if (_idom != NULL) { + set_idom(call, rgn, dom_depth(rgn)); + } } + Node* entry = iff->in(0); + if (new_entry != NULL) { + // Clonning the predicate to new location. + entry = new_entry; + } // Create new_iff - uint iffdd = dom_depth(iff); - IdealLoopTree* lp = get_loop(iff); - IfNode *new_iff = new (C, 2) IfNode(iff->in(0), NULL, iff->_prob, iff->_fcnt); - register_node(new_iff, lp, idom(iff), iffdd); + IdealLoopTree* lp = get_loop(entry); + IfNode *new_iff = new (C, 2) IfNode(entry, NULL, iff->_prob, iff->_fcnt); + register_control(new_iff, lp, entry); Node *if_cont = new (C, 1) IfTrueNode(new_iff); Node *if_uct = new (C, 1) IfFalseNode(new_iff); if (cont_proj->is_IfFalse()) { // Swap Node* tmp = if_uct; if_uct = if_cont; if_cont = tmp; } - register_node(if_cont, lp, new_iff, iffdd); - register_node(if_uct, get_loop(rgn), new_iff, iffdd); - - // if_cont to iff - _igvn.hash_delete(iff); - iff->set_req(0, if_cont); - set_idom(iff, if_cont, dom_depth(iff)); + register_control(if_cont, lp, new_iff); + register_control(if_uct, get_loop(rgn), new_iff); // if_uct to rgn _igvn.hash_delete(rgn); rgn->add_req(if_uct); - Node* ridom = idom(rgn); - Node* nrdom = dom_lca(ridom, new_iff); - set_idom(rgn, nrdom, dom_depth(rgn)); - + // When called from beautify_loops() idom is not constructed yet. + if (_idom != NULL) { + Node* ridom = idom(rgn); + Node* nrdom = dom_lca(ridom, new_iff); + set_idom(rgn, nrdom, dom_depth(rgn)); + } // rgn must have no phis assert(!rgn->as_Region()->has_phi(), "region must have no phis"); + if (new_entry == NULL) { + // Attach if_cont to iff + _igvn.hash_delete(iff); + iff->set_req(0, if_cont); + if (_idom != NULL) { + set_idom(iff, if_cont, dom_depth(iff)); + } + } return if_cont->as_Proj(); } -//------------------------------find_predicate_insertion_point-------------------------- +//--------------------------find_predicate_insertion_point------------------- // Find a good location to insert a predicate -ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c) { - if (start_c == C->root() || !start_c->is_Proj()) +ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason) { + if (start_c == NULL || !start_c->is_Proj()) return NULL; - if (is_uncommon_trap_if_pattern(start_c->as_Proj(), true/*Reason_Predicate*/)) { + if (is_uncommon_trap_if_pattern(start_c->as_Proj(), reason)) { return start_c->as_Proj(); } return NULL; } +//--------------------------find_predicate------------------------------------ +// Find a predicate +Node* PhaseIdealLoop::find_predicate(Node* entry) { + Node* predicate = NULL; + if (UseLoopPredicate) { + predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); + if (predicate != NULL) { // right pattern that can be used by loop predication + assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); + return entry; + } + } + return NULL; +} + //------------------------------Invariance----------------------------------- // Helper class for loop_predication_impl to compute invariance on the fly and // clone invariants. @@ -2151,6 +2232,11 @@ return false; } + if (loop->_head->unique_ctrl_out()->Opcode() == Op_NeverBranch) { + // do nothing for infinite loops + return false; + } + CountedLoopNode *cl = NULL; if (loop->_head->is_CountedLoop()) { cl = loop->_head->as_CountedLoop(); @@ -2158,40 +2244,22 @@ if (!cl->is_normal_loop()) return false; } - // Too many traps seen? - bool tmt = C->too_many_traps(C->method(), 0, Deoptimization::Reason_predicate); - int tc = C->trap_count(Deoptimization::Reason_predicate); - if (tmt || tc > 0) { - if (TraceLoopPredicate) { - tty->print_cr("too many predicate traps: %d", tc); - C->method()->print(); // which method has too many predicate traps - tty->print_cr(""); - } - return false; - } - LoopNode *lpn = loop->_head->as_Loop(); Node* entry = lpn->in(LoopNode::EntryControl); - ProjNode *predicate_proj = find_predicate_insertion_point(entry); - if (!predicate_proj){ + ProjNode *predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); + if (!predicate_proj) { #ifndef PRODUCT if (TraceLoopPredicate) { tty->print("missing predicate:"); loop->dump_head(); + lpn->dump(1); } #endif return false; } - ConNode* zero = _igvn.intcon(0); set_ctrl(zero, C->root()); - Node *cond_false = new (C, 2) Conv2BNode(zero); - register_new_node(cond_false, C->root()); - ConNode* one = _igvn.intcon(1); - set_ctrl(one, C->root()); - Node *cond_true = new (C, 2) Conv2BNode(one); - register_new_node(cond_true, C->root()); ResourceArea *area = Thread::current()->resource_area(); Invariance invar(area, loop); @@ -2218,7 +2286,7 @@ ProjNode* proj = if_proj_list.pop()->as_Proj(); IfNode* iff = proj->in(0)->as_If(); - if (!is_uncommon_trap_if_pattern(proj)) { + if (!is_uncommon_trap_if_pattern(proj, Deoptimization::Reason_none)) { if (loop->is_loop_exit(iff)) { // stop processing the remaining projs in the list because the execution of them // depends on the condition of "iff" (iff->in(1)). @@ -2242,7 +2310,8 @@ BoolNode* bol = test->as_Bool(); if (invar.is_invariant(bol)) { // Invariant test - new_predicate_proj = create_new_if_for_predicate(predicate_proj); + new_predicate_proj = create_new_if_for_predicate(predicate_proj, NULL, + Deoptimization::Reason_predicate); Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0); BoolNode* new_predicate_bol = invar.clone(bol, ctrl)->as_Bool(); @@ -2256,8 +2325,15 @@ IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If(); _igvn.hash_delete(new_predicate_iff); new_predicate_iff->set_req(1, new_predicate_bol); - if (TraceLoopPredicate) tty->print_cr("invariant if%s: %d", negated ? " negated" : "", new_predicate_iff->_idx); - +#ifndef PRODUCT + if (TraceLoopPredicate) { + tty->print("Predicate invariant if%s: %d ", negated ? " negated" : "", new_predicate_iff->_idx); + loop->dump_head(); + } else if (TraceLoopOpts) { + tty->print("Predicate IC "); + loop->dump_head(); + } +#endif } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) { assert(proj->_con == predicate_proj->_con, "must match"); @@ -2281,8 +2357,8 @@ // lower_bound test will dominate the upper bound test and all // cloned or created nodes will use the lower bound test as // their declared control. - ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj); - ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj); + ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate); + ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate); assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate"); Node *ctrl = lower_bound_proj->in(0)->as_If()->in(0); @@ -2311,41 +2387,24 @@ // Fall through into rest of the clean up code which will move // any dependent nodes onto the upper bound test. new_predicate_proj = upper_bound_proj; + +#ifndef PRODUCT + if (TraceLoopOpts && !TraceLoopPredicate) { + tty->print("Predicate RC "); + loop->dump_head(); + } +#endif } else { - // The other proj of the "iff" is a uncommon trap projection, and we can assume - // the other proj will not be executed ("executed" means uct raised). + // Loop variant check (for example, range check in non-counted loop) + // with uncommon trap. continue; } - + assert(new_predicate_proj != NULL, "sanity"); // Success - attach condition (new_predicate_bol) to predicate if invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate - // Eliminate the old if in the loop body - _igvn.hash_delete(iff); - iff->set_req(1, proj->is_IfFalse() ? cond_false : cond_true); - - Node* ctrl = new_predicate_proj; // new control - ProjNode* dp = proj; // old control - assert(get_loop(dp) == loop, "guaranteed at the time of collecting proj"); - // Find nodes (depends only on the test) off the surviving projection; - // move them outside the loop with the control of proj_clone - for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { - Node* cd = dp->fast_out(i); // Control-dependent node - if (cd->depends_only_on_test()) { - assert(cd->in(0) == dp, ""); - _igvn.hash_delete(cd); - cd->set_req(0, ctrl); // ctrl, not NULL - set_early_ctrl(cd); - _igvn._worklist.push(cd); - IdealLoopTree *new_loop = get_loop(get_ctrl(cd)); - if (new_loop != loop) { - if (!loop->_child) loop->_body.yank(cd); - if (!new_loop->_child ) new_loop->_body.push(cd); - } - --i; - --imax; - } - } + // Eliminate the old If in the loop body + dominated_by( new_predicate_proj, iff, proj->_con != new_predicate_proj->_con ); hoisted = true; C->set_major_progress(); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/loopUnswitch.cpp --- a/src/share/vm/opto/loopUnswitch.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/loopUnswitch.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -110,6 +110,13 @@ IfNode* unswitch_iff = find_unswitching_candidate((const IdealLoopTree *)loop); assert(unswitch_iff != NULL, "should be at least one"); +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("Unswitch %d ", head->unswitch_count()+1); + loop->dump_head(); + } +#endif + // Need to revert back to normal loop if (head->is_CountedLoop() && !head->as_CountedLoop()->is_normal_loop()) { head->as_CountedLoop()->set_normal_loop(); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/loopnode.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -56,12 +56,32 @@ // Dump special per-node info #ifndef PRODUCT void LoopNode::dump_spec(outputStream *st) const { - if( is_inner_loop () ) st->print( "inner " ); - if( is_partial_peel_loop () ) st->print( "partial_peel " ); - if( partial_peel_has_failed () ) st->print( "partial_peel_failed " ); + if (is_inner_loop()) st->print( "inner " ); + if (is_partial_peel_loop()) st->print( "partial_peel " ); + if (partial_peel_has_failed()) st->print( "partial_peel_failed " ); } #endif +//------------------------------is_valid_counted_loop------------------------- +bool LoopNode::is_valid_counted_loop() const { + if (is_CountedLoop()) { + CountedLoopNode* l = as_CountedLoop(); + CountedLoopEndNode* le = l->loopexit(); + if (le != NULL && + le->proj_out(1 /* true */) == l->in(LoopNode::LoopBackControl)) { + Node* phi = l->phi(); + Node* exit = le->proj_out(0 /* false */); + if (exit != NULL && exit->Opcode() == Op_IfFalse && + phi != NULL && phi->is_Phi() && + phi->in(LoopNode::LoopBackControl) == l->incr() && + le->loopnode() == l && le->stride_is_con()) { + return true; + } + } + } + return false; +} + //------------------------------get_early_ctrl--------------------------------- // Compute earliest legal control Node *PhaseIdealLoop::get_early_ctrl( Node *n ) { @@ -142,43 +162,44 @@ } //------------------------------is_counted_loop-------------------------------- -Node *PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { +bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { PhaseGVN *gvn = &_igvn; // Counted loop head must be a good RegionNode with only 3 not NULL // control input edges: Self, Entry, LoopBack. - if ( x->in(LoopNode::Self) == NULL || x->req() != 3 ) - return NULL; + if (x->in(LoopNode::Self) == NULL || x->req() != 3) + return false; Node *init_control = x->in(LoopNode::EntryControl); Node *back_control = x->in(LoopNode::LoopBackControl); - if( init_control == NULL || back_control == NULL ) // Partially dead - return NULL; + if (init_control == NULL || back_control == NULL) // Partially dead + return false; // Must also check for TOP when looking for a dead loop - if( init_control->is_top() || back_control->is_top() ) - return NULL; + if (init_control->is_top() || back_control->is_top()) + return false; // Allow funny placement of Safepoint - if( back_control->Opcode() == Op_SafePoint ) + if (back_control->Opcode() == Op_SafePoint) back_control = back_control->in(TypeFunc::Control); // Controlling test for loop Node *iftrue = back_control; uint iftrue_op = iftrue->Opcode(); - if( iftrue_op != Op_IfTrue && - iftrue_op != Op_IfFalse ) + if (iftrue_op != Op_IfTrue && + iftrue_op != Op_IfFalse) // I have a weird back-control. Probably the loop-exit test is in // the middle of the loop and I am looking at some trailing control-flow // merge point. To fix this I would have to partially peel the loop. - return NULL; // Obscure back-control + return false; // Obscure back-control // Get boolean guarding loop-back test Node *iff = iftrue->in(0); - if( get_loop(iff) != loop || !iff->in(1)->is_Bool() ) return NULL; + if (get_loop(iff) != loop || !iff->in(1)->is_Bool()) + return false; BoolNode *test = iff->in(1)->as_Bool(); BoolTest::mask bt = test->_test._test; float cl_prob = iff->as_If()->_prob; - if( iftrue_op == Op_IfFalse ) { + if (iftrue_op == Op_IfFalse) { bt = BoolTest(bt).negate(); cl_prob = 1.0 - cl_prob; } @@ -186,7 +207,7 @@ Node *cmp = test->in(1); int cmp_op = cmp->Opcode(); if( cmp_op != Op_CmpI ) - return NULL; // Avoid pointer & float compares + return false; // Avoid pointer & float compares // Find the trip-counter increment & limit. Limit must be loop invariant. Node *incr = cmp->in(1); @@ -196,55 +217,64 @@ // need 'loop()' test to tell if limit is loop invariant // --------- - if( !is_member( loop, get_ctrl(incr) ) ) { // Swapped trip counter and limit? - Node *tmp = incr; // Then reverse order into the CmpI + if (!is_member(loop, get_ctrl(incr))) { // Swapped trip counter and limit? + Node *tmp = incr; // Then reverse order into the CmpI incr = limit; limit = tmp; bt = BoolTest(bt).commute(); // And commute the exit test } - if( is_member( loop, get_ctrl(limit) ) ) // Limit must loop-invariant - return NULL; + if (is_member(loop, get_ctrl(limit))) // Limit must be loop-invariant + return false; + if (!is_member(loop, get_ctrl(incr))) // Trip counter must be loop-variant + return false; + Node* phi_incr = NULL; // Trip-counter increment must be commutative & associative. - uint incr_op = incr->Opcode(); - if( incr_op == Op_Phi && incr->req() == 3 ) { - incr = incr->in(2); // Assume incr is on backedge of Phi - incr_op = incr->Opcode(); + if (incr->is_Phi()) { + if (incr->as_Phi()->region() != x || incr->req() != 3) + return false; // Not simple trip counter expression + phi_incr = incr; + incr = phi_incr->in(LoopNode::LoopBackControl); // Assume incr is on backedge of Phi + if (!is_member(loop, get_ctrl(incr))) // Trip counter must be loop-variant + return false; } + Node* trunc1 = NULL; Node* trunc2 = NULL; const TypeInt* iv_trunc_t = NULL; if (!(incr = CountedLoopNode::match_incr_with_optional_truncation(incr, &trunc1, &trunc2, &iv_trunc_t))) { - return NULL; // Funny increment opcode + return false; // Funny increment opcode } + assert(incr->Opcode() == Op_AddI, "wrong increment code"); // Get merge point Node *xphi = incr->in(1); Node *stride = incr->in(2); - if( !stride->is_Con() ) { // Oops, swap these - if( !xphi->is_Con() ) // Is the other guy a constant? - return NULL; // Nope, unknown stride, bail out + if (!stride->is_Con()) { // Oops, swap these + if (!xphi->is_Con()) // Is the other guy a constant? + return false; // Nope, unknown stride, bail out Node *tmp = xphi; // 'incr' is commutative, so ok to swap xphi = stride; stride = tmp; } - //if( loop(xphi) != l) return NULL;// Merge point is in inner loop?? - if( !xphi->is_Phi() ) return NULL; // Too much math on the trip counter + // Stride must be constant + int stride_con = stride->get_int(); + assert(stride_con != 0, "missed some peephole opt"); + + if (!xphi->is_Phi()) + return false; // Too much math on the trip counter + if (phi_incr != NULL && phi_incr != xphi) + return false; PhiNode *phi = xphi->as_Phi(); - // Stride must be constant - const Type *stride_t = stride->bottom_type(); - int stride_con = stride_t->is_int()->get_con(); - assert( stride_con, "missed some peephole opt" ); - // Phi must be of loop header; backedge must wrap to increment - if( phi->region() != x ) return NULL; - if( trunc1 == NULL && phi->in(LoopNode::LoopBackControl) != incr || - trunc1 != NULL && phi->in(LoopNode::LoopBackControl) != trunc1 ) { - return NULL; + if (phi->region() != x) + return false; + if (trunc1 == NULL && phi->in(LoopNode::LoopBackControl) != incr || + trunc1 != NULL && phi->in(LoopNode::LoopBackControl) != trunc1) { + return false; } Node *init_trip = phi->in(LoopNode::EntryControl); - //if (!init_trip->is_Con()) return NULL; // avoid rolling over MAXINT/MININT // If iv trunc type is smaller than int, check for possible wrap. if (!TypeInt::INT->higher_equal(iv_trunc_t)) { @@ -267,12 +297,12 @@ if (stride_con > 0) { if (iv_trunc_t->_hi - phi_ft->_hi < stride_con || iv_trunc_t->_lo > phi_ft->_lo) { - return NULL; // truncation may occur + return false; // truncation may occur } } else if (stride_con < 0) { if (iv_trunc_t->_lo - phi_ft->_lo > stride_con || iv_trunc_t->_hi < phi_ft->_hi) { - return NULL; // truncation may occur + return false; // truncation may occur } } // No possibility of wrap so truncation can be discarded @@ -281,35 +311,45 @@ assert(trunc1 == NULL && trunc2 == NULL, "no truncation for int"); } + // If the condition is inverted and we will be rolling + // through MININT to MAXINT, then bail out. + if (bt == BoolTest::eq || // Bail out, but this loop trips at most twice! + // Odd stride + bt == BoolTest::ne && stride_con != 1 && stride_con != -1 || + // Count down loop rolls through MAXINT + (bt == BoolTest::le || bt == BoolTest::lt) && stride_con < 0 || + // Count up loop rolls through MININT + (bt == BoolTest::ge || bt == BoolTest::gt) && stride_con > 0 ) { + return false; // Bail out + } + + const TypeInt* init_t = gvn->type(init_trip)->is_int(); + const TypeInt* limit_t = gvn->type(limit)->is_int(); + + if (stride_con > 0) { + long init_p = (long)init_t->_lo + stride_con; + if (init_p > (long)max_jint || init_p > (long)limit_t->_hi) + return false; // cyclic loop or this loop trips only once + } else { + long init_p = (long)init_t->_hi + stride_con; + if (init_p < (long)min_jint || init_p < (long)limit_t->_lo) + return false; // cyclic loop or this loop trips only once + } + // ================================================= // ---- SUCCESS! Found A Trip-Counted Loop! ----- // - // Canonicalize the condition on the test. If we can exactly determine - // the trip-counter exit value, then set limit to that value and use - // a '!=' test. Otherwise use condition '<' for count-up loops and - // '>' for count-down loops. If the condition is inverted and we will - // be rolling through MININT to MAXINT, then bail out. - + assert(x->Opcode() == Op_Loop, "regular loops only"); C->print_method("Before CountedLoop", 3); - // Check for SafePoint on backedge and remove - Node *sfpt = x->in(LoopNode::LoopBackControl); - if( sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { - lazy_replace( sfpt, iftrue ); - loop->_tail = iftrue; - } - - // If compare points to incr, we are ok. Otherwise the compare // can directly point to the phi; in this case adjust the compare so that // it points to the incr by adjusting the limit. - if( cmp->in(1) == phi || cmp->in(2) == phi ) + if (cmp->in(1) == phi || cmp->in(2) == phi) limit = gvn->transform(new (C, 3) AddINode(limit,stride)); // trip-count for +-tive stride should be: (limit - init_trip + stride - 1)/stride. // Final value for iterator should be: trip_count * stride + init_trip. - const Type *limit_t = limit->bottom_type(); - const Type *init_t = init_trip->bottom_type(); Node *one_p = gvn->intcon( 1); Node *one_m = gvn->intcon(-1); @@ -317,15 +357,15 @@ Node *hook = new (C, 6) Node(6); switch( bt ) { case BoolTest::eq: - return NULL; // Bail out, but this loop trips at most twice! + ShouldNotReachHere(); case BoolTest::ne: // Ahh, the case we desire - if( stride_con == 1 ) + if (stride_con == 1) trip_count = gvn->transform(new (C, 3) SubINode(limit,init_trip)); - else if( stride_con == -1 ) + else if (stride_con == -1) trip_count = gvn->transform(new (C, 3) SubINode(init_trip,limit)); else - return NULL; // Odd stride; must prove we hit limit exactly - set_subtree_ctrl( trip_count ); + ShouldNotReachHere(); + set_subtree_ctrl(trip_count); //_loop.map(trip_count->_idx,loop(limit)); break; case BoolTest::le: // Maybe convert to '<' case @@ -338,7 +378,8 @@ //_loop.map(limit->_idx,limit_loop); // Fall into next case case BoolTest::lt: { // Maybe convert to '!=' case - if( stride_con < 0 ) return NULL; // Count down loop rolls through MAXINT + if (stride_con < 0) // Count down loop rolls through MAXINT + ShouldNotReachHere(); Node *range = gvn->transform(new (C, 3) SubINode(limit,init_trip)); set_subtree_ctrl( range ); hook->init_req(0, range); @@ -367,7 +408,8 @@ //_loop.map(limit->_idx,limit_loop); // Fall into next case case BoolTest::gt: { // Maybe convert to '!=' case - if( stride_con > 0 ) return NULL; // count up loop rolls through MININT + if (stride_con > 0) // count up loop rolls through MININT + ShouldNotReachHere(); Node *range = gvn->transform(new (C, 3) SubINode(limit,init_trip)); set_subtree_ctrl( range ); hook->init_req(0, range); @@ -385,7 +427,7 @@ hook->init_req(3, trip_count); break; } - } + } // switch( bt ) Node *span = gvn->transform(new (C, 3) MulINode(trip_count,stride)); set_subtree_ctrl( span ); @@ -394,83 +436,82 @@ limit = gvn->transform(new (C, 3) AddINode(span,init_trip)); set_subtree_ctrl( limit ); + // Check for SafePoint on backedge and remove + Node *sfpt = x->in(LoopNode::LoopBackControl); + if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { + lazy_replace( sfpt, iftrue ); + loop->_tail = iftrue; + } + // Build a canonical trip test. // Clone code, as old values may be in use. + Node* nphi = PhiNode::make(x, init_trip, TypeInt::INT); + nphi = _igvn.register_new_node_with_optimizer(nphi); + set_ctrl(nphi, get_ctrl(phi)); + incr = incr->clone(); - incr->set_req(1,phi); + incr->set_req(1,nphi); incr->set_req(2,stride); incr = _igvn.register_new_node_with_optimizer(incr); set_early_ctrl( incr ); - _igvn.hash_delete(phi); - phi->set_req_X( LoopNode::LoopBackControl, incr, &_igvn ); - // If phi type is more restrictive than Int, raise to - // Int to prevent (almost) infinite recursion in igvn - // which can only handle integer types for constants or minint..maxint. - if (!TypeInt::INT->higher_equal(phi->bottom_type())) { - Node* nphi = PhiNode::make(phi->in(0), phi->in(LoopNode::EntryControl), TypeInt::INT); - nphi->set_req(LoopNode::LoopBackControl, phi->in(LoopNode::LoopBackControl)); - nphi = _igvn.register_new_node_with_optimizer(nphi); - set_ctrl(nphi, get_ctrl(phi)); - _igvn.replace_node(phi, nphi); - phi = nphi->as_Phi(); - } + nphi->set_req(LoopNode::LoopBackControl, incr); + _igvn.replace_node(phi, nphi); + phi = nphi->as_Phi(); + cmp = cmp->clone(); cmp->set_req(1,incr); cmp->set_req(2,limit); cmp = _igvn.register_new_node_with_optimizer(cmp); set_ctrl(cmp, iff->in(0)); - Node *tmp = test->clone(); - assert( tmp->is_Bool(), "" ); - test = (BoolNode*)tmp; - (*(BoolTest*)&test->_test)._test = bt; //BoolTest::ne; + test = test->clone()->as_Bool(); + (*(BoolTest*)&test->_test)._test = bt; test->set_req(1,cmp); _igvn.register_new_node_with_optimizer(test); set_ctrl(test, iff->in(0)); - // If the exit test is dead, STOP! - if( test == NULL ) return NULL; - _igvn.hash_delete(iff); - iff->set_req_X( 1, test, &_igvn ); // Replace the old IfNode with a new LoopEndNode - Node *lex = _igvn.register_new_node_with_optimizer(new (C, 2) CountedLoopEndNode( iff->in(0), iff->in(1), cl_prob, iff->as_If()->_fcnt )); + Node *lex = _igvn.register_new_node_with_optimizer(new (C, 2) CountedLoopEndNode( iff->in(0), test, cl_prob, iff->as_If()->_fcnt )); IfNode *le = lex->as_If(); uint dd = dom_depth(iff); set_idom(le, le->in(0), dd); // Update dominance for loop exit set_loop(le, loop); // Get the loop-exit control - Node *if_f = iff->as_If()->proj_out(!(iftrue_op == Op_IfTrue)); + Node *iffalse = iff->as_If()->proj_out(!(iftrue_op == Op_IfTrue)); // Need to swap loop-exit and loop-back control? - if( iftrue_op == Op_IfFalse ) { + if (iftrue_op == Op_IfFalse) { Node *ift2=_igvn.register_new_node_with_optimizer(new (C, 1) IfTrueNode (le)); Node *iff2=_igvn.register_new_node_with_optimizer(new (C, 1) IfFalseNode(le)); loop->_tail = back_control = ift2; set_loop(ift2, loop); - set_loop(iff2, get_loop(if_f)); + set_loop(iff2, get_loop(iffalse)); // Lazy update of 'get_ctrl' mechanism. - lazy_replace_proj( if_f , iff2 ); - lazy_replace_proj( iftrue, ift2 ); + lazy_replace_proj( iffalse, iff2 ); + lazy_replace_proj( iftrue, ift2 ); // Swap names - if_f = iff2; - iftrue = ift2; + iffalse = iff2; + iftrue = ift2; } else { - _igvn.hash_delete(if_f ); + _igvn.hash_delete(iffalse); _igvn.hash_delete(iftrue); - if_f ->set_req_X( 0, le, &_igvn ); - iftrue->set_req_X( 0, le, &_igvn ); + iffalse->set_req_X( 0, le, &_igvn ); + iftrue ->set_req_X( 0, le, &_igvn ); } - set_idom(iftrue, le, dd+1); - set_idom(if_f, le, dd+1); + set_idom(iftrue, le, dd+1); + set_idom(iffalse, le, dd+1); + assert(iff->outcnt() == 0, "should be dead now"); + lazy_replace( iff, le ); // fix 'get_ctrl' // Now setup a new CountedLoopNode to replace the existing LoopNode CountedLoopNode *l = new (C, 3) CountedLoopNode(init_control, back_control); + l->set_unswitch_count(x->as_Loop()->unswitch_count()); // Preserve // The following assert is approximately true, and defines the intention // of can_be_counted_loop. It fails, however, because phase->type // is not yet initialized for this loop and its parts. @@ -491,10 +532,14 @@ // Free up intermediate goo _igvn.remove_dead_node(hook); +#ifdef ASSERT + assert(l->is_valid_counted_loop(), "counted loop shape is messed up"); + assert(l == loop->_head && l->phi() == phi && l->loopexit() == lex, "" ); +#endif + C->print_method("After CountedLoop", 3); - // Return trip counter - return trip_count; + return true; } @@ -1256,17 +1301,98 @@ return true; } +//---------------------------replace_parallel_iv------------------------------- +// Replace parallel induction variable (parallel to trip counter) +void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { + assert(loop->_head->is_CountedLoop(), ""); + CountedLoopNode *cl = loop->_head->as_CountedLoop(); + Node *incr = cl->incr(); + if (incr == NULL) + return; // Dead loop? + Node *init = cl->init_trip(); + Node *phi = cl->phi(); + // protect against stride not being a constant + if (!cl->stride_is_con()) + return; + int stride_con = cl->stride_con(); + + PhaseGVN *gvn = &_igvn; + + // Visit all children, looking for Phis + for (DUIterator i = cl->outs(); cl->has_out(i); i++) { + Node *out = cl->out(i); + // Look for other phis (secondary IVs). Skip dead ones + if (!out->is_Phi() || out == phi || !has_node(out)) + continue; + PhiNode* phi2 = out->as_Phi(); + Node *incr2 = phi2->in( LoopNode::LoopBackControl ); + // Look for induction variables of the form: X += constant + if (phi2->region() != loop->_head || + incr2->req() != 3 || + incr2->in(1) != phi2 || + incr2 == incr || + incr2->Opcode() != Op_AddI || + !incr2->in(2)->is_Con()) + continue; + + // Check for parallel induction variable (parallel to trip counter) + // via an affine function. In particular, count-down loops with + // count-up array indices are common. We only RCE references off + // the trip-counter, so we need to convert all these to trip-counter + // expressions. + Node *init2 = phi2->in( LoopNode::EntryControl ); + int stride_con2 = incr2->in(2)->get_int(); + + // The general case here gets a little tricky. We want to find the + // GCD of all possible parallel IV's and make a new IV using this + // GCD for the loop. Then all possible IVs are simple multiples of + // the GCD. In practice, this will cover very few extra loops. + // Instead we require 'stride_con2' to be a multiple of 'stride_con', + // where +/-1 is the common case, but other integer multiples are + // also easy to handle. + int ratio_con = stride_con2/stride_con; + + if ((ratio_con * stride_con) == stride_con2) { // Check for exact + // Convert to using the trip counter. The parallel induction + // variable differs from the trip counter by a loop-invariant + // amount, the difference between their respective initial values. + // It is scaled by the 'ratio_con'. + // Perform local Ideal transformation since in most cases ratio == 1. + Node* ratio = _igvn.intcon(ratio_con); + set_ctrl(ratio, C->root()); + Node* hook = new (C, 3) Node(3); + Node* ratio_init = gvn->transform(new (C, 3) MulINode(init, ratio)); + hook->init_req(0, ratio_init); + Node* diff = gvn->transform(new (C, 3) SubINode(init2, ratio_init)); + hook->init_req(1, diff); + Node* ratio_idx = gvn->transform(new (C, 3) MulINode(phi, ratio)); + hook->init_req(2, ratio_idx); + Node* add = gvn->transform(new (C, 3) AddINode(ratio_idx, diff)); + set_subtree_ctrl(add); + _igvn.replace_node( phi2, add ); + // Free up intermediate goo + _igvn.remove_dead_node(hook); + // Sometimes an induction variable is unused + if (add->outcnt() == 0) { + _igvn.remove_dead_node(add); + } + --i; // deleted this phi; rescan starting with next position + continue; + } + } +} + //------------------------------counted_loop----------------------------------- // Convert to counted loops where possible void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { // For grins, set the inner-loop flag here - if( !_child ) { - if( _head->is_Loop() ) _head->as_Loop()->set_inner_loop(); + if (!_child) { + if (_head->is_Loop()) _head->as_Loop()->set_inner_loop(); } - if( _head->is_CountedLoop() || - phase->is_counted_loop( _head, this ) ) { + if (_head->is_CountedLoop() || + phase->is_counted_loop(_head, this)) { _has_sfpt = 1; // Indicate we do not need a safepoint here // Look for a safepoint to remove @@ -1275,79 +1401,9 @@ phase->is_deleteable_safept(n)) phase->lazy_replace(n,n->in(TypeFunc::Control)); - CountedLoopNode *cl = _head->as_CountedLoop(); - Node *incr = cl->incr(); - if( !incr ) return; // Dead loop? - Node *init = cl->init_trip(); - Node *phi = cl->phi(); - // protect against stride not being a constant - if( !cl->stride_is_con() ) return; - int stride_con = cl->stride_con(); - // Look for induction variables - - // Visit all children, looking for Phis - for (DUIterator i = cl->outs(); cl->has_out(i); i++) { - Node *out = cl->out(i); - // Look for other phis (secondary IVs). Skip dead ones - if (!out->is_Phi() || out == phi || !phase->has_node(out)) continue; - PhiNode* phi2 = out->as_Phi(); - Node *incr2 = phi2->in( LoopNode::LoopBackControl ); - // Look for induction variables of the form: X += constant - if( phi2->region() != _head || - incr2->req() != 3 || - incr2->in(1) != phi2 || - incr2 == incr || - incr2->Opcode() != Op_AddI || - !incr2->in(2)->is_Con() ) - continue; - - // Check for parallel induction variable (parallel to trip counter) - // via an affine function. In particular, count-down loops with - // count-up array indices are common. We only RCE references off - // the trip-counter, so we need to convert all these to trip-counter - // expressions. - Node *init2 = phi2->in( LoopNode::EntryControl ); - int stride_con2 = incr2->in(2)->get_int(); + phase->replace_parallel_iv(this); - // The general case here gets a little tricky. We want to find the - // GCD of all possible parallel IV's and make a new IV using this - // GCD for the loop. Then all possible IVs are simple multiples of - // the GCD. In practice, this will cover very few extra loops. - // Instead we require 'stride_con2' to be a multiple of 'stride_con', - // where +/-1 is the common case, but other integer multiples are - // also easy to handle. - int ratio_con = stride_con2/stride_con; - - if( ratio_con * stride_con == stride_con2 ) { // Check for exact - // Convert to using the trip counter. The parallel induction - // variable differs from the trip counter by a loop-invariant - // amount, the difference between their respective initial values. - // It is scaled by the 'ratio_con'. - Compile* C = phase->C; - Node* ratio = phase->_igvn.intcon(ratio_con); - phase->set_ctrl(ratio, C->root()); - Node* ratio_init = new (C, 3) MulINode(init, ratio); - phase->_igvn.register_new_node_with_optimizer(ratio_init, init); - phase->set_early_ctrl(ratio_init); - Node* diff = new (C, 3) SubINode(init2, ratio_init); - phase->_igvn.register_new_node_with_optimizer(diff, init2); - phase->set_early_ctrl(diff); - Node* ratio_idx = new (C, 3) MulINode(phi, ratio); - phase->_igvn.register_new_node_with_optimizer(ratio_idx, phi); - phase->set_ctrl(ratio_idx, cl); - Node* add = new (C, 3) AddINode(ratio_idx, diff); - phase->_igvn.register_new_node_with_optimizer(add); - phase->set_ctrl(add, cl); - phase->_igvn.replace_node( phi2, add ); - // Sometimes an induction variable is unused - if (add->outcnt() == 0) { - phase->_igvn.remove_dead_node(add); - } - --i; // deleted this phi; rescan starting with next position - continue; - } - } } else if (_parent != NULL && !_irreducible) { // Not a counted loop. // Look for a safepoint on the idom-path to remove, preserving the first one @@ -1366,24 +1422,31 @@ } // Recursively - if( _child ) _child->counted_loop( phase ); - if( _next ) _next ->counted_loop( phase ); + if (_child) _child->counted_loop( phase ); + if (_next) _next ->counted_loop( phase ); } #ifndef PRODUCT //------------------------------dump_head-------------------------------------- // Dump 1 liner for loop header info void IdealLoopTree::dump_head( ) const { - for( uint i=0; i<_nest; i++ ) + for (uint i=0; i<_nest; i++) tty->print(" "); tty->print("Loop: N%d/N%d ",_head->_idx,_tail->_idx); - if( _irreducible ) tty->print(" IRREDUCIBLE"); - if( _head->is_CountedLoop() ) { + if (_irreducible) tty->print(" IRREDUCIBLE"); + if (UseLoopPredicate) { + Node* entry = _head->in(LoopNode::EntryControl); + if (entry != NULL && entry->is_Proj() && + PhaseIdealLoop::is_uncommon_trap_if_pattern(entry->as_Proj(), Deoptimization::Reason_predicate)) { + tty->print(" predicated"); + } + } + if (_head->is_CountedLoop()) { CountedLoopNode *cl = _head->as_CountedLoop(); tty->print(" counted"); - if( cl->is_pre_loop () ) tty->print(" pre" ); - if( cl->is_main_loop() ) tty->print(" main"); - if( cl->is_post_loop() ) tty->print(" post"); + if (cl->is_pre_loop ()) tty->print(" pre" ); + if (cl->is_main_loop()) tty->print(" main"); + if (cl->is_post_loop()) tty->print(" post"); } tty->cr(); } @@ -1392,8 +1455,8 @@ // Dump loops by loop tree void IdealLoopTree::dump( ) const { dump_head(); - if( _child ) _child->dump(); - if( _next ) _next ->dump(); + if (_child) _child->dump(); + if (_next) _next ->dump(); } #endif @@ -1439,19 +1502,19 @@ } // self (only loops that we can apply loop predication may use their predicates) - if (loop->_head->is_Loop() && - !loop->_irreducible && + if (loop->_head->is_Loop() && + !loop->_irreducible && !loop->tail()->is_top()) { - LoopNode *lpn = loop->_head->as_Loop(); + LoopNode* lpn = loop->_head->as_Loop(); Node* entry = lpn->in(LoopNode::EntryControl); - ProjNode *predicate_proj = find_predicate_insertion_point(entry); + Node* predicate_proj = find_predicate(entry); if (predicate_proj != NULL ) { // right pattern that can be used by loop predication - assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); + assert(entry->in(0)->in(1)->in(1)->Opcode() == Op_Opaque1, "must be"); useful_predicates.push(entry->in(0)->in(1)->in(1)); // good one } } - if ( loop->_next ) { // sibling + if (loop->_next) { // sibling collect_potentially_useful_predicates(loop->_next, useful_predicates); } } @@ -1459,7 +1522,8 @@ //------------------------eliminate_useless_predicates----------------------------- // Eliminate all inserted predicates if they could not be used by loop predication. void PhaseIdealLoop::eliminate_useless_predicates() { - if (C->predicate_count() == 0) return; // no predicate left + if (C->predicate_count() == 0) + return; // no predicate left Unique_Node_List useful_predicates; // to store useful predicates if (C->has_loops()) { @@ -1647,12 +1711,15 @@ #ifndef PRODUCT C->verify_graph_edges(); - if( _verify_me ) { // Nested verify pass? + if (_verify_me) { // Nested verify pass? // Check to see if the verify mode is broken assert(C->unique() == unique, "non-optimize mode made Nodes? ? ?"); return; } - if( VerifyLoopOptimizations ) verify(); + if(VerifyLoopOptimizations) verify(); + if(TraceLoopOpts && C->has_loops()) { + _ltree_root->dump(); + } #endif if (ReassociateInvariants) { diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/loopnode.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -93,6 +93,7 @@ in(1) != NULL && phase->type(in(1)) != Type::TOP && in(2) != NULL && phase->type(in(2)) != Type::TOP; } + bool is_valid_counted_loop() const; #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif @@ -101,9 +102,8 @@ //------------------------------Counted Loops---------------------------------- // Counted loops are all trip-counted loops, with exactly 1 trip-counter exit // path (and maybe some other exit paths). The trip-counter exit is always -// last in the loop. The trip-counter does not have to stride by a constant, -// but it does have to stride by a loop-invariant amount; the exit value is -// also loop invariant. +// last in the loop. The trip-counter have to stride by a constant; +// the exit value is also loop invariant. // CountedLoopNodes and CountedLoopEndNodes come in matched pairs. The // CountedLoopNode has the incoming loop control and the loop-back-control @@ -112,7 +112,7 @@ // CountedLoopNode if there is control flow in the loop), the post-increment // trip-counter value, and the limit. The trip-counter value is always of // the form (Op old-trip-counter stride). The old-trip-counter is produced -// by a Phi connected to the CountedLoopNode. The stride is loop invariant. +// by a Phi connected to the CountedLoopNode. The stride is constant. // The Op is any commutable opcode, including Add, Mul, Xor. The // CountedLoopEndNode also takes in the loop-invariant limit value. @@ -696,6 +696,9 @@ // Is safept not required by an outer loop? bool is_deleteable_safept(Node* sfpt); + // Replace parallel induction variable (parallel to trip counter) + void replace_parallel_iv(IdealLoopTree *loop); + // Perform verification that the graph is valid. PhaseIdealLoop( PhaseIterGVN &igvn) : PhaseTransform(Ideal_Loop), @@ -751,7 +754,7 @@ // Per-Node transform virtual Node *transform( Node *a_node ) { return 0; } - Node *is_counted_loop( Node *x, IdealLoopTree *loop ); + bool is_counted_loop( Node *x, IdealLoopTree *loop ); // Return a post-walked LoopNode IdealLoopTree *get_loop( Node *n ) const { @@ -815,16 +818,22 @@ bool is_scaled_iv_plus_offset(Node* exp, Node* iv, int* p_scale, Node** p_offset, int depth = 0); // Return true if proj is for "proj->[region->..]call_uct" - bool is_uncommon_trap_proj(ProjNode* proj, bool must_reason_predicate = false); + // Return true if proj is for "proj->[region->..]call_uct" + static bool is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason); // Return true for "if(test)-> proj -> ... // | // V // other_proj->[region->..]call_uct" - bool is_uncommon_trap_if_pattern(ProjNode* proj, bool must_reason_predicate = false); + static bool is_uncommon_trap_if_pattern(ProjNode* proj, Deoptimization::DeoptReason reason); // Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted - ProjNode* create_new_if_for_predicate(ProjNode* cont_proj); - // Find a good location to insert a predicate - ProjNode* find_predicate_insertion_point(Node* start_c); + ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, + Deoptimization::DeoptReason reason); + void register_control(Node* n, IdealLoopTree *loop, Node* pred); + + // Find a good location to insert a predicate + static ProjNode* find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason); + // Find a predicate + static Node* find_predicate(Node* entry); // Construct a range check for a predicate if BoolNode* rc_predicate(Node* ctrl, int scale, Node* offset, @@ -936,7 +945,7 @@ Node *has_local_phi_input( Node *n ); // Mark an IfNode as being dominated by a prior test, // without actually altering the CFG (and hence IDOM info). - void dominated_by( Node *prevdom, Node *iff ); + void dominated_by( Node *prevdom, Node *iff, bool flip = false ); // Split Node 'n' through merge point Node *split_thru_region( Node *n, Node *region ); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/loopopts.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -42,13 +42,13 @@ return NULL; } int wins = 0; - assert( !n->is_CFG(), "" ); - assert( region->is_Region(), "" ); + assert(!n->is_CFG(), ""); + assert(region->is_Region(), ""); const Type* type = n->bottom_type(); const TypeOopPtr *t_oop = _igvn.type(n)->isa_oopptr(); Node *phi; - if( t_oop != NULL && t_oop->is_known_instance_field() ) { + if (t_oop != NULL && t_oop->is_known_instance_field()) { int iid = t_oop->instance_id(); int index = C->get_alias_index(t_oop); int offset = t_oop->offset(); @@ -57,20 +57,20 @@ phi = PhiNode::make_blank(region, n); } uint old_unique = C->unique(); - for( uint i = 1; i < region->req(); i++ ) { + for (uint i = 1; i < region->req(); i++) { Node *x; Node* the_clone = NULL; - if( region->in(i) == C->top() ) { + if (region->in(i) == C->top()) { x = C->top(); // Dead path? Use a dead data op } else { x = n->clone(); // Else clone up the data op the_clone = x; // Remember for possible deletion. // Alter data node to use pre-phi inputs - if( n->in(0) == region ) + if (n->in(0) == region) x->set_req( 0, region->in(i) ); - for( uint j = 1; j < n->req(); j++ ) { + for (uint j = 1; j < n->req(); j++) { Node *in = n->in(j); - if( in->is_Phi() && in->in(0) == region ) + if (in->is_Phi() && in->in(0) == region) x->set_req( j, in->in(i) ); // Use pre-Phi input for the clone } } @@ -85,7 +85,7 @@ // happen if the singleton occurs on loop entry, as the elimination of // the PhiNode may cause the resulting node to migrate back to a previous // loop iteration. - if( singleton && t == Type::TOP ) { + if (singleton && t == Type::TOP) { // Is_Loop() == false does not confirm the absence of a loop (e.g., an // irreducible loop may not be indicated by an affirmative is_Loop()); // therefore, the only top we can split thru a phi is on a backedge of @@ -93,7 +93,7 @@ singleton &= region->is_Loop() && (i != LoopNode::EntryControl); } - if( singleton ) { + if (singleton) { wins++; x = ((PhaseGVN&)_igvn).makecon(t); } else { @@ -108,12 +108,12 @@ // igvn->type(x) is set to x->Value() already. x->raise_bottom_type(t); Node *y = x->Identity(&_igvn); - if( y != x ) { + if (y != x) { wins++; x = y; } else { y = _igvn.hash_find(x); - if( y ) { + if (y) { wins++; x = y; } else { @@ -129,7 +129,7 @@ phi->set_req( i, x ); } // Too few wins? - if( wins <= policy ) { + if (wins <= policy) { _igvn.remove_dead_node(phi); return NULL; } @@ -137,7 +137,7 @@ // Record Phi register_new_node( phi, region ); - for( uint i2 = 1; i2 < phi->req(); i2++ ) { + for (uint i2 = 1; i2 < phi->req(); i2++) { Node *x = phi->in(i2); // If we commoned up the cloned 'x' with another existing Node, // the existing Node picks up a new use. We need to make the @@ -145,24 +145,44 @@ Node *old_ctrl; IdealLoopTree *old_loop; + if (x->is_Con()) { + // Constant's control is always root. + set_ctrl(x, C->root()); + continue; + } // The occasional new node - if( x->_idx >= old_unique ) { // Found a new, unplaced node? - old_ctrl = x->is_Con() ? C->root() : NULL; - old_loop = NULL; // Not in any prior loop + if (x->_idx >= old_unique) { // Found a new, unplaced node? + old_ctrl = NULL; + old_loop = NULL; // Not in any prior loop } else { - old_ctrl = x->is_Con() ? C->root() : get_ctrl(x); + old_ctrl = get_ctrl(x); old_loop = get_loop(old_ctrl); // Get prior loop } // New late point must dominate new use - Node *new_ctrl = dom_lca( old_ctrl, region->in(i2) ); + Node *new_ctrl = dom_lca(old_ctrl, region->in(i2)); + if (new_ctrl == old_ctrl) // Nothing is changed + continue; + + IdealLoopTree *new_loop = get_loop(new_ctrl); + + // Don't move x into a loop if its uses are + // outside of loop. Otherwise x will be cloned + // for each use outside of this loop. + IdealLoopTree *use_loop = get_loop(region); + if (!new_loop->is_member(use_loop) && + (old_loop == NULL || !new_loop->is_member(old_loop))) { + // Take early control, later control will be recalculated + // during next iteration of loop optimizations. + new_ctrl = get_early_ctrl(x); + new_loop = get_loop(new_ctrl); + } // Set new location set_ctrl(x, new_ctrl); - IdealLoopTree *new_loop = get_loop( new_ctrl ); // If changing loop bodies, see if we need to collect into new body - if( old_loop != new_loop ) { - if( old_loop && !old_loop->_child ) + if (old_loop != new_loop) { + if (old_loop && !old_loop->_child) old_loop->_body.yank(x); - if( !new_loop->_child ) + if (!new_loop->_child) new_loop->_body.push(x); // Collect body info } } @@ -174,9 +194,9 @@ // Replace the dominated test with an obvious true or false. Place it on the // IGVN worklist for later cleanup. Move control-dependent data Nodes on the // live path up to the dominating control. -void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff ) { +void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff, bool flip ) { #ifndef PRODUCT - if( VerifyLoopOptimizations && PrintOpto ) tty->print_cr("dominating test"); + if (VerifyLoopOptimizations && PrintOpto) tty->print_cr("dominating test"); #endif @@ -185,6 +205,12 @@ assert( iff->Opcode() == Op_If || iff->Opcode() == Op_CountedLoopEnd, "Check this code when new subtype is added"); int pop = prevdom->Opcode(); assert( pop == Op_IfFalse || pop == Op_IfTrue, "" ); + if (flip) { + if (pop == Op_IfTrue) + pop = Op_IfFalse; + else + pop = Op_IfTrue; + } // 'con' is set to true or false to kill the dominated test. Node *con = _igvn.makecon(pop == Op_IfTrue ? TypeInt::ONE : TypeInt::ZERO); set_ctrl(con, C->root()); // Constant gets a new use @@ -197,7 +223,7 @@ // I can assume this path reaches an infinite loop. In this case it's not // important to optimize the data Nodes - either the whole compilation will // be tossed or this path (and all data Nodes) will go dead. - if( iff->outcnt() != 2 ) return; + if (iff->outcnt() != 2) return; // Make control-dependent data Nodes on the live path (path that will remain // once the dominated IF is removed) become control-dependent on the @@ -207,16 +233,16 @@ for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { Node* cd = dp->fast_out(i); // Control-dependent node - if( cd->depends_only_on_test() ) { - assert( cd->in(0) == dp, "" ); - _igvn.hash_delete( cd ); + if (cd->depends_only_on_test()) { + assert(cd->in(0) == dp, ""); + _igvn.hash_delete(cd); cd->set_req(0, prevdom); - set_early_ctrl( cd ); + set_early_ctrl(cd); _igvn._worklist.push(cd); IdealLoopTree *new_loop = get_loop(get_ctrl(cd)); - if( old_loop != new_loop ) { - if( !old_loop->_child ) old_loop->_body.yank(cd); - if( !new_loop->_child ) new_loop->_body.push(cd); + if (old_loop != new_loop) { + if (!old_loop->_child) old_loop->_body.yank(cd); + if (!new_loop->_child) new_loop->_body.push(cd); } --i; --imax; @@ -2338,6 +2364,11 @@ } #if !defined(PRODUCT) + if (TraceLoopOpts) { + tty->print("PartialPeel "); + loop->dump_head(); + } + if (TracePartialPeeling) { tty->print_cr("before partial peel one iteration"); Node_List wl; @@ -2481,6 +2512,7 @@ // Create new loop head for new phis and to hang // the nodes being moved (sinked) from the peel region. LoopNode* new_head = new (C, 3) LoopNode(last_peel, last_peel); + new_head->set_unswitch_count(head->unswitch_count()); // Preserve _igvn.register_new_node_with_optimizer(new_head); assert(first_not_peeled->in(0) == last_peel, "last_peel <- first_not_peeled"); first_not_peeled->set_req(0, new_head); @@ -2651,24 +2683,23 @@ // prevent loop-fallout uses of the pre-incremented trip counter (which are // then alive with the post-incremented trip counter forcing an extra // register move) -void PhaseIdealLoop::reorg_offsets( IdealLoopTree *loop ) { +void PhaseIdealLoop::reorg_offsets(IdealLoopTree *loop) { + // Perform it only for canonical counted loops. + // Loop's shape could be messed up by iteration_split_impl. + if (!loop->_head->is_CountedLoop()) + return; + if (!loop->_head->as_Loop()->is_valid_counted_loop()) + return; CountedLoopNode *cl = loop->_head->as_CountedLoop(); CountedLoopEndNode *cle = cl->loopexit(); - if( !cle ) return; // The occasional dead loop - // Find loop exit control Node *exit = cle->proj_out(false); - assert( exit->Opcode() == Op_IfFalse, "" ); + Node *phi = cl->phi(); // Check for the special case of folks using the pre-incremented // trip-counter on the fall-out path (forces the pre-incremented // and post-incremented trip counter to be live at the same time). // Fix this by adjusting to use the post-increment trip counter. - Node *phi = cl->phi(); - if( !phi ) return; // Dead infinite loop - - // Shape messed up, probably by iteration_split_impl - if (phi->in(LoopNode::LoopBackControl) != cl->incr()) return; bool progress = true; while (progress) { @@ -2677,21 +2708,19 @@ Node* use = phi->fast_out(i); // User of trip-counter if (!has_ctrl(use)) continue; Node *u_ctrl = get_ctrl(use); - if( use->is_Phi() ) { + if (use->is_Phi()) { u_ctrl = NULL; - for( uint j = 1; j < use->req(); j++ ) - if( use->in(j) == phi ) - u_ctrl = dom_lca( u_ctrl, use->in(0)->in(j) ); + for (uint j = 1; j < use->req(); j++) + if (use->in(j) == phi) + u_ctrl = dom_lca(u_ctrl, use->in(0)->in(j)); } IdealLoopTree *u_loop = get_loop(u_ctrl); // Look for loop-invariant use - if( u_loop == loop ) continue; - if( loop->is_member( u_loop ) ) continue; + if (u_loop == loop) continue; + if (loop->is_member(u_loop)) continue; // Check that use is live out the bottom. Assuming the trip-counter // update is right at the bottom, uses of of the loop middle are ok. - if( dom_lca( exit, u_ctrl ) != exit ) continue; - // protect against stride not being a constant - if( !cle->stride_is_con() ) continue; + if (dom_lca(exit, u_ctrl) != exit) continue; // Hit! Refactor use to use the post-incremented tripcounter. // Compute a post-increment tripcounter. Node *opaq = new (C, 2) Opaque2Node( C, cle->incr() ); @@ -2702,9 +2731,10 @@ register_new_node( post, u_ctrl ); _igvn.hash_delete(use); _igvn._worklist.push(use); - for( uint j = 1; j < use->req(); j++ ) - if( use->in(j) == phi ) + for (uint j = 1; j < use->req(); j++) { + if (use->in(j) == phi) use->set_req(j, post); + } // Since DU info changed, rerun loop progress = true; break; diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/memnode.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1573,9 +1573,9 @@ return TypeInt::make(constant.as_int()); } else if (constant.basic_type() == T_ARRAY) { if (adr->bottom_type()->is_ptr_to_narrowoop()) { - return TypeNarrowOop::make_from_constant(constant.as_object()); + return TypeNarrowOop::make_from_constant(constant.as_object(), true); } else { - return TypeOopPtr::make_from_constant(constant.as_object()); + return TypeOopPtr::make_from_constant(constant.as_object(), true); } } } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/parse.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -136,6 +136,7 @@ uint _count; // how many times executed? Currently only set by _goto's bool _is_parsed; // has this block been parsed yet? bool _is_handler; // is this block an exception handler? + bool _has_merged_backedge; // does this block have merged backedge? SafePointNode* _start_map; // all values flowing into this block MethodLivenessResult _live_locals; // lazily initialized liveness bitmap @@ -168,6 +169,18 @@ // True after any predecessor flows control into this block bool is_merged() const { return _start_map != NULL; } +#ifdef ASSERT + // True after backedge predecessor flows control into this block + bool has_merged_backedge() const { return _has_merged_backedge; } + void mark_merged_backedge(Block* pred) { + assert(is_SEL_head(), "should be loop head"); + if (pred != NULL && is_SEL_backedge(pred)) { + assert(is_parsed(), "block should be parsed before merging backedges"); + _has_merged_backedge = true; + } + } +#endif + // True when all non-exception predecessors have been parsed. bool is_ready() const { return preds_parsed() == pred_count(); } @@ -441,11 +454,6 @@ } } - // Return true if the parser should add a loop predicate - bool should_add_predicate(int target_bci); - // Insert a loop predicate into the graph - void add_predicate(); - // Note: Intrinsic generation routines may be found in library_call.cpp. // Helper function to setup Ideal Call nodes @@ -483,8 +491,8 @@ bool static_field_ok_in_clinit(ciField *field, ciMethod *method); // common code for actually performing the load or store - void do_get_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool is_field); - void do_put_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool is_field); + void do_get_xxx(Node* obj, ciField* field, bool is_field); + void do_put_xxx(Node* obj, ciField* field, bool is_field); // loading from a constant field or the constant pool // returns false if push failed (non-perm field constants only, not ldcs) diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/parse1.cpp --- a/src/share/vm/opto/parse1.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/parse1.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -637,6 +637,25 @@ // (Note that dead locals do not get phis built, ever.) ensure_phis_everywhere(); + if (block->is_SEL_head() && + UseLoopPredicate) { + // Add predicate to single entry (not irreducible) loop head. + assert(!block->has_merged_backedge(), "only entry paths should be merged for now"); + // Need correct bci for predicate. + // It is fine to set it here since do_one_block() will set it anyway. + set_parse_bci(block->start()); + add_predicate(); + // Add new region for back branches. + int edges = block->pred_count() - block->preds_parsed() + 1; // +1 for original region + RegionNode *r = new (C, edges+1) RegionNode(edges+1); + _gvn.set_type(r, Type::CONTROL); + record_for_igvn(r); + r->init_req(edges, control()); + set_control(r); + // Add new phis. + ensure_phis_everywhere(); + } + // Leave behind an undisturbed copy of the map, for future merges. set_map(clone_map()); } @@ -1113,7 +1132,7 @@ _preds_parsed = 0; _count = 0; assert(pred_count() == 0 && preds_parsed() == 0, "sanity"); - assert(!(is_merged() || is_parsed() || is_handler()), "sanity"); + assert(!(is_merged() || is_parsed() || is_handler() || has_merged_backedge()), "sanity"); assert(_live_locals.size() == 0, "sanity"); // entry point has additional predecessor @@ -1350,10 +1369,6 @@ set_parse_bci(iter().cur_bci()); if (bci() == block()->limit()) { - // insert a predicate if it falls through to a loop head block - if (should_add_predicate(bci())){ - add_predicate(); - } // Do not walk into the next block until directed by do_all_blocks. merge(bci()); break; @@ -1498,17 +1513,29 @@ || target->is_handler() // These have unpredictable inputs. || target->is_loop_head() // Known multiple inputs || control()->is_Region()) { // We must hide this guy. + + int current_bci = bci(); + set_parse_bci(target->start()); // Set target bci + if (target->is_SEL_head()) { + DEBUG_ONLY( target->mark_merged_backedge(block()); ) + if (target->start() == 0) { + // Add loop predicate for the special case when + // there are backbranches to the method entry. + add_predicate(); + } + } // Add a Region to start the new basic block. Phis will be added // later lazily. int edges = target->pred_count(); if (edges < pnum) edges = pnum; // might be a new path! - Node *r = new (C, edges+1) RegionNode(edges+1); + RegionNode *r = new (C, edges+1) RegionNode(edges+1); gvn().set_type(r, Type::CONTROL); record_for_igvn(r); // zap all inputs to NULL for debugging (done in Node(uint) constructor) // for (int j = 1; j < edges+1; j++) { r->init_req(j, NULL); } r->init_req(pnum, control()); set_control(r); + set_parse_bci(current_bci); // Restore bci } // Convert the existing Parser mapping into a mapping at this bci. @@ -1517,7 +1544,11 @@ } else { // Prior mapping at this bci if (TraceOptoParse) { tty->print(" with previous state"); } - +#ifdef ASSERT + if (target->is_SEL_head()) { + target->mark_merged_backedge(block()); + } +#endif // We must not manufacture more phis if the target is already parsed. bool nophi = target->is_parsed(); @@ -2054,37 +2085,6 @@ } } -//------------------------------should_add_predicate-------------------------- -bool Parse::should_add_predicate(int target_bci) { - if (!UseLoopPredicate) return false; - Block* target = successor_for_bci(target_bci); - if (target != NULL && - target->is_loop_head() && - block()->rpo() < target->rpo()) { - return true; - } - return false; -} - -//------------------------------add_predicate--------------------------------- -void Parse::add_predicate() { - assert(UseLoopPredicate,"use only for loop predicate"); - Node *cont = _gvn.intcon(1); - Node* opq = _gvn.transform(new (C, 2) Opaque1Node(C, cont)); - Node *bol = _gvn.transform(new (C, 2) Conv2BNode(opq)); - IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN); - Node* iffalse = _gvn.transform(new (C, 1) IfFalseNode(iff)); - C->add_predicate_opaq(opq); - { - PreserveJVMState pjvms(this); - set_control(iffalse); - uncommon_trap(Deoptimization::Reason_predicate, - Deoptimization::Action_maybe_recompile); - } - Node* iftrue = _gvn.transform(new (C, 1) IfTrueNode(iff)); - set_control(iftrue); -} - #ifndef PRODUCT //------------------------show_parse_info-------------------------------------- void Parse::show_parse_info() { diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/parse2.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -293,11 +293,6 @@ if (len < 1) { // If this is a backward branch, add safepoint maybe_add_safepoint(default_dest); - if (should_add_predicate(default_dest)){ - _sp += 1; // set original stack for use by uncommon_trap - add_predicate(); - _sp -= 1; - } merge(default_dest); return; } @@ -344,11 +339,6 @@ if (len < 1) { // If this is a backward branch, add safepoint maybe_add_safepoint(default_dest); - if (should_add_predicate(default_dest)){ - _sp += 1; // set original stack for use by uncommon_trap - add_predicate(); - _sp -= 1; - } merge(default_dest); return; } @@ -756,9 +746,6 @@ push(_gvn.makecon(ret_addr)); // Flow to the jsr. - if (should_add_predicate(jsr_bci)){ - add_predicate(); - } merge(jsr_bci); } @@ -1040,11 +1027,6 @@ profile_taken_branch(target_bci); adjust_map_after_if(btest, c, prob, branch_block, next_block); if (!stopped()) { - if (should_add_predicate(target_bci)){ // add a predicate if it branches to a loop - int nargs = repush_if_args(); // set original stack for uncommon_trap - add_predicate(); - _sp -= nargs; - } merge(target_bci); } } @@ -1168,11 +1150,6 @@ profile_taken_branch(target_bci); adjust_map_after_if(taken_btest, c, prob, branch_block, next_block); if (!stopped()) { - if (should_add_predicate(target_bci)){ // add a predicate if it branches to a loop - int nargs = repush_if_args(); // set original stack for the uncommon_trap - add_predicate(); - _sp -= nargs; - } merge(target_bci); } } @@ -2166,10 +2143,6 @@ // Update method data profile_taken_branch(target_bci); - // Add loop predicate if it goes to a loop - if (should_add_predicate(target_bci)){ - add_predicate(); - } // Merge the current control into the target basic block merge(target_bci); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/parse3.cpp --- a/src/share/vm/opto/parse3.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/parse3.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -112,29 +112,31 @@ // Compile-time detect of null-exception? if (stopped()) return; +#ifdef ASSERT const TypeInstPtr *tjp = TypeInstPtr::make(TypePtr::NotNull, iter().get_declared_field_holder()); assert(_gvn.type(obj)->higher_equal(tjp), "cast_up is no longer needed"); +#endif if (is_get) { --_sp; // pop receiver before getting - do_get_xxx(tjp, obj, field, is_field); + do_get_xxx(obj, field, is_field); } else { - do_put_xxx(tjp, obj, field, is_field); + do_put_xxx(obj, field, is_field); --_sp; // pop receiver after putting } } else { - const TypeKlassPtr* tkp = TypeKlassPtr::make(field_holder); - obj = _gvn.makecon(tkp); + const TypeInstPtr* tip = TypeInstPtr::make(field_holder->java_mirror()); + obj = _gvn.makecon(tip); if (is_get) { - do_get_xxx(tkp, obj, field, is_field); + do_get_xxx(obj, field, is_field); } else { - do_put_xxx(tkp, obj, field, is_field); + do_put_xxx(obj, field, is_field); } } } -void Parse::do_get_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool is_field) { +void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) { // Does this field have a constant value? If so, just push the value. if (field->is_constant()) { if (field->is_static()) { @@ -231,7 +233,7 @@ } } -void Parse::do_put_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool is_field) { +void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) { bool is_vol = field->is_volatile(); // If reference is volatile, prevent following memory ops from // floating down past the volatile write. Also prevents commoning diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/stringopts.cpp --- a/src/share/vm/opto/stringopts.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/stringopts.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -910,7 +910,7 @@ ciObject* con = field->constant_value().as_object(); // Do not "join" in the previous type; it doesn't add value, // and may yield a vacuous result if the field is of interface type. - type = TypeOopPtr::make_from_constant(con)->isa_oopptr(); + type = TypeOopPtr::make_from_constant(con, true)->isa_oopptr(); assert(type != NULL, "field singleton type must be consistent"); } else { type = TypeOopPtr::make_from_klass(field_klass->as_klass()); @@ -969,6 +969,10 @@ // for (int i=0; ; i++) // if (x <= sizeTable[i]) // return i+1; + + // Add loop predicate first. + kit.add_predicate(); + RegionNode *loop = new (C, 3) RegionNode(3); loop->init_req(1, kit.control()); kit.gvn().set_type(loop, Type::CONTROL); @@ -1086,6 +1090,9 @@ // } { + // Add loop predicate first. + kit.add_predicate(); + RegionNode *head = new (C, 3) RegionNode(3); head->init_req(1, kit.control()); kit.gvn().set_type(head, Type::CONTROL); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/type.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -32,6 +32,7 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/klassKlass.hpp" #include "oops/objArrayKlass.hpp" #include "oops/typeArrayKlass.hpp" @@ -2241,43 +2242,49 @@ } else if (this->isa_aryptr()) { _is_ptr_to_narrowoop = (klass()->is_obj_array_klass() && _offset != arrayOopDesc::length_offset_in_bytes()); - } else if (klass() == ciEnv::current()->Class_klass() && - (_offset == java_lang_Class::klass_offset_in_bytes() || - _offset == java_lang_Class::array_klass_offset_in_bytes())) { - // Special hidden fields from the Class. - assert(this->isa_instptr(), "must be an instance ptr."); - _is_ptr_to_narrowoop = true; } else if (klass()->is_instance_klass()) { ciInstanceKlass* ik = klass()->as_instance_klass(); ciField* field = NULL; if (this->isa_klassptr()) { - // Perm objects don't use compressed references, except for - // static fields which are currently compressed. - field = ik->get_field_by_offset(_offset, true); - if (field != NULL) { - BasicType basic_elem_type = field->layout_type(); - _is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT || - basic_elem_type == T_ARRAY); - } + // Perm objects don't use compressed references } else if (_offset == OffsetBot || _offset == OffsetTop) { // unsafe access _is_ptr_to_narrowoop = true; } else { // exclude unsafe ops assert(this->isa_instptr(), "must be an instance ptr."); - // Field which contains a compressed oop references. - field = ik->get_field_by_offset(_offset, false); - if (field != NULL) { + + if (klass() == ciEnv::current()->Class_klass() && + (_offset == java_lang_Class::klass_offset_in_bytes() || + _offset == java_lang_Class::array_klass_offset_in_bytes())) { + // Special hidden fields from the Class. + assert(this->isa_instptr(), "must be an instance ptr."); + _is_ptr_to_narrowoop = true; + } else if (klass() == ciEnv::current()->Class_klass() && + _offset >= instanceMirrorKlass::offset_of_static_fields()) { + // Static fields + assert(o != NULL, "must be constant"); + ciInstanceKlass* k = o->as_instance()->java_lang_Class_klass()->as_instance_klass(); + ciField* field = k->get_field_by_offset(_offset, true); + assert(field != NULL, "missing field"); BasicType basic_elem_type = field->layout_type(); _is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT || basic_elem_type == T_ARRAY); - } else if (klass()->equals(ciEnv::current()->Object_klass())) { - // Compile::find_alias_type() cast exactness on all types to verify - // that it does not affect alias type. - _is_ptr_to_narrowoop = true; } else { - // Type for the copy start in LibraryCallKit::inline_native_clone(). - assert(!klass_is_exact(), "only non-exact klass"); - _is_ptr_to_narrowoop = true; + // Instance fields which contains a compressed oop references. + field = ik->get_field_by_offset(_offset, false); + if (field != NULL) { + BasicType basic_elem_type = field->layout_type(); + _is_ptr_to_narrowoop = (basic_elem_type == T_OBJECT || + basic_elem_type == T_ARRAY); + } else if (klass()->equals(ciEnv::current()->Object_klass())) { + // Compile::find_alias_type() cast exactness on all types to verify + // that it does not affect alias type. + _is_ptr_to_narrowoop = true; + } else { + // Type for the copy start in LibraryCallKit::inline_native_clone(). + assert(!klass_is_exact(), "only non-exact klass"); + _is_ptr_to_narrowoop = true; + } } } } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/opto/type.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -988,8 +988,8 @@ static const TypeNarrowOop *make( const TypePtr* type); - static const TypeNarrowOop* make_from_constant(ciObject* con) { - return make(TypeOopPtr::make_from_constant(con)); + static const TypeNarrowOop* make_from_constant(ciObject* con, bool require_constant = false) { + return make(TypeOopPtr::make_from_constant(con, require_constant)); } // returns the equivalent ptr type for this compressed pointer diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/prims/jni.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -1858,7 +1858,7 @@ // Static field. The fieldID a JNIid specifying the field holder and the offset within the klassOop. JNIid* id = jfieldIDWorkaround::from_static_jfieldID(fieldID); assert(id->is_static_field_id(), "invalid static field id"); - found = instanceKlass::cast(id->holder())->find_local_field_from_offset(id->offset(), true, &fd); + found = id->find_local_field(&fd); } else { // Non-static field. The fieldID is really the offset of the field within the instanceOop. int offset = jfieldIDWorkaround::from_instance_jfieldID(k, fieldID); @@ -1906,9 +1906,7 @@ JNIid* id = instanceKlass::cast(fd.field_holder())->jni_id_for(fd.offset()); debug_only(id->set_is_static_field_id();) - debug_only(int first_offset = instanceKlass::cast(fd.field_holder())->offset_of_static_fields();) - debug_only(int end_offset = first_offset + (instanceKlass::cast(fd.field_holder())->static_field_size() * wordSize);) - assert(id->offset() >= first_offset && id->offset() < end_offset, "invalid static field offset"); + debug_only(id->verify(fd.field_holder())); ret = jfieldIDWorkaround::to_static_jfieldID(id); return ret; @@ -1928,7 +1926,7 @@ if (JvmtiExport::should_post_field_access()) { JvmtiExport::jni_GetField_probe(thread, NULL, NULL, id->holder(), fieldID, true); } - jobject ret = JNIHandles::make_local(id->holder()->obj_field(id->offset())); + jobject ret = JNIHandles::make_local(id->holder()->java_mirror()->obj_field(id->offset())); DTRACE_PROBE1(hotspot_jni, GetStaticObjectField__return, ret); return ret; JNI_END @@ -1950,7 +1948,7 @@ if (JvmtiExport::should_post_field_access()) { \ JvmtiExport::jni_GetField_probe(thread, NULL, NULL, id->holder(), fieldID, true); \ } \ - ret = id->holder()-> Fieldname##_field (id->offset()); \ + ret = id->holder()->java_mirror()-> Fieldname##_field (id->offset()); \ return ret;\ JNI_END @@ -1976,7 +1974,7 @@ field_value.l = value; JvmtiExport::jni_SetField_probe(thread, NULL, NULL, id->holder(), fieldID, true, 'L', (jvalue *)&field_value); } - id->holder()->obj_field_put(id->offset(), JNIHandles::resolve(value)); + id->holder()->java_mirror()->obj_field_put(id->offset(), JNIHandles::resolve(value)); DTRACE_PROBE(hotspot_jni, SetStaticObjectField__return); JNI_END @@ -1999,7 +1997,7 @@ field_value.unionType = value; \ JvmtiExport::jni_SetField_probe(thread, NULL, NULL, id->holder(), fieldID, true, SigType, (jvalue *)&field_value); \ } \ - id->holder()-> Fieldname##_field_put (id->offset(), value); \ + id->holder()->java_mirror()-> Fieldname##_field_put (id->offset(), value); \ DTRACE_PROBE(hotspot_jni, SetStatic##Result##Field__return);\ JNI_END diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/prims/jniCheck.cpp --- a/src/share/vm/prims/jniCheck.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/prims/jniCheck.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -224,8 +224,7 @@ ReportJNIFatalError(thr, fatal_wrong_static_field); /* check for proper field type */ - if (!instanceKlass::cast(f_oop)->find_local_field_from_offset( - id->offset(), true, &fd)) + if (!id->find_local_field(&fd)) ReportJNIFatalError(thr, fatal_static_field_not_found); if ((fd.field_type() != ftype) && !(fd.field_type() == T_ARRAY && ftype == T_OBJECT)) { diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/prims/jvm.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1808,7 +1808,7 @@ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Wrong type at constant pool index"); } klassOop k = cp->klass_at(index, CHECK_NULL); - return (jclass) JNIHandles::make_local(k->klass_part()->java_mirror()); + return (jclass) JNIHandles::make_local(k->java_mirror()); } JVM_END @@ -1824,7 +1824,7 @@ } klassOop k = constantPoolOopDesc::klass_at_if_loaded(cp, index); if (k == NULL) return NULL; - return (jclass) JNIHandles::make_local(k->klass_part()->java_mirror()); + return (jclass) JNIHandles::make_local(k->java_mirror()); } JVM_END diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/prims/jvmtiEnvBase.cpp --- a/src/share/vm/prims/jvmtiEnvBase.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/prims/jvmtiEnvBase.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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 @@ -616,9 +616,7 @@ bool found = false; if (jfieldIDWorkaround::is_static_jfieldID(field)) { JNIid* id = jfieldIDWorkaround::from_static_jfieldID(field); - int offset = id->offset(); - klassOop holder = id->holder(); - found = instanceKlass::cast(holder)->find_local_field_from_offset(offset, true, fd); + found = id->find_local_field(fd); } else { // Non-static field. The fieldID is really the offset of the field within the object. int offset = jfieldIDWorkaround::from_instance_jfieldID(k, field); diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -3350,11 +3350,12 @@ for (Klass *subk = ik->subklass(); subk != NULL; subk = subk->next_sibling()) { - klassOop sub = subk->as_klassOop(); - instanceKlass *subik = (instanceKlass *)sub->klass_part(); - - // recursively do subclasses of the current subclass - increment_class_counter(subik, THREAD); + if (subk->oop_is_instance()) { + // Only update instanceKlasses + instanceKlass *subik = (instanceKlass*)subk; + // recursively do subclasses of the current subclass + increment_class_counter(subik, THREAD); + } } } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/prims/jvmtiTagMap.cpp --- a/src/share/vm/prims/jvmtiTagMap.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/prims/jvmtiTagMap.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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 @@ -27,6 +27,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "jvmtifiles/jvmtiEnv.hpp" +#include "oops/instanceMirrorKlass.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline2.hpp" #include "prims/jvmtiEventController.hpp" @@ -2594,6 +2595,11 @@ if (o->is_klass()) { klassOop k = (klassOop)o; o = Klass::cast(k)->java_mirror(); + if (o == NULL) { + // Classes without mirrors don't correspond to real Java + // classes so just ignore them. + return; + } } else { // SystemDictionary::always_strong_oops_do reports the application @@ -2834,10 +2840,10 @@ // verify that a static oop field is in range static inline bool verify_static_oop(instanceKlass* ik, - klassOop k, int offset) { - address obj_p = (address)k + offset; - address start = (address)ik->start_of_static_fields(); - address end = start + (ik->static_oop_field_size() * heapOopSize); + oop mirror, int offset) { + address obj_p = (address)mirror + offset; + address start = (address)instanceMirrorKlass::start_of_static_fields(mirror); + address end = start + (java_lang_Class::static_oop_field_count(mirror) * heapOopSize); assert(end >= start, "sanity check"); if (obj_p >= start && obj_p < end) { @@ -2938,8 +2944,8 @@ ClassFieldDescriptor* field = field_map->field_at(i); char type = field->field_type(); if (!is_primitive_field_type(type)) { - oop fld_o = k->obj_field(field->field_offset()); - assert(verify_static_oop(ik, k, field->field_offset()), "sanity check"); + oop fld_o = mirror->obj_field(field->field_offset()); + assert(verify_static_oop(ik, mirror, field->field_offset()), "sanity check"); if (fld_o != NULL) { int slot = field->field_index(); if (!CallbackInvoker::report_static_field_reference(mirror, fld_o, slot)) { @@ -2949,7 +2955,7 @@ } } else { if (is_reporting_primitive_fields()) { - address addr = (address)k + field->field_offset(); + address addr = (address)mirror + field->field_offset(); int slot = field->field_index(); if (!CallbackInvoker::report_primitive_static_field(mirror, slot, addr, type)) { delete field_map; diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/prims/unsafe.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -688,7 +688,7 @@ THROW_0(vmSymbols::java_lang_IllegalArgumentException()); } - return JNIHandles::make_local(env, java_lang_Class::as_klassOop(mirror)); + return JNIHandles::make_local(env, mirror); UNSAFE_END //@deprecated @@ -706,7 +706,7 @@ if (clazz == NULL) { THROW_0(vmSymbols::java_lang_NullPointerException()); } - return JNIHandles::make_local(env, java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(clazz))); + return JNIHandles::make_local(env, JNIHandles::resolve_non_null(clazz)); UNSAFE_END UNSAFE_ENTRY(void, Unsafe_EnsureClassInitialized(JNIEnv *env, jobject unsafe, jobject clazz)) diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/runtime/arguments.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -2819,22 +2819,38 @@ } void Arguments::set_shared_spaces_flags() { + const bool must_share = DumpSharedSpaces || RequireSharedSpaces; + const bool might_share = must_share || UseSharedSpaces; + + // The string table is part of the shared archive so the size must match. + if (!FLAG_IS_DEFAULT(StringTableSize)) { + // Disable sharing. + if (must_share) { + warning("disabling shared archive %s because of non-default " + "StringTableSize", DumpSharedSpaces ? "creation" : "use"); + } + if (might_share) { + FLAG_SET_DEFAULT(DumpSharedSpaces, false); + FLAG_SET_DEFAULT(RequireSharedSpaces, false); + FLAG_SET_DEFAULT(UseSharedSpaces, false); + } + return; + } + // Check whether class data sharing settings conflict with GC, compressed oops // or page size, and fix them up. Explicit sharing options override other // settings. const bool cannot_share = UseConcMarkSweepGC || CMSIncrementalMode || UseG1GC || UseParNewGC || UseParallelGC || UseParallelOldGC || UseCompressedOops || UseLargePages && FLAG_IS_CMDLINE(UseLargePages); - const bool must_share = DumpSharedSpaces || RequireSharedSpaces; - const bool might_share = must_share || UseSharedSpaces; if (cannot_share) { if (must_share) { - warning("selecting serial gc and disabling large pages %s" - "because of %s", "" LP64_ONLY("and compressed oops "), - DumpSharedSpaces ? "-Xshare:dump" : "-Xshare:on"); - force_serial_gc(); - FLAG_SET_CMDLINE(bool, UseLargePages, false); - LP64_ONLY(FLAG_SET_CMDLINE(bool, UseCompressedOops, false)); + warning("selecting serial gc and disabling large pages %s" + "because of %s", "" LP64_ONLY("and compressed oops "), + DumpSharedSpaces ? "-Xshare:dump" : "-Xshare:on"); + force_serial_gc(); + FLAG_SET_CMDLINE(bool, UseLargePages, false); + LP64_ONLY(FLAG_SET_CMDLINE(bool, UseCompressedOops, false)); } else { if (UseSharedSpaces && Verbose) { warning("turning off use of shared archive because of " @@ -2976,6 +2992,12 @@ } ScavengeRootsInCode = 1; } + if (!JavaObjectsInPerm && ScavengeRootsInCode == 0) { + if (!FLAG_IS_DEFAULT(ScavengeRootsInCode)) { + warning("forcing ScavengeRootsInCode non-zero because JavaObjectsInPerm is false"); + } + ScavengeRootsInCode = 1; + } if (PrintGCDetails) { // Turn on -verbose:gc options as well diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/runtime/globals.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -851,7 +851,7 @@ diagnostic(bool, TraceNMethodInstalls, false, \ "Trace nmethod intallation") \ \ - diagnostic(intx, ScavengeRootsInCode, 0, \ + diagnostic(intx, ScavengeRootsInCode, 1, \ "0: do not allow scavengable oops in the code cache; " \ "1: allow scavenging from the code cache; " \ "2: emit as many constants as the compiler can see") \ @@ -1221,6 +1221,11 @@ "Decay time (in milliseconds) to re-enable bulk rebiasing of a " \ "type after previous bulk rebias") \ \ + develop(bool, JavaObjectsInPerm, false, \ + "controls whether Classes and interned Strings are allocated" \ + "in perm. This purely intended to allow debugging issues" \ + "in production.") \ + \ /* tracing */ \ \ notproduct(bool, TraceRuntimeCalls, false, \ @@ -3751,6 +3756,9 @@ diagnostic(bool, PrintDTraceDOF, false, \ "Print the DTrace DOF passed to the system for JSDT probes") \ \ + product(uintx, StringTableSize, 1009, \ + "Number of buckets in the interned String table") \ + \ product(bool, UseVMInterruptibleIO, false, \ "(Unstable, Solaris-specific) Thread interrupt before or with " \ "EINTR for I/O operations results in OS_INTRPT. The default value"\ diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/runtime/os.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1079,11 +1079,6 @@ "%/lib/jsse.jar:" "%/lib/jce.jar:" "%/lib/charsets.jar:" - - // ## TEMPORARY hack to keep the legacy launcher working when - // ## only the boot module is installed (cf. j.l.ClassLoader) - "%/lib/modules/jdk.boot.jar:" - "%/classes"; char* sysclasspath = format_boot_path(classpath_format, home, home_len, fileSep, pathSep); if (sysclasspath == NULL) return false; diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/runtime/osThread.hpp --- a/src/share/vm/runtime/osThread.hpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/runtime/osThread.hpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ OSThreadStartFunc _start_proc; // Thread start routine void* _start_parm; // Thread start routine parameter volatile ThreadState _state; // Thread state *hint* - jint _interrupted; // Thread.isInterrupted state + volatile jint _interrupted; // Thread.isInterrupted state // Note: _interrupted must be jint, so that Java intrinsics can access it. // The value stored there must be either 0 or 1. It must be possible @@ -89,7 +89,7 @@ void* start_parm() const { return _start_parm; } void set_start_parm(void* start_parm) { _start_parm = start_parm; } - bool interrupted() const { return _interrupted != 0; } + volatile bool interrupted() const { return _interrupted != 0; } void set_interrupted(bool z) { _interrupted = z ? 1 : 0; } // Printing diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/runtime/reflection.cpp --- a/src/share/vm/runtime/reflection.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/runtime/reflection.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, 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 @@ -649,7 +649,7 @@ if (TraceClassResolution) { trace_class_resolution(k); } - return k->klass_part()->java_mirror(); + return k->java_mirror(); }; } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/runtime/thread.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -3166,7 +3166,7 @@ fieldDescriptor fd; // Possible we might not find this field; if so, don't break if (ik->find_local_field(vmSymbols::frontCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { - k()->bool_field_put(fd.offset(), true); + k()->java_mirror()->bool_field_put(fd.offset(), true); } } @@ -3182,7 +3182,7 @@ fieldDescriptor fd; // Possible we might not find this field: if so, silently don't break if (ik->find_local_field(vmSymbols::stringCacheEnabled_name(), vmSymbols::bool_signature(), &fd)) { - k()->bool_field_put(fd.offset(), true); + k()->java_mirror()->bool_field_put(fd.offset(), true); } } } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/runtime/vmStructs.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -269,7 +269,7 @@ nonstatic_field(instanceKlass, _inner_classes, typeArrayOop) \ nonstatic_field(instanceKlass, _nonstatic_field_size, int) \ nonstatic_field(instanceKlass, _static_field_size, int) \ - nonstatic_field(instanceKlass, _static_oop_field_size, int) \ + nonstatic_field(instanceKlass, _static_oop_field_count, int) \ nonstatic_field(instanceKlass, _nonstatic_oop_map_size, int) \ nonstatic_field(instanceKlass, _is_marked_dependent, bool) \ nonstatic_field(instanceKlass, _minor_version, u2) \ @@ -840,7 +840,7 @@ /* OSThread */ \ /************/ \ \ - nonstatic_field(OSThread, _interrupted, jint) \ + volatile_nonstatic_field(OSThread, _interrupted, jint) \ \ /************************/ \ /* OopMap and OopMapSet */ \ @@ -945,6 +945,15 @@ static_field(Arguments, _num_jvm_args, int) \ static_field(Arguments, _java_command, char*) \ \ + /*********************************/ \ + /* java_lang_Class fields */ \ + /*********************************/ \ + \ + static_field(java_lang_Class, klass_offset, int) \ + static_field(java_lang_Class, resolved_constructor_offset, int) \ + static_field(java_lang_Class, array_klass_offset, int) \ + static_field(java_lang_Class, oop_size_offset, int) \ + static_field(java_lang_Class, static_oop_field_count_offset, int) \ \ /************************/ \ /* Miscellaneous fields */ \ @@ -1414,6 +1423,7 @@ declare_toplevel_type(intptr_t*) \ declare_unsigned_integer_type(InvocationCounter) /* FIXME: wrong type (not integer) */ \ declare_toplevel_type(JavaThread*) \ + declare_toplevel_type(java_lang_Class) \ declare_toplevel_type(jbyte*) \ declare_toplevel_type(jbyte**) \ declare_toplevel_type(jint*) \ @@ -1543,12 +1553,6 @@ \ declare_constant(SymbolTable::symbol_table_size) \ \ - /***************/ \ - /* StringTable */ \ - /***************/ \ - \ - declare_constant(StringTable::string_table_size) \ - \ /********************/ \ /* SystemDictionary */ \ /********************/ \ @@ -1700,15 +1704,6 @@ \ declare_constant(ConstantPoolCacheEntry::tosBits) \ \ - /*********************************/ \ - /* java_lang_Class field offsets */ \ - /*********************************/ \ - \ - declare_constant(java_lang_Class::hc_klass_offset) \ - declare_constant(java_lang_Class::hc_array_klass_offset) \ - declare_constant(java_lang_Class::hc_resolved_constructor_offset) \ - declare_constant(java_lang_Class::hc_number_of_fake_oop_fields) \ - \ /***************************************/ \ /* java_lang_Thread::ThreadStatus enum */ \ /***************************************/ \ diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/services/heapDumper.cpp --- a/src/share/vm/services/heapDumper.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/services/heapDumper.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -832,7 +832,7 @@ // value int offset = fld.offset(); - address addr = (address)k + offset; + address addr = (address)ikh->java_mirror() + offset; dump_field_value(writer, sig->byte_at(0), addr); } diff -r 661c46a8434c -r c10b82a05d58 src/share/vm/shark/sharkNativeWrapper.cpp --- a/src/share/vm/shark/sharkNativeWrapper.cpp Fri Mar 25 17:26:33 2011 -0700 +++ b/src/share/vm/shark/sharkNativeWrapper.cpp Fri Mar 25 18:04:45 2011 -0700 @@ -101,7 +101,7 @@ builder()->CreateStore( builder()->CreateInlineOop( JNIHandles::make_local( - target()->method_holder()->klass_part()->java_mirror())), + target()->method_holder()->java_mirror())), oop_tmp_slot()); param_types.push_back(box_type); diff -r 661c46a8434c -r c10b82a05d58 test/compiler/6987555/Test6987555.java --- a/test/compiler/6987555/Test6987555.java Fri Mar 25 17:26:33 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -/** - * @test - * @bug 6987555 - * @summary JSR 292 unboxing to a boolean value fails on big-endian SPARC - * - * @run main/othervm -Xint -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6987555 - */ - -import java.dyn.*; - -public class Test6987555 { - private static final Class CLASS = Test6987555.class; - private static final String NAME = "foo"; - private static final boolean DEBUG = false; - - public static void main(String[] args) throws Throwable { - testboolean(); - testbyte(); - testchar(); - testshort(); - testint(); - } - - // boolean - static void testboolean() throws Throwable { - doboolean(false); - doboolean(true); - } - static void doboolean(boolean x) throws Throwable { - if (DEBUG) System.out.println("boolean=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(boolean.class, boolean.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(boolean.class, Boolean.class)); - boolean a = (boolean) mh1.invokeExact(x); - boolean b = (boolean) mh2.invokeExact(Boolean.valueOf(x)); - assert a == b : a + " != " + b; - } - - // byte - static void testbyte() throws Throwable { - byte[] a = new byte[] { - Byte.MIN_VALUE, - Byte.MIN_VALUE + 1, - -0x0F, - -1, - 0, - 1, - 0x0F, - Byte.MAX_VALUE - 1, - Byte.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dobyte(a[i]); - } - } - static void dobyte(byte x) throws Throwable { - if (DEBUG) System.out.println("byte=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(byte.class, byte.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(byte.class, Byte.class)); - byte a = (byte) mh1.invokeExact(x); - byte b = (byte) mh2.invokeExact(Byte.valueOf(x)); - assert a == b : a + " != " + b; - } - - // char - static void testchar() throws Throwable { - char[] a = new char[] { - Character.MIN_VALUE, - Character.MIN_VALUE + 1, - 0x000F, - 0x00FF, - 0x0FFF, - Character.MAX_VALUE - 1, - Character.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dochar(a[i]); - } - } - static void dochar(char x) throws Throwable { - if (DEBUG) System.out.println("char=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(char.class, char.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(char.class, Character.class)); - char a = (char) mh1.invokeExact(x); - char b = (char) mh2.invokeExact(Character.valueOf(x)); - assert a == b : a + " != " + b; - } - - // short - static void testshort() throws Throwable { - short[] a = new short[] { - Short.MIN_VALUE, - Short.MIN_VALUE + 1, - -0x0FFF, - -0x00FF, - -0x000F, - -1, - 0, - 1, - 0x000F, - 0x00FF, - 0x0FFF, - Short.MAX_VALUE - 1, - Short.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doshort(a[i]); - } - } - static void doshort(short x) throws Throwable { - if (DEBUG) System.out.println("short=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(short.class, short.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(short.class, Short.class)); - short a = (short) mh1.invokeExact(x); - short b = (short) mh2.invokeExact(Short.valueOf(x)); - assert a == b : a + " != " + b; - } - - // int - static void testint() throws Throwable { - int[] a = new int[] { - Integer.MIN_VALUE, - Integer.MIN_VALUE + 1, - -0x00000FFF, - -0x000000FF, - -0x0000000F, - -1, - 0, - 1, - 0x0000000F, - 0x000000FF, - 0x00000FFF, - Integer.MAX_VALUE - 1, - Integer.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doint(a[i]); - } - } - static void doint(int x) throws Throwable { - if (DEBUG) System.out.println("int=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(int.class, int.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(int.class, Integer.class)); - int a = (int) mh1.invokeExact(x); - int b = (int) mh2.invokeExact(Integer.valueOf(x)); - assert a == b : a + " != " + b; - } - - public static boolean foo(boolean i) { return i; } - public static byte foo(byte i) { return i; } - public static char foo(char i) { return i; } - public static short foo(short i) { return i; } - public static int foo(int i) { return i; } -} diff -r 661c46a8434c -r c10b82a05d58 test/compiler/6991596/Test6991596.java --- a/test/compiler/6991596/Test6991596.java Fri Mar 25 17:26:33 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,465 +0,0 @@ -/* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -/** - * @test - * @bug 6991596 - * @summary JSR 292 unimplemented adapter_opt_i2i and adapter_opt_l2i on SPARC - * - * @run main/othervm -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6991596 - */ - -import java.dyn.*; - -public class Test6991596 { - private static final Class CLASS = Test6991596.class; - private static final String NAME = "foo"; - private static final boolean DEBUG = System.getProperty("DEBUG", "false").equals("true"); - - public static void main(String[] args) throws Throwable { - testboolean(); - testbyte(); - testchar(); - testshort(); - testint(); - testlong(); - } - - // Helpers to get various methods. - static MethodHandle getmh1(Class ret, Class arg) throws NoAccessException { - return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg)); - } - static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) { - return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); - } - static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) { - return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); - } - - // test adapter_opt_i2i - static void testboolean() throws Throwable { - boolean[] a = new boolean[] { - true, - false - }; - for (int i = 0; i < a.length; i++) { - doboolean(a[i]); - } - } - static void doboolean(boolean x) throws Throwable { - if (DEBUG) System.out.println("boolean=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, boolean.class); - // TODO add this for all cases when the bugs are fixed. - //MethodHandle mh3 = getmh3(mh1, boolean.class, boolean.class); - boolean a = (boolean) mh1.invokeExact((boolean) x); - boolean b = (boolean) mh2.invokeExact(x); - //boolean c = mh3.invokeExact((boolean) x); - check(x, a, b); - //check(x, c, x); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class ); - MethodHandle mh2 = getmh2(mh1, byte.class, boolean.class); - byte a = (byte) mh1.invokeExact((byte) (x ? 1 : 0)); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, boolean.class); - char a = (char) mh1.invokeExact((char) (x ? 1 : 0)); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, boolean.class); - short a = (short) mh1.invokeExact((short) (x ? 1 : 0)); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testbyte() throws Throwable { - byte[] a = new byte[] { - Byte.MIN_VALUE, - Byte.MIN_VALUE + 1, - -0x0F, - -1, - 0, - 1, - 0x0F, - Byte.MAX_VALUE - 1, - Byte.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dobyte(a[i]); - } - } - static void dobyte(byte x) throws Throwable { - if (DEBUG) System.out.println("byte=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, byte.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, byte.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, byte.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, byte.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testchar() throws Throwable { - char[] a = new char[] { - Character.MIN_VALUE, - Character.MIN_VALUE + 1, - 0x000F, - 0x00FF, - 0x0FFF, - Character.MAX_VALUE - 1, - Character.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dochar(a[i]); - } - } - static void dochar(char x) throws Throwable { - if (DEBUG) System.out.println("char=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, char.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, char.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, char.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, char.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testshort() throws Throwable { - short[] a = new short[] { - Short.MIN_VALUE, - Short.MIN_VALUE + 1, - -0x0FFF, - -0x00FF, - -0x000F, - -1, - 0, - 1, - 0x000F, - 0x00FF, - 0x0FFF, - Short.MAX_VALUE - 1, - Short.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doshort(a[i]); - } - } - static void doshort(short x) throws Throwable { - if (DEBUG) System.out.println("short=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, short.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, short.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, short.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, short.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testint() throws Throwable { - int[] a = new int[] { - Integer.MIN_VALUE, - Integer.MIN_VALUE + 1, - -0x0FFFFFFF, - -0x00FFFFFF, - -0x000FFFFF, - -0x0000FFFF, - -0x00000FFF, - -0x000000FF, - -0x0000000F, - -1, - 0, - 1, - 0x0000000F, - 0x000000FF, - 0x00000FFF, - 0x0000FFFF, - 0x000FFFFF, - 0x00FFFFFF, - 0x0FFFFFFF, - Integer.MAX_VALUE - 1, - Integer.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doint(a[i]); - } - } - static void doint(int x) throws Throwable { - if (DEBUG) System.out.println("int=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, int.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, int.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, int.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, int.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - assert a == b : a + " != " + b; - check(x, a, b); - } - - // int - { - MethodHandle mh1 = getmh1( int.class, int.class); - MethodHandle mh2 = getmh2(mh1, int.class, int.class); - int a = (int) mh1.invokeExact((int) x); - int b = (int) mh2.invokeExact(x); - check(x, a, b); - } - } - - // test adapter_opt_l2i - static void testlong() throws Throwable { - long[] a = new long[] { - Long.MIN_VALUE, - Long.MIN_VALUE + 1, - -0x000000000FFFFFFFL, - -0x0000000000FFFFFFL, - -0x00000000000FFFFFL, - -0x000000000000FFFFL, - -0x0000000000000FFFL, - -0x00000000000000FFL, - -0x000000000000000FL, - -1L, - 0L, - 1L, - 0x000000000000000FL, - 0x00000000000000FFL, - 0x0000000000000FFFL, - 0x0000000000000FFFL, - 0x000000000000FFFFL, - 0x00000000000FFFFFL, - 0x0000000000FFFFFFL, - 0x000000000FFFFFFFL, - Long.MAX_VALUE - 1, - Long.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dolong(a[i]); - } - } - static void dolong(long x) throws Throwable { - if (DEBUG) System.out.println("long=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, long.class); - boolean a = (boolean) mh1.invokeExact((x & 1L) == 1L); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, long.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, long.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, long.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - - // int - { - MethodHandle mh1 = getmh1( int.class, int.class); - MethodHandle mh2 = getmh2(mh1, int.class, long.class); - int a = (int) mh1.invokeExact((int) x); - int b = (int) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void check(boolean x, boolean e, boolean a) { p(z2h(x), z2h(e), z2h(a)); assert e == a : z2h(x) + ": " + z2h(e) + " != " + z2h(a); } - static void check(boolean x, byte e, byte a) { p(z2h(x), i2h(e), i2h(a)); assert e == a : z2h(x) + ": " + i2h(e) + " != " + i2h(a); } - static void check(boolean x, int e, int a) { p(z2h(x), i2h(e), i2h(a)); assert e == a : z2h(x) + ": " + i2h(e) + " != " + i2h(a); } - - static void check(int x, boolean e, boolean a) { p(i2h(x), z2h(e), z2h(a)); assert e == a : i2h(x) + ": " + z2h(e) + " != " + z2h(a); } - static void check(int x, byte e, byte a) { p(i2h(x), i2h(e), i2h(a)); assert e == a : i2h(x) + ": " + i2h(e) + " != " + i2h(a); } - static void check(int x, int e, int a) { p(i2h(x), i2h(e), i2h(a)); assert e == a : i2h(x) + ": " + i2h(e) + " != " + i2h(a); } - - static void check(long x, boolean e, boolean a) { p(l2h(x), z2h(e), z2h(a)); assert e == a : l2h(x) + ": " + z2h(e) + " != " + z2h(a); } - static void check(long x, byte e, byte a) { p(l2h(x), i2h(e), i2h(a)); assert e == a : l2h(x) + ": " + i2h(e) + " != " + i2h(a); } - static void check(long x, int e, int a) { p(l2h(x), i2h(e), i2h(a)); assert e == a : l2h(x) + ": " + i2h(e) + " != " + i2h(a); } - - static void p(String x, String e, String a) { if (DEBUG) System.out.println(x + ": expected: " + e + ", actual: " + a); } - - static String z2h(boolean x) { return x ? "1" : "0"; } - static String i2h(int x) { return Integer.toHexString(x); } - static String l2h(long x) { return Long.toHexString(x); } - - // to int - public static boolean foo(boolean i) { return i; } - public static byte foo(byte i) { return i; } - public static char foo(char i) { return i; } - public static short foo(short i) { return i; } - public static int foo(int i) { return i; } -}