# HG changeset patch # User xlu # Date 1255549220 25200 # Node ID a2ad635573fbb7229a754c67f38a2c5849aee66d # Parent 054afbef90813f8c8c180e8ee8a8afaff61dae38# Parent f4b900403d6e4b0af51447bd13bbe23fe3a1dac7 Merge diff -r 054afbef9081 -r a2ad635573fb .hgtags --- a/.hgtags Mon Sep 28 12:27:52 2009 -0400 +++ b/.hgtags Wed Oct 14 12:40:20 2009 -0700 @@ -45,3 +45,6 @@ d07e68298d4e17ebf93d8299e43fcc3ded26472a jdk7-b68 54fd4d9232969ea6cd3d236e5ad276183bb0d423 jdk7-b69 0632c3e615a315ff11e2ab1d64f4d82ff9853461 jdk7-b70 +50a95aa4a247f0cbbf66df285a8b1d78ffb153d9 jdk7-b71 +a94714c550658fd6741793ef036cb9625dc2ab1a jdk7-b72 +faf94d94786b621f8e13cbcc941ca69c6d967c3f jdk7-b73 diff -r 054afbef9081 -r a2ad635573fb agent/make/saenv.sh --- a/agent/make/saenv.sh Mon Sep 28 12:27:52 2009 -0400 +++ b/agent/make/saenv.sh Wed Oct 14 12:40:20 2009 -0700 @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb agent/make/saenv64.sh --- a/agent/make/saenv64.sh Mon Sep 28 12:27:52 2009 -0400 +++ b/agent/make/saenv64.sh Wed Oct 14 12:40:20 2009 -0700 @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb agent/src/os/solaris/proc/Makefile --- a/agent/src/os/solaris/proc/Makefile Mon Sep 28 12:27:52 2009 -0400 +++ b/agent/src/os/solaris/proc/Makefile Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ # -# Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2002-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb agent/src/os/solaris/proc/mapfile --- a/agent/src/os/solaris/proc/mapfile Mon Sep 28 12:27:52 2009 -0400 +++ b/agent/src/os/solaris/proc/mapfile Wed Oct 14 12:40:20 2009 -0700 @@ -1,7 +1,7 @@ # # -# Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved. +# Copyright 2003-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java Mon Sep 28 12:27:52 2009 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/CodeCache.java Wed Oct 14 12:40:20 2009 -0700 @@ -33,6 +33,7 @@ public class CodeCache { private static AddressField heapField; + private static AddressField scavengeRootNMethodsField; private static VirtualConstructor virtualConstructor; private CodeHeap heap; @@ -49,6 +50,7 @@ Type type = db.lookupType("CodeCache"); heapField = type.getAddressField("_heap"); + scavengeRootNMethodsField = type.getAddressField("_scavenge_root_nmethods"); virtualConstructor = new VirtualConstructor(db); // Add mappings for all possible CodeBlob subclasses @@ -67,6 +69,10 @@ heap = (CodeHeap) VMObjectFactory.newObject(CodeHeap.class, heapField.getValue()); } + public NMethod scavengeRootMethods() { + return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootNMethodsField.getValue()); + } + public boolean contains(Address p) { return getHeap().contains(p); } diff -r 054afbef9081 -r a2ad635573fb agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java --- a/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Mon Sep 28 12:27:52 2009 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Wed Oct 14 12:40:20 2009 -0700 @@ -40,7 +40,10 @@ /** != InvocationEntryBci if this nmethod is an on-stack replacement method */ private static CIntegerField entryBCIField; /** To support simple linked-list chaining of nmethods */ - private static AddressField linkField; + private static AddressField osrLinkField; + private static AddressField scavengeRootLinkField; + private static CIntegerField scavengeRootStateField; + /** Offsets for different nmethod parts */ private static CIntegerField exceptionOffsetField; private static CIntegerField deoptOffsetField; @@ -87,7 +90,10 @@ zombieInstructionSizeField = type.getCIntegerField("_zombie_instruction_size"); methodField = type.getOopField("_method"); entryBCIField = type.getCIntegerField("_entry_bci"); - linkField = type.getAddressField("_link"); + osrLinkField = type.getAddressField("_osr_link"); + scavengeRootLinkField = type.getAddressField("_scavenge_root_link"); + scavengeRootStateField = type.getCIntegerField("_scavenge_root_state"); + exceptionOffsetField = type.getCIntegerField("_exception_offset"); deoptOffsetField = type.getCIntegerField("_deoptimize_offset"); origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); @@ -219,10 +225,19 @@ return getEntryBCI(); } - public NMethod getLink() { - return (NMethod) VMObjectFactory.newObject(NMethod.class, linkField.getValue(addr)); + public NMethod getOSRLink() { + return (NMethod) VMObjectFactory.newObject(NMethod.class, osrLinkField.getValue(addr)); } + public NMethod getScavengeRootLink() { + return (NMethod) VMObjectFactory.newObject(NMethod.class, scavengeRootLinkField.getValue(addr)); + } + + public int getScavengeRootState() { + return (int) scavengeRootStateField.getValue(addr); + } + + /** Tells whether frames described by this nmethod can be deoptimized. Note: native wrappers cannot be deoptimized. */ public boolean canBeDeoptimized() { return isJavaMethod(); } diff -r 054afbef9081 -r a2ad635573fb agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java Mon Sep 28 12:27:52 2009 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/CompactibleFreeListSpace.java Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java --- a/agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java Mon Sep 28 12:27:52 2009 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/memory/FreeChunk.java Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb make/hotspot_version --- a/make/hotspot_version Mon Sep 28 12:27:52 2009 -0400 +++ b/make/hotspot_version Wed Oct 14 12:40:20 2009 -0700 @@ -35,7 +35,7 @@ HS_MAJOR_VER=17 HS_MINOR_VER=0 -HS_BUILD_NUMBER=01 +HS_BUILD_NUMBER=03 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff -r 054afbef9081 -r a2ad635573fb src/cpu/sparc/vm/assembler_sparc.cpp --- a/src/cpu/sparc/vm/assembler_sparc.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/cpu/sparc/vm/assembler_sparc.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -4676,3 +4676,50 @@ load_ptr_contents(base, G6_heapbase); } } + +// Compare char[] arrays aligned to 4 bytes. +void MacroAssembler::char_arrays_equals(Register ary1, Register ary2, + Register limit, Register result, + Register chr1, Register chr2, Label& Ldone) { + Label Lvector, Lloop; + assert(chr1 == result, "should be the same"); + + // Note: limit contains number of bytes (2*char_elements) != 0. + andcc(limit, 0x2, chr1); // trailing character ? + br(Assembler::zero, false, Assembler::pt, Lvector); + delayed()->nop(); + + // compare the trailing char + sub(limit, sizeof(jchar), limit); + lduh(ary1, limit, chr1); + lduh(ary2, limit, chr2); + cmp(chr1, chr2); + br(Assembler::notEqual, true, Assembler::pt, Ldone); + delayed()->mov(G0, result); // not equal + + // only one char ? + br_on_reg_cond(rc_z, true, Assembler::pn, limit, Ldone); + delayed()->add(G0, 1, result); // zero-length arrays are equal + + // word by word compare, dont't need alignment check + bind(Lvector); + // Shift ary1 and ary2 to the end of the arrays, negate limit + add(ary1, limit, ary1); + add(ary2, limit, ary2); + neg(limit, limit); + + lduw(ary1, limit, chr1); + bind(Lloop); + lduw(ary2, limit, chr2); + cmp(chr1, chr2); + br(Assembler::notEqual, true, Assembler::pt, Ldone); + delayed()->mov(G0, result); // not equal + inccc(limit, 2*sizeof(jchar)); + // annul LDUW if branch is not taken to prevent access past end of array + br(Assembler::notZero, true, Assembler::pt, Lloop); + delayed()->lduw(ary1, limit, chr1); // hoisted + + // Caller should set it: + // add(G0, 1, result); // equals +} + diff -r 054afbef9081 -r a2ad635573fb src/cpu/sparc/vm/assembler_sparc.hpp --- a/src/cpu/sparc/vm/assembler_sparc.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/cpu/sparc/vm/assembler_sparc.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -2455,6 +2455,11 @@ void inc_counter(address counter_addr, Register Rtmp1, Register Rtmp2); void inc_counter(int* counter_addr, Register Rtmp1, Register Rtmp2); + // Compare char[] arrays aligned to 4 bytes. + void char_arrays_equals(Register ary1, Register ary2, + Register limit, Register result, + Register chr1, Register chr2, Label& Ldone); + #undef VIRTUAL }; diff -r 054afbef9081 -r a2ad635573fb src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -2171,7 +2171,7 @@ // subtype which we can't check or src is the same array as dst // but not necessarily exactly of type default_type. Label known_ok, halt; - jobject2reg(op->expected_type()->encoding(), tmp); + jobject2reg(op->expected_type()->constant_encoding(), tmp); __ ld_ptr(dst, oopDesc::klass_offset_in_bytes(), tmp2); if (basic_type != T_OBJECT) { __ cmp(tmp, tmp2); @@ -2429,7 +2429,7 @@ assert(data->is_BitData(), "need BitData for checkcast"); Register mdo = k_RInfo; Register data_val = Rtmp1; - jobject2reg(md->encoding(), mdo); + jobject2reg(md->constant_encoding(), mdo); int mdo_offset_bias = 0; if (!Assembler::is_simm13(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) { @@ -2452,7 +2452,7 @@ // patching may screw with our temporaries on sparc, // so let's do it before loading the class if (k->is_loaded()) { - jobject2reg(k->encoding(), k_RInfo); + jobject2reg(k->constant_encoding(), k_RInfo); } else { jobject2reg_with_patching(k_RInfo, op->info_for_patch()); } @@ -2513,7 +2513,7 @@ // patching may screw with our temporaries on sparc, // so let's do it before loading the class if (k->is_loaded()) { - jobject2reg(k->encoding(), k_RInfo); + jobject2reg(k->constant_encoding(), k_RInfo); } else { jobject2reg_with_patching(k_RInfo, op->info_for_patch()); } @@ -2717,7 +2717,7 @@ assert(op->tmp1()->is_single_cpu(), "tmp1 must be allocated"); Register mdo = op->mdo()->as_register(); Register tmp1 = op->tmp1()->as_register(); - jobject2reg(md->encoding(), mdo); + jobject2reg(md->constant_encoding(), mdo); int mdo_offset_bias = 0; if (!Assembler::is_simm13(md->byte_offset_of_slot(data, CounterData::count_offset()) + data->size_in_bytes())) { @@ -2774,7 +2774,7 @@ if (receiver == NULL) { Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) - mdo_offset_bias); - jobject2reg(known_klass->encoding(), tmp1); + jobject2reg(known_klass->constant_encoding(), tmp1); __ st_ptr(tmp1, recv_addr); Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias); diff -r 054afbef9081 -r a2ad635573fb src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -668,7 +668,7 @@ __ add(obj.result(), offset.result(), addr); if (type == objectType) { // Write-barrier needed for Object fields. - pre_barrier(obj.result(), false, NULL); + pre_barrier(addr, false, NULL); } if (type == objectType) @@ -896,7 +896,7 @@ LIR_Opr len = length.result(); BasicType elem_type = x->elt_type(); - __ oop2reg(ciTypeArrayKlass::make(elem_type)->encoding(), klass_reg); + __ oop2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg); CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info); __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path); diff -r 054afbef9081 -r a2ad635573fb src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Mon Sep 28 12:27:52 2009 -0400 +++ b/src/cpu/sparc/vm/sparc.ad Wed Oct 14 12:40:20 2009 -0700 @@ -2838,63 +2838,41 @@ %} - enc_class enc_String_Compare(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{ + enc_class enc_String_Compare(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result) %{ Label Ldone, Lloop; MacroAssembler _masm(&cbuf); Register str1_reg = reg_to_register_object($str1$$reg); Register str2_reg = reg_to_register_object($str2$$reg); - Register tmp1_reg = reg_to_register_object($tmp1$$reg); - Register tmp2_reg = reg_to_register_object($tmp2$$reg); + Register cnt1_reg = reg_to_register_object($cnt1$$reg); + Register cnt2_reg = reg_to_register_object($cnt2$$reg); Register result_reg = reg_to_register_object($result$$reg); - // Get the first character position in both strings - // [8] char array, [12] offset, [16] count - int value_offset = java_lang_String:: value_offset_in_bytes(); - int offset_offset = java_lang_String::offset_offset_in_bytes(); - int count_offset = java_lang_String:: count_offset_in_bytes(); - - // load str1 (jchar*) base address into tmp1_reg - __ load_heap_oop(str1_reg, value_offset, tmp1_reg); - __ ld(str1_reg, offset_offset, result_reg); - __ add(tmp1_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp1_reg); - __ ld(str1_reg, count_offset, str1_reg); // hoisted - __ sll(result_reg, exact_log2(sizeof(jchar)), result_reg); - __ load_heap_oop(str2_reg, value_offset, tmp2_reg); // hoisted - __ add(result_reg, tmp1_reg, tmp1_reg); - - // load str2 (jchar*) base address into tmp2_reg - // __ ld_ptr(str2_reg, value_offset, tmp2_reg); // hoisted - __ ld(str2_reg, offset_offset, result_reg); - __ add(tmp2_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp2_reg); - __ ld(str2_reg, count_offset, str2_reg); // hoisted - __ sll(result_reg, exact_log2(sizeof(jchar)), result_reg); - __ subcc(str1_reg, str2_reg, O7); // hoisted - __ add(result_reg, tmp2_reg, tmp2_reg); + assert(result_reg != str1_reg && + result_reg != str2_reg && + result_reg != cnt1_reg && + result_reg != cnt2_reg , + "need different registers"); // Compute the minimum of the string lengths(str1_reg) and the // difference of the string lengths (stack) - // discard string base pointers, after loading up the lengths - // __ ld(str1_reg, count_offset, str1_reg); // hoisted - // __ ld(str2_reg, count_offset, str2_reg); // hoisted - // See if the lengths are different, and calculate min in str1_reg. // Stash diff in O7 in case we need it for a tie-breaker. Label Lskip; - // __ subcc(str1_reg, str2_reg, O7); // hoisted - __ sll(str1_reg, exact_log2(sizeof(jchar)), str1_reg); // scale the limit + __ subcc(cnt1_reg, cnt2_reg, O7); + __ sll(cnt1_reg, exact_log2(sizeof(jchar)), cnt1_reg); // scale the limit __ br(Assembler::greater, true, Assembler::pt, Lskip); - // str2 is shorter, so use its count: - __ delayed()->sll(str2_reg, exact_log2(sizeof(jchar)), str1_reg); // scale the limit + // cnt2 is shorter, so use its count: + __ delayed()->sll(cnt2_reg, exact_log2(sizeof(jchar)), cnt1_reg); // scale the limit __ bind(Lskip); - // reallocate str1_reg, str2_reg, result_reg + // reallocate cnt1_reg, cnt2_reg, result_reg // Note: limit_reg holds the string length pre-scaled by 2 - Register limit_reg = str1_reg; - Register chr2_reg = str2_reg; + Register limit_reg = cnt1_reg; + Register chr2_reg = cnt2_reg; Register chr1_reg = result_reg; - // tmp{12} are the base pointers + // str{12} are the base pointers // Is the minimum length zero? __ cmp(limit_reg, (int)(0 * sizeof(jchar))); // use cast to resolve overloading ambiguity @@ -2902,8 +2880,8 @@ __ delayed()->mov(O7, result_reg); // result is difference in lengths // Load first characters - __ lduh(tmp1_reg, 0, chr1_reg); - __ lduh(tmp2_reg, 0, chr2_reg); + __ lduh(str1_reg, 0, chr1_reg); + __ lduh(str2_reg, 0, chr2_reg); // Compare first characters __ subcc(chr1_reg, chr2_reg, chr1_reg); @@ -2915,7 +2893,7 @@ // Check after comparing first character to see if strings are equivalent Label LSkip2; // Check if the strings start at same location - __ cmp(tmp1_reg, tmp2_reg); + __ cmp(str1_reg, str2_reg); __ brx(Assembler::notEqual, true, Assembler::pt, LSkip2); __ delayed()->nop(); @@ -2932,23 +2910,23 @@ __ br(Assembler::equal, true, Assembler::pn, Ldone); __ delayed()->mov(O7, result_reg); // result is difference in lengths - // Shift tmp1_reg and tmp2_reg to the end of the arrays, negate limit - __ add(tmp1_reg, limit_reg, tmp1_reg); - __ add(tmp2_reg, limit_reg, tmp2_reg); + // Shift str1_reg and str2_reg to the end of the arrays, negate limit + __ add(str1_reg, limit_reg, str1_reg); + __ add(str2_reg, limit_reg, str2_reg); __ neg(chr1_reg, limit_reg); // limit = -(limit-2) // Compare the rest of the characters - __ lduh(tmp1_reg, limit_reg, chr1_reg); + __ lduh(str1_reg, limit_reg, chr1_reg); __ bind(Lloop); - // __ lduh(tmp1_reg, limit_reg, chr1_reg); // hoisted - __ lduh(tmp2_reg, limit_reg, chr2_reg); + // __ lduh(str1_reg, limit_reg, chr1_reg); // hoisted + __ lduh(str2_reg, limit_reg, chr2_reg); __ subcc(chr1_reg, chr2_reg, chr1_reg); __ br(Assembler::notZero, false, Assembler::pt, Ldone); assert(chr1_reg == result_reg, "result must be pre-placed"); __ delayed()->inccc(limit_reg, sizeof(jchar)); // annul LDUH if branch is not taken to prevent access past end of string __ br(Assembler::notZero, true, Assembler::pt, Lloop); - __ delayed()->lduh(tmp1_reg, limit_reg, chr1_reg); // hoisted + __ delayed()->lduh(str1_reg, limit_reg, chr1_reg); // hoisted // If strings are equal up to min length, return the length difference. __ mov(O7, result_reg); @@ -2957,125 +2935,80 @@ __ bind(Ldone); %} -enc_class enc_String_Equals(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{ - Label Lword, Lword_loop, Lpost_word, Lchar, Lchar_loop, Ldone; +enc_class enc_String_Equals(o0RegP str1, o1RegP str2, g3RegI cnt, notemp_iRegI result) %{ + Label Lword_loop, Lpost_word, Lchar, Lchar_loop, Ldone; MacroAssembler _masm(&cbuf); Register str1_reg = reg_to_register_object($str1$$reg); Register str2_reg = reg_to_register_object($str2$$reg); - Register tmp1_reg = reg_to_register_object($tmp1$$reg); - Register tmp2_reg = reg_to_register_object($tmp2$$reg); + Register cnt_reg = reg_to_register_object($cnt$$reg); + Register tmp1_reg = O7; Register result_reg = reg_to_register_object($result$$reg); - // Get the first character position in both strings - // [8] char array, [12] offset, [16] count - int value_offset = java_lang_String:: value_offset_in_bytes(); - int offset_offset = java_lang_String::offset_offset_in_bytes(); - int count_offset = java_lang_String:: count_offset_in_bytes(); - - // load str1 (jchar*) base address into tmp1_reg - __ load_heap_oop(Address(str1_reg, value_offset), tmp1_reg); - __ ld(Address(str1_reg, offset_offset), result_reg); - __ add(tmp1_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp1_reg); - __ ld(Address(str1_reg, count_offset), str1_reg); // hoisted - __ sll(result_reg, exact_log2(sizeof(jchar)), result_reg); - __ load_heap_oop(Address(str2_reg, value_offset), tmp2_reg); // hoisted - __ add(result_reg, tmp1_reg, tmp1_reg); - - // load str2 (jchar*) base address into tmp2_reg - // __ ld_ptr(Address(str2_reg, value_offset), tmp2_reg); // hoisted - __ ld(Address(str2_reg, offset_offset), result_reg); - __ add(tmp2_reg, arrayOopDesc::base_offset_in_bytes(T_CHAR), tmp2_reg); - __ ld(Address(str2_reg, count_offset), str2_reg); // hoisted - __ sll(result_reg, exact_log2(sizeof(jchar)), result_reg); - __ cmp(str1_reg, str2_reg); // hoisted - __ add(result_reg, tmp2_reg, tmp2_reg); - - __ sll(str1_reg, exact_log2(sizeof(jchar)), str1_reg); - __ br(Assembler::notEqual, true, Assembler::pt, Ldone); - __ delayed()->mov(G0, result_reg); // not equal - - __ br_zero(Assembler::equal, true, Assembler::pn, str1_reg, Ldone); - __ delayed()->add(G0, 1, result_reg); //equals - - __ cmp(tmp1_reg, tmp2_reg); //same string ? + assert(result_reg != str1_reg && + result_reg != str2_reg && + result_reg != cnt_reg && + result_reg != tmp1_reg , + "need different registers"); + + __ cmp(str1_reg, str2_reg); //same char[] ? __ brx(Assembler::equal, true, Assembler::pn, Ldone); __ delayed()->add(G0, 1, result_reg); + __ br_on_reg_cond(Assembler::rc_z, true, Assembler::pn, cnt_reg, Ldone); + __ delayed()->add(G0, 1, result_reg); // count == 0 + //rename registers - Register limit_reg = str1_reg; - Register chr2_reg = str2_reg; + Register limit_reg = cnt_reg; Register chr1_reg = result_reg; - // tmp{12} are the base pointers + Register chr2_reg = tmp1_reg; //check for alignment and position the pointers to the ends - __ or3(tmp1_reg, tmp2_reg, chr1_reg); - __ andcc(chr1_reg, 0x3, chr1_reg); // notZero means at least one not 4-byte aligned - __ br(Assembler::notZero, false, Assembler::pn, Lchar); - __ delayed()->nop(); - - __ bind(Lword); - __ and3(limit_reg, 0x2, O7); //remember the remainder (either 0 or 2) - __ andn(limit_reg, 0x3, limit_reg); - __ br_zero(Assembler::zero, false, Assembler::pn, limit_reg, Lpost_word); - __ delayed()->nop(); - - __ add(tmp1_reg, limit_reg, tmp1_reg); - __ add(tmp2_reg, limit_reg, tmp2_reg); - __ neg(limit_reg); - - __ lduw(tmp1_reg, limit_reg, chr1_reg); - __ bind(Lword_loop); - __ lduw(tmp2_reg, limit_reg, chr2_reg); - __ cmp(chr1_reg, chr2_reg); - __ br(Assembler::notEqual, true, Assembler::pt, Ldone); - __ delayed()->mov(G0, result_reg); - __ inccc(limit_reg, 2*sizeof(jchar)); - // annul LDUW if branch i s not taken to prevent access past end of string - __ br(Assembler::notZero, true, Assembler::pt, Lword_loop); //annul on taken - __ delayed()->lduw(tmp1_reg, limit_reg, chr1_reg); // hoisted - - __ bind(Lpost_word); - __ br_zero(Assembler::zero, true, Assembler::pt, O7, Ldone); - __ delayed()->add(G0, 1, result_reg); - - __ lduh(tmp1_reg, 0, chr1_reg); - __ lduh(tmp2_reg, 0, chr2_reg); - __ cmp (chr1_reg, chr2_reg); - __ br(Assembler::notEqual, true, Assembler::pt, Ldone); - __ delayed()->mov(G0, result_reg); + __ or3(str1_reg, str2_reg, chr1_reg); + __ andcc(chr1_reg, 0x3, chr1_reg); + // notZero means at least one not 4-byte aligned. + // We could optimize the case when both arrays are not aligned + // but it is not frequent case and it requires additional checks. + __ br(Assembler::notZero, false, Assembler::pn, Lchar); // char by char compare + __ delayed()->sll(limit_reg, exact_log2(sizeof(jchar)), limit_reg); // set byte count + + // Compare char[] arrays aligned to 4 bytes. + __ char_arrays_equals(str1_reg, str2_reg, limit_reg, result_reg, + chr1_reg, chr2_reg, Ldone); __ ba(false,Ldone); __ delayed()->add(G0, 1, result_reg); + // char by char compare __ bind(Lchar); - __ add(tmp1_reg, limit_reg, tmp1_reg); - __ add(tmp2_reg, limit_reg, tmp2_reg); + __ add(str1_reg, limit_reg, str1_reg); + __ add(str2_reg, limit_reg, str2_reg); __ neg(limit_reg); //negate count - __ lduh(tmp1_reg, limit_reg, chr1_reg); + __ lduh(str1_reg, limit_reg, chr1_reg); + // Lchar_loop __ bind(Lchar_loop); - __ lduh(tmp2_reg, limit_reg, chr2_reg); + __ lduh(str2_reg, limit_reg, chr2_reg); __ cmp(chr1_reg, chr2_reg); __ br(Assembler::notEqual, true, Assembler::pt, Ldone); __ delayed()->mov(G0, result_reg); //not equal __ inccc(limit_reg, sizeof(jchar)); // annul LDUH if branch is not taken to prevent access past end of string - __ br(Assembler::notZero, true, Assembler::pt, Lchar_loop); //annul on taken - __ delayed()->lduh(tmp1_reg, limit_reg, chr1_reg); // hoisted + __ br(Assembler::notZero, true, Assembler::pt, Lchar_loop); + __ delayed()->lduh(str1_reg, limit_reg, chr1_reg); // hoisted __ add(G0, 1, result_reg); //equal __ bind(Ldone); %} -enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result) %{ +enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, notemp_iRegI result) %{ Label Lvector, Ldone, Lloop; MacroAssembler _masm(&cbuf); Register ary1_reg = reg_to_register_object($ary1$$reg); Register ary2_reg = reg_to_register_object($ary2$$reg); Register tmp1_reg = reg_to_register_object($tmp1$$reg); - Register tmp2_reg = reg_to_register_object($tmp2$$reg); + Register tmp2_reg = O7; Register result_reg = reg_to_register_object($result$$reg); int length_offset = arrayOopDesc::length_offset_in_bytes(); @@ -3101,7 +3034,7 @@ __ br(Assembler::notEqual, true, Assembler::pn, Ldone); __ delayed()->mov(G0, result_reg); // not equal - __ br_zero(Assembler::zero, true, Assembler::pn, tmp1_reg, Ldone); + __ br_on_reg_cond(Assembler::rc_z, true, Assembler::pn, tmp1_reg, Ldone); __ delayed()->add(G0, 1, result_reg); // zero-length arrays are equal // load array addresses @@ -3109,45 +3042,16 @@ __ add(ary2_reg, base_offset, ary2_reg); // renaming registers - Register chr1_reg = tmp2_reg; // for characters in ary1 - Register chr2_reg = result_reg; // for characters in ary2 + Register chr1_reg = result_reg; // for characters in ary1 + Register chr2_reg = tmp2_reg; // for characters in ary2 Register limit_reg = tmp1_reg; // length // set byte count __ sll(limit_reg, exact_log2(sizeof(jchar)), limit_reg); - __ andcc(limit_reg, 0x2, chr1_reg); //trailing character ? - __ br(Assembler::zero, false, Assembler::pt, Lvector); - __ delayed()->nop(); - - //compare the trailing char - __ sub(limit_reg, sizeof(jchar), limit_reg); - __ lduh(ary1_reg, limit_reg, chr1_reg); - __ lduh(ary2_reg, limit_reg, chr2_reg); - __ cmp(chr1_reg, chr2_reg); - __ br(Assembler::notEqual, true, Assembler::pt, Ldone); - __ delayed()->mov(G0, result_reg); // not equal - - // only one char ? - __ br_zero(Assembler::zero, true, Assembler::pn, limit_reg, Ldone); - __ delayed()->add(G0, 1, result_reg); // zero-length arrays are equal - - __ bind(Lvector); - // Shift ary1_reg and ary2_reg to the end of the arrays, negate limit - __ add(ary1_reg, limit_reg, ary1_reg); - __ add(ary2_reg, limit_reg, ary2_reg); - __ neg(limit_reg, limit_reg); - - __ lduw(ary1_reg, limit_reg, chr1_reg); - __ bind(Lloop); - __ lduw(ary2_reg, limit_reg, chr2_reg); - __ cmp(chr1_reg, chr2_reg); - __ br(Assembler::notEqual, false, Assembler::pt, Ldone); - __ delayed()->mov(G0, result_reg); // not equal - __ inccc(limit_reg, 2*sizeof(jchar)); - // annul LDUW if branch is not taken to prevent access past end of string - __ br(Assembler::notZero, true, Assembler::pt, Lloop); //annul on taken - __ delayed()->lduw(ary1_reg, limit_reg, chr1_reg); // hoisted - + + // Compare char[] arrays aligned to 4 bytes. + __ char_arrays_equals(ary1_reg, ary2_reg, limit_reg, result_reg, + chr1_reg, chr2_reg, Ldone); __ add(G0, 1, result_reg); // equals __ bind(Ldone); @@ -9471,33 +9375,33 @@ ins_pipe(long_memory_op); %} -instruct string_compare(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result, - o7RegI tmp3, flagsReg ccr) %{ - match(Set result (StrComp str1 str2)); - effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL ccr, KILL tmp3); +instruct string_compare(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result, + o7RegI tmp, flagsReg ccr) %{ + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, KILL tmp); ins_cost(300); - format %{ "String Compare $str1,$str2 -> $result" %} - ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, result) ); + format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp" %} + ins_encode( enc_String_Compare(str1, str2, cnt1, cnt2, result) ); ins_pipe(long_memory_op); %} -instruct string_equals(o0RegP str1, o1RegP str2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result, - o7RegI tmp3, flagsReg ccr) %{ - match(Set result (StrEquals str1 str2)); - effect(USE_KILL str1, USE_KILL str2, KILL tmp1, KILL tmp2, KILL ccr, KILL tmp3); +instruct string_equals(o0RegP str1, o1RegP str2, g3RegI cnt, notemp_iRegI result, + o7RegI tmp, flagsReg ccr) %{ + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp, KILL ccr); ins_cost(300); - format %{ "String Equals $str1,$str2 -> $result" %} - ins_encode( enc_String_Equals(str1, str2, tmp1, tmp2, result) ); + format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp" %} + ins_encode( enc_String_Equals(str1, str2, cnt, result) ); ins_pipe(long_memory_op); %} -instruct array_equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, g4RegP tmp2, notemp_iRegI result, - flagsReg ccr) %{ +instruct array_equals(o0RegP ary1, o1RegP ary2, g3RegI tmp1, notemp_iRegI result, + o7RegI tmp2, flagsReg ccr) %{ match(Set result (AryEq ary1 ary2)); effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL ccr); ins_cost(300); - format %{ "Array Equals $ary1,$ary2 -> $result" %} - ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, result)); + format %{ "Array Equals $ary1,$ary2 -> $result // KILL $tmp1,$tmp2" %} + ins_encode( enc_Array_Equals(ary1, ary2, tmp1, result)); ins_pipe(long_memory_op); %} diff -r 054afbef9081 -r a2ad635573fb src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/cpu/x86/vm/assembler_x86.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -8404,6 +8404,319 @@ } #endif // _LP64 +// IndexOf substring. +void MacroAssembler::string_indexof(Register str1, Register str2, + Register cnt1, Register cnt2, Register result, + XMMRegister vec, Register tmp) { + assert(UseSSE42Intrinsics, "SSE4.2 is required"); + + Label RELOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR, + SCAN_SUBSTR, RET_NOT_FOUND, CLEANUP; + + push(str1); // string addr + push(str2); // substr addr + push(cnt2); // substr count + jmpb(PREP_FOR_SCAN); + + // Substr count saved at sp + // Substr saved at sp+1*wordSize + // String saved at sp+2*wordSize + + // Reload substr for rescan + bind(RELOAD_SUBSTR); + movl(cnt2, Address(rsp, 0)); + movptr(str2, Address(rsp, wordSize)); + // We came here after the beginninig of the substring was + // matched but the rest of it was not so we need to search + // again. Start from the next element after the previous match. + subptr(str1, result); // Restore counter + shrl(str1, 1); + addl(cnt1, str1); + lea(str1, Address(result, 2)); // Reload string + + // Load substr + bind(PREP_FOR_SCAN); + movdqu(vec, Address(str2, 0)); + addl(cnt1, 8); // prime the loop + subptr(str1, 16); + + // Scan string for substr in 16-byte vectors + bind(SCAN_TO_SUBSTR); + subl(cnt1, 8); + addptr(str1, 16); + + // pcmpestri + // inputs: + // xmm - substring + // rax - substring length (elements count) + // mem - scaned string + // rdx - string length (elements count) + // 0xd - mode: 1100 (substring search) + 01 (unsigned shorts) + // outputs: + // rcx - matched index in string + assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri"); + + pcmpestri(vec, Address(str1, 0), 0x0d); + jcc(Assembler::above, SCAN_TO_SUBSTR); // CF == 0 && ZF == 0 + jccb(Assembler::aboveEqual, RET_NOT_FOUND); // CF == 0 + + // Fallthrough: found a potential substr + + // Make sure string is still long enough + subl(cnt1, tmp); + cmpl(cnt1, cnt2); + jccb(Assembler::negative, RET_NOT_FOUND); + // Compute start addr of substr + lea(str1, Address(str1, tmp, Address::times_2)); + movptr(result, str1); // save + + // Compare potential substr + addl(cnt1, 8); // prime the loop + addl(cnt2, 8); + subptr(str1, 16); + subptr(str2, 16); + + // Scan 16-byte vectors of string and substr + bind(SCAN_SUBSTR); + subl(cnt1, 8); + subl(cnt2, 8); + addptr(str1, 16); + addptr(str2, 16); + movdqu(vec, Address(str2, 0)); + pcmpestri(vec, Address(str1, 0), 0x0d); + jcc(Assembler::noOverflow, RELOAD_SUBSTR); // OF == 0 + jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0 + + // Compute substr offset + subptr(result, Address(rsp, 2*wordSize)); + shrl(result, 1); // index + jmpb(CLEANUP); + + bind(RET_NOT_FOUND); + movl(result, -1); + + bind(CLEANUP); + addptr(rsp, 3*wordSize); +} + +// Compare strings. +void MacroAssembler::string_compare(Register str1, Register str2, + Register cnt1, Register cnt2, Register result, + XMMRegister vec1, XMMRegister vec2) { + Label LENGTH_DIFF_LABEL, POP_LABEL, DONE_LABEL, WHILE_HEAD_LABEL; + + // Compute the minimum of the string lengths and the + // difference of the string lengths (stack). + // Do the conditional move stuff + movl(result, cnt1); + subl(cnt1, cnt2); + push(cnt1); + if (VM_Version::supports_cmov()) { + cmovl(Assembler::lessEqual, cnt2, result); + } else { + Label GT_LABEL; + jccb(Assembler::greater, GT_LABEL); + movl(cnt2, result); + bind(GT_LABEL); + } + + // Is the minimum length zero? + testl(cnt2, cnt2); + jcc(Assembler::zero, LENGTH_DIFF_LABEL); + + // Load first characters + load_unsigned_short(result, Address(str1, 0)); + load_unsigned_short(cnt1, Address(str2, 0)); + + // Compare first characters + subl(result, cnt1); + jcc(Assembler::notZero, POP_LABEL); + decrementl(cnt2); + jcc(Assembler::zero, LENGTH_DIFF_LABEL); + + { + // Check after comparing first character to see if strings are equivalent + Label LSkip2; + // Check if the strings start at same location + cmpptr(str1, str2); + jccb(Assembler::notEqual, LSkip2); + + // Check if the length difference is zero (from stack) + cmpl(Address(rsp, 0), 0x0); + jcc(Assembler::equal, LENGTH_DIFF_LABEL); + + // Strings might not be equivalent + bind(LSkip2); + } + + // Advance to next character + addptr(str1, 2); + addptr(str2, 2); + + if (UseSSE42Intrinsics) { + // With SSE4.2, use double quad vector compare + Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL; + // Setup to compare 16-byte vectors + movl(cnt1, cnt2); + andl(cnt2, 0xfffffff8); // cnt2 holds the vector count + andl(cnt1, 0x00000007); // cnt1 holds the tail count + testl(cnt2, cnt2); + jccb(Assembler::zero, COMPARE_TAIL); + + lea(str2, Address(str2, cnt2, Address::times_2)); + lea(str1, Address(str1, cnt2, Address::times_2)); + negptr(cnt2); + + bind(COMPARE_VECTORS); + movdqu(vec1, Address(str1, cnt2, Address::times_2)); + movdqu(vec2, Address(str2, cnt2, Address::times_2)); + pxor(vec1, vec2); + ptest(vec1, vec1); + jccb(Assembler::notZero, VECTOR_NOT_EQUAL); + addptr(cnt2, 8); + jcc(Assembler::notZero, COMPARE_VECTORS); + jmpb(COMPARE_TAIL); + + // Mismatched characters in the vectors + bind(VECTOR_NOT_EQUAL); + lea(str1, Address(str1, cnt2, Address::times_2)); + lea(str2, Address(str2, cnt2, Address::times_2)); + movl(cnt1, 8); + + // Compare tail (< 8 chars), or rescan last vectors to + // find 1st mismatched characters + bind(COMPARE_TAIL); + testl(cnt1, cnt1); + jccb(Assembler::zero, LENGTH_DIFF_LABEL); + movl(cnt2, cnt1); + // Fallthru to tail compare + } + + // Shift str2 and str1 to the end of the arrays, negate min + lea(str1, Address(str1, cnt2, Address::times_2, 0)); + lea(str2, Address(str2, cnt2, Address::times_2, 0)); + negptr(cnt2); + + // Compare the rest of the characters + bind(WHILE_HEAD_LABEL); + load_unsigned_short(result, Address(str1, cnt2, Address::times_2, 0)); + load_unsigned_short(cnt1, Address(str2, cnt2, Address::times_2, 0)); + subl(result, cnt1); + jccb(Assembler::notZero, POP_LABEL); + increment(cnt2); + jcc(Assembler::notZero, WHILE_HEAD_LABEL); + + // Strings are equal up to min length. Return the length difference. + bind(LENGTH_DIFF_LABEL); + pop(result); + jmpb(DONE_LABEL); + + // Discard the stored length difference + bind(POP_LABEL); + addptr(rsp, wordSize); + + // That's it + bind(DONE_LABEL); +} + +// Compare char[] arrays aligned to 4 bytes or substrings. +void MacroAssembler::char_arrays_equals(bool is_array_equ, Register ary1, Register ary2, + Register limit, Register result, Register chr, + XMMRegister vec1, XMMRegister vec2) { + Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR; + + int length_offset = arrayOopDesc::length_offset_in_bytes(); + int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); + + // Check the input args + cmpptr(ary1, ary2); + jcc(Assembler::equal, TRUE_LABEL); + + if (is_array_equ) { + // Need additional checks for arrays_equals. + andptr(ary1, ary2); + jcc(Assembler::zero, FALSE_LABEL); // One pointer is NULL + + // Check the lengths + movl(limit, Address(ary1, length_offset)); + cmpl(limit, Address(ary2, length_offset)); + jcc(Assembler::notEqual, FALSE_LABEL); + } + + // count == 0 + testl(limit, limit); + jcc(Assembler::zero, TRUE_LABEL); + + if (is_array_equ) { + // Load array address + lea(ary1, Address(ary1, base_offset)); + lea(ary2, Address(ary2, base_offset)); + } + + shll(limit, 1); // byte count != 0 + movl(result, limit); // copy + + if (UseSSE42Intrinsics) { + // With SSE4.2, use double quad vector compare + Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; + // Compare 16-byte vectors + andl(result, 0x0000000e); // tail count (in bytes) + andl(limit, 0xfffffff0); // vector count (in bytes) + jccb(Assembler::zero, COMPARE_TAIL); + + lea(ary1, Address(ary1, limit, Address::times_1)); + lea(ary2, Address(ary2, limit, Address::times_1)); + negptr(limit); + + bind(COMPARE_WIDE_VECTORS); + movdqu(vec1, Address(ary1, limit, Address::times_1)); + movdqu(vec2, Address(ary2, limit, Address::times_1)); + pxor(vec1, vec2); + ptest(vec1, vec1); + jccb(Assembler::notZero, FALSE_LABEL); + addptr(limit, 16); + jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); + + bind(COMPARE_TAIL); // limit is zero + movl(limit, result); + // Fallthru to tail compare + } + + // Compare 4-byte vectors + andl(limit, 0xfffffffc); // vector count (in bytes) + jccb(Assembler::zero, COMPARE_CHAR); + + lea(ary1, Address(ary1, limit, Address::times_1)); + lea(ary2, Address(ary2, limit, Address::times_1)); + negptr(limit); + + bind(COMPARE_VECTORS); + movl(chr, Address(ary1, limit, Address::times_1)); + cmpl(chr, Address(ary2, limit, Address::times_1)); + jccb(Assembler::notEqual, FALSE_LABEL); + addptr(limit, 4); + jcc(Assembler::notZero, COMPARE_VECTORS); + + // Compare trailing char (final 2 bytes), if any + bind(COMPARE_CHAR); + testl(result, 0x2); // tail char + jccb(Assembler::zero, TRUE_LABEL); + load_unsigned_short(chr, Address(ary1, 0)); + load_unsigned_short(limit, Address(ary2, 0)); + cmpl(chr, limit); + jccb(Assembler::notEqual, FALSE_LABEL); + + bind(TRUE_LABEL); + movl(result, 1); // return true + jmpb(DONE); + + bind(FALSE_LABEL); + xorl(result, result); // return false + + // That's it + bind(DONE); +} + Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) { switch (cond) { // Note some conditions are synonyms for others diff -r 054afbef9081 -r a2ad635573fb src/cpu/x86/vm/assembler_x86.hpp --- a/src/cpu/x86/vm/assembler_x86.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/cpu/x86/vm/assembler_x86.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -2206,6 +2206,20 @@ void movl2ptr(Register dst, Address src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(movl(dst, src)); } void movl2ptr(Register dst, Register src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(if (dst != src) movl(dst, src)); } + // IndexOf strings. + void string_indexof(Register str1, Register str2, + Register cnt1, Register cnt2, Register result, + XMMRegister vec, Register tmp); + + // Compare strings. + void string_compare(Register str1, Register str2, + Register cnt1, Register cnt2, Register result, + XMMRegister vec1, XMMRegister vec2); + + // Compare char[] arrays. + void char_arrays_equals(bool is_array_equ, Register ary1, Register ary2, + Register limit, Register result, Register chr, + XMMRegister vec1, XMMRegister vec2); #undef VIRTUAL diff -r 054afbef9081 -r a2ad635573fb src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1638,7 +1638,7 @@ jobject2reg_with_patching(k_RInfo, op->info_for_patch()); } else { #ifdef _LP64 - __ movoop(k_RInfo, k->encoding()); + __ movoop(k_RInfo, k->constant_encoding()); #else k_RInfo = noreg; #endif // _LP64 @@ -1661,7 +1661,7 @@ assert(data != NULL, "need data for checkcast"); assert(data->is_BitData(), "need BitData for checkcast"); Register mdo = klass_RInfo; - __ movoop(mdo, md->encoding()); + __ movoop(mdo, md->constant_encoding()); Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::header_offset())); int header_bits = DataLayout::flag_mask_to_header_mask(BitData::null_seen_byte_constant()); __ orl(data_addr, header_bits); @@ -1679,7 +1679,7 @@ #ifdef _LP64 __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); #else - __ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->encoding()); + __ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->constant_encoding()); #endif // _LP64 } else { __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); @@ -1696,7 +1696,7 @@ #ifdef _LP64 __ cmpptr(k_RInfo, Address(klass_RInfo, k->super_check_offset())); #else - __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->encoding()); + __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->constant_encoding()); #endif // _LP64 if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() != k->super_check_offset()) { __ jcc(Assembler::notEqual, *stub->entry()); @@ -1707,7 +1707,7 @@ #ifdef _LP64 __ cmpptr(klass_RInfo, k_RInfo); #else - __ cmpoop(klass_RInfo, k->encoding()); + __ cmpoop(klass_RInfo, k->constant_encoding()); #endif // _LP64 __ jcc(Assembler::equal, done); @@ -1715,7 +1715,7 @@ #ifdef _LP64 __ push(k_RInfo); #else - __ pushoop(k->encoding()); + __ pushoop(k->constant_encoding()); #endif // _LP64 __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); __ pop(klass_RInfo); @@ -1763,7 +1763,7 @@ if (!k->is_loaded()) { jobject2reg_with_patching(k_RInfo, op->info_for_patch()); } else { - LP64_ONLY(__ movoop(k_RInfo, k->encoding())); + LP64_ONLY(__ movoop(k_RInfo, k->constant_encoding())); } assert(obj != k_RInfo, "must be different"); @@ -1774,7 +1774,7 @@ // get object class // not a safepoint as obj null check happens earlier if (LP64_ONLY(false &&) k->is_loaded()) { - NOT_LP64(__ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->encoding())); + NOT_LP64(__ cmpoop(Address(obj, oopDesc::klass_offset_in_bytes()), k->constant_encoding())); k_RInfo = noreg; } else { __ cmpptr(k_RInfo, Address(obj, oopDesc::klass_offset_in_bytes())); @@ -1791,14 +1791,14 @@ #ifndef _LP64 if (k->is_loaded()) { // See if we get an immediate positive hit - __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->encoding()); + __ cmpoop(Address(klass_RInfo, k->super_check_offset()), k->constant_encoding()); __ jcc(Assembler::equal, one); if (sizeof(oopDesc) + Klass::secondary_super_cache_offset_in_bytes() == k->super_check_offset()) { // check for self - __ cmpoop(klass_RInfo, k->encoding()); + __ cmpoop(klass_RInfo, k->constant_encoding()); __ jcc(Assembler::equal, one); __ push(klass_RInfo); - __ pushoop(k->encoding()); + __ pushoop(k->constant_encoding()); __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); __ pop(klass_RInfo); __ pop(dst); @@ -3112,7 +3112,7 @@ // subtype which we can't check or src is the same array as dst // but not necessarily exactly of type default_type. Label known_ok, halt; - __ movoop(tmp, default_type->encoding()); + __ movoop(tmp, default_type->constant_encoding()); if (basic_type != T_OBJECT) { __ cmpptr(tmp, dst_klass_addr); __ jcc(Assembler::notEqual, halt); @@ -3200,7 +3200,7 @@ assert(data->is_CounterData(), "need CounterData for calls"); assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); Register mdo = op->mdo()->as_register(); - __ movoop(mdo, md->encoding()); + __ movoop(mdo, md->constant_encoding()); Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); __ addl(counter_addr, DataLayout::counter_increment); Bytecodes::Code bc = method->java_code_at_bci(bci); @@ -3240,7 +3240,7 @@ ciKlass* receiver = vc_data->receiver(i); if (receiver == NULL) { Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i))); - __ movoop(recv_addr, known_klass->encoding()); + __ movoop(recv_addr, known_klass->constant_encoding()); Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))); __ addl(data_addr, DataLayout::counter_increment); return; diff -r 054afbef9081 -r a2ad635573fb src/cpu/x86/vm/c1_LIRGenerator_x86.cpp --- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. 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 @@ -994,7 +994,7 @@ LIR_Opr len = length.result(); BasicType elem_type = x->elt_type(); - __ oop2reg(ciTypeArrayKlass::make(elem_type)->encoding(), klass_reg); + __ oop2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg); CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info); __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path); diff -r 054afbef9081 -r a2ad635573fb src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Mon Sep 28 12:27:52 2009 -0400 +++ b/src/cpu/x86/vm/x86_32.ad Wed Oct 14 12:40:20 2009 -0700 @@ -379,7 +379,7 @@ int format) { #ifdef ASSERT if (rspec.reloc()->type() == relocInfo::oop_type && d32 != 0 && d32 != (int)Universe::non_oop_word()) { - assert(oop(d32)->is_oop() && oop(d32)->is_perm(), "cannot embed non-perm oops in code"); + assert(oop(d32)->is_oop() && (ScavengeRootsInCode || !oop(d32)->is_scavengable()), "cannot embed scavengable oops in code"); } #endif cbuf.relocate(cbuf.inst_mark(), rspec, format); @@ -3701,458 +3701,6 @@ } %} - enc_class enc_String_Compare(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2, - eAXRegI tmp3, eBXRegI tmp4, eCXRegI result) %{ - Label ECX_GOOD_LABEL, LENGTH_DIFF_LABEL, - POP_LABEL, DONE_LABEL, CONT_LABEL, - WHILE_HEAD_LABEL; - MacroAssembler masm(&cbuf); - - XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); - XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); - - // Get the first character position in both strings - // [8] char array, [12] offset, [16] count - int value_offset = java_lang_String::value_offset_in_bytes(); - int offset_offset = java_lang_String::offset_offset_in_bytes(); - int count_offset = java_lang_String::count_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - masm.movptr(rax, Address(rsi, value_offset)); - masm.movl(rcx, Address(rsi, offset_offset)); - masm.lea(rax, Address(rax, rcx, Address::times_2, base_offset)); - masm.movptr(rbx, Address(rdi, value_offset)); - masm.movl(rcx, Address(rdi, offset_offset)); - masm.lea(rbx, Address(rbx, rcx, Address::times_2, base_offset)); - - // Compute the minimum of the string lengths(rsi) and the - // difference of the string lengths (stack) - - if (VM_Version::supports_cmov()) { - masm.movl(rdi, Address(rdi, count_offset)); - masm.movl(rsi, Address(rsi, count_offset)); - masm.movl(rcx, rdi); - masm.subl(rdi, rsi); - masm.push(rdi); - masm.cmovl(Assembler::lessEqual, rsi, rcx); - } else { - masm.movl(rdi, Address(rdi, count_offset)); - masm.movl(rcx, Address(rsi, count_offset)); - masm.movl(rsi, rdi); - masm.subl(rdi, rcx); - masm.push(rdi); - masm.jccb(Assembler::lessEqual, ECX_GOOD_LABEL); - masm.movl(rsi, rcx); - // rsi holds min, rcx is unused - } - - // Is the minimum length zero? - masm.bind(ECX_GOOD_LABEL); - masm.testl(rsi, rsi); - masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL); - - // Load first characters - masm.load_unsigned_short(rcx, Address(rbx, 0)); - masm.load_unsigned_short(rdi, Address(rax, 0)); - - // Compare first characters - masm.subl(rcx, rdi); - masm.jcc(Assembler::notZero, POP_LABEL); - masm.decrementl(rsi); - masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL); - - { - // Check after comparing first character to see if strings are equivalent - Label LSkip2; - // Check if the strings start at same location - masm.cmpptr(rbx,rax); - masm.jccb(Assembler::notEqual, LSkip2); - - // Check if the length difference is zero (from stack) - masm.cmpl(Address(rsp, 0), 0x0); - masm.jcc(Assembler::equal, LENGTH_DIFF_LABEL); - - // Strings might not be equivalent - masm.bind(LSkip2); - } - - // Advance to next character - masm.addptr(rax, 2); - masm.addptr(rbx, 2); - - if (UseSSE42Intrinsics) { - // With SSE4.2, use double quad vector compare - Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL; - // Setup to compare 16-byte vectors - masm.movl(rdi, rsi); - masm.andl(rsi, 0xfffffff8); // rsi holds the vector count - masm.andl(rdi, 0x00000007); // rdi holds the tail count - masm.testl(rsi, rsi); - masm.jccb(Assembler::zero, COMPARE_TAIL); - - masm.lea(rax, Address(rax, rsi, Address::times_2)); - masm.lea(rbx, Address(rbx, rsi, Address::times_2)); - masm.negl(rsi); - - masm.bind(COMPARE_VECTORS); - masm.movdqu(tmp1Reg, Address(rax, rsi, Address::times_2)); - masm.movdqu(tmp2Reg, Address(rbx, rsi, Address::times_2)); - masm.pxor(tmp1Reg, tmp2Reg); - masm.ptest(tmp1Reg, tmp1Reg); - masm.jccb(Assembler::notZero, VECTOR_NOT_EQUAL); - masm.addl(rsi, 8); - masm.jcc(Assembler::notZero, COMPARE_VECTORS); - masm.jmpb(COMPARE_TAIL); - - // Mismatched characters in the vectors - masm.bind(VECTOR_NOT_EQUAL); - masm.lea(rax, Address(rax, rsi, Address::times_2)); - masm.lea(rbx, Address(rbx, rsi, Address::times_2)); - masm.movl(rdi, 8); - - // Compare tail (< 8 chars), or rescan last vectors to - // find 1st mismatched characters - masm.bind(COMPARE_TAIL); - masm.testl(rdi, rdi); - masm.jccb(Assembler::zero, LENGTH_DIFF_LABEL); - masm.movl(rsi, rdi); - // Fallthru to tail compare - } - - //Shift rax, and rbx, to the end of the arrays, negate min - masm.lea(rax, Address(rax, rsi, Address::times_2, 0)); - masm.lea(rbx, Address(rbx, rsi, Address::times_2, 0)); - masm.negl(rsi); - - // Compare the rest of the characters - masm.bind(WHILE_HEAD_LABEL); - masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0)); - masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0)); - masm.subl(rcx, rdi); - masm.jccb(Assembler::notZero, POP_LABEL); - masm.incrementl(rsi); - masm.jcc(Assembler::notZero, WHILE_HEAD_LABEL); - - // Strings are equal up to min length. Return the length difference. - masm.bind(LENGTH_DIFF_LABEL); - masm.pop(rcx); - masm.jmpb(DONE_LABEL); - - // Discard the stored length difference - masm.bind(POP_LABEL); - masm.addptr(rsp, 4); - - // That's it - masm.bind(DONE_LABEL); - %} - - enc_class enc_String_Equals(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2, - eBXRegI tmp3, eCXRegI tmp4, eAXRegI result) %{ - Label RET_TRUE, RET_FALSE, DONE, COMPARE_VECTORS, COMPARE_CHAR; - MacroAssembler masm(&cbuf); - - XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); - XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); - - int value_offset = java_lang_String::value_offset_in_bytes(); - int offset_offset = java_lang_String::offset_offset_in_bytes(); - int count_offset = java_lang_String::count_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - // does source == target string? - masm.cmpptr(rdi, rsi); - masm.jcc(Assembler::equal, RET_TRUE); - - // get and compare counts - masm.movl(rcx, Address(rdi, count_offset)); - masm.movl(rax, Address(rsi, count_offset)); - masm.cmpl(rcx, rax); - masm.jcc(Assembler::notEqual, RET_FALSE); - masm.testl(rax, rax); - masm.jcc(Assembler::zero, RET_TRUE); - - // get source string offset and value - masm.movptr(rbx, Address(rsi, value_offset)); - masm.movl(rax, Address(rsi, offset_offset)); - masm.leal(rsi, Address(rbx, rax, Address::times_2, base_offset)); - - // get compare string offset and value - masm.movptr(rbx, Address(rdi, value_offset)); - masm.movl(rax, Address(rdi, offset_offset)); - masm.leal(rdi, Address(rbx, rax, Address::times_2, base_offset)); - - // Set byte count - masm.shll(rcx, 1); - masm.movl(rax, rcx); - - if (UseSSE42Intrinsics) { - // With SSE4.2, use double quad vector compare - Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; - // Compare 16-byte vectors - masm.andl(rcx, 0xfffffff0); // vector count (in bytes) - masm.andl(rax, 0x0000000e); // tail count (in bytes) - masm.testl(rcx, rcx); - masm.jccb(Assembler::zero, COMPARE_TAIL); - masm.lea(rdi, Address(rdi, rcx, Address::times_1)); - masm.lea(rsi, Address(rsi, rcx, Address::times_1)); - masm.negl(rcx); - - masm.bind(COMPARE_WIDE_VECTORS); - masm.movdqu(tmp1Reg, Address(rdi, rcx, Address::times_1)); - masm.movdqu(tmp2Reg, Address(rsi, rcx, Address::times_1)); - masm.pxor(tmp1Reg, tmp2Reg); - masm.ptest(tmp1Reg, tmp1Reg); - masm.jccb(Assembler::notZero, RET_FALSE); - masm.addl(rcx, 16); - masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); - masm.bind(COMPARE_TAIL); - masm.movl(rcx, rax); - // Fallthru to tail compare - } - - // Compare 4-byte vectors - masm.andl(rcx, 0xfffffffc); // vector count (in bytes) - masm.andl(rax, 0x00000002); // tail char (in bytes) - masm.testl(rcx, rcx); - masm.jccb(Assembler::zero, COMPARE_CHAR); - masm.lea(rdi, Address(rdi, rcx, Address::times_1)); - masm.lea(rsi, Address(rsi, rcx, Address::times_1)); - masm.negl(rcx); - - masm.bind(COMPARE_VECTORS); - masm.movl(rbx, Address(rdi, rcx, Address::times_1)); - masm.cmpl(rbx, Address(rsi, rcx, Address::times_1)); - masm.jccb(Assembler::notEqual, RET_FALSE); - masm.addl(rcx, 4); - masm.jcc(Assembler::notZero, COMPARE_VECTORS); - - // Compare trailing char (final 2 bytes), if any - masm.bind(COMPARE_CHAR); - masm.testl(rax, rax); - masm.jccb(Assembler::zero, RET_TRUE); - masm.load_unsigned_short(rbx, Address(rdi, 0)); - masm.load_unsigned_short(rcx, Address(rsi, 0)); - masm.cmpl(rbx, rcx); - masm.jccb(Assembler::notEqual, RET_FALSE); - - masm.bind(RET_TRUE); - masm.movl(rax, 1); // return true - masm.jmpb(DONE); - - masm.bind(RET_FALSE); - masm.xorl(rax, rax); // return false - - masm.bind(DONE); - %} - - enc_class enc_String_IndexOf(eSIRegP str1, eDIRegP str2, regXD tmp1, eAXRegI tmp2, - eCXRegI tmp3, eDXRegI tmp4, eBXRegI result) %{ - // SSE4.2 version - Label LOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR, - SCAN_SUBSTR, RET_NEG_ONE, RET_NOT_FOUND, CLEANUP, DONE; - MacroAssembler masm(&cbuf); - - XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); - - // Get the first character position in both strings - // [8] char array, [12] offset, [16] count - int value_offset = java_lang_String::value_offset_in_bytes(); - int offset_offset = java_lang_String::offset_offset_in_bytes(); - int count_offset = java_lang_String::count_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - // Get counts for string and substr - masm.movl(rdx, Address(rsi, count_offset)); - masm.movl(rax, Address(rdi, count_offset)); - // Check for substr count > string count - masm.cmpl(rax, rdx); - masm.jcc(Assembler::greater, RET_NEG_ONE); - - // Start the indexOf operation - // Get start addr of string - masm.movptr(rbx, Address(rsi, value_offset)); - masm.movl(rcx, Address(rsi, offset_offset)); - masm.lea(rsi, Address(rbx, rcx, Address::times_2, base_offset)); - masm.push(rsi); - - // Get start addr of substr - masm.movptr(rbx, Address(rdi, value_offset)); - masm.movl(rcx, Address(rdi, offset_offset)); - masm.lea(rdi, Address(rbx, rcx, Address::times_2, base_offset)); - masm.push(rdi); - masm.push(rax); - masm.jmpb(PREP_FOR_SCAN); - - // Substr count saved at sp - // Substr saved at sp+4 - // String saved at sp+8 - - // Prep to load substr for scan - masm.bind(LOAD_SUBSTR); - masm.movptr(rdi, Address(rsp, 4)); - masm.movl(rax, Address(rsp, 0)); - - // Load substr - masm.bind(PREP_FOR_SCAN); - masm.movdqu(tmp1Reg, Address(rdi, 0)); - masm.addl(rdx, 8); // prime the loop - masm.subptr(rsi, 16); - - // Scan string for substr in 16-byte vectors - masm.bind(SCAN_TO_SUBSTR); - masm.subl(rdx, 8); - masm.addptr(rsi, 16); - masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d); - masm.jcc(Assembler::above, SCAN_TO_SUBSTR); // CF == 0 && ZF == 0 - masm.jccb(Assembler::aboveEqual, RET_NOT_FOUND); // CF == 0 - - // Fallthru: found a potential substr - - // Make sure string is still long enough - masm.subl(rdx, rcx); - masm.cmpl(rdx, rax); - masm.jccb(Assembler::negative, RET_NOT_FOUND); - // Compute start addr of substr - masm.lea(rsi, Address(rsi, rcx, Address::times_2)); - masm.movptr(rbx, rsi); - - // Compare potential substr - masm.addl(rdx, 8); // prime the loop - masm.addl(rax, 8); - masm.subptr(rsi, 16); - masm.subptr(rdi, 16); - - // Scan 16-byte vectors of string and substr - masm.bind(SCAN_SUBSTR); - masm.subl(rax, 8); - masm.subl(rdx, 8); - masm.addptr(rsi, 16); - masm.addptr(rdi, 16); - masm.movdqu(tmp1Reg, Address(rdi, 0)); - masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d); - masm.jcc(Assembler::noOverflow, LOAD_SUBSTR); // OF == 0 - masm.jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0 - - // Compute substr offset - masm.movptr(rsi, Address(rsp, 8)); - masm.subptr(rbx, rsi); - masm.shrl(rbx, 1); - masm.jmpb(CLEANUP); - - masm.bind(RET_NEG_ONE); - masm.movl(rbx, -1); - masm.jmpb(DONE); - - masm.bind(RET_NOT_FOUND); - masm.movl(rbx, -1); - - masm.bind(CLEANUP); - masm.addptr(rsp, 12); - - masm.bind(DONE); - %} - - enc_class enc_Array_Equals(eDIRegP ary1, eSIRegP ary2, regXD tmp1, regXD tmp2, - eBXRegI tmp3, eDXRegI tmp4, eAXRegI result) %{ - Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR; - MacroAssembler masm(&cbuf); - - XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); - XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); - Register ary1Reg = as_Register($ary1$$reg); - Register ary2Reg = as_Register($ary2$$reg); - Register tmp3Reg = as_Register($tmp3$$reg); - Register tmp4Reg = as_Register($tmp4$$reg); - Register resultReg = as_Register($result$$reg); - - int length_offset = arrayOopDesc::length_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - // Check the input args - masm.cmpptr(ary1Reg, ary2Reg); - masm.jcc(Assembler::equal, TRUE_LABEL); - masm.testptr(ary1Reg, ary1Reg); - masm.jcc(Assembler::zero, FALSE_LABEL); - masm.testptr(ary2Reg, ary2Reg); - masm.jcc(Assembler::zero, FALSE_LABEL); - - // Check the lengths - masm.movl(tmp4Reg, Address(ary1Reg, length_offset)); - masm.movl(resultReg, Address(ary2Reg, length_offset)); - masm.cmpl(tmp4Reg, resultReg); - masm.jcc(Assembler::notEqual, FALSE_LABEL); - masm.testl(resultReg, resultReg); - masm.jcc(Assembler::zero, TRUE_LABEL); - - // Load array addrs - masm.lea(ary1Reg, Address(ary1Reg, base_offset)); - masm.lea(ary2Reg, Address(ary2Reg, base_offset)); - - // Set byte count - masm.shll(tmp4Reg, 1); - masm.movl(resultReg, tmp4Reg); - - if (UseSSE42Intrinsics) { - // With SSE4.2, use double quad vector compare - Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; - // Compare 16-byte vectors - masm.andl(tmp4Reg, 0xfffffff0); // vector count (in bytes) - masm.andl(resultReg, 0x0000000e); // tail count (in bytes) - masm.testl(tmp4Reg, tmp4Reg); - masm.jccb(Assembler::zero, COMPARE_TAIL); - masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); - masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); - masm.negl(tmp4Reg); - - masm.bind(COMPARE_WIDE_VECTORS); - masm.movdqu(tmp1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); - masm.movdqu(tmp2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); - masm.pxor(tmp1Reg, tmp2Reg); - masm.ptest(tmp1Reg, tmp1Reg); - - masm.jccb(Assembler::notZero, FALSE_LABEL); - masm.addl(tmp4Reg, 16); - masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); - masm.bind(COMPARE_TAIL); - masm.movl(tmp4Reg, resultReg); - // Fallthru to tail compare - } - - // Compare 4-byte vectors - masm.andl(tmp4Reg, 0xfffffffc); // vector count (in bytes) - masm.andl(resultReg, 0x00000002); // tail char (in bytes) - masm.testl(tmp4Reg, tmp4Reg); - masm.jccb(Assembler::zero, COMPARE_CHAR); - masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); - masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); - masm.negl(tmp4Reg); - - masm.bind(COMPARE_VECTORS); - masm.movl(tmp3Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); - masm.cmpl(tmp3Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); - masm.jccb(Assembler::notEqual, FALSE_LABEL); - masm.addl(tmp4Reg, 4); - masm.jcc(Assembler::notZero, COMPARE_VECTORS); - - // Compare trailing char (final 2 bytes), if any - masm.bind(COMPARE_CHAR); - masm.testl(resultReg, resultReg); - masm.jccb(Assembler::zero, TRUE_LABEL); - masm.load_unsigned_short(tmp3Reg, Address(ary1Reg, 0)); - masm.load_unsigned_short(tmp4Reg, Address(ary2Reg, 0)); - masm.cmpl(tmp3Reg, tmp4Reg); - masm.jccb(Assembler::notEqual, FALSE_LABEL); - - masm.bind(TRUE_LABEL); - masm.movl(resultReg, 1); // return true - masm.jmpb(DONE); - - masm.bind(FALSE_LABEL); - masm.xorl(resultReg, resultReg); // return false - - // That's it - masm.bind(DONE); - %} enc_class enc_pop_rdx() %{ emit_opcode(cbuf,0x5A); @@ -12718,48 +12266,64 @@ ins_pipe( pipe_slow ); %} -instruct string_compare(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2, - eAXRegI tmp3, eBXRegI tmp4, eCXRegI result, eFlagsReg cr) %{ - match(Set result (StrComp str1 str2)); - effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr); - //ins_cost(300); - - format %{ "String Compare $str1,$str2 -> $result // KILL EAX, EBX" %} - ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, tmp3, tmp4, result) ); +instruct string_compare(eDIRegP str1, eCXRegI cnt1, eSIRegP str2, eBXRegI cnt2, + eAXRegI result, regXD tmp1, regXD tmp2, eFlagsReg cr) %{ + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1, $tmp2" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister); + %} ins_pipe( pipe_slow ); %} // fast string equals -instruct string_equals(eDIRegP str1, eSIRegP str2, regXD tmp1, regXD tmp2, - eBXRegI tmp3, eCXRegI tmp4, eAXRegI result, eFlagsReg cr) %{ - match(Set result (StrEquals str1 str2)); - effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr); - - format %{ "String Equals $str1,$str2 -> $result // KILL EBX, ECX" %} - ins_encode( enc_String_Equals(tmp1, tmp2, str1, str2, tmp3, tmp4, result) ); - ins_pipe( pipe_slow ); -%} - -instruct string_indexof(eSIRegP str1, eDIRegP str2, regXD tmp1, eAXRegI tmp2, - eCXRegI tmp3, eDXRegI tmp4, eBXRegI result, eFlagsReg cr) %{ +instruct string_equals(eDIRegP str1, eSIRegP str2, eCXRegI cnt, eAXRegI result, + regXD tmp1, regXD tmp2, eBXRegI tmp3, eFlagsReg cr) %{ + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp3, KILL cr); + + format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp1, $tmp2, $tmp3" %} + ins_encode %{ + __ char_arrays_equals(false, $str1$$Register, $str2$$Register, + $cnt$$Register, $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister); + %} + ins_pipe( pipe_slow ); +%} + +instruct string_indexof(eDIRegP str1, eDXRegI cnt1, eSIRegP str2, eAXRegI cnt2, + eBXRegI result, regXD tmp1, eCXRegI tmp2, eFlagsReg cr) %{ predicate(UseSSE42Intrinsics); - match(Set result (StrIndexOf str1 str2)); - effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, KILL tmp2, KILL tmp3, KILL tmp4, KILL cr); - - format %{ "String IndexOf $str1,$str2 -> $result // KILL EAX, ECX, EDX" %} - ins_encode( enc_String_IndexOf(str1, str2, tmp1, tmp2, tmp3, tmp4, result) ); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp2, KILL cr); + + format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp2, $tmp1" %} + ins_encode %{ + __ string_indexof($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$XMMRegister, $tmp2$$Register); + %} ins_pipe( pipe_slow ); %} // fast array equals -instruct array_equals(eDIRegP ary1, eSIRegP ary2, regXD tmp1, regXD tmp2, eBXRegI tmp3, - eDXRegI tmp4, eAXRegI result, eFlagsReg cr) %{ +instruct array_equals(eDIRegP ary1, eSIRegP ary2, eAXRegI result, + regXD tmp1, regXD tmp2, eCXRegI tmp3, eBXRegI tmp4, eFlagsReg cr) +%{ match(Set result (AryEq ary1 ary2)); effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); //ins_cost(300); - format %{ "Array Equals $ary1,$ary2 -> $result // KILL EBX, EDX" %} - ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, tmp4, result) ); + format %{ "Array Equals $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %} + ins_encode %{ + __ char_arrays_equals(true, $ary1$$Register, $ary2$$Register, + $tmp3$$Register, $result$$Register, $tmp4$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister); + %} ins_pipe( pipe_slow ); %} diff -r 054afbef9081 -r a2ad635573fb src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Mon Sep 28 12:27:52 2009 -0400 +++ b/src/cpu/x86/vm/x86_64.ad Wed Oct 14 12:40:20 2009 -0700 @@ -683,7 +683,7 @@ #ifdef ASSERT if (rspec.reloc()->type() == relocInfo::oop_type && d32 != 0 && d32 != (intptr_t) Universe::non_oop_word()) { - assert(oop((intptr_t)d32)->is_oop() && oop((intptr_t)d32)->is_perm(), "cannot embed non-perm oops in code"); + assert(oop((intptr_t)d32)->is_oop() && (ScavengeRootsInCode || !oop((intptr_t)d32)->is_scavengable()), "cannot embed scavengable oops in code"); } #endif cbuf.relocate(cbuf.inst_mark(), rspec, format); @@ -721,8 +721,8 @@ #ifdef ASSERT if (rspec.reloc()->type() == relocInfo::oop_type && d64 != 0 && d64 != (int64_t) Universe::non_oop_word()) { - assert(oop(d64)->is_oop() && oop(d64)->is_perm(), - "cannot embed non-perm oops in code"); + assert(oop(d64)->is_oop() && (ScavengeRootsInCode || !oop(d64)->is_scavengable()), + "cannot embed scavengable oops in code"); } #endif cbuf.relocate(cbuf.inst_mark(), rspec, format); @@ -3701,448 +3701,6 @@ } %} - enc_class enc_String_Compare(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2, - rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result) %{ - Label RCX_GOOD_LABEL, LENGTH_DIFF_LABEL, - POP_LABEL, DONE_LABEL, CONT_LABEL, - WHILE_HEAD_LABEL; - MacroAssembler masm(&cbuf); - - XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); - XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); - - // Get the first character position in both strings - // [8] char array, [12] offset, [16] count - int value_offset = java_lang_String::value_offset_in_bytes(); - int offset_offset = java_lang_String::offset_offset_in_bytes(); - int count_offset = java_lang_String::count_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - masm.load_heap_oop(rax, Address(rsi, value_offset)); - masm.movl(rcx, Address(rsi, offset_offset)); - masm.lea(rax, Address(rax, rcx, Address::times_2, base_offset)); - masm.load_heap_oop(rbx, Address(rdi, value_offset)); - masm.movl(rcx, Address(rdi, offset_offset)); - masm.lea(rbx, Address(rbx, rcx, Address::times_2, base_offset)); - - // Compute the minimum of the string lengths(rsi) and the - // difference of the string lengths (stack) - - // do the conditional move stuff - masm.movl(rdi, Address(rdi, count_offset)); - masm.movl(rsi, Address(rsi, count_offset)); - masm.movl(rcx, rdi); - masm.subl(rdi, rsi); - masm.push(rdi); - masm.cmov(Assembler::lessEqual, rsi, rcx); - - // Is the minimum length zero? - masm.bind(RCX_GOOD_LABEL); - masm.testl(rsi, rsi); - masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL); - - // Load first characters - masm.load_unsigned_short(rcx, Address(rbx, 0)); - masm.load_unsigned_short(rdi, Address(rax, 0)); - - // Compare first characters - masm.subl(rcx, rdi); - masm.jcc(Assembler::notZero, POP_LABEL); - masm.decrementl(rsi); - masm.jcc(Assembler::zero, LENGTH_DIFF_LABEL); - - { - // Check after comparing first character to see if strings are equivalent - Label LSkip2; - // Check if the strings start at same location - masm.cmpptr(rbx, rax); - masm.jccb(Assembler::notEqual, LSkip2); - - // Check if the length difference is zero (from stack) - masm.cmpl(Address(rsp, 0), 0x0); - masm.jcc(Assembler::equal, LENGTH_DIFF_LABEL); - - // Strings might not be equivalent - masm.bind(LSkip2); - } - - // Advance to next character - masm.addptr(rax, 2); - masm.addptr(rbx, 2); - - if (UseSSE42Intrinsics) { - // With SSE4.2, use double quad vector compare - Label COMPARE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL; - // Setup to compare 16-byte vectors - masm.movl(rdi, rsi); - masm.andl(rsi, 0xfffffff8); // rsi holds the vector count - masm.andl(rdi, 0x00000007); // rdi holds the tail count - masm.testl(rsi, rsi); - masm.jccb(Assembler::zero, COMPARE_TAIL); - - masm.lea(rax, Address(rax, rsi, Address::times_2)); - masm.lea(rbx, Address(rbx, rsi, Address::times_2)); - masm.negptr(rsi); - - masm.bind(COMPARE_VECTORS); - masm.movdqu(tmp1Reg, Address(rax, rsi, Address::times_2)); - masm.movdqu(tmp2Reg, Address(rbx, rsi, Address::times_2)); - masm.pxor(tmp1Reg, tmp2Reg); - masm.ptest(tmp1Reg, tmp1Reg); - masm.jccb(Assembler::notZero, VECTOR_NOT_EQUAL); - masm.addptr(rsi, 8); - masm.jcc(Assembler::notZero, COMPARE_VECTORS); - masm.jmpb(COMPARE_TAIL); - - // Mismatched characters in the vectors - masm.bind(VECTOR_NOT_EQUAL); - masm.lea(rax, Address(rax, rsi, Address::times_2)); - masm.lea(rbx, Address(rbx, rsi, Address::times_2)); - masm.movl(rdi, 8); - - // Compare tail (< 8 chars), or rescan last vectors to - // find 1st mismatched characters - masm.bind(COMPARE_TAIL); - masm.testl(rdi, rdi); - masm.jccb(Assembler::zero, LENGTH_DIFF_LABEL); - masm.movl(rsi, rdi); - // Fallthru to tail compare - } - - // Shift RAX and RBX to the end of the arrays, negate min - masm.lea(rax, Address(rax, rsi, Address::times_2, 0)); - masm.lea(rbx, Address(rbx, rsi, Address::times_2, 0)); - masm.negptr(rsi); - - // Compare the rest of the characters - masm.bind(WHILE_HEAD_LABEL); - masm.load_unsigned_short(rcx, Address(rbx, rsi, Address::times_2, 0)); - masm.load_unsigned_short(rdi, Address(rax, rsi, Address::times_2, 0)); - masm.subl(rcx, rdi); - masm.jccb(Assembler::notZero, POP_LABEL); - masm.increment(rsi); - masm.jcc(Assembler::notZero, WHILE_HEAD_LABEL); - - // Strings are equal up to min length. Return the length difference. - masm.bind(LENGTH_DIFF_LABEL); - masm.pop(rcx); - masm.jmpb(DONE_LABEL); - - // Discard the stored length difference - masm.bind(POP_LABEL); - masm.addptr(rsp, 8); - - // That's it - masm.bind(DONE_LABEL); - %} - - enc_class enc_String_IndexOf(rsi_RegP str1, rdi_RegP str2, regD tmp1, rax_RegI tmp2, - rcx_RegI tmp3, rdx_RegI tmp4, rbx_RegI result) %{ - // SSE4.2 version - Label LOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR, - SCAN_SUBSTR, RET_NEG_ONE, RET_NOT_FOUND, CLEANUP, DONE; - MacroAssembler masm(&cbuf); - - XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); - - // Get the first character position in both strings - // [8] char array, [12] offset, [16] count - int value_offset = java_lang_String::value_offset_in_bytes(); - int offset_offset = java_lang_String::offset_offset_in_bytes(); - int count_offset = java_lang_String::count_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - // Get counts for string and substr - masm.movl(rdx, Address(rsi, count_offset)); - masm.movl(rax, Address(rdi, count_offset)); - // Check for substr count > string count - masm.cmpl(rax, rdx); - masm.jcc(Assembler::greater, RET_NEG_ONE); - - // Start the indexOf operation - // Get start addr of string - masm.load_heap_oop(rbx, Address(rsi, value_offset)); - masm.movl(rcx, Address(rsi, offset_offset)); - masm.lea(rsi, Address(rbx, rcx, Address::times_2, base_offset)); - masm.push(rsi); - - // Get start addr of substr - masm.load_heap_oop(rbx, Address(rdi, value_offset)); - masm.movl(rcx, Address(rdi, offset_offset)); - masm.lea(rdi, Address(rbx, rcx, Address::times_2, base_offset)); - masm.push(rdi); - masm.push(rax); - masm.jmpb(PREP_FOR_SCAN); - - // Substr count saved at sp - // Substr saved at sp+8 - // String saved at sp+16 - - // Prep to load substr for scan - masm.bind(LOAD_SUBSTR); - masm.movptr(rdi, Address(rsp, 8)); - masm.movl(rax, Address(rsp, 0)); - - // Load substr - masm.bind(PREP_FOR_SCAN); - masm.movdqu(tmp1Reg, Address(rdi, 0)); - masm.addq(rdx, 8); // prime the loop - masm.subptr(rsi, 16); - - // Scan string for substr in 16-byte vectors - masm.bind(SCAN_TO_SUBSTR); - masm.subq(rdx, 8); - masm.addptr(rsi, 16); - masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d); - masm.jcc(Assembler::above, SCAN_TO_SUBSTR); - masm.jccb(Assembler::aboveEqual, RET_NOT_FOUND); - - // Fallthru: found a potential substr - - //Make sure string is still long enough - masm.subl(rdx, rcx); - masm.cmpl(rdx, rax); - masm.jccb(Assembler::negative, RET_NOT_FOUND); - // Compute start addr of substr - masm.lea(rsi, Address(rsi, rcx, Address::times_2)); - masm.movptr(rbx, rsi); - - // Compare potential substr - masm.addq(rdx, 8); // prime the loop - masm.addq(rax, 8); - masm.subptr(rsi, 16); - masm.subptr(rdi, 16); - - // Scan 16-byte vectors of string and substr - masm.bind(SCAN_SUBSTR); - masm.subq(rax, 8); - masm.subq(rdx, 8); - masm.addptr(rsi, 16); - masm.addptr(rdi, 16); - masm.movdqu(tmp1Reg, Address(rdi, 0)); - masm.pcmpestri(tmp1Reg, Address(rsi, 0), 0x0d); - masm.jcc(Assembler::noOverflow, LOAD_SUBSTR); // OF == 0 - masm.jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0 - - // Compute substr offset - masm.movptr(rsi, Address(rsp, 16)); - masm.subptr(rbx, rsi); - masm.shrl(rbx, 1); - masm.jmpb(CLEANUP); - - masm.bind(RET_NEG_ONE); - masm.movl(rbx, -1); - masm.jmpb(DONE); - - masm.bind(RET_NOT_FOUND); - masm.movl(rbx, -1); - - masm.bind(CLEANUP); - masm.addptr(rsp, 24); - - masm.bind(DONE); - %} - - enc_class enc_String_Equals(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2, - rbx_RegI tmp3, rcx_RegI tmp2, rax_RegI result) %{ - Label RET_TRUE, RET_FALSE, DONE, COMPARE_VECTORS, COMPARE_CHAR; - MacroAssembler masm(&cbuf); - - XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); - XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); - - int value_offset = java_lang_String::value_offset_in_bytes(); - int offset_offset = java_lang_String::offset_offset_in_bytes(); - int count_offset = java_lang_String::count_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - // does source == target string? - masm.cmpptr(rdi, rsi); - masm.jcc(Assembler::equal, RET_TRUE); - - // get and compare counts - masm.movl(rcx, Address(rdi, count_offset)); - masm.movl(rax, Address(rsi, count_offset)); - masm.cmpl(rcx, rax); - masm.jcc(Assembler::notEqual, RET_FALSE); - masm.testl(rax, rax); - masm.jcc(Assembler::zero, RET_TRUE); - - // get source string offset and value - masm.load_heap_oop(rbx, Address(rsi, value_offset)); - masm.movl(rax, Address(rsi, offset_offset)); - masm.lea(rsi, Address(rbx, rax, Address::times_2, base_offset)); - - // get compare string offset and value - masm.load_heap_oop(rbx, Address(rdi, value_offset)); - masm.movl(rax, Address(rdi, offset_offset)); - masm.lea(rdi, Address(rbx, rax, Address::times_2, base_offset)); - - // Set byte count - masm.shll(rcx, 1); - masm.movl(rax, rcx); - - if (UseSSE42Intrinsics) { - // With SSE4.2, use double quad vector compare - Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; - // Compare 16-byte vectors - masm.andl(rcx, 0xfffffff0); // vector count (in bytes) - masm.andl(rax, 0x0000000e); // tail count (in bytes) - masm.testl(rcx, rcx); - masm.jccb(Assembler::zero, COMPARE_TAIL); - masm.lea(rdi, Address(rdi, rcx, Address::times_1)); - masm.lea(rsi, Address(rsi, rcx, Address::times_1)); - masm.negptr(rcx); - - masm.bind(COMPARE_WIDE_VECTORS); - masm.movdqu(tmp1Reg, Address(rdi, rcx, Address::times_1)); - masm.movdqu(tmp2Reg, Address(rsi, rcx, Address::times_1)); - masm.pxor(tmp1Reg, tmp2Reg); - masm.ptest(tmp1Reg, tmp1Reg); - masm.jccb(Assembler::notZero, RET_FALSE); - masm.addptr(rcx, 16); - masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); - masm.bind(COMPARE_TAIL); - masm.movl(rcx, rax); - // Fallthru to tail compare - } - - // Compare 4-byte vectors - masm.andl(rcx, 0xfffffffc); // vector count (in bytes) - masm.andl(rax, 0x00000002); // tail char (in bytes) - masm.testl(rcx, rcx); - masm.jccb(Assembler::zero, COMPARE_CHAR); - masm.lea(rdi, Address(rdi, rcx, Address::times_1)); - masm.lea(rsi, Address(rsi, rcx, Address::times_1)); - masm.negptr(rcx); - - masm.bind(COMPARE_VECTORS); - masm.movl(rbx, Address(rdi, rcx, Address::times_1)); - masm.cmpl(rbx, Address(rsi, rcx, Address::times_1)); - masm.jccb(Assembler::notEqual, RET_FALSE); - masm.addptr(rcx, 4); - masm.jcc(Assembler::notZero, COMPARE_VECTORS); - - // Compare trailing char (final 2 bytes), if any - masm.bind(COMPARE_CHAR); - masm.testl(rax, rax); - masm.jccb(Assembler::zero, RET_TRUE); - masm.load_unsigned_short(rbx, Address(rdi, 0)); - masm.load_unsigned_short(rcx, Address(rsi, 0)); - masm.cmpl(rbx, rcx); - masm.jccb(Assembler::notEqual, RET_FALSE); - - masm.bind(RET_TRUE); - masm.movl(rax, 1); // return true - masm.jmpb(DONE); - - masm.bind(RET_FALSE); - masm.xorl(rax, rax); // return false - - masm.bind(DONE); - %} - - enc_class enc_Array_Equals(rdi_RegP ary1, rsi_RegP ary2, regD tmp1, regD tmp2, - rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result) %{ - Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR; - MacroAssembler masm(&cbuf); - - XMMRegister tmp1Reg = as_XMMRegister($tmp1$$reg); - XMMRegister tmp2Reg = as_XMMRegister($tmp2$$reg); - Register ary1Reg = as_Register($ary1$$reg); - Register ary2Reg = as_Register($ary2$$reg); - Register tmp3Reg = as_Register($tmp3$$reg); - Register tmp4Reg = as_Register($tmp4$$reg); - Register resultReg = as_Register($result$$reg); - - int length_offset = arrayOopDesc::length_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - // Check the input args - masm.cmpq(ary1Reg, ary2Reg); - masm.jcc(Assembler::equal, TRUE_LABEL); - masm.testq(ary1Reg, ary1Reg); - masm.jcc(Assembler::zero, FALSE_LABEL); - masm.testq(ary2Reg, ary2Reg); - masm.jcc(Assembler::zero, FALSE_LABEL); - - // Check the lengths - masm.movl(tmp4Reg, Address(ary1Reg, length_offset)); - masm.movl(resultReg, Address(ary2Reg, length_offset)); - masm.cmpl(tmp4Reg, resultReg); - masm.jcc(Assembler::notEqual, FALSE_LABEL); - masm.testl(resultReg, resultReg); - masm.jcc(Assembler::zero, TRUE_LABEL); - - //load array address - masm.lea(ary1Reg, Address(ary1Reg, base_offset)); - masm.lea(ary2Reg, Address(ary2Reg, base_offset)); - - //set byte count - masm.shll(tmp4Reg, 1); - masm.movl(resultReg,tmp4Reg); - - if (UseSSE42Intrinsics){ - // With SSE4.2, use double quad vector compare - Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; - // Compare 16-byte vectors - masm.andl(tmp4Reg, 0xfffffff0); // vector count (in bytes) - masm.andl(resultReg, 0x0000000e); // tail count (in bytes) - masm.testl(tmp4Reg, tmp4Reg); - masm.jccb(Assembler::zero, COMPARE_TAIL); - masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); - masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); - masm.negptr(tmp4Reg); - - masm.bind(COMPARE_WIDE_VECTORS); - masm.movdqu(tmp1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); - masm.movdqu(tmp2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); - masm.pxor(tmp1Reg, tmp2Reg); - masm.ptest(tmp1Reg, tmp1Reg); - - masm.jccb(Assembler::notZero, FALSE_LABEL); - masm.addptr(tmp4Reg, 16); - masm.jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); - masm.bind(COMPARE_TAIL); - masm.movl(tmp4Reg, resultReg); - // Fallthru to tail compare - } - - // Compare 4-byte vectors - masm.andl(tmp4Reg, 0xfffffffc); // vector count (in bytes) - masm.andl(resultReg, 0x00000002); // tail char (in bytes) - masm.testl(tmp4Reg, tmp4Reg); //if tmp2 == 0, only compare char - masm.jccb(Assembler::zero, COMPARE_CHAR); - masm.lea(ary1Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); - masm.lea(ary2Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); - masm.negptr(tmp4Reg); - - masm.bind(COMPARE_VECTORS); - masm.movl(tmp3Reg, Address(ary1Reg, tmp4Reg, Address::times_1)); - masm.cmpl(tmp3Reg, Address(ary2Reg, tmp4Reg, Address::times_1)); - masm.jccb(Assembler::notEqual, FALSE_LABEL); - masm.addptr(tmp4Reg, 4); - masm.jcc(Assembler::notZero, COMPARE_VECTORS); - - // Compare trailing char (final 2 bytes), if any - masm.bind(COMPARE_CHAR); - masm.testl(resultReg, resultReg); - masm.jccb(Assembler::zero, TRUE_LABEL); - masm.load_unsigned_short(tmp3Reg, Address(ary1Reg, 0)); - masm.load_unsigned_short(tmp4Reg, Address(ary2Reg, 0)); - masm.cmpl(tmp3Reg, tmp4Reg); - masm.jccb(Assembler::notEqual, FALSE_LABEL); - - masm.bind(TRUE_LABEL); - masm.movl(resultReg, 1); // return true - masm.jmpb(DONE); - - masm.bind(FALSE_LABEL); - masm.xorl(resultReg, resultReg); // return false - - // That's it - masm.bind(DONE); - %} enc_class enc_rethrow() %{ @@ -12096,52 +11654,67 @@ ins_pipe(pipe_slow); %} -instruct string_compare(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2, - rax_RegI tmp3, rbx_RegI tmp4, rcx_RegI result, rFlagsReg cr) -%{ - match(Set result (StrComp str1 str2)); - effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr); - //ins_cost(300); - - format %{ "String Compare $str1, $str2 -> $result // XXX KILL RAX, RBX" %} - ins_encode( enc_String_Compare(str1, str2, tmp1, tmp2, tmp3, tmp4, result) ); +instruct string_compare(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rbx_RegI cnt2, + rax_RegI result, regD tmp1, regD tmp2, rFlagsReg cr) +%{ + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1, $tmp2" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister); + %} ins_pipe( pipe_slow ); %} -instruct string_indexof(rsi_RegP str1, rdi_RegP str2, regD tmp1, rax_RegI tmp2, - rcx_RegI tmp3, rdx_RegI tmp4, rbx_RegI result, rFlagsReg cr) +instruct string_indexof(rdi_RegP str1, rdx_RegI cnt1, rsi_RegP str2, rax_RegI cnt2, + rbx_RegI result, regD tmp1, rcx_RegI tmp2, rFlagsReg cr) %{ predicate(UseSSE42Intrinsics); - match(Set result (StrIndexOf str1 str2)); - effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, KILL tmp2, KILL tmp3, KILL tmp4, KILL cr); - - format %{ "String IndexOf $str1,$str2 -> $result // KILL RAX, RCX, RDX" %} - ins_encode( enc_String_IndexOf(str1, str2, tmp1, tmp2, tmp3, tmp4, result) ); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP tmp1, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL tmp2, KILL cr); + + format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1, $tmp2" %} + ins_encode %{ + __ string_indexof($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$XMMRegister, $tmp2$$Register); + %} ins_pipe( pipe_slow ); %} // fast string equals -instruct string_equals(rdi_RegP str1, rsi_RegP str2, regD tmp1, regD tmp2, rbx_RegI tmp3, - rcx_RegI tmp4, rax_RegI result, rFlagsReg cr) -%{ - match(Set result (StrEquals str1 str2)); - effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, KILL tmp3, KILL tmp4, KILL cr); - - format %{ "String Equals $str1,$str2 -> $result // KILL RBX, RCX" %} - ins_encode( enc_String_Equals(str1, str2, tmp1, tmp2, tmp3, tmp4, result) ); +instruct string_equals(rdi_RegP str1, rsi_RegP str2, rcx_RegI cnt, rax_RegI result, + regD tmp1, regD tmp2, rbx_RegI tmp3, rFlagsReg cr) +%{ + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(TEMP tmp1, TEMP tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp3, KILL cr); + + format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp1, $tmp2, $tmp3" %} + ins_encode %{ + __ char_arrays_equals(false, $str1$$Register, $str2$$Register, + $cnt$$Register, $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister); + %} ins_pipe( pipe_slow ); %} // fast array equals -instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, regD tmp1, regD tmp2, rax_RegI tmp3, - rbx_RegI tmp4, rcx_RegI result, rFlagsReg cr) +instruct array_equals(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, + regD tmp1, regD tmp2, rcx_RegI tmp3, rbx_RegI tmp4, rFlagsReg cr) %{ match(Set result (AryEq ary1 ary2)); effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL ary2, KILL tmp3, KILL tmp4, KILL cr); //ins_cost(300); - format %{ "Array Equals $ary1,$ary2 -> $result // KILL RAX, RBX" %} - ins_encode( enc_Array_Equals(ary1, ary2, tmp1, tmp2, tmp3, tmp4, result) ); + format %{ "Array Equals $ary1,$ary2 -> $result // KILL $tmp1, $tmp2, $tmp3, $tmp4" %} + ins_encode %{ + __ char_arrays_equals(true, $ary1$$Register, $ary2$$Register, + $tmp3$$Register, $result$$Register, $tmp4$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister); + %} ins_pipe( pipe_slow ); %} diff -r 054afbef9081 -r a2ad635573fb src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp --- a/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/os_cpu/solaris_sparc/vm/atomic_solaris_sparc.inline.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp --- a/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/os_cpu/solaris_x86/vm/atomic_solaris_x86.inline.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/adlc/formssel.cpp --- a/src/share/vm/adlc/formssel.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/adlc/formssel.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -828,11 +828,13 @@ return AdlcVMDeps::Parms; // Skip the machine-state edges if( _matrule->_rChild && - ( strcmp(_matrule->_rChild->_opType,"StrComp" )==0 || + ( strcmp(_matrule->_rChild->_opType,"AryEq" )==0 || + strcmp(_matrule->_rChild->_opType,"StrComp" )==0 || strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 || strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 )) { - // String.(compareTo/equals/indexOf) take 1 control and 4 memory edges. - return 5; + // String.(compareTo/equals/indexOf) and Arrays.equals + // take 1 control and 1 memory edges. + return 2; } // Check for handling of 'Memory' input/edge in the ideal world. diff -r 054afbef9081 -r a2ad635573fb src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1442,7 +1442,7 @@ switch (field_type) { case T_ARRAY: case T_OBJECT: - if (field_val.as_object()->has_encoding()) { + if (field_val.as_object()->should_be_constant()) { constant = new Constant(as_ValueType(field_val)); } break; diff -r 054afbef9081 -r a2ad635573fb src/share/vm/c1/c1_IR.cpp --- a/src/share/vm/c1/c1_IR.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/c1/c1_IR.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/c1/c1_IR.hpp --- a/src/share/vm/c1/c1_IR.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/c1/c1_IR.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/c1/c1_InstructionPrinter.cpp --- a/src/share/vm/c1/c1_InstructionPrinter.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/c1/c1_InstructionPrinter.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -133,12 +133,12 @@ ciMethod* m = (ciMethod*)value; output()->print("", m->holder()->name()->as_utf8(), m->name()->as_utf8()); } else { - output()->print("", value->encoding()); + output()->print("", value->constant_encoding()); } } else if (type->as_InstanceConstant() != NULL) { - output()->print("", type->as_InstanceConstant()->value()->encoding()); + output()->print("", type->as_InstanceConstant()->value()->constant_encoding()); } else if (type->as_ArrayConstant() != NULL) { - output()->print("", type->as_ArrayConstant()->value()->encoding()); + output()->print("", type->as_ArrayConstant()->value()->constant_encoding()); } else if (type->as_ClassConstant() != NULL) { ciInstanceKlass* klass = type->as_ClassConstant()->value(); if (!klass->is_loaded()) { diff -r 054afbef9081 -r a2ad635573fb src/share/vm/c1/c1_LIRAssembler.cpp --- a/src/share/vm/c1/c1_LIRAssembler.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/c1/c1_LIRAssembler.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -440,7 +440,7 @@ __ oop2reg_patch(NULL, r, info); } else { // no patching needed - __ oop2reg(obj->encoding(), r); + __ oop2reg(obj->constant_encoding(), r); } } @@ -831,7 +831,7 @@ int taken_count_offset = md->byte_offset_of_slot(data, BranchData::taken_offset()); int not_taken_count_offset = md->byte_offset_of_slot(data, BranchData::not_taken_offset()); LIR_Opr md_reg = new_register(T_OBJECT); - __ move(LIR_OprFact::oopConst(md->encoding()), md_reg); + __ move(LIR_OprFact::oopConst(md->constant_encoding()), md_reg); LIR_Opr data_offset_reg = new_register(T_INT); __ cmove(lir_cond(cond), LIR_OprFact::intConst(taken_count_offset), @@ -1071,7 +1071,7 @@ LIR_OprList* args = new LIR_OprList(); args->append(getThreadPointer()); LIR_Opr meth = new_register(T_OBJECT); - __ oop2reg(method()->encoding(), meth); + __ oop2reg(method()->constant_encoding(), meth); args->append(meth); call_runtime(&signature, args, CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), voidType, NULL); } @@ -1784,7 +1784,7 @@ LIR_OprList* args = new LIR_OprList(); args->append(getThreadPointer()); LIR_Opr meth = new_register(T_OBJECT); - __ oop2reg(method()->encoding(), meth); + __ oop2reg(method()->constant_encoding(), meth); args->append(meth); call_runtime(&signature, args, CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), voidType, NULL); } @@ -2207,7 +2207,7 @@ LIR_OprList* args = new LIR_OprList(); args->append(getThreadPointer()); LIR_Opr meth = new_register(T_OBJECT); - __ oop2reg(method()->encoding(), meth); + __ oop2reg(method()->constant_encoding(), meth); args->append(meth); call_runtime(&signature, args, CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), voidType, NULL); } @@ -2216,7 +2216,7 @@ LIR_Opr obj; if (method()->is_static()) { obj = new_register(T_OBJECT); - __ oop2reg(method()->holder()->java_mirror()->encoding(), obj); + __ oop2reg(method()->holder()->java_mirror()->constant_encoding(), obj); } else { Local* receiver = x->state()->local_at(0)->as_Local(); assert(receiver != NULL, "must already exist"); @@ -2660,7 +2660,7 @@ } LIR_Opr meth = new_register(T_OBJECT); - __ oop2reg(method()->encoding(), meth); + __ oop2reg(method()->constant_encoding(), meth); LIR_Opr result = increment_and_return_counter(meth, offset, InvocationCounter::count_increment); __ cmp(lir_cond_aboveEqual, result, LIR_OprFact::intConst(limit)); CodeStub* overflow = new CounterOverflowStub(info, info->bci()); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/c1/c1_ValueType.cpp --- a/src/share/vm/c1/c1_ValueType.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/c1/c1_ValueType.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -86,7 +86,7 @@ jobject ObjectType::encoding() const { assert(is_constant(), "must be"); - return constant_value()->encoding(); + return constant_value()->constant_encoding(); } bool ObjectType::is_loaded() const { diff -r 054afbef9081 -r a2ad635573fb src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/ci/ciEnv.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -257,7 +257,7 @@ // ------------------------------------------------------------------ // ciEnv::make_array -ciArray* ciEnv::make_array(GrowableArray* objects) { +ciArray* ciEnv::make_system_array(GrowableArray* objects) { VM_ENTRY_MARK; int length = objects->length(); objArrayOop a = oopFactory::new_system_objArray(length, THREAD); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/ci/ciEnv.hpp --- a/src/share/vm/ci/ciEnv.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/ci/ciEnv.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -339,8 +339,8 @@ // but consider adding to vmSymbols.hpp instead. // Use this to make a holder for non-perm compile time constants. - // The resulting array is guaranteed to satisfy "has_encoding". - ciArray* make_array(GrowableArray* objects); + // The resulting array is guaranteed to satisfy "can_be_constant". + ciArray* make_system_array(GrowableArray* objects); // converts the ciKlass* representing the holder of a method into a // ciInstanceKlass*. This is needed since the holder of a method in diff -r 054afbef9081 -r a2ad635573fb src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/ci/ciMethod.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -325,10 +325,10 @@ } // ------------------------------------------------------------------ -// ciMethod::liveness_at_bci +// ciMethod::raw_liveness_at_bci // // Which local variables are live at a specific bci? -MethodLivenessResult ciMethod::liveness_at_bci(int bci) { +MethodLivenessResult ciMethod::raw_liveness_at_bci(int bci) { check_is_loaded(); if (_liveness == NULL) { // Create the liveness analyzer. @@ -336,7 +336,17 @@ _liveness = new (arena) MethodLiveness(arena, this); _liveness->compute_liveness(); } - MethodLivenessResult result = _liveness->get_liveness_at(bci); + return _liveness->get_liveness_at(bci); +} + +// ------------------------------------------------------------------ +// ciMethod::liveness_at_bci +// +// Which local variables are live at a specific bci? When debugging +// will return true for all locals in some cases to improve debug +// information. +MethodLivenessResult ciMethod::liveness_at_bci(int bci) { + MethodLivenessResult result = raw_liveness_at_bci(bci); if (CURRENT_ENV->jvmti_can_access_local_variables() || DeoptimizeALot || CompileTheWorld) { // Keep all locals live for the user's edification and amusement. result.at_put_range(0, result.size(), true); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/ci/ciMethod.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -149,6 +149,12 @@ bool has_monitor_bytecodes() const { return _uses_monitors; } bool has_balanced_monitors(); + // Returns a bitmap indicating which locals are required to be + // maintained as live for deopt. raw_liveness_at_bci is always the + // direct output of the liveness computation while liveness_at_bci + // may mark all locals as live to improve support for debugging Java + // code by maintaining the state of as many locals as possible. + MethodLivenessResult raw_liveness_at_bci(int bci); MethodLivenessResult liveness_at_bci(int bci); // Get the interpreters viewpoint on oop liveness. MethodLiveness is diff -r 054afbef9081 -r a2ad635573fb src/share/vm/ci/ciObject.cpp --- a/src/share/vm/ci/ciObject.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/ci/ciObject.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -55,6 +55,7 @@ } _klass = NULL; _ident = 0; + init_flags_from(o); } // ------------------------------------------------------------------ @@ -69,6 +70,7 @@ } _klass = NULL; _ident = 0; + init_flags_from(h()); } // ------------------------------------------------------------------ @@ -158,7 +160,7 @@ } // ------------------------------------------------------------------ -// ciObject::encoding +// ciObject::constant_encoding // // The address which the compiler should embed into the // generated code to represent this oop. This address @@ -172,16 +174,24 @@ // // This method should be changed to return an generified address // to discourage use of the JNI handle. -jobject ciObject::encoding() { +jobject ciObject::constant_encoding() { assert(is_null_object() || handle() != NULL, "cannot embed null pointer"); - assert(has_encoding(), "oop must be NULL or perm"); + assert(can_be_constant(), "oop must be NULL or perm"); return handle(); } // ------------------------------------------------------------------ -// ciObject::has_encoding -bool ciObject::has_encoding() { - return handle() == NULL || is_perm(); +// ciObject::can_be_constant +bool ciObject::can_be_constant() { + if (ScavengeRootsInCode >= 1) return true; // now everybody can encode as a constant + return handle() == NULL || !is_scavengable(); +} + +// ------------------------------------------------------------------ +// ciObject::should_be_constant() +bool ciObject::should_be_constant() { + if (ScavengeRootsInCode >= 2) return true; // force everybody to be a constant + return handle() == NULL || !is_scavengable(); } @@ -195,8 +205,9 @@ void ciObject::print(outputStream* st) { st->print("<%s", type_string()); GUARDED_VM_ENTRY(print_impl(st);) - st->print(" ident=%d %s address=0x%x>", ident(), + st->print(" ident=%d %s%s address=0x%x>", ident(), is_perm() ? "PERM" : "", + is_scavengable() ? "SCAVENGABLE" : "", (address)this); } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/ci/ciObject.hpp --- a/src/share/vm/ci/ciObject.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/ci/ciObject.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -51,9 +51,10 @@ ciKlass* _klass; uint _ident; - enum { FLAG_BITS = 1}; + enum { FLAG_BITS = 2 }; enum { - PERM_FLAG = 1 + PERM_FLAG = 1, + SCAVENGABLE_FLAG = 2 }; protected: ciObject(); @@ -68,8 +69,15 @@ return JNIHandles::resolve_non_null(_handle); } - void set_perm() { - _ident |= PERM_FLAG; + void init_flags_from(oop x) { + int flags = 0; + if (x != NULL) { + if (x->is_perm()) + flags |= PERM_FLAG; + if (x->is_scavengable()) + flags |= SCAVENGABLE_FLAG; + } + _ident |= flags; } // Virtual behavior of the print() method. @@ -91,17 +99,27 @@ // A hash value for the convenience of compilers. int hash(); - // Tells if this oop has an encoding. (I.e., is it null or perm?) + // Tells if this oop has an encoding as a constant. + // True if is_scavengable is false. + // Also true if ScavengeRootsInCode is non-zero. // If it does not have an encoding, the compiler is responsible for // making other arrangements for dealing with the oop. - // See ciEnv::make_perm_array - bool has_encoding(); + // See ciEnv::make_array + bool can_be_constant(); + + // Tells if this oop should be made a constant. + // True if is_scavengable is false or ScavengeRootsInCode > 1. + bool should_be_constant(); // Is this object guaranteed to be in the permanent part of the heap? // If so, CollectedHeap::can_elide_permanent_oop_store_barriers is relevant. // If the answer is false, no guarantees are made. bool is_perm() { return (_ident & PERM_FLAG) != 0; } + // Might this object possibly move during a scavenge operation? + // If the answer is true and ScavengeRootsInCode==0, the oop cannot be embedded in code. + bool is_scavengable() { return (_ident & SCAVENGABLE_FLAG) != 0; } + // The address which the compiler should embed into the // generated code to represent this oop. This address // is not the true address of the oop -- it will get patched @@ -109,7 +127,7 @@ // // Usage note: no address arithmetic allowed. Oop must // be registered with the oopRecorder. - jobject encoding(); + jobject constant_encoding(); // What kind of ciObject is this? virtual bool is_null_object() const { return false; } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/ci/ciObjectFactory.cpp --- a/src/share/vm/ci/ciObjectFactory.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/ci/ciObjectFactory.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. 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 @@ -261,12 +261,11 @@ ciObject* new_object = create_new_object(keyHandle()); assert(keyHandle() == new_object->get_oop(), "must be properly recorded"); init_ident_of(new_object); - if (!keyHandle->is_perm()) { + if (!new_object->is_perm()) { // Not a perm-space object. insert_non_perm(bucket, keyHandle(), new_object); return new_object; } - new_object->set_perm(); if (len != _ci_objects->length()) { // creating the new object has recursively entered new objects // into the table. We need to recompute our index. diff -r 054afbef9081 -r a2ad635573fb src/share/vm/ci/ciTypeFlow.cpp --- a/src/share/vm/ci/ciTypeFlow.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/ci/ciTypeFlow.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -2486,8 +2486,13 @@ // Assume irreducible entries need more data flow add_to_work_list(succ); } - lp = lp->parent(); - assert(lp != NULL, "nested loop must have parent by now"); + Loop* plp = lp->parent(); + if (plp == NULL) { + // This only happens for some irreducible cases. The parent + // will be updated during a later pass. + break; + } + lp = plp; } // Merge loop tree branch for all successors. diff -r 054afbef9081 -r a2ad635573fb src/share/vm/classfile/classLoader.hpp --- a/src/share/vm/classfile/classLoader.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/classfile/classLoader.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/classfile/systemDictionary.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -2417,6 +2417,8 @@ vmSymbols::makeSite_name(), vmSymbols::makeSite_signature(), &args, CHECK_(empty)); oop call_site_oop = (oop) result.get_jobject(); + assert(call_site_oop->is_oop() + /*&& sun_dyn_CallSiteImpl::is_instance(call_site_oop)*/, "must be sane"); sun_dyn_CallSiteImpl::set_vmmethod(call_site_oop, mh_invdyn()); if (TraceMethodHandles) { tty->print_cr("Linked invokedynamic bci=%d site="INTPTR_FORMAT":", caller_bci, call_site_oop); @@ -2453,6 +2455,8 @@ oop boot_method_oop = (oop) result.get_jobject(); if (boot_method_oop != NULL) { + assert(boot_method_oop->is_oop() + && java_dyn_MethodHandle::is_instance(boot_method_oop), "must be sane"); // probably no race conditions, but let's be careful: if (Atomic::cmpxchg_ptr(boot_method_oop, ik->adr_bootstrap_method(), NULL) == NULL) ik->set_bootstrap_method(boot_method_oop); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/code/codeBlob.hpp --- a/src/share/vm/code/codeBlob.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/code/codeBlob.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -175,6 +175,8 @@ OopClosure* keep_alive, bool unloading_occurred); virtual void oops_do(OopClosure* f) = 0; + // (All CodeBlob subtypes other than NMethod currently have + // an empty oops_do() method. // OopMap for frame OopMapSet* oop_maps() const { return _oop_maps; } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/code/codeCache.cpp --- a/src/share/vm/code/codeCache.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/code/codeCache.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -95,6 +95,7 @@ int CodeCache::_number_of_blobs = 0; int CodeCache::_number_of_nmethods_with_dependencies = 0; bool CodeCache::_needs_cache_clean = false; +nmethod* CodeCache::_scavenge_root_nmethods = NULL; CodeBlob* CodeCache::first() { @@ -148,10 +149,7 @@ } } verify_if_often(); - if (PrintCodeCache2) { // Need to add a new flag - ResourceMark rm; - tty->print_cr("CodeCache allocation: addr: " INTPTR_FORMAT ", size: 0x%x\n", cb, size); - } + print_trace("allocation", cb, size); return cb; } @@ -159,10 +157,7 @@ assert_locked_or_safepoint(CodeCache_lock); verify_if_often(); - if (PrintCodeCache2) { // Need to add a new flag - ResourceMark rm; - tty->print_cr("CodeCache free: addr: " INTPTR_FORMAT ", size: 0x%x\n", cb, cb->size()); - } + print_trace("free", cb); if (cb->is_nmethod() && ((nmethod *)cb)->has_dependencies()) { _number_of_nmethods_with_dependencies--; } @@ -260,14 +255,148 @@ } } -void CodeCache::oops_do(OopClosure* f) { +void CodeCache::blobs_do(CodeBlobClosure* f) { assert_locked_or_safepoint(CodeCache_lock); FOR_ALL_ALIVE_BLOBS(cb) { - cb->oops_do(f); + f->do_code_blob(cb); + +#ifdef ASSERT + if (cb->is_nmethod()) + ((nmethod*)cb)->verify_scavenge_root_oops(); +#endif //ASSERT } } +// Walk the list of methods which might contain non-perm oops. +void CodeCache::scavenge_root_nmethods_do(CodeBlobClosure* f) { + assert_locked_or_safepoint(CodeCache_lock); + debug_only(mark_scavenge_root_nmethods()); + + for (nmethod* cur = scavenge_root_nmethods(); cur != NULL; cur = cur->scavenge_root_link()) { + debug_only(cur->clear_scavenge_root_marked()); + assert(cur->scavenge_root_not_marked(), ""); + assert(cur->on_scavenge_root_list(), "else shouldn't be on this list"); + + bool is_live = (!cur->is_zombie() && !cur->is_unloaded()); +#ifndef PRODUCT + if (TraceScavenge) { + cur->print_on(tty, is_live ? "scavenge root" : "dead scavenge root"); tty->cr(); + } +#endif //PRODUCT + if (is_live) + // Perform cur->oops_do(f), maybe just once per nmethod. + f->do_code_blob(cur); + } + + // Check for stray marks. + debug_only(verify_perm_nmethods(NULL)); +} + +void CodeCache::add_scavenge_root_nmethod(nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + nm->set_on_scavenge_root_list(); + nm->set_scavenge_root_link(_scavenge_root_nmethods); + set_scavenge_root_nmethods(nm); + print_trace("add_scavenge_root", nm); +} + +void CodeCache::drop_scavenge_root_nmethod(nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); + print_trace("drop_scavenge_root", nm); + nmethod* last = NULL; + nmethod* cur = scavenge_root_nmethods(); + while (cur != NULL) { + nmethod* next = cur->scavenge_root_link(); + if (cur == nm) { + if (last != NULL) + last->set_scavenge_root_link(next); + else set_scavenge_root_nmethods(next); + nm->set_scavenge_root_link(NULL); + nm->clear_on_scavenge_root_list(); + return; + } + last = cur; + cur = next; + } + assert(false, "should have been on list"); +} + +void CodeCache::prune_scavenge_root_nmethods() { + assert_locked_or_safepoint(CodeCache_lock); + debug_only(mark_scavenge_root_nmethods()); + + nmethod* last = NULL; + nmethod* cur = scavenge_root_nmethods(); + while (cur != NULL) { + nmethod* next = cur->scavenge_root_link(); + debug_only(cur->clear_scavenge_root_marked()); + assert(cur->scavenge_root_not_marked(), ""); + assert(cur->on_scavenge_root_list(), "else shouldn't be on this list"); + + if (!cur->is_zombie() && !cur->is_unloaded() + && cur->detect_scavenge_root_oops()) { + // Keep it. Advance 'last' to prevent deletion. + last = cur; + } else { + // Prune it from the list, so we don't have to look at it any more. + print_trace("prune_scavenge_root", cur); + cur->set_scavenge_root_link(NULL); + cur->clear_on_scavenge_root_list(); + if (last != NULL) + last->set_scavenge_root_link(next); + else set_scavenge_root_nmethods(next); + } + cur = next; + } + + // Check for stray marks. + debug_only(verify_perm_nmethods(NULL)); +} + +#ifndef PRODUCT +void CodeCache::asserted_non_scavengable_nmethods_do(CodeBlobClosure* f) { + // While we are here, verify the integrity of the list. + mark_scavenge_root_nmethods(); + for (nmethod* cur = scavenge_root_nmethods(); cur != NULL; cur = cur->scavenge_root_link()) { + assert(cur->on_scavenge_root_list(), "else shouldn't be on this list"); + cur->clear_scavenge_root_marked(); + } + verify_perm_nmethods(f); +} + +// Temporarily mark nmethods that are claimed to be on the non-perm list. +void CodeCache::mark_scavenge_root_nmethods() { + FOR_ALL_ALIVE_BLOBS(cb) { + if (cb->is_nmethod()) { + nmethod *nm = (nmethod*)cb; + assert(nm->scavenge_root_not_marked(), "clean state"); + if (nm->on_scavenge_root_list()) + nm->set_scavenge_root_marked(); + } + } +} + +// If the closure is given, run it on the unlisted nmethods. +// Also make sure that the effects of mark_scavenge_root_nmethods is gone. +void CodeCache::verify_perm_nmethods(CodeBlobClosure* f_or_null) { + FOR_ALL_ALIVE_BLOBS(cb) { + bool call_f = (f_or_null != NULL); + if (cb->is_nmethod()) { + nmethod *nm = (nmethod*)cb; + assert(nm->scavenge_root_not_marked(), "must be already processed"); + if (nm->on_scavenge_root_list()) + call_f = false; // don't show this one to the client + nm->verify_scavenge_root_oops(); + } else { + call_f = false; // not an nmethod + } + if (call_f) f_or_null->do_code_blob(cb); + } +} +#endif //PRODUCT + void CodeCache::gc_prologue() { + assert(!nmethod::oops_do_marking_is_active(), "oops_do_marking_epilogue must be called"); } @@ -285,6 +414,8 @@ cb->fix_oop_relocations(); } set_needs_cache_clean(false); + prune_scavenge_root_nmethods(); + assert(!nmethod::oops_do_marking_is_active(), "oops_do_marking_prologue must be called"); } @@ -508,6 +639,14 @@ } } +void CodeCache::print_trace(const char* event, CodeBlob* cb, int size) { + if (PrintCodeCache2) { // Need to add a new flag + ResourceMark rm; + if (size == 0) size = cb->size(); + tty->print_cr("CodeCache %s: addr: " INTPTR_FORMAT ", size: 0x%x", event, cb, size); + } +} + void CodeCache::print_internals() { int nmethodCount = 0; int runtimeStubCount = 0; diff -r 054afbef9081 -r a2ad635573fb src/share/vm/code/codeCache.hpp --- a/src/share/vm/code/codeCache.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/code/codeCache.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -45,8 +45,13 @@ static int _number_of_blobs; static int _number_of_nmethods_with_dependencies; static bool _needs_cache_clean; + static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link() static void verify_if_often() PRODUCT_RETURN; + + static void mark_scavenge_root_nmethods() PRODUCT_RETURN; + static void verify_perm_nmethods(CodeBlobClosure* f_or_null) PRODUCT_RETURN; + public: // Initialization @@ -61,6 +66,7 @@ static void flush(); // flushes all CodeBlobs static bool contains(void *p); // returns whether p is included static void blobs_do(void f(CodeBlob* cb)); // iterates over all CodeBlobs + static void blobs_do(CodeBlobClosure* f); // iterates over all CodeBlobs static void nmethods_do(void f(nmethod* nm)); // iterates over all nmethods // Lookup @@ -106,12 +112,24 @@ static void do_unloading(BoolObjectClosure* is_alive, OopClosure* keep_alive, bool unloading_occurred); - static void oops_do(OopClosure* f); + static void oops_do(OopClosure* f) { + CodeBlobToOopClosure oopc(f, /*do_marking=*/ false); + blobs_do(&oopc); + } + static void asserted_non_scavengable_nmethods_do(CodeBlobClosure* f = NULL) PRODUCT_RETURN; + static void scavenge_root_nmethods_do(CodeBlobClosure* f); + + static nmethod* scavenge_root_nmethods() { return _scavenge_root_nmethods; } + static void set_scavenge_root_nmethods(nmethod* nm) { _scavenge_root_nmethods = nm; } + static void add_scavenge_root_nmethod(nmethod* nm); + static void drop_scavenge_root_nmethod(nmethod* nm); + static void prune_scavenge_root_nmethods(); // Printing/debugging static void print() PRODUCT_RETURN; // prints summary static void print_internals(); static void verify(); // verifies the code cache + static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN; // The full limits of the codeCache static address low_bound() { return (address) _heap->low_boundary(); } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/code/debugInfoRec.cpp --- a/src/share/vm/code/debugInfoRec.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/code/debugInfoRec.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -299,7 +299,7 @@ stream()->write_int(sender_stream_offset); // serialize scope - jobject method_enc = (method == NULL)? NULL: method->encoding(); + jobject method_enc = (method == NULL)? NULL: method->constant_encoding(); stream()->write_int(oop_recorder()->find_index(method_enc)); stream()->write_bci(bci); assert(method == NULL || diff -r 054afbef9081 -r a2ad635573fb src/share/vm/code/debugInfoRec.hpp --- a/src/share/vm/code/debugInfoRec.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/code/debugInfoRec.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/code/dependencies.cpp --- a/src/share/vm/code/dependencies.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/code/dependencies.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -302,7 +302,7 @@ bytes.write_byte(code_byte); for (int j = 0; j < stride; j++) { if (j == skipj) continue; - bytes.write_int(_oop_recorder->find_index(deps->at(i+j)->encoding())); + bytes.write_int(_oop_recorder->find_index(deps->at(i+j)->constant_encoding())); } } } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/code/nmethod.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -581,10 +581,13 @@ debug_only(No_Safepoint_Verifier nsv;) assert_locked_or_safepoint(CodeCache_lock); - NOT_PRODUCT(_has_debug_info = false; ) + NOT_PRODUCT(_has_debug_info = false); + _oops_do_mark_link = NULL; _method = method; _entry_bci = InvocationEntryBci; - _link = NULL; + _osr_link = NULL; + _scavenge_root_link = NULL; + _scavenge_root_state = 0; _compiler = NULL; // We have no exception handler or deopt handler make the // values something that will never match a pc like the nmethod vtable entry @@ -618,7 +621,7 @@ _stack_traversal_mark = 0; code_buffer->copy_oops_to(this); - debug_only(check_store();) + debug_only(verify_scavenge_root_oops()); CodeCache::commit(this); VTune::create_nmethod(this); } @@ -668,10 +671,13 @@ debug_only(No_Safepoint_Verifier nsv;) assert_locked_or_safepoint(CodeCache_lock); - NOT_PRODUCT(_has_debug_info = false; ) + NOT_PRODUCT(_has_debug_info = false); + _oops_do_mark_link = NULL; _method = method; _entry_bci = InvocationEntryBci; - _link = NULL; + _osr_link = NULL; + _scavenge_root_link = NULL; + _scavenge_root_state = 0; _compiler = NULL; // We have no exception handler or deopt handler make the // values something that will never match a pc like the nmethod vtable entry @@ -703,7 +709,7 @@ _stack_traversal_mark = 0; code_buffer->copy_oops_to(this); - debug_only(check_store();) + debug_only(verify_scavenge_root_oops()); CodeCache::commit(this); VTune::create_nmethod(this); } @@ -770,12 +776,15 @@ debug_only(No_Safepoint_Verifier nsv;) assert_locked_or_safepoint(CodeCache_lock); - NOT_PRODUCT(_has_debug_info = false; ) + NOT_PRODUCT(_has_debug_info = false); + _oops_do_mark_link = NULL; _method = method; _compile_id = compile_id; _comp_level = comp_level; _entry_bci = entry_bci; - _link = NULL; + _osr_link = NULL; + _scavenge_root_link = NULL; + _scavenge_root_state = 0; _compiler = compiler; _orig_pc_offset = orig_pc_offset; #ifdef HAVE_DTRACE_H @@ -813,7 +822,10 @@ code_buffer->copy_oops_to(this); debug_info->copy_to(this); dependencies->copy_to(this); - debug_only(check_store();) + if (ScavengeRootsInCode && detect_scavenge_root_oops()) { + CodeCache::add_scavenge_root_nmethod(this); + } + debug_only(verify_scavenge_root_oops()); CodeCache::commit(this); @@ -902,23 +914,30 @@ if (st != NULL) { ttyLocker ttyl; // Print a little tag line that looks like +PrintCompilation output: - st->print("%3d%c %s", + int tlen = (int) strlen(title); + bool do_nl = false; + if (tlen > 0 && title[tlen-1] == '\n') { tlen--; do_nl = true; } + st->print("%3d%c %.*s", compile_id(), is_osr_method() ? '%' : method() != NULL && is_native_method() ? 'n' : ' ', - title); + tlen, title); #ifdef TIERED st->print(" (%d) ", comp_level()); #endif // TIERED if (WizardMode) st->print(" (" INTPTR_FORMAT ")", this); - if (method() != NULL) { - method()->print_short_name(st); + if (Universe::heap()->is_gc_active() && method() != NULL) { + st->print("(method)"); + } else if (method() != NULL) { + method()->print_short_name(st); if (is_osr_method()) st->print(" @ %d", osr_entry_bci()); if (method()->code_size() > 0) st->print(" (%d bytes)", method()->code_size()); } + + if (do_nl) st->cr(); } } @@ -1033,6 +1052,7 @@ } } +// This is a private interface with the sweeper. void nmethod::mark_as_seen_on_stack() { assert(is_not_entrant(), "must be a non-entrant method"); set_stack_traversal_mark(NMethodSweeper::traversal_count()); @@ -1077,7 +1097,8 @@ " unloadable], methodOop(" INTPTR_FORMAT "), cause(" INTPTR_FORMAT ")", this, (address)_method, (address)cause); - cause->klass()->print(); + if (!Universe::heap()->is_gc_active()) + cause->klass()->print(); } // Unlink the osr method, so we do not look this up again if (is_osr_method()) { @@ -1109,7 +1130,8 @@ // The methodOop is gone at this point assert(_method == NULL, "Tautology"); - set_link(NULL); + set_osr_link(NULL); + //set_scavenge_root_link(NULL); // done by prune_scavenge_root_nmethods NMethodSweeper::notify(this); } @@ -1295,6 +1317,10 @@ ec = next; } + if (on_scavenge_root_list()) { + CodeCache::drop_scavenge_root_nmethod(this); + } + ((CodeBlob*)(this))->flush(); CodeCache::free(this); @@ -1354,7 +1380,10 @@ return false; } } - assert(unloading_occurred, "Inconsistency in unloading"); + // If ScavengeRootsInCode is true, an nmethod might be unloaded + // simply because one of its constant oops has gone dead. + // No actual classes need to be unloaded in order for this to occur. + assert(unloading_occurred || ScavengeRootsInCode, "Inconsistency in unloading"); make_unloaded(is_alive, obj); return true; } @@ -1529,13 +1558,12 @@ // the (strong) marking phase, and then again when walking // the code cache contents during the weak roots processing // phase. The two uses are distinguished by means of the -// do_nmethods() method in the closure "f" below -- which -// answers "yes" in the first case, and "no" in the second +// 'do_strong_roots_only' flag, which is true in the first // case. We want to walk the weak roots in the nmethod // only in the second case. The weak roots in the nmethod // are the oops in the ExceptionCache and the InlineCache // oops. -void nmethod::oops_do(OopClosure* f) { +void nmethod::oops_do(OopClosure* f, bool do_strong_roots_only) { // make sure the oops ready to receive visitors assert(!is_zombie() && !is_unloaded(), "should not call follow on zombie or unloaded nmethod"); @@ -1553,7 +1581,7 @@ // Compiled code f->do_oop((oop*) &_method); - if (!f->do_nmethods()) { + if (!do_strong_roots_only) { // weak roots processing phase -- update ExceptionCache oops ExceptionCache* ec = exception_cache(); while(ec != NULL) { @@ -1579,12 +1607,108 @@ } // Scopes + // This includes oop constants not inlined in the code stream. for (oop* p = oops_begin(); p < oops_end(); p++) { if (*p == Universe::non_oop_word()) continue; // skip non-oops f->do_oop(p); } } +#define NMETHOD_SENTINEL ((nmethod*)badAddress) + +nmethod* volatile nmethod::_oops_do_mark_nmethods; + +// An nmethod is "marked" if its _mark_link is set non-null. +// Even if it is the end of the linked list, it will have a non-null link value, +// as long as it is on the list. +// This code must be MP safe, because it is used from parallel GC passes. +bool nmethod::test_set_oops_do_mark() { + assert(nmethod::oops_do_marking_is_active(), "oops_do_marking_prologue must be called"); + nmethod* observed_mark_link = _oops_do_mark_link; + if (observed_mark_link == NULL) { + // Claim this nmethod for this thread to mark. + observed_mark_link = (nmethod*) + Atomic::cmpxchg_ptr(NMETHOD_SENTINEL, &_oops_do_mark_link, NULL); + if (observed_mark_link == NULL) { + + // Atomically append this nmethod (now claimed) to the head of the list: + nmethod* observed_mark_nmethods = _oops_do_mark_nmethods; + for (;;) { + nmethod* required_mark_nmethods = observed_mark_nmethods; + _oops_do_mark_link = required_mark_nmethods; + observed_mark_nmethods = (nmethod*) + Atomic::cmpxchg_ptr(this, &_oops_do_mark_nmethods, required_mark_nmethods); + if (observed_mark_nmethods == required_mark_nmethods) + break; + } + // Mark was clear when we first saw this guy. + NOT_PRODUCT(if (TraceScavenge) print_on(tty, "oops_do, mark\n")); + return false; + } + } + // On fall through, another racing thread marked this nmethod before we did. + return true; +} + +void nmethod::oops_do_marking_prologue() { + NOT_PRODUCT(if (TraceScavenge) tty->print_cr("[oops_do_marking_prologue")); + assert(_oops_do_mark_nmethods == NULL, "must not call oops_do_marking_prologue twice in a row"); + // We use cmpxchg_ptr instead of regular assignment here because the user + // may fork a bunch of threads, and we need them all to see the same state. + void* observed = Atomic::cmpxchg_ptr(NMETHOD_SENTINEL, &_oops_do_mark_nmethods, NULL); + guarantee(observed == NULL, "no races in this sequential code"); +} + +void nmethod::oops_do_marking_epilogue() { + assert(_oops_do_mark_nmethods != NULL, "must not call oops_do_marking_epilogue twice in a row"); + nmethod* cur = _oops_do_mark_nmethods; + while (cur != NMETHOD_SENTINEL) { + assert(cur != NULL, "not NULL-terminated"); + nmethod* next = cur->_oops_do_mark_link; + cur->_oops_do_mark_link = NULL; + NOT_PRODUCT(if (TraceScavenge) cur->print_on(tty, "oops_do, unmark\n")); + cur = next; + } + void* required = _oops_do_mark_nmethods; + void* observed = Atomic::cmpxchg_ptr(NULL, &_oops_do_mark_nmethods, required); + guarantee(observed == required, "no races in this sequential code"); + NOT_PRODUCT(if (TraceScavenge) tty->print_cr("oops_do_marking_epilogue]")); +} + +class DetectScavengeRoot: public OopClosure { + bool _detected_scavenge_root; +public: + DetectScavengeRoot() : _detected_scavenge_root(false) + { NOT_PRODUCT(_print_nm = NULL); } + bool detected_scavenge_root() { return _detected_scavenge_root; } + virtual void do_oop(oop* p) { + if ((*p) != NULL && (*p)->is_scavengable()) { + NOT_PRODUCT(maybe_print(p)); + _detected_scavenge_root = true; + } + } + virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } + +#ifndef PRODUCT + nmethod* _print_nm; + void maybe_print(oop* p) { + if (_print_nm == NULL) return; + if (!_detected_scavenge_root) _print_nm->print_on(tty, "new scavenge root"); + tty->print_cr(""PTR_FORMAT"[offset=%d] detected non-perm oop "PTR_FORMAT" (found at "PTR_FORMAT")", + _print_nm, (int)((intptr_t)p - (intptr_t)_print_nm), + (intptr_t)(*p), (intptr_t)p); + (*p)->print(); + } +#endif //PRODUCT +}; + +bool nmethod::detect_scavenge_root_oops() { + DetectScavengeRoot detect_scavenge_root; + NOT_PRODUCT(if (TraceScavenge) detect_scavenge_root._print_nm = this); + oops_do(&detect_scavenge_root); + return detect_scavenge_root.detected_scavenge_root(); +} + // Method that knows how to preserve outgoing arguments at call. This method must be // called with a frame corresponding to a Java invoke void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { @@ -1899,6 +2023,24 @@ // ----------------------------------------------------------------------------- // Verification +class VerifyOopsClosure: public OopClosure { + nmethod* _nm; + bool _ok; +public: + VerifyOopsClosure(nmethod* nm) : _nm(nm), _ok(true) { } + bool ok() { return _ok; } + virtual void do_oop(oop* p) { + if ((*p) == NULL || (*p)->is_oop()) return; + if (_ok) { + _nm->print_nmethod(true); + _ok = false; + } + tty->print_cr("*** non-oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)", + (intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); + } + virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } +}; + void nmethod::verify() { // Hmm. OSR methods can be deopted but not marked as zombie or not_entrant @@ -1932,6 +2074,11 @@ } } + VerifyOopsClosure voc(this); + oops_do(&voc); + assert(voc.ok(), "embedded oops must be OK"); + verify_scavenge_root_oops(); + verify_scopes(); } @@ -1995,19 +2142,34 @@ // Non-product code #ifndef PRODUCT -void nmethod::check_store() { - // Make sure all oops in the compiled code are tenured +class DebugScavengeRoot: public OopClosure { + nmethod* _nm; + bool _ok; +public: + DebugScavengeRoot(nmethod* nm) : _nm(nm), _ok(true) { } + bool ok() { return _ok; } + virtual void do_oop(oop* p) { + if ((*p) == NULL || !(*p)->is_scavengable()) return; + if (_ok) { + _nm->print_nmethod(true); + _ok = false; + } + tty->print_cr("*** non-perm oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)", + (intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm)); + (*p)->print(); + } + virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } +}; - RelocIterator iter(this); - while (iter.next()) { - if (iter.type() == relocInfo::oop_type) { - oop_Relocation* reloc = iter.oop_reloc(); - oop obj = reloc->oop_value(); - if (obj != NULL && !obj->is_perm()) { - fatal("must be permanent oop in compiled code"); - } - } +void nmethod::verify_scavenge_root_oops() { + if (!on_scavenge_root_list()) { + // Actually look inside, to verify the claim that it's clean. + DebugScavengeRoot debug_scavenge_root(this); + oops_do(&debug_scavenge_root); + if (!debug_scavenge_root.ok()) + fatal("found an unadvertised bad non-perm oop in the code cache"); } + assert(scavenge_root_not_marked(), ""); } #endif // PRODUCT @@ -2040,6 +2202,7 @@ if (is_not_entrant()) tty->print("not_entrant "); if (is_zombie()) tty->print("zombie "); if (is_unloaded()) tty->print("unloaded "); + if (on_scavenge_root_list()) tty->print("scavenge_root "); tty->print_cr("}:"); } if (size () > 0) tty->print_cr(" total in heap [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", diff -r 054afbef9081 -r a2ad635573fb src/share/vm/code/nmethod.hpp --- a/src/share/vm/code/nmethod.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/code/nmethod.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -125,6 +125,7 @@ class nmethod : public CodeBlob { friend class VMStructs; friend class NMethodSweeper; + friend class CodeCache; // non-perm oops private: // Shared fields for all nmethod's static int _zombie_instruction_size; @@ -132,7 +133,12 @@ methodOop _method; int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method - nmethod* _link; // To support simple linked-list chaining of nmethods + // To support simple linked-list chaining of nmethods: + nmethod* _osr_link; // from instanceKlass::osr_nmethods_head + nmethod* _scavenge_root_link; // from CodeCache::scavenge_root_nmethods + + static nmethod* volatile _oops_do_mark_nmethods; + nmethod* volatile _oops_do_mark_link; AbstractCompiler* _compiler; // The compiler which compiled this nmethod @@ -174,6 +180,8 @@ // used by jvmti to track if an unload event has been posted for this nmethod. bool _unload_reported; + jbyte _scavenge_root_state; + NOT_PRODUCT(bool _has_debug_info; ) // Nmethod Flushing lock (if non-zero, then the nmethod is not removed) @@ -242,7 +250,6 @@ // helper methods void* operator new(size_t size, int nmethod_size); - void check_store(); const char* reloc_string_for(u_char* begin, u_char* end); void make_not_entrant_or_zombie(int state); @@ -406,6 +413,24 @@ int version() const { return flags.version; } void set_version(int v); + // Non-perm oop support + bool on_scavenge_root_list() const { return (_scavenge_root_state & 1) != 0; } + protected: + enum { npl_on_list = 0x01, npl_marked = 0x10 }; + void set_on_scavenge_root_list() { _scavenge_root_state = npl_on_list; } + void clear_on_scavenge_root_list() { _scavenge_root_state = 0; } + // assertion-checking and pruning logic uses the bits of _scavenge_root_state +#ifndef PRODUCT + void set_scavenge_root_marked() { _scavenge_root_state |= npl_marked; } + void clear_scavenge_root_marked() { _scavenge_root_state &= ~npl_marked; } + bool scavenge_root_not_marked() { return (_scavenge_root_state &~ npl_on_list) == 0; } + // N.B. there is no positive marked query, and we only use the not_marked query for asserts. +#endif //PRODUCT + nmethod* scavenge_root_link() const { return _scavenge_root_link; } + void set_scavenge_root_link(nmethod *n) { _scavenge_root_link = n; } + + public: + // Sweeper support long stack_traversal_mark() { return _stack_traversal_mark; } void set_stack_traversal_mark(long l) { _stack_traversal_mark = l; } @@ -424,8 +449,8 @@ int osr_entry_bci() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _entry_bci; } address osr_entry() const { assert(_entry_bci != InvocationEntryBci, "wrong kind of nmethod"); return _osr_entry_point; } void invalidate_osr_method(); - nmethod* link() const { return _link; } - void set_link(nmethod *n) { _link = n; } + nmethod* osr_link() const { return _osr_link; } + void set_osr_link(nmethod *n) { _osr_link = n; } // tells whether frames described by this nmethod can be deoptimized // note: native wrappers cannot be deoptimized. @@ -465,7 +490,16 @@ void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f); - void oops_do(OopClosure* f); + virtual void oops_do(OopClosure* f) { oops_do(f, false); } + void oops_do(OopClosure* f, bool do_strong_roots_only); + bool detect_scavenge_root_oops(); + void verify_scavenge_root_oops() PRODUCT_RETURN; + + bool test_set_oops_do_mark(); + static void oops_do_marking_prologue(); + static void oops_do_marking_epilogue(); + static bool oops_do_marking_is_active() { return _oops_do_mark_nmethods != NULL; } + DEBUG_ONLY(bool test_oops_do_mark() { return _oops_do_mark_link != NULL; }) // ScopeDesc for an instruction ScopeDesc* scope_desc_at(address pc); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/compiler/oopMap.cpp --- a/src/share/vm/compiler/oopMap.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/compiler/oopMap.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/compiler/oopMap.hpp --- a/src/share/vm/compiler/oopMap.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/compiler/oopMap.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/cmsOopClosures.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -47,20 +47,15 @@ private: const MemRegion _span; CMSBitMap* _bitMap; - const bool _should_do_nmethods; protected: DO_OOP_WORK_DEFN public: - MarkRefsIntoClosure(MemRegion span, CMSBitMap* bitMap, - bool should_do_nmethods); + MarkRefsIntoClosure(MemRegion span, CMSBitMap* bitMap); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); inline void do_oop_nv(oop* p) { MarkRefsIntoClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { MarkRefsIntoClosure::do_oop_work(p); } bool do_header() { return true; } - virtual const bool do_nmethods() const { - return _should_do_nmethods; - } Prefetch::style prefetch_style() { return Prefetch::do_read; } @@ -73,20 +68,16 @@ const MemRegion _span; CMSBitMap* _verification_bm; CMSBitMap* _cms_bm; - const bool _should_do_nmethods; protected: DO_OOP_WORK_DEFN public: MarkRefsIntoVerifyClosure(MemRegion span, CMSBitMap* verification_bm, - CMSBitMap* cms_bm, bool should_do_nmethods); + CMSBitMap* cms_bm); virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); inline void do_oop_nv(oop* p) { MarkRefsIntoVerifyClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { MarkRefsIntoVerifyClosure::do_oop_work(p); } bool do_header() { return true; } - virtual const bool do_nmethods() const { - return _should_do_nmethods; - } Prefetch::style prefetch_style() { return Prefetch::do_read; } @@ -228,7 +219,6 @@ inline void do_oop_nv(oop* p) { MarkRefsIntoAndScanClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { MarkRefsIntoAndScanClosure::do_oop_work(p); } bool do_header() { return true; } - virtual const bool do_nmethods() const { return true; } Prefetch::style prefetch_style() { return Prefetch::do_read; } @@ -273,7 +263,6 @@ inline void do_oop_nv(oop* p) { Par_MarkRefsIntoAndScanClosure::do_oop_work(p); } inline void do_oop_nv(narrowOop* p) { Par_MarkRefsIntoAndScanClosure::do_oop_work(p); } bool do_header() { return true; } - virtual const bool do_nmethods() const { return true; } // When ScanMarkedObjectsAgainClosure is used, // it passes [Par_]MarkRefsIntoAndScanClosure to oop_oop_iterate(), // and this delegation is used. diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -2852,14 +2852,17 @@ GenCollectedHeap* gch = GenCollectedHeap::heap(); // Mark from roots one level into CMS - MarkRefsIntoClosure notOlder(_span, verification_mark_bm(), true /* nmethods */); + MarkRefsIntoClosure notOlder(_span, verification_mark_bm()); gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. gch->gen_process_strong_roots(_cmsGen->level(), true, // younger gens are roots + true, // activate StrongRootsScope true, // collecting perm gen SharedHeap::ScanningOption(roots_scanning_options()), - NULL, ¬Older); + ¬Older, + true, // walk code active on stacks + NULL); // Now mark from the roots assert(_revisitStack.isEmpty(), "Should be empty"); @@ -2901,13 +2904,16 @@ // Mark from roots one level into CMS MarkRefsIntoVerifyClosure notOlder(_span, verification_mark_bm(), - markBitMap(), true /* nmethods */); + markBitMap()); gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. gch->gen_process_strong_roots(_cmsGen->level(), true, // younger gens are roots + true, // activate StrongRootsScope true, // collecting perm gen SharedHeap::ScanningOption(roots_scanning_options()), - NULL, ¬Older); + ¬Older, + true, // walk code active on stacks + NULL); // Now mark from the roots assert(_revisitStack.isEmpty(), "Should be empty"); @@ -3484,8 +3490,10 @@ FalseClosure falseClosure; // In the case of a synchronous collection, we will elide the // remark step, so it's important to catch all the nmethod oops - // in this step; hence the last argument to the constrcutor below. - MarkRefsIntoClosure notOlder(_span, &_markBitMap, !asynch /* nmethods */); + // in this step. + // The final 'true' flag to gen_process_strong_roots will ensure this. + // If 'async' is true, we can relax the nmethod tracing. + MarkRefsIntoClosure notOlder(_span, &_markBitMap); GenCollectedHeap* gch = GenCollectedHeap::heap(); verify_work_stacks_empty(); @@ -3504,9 +3512,12 @@ gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. gch->gen_process_strong_roots(_cmsGen->level(), true, // younger gens are roots + true, // activate StrongRootsScope true, // collecting perm gen SharedHeap::ScanningOption(roots_scanning_options()), - NULL, ¬Older); + ¬Older, + true, // walk all of code cache if (so & SO_CodeCache) + NULL); } // Clear mod-union table; it will be dirtied in the prologue of @@ -5040,9 +5051,15 @@ _timer.start(); gch->gen_process_strong_roots(_collector->_cmsGen->level(), false, // yg was scanned above + false, // this is parallel code true, // collecting perm gen SharedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()), - NULL, &par_mrias_cl); + &par_mrias_cl, + true, // walk all of code cache if (so & SO_CodeCache) + NULL); + assert(_collector->should_unload_classes() + || (_collector->CMSCollector::roots_scanning_options() & SharedHeap::SO_CodeCache), + "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops"); _timer.stop(); if (PrintCMSStatistics != 0) { gclog_or_tty->print_cr( @@ -5423,7 +5440,6 @@ // Set up for parallel process_strong_roots work. gch->set_par_threads(n_workers); - gch->change_strong_roots_parity(); // We won't be iterating over the cards in the card table updating // the younger_gen cards, so we shouldn't call the following else // the verification code as well as subsequent younger_refs_iterate @@ -5454,8 +5470,10 @@ if (n_workers > 1) { // Make refs discovery MT-safe ReferenceProcessorMTMutator mt(ref_processor(), true); + GenCollectedHeap::StrongRootsScope srs(gch); workers->run_task(&tsk); } else { + GenCollectedHeap::StrongRootsScope srs(gch); tsk.work(0); } gch->set_par_threads(0); // 0 ==> non-parallel. @@ -5539,11 +5557,18 @@ verify_work_stacks_empty(); gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel. + GenCollectedHeap::StrongRootsScope srs(gch); gch->gen_process_strong_roots(_cmsGen->level(), true, // younger gens as roots + false, // use the local StrongRootsScope true, // collecting perm gen SharedHeap::ScanningOption(roots_scanning_options()), - NULL, &mrias_cl); + &mrias_cl, + true, // walk code active on stacks + NULL); + assert(should_unload_classes() + || (roots_scanning_options() & SharedHeap::SO_CodeCache), + "if we didn't scan the code cache, we have to be ready to drop nmethods with expired weak oops"); } verify_work_stacks_empty(); // Restore evacuated mark words, if any, used for overflow list links @@ -6418,10 +6443,9 @@ // generation then this will lose younger_gen cards! MarkRefsIntoClosure::MarkRefsIntoClosure( - MemRegion span, CMSBitMap* bitMap, bool should_do_nmethods): + MemRegion span, CMSBitMap* bitMap): _span(span), - _bitMap(bitMap), - _should_do_nmethods(should_do_nmethods) + _bitMap(bitMap) { assert(_ref_processor == NULL, "deliberately left NULL"); assert(_bitMap->covers(_span), "_bitMap/_span mismatch"); @@ -6442,12 +6466,11 @@ // A variant of the above, used for CMS marking verification. MarkRefsIntoVerifyClosure::MarkRefsIntoVerifyClosure( - MemRegion span, CMSBitMap* verification_bm, CMSBitMap* cms_bm, - bool should_do_nmethods): + MemRegion span, CMSBitMap* verification_bm, CMSBitMap* cms_bm): _span(span), _verification_bm(verification_bm), - _cms_bm(cms_bm), - _should_do_nmethods(should_do_nmethods) { + _cms_bm(cms_bm) +{ assert(_ref_processor == NULL, "deliberately left NULL"); assert(_verification_bm->covers(_span), "_verification_bm/_span mismatch"); } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -746,10 +746,11 @@ // clear the mark bitmap (no grey objects to start with) _nextMarkBitMap->clearAll(); PrintReachableClosure prcl(_nextMarkBitMap); - g1h->process_strong_roots( + g1h->process_strong_roots(true, // activate StrongRootsScope false, // fake perm gen collection SharedHeap::SO_AllClasses, &prcl, // Regular roots + NULL, // do not visit active blobs &prcl // Perm Gen Roots ); // The root iteration above "consumed" dirty cards in the perm gen. @@ -852,9 +853,11 @@ g1h->set_marking_started(); g1h->rem_set()->prepare_for_younger_refs_iterate(false); - g1h->process_strong_roots(false, // fake perm gen collection + g1h->process_strong_roots(true, // activate StrongRootsScope + false, // fake perm gen collection SharedHeap::SO_AllClasses, ¬Older, // Regular roots + NULL, // do not visit active blobs &older // Perm Gen Roots ); checkpointRootsInitialPost(); @@ -1915,7 +1918,7 @@ g1h->ensure_parsability(false); if (ParallelGCThreads > 0) { - g1h->change_strong_roots_parity(); + G1CollectedHeap::StrongRootsScope srs(g1h); // this is remark, so we'll use up all available threads int active_workers = ParallelGCThreads; set_phase(active_workers, false); @@ -1932,7 +1935,7 @@ SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); guarantee( satb_mq_set.completed_buffers_num() == 0, "invariant" ); } else { - g1h->change_strong_roots_parity(); + G1CollectedHeap::StrongRootsScope srs(g1h); // this is remark, so we'll use up all available threads int active_workers = 1; set_phase(active_workers, false); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/g1/concurrentZFThread.cpp --- a/src/share/vm/gc_implementation/g1/concurrentZFThread.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/g1/concurrentZFThread.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -2300,9 +2300,12 @@ if (SafepointSynchronize::is_at_safepoint() || ! UseTLAB) { if (!silent) { gclog_or_tty->print("roots "); } VerifyRootsClosure rootsCl(use_prev_marking); - process_strong_roots(false, + CodeBlobToOopClosure blobsCl(&rootsCl, /*do_marking=*/ false); + process_strong_roots(true, // activate StrongRootsScope + false, SharedHeap::SO_AllClasses, &rootsCl, + &blobsCl, &rootsCl); rem_set()->invalidate(perm_gen()->used_region(), false); if (!silent) { gclog_or_tty->print("heapRegions "); } @@ -3987,8 +3990,14 @@ BufferingOopsInGenClosure buf_scan_perm(scan_perm); buf_scan_perm.set_generation(perm_gen()); - process_strong_roots(collecting_perm_gen, so, + // Walk the code cache w/o buffering, because StarTask cannot handle + // unaligned oop locations. + CodeBlobToOopClosure eager_scan_code_roots(scan_non_heap_roots, /*do_marking=*/ true); + + process_strong_roots(false, // no scoping; this is parallel code + collecting_perm_gen, so, &buf_scan_non_heap_roots, + &eager_scan_code_roots, &buf_scan_perm); // Finish up any enqueued closure apps. buf_scan_non_heap_roots.done(); @@ -4078,7 +4087,8 @@ void G1CollectedHeap::g1_process_weak_roots(OopClosure* root_closure, OopClosure* non_root_closure) { - SharedHeap::process_weak_roots(root_closure, non_root_closure); + CodeBlobToOopClosure roots_in_blobs(root_closure, /*do_marking=*/ false); + SharedHeap::process_weak_roots(root_closure, &roots_in_blobs, non_root_closure); } @@ -4112,15 +4122,16 @@ init_for_evac_failure(NULL); - change_strong_roots_parity(); // In preparation for parallel strong roots. rem_set()->prepare_for_younger_refs_iterate(true); assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty"); double start_par = os::elapsedTime(); if (ParallelGCThreads > 0) { // The individual threads will set their evac-failure closures. + StrongRootsScope srs(this); workers()->run_task(&g1_par_task); } else { + StrongRootsScope srs(this); g1_par_task.work(0); } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/g1/g1MMUTracker.cpp --- a/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -121,9 +121,11 @@ SharedHeap* sh = SharedHeap::heap(); - sh->process_strong_roots(true, // Collecting permanent generation. + sh->process_strong_roots(true, // activeate StrongRootsScope + true, // Collecting permanent generation. SharedHeap::SO_SystemClasses, &GenMarkSweep::follow_root_closure, + &GenMarkSweep::follow_code_root_closure, &GenMarkSweep::follow_root_closure); // Process reference objects found during marking @@ -286,9 +288,11 @@ SharedHeap* sh = SharedHeap::heap(); - sh->process_strong_roots(true, // Collecting permanent generation. + sh->process_strong_roots(true, // activate StrongRootsScope + true, // Collecting permanent generation. SharedHeap::SO_AllClasses, &GenMarkSweep::adjust_root_pointer_closure, + NULL, // do not touch code cache here &GenMarkSweep::adjust_pointer_closure); g1h->ref_processor()->weak_oops_do(&GenMarkSweep::adjust_root_pointer_closure); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/includeDB_gc_parallelScavenge --- a/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/includeDB_gc_parallelScavenge Wed Oct 14 12:40:20 2009 -0700 @@ -373,6 +373,7 @@ psScavenge.inline.hpp psPromotionManager.hpp psScavenge.inline.hpp psScavenge.hpp +pcTasks.cpp codeCache.hpp pcTasks.cpp collectedHeap.hpp pcTasks.cpp fprofiler.hpp pcTasks.cpp jniHandles.hpp @@ -392,6 +393,7 @@ pcTasks.hpp psTasks.hpp psTasks.cpp cardTableExtension.hpp +psTasks.cpp codeCache.hpp psTasks.cpp fprofiler.hpp psTasks.cpp gcTaskManager.hpp psTasks.cpp iterator.hpp diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parNew/parNewGeneration.cpp --- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -480,12 +480,14 @@ par_scan_state.start_strong_roots(); gch->gen_process_strong_roots(_gen->level(), - true, // Process younger gens, if any, - // as strong roots. - false,// not collecting perm generation. + true, // Process younger gens, if any, + // as strong roots. + false, // no scope; this is parallel code + false, // not collecting perm generation. SharedHeap::SO_AllClasses, - &par_scan_state.older_gen_closure(), - &par_scan_state.to_space_root_closure()); + &par_scan_state.to_space_root_closure(), + true, // walk *all* scavengable nmethods + &par_scan_state.older_gen_closure()); par_scan_state.end_strong_roots(); // "evacuate followers". @@ -799,15 +801,16 @@ ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set); int n_workers = workers->total_workers(); gch->set_par_threads(n_workers); - gch->change_strong_roots_parity(); gch->rem_set()->prepare_for_younger_refs_iterate(true); // It turns out that even when we're using 1 thread, doing the work in a // separate thread causes wide variance in run times. We can't help this // in the multi-threaded case, but we special-case n=1 here to get // repeatable measurements of the 1-thread overhead of the parallel code. if (n_workers > 1) { + GenCollectedHeap::StrongRootsScope srs(gch); workers->run_task(&tsk); } else { + GenCollectedHeap::StrongRootsScope srs(gch); tsk.work(0); } thread_state_set.reset(); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -962,6 +962,14 @@ _old_gen->resize(desired_free_space); } +ParallelScavengeHeap::ParStrongRootsScope::ParStrongRootsScope() { + // nothing particular +} + +ParallelScavengeHeap::ParStrongRootsScope::~ParStrongRootsScope() { + // nothing particular +} + #ifndef PRODUCT void ParallelScavengeHeap::record_gen_tops_before_GC() { if (ZapUnusedHeapArea) { diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -234,6 +234,13 @@ // Mangle the unused parts of all spaces in the heap void gen_mangle_unused_area() PRODUCT_RETURN; + + // Call these in sequential code around the processing of strong roots. + class ParStrongRootsScope : public MarkingCodeBlobClosure::MarkScope { + public: + ParStrongRootsScope(); + ~ParStrongRootsScope(); + }; }; inline size_t ParallelScavengeHeap::set_alignment(size_t& var, size_t val) diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. 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 @@ -39,12 +39,13 @@ ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(which); PSParallelCompact::MarkAndPushClosure mark_and_push_closure(cm); + CodeBlobToOopClosure mark_and_push_in_blobs(&mark_and_push_closure, /*do_marking=*/ true); if (_java_thread != NULL) - _java_thread->oops_do(&mark_and_push_closure); + _java_thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs); if (_vm_thread != NULL) - _vm_thread->oops_do(&mark_and_push_closure); + _vm_thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs); // Do the real work cm->drain_marking_stacks(&mark_and_push_closure); @@ -78,7 +79,8 @@ case threads: { ResourceMark rm; - Threads::oops_do(&mark_and_push_closure); + CodeBlobToOopClosure each_active_code_blob(&mark_and_push_closure, /*do_marking=*/ true); + Threads::oops_do(&mark_and_push_closure, &each_active_code_blob); } break; @@ -106,6 +108,11 @@ vmSymbols::oops_do(&mark_and_push_closure); break; + case code_cache: + // Do not treat nmethods as strong roots for mark/sweep, since we can unload them. + //CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure(&mark_and_push_closure)); + break; + default: fatal("Unknown root type"); } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/pcTasks.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -92,7 +92,8 @@ jvmti = 7, system_dictionary = 8, vm_symbols = 9, - reference_processing = 10 + reference_processing = 10, + code_cache = 11 }; private: RootType _root_type; diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/psCompactionManager.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -511,16 +511,22 @@ assert(heap->kind() == CollectedHeap::ParallelScavengeHeap, "Sanity"); // General strong roots. - Universe::oops_do(mark_and_push_closure()); - ReferenceProcessor::oops_do(mark_and_push_closure()); - JNIHandles::oops_do(mark_and_push_closure()); // Global (strong) JNI handles - Threads::oops_do(mark_and_push_closure()); - ObjectSynchronizer::oops_do(mark_and_push_closure()); - FlatProfiler::oops_do(mark_and_push_closure()); - Management::oops_do(mark_and_push_closure()); - JvmtiExport::oops_do(mark_and_push_closure()); - SystemDictionary::always_strong_oops_do(mark_and_push_closure()); - vmSymbols::oops_do(mark_and_push_closure()); + { + ParallelScavengeHeap::ParStrongRootsScope psrs; + Universe::oops_do(mark_and_push_closure()); + ReferenceProcessor::oops_do(mark_and_push_closure()); + JNIHandles::oops_do(mark_and_push_closure()); // Global (strong) JNI handles + CodeBlobToOopClosure each_active_code_blob(mark_and_push_closure(), /*do_marking=*/ true); + Threads::oops_do(mark_and_push_closure(), &each_active_code_blob); + ObjectSynchronizer::oops_do(mark_and_push_closure()); + FlatProfiler::oops_do(mark_and_push_closure()); + Management::oops_do(mark_and_push_closure()); + JvmtiExport::oops_do(mark_and_push_closure()); + SystemDictionary::always_strong_oops_do(mark_and_push_closure()); + vmSymbols::oops_do(mark_and_push_closure()); + // Do not treat nmethods as strong roots for mark/sweep, since we can unload them. + //CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure(mark_and_push_closure())); + } // Flush marking stack. follow_stack(); @@ -617,7 +623,7 @@ Universe::oops_do(adjust_root_pointer_closure()); ReferenceProcessor::oops_do(adjust_root_pointer_closure()); JNIHandles::oops_do(adjust_root_pointer_closure()); // Global (strong) JNI handles - Threads::oops_do(adjust_root_pointer_closure()); + Threads::oops_do(adjust_root_pointer_closure(), NULL); ObjectSynchronizer::oops_do(adjust_root_pointer_closure()); FlatProfiler::oops_do(adjust_root_pointer_closure()); Management::oops_do(adjust_root_pointer_closure()); @@ -625,6 +631,7 @@ // SO_AllClasses SystemDictionary::oops_do(adjust_root_pointer_closure()); vmSymbols::oops_do(adjust_root_pointer_closure()); + //CodeCache::scavenge_root_nmethods_oops_do(adjust_root_pointer_closure()); // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -2322,6 +2322,7 @@ { TraceTime tm_m("par mark", print_phases(), true, gclog_or_tty); + ParallelScavengeHeap::ParStrongRootsScope psrs; GCTaskQueue* q = GCTaskQueue::create(); @@ -2335,6 +2336,7 @@ q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::system_dictionary)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::jvmti)); q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::vm_symbols)); + q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::code_cache)); if (parallel_gc_threads > 1) { for (uint j = 0; j < parallel_gc_threads; j++) { @@ -2408,7 +2410,7 @@ Universe::oops_do(adjust_root_pointer_closure()); ReferenceProcessor::oops_do(adjust_root_pointer_closure()); JNIHandles::oops_do(adjust_root_pointer_closure()); // Global (strong) JNI handles - Threads::oops_do(adjust_root_pointer_closure()); + Threads::oops_do(adjust_root_pointer_closure(), NULL); ObjectSynchronizer::oops_do(adjust_root_pointer_closure()); FlatProfiler::oops_do(adjust_root_pointer_closure()); Management::oops_do(adjust_root_pointer_closure()); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -799,8 +799,7 @@ FollowRootClosure(ParCompactionManager* cm) : _compaction_manager(cm) { } virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - virtual const bool do_nmethods() const { return true; } - }; + }; class FollowStackClosure: public VoidClosure { private: @@ -817,6 +816,8 @@ AdjustPointerClosure(bool is_root) : _is_root(is_root) { } virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); + // do not walk from thread stacks to the code cache on this phase + virtual void do_code_blob(CodeBlob* cb) const { } }; // Closure for verifying update of pointers. Does not @@ -1063,7 +1064,6 @@ MarkAndPushClosure(ParCompactionManager* cm) : _compaction_manager(cm) { } virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - virtual const bool do_nmethods() const { return true; } }; PSParallelCompact(); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -358,6 +358,7 @@ PSPromotionManager* promotion_manager = PSPromotionManager::vm_thread_promotion_manager(); { // TraceTime("Roots"); + ParallelScavengeHeap::ParStrongRootsScope psrs; GCTaskQueue* q = GCTaskQueue::create(); @@ -376,6 +377,7 @@ q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::management)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::system_dictionary)); q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::jvmti)); + q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::code_cache)); ParallelTaskTerminator terminator( gc_task_manager()->workers(), diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/psTasks.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -66,7 +66,7 @@ case threads: { ResourceMark rm; - Threads::oops_do(&roots_closure); + Threads::oops_do(&roots_closure, NULL); } break; @@ -90,6 +90,14 @@ JvmtiExport::oops_do(&roots_closure); break; + + case code_cache: + { + CodeBlobToOopClosure each_scavengable_code_blob(&roots_closure, /*do_marking=*/ true); + CodeCache::scavenge_root_nmethods_do(&each_scavengable_code_blob); + } + break; + default: fatal("Unknown root type"); } @@ -107,12 +115,13 @@ PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(which); PSScavengeRootsClosure roots_closure(pm); + CodeBlobToOopClosure roots_in_blobs(&roots_closure, /*do_marking=*/ true); if (_java_thread != NULL) - _java_thread->oops_do(&roots_closure); + _java_thread->oops_do(&roots_closure, &roots_in_blobs); if (_vm_thread != NULL) - _vm_thread->oops_do(&roots_closure); + _vm_thread->oops_do(&roots_closure, &roots_in_blobs); // Do the real work pm->drain_stacks(false); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/parallelScavenge/psTasks.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -54,7 +54,8 @@ flat_profiler = 5, system_dictionary = 6, management = 7, - jvmti = 8 + jvmti = 8, + code_cache = 9 }; private: RootType _root_type; diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/shared/markSweep.cpp --- a/src/share/vm/gc_implementation/shared/markSweep.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/shared/markSweep.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -93,6 +93,7 @@ } MarkSweep::FollowRootClosure MarkSweep::follow_root_closure; +CodeBlobToOopClosure MarkSweep::follow_code_root_closure(&MarkSweep::follow_root_closure, /*do_marking=*/ true); void MarkSweep::FollowRootClosure::do_oop(oop* p) { follow_root(p); } void MarkSweep::FollowRootClosure::do_oop(narrowOop* p) { follow_root(p); } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_implementation/shared/markSweep.hpp --- a/src/share/vm/gc_implementation/shared/markSweep.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_implementation/shared/markSweep.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -58,14 +58,12 @@ public: virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - virtual const bool do_nmethods() const { return true; } }; class MarkAndPushClosure: public OopClosure { public: virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - virtual const bool do_nmethods() const { return true; } virtual const bool should_remember_mdo() const { return true; } virtual void remember_mdo(DataLayout* p) { MarkSweep::revisit_mdo(p); } }; @@ -173,6 +171,7 @@ public: // Public closures static FollowRootClosure follow_root_closure; + static CodeBlobToOopClosure follow_code_root_closure; // => follow_root_closure static MarkAndPushClosure mark_and_push_closure; static FollowStackClosure follow_stack_closure; static AdjustPointerClosure adjust_root_pointer_closure; diff -r 054afbef9081 -r a2ad635573fb src/share/vm/gc_interface/collectedHeap.hpp --- a/src/share/vm/gc_interface/collectedHeap.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/gc_interface/collectedHeap.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -263,6 +263,14 @@ return p == NULL || is_permanent(p); } + // An object is scavengable if its location may move during a scavenge. + // (A scavenge is a GC which is not a full GC.) + // Currently, this just means it is not perm (and not null). + // This could change if we rethink what's in perm-gen. + bool is_scavengable(const void *p) const { + return !is_in_permanent_or_null(p); + } + // Returns "TRUE" if "p" is a method oop in the // current heap, with high probability. This predicate // is not stable, in general. diff -r 054afbef9081 -r a2ad635573fb src/share/vm/memory/defNewGeneration.cpp --- a/src/share/vm/memory/defNewGeneration.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/memory/defNewGeneration.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -555,12 +555,14 @@ "save marks have not been newly set."); gch->gen_process_strong_roots(_level, - true, // Process younger gens, if any, as - // strong roots. - false,// not collecting permanent generation. + true, // Process younger gens, if any, + // as strong roots. + true, // activate StrongRootsScope + false, // not collecting perm generation. SharedHeap::SO_AllClasses, - &fsc_with_gc_barrier, - &fsc_with_no_gc_barrier); + &fsc_with_no_gc_barrier, + true, // walk *all* scavengable nmethods + &fsc_with_gc_barrier); // "evacuate followers". evacuate_followers.do_void(); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/memory/genCollectedHeap.cpp --- a/src/share/vm/memory/genCollectedHeap.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/memory/genCollectedHeap.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -677,13 +677,23 @@ void GenCollectedHeap:: gen_process_strong_roots(int level, bool younger_gens_as_roots, + bool activate_scope, bool collecting_perm_gen, SharedHeap::ScanningOption so, - OopsInGenClosure* older_gens, - OopsInGenClosure* not_older_gens) { + OopsInGenClosure* not_older_gens, + bool do_code_roots, + OopsInGenClosure* older_gens) { // General strong roots. - SharedHeap::process_strong_roots(collecting_perm_gen, so, - not_older_gens, older_gens); + + if (!do_code_roots) { + SharedHeap::process_strong_roots(activate_scope, collecting_perm_gen, so, + not_older_gens, NULL, older_gens); + } else { + bool do_code_marking = (activate_scope || nmethod::oops_do_marking_is_active()); + CodeBlobToOopClosure code_roots(not_older_gens, /*do_marking=*/ do_code_marking); + SharedHeap::process_strong_roots(activate_scope, collecting_perm_gen, so, + not_older_gens, &code_roots, older_gens); + } if (younger_gens_as_roots) { if (!_gen_process_strong_tasks->is_task_claimed(GCH_PS_younger_gens)) { @@ -706,8 +716,9 @@ } void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure, + CodeBlobClosure* code_roots, OopClosure* non_root_closure) { - SharedHeap::process_weak_roots(root_closure, non_root_closure); + SharedHeap::process_weak_roots(root_closure, code_roots, non_root_closure); // "Local" "weak" refs for (int i = 0; i < _n_gens; i++) { _gens[i]->ref_processor()->weak_oops_do(root_closure); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/memory/genCollectedHeap.hpp --- a/src/share/vm/memory/genCollectedHeap.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/memory/genCollectedHeap.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -408,16 +408,22 @@ // "SO_SystemClasses" to all the "system" classes and loaders; // "SO_Symbols_and_Strings" applies the closure to all entries in // SymbolsTable and StringTable. - void gen_process_strong_roots(int level, bool younger_gens_as_roots, + void gen_process_strong_roots(int level, + bool younger_gens_as_roots, + // The remaining arguments are in an order + // consistent with SharedHeap::process_strong_roots: + bool activate_scope, bool collecting_perm_gen, SharedHeap::ScanningOption so, - OopsInGenClosure* older_gens, - OopsInGenClosure* not_older_gens); + OopsInGenClosure* not_older_gens, + bool do_code_roots, + OopsInGenClosure* older_gens); // Apply "blk" to all the weak roots of the system. These include // JNI weak roots, the code cache, system dictionary, symbol table, // string table, and referents of reachable weak refs. void gen_process_weak_roots(OopClosure* root_closure, + CodeBlobClosure* code_roots, OopClosure* non_root_closure); // Set the saved marks of generations, if that makes sense. diff -r 054afbef9081 -r a2ad635573fb src/share/vm/memory/genMarkSweep.cpp --- a/src/share/vm/memory/genMarkSweep.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/memory/genMarkSweep.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. 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 @@ -244,9 +244,12 @@ gch->gen_process_strong_roots(level, false, // Younger gens are not roots. + true, // activate StrongRootsScope true, // Collecting permanent generation. SharedHeap::SO_SystemClasses, - &follow_root_closure, &follow_root_closure); + &follow_root_closure, + true, // walk code active on stacks + &follow_root_closure); // Process reference objects found during marking { @@ -338,14 +341,19 @@ gch->gen_process_strong_roots(level, false, // Younger gens are not roots. + true, // activate StrongRootsScope true, // Collecting permanent generation. SharedHeap::SO_AllClasses, &adjust_root_pointer_closure, + false, // do not walk code &adjust_root_pointer_closure); // Now adjust pointers in remaining weak roots. (All of which should // have been cleared if they pointed to non-surviving objects.) + CodeBlobToOopClosure adjust_code_pointer_closure(&adjust_pointer_closure, + /*do_marking=*/ false); gch->gen_process_weak_roots(&adjust_root_pointer_closure, + &adjust_code_pointer_closure, &adjust_pointer_closure); adjust_marks(); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/memory/iterator.cpp --- a/src/share/vm/memory/iterator.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/memory/iterator.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2001 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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,3 +46,42 @@ } #endif + +MarkingCodeBlobClosure::MarkScope::MarkScope(bool activate) + : _active(activate) +{ + if (_active) nmethod::oops_do_marking_prologue(); +} + +MarkingCodeBlobClosure::MarkScope::~MarkScope() { + if (_active) nmethod::oops_do_marking_epilogue(); +} + +void MarkingCodeBlobClosure::do_code_blob(CodeBlob* cb) { + if (!cb->is_nmethod()) return; + nmethod* nm = (nmethod*) cb; + if (!nm->test_set_oops_do_mark()) { + NOT_PRODUCT(if (TraceScavenge) nm->print_on(tty, "oops_do, 1st visit\n")); + do_newly_marked_nmethod(nm); + } else { + NOT_PRODUCT(if (TraceScavenge) nm->print_on(tty, "oops_do, skipped on 2nd visit\n")); + } +} + +void CodeBlobToOopClosure::do_newly_marked_nmethod(nmethod* nm) { + nm->oops_do(_cl, /*do_strong_roots_only=*/ true); +} + +void CodeBlobToOopClosure::do_code_blob(CodeBlob* cb) { + if (!_do_marking) { + NOT_PRODUCT(if (TraceScavenge && Verbose && cb->is_nmethod()) ((nmethod*)cb)->print_on(tty, "oops_do, unmarked visit\n")); + // This assert won't work, since there are lots of mini-passes + // (mostly in debug mode) that co-exist with marking phases. + //assert(!(cb->is_nmethod() && ((nmethod*)cb)->test_oops_do_mark()), "found marked nmethod during mark-free phase"); + cb->oops_do(_cl); + } else { + MarkingCodeBlobClosure::do_code_blob(cb); + } +} + + diff -r 054afbef9081 -r a2ad635573fb src/share/vm/memory/iterator.hpp --- a/src/share/vm/memory/iterator.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/memory/iterator.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 @@ -24,6 +24,8 @@ // The following classes are C++ `closures` for iterating over objects, roots and spaces +class CodeBlob; +class nmethod; class ReferenceProcessor; class DataLayout; @@ -69,9 +71,6 @@ virtual const bool should_remember_mdo() const { return false; } virtual void remember_mdo(DataLayout* v) { /* do nothing */ } - // If "true", invoke on nmethods (when scanning compiled frames). - virtual const bool do_nmethods() const { return false; } - // The methods below control how object iterations invoking this closure // should be performed: @@ -176,6 +175,51 @@ }; +// CodeBlobClosure is used for iterating through code blobs +// in the code cache or on thread stacks + +class CodeBlobClosure : public Closure { + public: + // Called for each code blob. + virtual void do_code_blob(CodeBlob* cb) = 0; +}; + + +class MarkingCodeBlobClosure : public CodeBlobClosure { + public: + // Called for each code blob, but at most once per unique blob. + virtual void do_newly_marked_nmethod(nmethod* nm) = 0; + + virtual void do_code_blob(CodeBlob* cb); + // = { if (!nmethod(cb)->test_set_oops_do_mark()) do_newly_marked_nmethod(cb); } + + class MarkScope : public StackObj { + protected: + bool _active; + public: + MarkScope(bool activate = true); + // = { if (active) nmethod::oops_do_marking_prologue(); } + ~MarkScope(); + // = { if (active) nmethod::oops_do_marking_epilogue(); } + }; +}; + + +// Applies an oop closure to all ref fields in code blobs +// iterated over in an object iteration. +class CodeBlobToOopClosure: public MarkingCodeBlobClosure { + OopClosure* _cl; + bool _do_marking; +public: + virtual void do_newly_marked_nmethod(nmethod* cb); + // = { cb->oops_do(_cl); } + virtual void do_code_blob(CodeBlob* cb); + // = { if (_do_marking) super::do_code_blob(cb); else cb->oops_do(_cl); } + CodeBlobToOopClosure(OopClosure* cl, bool do_marking) + : _cl(cl), _do_marking(do_marking) {} +}; + + // MonitorClosure is used for iterating over monitors in the monitors cache diff -r 054afbef9081 -r a2ad635573fb src/share/vm/memory/serialize.cpp --- a/src/share/vm/memory/serialize.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/memory/serialize.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/memory/sharedHeap.cpp --- a/src/share/vm/memory/sharedHeap.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/memory/sharedHeap.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -100,12 +100,27 @@ "Not in range."); } -void SharedHeap::process_strong_roots(bool collecting_perm_gen, +SharedHeap::StrongRootsScope::StrongRootsScope(SharedHeap* outer, bool activate) + : MarkScope(activate) +{ + if (_active) { + outer->change_strong_roots_parity(); + } +} + +SharedHeap::StrongRootsScope::~StrongRootsScope() { + // nothing particular +} + +void SharedHeap::process_strong_roots(bool activate_scope, + bool collecting_perm_gen, ScanningOption so, OopClosure* roots, + CodeBlobClosure* code_roots, OopsInGenClosure* perm_blk) { + StrongRootsScope srs(this, activate_scope); // General strong roots. - if (n_par_threads() == 0) change_strong_roots_parity(); + assert(_strong_roots_parity != 0, "must have called prologue code"); if (!_process_strong_tasks->is_task_claimed(SH_PS_Universe_oops_do)) { Universe::oops_do(roots); ReferenceProcessor::oops_do(roots); @@ -117,9 +132,9 @@ JNIHandles::oops_do(roots); // All threads execute this; the individual threads are task groups. if (ParallelGCThreads > 0) { - Threads::possibly_parallel_oops_do(roots); + Threads::possibly_parallel_oops_do(roots, code_roots); } else { - Threads::oops_do(roots); + Threads::oops_do(roots, code_roots); } if (!_process_strong_tasks-> is_task_claimed(SH_PS_ObjectSynchronizer_oops_do)) ObjectSynchronizer::oops_do(roots); @@ -156,11 +171,29 @@ } if (!_process_strong_tasks->is_task_claimed(SH_PS_CodeCache_oops_do)) { - if (so & SO_CodeCache) { - CodeCache::oops_do(roots); - } + if (so & SO_CodeCache) { + // (Currently, CMSCollector uses this to do intermediate-strength collections.) + assert(collecting_perm_gen, "scanning all of code cache"); + assert(code_roots != NULL, "must supply closure for code cache"); + if (code_roots != NULL) { + CodeCache::blobs_do(code_roots); + } + } else if (so & (SO_SystemClasses|SO_AllClasses)) { + if (!collecting_perm_gen) { + // If we are collecting from class statics, but we are not going to + // visit all of the CodeCache, collect from the non-perm roots if any. + // This makes the code cache function temporarily as a source of strong + // roots for oops, until the next major collection. + // + // If collecting_perm_gen is true, we require that this phase will call + // CodeCache::do_unloading. This will kill off nmethods with expired + // weak references, such as stale invokedynamic targets. + CodeCache::scavenge_root_nmethods_do(code_roots); + } + } // Verify if the code cache contents are in the perm gen - NOT_PRODUCT(CodeCache::oops_do(&assert_is_perm_closure)); + NOT_PRODUCT(CodeBlobToOopClosure assert_code_is_perm(&assert_is_perm_closure, /*do_marking=*/ false)); + NOT_PRODUCT(CodeCache::asserted_non_scavengable_nmethods_do(&assert_code_is_perm)); } // Roots that should point only into permanent generation. @@ -220,11 +253,12 @@ // just skip adjusting any shared entries in the string table. void SharedHeap::process_weak_roots(OopClosure* root_closure, + CodeBlobClosure* code_roots, OopClosure* non_root_closure) { // Global (weak) JNI handles JNIHandles::weak_oops_do(&always_true, root_closure); - CodeCache::oops_do(non_root_closure); + CodeCache::blobs_do(code_roots); SymbolTable::oops_do(root_closure); if (UseSharedSpaces && !DumpSharedSpaces) { SkipAdjustingSharedStrings skip_closure(root_closure); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/memory/sharedHeap.hpp --- a/src/share/vm/memory/sharedHeap.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/memory/sharedHeap.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -165,9 +165,21 @@ // c) to never return a distinguished value (zero) with which such // task-claiming variables may be initialized, to indicate "never // claimed". + private: void change_strong_roots_parity(); + public: int strong_roots_parity() { return _strong_roots_parity; } + // Call these in sequential code around process_strong_roots. + // strong_roots_prologue calls change_strong_roots_parity, if + // parallel tasks are enabled. + class StrongRootsScope : public MarkingCodeBlobClosure::MarkScope { + public: + StrongRootsScope(SharedHeap* outer, bool activate = true); + ~StrongRootsScope(); + }; + friend class StrongRootsScope; + enum ScanningOption { SO_None = 0x0, SO_AllClasses = 0x1, @@ -198,15 +210,18 @@ // "SO_Symbols" applies the closure to all entries in SymbolsTable; // "SO_Strings" applies the closure to all entries in StringTable; // "SO_CodeCache" applies the closure to all elements of the CodeCache. - void process_strong_roots(bool collecting_perm_gen, + void process_strong_roots(bool activate_scope, + bool collecting_perm_gen, ScanningOption so, OopClosure* roots, + CodeBlobClosure* code_roots, OopsInGenClosure* perm_blk); // Apply "blk" to all the weak roots of the system. These include // JNI weak roots, the code cache, system dictionary, symbol table, // string table. void process_weak_roots(OopClosure* root_closure, + CodeBlobClosure* code_roots, OopClosure* non_root_closure); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/oops/arrayKlass.cpp --- a/src/share/vm/oops/arrayKlass.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/oops/arrayKlass.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/oops/instanceKlass.cpp --- a/src/share/vm/oops/instanceKlass.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/oops/instanceKlass.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -2152,7 +2152,7 @@ // This is a short non-blocking critical region, so the no safepoint check is ok. OsrList_lock->lock_without_safepoint_check(); assert(n->is_osr_method(), "wrong kind of nmethod"); - n->set_link(osr_nmethods_head()); + n->set_osr_link(osr_nmethods_head()); set_osr_nmethods_head(n); // Remember to unlock again OsrList_lock->unlock(); @@ -2168,17 +2168,17 @@ // Search for match while(cur != NULL && cur != n) { last = cur; - cur = cur->link(); + cur = cur->osr_link(); } if (cur == n) { if (last == NULL) { // Remove first element - set_osr_nmethods_head(osr_nmethods_head()->link()); + set_osr_nmethods_head(osr_nmethods_head()->osr_link()); } else { - last->set_link(cur->link()); + last->set_osr_link(cur->osr_link()); } } - n->set_link(NULL); + n->set_osr_link(NULL); // Remember to unlock again OsrList_lock->unlock(); } @@ -2195,7 +2195,7 @@ OsrList_lock->unlock(); return osr; } - osr = osr->link(); + osr = osr->osr_link(); } OsrList_lock->unlock(); return NULL; diff -r 054afbef9081 -r a2ad635573fb src/share/vm/oops/instanceKlassKlass.hpp --- a/src/share/vm/oops/instanceKlassKlass.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/oops/instanceKlassKlass.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/oops/instanceRefKlass.cpp --- a/src/share/vm/oops/instanceRefKlass.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/oops/instanceRefKlass.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/oops/methodDataOop.hpp --- a/src/share/vm/oops/methodDataOop.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/oops/methodDataOop.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/oops/objArrayOop.hpp --- a/src/share/vm/oops/objArrayOop.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/oops/objArrayOop.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/oops/oop.hpp --- a/src/share/vm/oops/oop.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/oops/oop.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -330,6 +330,7 @@ bool is_perm() const; bool is_perm_or_null() const; + bool is_scavengable() const; bool is_shared() const; bool is_shared_readonly() const; bool is_shared_readwrite() const; diff -r 054afbef9081 -r a2ad635573fb src/share/vm/oops/oop.inline2.hpp --- a/src/share/vm/oops/oop.inline2.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/oops/oop.inline2.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -34,3 +34,7 @@ inline bool oopDesc::is_perm_or_null() const { return this == NULL || is_perm(); } + +inline bool oopDesc::is_scavengable() const { + return Universe::heap()->is_scavengable(this); +} diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/compile.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/connode.cpp --- a/src/share/vm/opto/connode.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/connode.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1085,6 +1085,9 @@ switch (op) { case Op_SubX: x = in(1)->in(1); + // Avoid ideal transformations ping-pong between this and AddP for raw pointers. + if (phase->find_intptr_t_con(x, -1) == 0) + break; y = in(1)->in(2); if (fits_in_int(phase->type(y), true)) { return addP_of_X2P(phase, x, y, true); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/escape.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -524,12 +524,15 @@ // inlining) which was not eliminated during parsing since the exactness // of the allocation type was not propagated to the subclass type check. // + // Or the type 't' could be not related to 'base_t' at all. + // It could happened when CHA type is different from MDO type on a dead path + // (for example, from instanceof check) which is not collapsed during parsing. + // // Do nothing for such AddP node and don't process its users since // this code branch will go away. // if (!t->is_known_instance() && - !t->klass()->equals(base_t->klass()) && - t->klass()->is_subtype_of(base_t->klass())) { + !base_t->klass()->is_subtype_of(t->klass())) { return false; // bail out } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/graphKit.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1450,7 +1450,7 @@ case BarrierSet::CardTableModRef: case BarrierSet::CardTableExtension: - write_barrier_post(store, obj, adr, val, use_precise); + write_barrier_post(store, obj, adr, adr_idx, val, use_precise); break; case BarrierSet::ModRef: @@ -3165,6 +3165,7 @@ void GraphKit::write_barrier_post(Node* oop_store, Node* obj, Node* adr, + uint adr_idx, Node* val, bool use_precise) { // No store check needed if we're storing a NULL or an old object @@ -3214,7 +3215,7 @@ __ store(__ ctrl(), card_adr, zero, bt, adr_type); } else { // Specialized path for CM store barrier - __ storeCM(__ ctrl(), card_adr, zero, oop_store, bt, adr_type); + __ storeCM(__ ctrl(), card_adr, zero, oop_store, adr_idx, bt, adr_type); } // Final sync IdealKit and GraphKit. @@ -3314,6 +3315,7 @@ void GraphKit::g1_mark_card(IdealKit& ideal, Node* card_adr, Node* oop_store, + uint oop_alias_idx, Node* index, Node* index_adr, Node* buffer, @@ -3323,7 +3325,7 @@ Node* no_base = __ top(); BasicType card_bt = T_BYTE; // Smash zero into card. MUST BE ORDERED WRT TO STORE - __ storeCM(__ ctrl(), card_adr, zero, oop_store, card_bt, Compile::AliasIdxRaw); + __ storeCM(__ ctrl(), card_adr, zero, oop_store, oop_alias_idx, card_bt, Compile::AliasIdxRaw); // Now do the queue work __ if_then(index, BoolTest::ne, zero); { @@ -3435,13 +3437,13 @@ Node* card_val = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); __ if_then(card_val, BoolTest::ne, zero); { - g1_mark_card(ideal, card_adr, oop_store, index, index_adr, buffer, tf); + g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); } __ end_if(); } __ end_if(); } __ end_if(); } else { // Object.clone() instrinsic uses this path. - g1_mark_card(ideal, card_adr, oop_store, index, index_adr, buffer, tf); + g1_mark_card(ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); } // Final sync IdealKit and GraphKit. diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/graphKit.hpp --- a/src/share/vm/opto/graphKit.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/graphKit.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -603,7 +603,8 @@ void sync_kit(IdealKit& ideal); // vanilla/CMS post barrier - void write_barrier_post(Node *store, Node* obj, Node* adr, Node* val, bool use_precise); + void write_barrier_post(Node *store, Node* obj, + Node* adr, uint adr_idx, Node* val, bool use_precise); // G1 pre/post barriers void g1_write_barrier_pre(Node* obj, @@ -622,7 +623,8 @@ bool use_precise); // Helper function for g1 private: - void g1_mark_card(IdealKit& ideal, Node* card_adr, Node* store, Node* index, Node* index_adr, + void g1_mark_card(IdealKit& ideal, Node* card_adr, Node* store, uint oop_alias_idx, + Node* index, Node* index_adr, Node* buffer, const TypeFunc* tf); public: diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/idealKit.cpp --- a/src/share/vm/opto/idealKit.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/idealKit.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. 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 @@ -378,7 +378,7 @@ // Card mark store. Must be ordered so that it will come after the store of // the oop. -Node* IdealKit::storeCM(Node* ctl, Node* adr, Node *val, Node* oop_store, +Node* IdealKit::storeCM(Node* ctl, Node* adr, Node *val, Node* oop_store, int oop_adr_idx, BasicType bt, int adr_idx) { assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" ); @@ -388,7 +388,7 @@ // Add required edge to oop_store, optimizer does not support precedence edges. // Convert required edge to precedence edge before allocation. - Node* st = new (C, 5) StoreCMNode(ctl, mem, adr, adr_type, val, oop_store); + Node* st = new (C, 5) StoreCMNode(ctl, mem, adr, adr_type, val, oop_store, oop_adr_idx); st = transform(st); set_memory(st, adr_idx); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/idealKit.hpp --- a/src/share/vm/opto/idealKit.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/idealKit.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2005-2009 Sun Microsystems, Inc. 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 @@ -216,6 +216,7 @@ Node* adr, Node* val, Node* oop_store, + int oop_adr_idx, BasicType bt, int adr_idx); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/ifnode.cpp --- a/src/share/vm/opto/ifnode.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/ifnode.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2000-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/library_call.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -133,6 +133,7 @@ return generate_method_call(method_id, true, false); } + Node* make_string_method_node(int opcode, Node* str1, Node* cnt1, Node* str2, Node* cnt2); bool inline_string_compareTo(); bool inline_string_indexOf(); Node* string_indexOf(Node* string_object, ciTypeArray* target_array, jint offset, jint cache_i, jint md2_i); @@ -796,6 +797,64 @@ } +//------------------------------make_string_method_node------------------------ +// Helper method for String intrinsic finctions. +Node* LibraryCallKit::make_string_method_node(int opcode, Node* str1, Node* cnt1, Node* str2, Node* cnt2) { + 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(); + + Node* no_ctrl = NULL; + + ciInstanceKlass* klass = env()->String_klass(); + const TypeInstPtr* string_type = + TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); + + const TypeAryPtr* value_type = + TypeAryPtr::make(TypePtr::NotNull, + TypeAry::make(TypeInt::CHAR,TypeInt::POS), + ciTypeArrayKlass::make(T_CHAR), true, 0); + + // Get start addr of string and substring + Node* str1_valuea = basic_plus_adr(str1, str1, value_offset); + Node* str1_value = make_load(no_ctrl, str1_valuea, value_type, T_OBJECT, string_type->add_offset(value_offset)); + Node* str1_offseta = basic_plus_adr(str1, str1, offset_offset); + Node* str1_offset = make_load(no_ctrl, str1_offseta, TypeInt::INT, T_INT, string_type->add_offset(offset_offset)); + Node* str1_start = array_element_address(str1_value, str1_offset, T_CHAR); + + // Pin loads from String::equals() argument since it could be NULL. + Node* str2_ctrl = (opcode == Op_StrEquals) ? control() : no_ctrl; + Node* str2_valuea = basic_plus_adr(str2, str2, value_offset); + Node* str2_value = make_load(str2_ctrl, str2_valuea, value_type, T_OBJECT, string_type->add_offset(value_offset)); + Node* str2_offseta = basic_plus_adr(str2, str2, offset_offset); + Node* str2_offset = make_load(str2_ctrl, str2_offseta, TypeInt::INT, T_INT, string_type->add_offset(offset_offset)); + Node* str2_start = array_element_address(str2_value, str2_offset, T_CHAR); + + Node* result = NULL; + switch (opcode) { + case Op_StrIndexOf: + result = new (C, 6) StrIndexOfNode(control(), memory(TypeAryPtr::CHARS), + str1_start, cnt1, str2_start, cnt2); + break; + case Op_StrComp: + result = new (C, 6) StrCompNode(control(), memory(TypeAryPtr::CHARS), + str1_start, cnt1, str2_start, cnt2); + break; + case Op_StrEquals: + result = new (C, 5) StrEqualsNode(control(), memory(TypeAryPtr::CHARS), + str1_start, str2_start, cnt1); + break; + default: + ShouldNotReachHere(); + return NULL; + } + + // All these intrinsics have checks. + C->set_has_split_ifs(true); // Has chance for split-if optimization + + return _gvn.transform(result); +} + //------------------------------inline_string_compareTo------------------------ bool LibraryCallKit::inline_string_compareTo() { @@ -824,16 +883,16 @@ ciInstanceKlass* klass = env()->String_klass(); const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); - - Node* compare = - _gvn.transform(new (C, 7) StrCompNode( - control(), - memory(TypeAryPtr::CHARS), - memory(string_type->add_offset(value_offset)), - memory(string_type->add_offset(count_offset)), - memory(string_type->add_offset(offset_offset)), - receiver, - argument)); + Node* no_ctrl = NULL; + + // Get counts for string and argument + Node* receiver_cnta = basic_plus_adr(receiver, receiver, count_offset); + Node* receiver_cnt = make_load(no_ctrl, receiver_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); + + Node* argument_cnta = basic_plus_adr(argument, argument, count_offset); + Node* argument_cnt = make_load(no_ctrl, argument_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); + + Node* compare = make_string_method_node(Op_StrComp, receiver, receiver_cnt, argument, argument_cnt); push(compare); return true; } @@ -865,45 +924,71 @@ return true; } + // paths (plus control) merge + RegionNode* region = new (C, 5) RegionNode(5); + Node* phi = new (C, 5) PhiNode(region, TypeInt::BOOL); + + // does source == target string? + Node* cmp = _gvn.transform(new (C, 3) CmpPNode(receiver, argument)); + Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq)); + + Node* if_eq = generate_slow_guard(bol, NULL); + if (if_eq != NULL) { + // receiver == argument + phi->init_req(2, intcon(1)); + region->init_req(2, if_eq); + } + // get String klass for instanceOf ciInstanceKlass* klass = env()->String_klass(); - // two paths (plus control) merge - RegionNode* region = new (C, 3) RegionNode(3); - Node* phi = new (C, 3) PhiNode(region, TypeInt::BOOL); - - Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass))); - Node* cmp = _gvn.transform(new (C, 3) CmpINode(inst, intcon(1))); - Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq)); - - IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN); - - Node* if_true = _gvn.transform(new (C, 1) IfTrueNode(iff)); - set_control(if_true); + if (!stopped()) { + Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass))); + Node* cmp = _gvn.transform(new (C, 3) CmpINode(inst, intcon(1))); + Node* bol = _gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::ne)); + + Node* inst_false = generate_guard(bol, NULL, PROB_MIN); + //instanceOf == true, fallthrough + + if (inst_false != NULL) { + phi->init_req(3, intcon(0)); + region->init_req(3, inst_false); + } + } const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); - // instanceOf == true - Node* equals = - _gvn.transform(new (C, 7) StrEqualsNode( - control(), - memory(TypeAryPtr::CHARS), - memory(string_type->add_offset(value_offset)), - memory(string_type->add_offset(count_offset)), - memory(string_type->add_offset(offset_offset)), - receiver, - argument)); - - phi->init_req(1, _gvn.transform(equals)); - region->init_req(1, if_true); - - //instanceOf == false, fallthrough - Node* if_false = _gvn.transform(new (C, 1) IfFalseNode(iff)); - set_control(if_false); - - phi->init_req(2, _gvn.transform(intcon(0))); - region->init_req(2, if_false); + Node* no_ctrl = NULL; + Node* receiver_cnt; + Node* argument_cnt; + + if (!stopped()) { + // Get counts for string and argument + Node* receiver_cnta = basic_plus_adr(receiver, receiver, count_offset); + receiver_cnt = make_load(no_ctrl, receiver_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); + + // Pin load from argument string since it could be NULL. + Node* argument_cnta = basic_plus_adr(argument, argument, count_offset); + argument_cnt = make_load(control(), argument_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); + + // Check for receiver count != argument count + Node* cmp = _gvn.transform( new(C, 3) CmpINode(receiver_cnt, argument_cnt) ); + Node* bol = _gvn.transform( new(C, 2) BoolNode(cmp, BoolTest::ne) ); + Node* if_ne = generate_slow_guard(bol, NULL); + if (if_ne != NULL) { + phi->init_req(4, intcon(0)); + region->init_req(4, if_ne); + } + } + + // Check for count == 0 is done by mach node StrEquals. + + if (!stopped()) { + Node* equals = make_string_method_node(Op_StrEquals, receiver, receiver_cnt, argument, argument_cnt); + phi->init_req(1, equals); + region->init_req(1, control()); + } // post merge set_control(_gvn.transform(region)); @@ -924,10 +1009,8 @@ Node *argument1 = pop(); Node* equals = - _gvn.transform(new (C, 3) AryEqNode(control(), - argument1, - argument2) - ); + _gvn.transform(new (C, 4) AryEqNode(control(), memory(TypeAryPtr::CHARS), + argument1, argument2) ); push(equals); return true; } @@ -1108,19 +1191,40 @@ return true; } + // Make the merge point + RegionNode* result_rgn = new (C, 3) RegionNode(3); + Node* result_phi = new (C, 3) PhiNode(result_rgn, TypeInt::INT); + Node* no_ctrl = NULL; + ciInstanceKlass* klass = env()->String_klass(); const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::BotPTR, klass, false, NULL, 0); - result = - _gvn.transform(new (C, 7) - StrIndexOfNode(control(), - memory(TypeAryPtr::CHARS), - memory(string_type->add_offset(value_offset)), - memory(string_type->add_offset(count_offset)), - memory(string_type->add_offset(offset_offset)), - receiver, - argument)); + // Get counts for string and substr + Node* source_cnta = basic_plus_adr(receiver, receiver, count_offset); + Node* source_cnt = make_load(no_ctrl, source_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); + + Node* substr_cnta = basic_plus_adr(argument, argument, count_offset); + Node* substr_cnt = make_load(no_ctrl, substr_cnta, TypeInt::INT, T_INT, string_type->add_offset(count_offset)); + + // Check for substr count > string count + Node* cmp = _gvn.transform( new(C, 3) CmpINode(substr_cnt, source_cnt) ); + Node* bol = _gvn.transform( new(C, 2) BoolNode(cmp, BoolTest::gt) ); + Node* if_gt = generate_slow_guard(bol, NULL); + if (if_gt != NULL) { + result_phi->init_req(2, intcon(-1)); + result_rgn->init_req(2, if_gt); + } + + if (!stopped()) { + result = make_string_method_node(Op_StrIndexOf, receiver, source_cnt, argument, substr_cnt); + result_phi->init_req(1, result); + result_rgn->init_req(1, control()); + } + set_control(_gvn.transform(result_rgn)); + record_for_igvn(result_rgn); + result = _gvn.transform(result_phi); + } else { //Use LibraryCallKit::string_indexOf // don't intrinsify is argument isn't a constant string. if (!argument->is_Con()) { diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/matcher.cpp --- a/src/share/vm/opto/matcher.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/matcher.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -2032,6 +2032,23 @@ n->del_req(3); break; } + case Op_StrEquals: { + Node *pair1 = new (C, 3) BinaryNode(n->in(2),n->in(3)); + n->set_req(2,pair1); + n->set_req(3,n->in(4)); + n->del_req(4); + break; + } + case Op_StrComp: + case Op_StrIndexOf: { + Node *pair1 = new (C, 3) BinaryNode(n->in(2),n->in(3)); + n->set_req(2,pair1); + Node *pair2 = new (C, 3) BinaryNode(n->in(4),n->in(5)); + n->set_req(3,pair2); + n->del_req(5); + n->del_req(4); + break; + } default: break; } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/memnode.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -2313,6 +2313,22 @@ return this; } +//============================================================================= +//------------------------------Ideal--------------------------------------- +Node *StoreCMNode::Ideal(PhaseGVN *phase, bool can_reshape){ + Node* progress = StoreNode::Ideal(phase, can_reshape); + if (progress != NULL) return progress; + + Node* my_store = in(MemNode::OopStore); + if (my_store->is_MergeMem()) { + Node* mem = my_store->as_MergeMem()->memory_at(oop_alias_idx()); + set_req(MemNode::OopStore, mem); + return this; + } + + return NULL; +} + //------------------------------Value----------------------------------------- const Type *StoreCMNode::Value( PhaseTransform *phase ) const { // Either input is TOP ==> the result is TOP @@ -2498,7 +2514,7 @@ //============================================================================= // Do we match on this edge? No memory edges uint StrCompNode::match_edge(uint idx) const { - return idx == 5 || idx == 6; + return idx == 2 || idx == 3; // StrComp (Binary str1 cnt1) (Binary str2 cnt2) } //------------------------------Ideal------------------------------------------ @@ -2508,9 +2524,10 @@ return remove_dead_region(phase, can_reshape) ? this : NULL; } +//============================================================================= // Do we match on this edge? No memory edges uint StrEqualsNode::match_edge(uint idx) const { - return idx == 5 || idx == 6; + return idx == 2 || idx == 3; // StrEquals (Binary str1 str2) cnt } //------------------------------Ideal------------------------------------------ @@ -2523,7 +2540,7 @@ //============================================================================= // Do we match on this edge? No memory edges uint StrIndexOfNode::match_edge(uint idx) const { - return idx == 5 || idx == 6; + return idx == 2 || idx == 3; // StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2) } //------------------------------Ideal------------------------------------------ @@ -2533,6 +2550,11 @@ return remove_dead_region(phase, can_reshape) ? this : NULL; } +//============================================================================= +// Do we match on this edge? No memory edges +uint AryEqNode::match_edge(uint idx) const { + return idx == 2 || idx == 3; // StrEquals ary1 ary2 +} //------------------------------Ideal------------------------------------------ // Return a node which is more "ideal" than the current node. Strip out // control copies diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/memnode.hpp --- a/src/share/vm/opto/memnode.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/memnode.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -582,12 +582,16 @@ // The last StoreCM before a SafePoint must be preserved and occur after its "oop" store // Preceeding equivalent StoreCMs may be eliminated. class StoreCMNode : public StoreNode { + private: + int _oop_alias_idx; // The alias_idx of OopStore public: - StoreCMNode( Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, Node *oop_store ) : StoreNode(c,mem,adr,at,val,oop_store) {} + StoreCMNode( Node *c, Node *mem, Node *adr, const TypePtr* at, Node *val, Node *oop_store, int oop_alias_idx ) : StoreNode(c,mem,adr,at,val,oop_store), _oop_alias_idx(oop_alias_idx) {} virtual int Opcode() const; virtual Node *Identity( PhaseTransform *phase ); + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type *Value( PhaseTransform *phase ) const; virtual BasicType memory_type() const { return T_VOID; } // unspecific + int oop_alias_idx() const { return _oop_alias_idx; } }; //------------------------------LoadPLockedNode--------------------------------- @@ -744,22 +748,15 @@ //------------------------------StrComp------------------------------------- class StrCompNode: public Node { public: - StrCompNode(Node *control, - Node* char_array_mem, - Node* value_mem, - Node* count_mem, - Node* offset_mem, - Node* s1, Node* s2): Node(control, - char_array_mem, - value_mem, - count_mem, - offset_mem, - s1, s2) {}; + StrCompNode(Node* control, Node* char_array_mem, + Node* s1, Node* c1, + Node* s2, Node* c2): Node(control, char_array_mem, + s1, c1, + s2, c2) {}; virtual int Opcode() const; virtual bool depends_only_on_test() const { return false; } virtual const Type* bottom_type() const { return TypeInt::INT; } - // a StrCompNode (conservatively) aliases with everything: - virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } + virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } virtual uint match_edge(uint idx) const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -768,22 +765,13 @@ //------------------------------StrEquals------------------------------------- class StrEqualsNode: public Node { public: - StrEqualsNode(Node *control, - Node* char_array_mem, - Node* value_mem, - Node* count_mem, - Node* offset_mem, - Node* s1, Node* s2): Node(control, - char_array_mem, - value_mem, - count_mem, - offset_mem, - s1, s2) {}; + StrEqualsNode(Node* control, Node* char_array_mem, + Node* s1, Node* s2, Node* c): Node(control, char_array_mem, + s1, s2, c) {}; virtual int Opcode() const; virtual bool depends_only_on_test() const { return false; } virtual const Type* bottom_type() const { return TypeInt::BOOL; } - // a StrEqualsNode (conservatively) aliases with everything: - virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } + virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } virtual uint match_edge(uint idx) const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -792,22 +780,15 @@ //------------------------------StrIndexOf------------------------------------- class StrIndexOfNode: public Node { public: - StrIndexOfNode(Node *control, - Node* char_array_mem, - Node* value_mem, - Node* count_mem, - Node* offset_mem, - Node* s1, Node* s2): Node(control, - char_array_mem, - value_mem, - count_mem, - offset_mem, - s1, s2) {}; + StrIndexOfNode(Node* control, Node* char_array_mem, + Node* s1, Node* c1, + Node* s2, Node* c2): Node(control, char_array_mem, + s1, c1, + s2, c2) {}; virtual int Opcode() const; virtual bool depends_only_on_test() const { return false; } virtual const Type* bottom_type() const { return TypeInt::INT; } - // a StrIndexOfNode (conservatively) aliases with everything: - virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; } + virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } virtual uint match_edge(uint idx) const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); @@ -816,11 +797,13 @@ //------------------------------AryEq--------------------------------------- class AryEqNode: public Node { public: - AryEqNode(Node *control, Node* s1, Node* s2): Node(control, s1, s2) {}; + AryEqNode(Node* control, Node* char_array_mem, + Node* s1, Node* s2): Node(control, char_array_mem, s1, s2) {}; virtual int Opcode() const; virtual bool depends_only_on_test() const { return false; } virtual const Type* bottom_type() const { return TypeInt::BOOL; } virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; } + virtual uint match_edge(uint idx) const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); }; diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/output.cpp --- a/src/share/vm/opto/output.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/output.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -611,7 +611,7 @@ assert(cik->is_instance_klass() || cik->is_array_klass(), "Not supported allocation."); sv = new ObjectValue(spobj->_idx, - new ConstantOopWriteValue(cik->encoding())); + new ConstantOopWriteValue(cik->constant_encoding())); Compile::set_sv_for_object_node(objs, sv); uint first_ind = spobj->first_index(); @@ -702,13 +702,13 @@ case Type::AryPtr: case Type::InstPtr: case Type::KlassPtr: // fall through - array->append(new ConstantOopWriteValue(t->isa_oopptr()->const_oop()->encoding())); + array->append(new ConstantOopWriteValue(t->isa_oopptr()->const_oop()->constant_encoding())); break; case Type::NarrowOop: if (t == TypeNarrowOop::NULL_PTR) { array->append(new ConstantOopWriteValue(NULL)); } else { - array->append(new ConstantOopWriteValue(t->make_ptr()->isa_oopptr()->const_oop()->encoding())); + array->append(new ConstantOopWriteValue(t->make_ptr()->isa_oopptr()->const_oop()->constant_encoding())); } break; case Type::Int: @@ -871,7 +871,7 @@ assert(cik->is_instance_klass() || cik->is_array_klass(), "Not supported allocation."); ObjectValue* sv = new ObjectValue(spobj->_idx, - new ConstantOopWriteValue(cik->encoding())); + new ConstantOopWriteValue(cik->constant_encoding())); Compile::set_sv_for_object_node(objs, sv); uint first_ind = spobj->first_index(); @@ -890,7 +890,7 @@ } } else { const TypePtr *tp = obj_node->bottom_type()->make_ptr(); - scval = new ConstantOopWriteValue(tp->is_instptr()->const_oop()->encoding()); + scval = new ConstantOopWriteValue(tp->is_instptr()->const_oop()->constant_encoding()); } OptoReg::Name box_reg = BoxLockNode::stack_slot(box_node); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/parse.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -469,7 +469,7 @@ // loading from a constant field or the constant pool // returns false if push failed (non-perm field constants only, not ldcs) - bool push_constant(ciConstant con); + bool push_constant(ciConstant con, bool require_constant = false); // implementation of object creation bytecodes void do_new(); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/parse1.cpp --- a/src/share/vm/opto/parse1.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/parse1.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -229,7 +229,9 @@ } } - MethodLivenessResult live_locals = method()->liveness_at_bci(osr_bci()); + // Use the raw liveness computation to make sure that unexpected + // values don't propagate into the OSR frame. + MethodLivenessResult live_locals = method()->raw_liveness_at_bci(osr_bci()); if (!live_locals.is_valid()) { // Degenerate or breakpointed method. C->record_method_not_compilable("OSR in empty or breakpointed method"); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/parse2.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1325,7 +1325,8 @@ } } } - push_constant(constant); + bool pushed = push_constant(constant, true); + guarantee(pushed, "must be possible to push this constant"); } break; diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/parse3.cpp --- a/src/share/vm/opto/parse3.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/parse3.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -267,7 +267,7 @@ } -bool Parse::push_constant(ciConstant constant) { +bool Parse::push_constant(ciConstant constant, bool require_constant) { switch (constant.basic_type()) { case T_BOOLEAN: push( intcon(constant.as_boolean()) ); break; case T_INT: push( intcon(constant.as_int()) ); break; @@ -279,13 +279,16 @@ case T_LONG: push_pair( longcon(constant.as_long()) ); break; case T_ARRAY: case T_OBJECT: { - // the oop is in perm space if the ciObject "has_encoding" + // cases: + // can_be_constant = (oop not scavengable || ScavengeRootsInCode != 0) + // should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2) + // An oop is not scavengable if it is in the perm gen. ciObject* oop_constant = constant.as_object(); if (oop_constant->is_null_object()) { push( zerocon(T_OBJECT) ); break; - } else if (oop_constant->has_encoding()) { - push( makecon(TypeOopPtr::make_from_constant(oop_constant)) ); + } else if (require_constant || oop_constant->should_be_constant()) { + push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant)) ); break; } else { // we cannot inline the oop, but we can use it later to narrow a type diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/phaseX.cpp --- a/src/share/vm/opto/phaseX.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/phaseX.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/phaseX.hpp --- a/src/share/vm/opto/phaseX.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/phaseX.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/postaloc.cpp --- a/src/share/vm/opto/postaloc.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/postaloc.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/superword.cpp --- a/src/share/vm/opto/superword.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/superword.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -457,10 +457,6 @@ } else if (out->Opcode() == Op_StoreCM && out->in(MemNode::OopStore) == n) { // StoreCM has an input edge used as a precedence edge. // Maybe an issue when oop stores are vectorized. - } else if( out->is_MergeMem() && prev && - prev->Opcode() == Op_StoreCM && out == prev->in(MemNode::OopStore)) { - // Oop store is a MergeMem! This should not happen. Temporarily remove the assertion - // for this case because it could not be superwordized anyway. } else { assert(out == prev || prev == NULL, "no branches off of store slice"); } @@ -477,6 +473,12 @@ // Can s1 and s2 be in a pack with s1 immediately preceding s2 and // s1 aligned at "align" bool SuperWord::stmts_can_pack(Node* s1, Node* s2, int align) { + + // Do not use superword for non-primitives + if((s1->is_Mem() && !is_java_primitive(s1->as_Mem()->memory_type())) || + (s2->is_Mem() && !is_java_primitive(s2->as_Mem()->memory_type()))) + return false; + if (isomorphic(s1, s2)) { if (independent(s1, s2)) { if (!exists_at(s1, 0) && !exists_at(s2, 1)) { diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/type.cpp --- a/src/share/vm/opto/type.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/type.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -296,7 +296,7 @@ false, 0, oopDesc::mark_offset_in_bytes()); TypeInstPtr::KLASS = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), false, 0, oopDesc::klass_offset_in_bytes()); - TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot); + TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot); TypeNarrowOop::NULL_PTR = TypeNarrowOop::make( TypePtr::NULL_PTR ); TypeNarrowOop::BOTTOM = TypeNarrowOop::make( TypeInstPtr::BOTTOM ); @@ -492,8 +492,13 @@ bool Type::interface_vs_oop(const Type *t) const { bool result = false; - const TypeInstPtr* this_inst = this->isa_instptr(); - const TypeInstPtr* t_inst = t->isa_instptr(); + const TypePtr* this_ptr = this->make_ptr(); // In case it is narrow_oop + const TypePtr* t_ptr = t->make_ptr(); + if( this_ptr == NULL || t_ptr == NULL ) + return result; + + const TypeInstPtr* this_inst = this_ptr->isa_instptr(); + const TypeInstPtr* t_inst = t_ptr->isa_instptr(); if( this_inst && this_inst->is_loaded() && t_inst && t_inst->is_loaded() ) { bool this_interface = this_inst->klass()->is_interface(); bool t_interface = t_inst->klass()->is_interface(); @@ -2249,7 +2254,7 @@ const Type *TypeOopPtr::cast_to_ptr_type(PTR ptr) const { assert(_base == OopPtr, "subclass must override cast_to_ptr_type"); if( ptr == _ptr ) return this; - return make(ptr, _offset); + return make(ptr, _offset, _instance_id); } //-----------------------------cast_to_instance_id---------------------------- @@ -2319,8 +2324,10 @@ if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset); // else fall through: case TopPTR: - case AnyNull: - return make(ptr, offset); + case AnyNull: { + int instance_id = meet_instance_id(InstanceTop); + return make(ptr, offset, instance_id); + } case BotPTR: case NotNull: return TypePtr::make(AnyPtr, ptr, offset); @@ -2411,14 +2418,13 @@ //------------------------------make_from_constant----------------------------- // Make a java pointer from an oop constant -const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o) { +const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_constant) { if (o->is_method_data() || o->is_method()) { // Treat much like a typeArray of bytes, like below, but fake the type... - assert(o->has_encoding(), "must be a perm space object"); const Type* etype = (Type*)get_const_basic_type(T_BYTE); const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS); ciKlass *klass = ciTypeArrayKlass::make((BasicType) T_BYTE); - assert(o->has_encoding(), "method data oops should be tenured"); + assert(o->can_be_constant(), "method data oops should be tenured"); const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0); return arr; } else { @@ -2427,8 +2433,9 @@ ciKlass *klass = o->klass(); if (klass->is_instance_klass()) { // Element is an instance - if (!o->has_encoding()) { // not a perm-space constant - // %%% remove this restriction by rewriting non-perm ConPNodes in a later phase + if (require_constant) { + if (!o->can_be_constant()) return NULL; + } else if (!o->should_be_constant()) { return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, 0); } return TypeInstPtr::make(o); @@ -2440,8 +2447,9 @@ // We used to pass NotNull in here, asserting that the sub-arrays // are all not-null. This is not true in generally, as code can // slam NULLs down in the subarrays. - if (!o->has_encoding()) { // not a perm-space constant - // %%% remove this restriction by rewriting non-perm ConPNodes in a later phase + if (require_constant) { + if (!o->can_be_constant()) return NULL; + } else if (!o->should_be_constant()) { return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0); } const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0); @@ -2453,8 +2461,9 @@ const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length())); // We used to pass NotNull in here, asserting that the array pointer // is not-null. That was not true in general. - if (!o->has_encoding()) { // not a perm-space constant - // %%% remove this restriction by rewriting non-perm ConPNodes in a later phase + if (require_constant) { + if (!o->can_be_constant()) return NULL; + } else if (!o->should_be_constant()) { return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0); } const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0); @@ -2483,7 +2492,7 @@ ShouldNotReachHere(); } - return (intptr_t)const_oop()->encoding(); + return (intptr_t)const_oop()->constant_encoding(); } @@ -2591,7 +2600,7 @@ //------------------------------add_offset------------------------------------- const TypePtr *TypeOopPtr::add_offset( intptr_t offset ) const { - return make( _ptr, xadd_offset(offset) ); + return make( _ptr, xadd_offset(offset), _instance_id); } //------------------------------meet_instance_id-------------------------------- @@ -2694,6 +2703,7 @@ const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const { int off = meet_offset(tinst->offset()); PTR ptr = meet_ptr(tinst->ptr()); + int instance_id = meet_instance_id(tinst->instance_id()); const TypeInstPtr *loaded = is_loaded() ? this : tinst; const TypeInstPtr *unloaded = is_loaded() ? tinst : this; @@ -2714,7 +2724,7 @@ assert(loaded->ptr() != TypePtr::Null, "insanity check"); // if( loaded->ptr() == TypePtr::TopPTR ) { return unloaded; } - else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make( ptr, unloaded->klass() ); } + else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make( ptr, unloaded->klass(), false, NULL, off, instance_id ); } else if (loaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; } else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) { if (unloaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; } @@ -3338,14 +3348,19 @@ ciObject* o = const_oop(); if( _ptr == Constant ) { if( tap->const_oop() != NULL && !o->equals(tap->const_oop()) ) { + xk = (klass() == tap->klass()); ptr = NotNull; o = NULL; instance_id = InstanceBot; + } else { + xk = true; } } else if( above_centerline(_ptr) ) { o = tap->const_oop(); + xk = true; + } else { + xk = this->_klass_is_exact; } - xk = true; return TypeAryPtr::make( ptr, o, tary, tap->_klass, xk, off, instance_id ); } case NotNull: diff -r 054afbef9081 -r a2ad635573fb src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/opto/type.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -711,10 +711,13 @@ return make_from_klass_common(klass, false, false); } // Creates a singleton type given an object. - static const TypeOopPtr* make_from_constant(ciObject* o); + // If the object cannot be rendered as a constant, + // may return a non-singleton type. + // If require_constant, produce a NULL if a singleton is not possible. + static const TypeOopPtr* make_from_constant(ciObject* o, bool require_constant = false); // Make a generic (unclassed) pointer to an oop. - static const TypeOopPtr* make(PTR ptr, int offset, int instance_id = InstanceBot); + static const TypeOopPtr* make(PTR ptr, int offset, int instance_id); ciObject* const_oop() const { return _const_oop; } virtual ciKlass* klass() const { return _klass; } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/prims/jvm.h --- a/src/share/vm/prims/jvm.h Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/prims/jvm.h Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/prims/jvmtiTagMap.cpp --- a/src/share/vm/prims/jvmtiTagMap.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/prims/jvmtiTagMap.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -3126,6 +3126,12 @@ // exceptions) will be visible. blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER); Universe::oops_do(&blk); + + // If there are any non-perm roots in the code cache, visit them. + blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER); + CodeBlobToOopClosure look_in_blobs(&blk, false); + CodeCache::scavenge_root_nmethods_do(&look_in_blobs); + return true; } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/arguments.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -2648,16 +2648,22 @@ if (EnableInvokeDynamic && !EnableMethodHandles) { if (!FLAG_IS_DEFAULT(EnableMethodHandles)) { - warning("forcing EnableMethodHandles true to allow EnableInvokeDynamic"); + warning("forcing EnableMethodHandles true because EnableInvokeDynamic is true"); } EnableMethodHandles = true; } if (EnableMethodHandles && !AnonymousClasses) { if (!FLAG_IS_DEFAULT(AnonymousClasses)) { - warning("forcing AnonymousClasses true to enable EnableMethodHandles"); + warning("forcing AnonymousClasses true because EnableMethodHandles is true"); } AnonymousClasses = true; } + if ((EnableMethodHandles || AnonymousClasses) && ScavengeRootsInCode == 0) { + if (!FLAG_IS_DEFAULT(ScavengeRootsInCode)) { + warning("forcing ScavengeRootsInCode non-zero because EnableMethodHandles or AnonymousClasses is true"); + } + ScavengeRootsInCode = 1; + } if (PrintGCDetails) { // Turn on -verbose:gc options as well diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/atomic.hpp --- a/src/share/vm/runtime/atomic.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/atomic.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1999-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/frame.cpp --- a/src/share/vm/runtime/frame.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/frame.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1043,7 +1043,7 @@ finder.oops_do(); } -void frame::oops_code_blob_do(OopClosure* f, const RegisterMap* reg_map) { +void frame::oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const RegisterMap* reg_map) { assert(_cb != NULL, "sanity check"); if (_cb->oop_maps() != NULL) { OopMapSet::oops_do(this, reg_map, f); @@ -1058,21 +1058,9 @@ // oops referenced from nmethods active on thread stacks so as to // prevent them from being collected. However, this visit should be // restricted to certain phases of the collection only. The - // closure answers whether it wants nmethods to be traced. - // (All CodeBlob subtypes other than NMethod currently have - // an empty oops_do() method. - if (f->do_nmethods()) { - _cb->oops_do(f); - } -} - -void frame::nmethods_code_blob_do() { - assert(_cb != NULL, "sanity check"); - - // If we see an activation belonging to a non_entrant nmethod, we mark it. - if (_cb->is_nmethod() && ((nmethod *)_cb)->is_not_entrant()) { - ((nmethod*)_cb)->mark_as_seen_on_stack(); - } + // closure decides how it wants nmethods to be traced. + if (cf != NULL) + cf->do_code_blob(_cb); } class CompiledArgumentOopFinder: public SignatureInfo { @@ -1201,18 +1189,18 @@ } -void frame::oops_do_internal(OopClosure* f, RegisterMap* map, bool use_interpreter_oop_map_cache) { +void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache) { if (is_interpreted_frame()) { oops_interpreted_do(f, map, use_interpreter_oop_map_cache); } else if (is_entry_frame()) { oops_entry_do (f, map); - } else if (CodeCache::contains(pc())) { oops_code_blob_do (f, map); + } else if (CodeCache::contains(pc())) { oops_code_blob_do (f, cf, map); } else { ShouldNotReachHere(); } } -void frame::nmethods_do() { +void frame::nmethods_do(CodeBlobClosure* cf) { if (_cb != NULL && _cb->is_nmethod()) { - nmethods_code_blob_do(); + cf->do_code_blob(_cb); } } @@ -1358,7 +1346,7 @@ } } COMPILER2_PRESENT(assert(DerivedPointerTable::is_empty(), "must be empty before verify");) - oops_do_internal(&VerifyOopClosure::verify_oop, (RegisterMap*)map, false); + oops_do_internal(&VerifyOopClosure::verify_oop, NULL, (RegisterMap*)map, false); } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/frame.hpp --- a/src/share/vm/runtime/frame.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/frame.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -384,16 +384,14 @@ void oops_interpreted_arguments_do(symbolHandle signature, bool is_static, OopClosure* f); // Iteration of oops - void oops_do_internal(OopClosure* f, RegisterMap* map, bool use_interpreter_oop_map_cache); + void oops_do_internal(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map, bool use_interpreter_oop_map_cache); void oops_entry_do(OopClosure* f, const RegisterMap* map); - void oops_code_blob_do(OopClosure* f, const RegisterMap* map); + void oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, const RegisterMap* map); int adjust_offset(methodOop method, int index); // helper for above fn - // Iteration of nmethods - void nmethods_code_blob_do(); public: // Memory management - void oops_do(OopClosure* f, RegisterMap* map) { oops_do_internal(f, map, true); } - void nmethods_do(); + void oops_do(OopClosure* f, CodeBlobClosure* cf, RegisterMap* map) { oops_do_internal(f, cf, map, true); } + void nmethods_do(CodeBlobClosure* cf); void gc_prologue(); void gc_epilogue(); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/globals.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -714,6 +714,11 @@ diagnostic(bool, TraceNMethodInstalls, false, \ "Trace nmethod intallation") \ \ + diagnostic(intx, ScavengeRootsInCode, 0, \ + "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") \ + \ diagnostic(bool, TraceOSRBreakpoint, false, \ "Trace OSR Breakpoint ") \ \ diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/perfData.hpp --- a/src/share/vm/runtime/perfData.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/perfData.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/sweeper.cpp --- a/src/share/vm/runtime/sweeper.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/sweeper.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,17 @@ jint NMethodSweeper::_not_entrant_seen_on_stack = 0; bool NMethodSweeper::_rescan = false; +class MarkActivationClosure: public CodeBlobClosure { +public: + virtual void do_code_blob(CodeBlob* cb) { + // If we see an activation belonging to a non_entrant nmethod, we mark it. + if (cb->is_nmethod() && ((nmethod*)cb)->is_not_entrant()) { + ((nmethod*)cb)->mark_as_seen_on_stack(); + } + } +}; +static MarkActivationClosure mark_activation_closure; + void NMethodSweeper::sweep() { assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint"); if (!MethodFlushing) return; @@ -57,7 +68,7 @@ if (PrintMethodFlushing) { tty->print_cr("### Sweep: stack traversal %d", _traversals); } - Threads::nmethods_do(); + Threads::nmethods_do(&mark_activation_closure); // reset the flags since we started a scan from the beginning. _rescan = false; diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/thread.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -683,14 +683,15 @@ return false; } -void Thread::oops_do(OopClosure* f) { +void Thread::oops_do(OopClosure* f, CodeBlobClosure* cf) { active_handles()->oops_do(f); // Do oop for ThreadShadow f->do_oop((oop*)&_pending_exception); handle_area()->oops_do(f); } -void Thread::nmethods_do() { +void Thread::nmethods_do(CodeBlobClosure* cf) { + // no nmethods in a generic thread... } void Thread::print_on(outputStream* st) const { @@ -2316,12 +2317,12 @@ } -void JavaThread::oops_do(OopClosure* f) { +void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) { // The ThreadProfiler oops_do is done from FlatProfiler::oops_do // since there may be more than one thread using each ThreadProfiler. // Traverse the GCHandles - Thread::oops_do(f); + Thread::oops_do(f, cf); assert( (!has_last_Java_frame() && java_call_counter() == 0) || (has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!"); @@ -2347,7 +2348,7 @@ // Traverse the execution stack for(StackFrameStream fst(this); !fst.is_done(); fst.next()) { - fst.current()->oops_do(f, fst.register_map()); + fst.current()->oops_do(f, cf, fst.register_map()); } } @@ -2379,9 +2380,8 @@ } } -void JavaThread::nmethods_do() { - // Traverse the GCHandles - Thread::nmethods_do(); +void JavaThread::nmethods_do(CodeBlobClosure* cf) { + Thread::nmethods_do(cf); // (super method is a no-op) assert( (!has_last_Java_frame() && java_call_counter() == 0) || (has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!"); @@ -2389,7 +2389,7 @@ if (has_last_Java_frame()) { // Traverse the execution stack for(StackFrameStream fst(this); !fst.is_done(); fst.next()) { - fst.current()->nmethods_do(); + fst.current()->nmethods_do(cf); } } } @@ -2463,7 +2463,7 @@ void JavaThread::verify() { // Verify oops in the thread. - oops_do(&VerifyOopClosure::verify_oop); + oops_do(&VerifyOopClosure::verify_oop, NULL); // Verify the stack frames. frames_do(frame_verify); @@ -3602,14 +3602,14 @@ // uses the Threads_lock to gurantee this property. It also makes sure that // all threads gets blocked when exiting or starting). -void Threads::oops_do(OopClosure* f) { +void Threads::oops_do(OopClosure* f, CodeBlobClosure* cf) { ALL_JAVA_THREADS(p) { - p->oops_do(f); + p->oops_do(f, cf); } - VMThread::vm_thread()->oops_do(f); + VMThread::vm_thread()->oops_do(f, cf); } -void Threads::possibly_parallel_oops_do(OopClosure* f) { +void Threads::possibly_parallel_oops_do(OopClosure* f, CodeBlobClosure* cf) { // Introduce a mechanism allowing parallel threads to claim threads as // root groups. Overhead should be small enough to use all the time, // even in sequential code. @@ -3618,12 +3618,12 @@ int cp = SharedHeap::heap()->strong_roots_parity(); ALL_JAVA_THREADS(p) { if (p->claim_oops_do(is_par, cp)) { - p->oops_do(f); + p->oops_do(f, cf); } } VMThread* vmt = VMThread::vm_thread(); if (vmt->claim_oops_do(is_par, cp)) - vmt->oops_do(f); + vmt->oops_do(f, cf); } #ifndef SERIALGC @@ -3644,11 +3644,11 @@ } #endif // SERIALGC -void Threads::nmethods_do() { +void Threads::nmethods_do(CodeBlobClosure* cf) { ALL_JAVA_THREADS(p) { - p->nmethods_do(); + p->nmethods_do(cf); } - VMThread::vm_thread()->nmethods_do(); + VMThread::vm_thread()->nmethods_do(cf); } void Threads::gc_epilogue() { diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/thread.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -374,7 +374,8 @@ // GC support // Apply "f->do_oop" to all root oops in "this". - void oops_do(OopClosure* f); + // Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames + void oops_do(OopClosure* f, CodeBlobClosure* cf); // Handles the parallel case for the method below. private: @@ -398,7 +399,7 @@ } // Sweeper support - void nmethods_do(); + void nmethods_do(CodeBlobClosure* cf); // Tells if adr belong to this thread. This is used // for checking if a lock is owned by the running thread. @@ -1229,10 +1230,10 @@ void frames_do(void f(frame*, const RegisterMap*)); // Memory operations - void oops_do(OopClosure* f); + void oops_do(OopClosure* f, CodeBlobClosure* cf); // Sweeper operations - void nmethods_do(); + void nmethods_do(CodeBlobClosure* cf); // Memory management operations void gc_epilogue(); @@ -1620,9 +1621,9 @@ // Apply "f->do_oop" to all root oops in all threads. // This version may only be called by sequential code. - static void oops_do(OopClosure* f); + static void oops_do(OopClosure* f, CodeBlobClosure* cf); // This version may be called by sequential or parallel code. - static void possibly_parallel_oops_do(OopClosure* f); + static void possibly_parallel_oops_do(OopClosure* f, CodeBlobClosure* cf); // This creates a list of GCTasks, one per thread. static void create_thread_roots_tasks(GCTaskQueue* q); // This creates a list of GCTasks, one per thread, for marking objects. @@ -1630,13 +1631,13 @@ // Apply "f->do_oop" to roots in all threads that // are part of compiled frames - static void compiled_frame_oops_do(OopClosure* f); + static void compiled_frame_oops_do(OopClosure* f, CodeBlobClosure* cf); static void convert_hcode_pointers(); static void restore_hcode_pointers(); // Sweeper - static void nmethods_do(); + static void nmethods_do(CodeBlobClosure* cf); static void gc_epilogue(); static void gc_prologue(); diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/vframeArray.hpp --- a/src/share/vm/runtime/vframeArray.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/vframeArray.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/vframe_hp.hpp --- a/src/share/vm/runtime/vframe_hp.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/vframe_hp.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/vmStructs.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -549,6 +549,7 @@ /********************************/ \ \ static_field(CodeCache, _heap, CodeHeap*) \ + static_field(CodeCache, _scavenge_root_nmethods, nmethod*) \ \ /*******************************/ \ /* CodeHeap (NOTE: incomplete) */ \ @@ -618,7 +619,9 @@ static_field(nmethod, _zombie_instruction_size, int) \ nonstatic_field(nmethod, _method, methodOop) \ nonstatic_field(nmethod, _entry_bci, int) \ - nonstatic_field(nmethod, _link, nmethod*) \ + nonstatic_field(nmethod, _osr_link, nmethod*) \ + nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \ + nonstatic_field(nmethod, _scavenge_root_state, jbyte) \ nonstatic_field(nmethod, _exception_offset, int) \ nonstatic_field(nmethod, _deoptimize_offset, int) \ nonstatic_field(nmethod, _orig_pc_offset, int) \ diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/vmThread.cpp --- a/src/share/vm/runtime/vmThread.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/vmThread.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -619,8 +619,8 @@ } -void VMThread::oops_do(OopClosure* f) { - Thread::oops_do(f); +void VMThread::oops_do(OopClosure* f, CodeBlobClosure* cf) { + Thread::oops_do(f, cf); _vm_queue->oops_do(f); } @@ -652,5 +652,5 @@ #endif void VMThread::verify() { - oops_do(&VerifyOopClosure::verify_oop); + oops_do(&VerifyOopClosure::verify_oop, NULL); } diff -r 054afbef9081 -r a2ad635573fb src/share/vm/runtime/vmThread.hpp --- a/src/share/vm/runtime/vmThread.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/runtime/vmThread.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -121,7 +121,7 @@ static VMThread* vm_thread() { return _vm_thread; } // GC support - void oops_do(OopClosure* f); + void oops_do(OopClosure* f, CodeBlobClosure* cf); // Debugging void print_on(outputStream* st) const; diff -r 054afbef9081 -r a2ad635573fb src/share/vm/services/threadService.cpp --- a/src/share/vm/services/threadService.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/services/threadService.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/services/threadService.hpp --- a/src/share/vm/services/threadService.hpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/services/threadService.hpp Wed Oct 14 12:40:20 2009 -0700 @@ -1,5 +1,5 @@ /* - * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2003-2009 Sun Microsystems, Inc. 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 diff -r 054afbef9081 -r a2ad635573fb src/share/vm/utilities/debug.cpp --- a/src/share/vm/utilities/debug.cpp Mon Sep 28 12:27:52 2009 -0400 +++ b/src/share/vm/utilities/debug.cpp Wed Oct 14 12:40:20 2009 -0700 @@ -702,11 +702,14 @@ tty->print_cr("Searching strong roots:"); Universe::oops_do(&lookFor, false); JNIHandles::oops_do(&lookFor); // Global (strong) JNI handles - Threads::oops_do(&lookFor); + Threads::oops_do(&lookFor, NULL); ObjectSynchronizer::oops_do(&lookFor); //FlatProfiler::oops_do(&lookFor); SystemDictionary::oops_do(&lookFor); + tty->print_cr("Searching code cache:"); + CodeCache::oops_do(&lookFor); + tty->print_cr("Done."); } diff -r 054afbef9081 -r a2ad635573fb test/compiler/6823453/Test.java --- a/test/compiler/6823453/Test.java Mon Sep 28 12:27:52 2009 -0400 +++ b/test/compiler/6823453/Test.java Wed Oct 14 12:40:20 2009 -0700 @@ -26,7 +26,7 @@ * @test * @bug 6823453 * @summary DeoptimizeALot causes fastdebug server jvm to fail with assert(false,"unscheduable graph") - * @run main/othervm -Xcomp -XX:CompileOnly=Test -XX:+DeoptimizeALot Test + * @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:CompileOnly=Test -XX:+DeoptimizeALot Test */ public class Test { diff -r 054afbef9081 -r a2ad635573fb test/compiler/6833129/Test.java --- a/test/compiler/6833129/Test.java Mon Sep 28 12:27:52 2009 -0400 +++ b/test/compiler/6833129/Test.java Wed Oct 14 12:40:20 2009 -0700 @@ -25,7 +25,7 @@ * @test * @bug 6833129 * @summary Object.clone() and Arrays.copyOf ignore coping with -XX:+DeoptimizeALot - * @run main/othervm -Xbatch -XX:+DeoptimizeALot Test + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot Test */ public class Test{ diff -r 054afbef9081 -r a2ad635573fb test/compiler/6875866/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6875866/Test.java Wed Oct 14 12:40:20 2009 -0700 @@ -0,0 +1,46 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6875866 + * @summary Intrinsic for String.indexOf() is broken on x86 with SSE4.2 + * + * @run main/othervm -Xcomp Test + */ + +public class Test { + + static int IndexOfTest(String str) { + return str.indexOf("11111xx1x"); + } + + public static void main(String args[]) { + String str = "11111xx11111xx1x"; + int idx = IndexOfTest(str); + System.out.println("IndexOf = " + idx); + if (idx != 7) { + System.exit(97); + } + } +} diff -r 054afbef9081 -r a2ad635573fb test/compiler/6877254/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6877254/Test.java Wed Oct 14 12:40:20 2009 -0700 @@ -0,0 +1,51 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6877254 + * @summary Implement StoreCMNode::Ideal to promote its OopStore above the MergeMem + * + * @run main/othervm -server -Xcomp -XX:+UseConcMarkSweepGC Test + */ + +public class Test { + static byte var_1; + static String var_2 = ""; + static byte var_3; + static float var_4 = 0; + + public static void main(String[] args) { + int i = 0; + + for (String var_tmp = var_2; i < 11; var_1 = 0, i++) { + var_2 = var_2; + var_4 *= (var_4 *= (var_3 = 0)); + } + + System.out.println("var_1 = " + var_1); + System.out.println("var_2 = " + var_2); + System.out.println("var_3 = " + var_3); + System.out.println("var_4 = " + var_4); + } +}