# HG changeset patch # User Doug Simon # Date 1412806997 -7200 # Node ID 21015ffe0a1eb8f55250eb49cd6c0f041971cfe3 # Parent d42e11af980d289aeabda632930ae041bc8cb1c0# Parent b888ded3ee422164bac2166a9232506922097474 Merge. diff -r d42e11af980d -r 21015ffe0a1e graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl --- a/graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl Thu Oct 09 00:20:30 2014 +0200 +++ b/graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl Thu Oct 09 00:23:17 2014 +0200 @@ -18,9 +18,12 @@ } function main() { + originalMaxCallerSize = getOption("TruffleInliningMaxCallerSize"); + setOption("TruffleInliningMaxCallerSize", 20); waitForOptimization(callUntilOptimized(test1)); assertTrue(isInlined(test1, test1, inlinableFunction), "inlinableFunction is not inlined"); waitForOptimization(callUntilOptimized(test2)); assertFalse(isInlined(test2, test2, notInlinableFunction), "notInlinableFunction is inlined"); + setOption("TruffleInliningMaxCallerSize", originalMaxCallerSize); } diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/code/debugInfoRec.cpp --- a/src/share/vm/code/debugInfoRec.cpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/code/debugInfoRec.cpp Thu Oct 09 00:23:17 2014 +0200 @@ -37,6 +37,9 @@ int _offset; // location in the stream of this scope int _length; // number of bytes in the stream int _hash; // hash of stream bytes (for quicker reuse) +#ifdef GRAAL + DebugInformationRecorder* _DIR; +#endif void* operator new(size_t ignore, DebugInformationRecorder* dir) throw() { assert(ignore == sizeof(DIR_Chunk), ""); @@ -51,6 +54,9 @@ DIR_Chunk(int offset, int length, DebugInformationRecorder* dir) { _offset = offset; _length = length; +#ifdef GRAAL + _DIR = dir; +#endif unsigned int hash = 0; address p = dir->stream()->buffer() + _offset; for (int i = 0; i < length; i++) { @@ -77,6 +83,25 @@ } return NULL; } + +#ifdef GRAAL + static int compare(DIR_Chunk* a, DIR_Chunk* b) { + if (b->_hash > a->_hash) { + return 1; + } + if (b->_hash < a->_hash) { + return -1; + } + if (b->_length > a->_length) { + return 1; + } + if (b->_length < a->_length) { + return -1; + } + address buf = a->_DIR->stream()->buffer(); + return memcmp(buf + b->_offset, buf + a->_offset, a->_length); + } +#endif }; static inline bool compute_recording_non_safepoints() { @@ -113,7 +138,9 @@ _oop_recorder = oop_recorder; _all_chunks = new GrowableArray(300); +#ifndef GRAAL _shared_chunks = new GrowableArray(30); +#endif _next_chunk = _next_chunk_limit = NULL; add_new_pc_offset(PcDesc::lower_offset_limit); // sentinel record @@ -250,6 +277,19 @@ DIR_Chunk* ns = new(this) DIR_Chunk(stream_offset, stream_length, this); +#ifdef GRAAL + DIR_Chunk* match = _all_chunks->find_insert_binary(ns); + if (match != ns) { + // Found an existing chunk + NOT_PRODUCT(++dir_stats.chunks_shared); + assert(ns+1 == _next_chunk, ""); + _next_chunk = ns; + return match->_offset; + } else { + // Inserted this chunk, so nothing to do + return serialized_null; + } +#else // Look in previously shared scopes first: DIR_Chunk* ms = ns->find_match(_shared_chunks, 0, this); if (ms != NULL) { @@ -277,6 +317,7 @@ // No match. Add this guy to the list, in hopes of future shares. _all_chunks->append(ns); return serialized_null; +#endif } diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/code/debugInfoRec.hpp --- a/src/share/vm/code/debugInfoRec.hpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/code/debugInfoRec.hpp Thu Oct 09 00:23:17 2014 +0200 @@ -163,7 +163,9 @@ // Scopes that have been described so far. GrowableArray* _all_chunks; +#ifndef GRAAL GrowableArray* _shared_chunks; +#endif DIR_Chunk* _next_chunk; DIR_Chunk* _next_chunk_limit; diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/code/nmethod.cpp --- a/src/share/vm/code/nmethod.cpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/code/nmethod.cpp Thu Oct 09 00:23:17 2014 +0200 @@ -1044,12 +1044,13 @@ LOG_OFFSET(xtty, consts); LOG_OFFSET(xtty, insts); LOG_OFFSET(xtty, stub); + LOG_OFFSET(xtty, oops); + LOG_OFFSET(xtty, metadata); LOG_OFFSET(xtty, scopes_data); LOG_OFFSET(xtty, scopes_pcs); LOG_OFFSET(xtty, dependencies); LOG_OFFSET(xtty, handler_table); LOG_OFFSET(xtty, nul_chk_table); - LOG_OFFSET(xtty, oops); xtty->method(method()); xtty->stamp(); diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/code/oopRecorder.cpp --- a/src/share/vm/code/oopRecorder.cpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/code/oopRecorder.cpp Thu Oct 09 00:23:17 2014 +0200 @@ -34,9 +34,17 @@ template int ValueRecorder::_find_index_calls = 0; template int ValueRecorder::_hit_indexes = 0; template int ValueRecorder::_missed_indexes = 0; + +void OopRecorder::check_for_duplicates(int index, jobject h) { + oop o = JNIHandles::resolve(h); + for (int i = 1; i < oop_count(); i++) { + if (o == JNIHandles::resolve(oop_at(i)) && index != i) { + assert(false, "duplicate found"); + } + } +} #endif //ASSERT - template ValueRecorder::ValueRecorder(Arena* arena) { _handles = NULL; _indexes = NULL; @@ -157,3 +165,49 @@ // Explicitly instantiate these types template class ValueRecorder; template class ValueRecorder; + +oop ObjectLookup::ObjectEntry::oop_value() { return JNIHandles::resolve(_value); } + +ObjectLookup::ObjectLookup(): _gc_count(Universe::heap()->total_collections()), _values(4) {} + +void ObjectLookup::maybe_resort() { + // The values are kept sorted by address which may be invalidated + // after a GC, so resort if a GC has occurred since last time. + if (_gc_count != Universe::heap()->total_collections()) { + _gc_count = Universe::heap()->total_collections(); + _values.sort(sort_by_address); + } +} + +int ObjectLookup::sort_by_address(oop a, oop b) { + if (b > a) return 1; + if (a > b) return -1; + return 0; +} + +int ObjectLookup::sort_by_address(ObjectEntry* a, ObjectEntry* b) { + return sort_by_address(a->oop_value(), b->oop_value()); +} + +int ObjectLookup::sort_oop_by_address(oop a, ObjectEntry b) { + return sort_by_address(a, b.oop_value()); +} + +int ObjectLookup::find_index(jobject handle, OopRecorder* oop_recorder) { + if (handle == NULL) { + return 0; + } + oop object = JNIHandles::resolve(handle); + maybe_resort(); + bool found; + int location = _values.find_binary(object, found); + if (!found) { + assert(location <= _values.length(), "out of range"); + jobject handle = JNIHandles::make_local(object); + ObjectEntry r(handle, oop_recorder->allocate_oop_index(handle)); + _values.insert_binary(location, r); + return r.index(); + } + return _values.at(location).index(); +} + diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/code/oopRecorder.hpp --- a/src/share/vm/code/oopRecorder.hpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/code/oopRecorder.hpp Thu Oct 09 00:23:17 2014 +0200 @@ -146,18 +146,61 @@ #endif }; +class OopRecorder; + +class ObjectLookup : public ResourceObj { + private: + class ObjectEntry { + private: + jobject _value; + int _index; + + public: + ObjectEntry(jobject value, int index): _value(value), _index(index) {} + ObjectEntry() {} + oop oop_value(); // { return JNIHandles::resolve(_value); } + int index() { return _index; } + }; + + GrowableArray _values; + unsigned int _gc_count; + + // Utility sort functions + static int sort_by_address(oop a, oop b); + static int sort_by_address(ObjectEntry* a, ObjectEntry* b); + static int sort_oop_by_address(oop a, ObjectEntry b); + + public: + ObjectLookup(); + + // Resort list if a GC has occurred since the last sort + void maybe_resort(); + int find_index(jobject object, OopRecorder* oop_recorder); +}; + class OopRecorder : public ResourceObj { private: ValueRecorder _oops; ValueRecorder _metadata; + ObjectLookup* _object_lookup; public: - OopRecorder(Arena* arena = NULL): _oops(arena), _metadata(arena) {} + OopRecorder(Arena* arena = NULL, bool deduplicate = false): _oops(arena), _metadata(arena) { + if (deduplicate) { + _object_lookup = new ObjectLookup(); + } else { + _object_lookup = NULL; + } + } + + void check_for_duplicates(int index, jobject h) NOT_DEBUG_RETURN; int allocate_oop_index(jobject h) { return _oops.allocate_index(h); } int find_index(jobject h) { - return _oops.find_index(h); + int result = _object_lookup != NULL ? _object_lookup->find_index(h, this) : _oops.find_index(h); + check_for_duplicates(result, h); + return result; } jobject oop_at(int index) { return _oops.at(index); diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/compiler/compileBroker.cpp Thu Oct 09 00:23:17 2014 +0200 @@ -2381,6 +2381,7 @@ stats->_standard._time.seconds(), stats->_standard._bytes, stats->_standard._count, stats->_osr._time.seconds(), stats->_osr._bytes, stats->_osr._count, stats->_nmethods_size, stats->_nmethods_code_size); + comp->print_timers(); } #endif diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/graal/graalCodeInstaller.cpp --- a/src/share/vm/graal/graalCodeInstaller.cpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/graal/graalCodeInstaller.cpp Thu Oct 09 00:23:17 2014 +0200 @@ -370,7 +370,7 @@ } void CodeInstaller::initialize_assumptions(oop compiled_code) { - _oop_recorder = new OopRecorder(&_arena); + _oop_recorder = new OopRecorder(&_arena, true); _dependencies = new Dependencies(&_arena, _oop_recorder); Handle assumptions_handle = CompilationResult::assumptions(HotSpotCompiledCode::comp(compiled_code)); if (!assumptions_handle.is_null()) { diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/graal/graalCompiler.cpp Thu Oct 09 00:23:17 2014 +0200 @@ -31,6 +31,7 @@ #include "runtime/globals_extension.hpp" GraalCompiler* GraalCompiler::_instance = NULL; +elapsedTimer GraalCompiler::_codeInstallTimer; GraalCompiler::GraalCompiler() : AbstractCompiler(graal) { #ifdef COMPILERGRAAL @@ -152,6 +153,7 @@ // Print compilation timers and statistics void GraalCompiler::print_timers() { TRACE_graal_1("GraalCompiler::print_timers"); + tty->print_cr(" Graal code install time: %6.3f s", _codeInstallTimer.seconds()); } #endif // COMPILERGRAAL diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/graal/graalCompiler.hpp --- a/src/share/vm/graal/graalCompiler.hpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/graal/graalCompiler.hpp Thu Oct 09 00:23:17 2014 +0200 @@ -43,6 +43,8 @@ static GraalCompiler* _instance; + static elapsedTimer _codeInstallTimer; + public: GraalCompiler(); @@ -79,6 +81,8 @@ void reset_compilation_stats(); #endif // COMPILERGRAAL + static elapsedTimer* codeInstallTimer() { return &_codeInstallTimer; } + #ifndef PRODUCT void compile_the_world(); #endif diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Thu Oct 09 00:23:17 2014 +0200 @@ -454,6 +454,7 @@ Handle installed_code_handle = JNIHandles::resolve(installed_code); Handle speculation_log_handle = JNIHandles::resolve(speculation_log); + TraceTime install_time("installCode", GraalCompiler::codeInstallTimer()); CodeInstaller installer; GraalEnv::CodeInstallResult result = installer.install(compiled_code_handle, cb, installed_code_handle, speculation_log_handle); diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/graal/graalJavaAccess.cpp --- a/src/share/vm/graal/graalJavaAccess.cpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/graal/graalJavaAccess.cpp Thu Oct 09 00:23:17 2014 +0200 @@ -29,13 +29,16 @@ // It looks up the name and signature symbols without creating new ones, all the symbols of these classes need to be already loaded. void compute_offset(int &dest_offset, Klass* klass, const char* name, const char* signature, bool static_field) { + InstanceKlass* ik = InstanceKlass::cast(klass); Symbol* name_symbol = SymbolTable::probe(name, (int)strlen(name)); Symbol* signature_symbol = SymbolTable::probe(signature, (int)strlen(signature)); if (name_symbol == NULL || signature_symbol == NULL) { +#ifndef PRODUCT + ik->print_on(tty); +#endif guarantee(false, err_msg("symbol with name %s and signature %s was not found in symbol table (klass=%s)", name, signature, klass->name()->as_C_string())); } - InstanceKlass* ik = InstanceKlass::cast(klass); fieldDescriptor fd; if (!ik->find_field(name_symbol, signature_symbol, &fd)) { ResourceMark rm; diff -r d42e11af980d -r 21015ffe0a1e src/share/vm/utilities/growableArray.hpp --- a/src/share/vm/utilities/growableArray.hpp Thu Oct 09 00:20:30 2014 +0200 +++ b/src/share/vm/utilities/growableArray.hpp Thu Oct 09 00:23:17 2014 +0200 @@ -360,6 +360,56 @@ void sort(int f(E*,E*), int stride) { qsort(_data, length() / stride, sizeof(E) * stride, (_sort_Fn)f); } + + // Binary search and insertion utility. Search array for element + // matching key according to the static compare function. Insert + // that element is not already in the list. Assumes the list is + // already sorted according to compare function. + template E find_insert_binary(E key) { + bool found; + int location = find_binary(key, found); + if (!found) { + assert(location <= length(), "out of range"); + insert_binary(location, key); + } + return at(location); + } + + template int find_binary(K key, bool& found) { + found = false; + int min = 0; + int max = length() - 1; + + while (max >= min) { + int mid = (max + min) / 2; + E value = at(mid); + int diff = compare(key, value); + if (diff > 0) { + min = mid + 1; + } else if (diff < 0) { + max = mid - 1; + } else { + found = true; + return mid; + } + } + return min; + } + + // Insert a new element at location, moving values as needed. + void insert_binary(int location, E element) { + int len = length(); + if (len == location) { + append(element); + } else { + append(at(len-1)); + int pos; + for (pos = len-2; pos >= location; pos--) { + at_put(pos+1, at(pos)); + } + at_put(location, element); + } + } }; // Global GrowableArray methods (one instance in the library per each 'E' type).