Mercurial > hg > graal-compiler
view src/share/vm/classfile/vmSymbols.cpp @ 2149:7e37af9d69ef
7011379: G1: overly long concurrent marking cycles
Summary: This changeset introduces filtering of SATB buffers at the point when they are about to be enqueued. If this filtering clears enough entries on each buffer, the buffer can then be re-used and not enqueued. This cuts down the number of SATB buffers that need to be processed by the concurrent marking threads.
Reviewed-by: johnc, ysr
author | tonyp |
---|---|
date | Wed, 19 Jan 2011 09:35:17 -0500 |
parents | f95d63e2154a |
children | 3582bf76420e |
line wrap: on
line source
/* * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #include "precompiled.hpp" #include "classfile/vmSymbols.hpp" #include "memory/oopFactory.hpp" #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" #include "utilities/xmlstream.hpp" symbolOop vmSymbols::_symbols[vmSymbols::SID_LIMIT]; symbolOop vmSymbols::_type_signatures[T_VOID+1] = { NULL /*, NULL...*/ }; inline int compare_symbol(symbolOop a, symbolOop b) { if (a == b) return 0; // follow the natural address order: return (address)a > (address)b ? +1 : -1; } static vmSymbols::SID vm_symbol_index[vmSymbols::SID_LIMIT]; extern "C" { static int compare_vmsymbol_sid(const void* void_a, const void* void_b) { symbolOop a = vmSymbols::symbol_at(*((vmSymbols::SID*) void_a)); symbolOop b = vmSymbols::symbol_at(*((vmSymbols::SID*) void_b)); return compare_symbol(a, b); } } #ifndef PRODUCT #define VM_SYMBOL_ENUM_NAME_BODY(name, string) #name "\0" static const char* vm_symbol_enum_names = VM_SYMBOLS_DO(VM_SYMBOL_ENUM_NAME_BODY, VM_ALIAS_IGNORE) "\0"; static const char* vm_symbol_enum_name(vmSymbols::SID sid) { const char* string = &vm_symbol_enum_names[0]; int skip = (int)sid - (int)vmSymbols::FIRST_SID; for (; skip != 0; skip--) { size_t skiplen = strlen(string); if (skiplen == 0) return "<unknown>"; // overflow string += skiplen+1; } return string; } #endif //PRODUCT // Put all the VM symbol strings in one place. // Makes for a more compact libjvm. #define VM_SYMBOL_BODY(name, string) string "\0" static const char* vm_symbol_bodies = VM_SYMBOLS_DO(VM_SYMBOL_BODY, VM_ALIAS_IGNORE); void vmSymbols::initialize(TRAPS) { assert((int)SID_LIMIT <= (1<<log2_SID_LIMIT), "must fit in this bitfield"); assert((int)SID_LIMIT*5 > (1<<log2_SID_LIMIT), "make the bitfield smaller, please"); assert(vmIntrinsics::FLAG_LIMIT <= (1 << vmIntrinsics::log2_FLAG_LIMIT), "must fit in this bitfield"); if (!UseSharedSpaces) { const char* string = &vm_symbol_bodies[0]; for (int index = (int)FIRST_SID; index < (int)SID_LIMIT; index++) { symbolOop sym = oopFactory::new_symbol(string, CHECK); _symbols[index] = sym; string += strlen(string); // skip string body string += 1; // skip trailing null } _type_signatures[T_BYTE] = byte_signature(); _type_signatures[T_CHAR] = char_signature(); _type_signatures[T_DOUBLE] = double_signature(); _type_signatures[T_FLOAT] = float_signature(); _type_signatures[T_INT] = int_signature(); _type_signatures[T_LONG] = long_signature(); _type_signatures[T_SHORT] = short_signature(); _type_signatures[T_BOOLEAN] = bool_signature(); _type_signatures[T_VOID] = void_signature(); // no single signatures for T_OBJECT or T_ARRAY } #ifdef ASSERT // Check for duplicates: for (int i1 = (int)FIRST_SID; i1 < (int)SID_LIMIT; i1++) { symbolOop sym = symbol_at((SID)i1); for (int i2 = (int)FIRST_SID; i2 < i1; i2++) { if (symbol_at((SID)i2) == sym) { tty->print("*** Duplicate VM symbol SIDs %s(%d) and %s(%d): \"", vm_symbol_enum_name((SID)i2), i2, vm_symbol_enum_name((SID)i1), i1); sym->print_symbol_on(tty); tty->print_cr("\""); } } } #endif //ASSERT // Create an index for find_id: { for (int index = (int)FIRST_SID; index < (int)SID_LIMIT; index++) { vm_symbol_index[index] = (SID)index; } int num_sids = SID_LIMIT-FIRST_SID; qsort(&vm_symbol_index[FIRST_SID], num_sids, sizeof(vm_symbol_index[0]), compare_vmsymbol_sid); } #ifdef ASSERT { // Spot-check correspondence between strings, symbols, and enums: assert(_symbols[NO_SID] == NULL, "must be"); const char* str = "java/lang/Object"; symbolOop sym = oopFactory::new_symbol(str, CHECK); assert(strcmp(str, (char*)sym->base()) == 0, ""); assert(sym == java_lang_Object(), ""); SID sid = VM_SYMBOL_ENUM_NAME(java_lang_Object); assert(find_sid(sym) == sid, ""); assert(symbol_at(sid) == sym, ""); // Make sure find_sid produces the right answer in each case. for (int index = (int)FIRST_SID; index < (int)SID_LIMIT; index++) { sym = symbol_at((SID)index); sid = find_sid(sym); assert(sid == (SID)index, "symbol index works"); // Note: If there are duplicates, this assert will fail. // A "Duplicate VM symbol" message will have already been printed. } // The string "format" happens (at the moment) not to be a vmSymbol, // though it is a method name in java.lang.String. str = "format"; sym = oopFactory::new_symbol(str, CHECK); sid = find_sid(sym); assert(sid == NO_SID, "symbol index works (negative test)"); } #endif } #ifndef PRODUCT const char* vmSymbols::name_for(vmSymbols::SID sid) { if (sid == NO_SID) return "NO_SID"; const char* string = &vm_symbol_bodies[0]; for (int index = (int)FIRST_SID; index < (int)SID_LIMIT; index++) { if (index == (int)sid) return string; string += strlen(string); // skip string body string += 1; // skip trailing null } return "BAD_SID"; } #endif void vmSymbols::oops_do(OopClosure* f, bool do_all) { for (int index = (int)FIRST_SID; index < (int)SID_LIMIT; index++) { f->do_oop((oop*) &_symbols[index]); } for (int i = 0; i < T_VOID+1; i++) { if (_type_signatures[i] != NULL) { assert(i >= T_BOOLEAN, "checking"); f->do_oop((oop*)&_type_signatures[i]); } else if (do_all) { f->do_oop((oop*)&_type_signatures[i]); } } } BasicType vmSymbols::signature_type(symbolOop s) { assert(s != NULL, "checking"); for (int i = T_BOOLEAN; i < T_VOID+1; i++) { if (s == _type_signatures[i]) { return (BasicType)i; } } return T_OBJECT; } static int mid_hint = (int)vmSymbols::FIRST_SID+1; #ifndef PRODUCT static int find_sid_calls, find_sid_probes; // (Typical counts are calls=7000 and probes=17000.) #endif vmSymbols::SID vmSymbols::find_sid(symbolOop symbol) { // Handle the majority of misses by a bounds check. // Then, use a binary search over the index. // Expected trip count is less than log2_SID_LIMIT, about eight. // This is slow but acceptable, given that calls are not // dynamically common. (methodOop::intrinsic_id has a cache.) NOT_PRODUCT(find_sid_calls++); int min = (int)FIRST_SID, max = (int)SID_LIMIT - 1; SID sid = NO_SID, sid1; int cmp1; sid1 = vm_symbol_index[min]; cmp1 = compare_symbol(symbol, symbol_at(sid1)); if (cmp1 <= 0) { // before the first if (cmp1 == 0) sid = sid1; } else { sid1 = vm_symbol_index[max]; cmp1 = compare_symbol(symbol, symbol_at(sid1)); if (cmp1 >= 0) { // after the last if (cmp1 == 0) sid = sid1; } else { // After checking the extremes, do a binary search. ++min; --max; // endpoints are done int mid = mid_hint; // start at previous success while (max >= min) { assert(mid >= min && mid <= max, ""); NOT_PRODUCT(find_sid_probes++); sid1 = vm_symbol_index[mid]; cmp1 = compare_symbol(symbol, symbol_at(sid1)); if (cmp1 == 0) { mid_hint = mid; sid = sid1; break; } if (cmp1 < 0) max = mid - 1; // symbol < symbol_at(sid) else min = mid + 1; // Pick a new probe point: mid = (max + min) / 2; } } } #ifdef ASSERT // Perform the exhaustive self-check the first 1000 calls, // and every 100 calls thereafter. static int find_sid_check_count = -2000; if ((uint)++find_sid_check_count > (uint)100) { if (find_sid_check_count > 0) find_sid_check_count = 0; // Make sure this is the right answer, using linear search. // (We have already proven that there are no duplicates in the list.) SID sid2 = NO_SID; for (int index = (int)FIRST_SID; index < (int)SID_LIMIT; index++) { symbolOop sym2 = symbol_at((SID)index); if (sym2 == symbol) { sid2 = (SID)index; break; } } // Unless it's a duplicate, assert that the sids are the same. if (_symbols[sid] != _symbols[sid2]) { assert(sid == sid2, "binary same as linear search"); } } #endif //ASSERT return sid; } static vmIntrinsics::ID wrapper_intrinsic(BasicType type, bool unboxing) { #define TYPE2(type, unboxing) ((int)(type)*2 + ((unboxing) ? 1 : 0)) switch (TYPE2(type, unboxing)) { #define BASIC_TYPE_CASE(type, box, unbox) \ case TYPE2(type, false): return vmIntrinsics::box; \ case TYPE2(type, true): return vmIntrinsics::unbox BASIC_TYPE_CASE(T_BOOLEAN, _Boolean_valueOf, _booleanValue); BASIC_TYPE_CASE(T_BYTE, _Byte_valueOf, _byteValue); BASIC_TYPE_CASE(T_CHAR, _Character_valueOf, _charValue); BASIC_TYPE_CASE(T_SHORT, _Short_valueOf, _shortValue); BASIC_TYPE_CASE(T_INT, _Integer_valueOf, _intValue); BASIC_TYPE_CASE(T_LONG, _Long_valueOf, _longValue); BASIC_TYPE_CASE(T_FLOAT, _Float_valueOf, _floatValue); BASIC_TYPE_CASE(T_DOUBLE, _Double_valueOf, _doubleValue); #undef BASIC_TYPE_CASE } #undef TYPE2 return vmIntrinsics::_none; } vmIntrinsics::ID vmIntrinsics::for_boxing(BasicType type) { return wrapper_intrinsic(type, false); } vmIntrinsics::ID vmIntrinsics::for_unboxing(BasicType type) { return wrapper_intrinsic(type, true); } vmIntrinsics::ID vmIntrinsics::for_raw_conversion(BasicType src, BasicType dest) { #define SRC_DEST(s,d) (((int)(s) << 4) + (int)(d)) switch (SRC_DEST(src, dest)) { case SRC_DEST(T_INT, T_FLOAT): return vmIntrinsics::_intBitsToFloat; case SRC_DEST(T_FLOAT, T_INT): return vmIntrinsics::_floatToRawIntBits; case SRC_DEST(T_LONG, T_DOUBLE): return vmIntrinsics::_longBitsToDouble; case SRC_DEST(T_DOUBLE, T_LONG): return vmIntrinsics::_doubleToRawLongBits; } #undef SRC_DEST return vmIntrinsics::_none; } methodOop vmIntrinsics::method_for(vmIntrinsics::ID id) { if (id == _none) return NULL; symbolOop cname = vmSymbols::symbol_at(class_for(id)); symbolOop mname = vmSymbols::symbol_at(name_for(id)); symbolOop msig = vmSymbols::symbol_at(signature_for(id)); if (cname == NULL || mname == NULL || msig == NULL) return NULL; klassOop k = SystemDictionary::find_well_known_klass(cname); if (k == NULL) return NULL; return instanceKlass::cast(k)->find_method(mname, msig); } #define VM_INTRINSIC_INITIALIZE(id, klass, name, sig, flags) #id "\0" static const char* vm_intrinsic_name_bodies = VM_INTRINSICS_DO(VM_INTRINSIC_INITIALIZE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE); static const char* vm_intrinsic_name_table[vmIntrinsics::ID_LIMIT]; const char* vmIntrinsics::name_at(vmIntrinsics::ID id) { const char** nt = &vm_intrinsic_name_table[0]; if (nt[_none] == NULL) { char* string = (char*) &vm_intrinsic_name_bodies[0]; for (int index = FIRST_ID; index < ID_LIMIT; index++) { nt[index] = string; string += strlen(string); // skip string body string += 1; // skip trailing null } assert(!strcmp(nt[_hashCode], "_hashCode"), "lined up"); nt[_none] = "_none"; } if ((uint)id < (uint)ID_LIMIT) return vm_intrinsic_name_table[(uint)id]; else return "(unknown intrinsic)"; } // These are flag-matching functions: inline bool match_F_R(jshort flags) { const int req = 0; const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED; return (flags & (req | neg)) == req; } inline bool match_F_Y(jshort flags) { const int req = JVM_ACC_SYNCHRONIZED; const int neg = JVM_ACC_STATIC; return (flags & (req | neg)) == req; } inline bool match_F_RN(jshort flags) { const int req = JVM_ACC_NATIVE; const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED; return (flags & (req | neg)) == req; } inline bool match_F_S(jshort flags) { const int req = JVM_ACC_STATIC; const int neg = JVM_ACC_SYNCHRONIZED; return (flags & (req | neg)) == req; } inline bool match_F_SN(jshort flags) { const int req = JVM_ACC_STATIC | JVM_ACC_NATIVE; const int neg = JVM_ACC_SYNCHRONIZED; return (flags & (req | neg)) == req; } inline bool match_F_RNY(jshort flags) { const int req = JVM_ACC_NATIVE | JVM_ACC_SYNCHRONIZED; const int neg = JVM_ACC_STATIC; return (flags & (req | neg)) == req; } // These are for forming case labels: #define ID3(x, y, z) (( jlong)(z) + \ ((jlong)(y) << vmSymbols::log2_SID_LIMIT) + \ ((jlong)(x) << (2*vmSymbols::log2_SID_LIMIT)) ) #define SID_ENUM(n) vmSymbols::VM_SYMBOL_ENUM_NAME(n) vmIntrinsics::ID vmIntrinsics::find_id_impl(vmSymbols::SID holder, vmSymbols::SID name, vmSymbols::SID sig, jshort flags) { assert((int)vmSymbols::SID_LIMIT <= (1<<vmSymbols::log2_SID_LIMIT), "must fit"); // Let the C compiler build the decision tree. #define VM_INTRINSIC_CASE(id, klass, name, sig, fcode) \ case ID3(SID_ENUM(klass), SID_ENUM(name), SID_ENUM(sig)): \ if (!match_##fcode(flags)) break; \ return id; switch (ID3(holder, name, sig)) { VM_INTRINSICS_DO(VM_INTRINSIC_CASE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE); } return vmIntrinsics::_none; #undef VM_INTRINSIC_CASE } const char* vmIntrinsics::short_name_as_C_string(vmIntrinsics::ID id, char* buf, int buflen) { const char* str = name_at(id); #ifndef PRODUCT const char* kname = vmSymbols::name_for(class_for(id)); const char* mname = vmSymbols::name_for(name_for(id)); const char* sname = vmSymbols::name_for(signature_for(id)); const char* fname = ""; switch (flags_for(id)) { case F_Y: fname = "synchronized "; break; case F_RN: fname = "native "; break; case F_SN: fname = "native static "; break; case F_S: fname = "static "; break; case F_RNY:fname = "native synchronized "; break; } const char* kptr = strrchr(kname, '/'); if (kptr != NULL) kname = kptr + 1; int len = jio_snprintf(buf, buflen, "%s: %s%s.%s%s", str, fname, kname, mname, sname); if (len < buflen) str = buf; #endif //PRODUCT return str; } // These are to get information about intrinsics. #define ID4(x, y, z, f) ((ID3(x, y, z) << vmIntrinsics::log2_FLAG_LIMIT) | (jlong) (f)) static const jlong intrinsic_info_array[vmIntrinsics::ID_LIMIT+1] = { #define VM_INTRINSIC_INFO(ignore_id, klass, name, sig, fcode) \ ID4(SID_ENUM(klass), SID_ENUM(name), SID_ENUM(sig), vmIntrinsics::fcode), 0, VM_INTRINSICS_DO(VM_INTRINSIC_INFO, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) 0 #undef VM_INTRINSIC_INFO }; inline jlong intrinsic_info(vmIntrinsics::ID id) { return intrinsic_info_array[vmIntrinsics::ID_from((int)id)]; } vmSymbols::SID vmIntrinsics::class_for(vmIntrinsics::ID id) { jlong info = intrinsic_info(id); int shift = 2*vmSymbols::log2_SID_LIMIT + log2_FLAG_LIMIT, mask = right_n_bits(vmSymbols::log2_SID_LIMIT); assert(((ID4(1021,1022,1023,15) >> shift) & mask) == 1021, ""); return vmSymbols::SID( (info >> shift) & mask ); } vmSymbols::SID vmIntrinsics::name_for(vmIntrinsics::ID id) { jlong info = intrinsic_info(id); int shift = vmSymbols::log2_SID_LIMIT + log2_FLAG_LIMIT, mask = right_n_bits(vmSymbols::log2_SID_LIMIT); assert(((ID4(1021,1022,1023,15) >> shift) & mask) == 1022, ""); return vmSymbols::SID( (info >> shift) & mask ); } vmSymbols::SID vmIntrinsics::signature_for(vmIntrinsics::ID id) { jlong info = intrinsic_info(id); int shift = log2_FLAG_LIMIT, mask = right_n_bits(vmSymbols::log2_SID_LIMIT); assert(((ID4(1021,1022,1023,15) >> shift) & mask) == 1023, ""); return vmSymbols::SID( (info >> shift) & mask ); } vmIntrinsics::Flags vmIntrinsics::flags_for(vmIntrinsics::ID id) { jlong info = intrinsic_info(id); int shift = 0, mask = right_n_bits(log2_FLAG_LIMIT); assert(((ID4(1021,1022,1023,15) >> shift) & mask) == 15, ""); return Flags( (info >> shift) & mask ); } #ifndef PRODUCT // verify_method performs an extra check on a matched intrinsic method static bool match_method(methodOop m, symbolOop n, symbolOop s) { return (m->name() == n && m->signature() == s); } static vmIntrinsics::ID match_method_with_klass(methodOop m, symbolOop mk) { #define VM_INTRINSIC_MATCH(id, klassname, namepart, sigpart, flags) \ { symbolOop k = vmSymbols::klassname(); \ if (mk == k) { \ symbolOop n = vmSymbols::namepart(); \ symbolOop s = vmSymbols::sigpart(); \ if (match_method(m, n, s)) \ return vmIntrinsics::id; \ } } VM_INTRINSICS_DO(VM_INTRINSIC_MATCH, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE); return vmIntrinsics::_none; #undef VM_INTRINSIC_MATCH } void vmIntrinsics::verify_method(ID actual_id, methodOop m) { symbolOop mk = Klass::cast(m->method_holder())->name(); ID declared_id = match_method_with_klass(m, mk); if (declared_id == actual_id) return; // success if (declared_id == _none && actual_id != _none && mk == vmSymbols::java_lang_StrictMath()) { // Here are a few special cases in StrictMath not declared in vmSymbols.hpp. switch (actual_id) { case _min: case _max: case _dsqrt: declared_id = match_method_with_klass(m, vmSymbols::java_lang_Math()); if (declared_id == actual_id) return; // acceptable alias break; } } const char* declared_name = name_at(declared_id); const char* actual_name = name_at(actual_id); methodHandle mh = m; m = NULL; ttyLocker ttyl; if (xtty != NULL) { xtty->begin_elem("intrinsic_misdeclared actual='%s' declared='%s'", actual_name, declared_name); xtty->method(mh); xtty->end_elem(""); } if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("*** misidentified method; %s(%d) should be %s(%d):", declared_name, declared_id, actual_name, actual_id); mh()->print_short_name(tty); tty->cr(); } } #endif //PRODUCT