ciReplay.cpp revision 11704:4731047cadb7
1130803Smarcel/* 2130803Smarcel * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. 3130803Smarcel * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4130803Smarcel * 5130803Smarcel * This code is free software; you can redistribute it and/or modify it 6130803Smarcel * under the terms of the GNU General Public License version 2 only, as 7130803Smarcel * published by the Free Software Foundation. 8130803Smarcel * 9130803Smarcel * This code is distributed in the hope that it will be useful, but WITHOUT 10130803Smarcel * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11130803Smarcel * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12130803Smarcel * version 2 for more details (a copy is included in the LICENSE file that 13130803Smarcel * accompanied this code). 14130803Smarcel * 15130803Smarcel * You should have received a copy of the GNU General Public License version 16130803Smarcel * 2 along with this work; if not, write to the Free Software Foundation, 17130803Smarcel * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18130803Smarcel * 19130803Smarcel * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20130803Smarcel * or visit www.oracle.com if you need additional information or have any 21130803Smarcel * questions. 22130803Smarcel * 23130803Smarcel */ 24130803Smarcel 25130803Smarcel#include "precompiled.hpp" 26130803Smarcel#include "ci/ciMethodData.hpp" 27130803Smarcel#include "ci/ciReplay.hpp" 28130803Smarcel#include "ci/ciSymbol.hpp" 29130803Smarcel#include "ci/ciKlass.hpp" 30130803Smarcel#include "ci/ciUtilities.hpp" 31130803Smarcel#include "compiler/compileBroker.hpp" 32130803Smarcel#include "gc/shared/referencePendingListLocker.hpp" 33130803Smarcel#include "memory/allocation.inline.hpp" 34130803Smarcel#include "memory/oopFactory.hpp" 35130803Smarcel#include "memory/resourceArea.hpp" 36130803Smarcel#include "oops/oop.inline.hpp" 37130803Smarcel#include "utilities/copy.hpp" 38130803Smarcel#include "utilities/macros.hpp" 39130803Smarcel 40130803Smarcel#ifndef PRODUCT 41130803Smarcel 42130803Smarcel// ciReplay 43130803Smarcel 44130803Smarceltypedef struct _ciMethodDataRecord { 45130803Smarcel const char* _klass_name; 46130803Smarcel const char* _method_name; 47130803Smarcel const char* _signature; 48130803Smarcel 49130803Smarcel int _state; 50130803Smarcel int _current_mileage; 51130803Smarcel 52130803Smarcel intptr_t* _data; 53130803Smarcel char* _orig_data; 54130803Smarcel Klass** _classes; 55130803Smarcel Method** _methods; 56130803Smarcel int* _classes_offsets; 57130803Smarcel int* _methods_offsets; 58130803Smarcel int _data_length; 59130803Smarcel int _orig_data_length; 60130803Smarcel int _classes_length; 61130803Smarcel int _methods_length; 62130803Smarcel} ciMethodDataRecord; 63130803Smarcel 64130803Smarceltypedef struct _ciMethodRecord { 65130803Smarcel const char* _klass_name; 66130803Smarcel const char* _method_name; 67130803Smarcel const char* _signature; 68130803Smarcel 69130803Smarcel int _instructions_size; 70130803Smarcel int _interpreter_invocation_count; 71130803Smarcel int _interpreter_throwout_count; 72130803Smarcel int _invocation_counter; 73130803Smarcel int _backedge_counter; 74130803Smarcel} ciMethodRecord; 75130803Smarcel 76130803Smarceltypedef struct _ciInlineRecord { 77130803Smarcel const char* _klass_name; 78130803Smarcel const char* _method_name; 79130803Smarcel const char* _signature; 80130803Smarcel 81130803Smarcel int _inline_depth; 82130803Smarcel int _inline_bci; 83130803Smarcel} ciInlineRecord; 84130803Smarcel 85130803Smarcelclass CompileReplay; 86130803Smarcelstatic CompileReplay* replay_state; 87130803Smarcel 88130803Smarcelclass CompileReplay : public StackObj { 89130803Smarcel private: 90130803Smarcel FILE* _stream; 91130803Smarcel Thread* _thread; 92130803Smarcel Handle _protection_domain; 93130803Smarcel Handle _loader; 94130803Smarcel 95130803Smarcel GrowableArray<ciMethodRecord*> _ci_method_records; 96130803Smarcel GrowableArray<ciMethodDataRecord*> _ci_method_data_records; 97130803Smarcel 98130803Smarcel // Use pointer because we may need to return inline records 99130803Smarcel // without destroying them. 100130803Smarcel GrowableArray<ciInlineRecord*>* _ci_inline_records; 101130803Smarcel 102130803Smarcel const char* _error_message; 103130803Smarcel 104130803Smarcel char* _bufptr; 105130803Smarcel char* _buffer; 106130803Smarcel int _buffer_length; 107130803Smarcel int _buffer_pos; 108130803Smarcel 109130803Smarcel // "compile" data 110130803Smarcel ciKlass* _iklass; 111130803Smarcel Method* _imethod; 112130803Smarcel int _entry_bci; 113130803Smarcel int _comp_level; 114130803Smarcel 115130803Smarcel public: 116130803Smarcel CompileReplay(const char* filename, TRAPS) { 117130803Smarcel _thread = THREAD; 118130803Smarcel _loader = Handle(_thread, SystemDictionary::java_system_loader()); 119130803Smarcel _protection_domain = Handle(); 120130803Smarcel 121130803Smarcel _stream = fopen(filename, "rt"); 122130803Smarcel if (_stream == NULL) { 123130803Smarcel fprintf(stderr, "ERROR: Can't open replay file %s\n", filename); 124130803Smarcel } 125130803Smarcel 126130803Smarcel _ci_inline_records = NULL; 127130803Smarcel _error_message = NULL; 128130803Smarcel 129130803Smarcel _buffer_length = 32; 130130803Smarcel _buffer = NEW_RESOURCE_ARRAY(char, _buffer_length); 131130803Smarcel _bufptr = _buffer; 132130803Smarcel _buffer_pos = 0; 133130803Smarcel 134130803Smarcel _imethod = NULL; 135130803Smarcel _iklass = NULL; 136130803Smarcel _entry_bci = 0; 137130803Smarcel _comp_level = 0; 138130803Smarcel 139130803Smarcel test(); 140130803Smarcel } 141130803Smarcel 142130803Smarcel ~CompileReplay() { 143130803Smarcel if (_stream != NULL) fclose(_stream); 144130803Smarcel } 145130803Smarcel 146130803Smarcel void test() { 147130803Smarcel strcpy(_buffer, "1 2 foo 4 bar 0x9 \"this is it\""); 148130803Smarcel _bufptr = _buffer; 149130803Smarcel assert(parse_int("test") == 1, "what"); 150130803Smarcel assert(parse_int("test") == 2, "what"); 151130803Smarcel assert(strcmp(parse_string(), "foo") == 0, "what"); 152130803Smarcel assert(parse_int("test") == 4, "what"); 153130803Smarcel assert(strcmp(parse_string(), "bar") == 0, "what"); 154130803Smarcel assert(parse_intptr_t("test") == 9, "what"); 155130803Smarcel assert(strcmp(parse_quoted_string(), "this is it") == 0, "what"); 156130803Smarcel } 157130803Smarcel 158130803Smarcel bool had_error() { 159130803Smarcel return _error_message != NULL || _thread->has_pending_exception(); 160130803Smarcel } 161130803Smarcel 162130803Smarcel bool can_replay() { 163130803Smarcel return !(_stream == NULL || had_error()); 164130803Smarcel } 165130803Smarcel 166130803Smarcel void report_error(const char* msg) { 167130803Smarcel _error_message = msg; 168130803Smarcel // Restore the _buffer contents for error reporting 169130803Smarcel for (int i = 0; i < _buffer_pos; i++) { 170130803Smarcel if (_buffer[i] == '\0') _buffer[i] = ' '; 171130803Smarcel } 172130803Smarcel } 173130803Smarcel 174130803Smarcel int parse_int(const char* label) { 175130803Smarcel if (had_error()) { 176130803Smarcel return 0; 177130803Smarcel } 178130803Smarcel 179130803Smarcel int v = 0; 180130803Smarcel int read; 181130803Smarcel if (sscanf(_bufptr, "%i%n", &v, &read) != 1) { 182130803Smarcel report_error(label); 183130803Smarcel } else { 184130803Smarcel _bufptr += read; 185130803Smarcel } 186130803Smarcel return v; 187130803Smarcel } 188130803Smarcel 189130803Smarcel intptr_t parse_intptr_t(const char* label) { 190130803Smarcel if (had_error()) { 191130803Smarcel return 0; 192130803Smarcel } 193130803Smarcel 194130803Smarcel intptr_t v = 0; 195130803Smarcel int read; 196130803Smarcel if (sscanf(_bufptr, INTPTR_FORMAT "%n", &v, &read) != 1) { 197130803Smarcel report_error(label); 198130803Smarcel } else { 199130803Smarcel _bufptr += read; 200130803Smarcel } 201130803Smarcel return v; 202130803Smarcel } 203130803Smarcel 204130803Smarcel void skip_ws() { 205130803Smarcel // Skip any leading whitespace 206130803Smarcel while (*_bufptr == ' ' || *_bufptr == '\t') { 207130803Smarcel _bufptr++; 208130803Smarcel } 209130803Smarcel } 210130803Smarcel 211130803Smarcel 212130803Smarcel char* scan_and_terminate(char delim) { 213130803Smarcel char* str = _bufptr; 214130803Smarcel while (*_bufptr != delim && *_bufptr != '\0') { 215130803Smarcel _bufptr++; 216130803Smarcel } 217130803Smarcel if (*_bufptr != '\0') { 218130803Smarcel *_bufptr++ = '\0'; 219130803Smarcel } 220130803Smarcel if (_bufptr == str) { 221130803Smarcel // nothing here 222130803Smarcel return NULL; 223130803Smarcel } 224130803Smarcel return str; 225130803Smarcel } 226130803Smarcel 227130803Smarcel char* parse_string() { 228130803Smarcel if (had_error()) return NULL; 229130803Smarcel 230130803Smarcel skip_ws(); 231130803Smarcel return scan_and_terminate(' '); 232130803Smarcel } 233130803Smarcel 234130803Smarcel char* parse_quoted_string() { 235130803Smarcel if (had_error()) return NULL; 236130803Smarcel 237130803Smarcel skip_ws(); 238130803Smarcel 239130803Smarcel if (*_bufptr == '"') { 240130803Smarcel _bufptr++; 241130803Smarcel return scan_and_terminate('"'); 242130803Smarcel } else { 243130803Smarcel return scan_and_terminate(' '); 244130803Smarcel } 245130803Smarcel } 246130803Smarcel 247130803Smarcel const char* parse_escaped_string() { 248130803Smarcel char* result = parse_quoted_string(); 249130803Smarcel if (result != NULL) { 250130803Smarcel unescape_string(result); 251130803Smarcel } 252130803Smarcel return result; 253130803Smarcel } 254130803Smarcel 255130803Smarcel // Look for the tag 'tag' followed by an 256130803Smarcel bool parse_tag_and_count(const char* tag, int& length) { 257130803Smarcel const char* t = parse_string(); 258130803Smarcel if (t == NULL) { 259130803Smarcel return false; 260130803Smarcel } 261130803Smarcel 262130803Smarcel if (strcmp(tag, t) != 0) { 263130803Smarcel report_error(tag); 264130803Smarcel return false; 265130803Smarcel } 266130803Smarcel length = parse_int("parse_tag_and_count"); 267130803Smarcel return !had_error(); 268130803Smarcel } 269130803Smarcel 270130803Smarcel // Parse a sequence of raw data encoded as bytes and return the 271130803Smarcel // resulting data. 272130803Smarcel char* parse_data(const char* tag, int& length) { 273130803Smarcel if (!parse_tag_and_count(tag, length)) { 274130803Smarcel return NULL; 275130803Smarcel } 276130803Smarcel 277130803Smarcel char * result = NEW_RESOURCE_ARRAY(char, length); 278130803Smarcel for (int i = 0; i < length; i++) { 279130803Smarcel int val = parse_int("data"); 280130803Smarcel result[i] = val; 281130803Smarcel } 282130803Smarcel return result; 283130803Smarcel } 284130803Smarcel 285130803Smarcel // Parse a standard chunk of data emitted as: 286130803Smarcel // 'tag' <length> # # ... 287130803Smarcel // Where each # is an intptr_t item 288130803Smarcel intptr_t* parse_intptr_data(const char* tag, int& length) { 289130803Smarcel if (!parse_tag_and_count(tag, length)) { 290130803Smarcel return NULL; 291130803Smarcel } 292130803Smarcel 293130803Smarcel intptr_t* result = NEW_RESOURCE_ARRAY(intptr_t, length); 294130803Smarcel for (int i = 0; i < length; i++) { 295130803Smarcel skip_ws(); 296130803Smarcel intptr_t val = parse_intptr_t("data"); 297130803Smarcel result[i] = val; 298130803Smarcel } 299130803Smarcel return result; 300130803Smarcel } 301130803Smarcel 302130803Smarcel // Parse a possibly quoted version of a symbol into a symbolOop 303130803Smarcel Symbol* parse_symbol(TRAPS) { 304130803Smarcel const char* str = parse_escaped_string(); 305130803Smarcel if (str != NULL) { 306130803Smarcel Symbol* sym = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL); 307130803Smarcel return sym; 308130803Smarcel } 309130803Smarcel return NULL; 310130803Smarcel } 311130803Smarcel 312130803Smarcel // Parse a valid klass name and look it up 313130803Smarcel Klass* parse_klass(TRAPS) { 314130803Smarcel const char* str = parse_escaped_string(); 315130803Smarcel Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL); 316130803Smarcel if (klass_name != NULL) { 317130803Smarcel Klass* k = NULL; 318130803Smarcel if (_iklass != NULL) { 319130803Smarcel k = (Klass*)_iklass->find_klass(ciSymbol::make(klass_name->as_C_string()))->constant_encoding(); 320130803Smarcel } else { 321130803Smarcel k = SystemDictionary::resolve_or_fail(klass_name, _loader, _protection_domain, true, THREAD); 322130803Smarcel } 323130803Smarcel if (HAS_PENDING_EXCEPTION) { 324130803Smarcel oop throwable = PENDING_EXCEPTION; 325130803Smarcel java_lang_Throwable::print(throwable, tty); 326130803Smarcel tty->cr(); 327130803Smarcel report_error(str); 328130803Smarcel return NULL; 329130803Smarcel } 330130803Smarcel return k; 331130803Smarcel } 332130803Smarcel return NULL; 333130803Smarcel } 334130803Smarcel 335130803Smarcel // Lookup a klass 336130803Smarcel Klass* resolve_klass(const char* klass, TRAPS) { 337130803Smarcel Symbol* klass_name = SymbolTable::lookup(klass, (int)strlen(klass), CHECK_NULL); 338130803Smarcel return SystemDictionary::resolve_or_fail(klass_name, _loader, _protection_domain, true, THREAD); 339130803Smarcel } 340130803Smarcel 341130803Smarcel // Parse the standard tuple of <klass> <name> <signature> 342130803Smarcel Method* parse_method(TRAPS) { 343130803Smarcel InstanceKlass* k = (InstanceKlass*)parse_klass(CHECK_NULL); 344130803Smarcel Symbol* method_name = parse_symbol(CHECK_NULL); 345130803Smarcel Symbol* method_signature = parse_symbol(CHECK_NULL); 346130803Smarcel Method* m = k->find_method(method_name, method_signature); 347130803Smarcel if (m == NULL) { 348130803Smarcel report_error("Can't find method"); 349130803Smarcel } 350130803Smarcel return m; 351130803Smarcel } 352130803Smarcel 353130803Smarcel int get_line(int c) { 354130803Smarcel while(c != EOF) { 355130803Smarcel if (_buffer_pos + 1 >= _buffer_length) { 356130803Smarcel int new_length = _buffer_length * 2; 357130803Smarcel // Next call will throw error in case of OOM. 358130803Smarcel _buffer = REALLOC_RESOURCE_ARRAY(char, _buffer, _buffer_length, new_length); 359130803Smarcel _buffer_length = new_length; 360130803Smarcel } 361130803Smarcel if (c == '\n') { 362130803Smarcel c = getc(_stream); // get next char 363130803Smarcel break; 364130803Smarcel } else if (c == '\r') { 365130803Smarcel // skip LF 366130803Smarcel } else { 367130803Smarcel _buffer[_buffer_pos++] = c; 368130803Smarcel } 369130803Smarcel c = getc(_stream); 370130803Smarcel } 371130803Smarcel // null terminate it, reset the pointer 372130803Smarcel _buffer[_buffer_pos] = '\0'; // NL or EOF 373130803Smarcel _buffer_pos = 0; 374130803Smarcel _bufptr = _buffer; 375130803Smarcel return c; 376130803Smarcel } 377130803Smarcel 378130803Smarcel // Process each line of the replay file executing each command until 379130803Smarcel // the file ends. 380130803Smarcel void process(TRAPS) { 381130803Smarcel int line_no = 1; 382130803Smarcel int c = getc(_stream); 383130803Smarcel while(c != EOF) { 384130803Smarcel c = get_line(c); 385130803Smarcel process_command(THREAD); 386130803Smarcel if (had_error()) { 387130803Smarcel tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message); 388130803Smarcel if (ReplayIgnoreInitErrors) { 389130803Smarcel CLEAR_PENDING_EXCEPTION; 390130803Smarcel _error_message = NULL; 391130803Smarcel } else { 392130803Smarcel return; 393130803Smarcel } 394130803Smarcel } 395130803Smarcel line_no++; 396130803Smarcel } 397130803Smarcel } 398130803Smarcel 399130803Smarcel void process_command(TRAPS) { 400130803Smarcel char* cmd = parse_string(); 401130803Smarcel if (cmd == NULL) { 402130803Smarcel return; 403130803Smarcel } 404130803Smarcel if (strcmp("#", cmd) == 0) { 405130803Smarcel // ignore 406130803Smarcel } else if (strcmp("compile", cmd) == 0) { 407130803Smarcel process_compile(CHECK); 408130803Smarcel } else if (strcmp("ciMethod", cmd) == 0) { 409130803Smarcel process_ciMethod(CHECK); 410130803Smarcel } else if (strcmp("ciMethodData", cmd) == 0) { 411130803Smarcel process_ciMethodData(CHECK); 412130803Smarcel } else if (strcmp("staticfield", cmd) == 0) { 413130803Smarcel process_staticfield(CHECK); 414130803Smarcel } else if (strcmp("ciInstanceKlass", cmd) == 0) { 415130803Smarcel process_ciInstanceKlass(CHECK); 416130803Smarcel } else if (strcmp("instanceKlass", cmd) == 0) { 417130803Smarcel process_instanceKlass(CHECK); 418130803Smarcel#if INCLUDE_JVMTI 419130803Smarcel } else if (strcmp("JvmtiExport", cmd) == 0) { 420130803Smarcel process_JvmtiExport(CHECK); 421130803Smarcel#endif // INCLUDE_JVMTI 422130803Smarcel } else { 423130803Smarcel report_error("unknown command"); 424130803Smarcel } 425130803Smarcel } 426130803Smarcel 427130803Smarcel // validation of comp_level 428130803Smarcel bool is_valid_comp_level(int comp_level) { 429130803Smarcel const int msg_len = 256; 430130803Smarcel char* msg = NULL; 431130803Smarcel if (!is_compile(comp_level)) { 432130803Smarcel msg = NEW_RESOURCE_ARRAY(char, msg_len); 433130803Smarcel jio_snprintf(msg, msg_len, "%d isn't compilation level", comp_level); 434130803Smarcel } else if (!TieredCompilation && (comp_level != CompLevel_highest_tier)) { 435130803Smarcel msg = NEW_RESOURCE_ARRAY(char, msg_len); 436130803Smarcel switch (comp_level) { 437130803Smarcel case CompLevel_simple: 438130803Smarcel jio_snprintf(msg, msg_len, "compilation level %d requires Client VM or TieredCompilation", comp_level); 439130803Smarcel break; 440130803Smarcel case CompLevel_full_optimization: 441130803Smarcel jio_snprintf(msg, msg_len, "compilation level %d requires Server VM", comp_level); 442130803Smarcel break; 443130803Smarcel default: 444130803Smarcel jio_snprintf(msg, msg_len, "compilation level %d requires TieredCompilation", comp_level); 445130803Smarcel } 446130803Smarcel } 447130803Smarcel if (msg != NULL) { 448130803Smarcel report_error(msg); 449130803Smarcel return false; 450130803Smarcel } 451130803Smarcel return true; 452130803Smarcel } 453130803Smarcel 454130803Smarcel // compile <klass> <name> <signature> <entry_bci> <comp_level> inline <count> <depth> <bci> <klass> <name> <signature> ... 455130803Smarcel void* process_inline(ciMethod* imethod, Method* m, int entry_bci, int comp_level, TRAPS) { 456130803Smarcel _imethod = m; 457130803Smarcel _iklass = imethod->holder(); 458130803Smarcel _entry_bci = entry_bci; 459130803Smarcel _comp_level = comp_level; 460130803Smarcel int line_no = 1; 461130803Smarcel int c = getc(_stream); 462130803Smarcel while(c != EOF) { 463130803Smarcel c = get_line(c); 464130803Smarcel // Expecting only lines with "compile" command in inline replay file. 465130803Smarcel char* cmd = parse_string(); 466130803Smarcel if (cmd == NULL || strcmp("compile", cmd) != 0) { 467130803Smarcel return NULL; 468130803Smarcel } 469130803Smarcel process_compile(CHECK_NULL); 470130803Smarcel if (had_error()) { 471130803Smarcel tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message); 472130803Smarcel tty->print_cr("%s", _buffer); 473130803Smarcel return NULL; 474130803Smarcel } 475130803Smarcel if (_ci_inline_records != NULL && _ci_inline_records->length() > 0) { 476130803Smarcel // Found inlining record for the requested method. 477130803Smarcel return _ci_inline_records; 478130803Smarcel } 479130803Smarcel line_no++; 480130803Smarcel } 481130803Smarcel return NULL; 482130803Smarcel } 483130803Smarcel 484130803Smarcel // compile <klass> <name> <signature> <entry_bci> <comp_level> inline <count> <depth> <bci> <klass> <name> <signature> ... 485130803Smarcel void process_compile(TRAPS) { 486130803Smarcel Method* method = parse_method(CHECK); 487130803Smarcel if (had_error()) return; 488130803Smarcel int entry_bci = parse_int("entry_bci"); 489130803Smarcel const char* comp_level_label = "comp_level"; 490130803Smarcel int comp_level = parse_int(comp_level_label); 491130803Smarcel // old version w/o comp_level 492130803Smarcel if (had_error() && (error_message() == comp_level_label)) { 493130803Smarcel // use highest available tier 494130803Smarcel comp_level = TieredCompilation ? TieredStopAtLevel : CompLevel_highest_tier; 495130803Smarcel } 496130803Smarcel if (!is_valid_comp_level(comp_level)) { 497130803Smarcel return; 498130803Smarcel } 499130803Smarcel if (_imethod != NULL) { 500130803Smarcel // Replay Inlining 501130803Smarcel if (entry_bci != _entry_bci || comp_level != _comp_level) { 502130803Smarcel return; 503130803Smarcel } 504130803Smarcel const char* iklass_name = _imethod->method_holder()->name()->as_utf8(); 505130803Smarcel const char* imethod_name = _imethod->name()->as_utf8(); 506130803Smarcel const char* isignature = _imethod->signature()->as_utf8(); 507130803Smarcel const char* klass_name = method->method_holder()->name()->as_utf8(); 508130803Smarcel const char* method_name = method->name()->as_utf8(); 509130803Smarcel const char* signature = method->signature()->as_utf8(); 510130803Smarcel if (strcmp(iklass_name, klass_name) != 0 || 511130803Smarcel strcmp(imethod_name, method_name) != 0 || 512130803Smarcel strcmp(isignature, signature) != 0) { 513130803Smarcel return; 514130803Smarcel } 515130803Smarcel } 516130803Smarcel int inline_count = 0; 517130803Smarcel if (parse_tag_and_count("inline", inline_count)) { 518130803Smarcel // Record inlining data 519130803Smarcel _ci_inline_records = new GrowableArray<ciInlineRecord*>(); 520130803Smarcel for (int i = 0; i < inline_count; i++) { 521130803Smarcel int depth = parse_int("inline_depth"); 522130803Smarcel int bci = parse_int("inline_bci"); 523130803Smarcel if (had_error()) { 524130803Smarcel break; 525130803Smarcel } 526130803Smarcel Method* inl_method = parse_method(CHECK); 527130803Smarcel if (had_error()) { 528130803Smarcel break; 529130803Smarcel } 530130803Smarcel new_ciInlineRecord(inl_method, bci, depth); 531130803Smarcel } 532130803Smarcel } 533130803Smarcel if (_imethod != NULL) { 534130803Smarcel return; // Replay Inlining 535130803Smarcel } 536130803Smarcel InstanceKlass* ik = method->method_holder(); 537130803Smarcel ik->initialize(THREAD); 538130803Smarcel if (HAS_PENDING_EXCEPTION) { 539130803Smarcel oop throwable = PENDING_EXCEPTION; 540130803Smarcel java_lang_Throwable::print(throwable, tty); 541130803Smarcel tty->cr(); 542130803Smarcel if (ReplayIgnoreInitErrors) { 543130803Smarcel CLEAR_PENDING_EXCEPTION; 544130803Smarcel ik->set_init_state(InstanceKlass::fully_initialized); 545130803Smarcel } else { 546130803Smarcel return; 547130803Smarcel } 548130803Smarcel } 549130803Smarcel // Make sure the existence of a prior compile doesn't stop this one 550130803Smarcel CompiledMethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code(); 551130803Smarcel if (nm != NULL) { 552130803Smarcel nm->make_not_entrant(); 553130803Smarcel } 554130803Smarcel replay_state = this; 555130803Smarcel CompileBroker::compile_method(method, entry_bci, comp_level, 556130803Smarcel methodHandle(), 0, CompileTask::Reason_Replay, THREAD); 557130803Smarcel replay_state = NULL; 558130803Smarcel reset(); 559130803Smarcel } 560130803Smarcel 561130803Smarcel // ciMethod <klass> <name> <signature> <invocation_counter> <backedge_counter> <interpreter_invocation_count> <interpreter_throwout_count> <instructions_size> 562130803Smarcel // 563130803Smarcel // 564130803Smarcel void process_ciMethod(TRAPS) { 565130803Smarcel Method* method = parse_method(CHECK); 566130803Smarcel if (had_error()) return; 567130803Smarcel ciMethodRecord* rec = new_ciMethod(method); 568130803Smarcel rec->_invocation_counter = parse_int("invocation_counter"); 569130803Smarcel rec->_backedge_counter = parse_int("backedge_counter"); 570130803Smarcel rec->_interpreter_invocation_count = parse_int("interpreter_invocation_count"); 571130803Smarcel rec->_interpreter_throwout_count = parse_int("interpreter_throwout_count"); 572130803Smarcel rec->_instructions_size = parse_int("instructions_size"); 573130803Smarcel } 574130803Smarcel 575130803Smarcel // ciMethodData <klass> <name> <signature> <state> <current mileage> orig <length> # # ... data <length> # # ... oops <length> # ... methods <length> 576130803Smarcel void process_ciMethodData(TRAPS) { 577130803Smarcel Method* method = parse_method(CHECK); 578130803Smarcel if (had_error()) return; 579130803Smarcel /* just copied from Method, to build interpret data*/ 580130803Smarcel if (ReferencePendingListLocker::is_locked_by_self()) { 581130803Smarcel return; 582130803Smarcel } 583130803Smarcel // To be properly initialized, some profiling in the MDO needs the 584130803Smarcel // method to be rewritten (number of arguments at a call for 585130803Smarcel // instance) 586130803Smarcel method->method_holder()->link_class(CHECK); 587130803Smarcel // methodOopDesc::build_interpreter_method_data(method, CHECK); 588130803Smarcel { 589130803Smarcel // Grab a lock here to prevent multiple 590130803Smarcel // MethodData*s from being created. 591130803Smarcel MutexLocker ml(MethodData_lock, THREAD); 592130803Smarcel if (method->method_data() == NULL) { 593130803Smarcel ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); 594130803Smarcel MethodData* method_data = MethodData::allocate(loader_data, method, CHECK); 595130803Smarcel method->set_method_data(method_data); 596130803Smarcel } 597130803Smarcel } 598130803Smarcel 599130803Smarcel // collect and record all the needed information for later 600130803Smarcel ciMethodDataRecord* rec = new_ciMethodData(method); 601130803Smarcel rec->_state = parse_int("state"); 602130803Smarcel rec->_current_mileage = parse_int("current_mileage"); 603130803Smarcel 604130803Smarcel rec->_orig_data = parse_data("orig", rec->_orig_data_length); 605130803Smarcel if (rec->_orig_data == NULL) { 606130803Smarcel return; 607130803Smarcel } 608130803Smarcel rec->_data = parse_intptr_data("data", rec->_data_length); 609130803Smarcel if (rec->_data == NULL) { 610130803Smarcel return; 611130803Smarcel } 612130803Smarcel if (!parse_tag_and_count("oops", rec->_classes_length)) { 613130803Smarcel return; 614130803Smarcel } 615130803Smarcel rec->_classes = NEW_RESOURCE_ARRAY(Klass*, rec->_classes_length); 616130803Smarcel rec->_classes_offsets = NEW_RESOURCE_ARRAY(int, rec->_classes_length); 617130803Smarcel for (int i = 0; i < rec->_classes_length; i++) { 618130803Smarcel int offset = parse_int("offset"); 619130803Smarcel if (had_error()) { 620130803Smarcel return; 621130803Smarcel } 622130803Smarcel Klass* k = parse_klass(CHECK); 623130803Smarcel rec->_classes_offsets[i] = offset; 624130803Smarcel rec->_classes[i] = k; 625130803Smarcel } 626130803Smarcel 627130803Smarcel if (!parse_tag_and_count("methods", rec->_methods_length)) { 628130803Smarcel return; 629130803Smarcel } 630130803Smarcel rec->_methods = NEW_RESOURCE_ARRAY(Method*, rec->_methods_length); 631130803Smarcel rec->_methods_offsets = NEW_RESOURCE_ARRAY(int, rec->_methods_length); 632130803Smarcel for (int i = 0; i < rec->_methods_length; i++) { 633130803Smarcel int offset = parse_int("offset"); 634130803Smarcel if (had_error()) { 635130803Smarcel return; 636130803Smarcel } 637130803Smarcel Method* m = parse_method(CHECK); 638130803Smarcel rec->_methods_offsets[i] = offset; 639130803Smarcel rec->_methods[i] = m; 640130803Smarcel } 641130803Smarcel } 642130803Smarcel 643130803Smarcel // instanceKlass <name> 644130803Smarcel // 645130803Smarcel // Loads and initializes the klass 'name'. This can be used to 646130803Smarcel // create particular class loading environments 647130803Smarcel void process_instanceKlass(TRAPS) { 648130803Smarcel // just load the referenced class 649130803Smarcel Klass* k = parse_klass(CHECK); 650130803Smarcel } 651130803Smarcel 652130803Smarcel // ciInstanceKlass <name> <is_linked> <is_initialized> <length> tag # # # ... 653130803Smarcel // 654130803Smarcel // Load the klass 'name' and link or initialize it. Verify that the 655130803Smarcel // constant pool is the same length as 'length' and make sure the 656130803Smarcel // constant pool tags are in the same state. 657130803Smarcel void process_ciInstanceKlass(TRAPS) { 658130803Smarcel InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK); 659130803Smarcel int is_linked = parse_int("is_linked"); 660130803Smarcel int is_initialized = parse_int("is_initialized"); 661130803Smarcel int length = parse_int("length"); 662130803Smarcel if (is_initialized) { 663130803Smarcel k->initialize(THREAD); 664130803Smarcel if (HAS_PENDING_EXCEPTION) { 665130803Smarcel oop throwable = PENDING_EXCEPTION; 666130803Smarcel java_lang_Throwable::print(throwable, tty); 667130803Smarcel tty->cr(); 668130803Smarcel if (ReplayIgnoreInitErrors) { 669130803Smarcel CLEAR_PENDING_EXCEPTION; 670130803Smarcel k->set_init_state(InstanceKlass::fully_initialized); 671130803Smarcel } else { 672130803Smarcel return; 673130803Smarcel } 674130803Smarcel } 675130803Smarcel } else if (is_linked) { 676130803Smarcel k->link_class(CHECK); 677130803Smarcel } 678130803Smarcel ConstantPool* cp = k->constants(); 679130803Smarcel if (length != cp->length()) { 680130803Smarcel report_error("constant pool length mismatch: wrong class files?"); 681130803Smarcel return; 682130803Smarcel } 683130803Smarcel 684130803Smarcel int parsed_two_word = 0; 685130803Smarcel for (int i = 1; i < length; i++) { 686130803Smarcel int tag = parse_int("tag"); 687130803Smarcel if (had_error()) { 688130803Smarcel return; 689130803Smarcel } 690130803Smarcel switch (cp->tag_at(i).value()) { 691130803Smarcel case JVM_CONSTANT_UnresolvedClass: { 692130803Smarcel if (tag == JVM_CONSTANT_Class) { 693130803Smarcel tty->print_cr("Resolving klass %s at %d", cp->klass_name_at(i)->as_utf8(), i); 694130803Smarcel Klass* k = cp->klass_at(i, CHECK); 695130803Smarcel } 696130803Smarcel break; 697130803Smarcel } 698130803Smarcel case JVM_CONSTANT_Long: 699130803Smarcel case JVM_CONSTANT_Double: 700130803Smarcel parsed_two_word = i + 1; 701130803Smarcel 702130803Smarcel case JVM_CONSTANT_ClassIndex: 703130803Smarcel case JVM_CONSTANT_StringIndex: 704130803Smarcel case JVM_CONSTANT_String: 705130803Smarcel case JVM_CONSTANT_UnresolvedClassInError: 706130803Smarcel case JVM_CONSTANT_Fieldref: 707130803Smarcel case JVM_CONSTANT_Methodref: 708130803Smarcel case JVM_CONSTANT_InterfaceMethodref: 709130803Smarcel case JVM_CONSTANT_NameAndType: 710130803Smarcel case JVM_CONSTANT_Utf8: 711130803Smarcel case JVM_CONSTANT_Integer: 712130803Smarcel case JVM_CONSTANT_Float: 713130803Smarcel case JVM_CONSTANT_MethodHandle: 714130803Smarcel case JVM_CONSTANT_MethodType: 715130803Smarcel case JVM_CONSTANT_InvokeDynamic: 716130803Smarcel if (tag != cp->tag_at(i).value()) { 717130803Smarcel report_error("tag mismatch: wrong class files?"); 718130803Smarcel return; 719130803Smarcel } 720130803Smarcel break; 721130803Smarcel 722130803Smarcel case JVM_CONSTANT_Class: 723130803Smarcel if (tag == JVM_CONSTANT_Class) { 724130803Smarcel } else if (tag == JVM_CONSTANT_UnresolvedClass) { 725130803Smarcel tty->print_cr("Warning: entry was unresolved in the replay data"); 726130803Smarcel } else { 727130803Smarcel report_error("Unexpected tag"); 728130803Smarcel return; 729130803Smarcel } 730130803Smarcel break; 731130803Smarcel 732130803Smarcel case 0: 733130803Smarcel if (parsed_two_word == i) continue; 734130803Smarcel 735130803Smarcel default: 736130803Smarcel fatal("Unexpected tag: %d", cp->tag_at(i).value()); 737130803Smarcel break; 738130803Smarcel } 739130803Smarcel 740130803Smarcel } 741130803Smarcel } 742130803Smarcel 743130803Smarcel // Initialize a class and fill in the value for a static field. 744130803Smarcel // This is useful when the compile was dependent on the value of 745130803Smarcel // static fields but it's impossible to properly rerun the static 746130803Smarcel // initiailizer. 747130803Smarcel void process_staticfield(TRAPS) { 748130803Smarcel InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK); 749130803Smarcel 750130803Smarcel if (ReplaySuppressInitializers == 0 || 751130803Smarcel ReplaySuppressInitializers == 2 && k->class_loader() == NULL) { 752130803Smarcel return; 753130803Smarcel } 754130803Smarcel 755130803Smarcel assert(k->is_initialized(), "must be"); 756130803Smarcel 757130803Smarcel const char* field_name = parse_escaped_string();; 758130803Smarcel const char* field_signature = parse_string(); 759130803Smarcel fieldDescriptor fd; 760130803Smarcel Symbol* name = SymbolTable::lookup(field_name, (int)strlen(field_name), CHECK); 761130803Smarcel Symbol* sig = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK); 762130803Smarcel if (!k->find_local_field(name, sig, &fd) || 763130803Smarcel !fd.is_static() || 764130803Smarcel fd.has_initial_value()) { 765130803Smarcel report_error(field_name); 766130803Smarcel return; 767130803Smarcel } 768130803Smarcel 769130803Smarcel oop java_mirror = k->java_mirror(); 770130803Smarcel if (field_signature[0] == '[') { 771130803Smarcel int length = parse_int("array length"); 772130803Smarcel oop value = NULL; 773130803Smarcel 774130803Smarcel if (field_signature[1] == '[') { 775130803Smarcel // multi dimensional array 776130803Smarcel ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK); 777130803Smarcel int rank = 0; 778130803Smarcel while (field_signature[rank] == '[') { 779130803Smarcel rank++; 780130803Smarcel } 781130803Smarcel int* dims = NEW_RESOURCE_ARRAY(int, rank); 782130803Smarcel dims[0] = length; 783130803Smarcel for (int i = 1; i < rank; i++) { 784130803Smarcel dims[i] = 1; // These aren't relevant to the compiler 785130803Smarcel } 786130803Smarcel value = kelem->multi_allocate(rank, dims, CHECK); 787130803Smarcel } else { 788130803Smarcel if (strcmp(field_signature, "[B") == 0) { 789130803Smarcel value = oopFactory::new_byteArray(length, CHECK); 790130803Smarcel } else if (strcmp(field_signature, "[Z") == 0) { 791130803Smarcel value = oopFactory::new_boolArray(length, CHECK); 792130803Smarcel } else if (strcmp(field_signature, "[C") == 0) { 793130803Smarcel value = oopFactory::new_charArray(length, CHECK); 794130803Smarcel } else if (strcmp(field_signature, "[S") == 0) { 795130803Smarcel value = oopFactory::new_shortArray(length, CHECK); 796130803Smarcel } else if (strcmp(field_signature, "[F") == 0) { 797130803Smarcel value = oopFactory::new_singleArray(length, CHECK); 798130803Smarcel } else if (strcmp(field_signature, "[D") == 0) { 799130803Smarcel value = oopFactory::new_doubleArray(length, CHECK); 800130803Smarcel } else if (strcmp(field_signature, "[I") == 0) { 801130803Smarcel value = oopFactory::new_intArray(length, CHECK); 802130803Smarcel } else if (strcmp(field_signature, "[J") == 0) { 803130803Smarcel value = oopFactory::new_longArray(length, CHECK); 804130803Smarcel } else if (field_signature[0] == '[' && field_signature[1] == 'L') { 805130803Smarcel KlassHandle kelem = resolve_klass(field_signature + 1, CHECK); 806130803Smarcel value = oopFactory::new_objArray(kelem(), length, CHECK); 807130803Smarcel } else { 808130803Smarcel report_error("unhandled array staticfield"); 809130803Smarcel } 810130803Smarcel } 811130803Smarcel java_mirror->obj_field_put(fd.offset(), value); 812130803Smarcel } else { 813130803Smarcel const char* string_value = parse_escaped_string(); 814130803Smarcel if (strcmp(field_signature, "I") == 0) { 815130803Smarcel int value = atoi(string_value); 816130803Smarcel java_mirror->int_field_put(fd.offset(), value); 817130803Smarcel } else if (strcmp(field_signature, "B") == 0) { 818130803Smarcel int value = atoi(string_value); 819130803Smarcel java_mirror->byte_field_put(fd.offset(), value); 820130803Smarcel } else if (strcmp(field_signature, "C") == 0) { 821130803Smarcel int value = atoi(string_value); 822130803Smarcel java_mirror->char_field_put(fd.offset(), value); 823130803Smarcel } else if (strcmp(field_signature, "S") == 0) { 824130803Smarcel int value = atoi(string_value); 825130803Smarcel java_mirror->short_field_put(fd.offset(), value); 826130803Smarcel } else if (strcmp(field_signature, "Z") == 0) { 827130803Smarcel int value = atoi(string_value); 828130803Smarcel java_mirror->bool_field_put(fd.offset(), value); 829130803Smarcel } else if (strcmp(field_signature, "J") == 0) { 830130803Smarcel jlong value; 831130803Smarcel if (sscanf(string_value, JLONG_FORMAT, &value) != 1) { 832130803Smarcel fprintf(stderr, "Error parsing long: %s\n", string_value); 833130803Smarcel return; 834130803Smarcel } 835130803Smarcel java_mirror->long_field_put(fd.offset(), value); 836130803Smarcel } else if (strcmp(field_signature, "F") == 0) { 837 float value = atof(string_value); 838 java_mirror->float_field_put(fd.offset(), value); 839 } else if (strcmp(field_signature, "D") == 0) { 840 double value = atof(string_value); 841 java_mirror->double_field_put(fd.offset(), value); 842 } else if (strcmp(field_signature, "Ljava/lang/String;") == 0) { 843 Handle value = java_lang_String::create_from_str(string_value, CHECK); 844 java_mirror->obj_field_put(fd.offset(), value()); 845 } else if (field_signature[0] == 'L') { 846 Symbol* klass_name = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK); 847 KlassHandle kelem = resolve_klass(field_signature, CHECK); 848 oop value = InstanceKlass::cast(kelem())->allocate_instance(CHECK); 849 java_mirror->obj_field_put(fd.offset(), value); 850 } else { 851 report_error("unhandled staticfield"); 852 } 853 } 854 } 855 856#if INCLUDE_JVMTI 857 void process_JvmtiExport(TRAPS) { 858 const char* field = parse_string(); 859 bool value = parse_int("JvmtiExport flag") != 0; 860 if (strcmp(field, "can_access_local_variables") == 0) { 861 JvmtiExport::set_can_access_local_variables(value); 862 } else if (strcmp(field, "can_hotswap_or_post_breakpoint") == 0) { 863 JvmtiExport::set_can_hotswap_or_post_breakpoint(value); 864 } else if (strcmp(field, "can_post_on_exceptions") == 0) { 865 JvmtiExport::set_can_post_on_exceptions(value); 866 } else { 867 report_error("Unrecognized JvmtiExport directive"); 868 } 869 } 870#endif // INCLUDE_JVMTI 871 872 // Create and initialize a record for a ciMethod 873 ciMethodRecord* new_ciMethod(Method* method) { 874 ciMethodRecord* rec = NEW_RESOURCE_OBJ(ciMethodRecord); 875 rec->_klass_name = method->method_holder()->name()->as_utf8(); 876 rec->_method_name = method->name()->as_utf8(); 877 rec->_signature = method->signature()->as_utf8(); 878 _ci_method_records.append(rec); 879 return rec; 880 } 881 882 // Lookup data for a ciMethod 883 ciMethodRecord* find_ciMethodRecord(Method* method) { 884 const char* klass_name = method->method_holder()->name()->as_utf8(); 885 const char* method_name = method->name()->as_utf8(); 886 const char* signature = method->signature()->as_utf8(); 887 for (int i = 0; i < _ci_method_records.length(); i++) { 888 ciMethodRecord* rec = _ci_method_records.at(i); 889 if (strcmp(rec->_klass_name, klass_name) == 0 && 890 strcmp(rec->_method_name, method_name) == 0 && 891 strcmp(rec->_signature, signature) == 0) { 892 return rec; 893 } 894 } 895 return NULL; 896 } 897 898 // Create and initialize a record for a ciMethodData 899 ciMethodDataRecord* new_ciMethodData(Method* method) { 900 ciMethodDataRecord* rec = NEW_RESOURCE_OBJ(ciMethodDataRecord); 901 rec->_klass_name = method->method_holder()->name()->as_utf8(); 902 rec->_method_name = method->name()->as_utf8(); 903 rec->_signature = method->signature()->as_utf8(); 904 _ci_method_data_records.append(rec); 905 return rec; 906 } 907 908 // Lookup data for a ciMethodData 909 ciMethodDataRecord* find_ciMethodDataRecord(Method* method) { 910 const char* klass_name = method->method_holder()->name()->as_utf8(); 911 const char* method_name = method->name()->as_utf8(); 912 const char* signature = method->signature()->as_utf8(); 913 for (int i = 0; i < _ci_method_data_records.length(); i++) { 914 ciMethodDataRecord* rec = _ci_method_data_records.at(i); 915 if (strcmp(rec->_klass_name, klass_name) == 0 && 916 strcmp(rec->_method_name, method_name) == 0 && 917 strcmp(rec->_signature, signature) == 0) { 918 return rec; 919 } 920 } 921 return NULL; 922 } 923 924 // Create and initialize a record for a ciInlineRecord 925 ciInlineRecord* new_ciInlineRecord(Method* method, int bci, int depth) { 926 ciInlineRecord* rec = NEW_RESOURCE_OBJ(ciInlineRecord); 927 rec->_klass_name = method->method_holder()->name()->as_utf8(); 928 rec->_method_name = method->name()->as_utf8(); 929 rec->_signature = method->signature()->as_utf8(); 930 rec->_inline_bci = bci; 931 rec->_inline_depth = depth; 932 _ci_inline_records->append(rec); 933 return rec; 934 } 935 936 // Lookup inlining data for a ciMethod 937 ciInlineRecord* find_ciInlineRecord(Method* method, int bci, int depth) { 938 if (_ci_inline_records != NULL) { 939 return find_ciInlineRecord(_ci_inline_records, method, bci, depth); 940 } 941 return NULL; 942 } 943 944 static ciInlineRecord* find_ciInlineRecord(GrowableArray<ciInlineRecord*>* records, 945 Method* method, int bci, int depth) { 946 if (records != NULL) { 947 const char* klass_name = method->method_holder()->name()->as_utf8(); 948 const char* method_name = method->name()->as_utf8(); 949 const char* signature = method->signature()->as_utf8(); 950 for (int i = 0; i < records->length(); i++) { 951 ciInlineRecord* rec = records->at(i); 952 if ((rec->_inline_bci == bci) && 953 (rec->_inline_depth == depth) && 954 (strcmp(rec->_klass_name, klass_name) == 0) && 955 (strcmp(rec->_method_name, method_name) == 0) && 956 (strcmp(rec->_signature, signature) == 0)) { 957 return rec; 958 } 959 } 960 } 961 return NULL; 962 } 963 964 const char* error_message() { 965 return _error_message; 966 } 967 968 void reset() { 969 _error_message = NULL; 970 _ci_method_records.clear(); 971 _ci_method_data_records.clear(); 972 } 973 974 // Take an ascii string contain \u#### escapes and convert it to utf8 975 // in place. 976 static void unescape_string(char* value) { 977 char* from = value; 978 char* to = value; 979 while (*from != '\0') { 980 if (*from != '\\') { 981 *from++ = *to++; 982 } else { 983 switch (from[1]) { 984 case 'u': { 985 from += 2; 986 jchar value=0; 987 for (int i=0; i<4; i++) { 988 char c = *from++; 989 switch (c) { 990 case '0': case '1': case '2': case '3': case '4': 991 case '5': case '6': case '7': case '8': case '9': 992 value = (value << 4) + c - '0'; 993 break; 994 case 'a': case 'b': case 'c': 995 case 'd': case 'e': case 'f': 996 value = (value << 4) + 10 + c - 'a'; 997 break; 998 case 'A': case 'B': case 'C': 999 case 'D': case 'E': case 'F': 1000 value = (value << 4) + 10 + c - 'A'; 1001 break; 1002 default: 1003 ShouldNotReachHere(); 1004 } 1005 } 1006 UNICODE::convert_to_utf8(&value, 1, to); 1007 to++; 1008 break; 1009 } 1010 case 't': *to++ = '\t'; from += 2; break; 1011 case 'n': *to++ = '\n'; from += 2; break; 1012 case 'r': *to++ = '\r'; from += 2; break; 1013 case 'f': *to++ = '\f'; from += 2; break; 1014 default: 1015 ShouldNotReachHere(); 1016 } 1017 } 1018 } 1019 *from = *to; 1020 } 1021}; 1022 1023void ciReplay::replay(TRAPS) { 1024 int exit_code = replay_impl(THREAD); 1025 1026 Threads::destroy_vm(); 1027 1028 vm_exit(exit_code); 1029} 1030 1031void* ciReplay::load_inline_data(ciMethod* method, int entry_bci, int comp_level) { 1032 if (FLAG_IS_DEFAULT(InlineDataFile)) { 1033 tty->print_cr("ERROR: no inline replay data file specified (use -XX:InlineDataFile=inline_pid12345.txt)."); 1034 return NULL; 1035 } 1036 1037 VM_ENTRY_MARK; 1038 // Load and parse the replay data 1039 CompileReplay rp(InlineDataFile, THREAD); 1040 if (!rp.can_replay()) { 1041 tty->print_cr("ciReplay: !rp.can_replay()"); 1042 return NULL; 1043 } 1044 void* data = rp.process_inline(method, method->get_Method(), entry_bci, comp_level, THREAD); 1045 if (HAS_PENDING_EXCEPTION) { 1046 Handle throwable(THREAD, PENDING_EXCEPTION); 1047 CLEAR_PENDING_EXCEPTION; 1048 java_lang_Throwable::print_stack_trace(throwable, tty); 1049 tty->cr(); 1050 return NULL; 1051 } 1052 1053 if (rp.had_error()) { 1054 tty->print_cr("ciReplay: Failed on %s", rp.error_message()); 1055 return NULL; 1056 } 1057 return data; 1058} 1059 1060int ciReplay::replay_impl(TRAPS) { 1061 HandleMark hm; 1062 ResourceMark rm; 1063 1064 if (ReplaySuppressInitializers > 2) { 1065 // ReplaySuppressInitializers > 2 means that we want to allow 1066 // normal VM bootstrap but once we get into the replay itself 1067 // don't allow any intializers to be run. 1068 ReplaySuppressInitializers = 1; 1069 } 1070 1071 if (FLAG_IS_DEFAULT(ReplayDataFile)) { 1072 tty->print_cr("ERROR: no compiler replay data file specified (use -XX:ReplayDataFile=replay_pid12345.txt)."); 1073 return 1; 1074 } 1075 1076 // Load and parse the replay data 1077 CompileReplay rp(ReplayDataFile, THREAD); 1078 int exit_code = 0; 1079 if (rp.can_replay()) { 1080 rp.process(THREAD); 1081 } else { 1082 exit_code = 1; 1083 return exit_code; 1084 } 1085 1086 if (HAS_PENDING_EXCEPTION) { 1087 Handle throwable(THREAD, PENDING_EXCEPTION); 1088 CLEAR_PENDING_EXCEPTION; 1089 java_lang_Throwable::print_stack_trace(throwable, tty); 1090 tty->cr(); 1091 exit_code = 2; 1092 } 1093 1094 if (rp.had_error()) { 1095 tty->print_cr("Failed on %s", rp.error_message()); 1096 exit_code = 1; 1097 } 1098 return exit_code; 1099} 1100 1101void ciReplay::initialize(ciMethodData* m) { 1102 if (replay_state == NULL) { 1103 return; 1104 } 1105 1106 ASSERT_IN_VM; 1107 ResourceMark rm; 1108 1109 Method* method = m->get_MethodData()->method(); 1110 ciMethodDataRecord* rec = replay_state->find_ciMethodDataRecord(method); 1111 if (rec == NULL) { 1112 // This indicates some mismatch with the original environment and 1113 // the replay environment though it's not always enough to 1114 // interfere with reproducing a bug 1115 tty->print_cr("Warning: requesting ciMethodData record for method with no data: "); 1116 method->print_name(tty); 1117 tty->cr(); 1118 } else { 1119 m->_state = rec->_state; 1120 m->_current_mileage = rec->_current_mileage; 1121 if (rec->_data_length != 0) { 1122 assert(m->_data_size + m->_extra_data_size == rec->_data_length * (int)sizeof(rec->_data[0]) || 1123 m->_data_size == rec->_data_length * (int)sizeof(rec->_data[0]), "must agree"); 1124 1125 // Write the correct ciObjects back into the profile data 1126 ciEnv* env = ciEnv::current(); 1127 for (int i = 0; i < rec->_classes_length; i++) { 1128 Klass *k = rec->_classes[i]; 1129 // In case this class pointer is is tagged, preserve the tag 1130 // bits 1131 rec->_data[rec->_classes_offsets[i]] = 1132 ciTypeEntries::with_status(env->get_metadata(k)->as_klass(), rec->_data[rec->_classes_offsets[i]]); 1133 } 1134 for (int i = 0; i < rec->_methods_length; i++) { 1135 Method *m = rec->_methods[i]; 1136 *(ciMetadata**)(rec->_data + rec->_methods_offsets[i]) = 1137 env->get_metadata(m); 1138 } 1139 // Copy the updated profile data into place as intptr_ts 1140#ifdef _LP64 1141 Copy::conjoint_jlongs_atomic((jlong *)rec->_data, (jlong *)m->_data, rec->_data_length); 1142#else 1143 Copy::conjoint_jints_atomic((jint *)rec->_data, (jint *)m->_data, rec->_data_length); 1144#endif 1145 } 1146 1147 // copy in the original header 1148 Copy::conjoint_jbytes(rec->_orig_data, (char*)&m->_orig, rec->_orig_data_length); 1149 } 1150} 1151 1152 1153bool ciReplay::should_not_inline(ciMethod* method) { 1154 if (replay_state == NULL) { 1155 return false; 1156 } 1157 VM_ENTRY_MARK; 1158 // ciMethod without a record shouldn't be inlined. 1159 return replay_state->find_ciMethodRecord(method->get_Method()) == NULL; 1160} 1161 1162bool ciReplay::should_inline(void* data, ciMethod* method, int bci, int inline_depth) { 1163 if (data != NULL) { 1164 GrowableArray<ciInlineRecord*>* records = (GrowableArray<ciInlineRecord*>*)data; 1165 VM_ENTRY_MARK; 1166 // Inline record are ordered by bci and depth. 1167 return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) != NULL; 1168 } else if (replay_state != NULL) { 1169 VM_ENTRY_MARK; 1170 // Inline record are ordered by bci and depth. 1171 return replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth) != NULL; 1172 } 1173 return false; 1174} 1175 1176bool ciReplay::should_not_inline(void* data, ciMethod* method, int bci, int inline_depth) { 1177 if (data != NULL) { 1178 GrowableArray<ciInlineRecord*>* records = (GrowableArray<ciInlineRecord*>*)data; 1179 VM_ENTRY_MARK; 1180 // Inline record are ordered by bci and depth. 1181 return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) == NULL; 1182 } else if (replay_state != NULL) { 1183 VM_ENTRY_MARK; 1184 // Inline record are ordered by bci and depth. 1185 return replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth) == NULL; 1186 } 1187 return false; 1188} 1189 1190void ciReplay::initialize(ciMethod* m) { 1191 if (replay_state == NULL) { 1192 return; 1193 } 1194 1195 ASSERT_IN_VM; 1196 ResourceMark rm; 1197 1198 Method* method = m->get_Method(); 1199 ciMethodRecord* rec = replay_state->find_ciMethodRecord(method); 1200 if (rec == NULL) { 1201 // This indicates some mismatch with the original environment and 1202 // the replay environment though it's not always enough to 1203 // interfere with reproducing a bug 1204 tty->print_cr("Warning: requesting ciMethod record for method with no data: "); 1205 method->print_name(tty); 1206 tty->cr(); 1207 } else { 1208 EXCEPTION_CONTEXT; 1209 // m->_instructions_size = rec->_instructions_size; 1210 m->_instructions_size = -1; 1211 m->_interpreter_invocation_count = rec->_interpreter_invocation_count; 1212 m->_interpreter_throwout_count = rec->_interpreter_throwout_count; 1213 MethodCounters* mcs = method->get_method_counters(CHECK_AND_CLEAR); 1214 guarantee(mcs != NULL, "method counters allocation failed"); 1215 mcs->invocation_counter()->_counter = rec->_invocation_counter; 1216 mcs->backedge_counter()->_counter = rec->_backedge_counter; 1217 } 1218} 1219 1220bool ciReplay::is_loaded(Method* method) { 1221 if (replay_state == NULL) { 1222 return true; 1223 } 1224 1225 ASSERT_IN_VM; 1226 ResourceMark rm; 1227 1228 ciMethodRecord* rec = replay_state->find_ciMethodRecord(method); 1229 return rec != NULL; 1230} 1231#endif // PRODUCT 1232