ciReplay.cpp revision 4594:7b23cb975cf2
1219820Sjeff/* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 2219820Sjeff * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3219820Sjeff * 4219820Sjeff * This code is free software; you can redistribute it and/or modify it 5219820Sjeff * under the terms of the GNU General Public License version 2 only, as 6219820Sjeff * published by the Free Software Foundation. 7219820Sjeff * 8219820Sjeff * This code is distributed in the hope that it will be useful, but WITHOUT 9219820Sjeff * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10219820Sjeff * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11219820Sjeff * version 2 for more details (a copy is included in the LICENSE file that 12219820Sjeff * accompanied this code). 13219820Sjeff * 14219820Sjeff * You should have received a copy of the GNU General Public License version 15219820Sjeff * 2 along with this work; if not, write to the Free Software Foundation, 16219820Sjeff * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17219820Sjeff * 18219820Sjeff * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19219820Sjeff * or visit www.oracle.com if you need additional information or have any 20219820Sjeff * questions. 21219820Sjeff * 22219820Sjeff */ 23219820Sjeff 24219820Sjeff#include "precompiled.hpp" 25219820Sjeff#include "ci/ciMethodData.hpp" 26219820Sjeff#include "ci/ciReplay.hpp" 27219820Sjeff#include "ci/ciUtilities.hpp" 28219820Sjeff#include "compiler/compileBroker.hpp" 29219820Sjeff#include "memory/allocation.inline.hpp" 30219820Sjeff#include "memory/oopFactory.hpp" 31219820Sjeff#include "memory/resourceArea.hpp" 32219820Sjeff#include "utilities/copy.hpp" 33219820Sjeff#include "utilities/macros.hpp" 34219820Sjeff 35219820Sjeff#ifndef PRODUCT 36219820Sjeff 37219820Sjeff// ciReplay 38219820Sjeff 39219820Sjefftypedef struct _ciMethodDataRecord { 40219820Sjeff const char* klass; 41219820Sjeff const char* method; 42219820Sjeff const char* signature; 43219820Sjeff int state; 44219820Sjeff int current_mileage; 45219820Sjeff intptr_t* data; 46219820Sjeff int data_length; 47219820Sjeff char* orig_data; 48219820Sjeff int orig_data_length; 49219820Sjeff int oops_length; 50219820Sjeff jobject* oops_handles; 51219820Sjeff int* oops_offsets; 52219820Sjeff} ciMethodDataRecord; 53219820Sjeff 54219820Sjefftypedef struct _ciMethodRecord { 55219820Sjeff const char* klass; 56219820Sjeff const char* method; 57219820Sjeff const char* signature; 58219820Sjeff int instructions_size; 59219820Sjeff int interpreter_invocation_count; 60219820Sjeff int interpreter_throwout_count; 61219820Sjeff int invocation_counter; 62219820Sjeff int backedge_counter; 63219820Sjeff} ciMethodRecord; 64219820Sjeff 65219820Sjeffclass CompileReplay; 66219820Sjeffstatic CompileReplay* replay_state; 67219820Sjeff 68219820Sjeffclass CompileReplay : public StackObj { 69219820Sjeff private: 70219820Sjeff FILE* stream; 71219820Sjeff Thread* thread; 72219820Sjeff Handle protection_domain; 73219820Sjeff Handle loader; 74219820Sjeff 75219820Sjeff GrowableArray<ciMethodRecord*> ci_method_records; 76219820Sjeff GrowableArray<ciMethodDataRecord*> ci_method_data_records; 77219820Sjeff 78219820Sjeff const char* _error_message; 79219820Sjeff 80219820Sjeff char* bufptr; 81219820Sjeff char* buffer; 82219820Sjeff int buffer_length; 83219820Sjeff int buffer_end; 84219820Sjeff int line_no; 85219820Sjeff 86219820Sjeff public: 87219820Sjeff CompileReplay(const char* filename, TRAPS) { 88219820Sjeff thread = THREAD; 89219820Sjeff loader = Handle(thread, SystemDictionary::java_system_loader()); 90219820Sjeff stream = fopen(filename, "rt"); 91219820Sjeff if (stream == NULL) { 92219820Sjeff fprintf(stderr, "ERROR: Can't open replay file %s\n", filename); 93219820Sjeff } 94219820Sjeff buffer_length = 32; 95219820Sjeff buffer = NEW_RESOURCE_ARRAY(char, buffer_length); 96219820Sjeff _error_message = NULL; 97219820Sjeff 98219820Sjeff test(); 99219820Sjeff } 100219820Sjeff 101219820Sjeff ~CompileReplay() { 102219820Sjeff if (stream != NULL) fclose(stream); 103219820Sjeff } 104219820Sjeff 105219820Sjeff void test() { 106219820Sjeff strcpy(buffer, "1 2 foo 4 bar 0x9 \"this is it\""); 107219820Sjeff bufptr = buffer; 108219820Sjeff assert(parse_int("test") == 1, "what"); 109219820Sjeff assert(parse_int("test") == 2, "what"); 110219820Sjeff assert(strcmp(parse_string(), "foo") == 0, "what"); 111219820Sjeff assert(parse_int("test") == 4, "what"); 112219820Sjeff assert(strcmp(parse_string(), "bar") == 0, "what"); 113219820Sjeff assert(parse_intptr_t("test") == 9, "what"); 114219820Sjeff assert(strcmp(parse_quoted_string(), "this is it") == 0, "what"); 115219820Sjeff } 116219820Sjeff 117219820Sjeff bool had_error() { 118219820Sjeff return _error_message != NULL || thread->has_pending_exception(); 119219820Sjeff } 120219820Sjeff 121219820Sjeff bool can_replay() { 122219820Sjeff return !(stream == NULL || had_error()); 123219820Sjeff } 124219820Sjeff 125219820Sjeff void report_error(const char* msg) { 126219820Sjeff _error_message = msg; 127219820Sjeff // Restore the buffer contents for error reporting 128219820Sjeff for (int i = 0; i < buffer_end; i++) { 129219820Sjeff if (buffer[i] == '\0') buffer[i] = ' '; 130219820Sjeff } 131219820Sjeff } 132219820Sjeff 133219820Sjeff int parse_int(const char* label) { 134219820Sjeff if (had_error()) { 135219820Sjeff return 0; 136219820Sjeff } 137219820Sjeff 138219820Sjeff int v = 0; 139219820Sjeff int read; 140219820Sjeff if (sscanf(bufptr, "%i%n", &v, &read) != 1) { 141219820Sjeff report_error(label); 142219820Sjeff } else { 143219820Sjeff bufptr += read; 144219820Sjeff } 145219820Sjeff return v; 146219820Sjeff } 147219820Sjeff 148219820Sjeff intptr_t parse_intptr_t(const char* label) { 149219820Sjeff if (had_error()) { 150219820Sjeff return 0; 151219820Sjeff } 152219820Sjeff 153219820Sjeff intptr_t v = 0; 154219820Sjeff int read; 155219820Sjeff if (sscanf(bufptr, INTPTR_FORMAT "%n", &v, &read) != 1) { 156219820Sjeff report_error(label); 157219820Sjeff } else { 158219820Sjeff bufptr += read; 159219820Sjeff } 160219820Sjeff return v; 161219820Sjeff } 162219820Sjeff 163219820Sjeff void skip_ws() { 164219820Sjeff // Skip any leading whitespace 165219820Sjeff while (*bufptr == ' ' || *bufptr == '\t') { 166219820Sjeff bufptr++; 167219820Sjeff } 168219820Sjeff } 169219820Sjeff 170219820Sjeff 171219820Sjeff char* scan_and_terminate(char delim) { 172219820Sjeff char* str = bufptr; 173219820Sjeff while (*bufptr != delim && *bufptr != '\0') { 174219820Sjeff bufptr++; 175219820Sjeff } 176219820Sjeff if (*bufptr != '\0') { 177219820Sjeff *bufptr++ = '\0'; 178219820Sjeff } 179219820Sjeff if (bufptr == str) { 180219820Sjeff // nothing here 181219820Sjeff return NULL; 182219820Sjeff } 183219820Sjeff return str; 184219820Sjeff } 185219820Sjeff 186219820Sjeff char* parse_string() { 187219820Sjeff if (had_error()) return NULL; 188219820Sjeff 189219820Sjeff skip_ws(); 190219820Sjeff return scan_and_terminate(' '); 191219820Sjeff } 192219820Sjeff 193219820Sjeff char* parse_quoted_string() { 194219820Sjeff if (had_error()) return NULL; 195219820Sjeff 196219820Sjeff skip_ws(); 197219820Sjeff 198219820Sjeff if (*bufptr == '"') { 199219820Sjeff bufptr++; 200219820Sjeff return scan_and_terminate('"'); 201219820Sjeff } else { 202219820Sjeff return scan_and_terminate(' '); 203219820Sjeff } 204219820Sjeff } 205219820Sjeff 206219820Sjeff const char* parse_escaped_string() { 207219820Sjeff char* result = parse_quoted_string(); 208219820Sjeff if (result != NULL) { 209219820Sjeff unescape_string(result); 210219820Sjeff } 211219820Sjeff return result; 212219820Sjeff } 213219820Sjeff 214219820Sjeff // Look for the tag 'tag' followed by an 215219820Sjeff bool parse_tag_and_count(const char* tag, int& length) { 216219820Sjeff const char* t = parse_string(); 217219820Sjeff if (t == NULL) { 218219820Sjeff return false; 219219820Sjeff } 220219820Sjeff 221219820Sjeff if (strcmp(tag, t) != 0) { 222219820Sjeff report_error(tag); 223219820Sjeff return false; 224219820Sjeff } 225219820Sjeff length = parse_int("parse_tag_and_count"); 226219820Sjeff return !had_error(); 227219820Sjeff } 228219820Sjeff 229219820Sjeff // Parse a sequence of raw data encoded as bytes and return the 230219820Sjeff // resulting data. 231219820Sjeff char* parse_data(const char* tag, int& length) { 232219820Sjeff if (!parse_tag_and_count(tag, length)) { 233219820Sjeff return NULL; 234219820Sjeff } 235219820Sjeff 236219820Sjeff char * result = NEW_RESOURCE_ARRAY(char, length); 237219820Sjeff for (int i = 0; i < length; i++) { 238219820Sjeff int val = parse_int("data"); 239219820Sjeff result[i] = val; 240219820Sjeff } 241219820Sjeff return result; 242219820Sjeff } 243219820Sjeff 244219820Sjeff // Parse a standard chunk of data emitted as: 245219820Sjeff // 'tag' <length> # # ... 246219820Sjeff // Where each # is an intptr_t item 247219820Sjeff intptr_t* parse_intptr_data(const char* tag, int& length) { 248219820Sjeff if (!parse_tag_and_count(tag, length)) { 249219820Sjeff return NULL; 250219820Sjeff } 251219820Sjeff 252219820Sjeff intptr_t* result = NEW_RESOURCE_ARRAY(intptr_t, length); 253219820Sjeff for (int i = 0; i < length; i++) { 254219820Sjeff skip_ws(); 255219820Sjeff intptr_t val = parse_intptr_t("data"); 256219820Sjeff result[i] = val; 257219820Sjeff } 258219820Sjeff return result; 259219820Sjeff } 260219820Sjeff 261219820Sjeff // Parse a possibly quoted version of a symbol into a symbolOop 262219820Sjeff Symbol* parse_symbol(TRAPS) { 263219820Sjeff const char* str = parse_escaped_string(); 264219820Sjeff if (str != NULL) { 265219820Sjeff Symbol* sym = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL); 266219820Sjeff return sym; 267219820Sjeff } 268219820Sjeff return NULL; 269219820Sjeff } 270219820Sjeff 271219820Sjeff // Parse a valid klass name and look it up 272219820Sjeff Klass* parse_klass(TRAPS) { 273219820Sjeff const char* str = parse_escaped_string(); 274219820Sjeff Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL); 275219820Sjeff if (klass_name != NULL) { 276219820Sjeff Klass* k = SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, THREAD); 277219820Sjeff if (HAS_PENDING_EXCEPTION) { 278219820Sjeff oop throwable = PENDING_EXCEPTION; 279219820Sjeff java_lang_Throwable::print(throwable, tty); 280219820Sjeff tty->cr(); 281219820Sjeff report_error(str); 282219820Sjeff return NULL; 283219820Sjeff } 284219820Sjeff return k; 285219820Sjeff } 286219820Sjeff return NULL; 287219820Sjeff } 288219820Sjeff 289219820Sjeff // Lookup a klass 290219820Sjeff Klass* resolve_klass(const char* klass, TRAPS) { 291219820Sjeff Symbol* klass_name = SymbolTable::lookup(klass, (int)strlen(klass), CHECK_NULL); 292219820Sjeff return SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, CHECK_NULL); 293219820Sjeff } 294219820Sjeff 295219820Sjeff // Parse the standard tuple of <klass> <name> <signature> 296219820Sjeff Method* parse_method(TRAPS) { 297219820Sjeff InstanceKlass* k = (InstanceKlass*)parse_klass(CHECK_NULL); 298219820Sjeff Symbol* method_name = parse_symbol(CHECK_NULL); 299219820Sjeff Symbol* method_signature = parse_symbol(CHECK_NULL); 300219820Sjeff Method* m = k->find_method(method_name, method_signature); 301219820Sjeff if (m == NULL) { 302219820Sjeff report_error("can't find method"); 303219820Sjeff } 304219820Sjeff return m; 305219820Sjeff } 306219820Sjeff 307219820Sjeff // Process each line of the replay file executing each command until 308219820Sjeff // the file ends. 309219820Sjeff void process(TRAPS) { 310219820Sjeff line_no = 1; 311219820Sjeff int pos = 0; 312219820Sjeff int c = getc(stream); 313219820Sjeff while(c != EOF) { 314219820Sjeff if (pos + 1 >= buffer_length) { 315219820Sjeff int newl = buffer_length * 2; 316219820Sjeff char* newb = NEW_RESOURCE_ARRAY(char, newl); 317219820Sjeff memcpy(newb, buffer, pos); 318219820Sjeff buffer = newb; 319219820Sjeff buffer_length = newl; 320219820Sjeff } 321219820Sjeff if (c == '\n') { 322219820Sjeff // null terminate it, reset the pointer and process the line 323219820Sjeff buffer[pos] = '\0'; 324219820Sjeff buffer_end = pos++; 325219820Sjeff bufptr = buffer; 326219820Sjeff process_command(CHECK); 327219820Sjeff if (had_error()) { 328219820Sjeff tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message); 329219820Sjeff tty->print_cr("%s", buffer); 330219820Sjeff return; 331219820Sjeff } 332219820Sjeff pos = 0; 333219820Sjeff buffer_end = 0; 334219820Sjeff line_no++; 335219820Sjeff } else if (c == '\r') { 336219820Sjeff // skip LF 337219820Sjeff } else { 338219820Sjeff buffer[pos++] = c; 339219820Sjeff } 340219820Sjeff c = getc(stream); 341219820Sjeff } 342219820Sjeff } 343219820Sjeff 344219820Sjeff void process_command(TRAPS) { 345219820Sjeff char* cmd = parse_string(); 346219820Sjeff if (cmd == NULL) { 347219820Sjeff return; 348219820Sjeff } 349219820Sjeff if (strcmp("#", cmd) == 0) { 350219820Sjeff // ignore 351219820Sjeff } else if (strcmp("compile", cmd) == 0) { 352219820Sjeff process_compile(CHECK); 353219820Sjeff } else if (strcmp("ciMethod", cmd) == 0) { 354219820Sjeff process_ciMethod(CHECK); 355219820Sjeff } else if (strcmp("ciMethodData", cmd) == 0) { 356219820Sjeff process_ciMethodData(CHECK); 357219820Sjeff } else if (strcmp("staticfield", cmd) == 0) { 358219820Sjeff process_staticfield(CHECK); 359219820Sjeff } else if (strcmp("ciInstanceKlass", cmd) == 0) { 360219820Sjeff process_ciInstanceKlass(CHECK); 361219820Sjeff } else if (strcmp("instanceKlass", cmd) == 0) { 362219820Sjeff process_instanceKlass(CHECK); 363219820Sjeff#if INCLUDE_JVMTI 364219820Sjeff } else if (strcmp("JvmtiExport", cmd) == 0) { 365219820Sjeff process_JvmtiExport(CHECK); 366219820Sjeff#endif // INCLUDE_JVMTI 367219820Sjeff } else { 368219820Sjeff report_error("unknown command"); 369219820Sjeff } 370219820Sjeff } 371219820Sjeff 372219820Sjeff // validation of comp_level 373219820Sjeff bool is_valid_comp_level(int comp_level) { 374219820Sjeff const int msg_len = 256; 375219820Sjeff char* msg = NULL; 376219820Sjeff if (!is_compile(comp_level)) { 377219820Sjeff msg = NEW_RESOURCE_ARRAY(char, msg_len); 378219820Sjeff jio_snprintf(msg, msg_len, "%d isn't compilation level", comp_level); 379219820Sjeff } else if (!TieredCompilation && (comp_level != CompLevel_highest_tier)) { 380219820Sjeff msg = NEW_RESOURCE_ARRAY(char, msg_len); 381219820Sjeff switch (comp_level) { 382219820Sjeff case CompLevel_simple: 383219820Sjeff jio_snprintf(msg, msg_len, "compilation level %d requires Client VM or TieredCompilation", comp_level); 384219820Sjeff break; 385219820Sjeff case CompLevel_full_optimization: 386219820Sjeff jio_snprintf(msg, msg_len, "compilation level %d requires Server VM", comp_level); 387219820Sjeff break; 388219820Sjeff default: 389219820Sjeff jio_snprintf(msg, msg_len, "compilation level %d requires TieredCompilation", comp_level); 390219820Sjeff } 391219820Sjeff } 392219820Sjeff if (msg != NULL) { 393219820Sjeff report_error(msg); 394219820Sjeff return false; 395219820Sjeff } 396219820Sjeff return true; 397219820Sjeff } 398219820Sjeff 399219820Sjeff // compile <klass> <name> <signature> <entry_bci> <comp_level> 400219820Sjeff void process_compile(TRAPS) { 401219820Sjeff // methodHandle method; 402219820Sjeff Method* method = parse_method(CHECK); 403219820Sjeff int entry_bci = parse_int("entry_bci"); 404219820Sjeff const char* comp_level_label = "comp_level"; 405219820Sjeff int comp_level = parse_int(comp_level_label); 406219820Sjeff // old version w/o comp_level 407219820Sjeff if (had_error() && (error_message() == comp_level_label)) { 408219820Sjeff comp_level = CompLevel_full_optimization; 409219820Sjeff } 410219820Sjeff if (!is_valid_comp_level(comp_level)) { 411219820Sjeff return; 412219820Sjeff } 413219820Sjeff Klass* k = method->method_holder(); 414219820Sjeff ((InstanceKlass*)k)->initialize(THREAD); 415219820Sjeff if (HAS_PENDING_EXCEPTION) { 416219820Sjeff oop throwable = PENDING_EXCEPTION; 417219820Sjeff java_lang_Throwable::print(throwable, tty); 418219820Sjeff tty->cr(); 419219820Sjeff if (ReplayIgnoreInitErrors) { 420219820Sjeff CLEAR_PENDING_EXCEPTION; 421219820Sjeff ((InstanceKlass*)k)->set_init_state(InstanceKlass::fully_initialized); 422219820Sjeff } else { 423219820Sjeff return; 424219820Sjeff } 425219820Sjeff } 426219820Sjeff // Make sure the existence of a prior compile doesn't stop this one 427219820Sjeff nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code(); 428219820Sjeff if (nm != NULL) { 429219820Sjeff nm->make_not_entrant(); 430219820Sjeff } 431219820Sjeff replay_state = this; 432219820Sjeff CompileBroker::compile_method(method, entry_bci, comp_level, 433219820Sjeff methodHandle(), 0, "replay", THREAD); 434219820Sjeff replay_state = NULL; 435219820Sjeff reset(); 436219820Sjeff } 437219820Sjeff 438219820Sjeff // ciMethod <klass> <name> <signature> <invocation_counter> <backedge_counter> <interpreter_invocation_count> <interpreter_throwout_count> <instructions_size> 439219820Sjeff // 440219820Sjeff // 441219820Sjeff void process_ciMethod(TRAPS) { 442219820Sjeff Method* method = parse_method(CHECK); 443219820Sjeff ciMethodRecord* rec = new_ciMethod(method); 444219820Sjeff rec->invocation_counter = parse_int("invocation_counter"); 445219820Sjeff rec->backedge_counter = parse_int("backedge_counter"); 446219820Sjeff rec->interpreter_invocation_count = parse_int("interpreter_invocation_count"); 447219820Sjeff rec->interpreter_throwout_count = parse_int("interpreter_throwout_count"); 448219820Sjeff rec->instructions_size = parse_int("instructions_size"); 449219820Sjeff } 450219820Sjeff 451219820Sjeff // ciMethodData <klass> <name> <signature> <state> <current mileage> orig <length> # # ... data <length> # # ... oops <length> 452219820Sjeff void process_ciMethodData(TRAPS) { 453219820Sjeff Method* method = parse_method(CHECK); 454219820Sjeff /* jsut copied from Method, to build interpret data*/ 455219820Sjeff if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) { 456219820Sjeff return; 457219820Sjeff } 458219820Sjeff // methodOopDesc::build_interpreter_method_data(method, CHECK); 459219820Sjeff { 460219820Sjeff // Grab a lock here to prevent multiple 461219820Sjeff // MethodData*s from being created. 462219820Sjeff MutexLocker ml(MethodData_lock, THREAD); 463219820Sjeff if (method->method_data() == NULL) { 464219820Sjeff ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); 465219820Sjeff MethodData* method_data = MethodData::allocate(loader_data, method, CHECK); 466219820Sjeff method->set_method_data(method_data); 467219820Sjeff } 468219820Sjeff } 469219820Sjeff 470219820Sjeff // collect and record all the needed information for later 471219820Sjeff ciMethodDataRecord* rec = new_ciMethodData(method); 472219820Sjeff rec->state = parse_int("state"); 473219820Sjeff rec->current_mileage = parse_int("current_mileage"); 474219820Sjeff 475219820Sjeff rec->orig_data = parse_data("orig", rec->orig_data_length); 476219820Sjeff if (rec->orig_data == NULL) { 477219820Sjeff return; 478219820Sjeff } 479219820Sjeff rec->data = parse_intptr_data("data", rec->data_length); 480219820Sjeff if (rec->data == NULL) { 481219820Sjeff return; 482219820Sjeff } 483219820Sjeff if (!parse_tag_and_count("oops", rec->oops_length)) { 484219820Sjeff return; 485219820Sjeff } 486219820Sjeff rec->oops_handles = NEW_RESOURCE_ARRAY(jobject, rec->oops_length); 487219820Sjeff rec->oops_offsets = NEW_RESOURCE_ARRAY(int, rec->oops_length); 488219820Sjeff for (int i = 0; i < rec->oops_length; i++) { 489219820Sjeff int offset = parse_int("offset"); 490219820Sjeff if (had_error()) { 491219820Sjeff return; 492219820Sjeff } 493219820Sjeff Klass* k = parse_klass(CHECK); 494219820Sjeff rec->oops_offsets[i] = offset; 495219820Sjeff rec->oops_handles[i] = (jobject)(new KlassHandle(THREAD, k)); 496219820Sjeff } 497219820Sjeff } 498219820Sjeff 499219820Sjeff // instanceKlass <name> 500219820Sjeff // 501219820Sjeff // Loads and initializes the klass 'name'. This can be used to 502219820Sjeff // create particular class loading environments 503219820Sjeff void process_instanceKlass(TRAPS) { 504219820Sjeff // just load the referenced class 505219820Sjeff Klass* k = parse_klass(CHECK); 506219820Sjeff } 507219820Sjeff 508219820Sjeff // ciInstanceKlass <name> <is_linked> <is_initialized> <length> tag # # # ... 509219820Sjeff // 510219820Sjeff // Load the klass 'name' and link or initialize it. Verify that the 511219820Sjeff // constant pool is the same length as 'length' and make sure the 512219820Sjeff // constant pool tags are in the same state. 513219820Sjeff void process_ciInstanceKlass(TRAPS) { 514219820Sjeff InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK); 515219820Sjeff int is_linked = parse_int("is_linked"); 516219820Sjeff int is_initialized = parse_int("is_initialized"); 517219820Sjeff int length = parse_int("length"); 518219820Sjeff if (is_initialized) { 519219820Sjeff k->initialize(THREAD); 520219820Sjeff if (HAS_PENDING_EXCEPTION) { 521219820Sjeff oop throwable = PENDING_EXCEPTION; 522219820Sjeff java_lang_Throwable::print(throwable, tty); 523219820Sjeff tty->cr(); 524219820Sjeff if (ReplayIgnoreInitErrors) { 525219820Sjeff CLEAR_PENDING_EXCEPTION; 526219820Sjeff k->set_init_state(InstanceKlass::fully_initialized); 527219820Sjeff } else { 528219820Sjeff return; 529219820Sjeff } 530219820Sjeff } 531219820Sjeff } else if (is_linked) { 532219820Sjeff k->link_class(CHECK); 533219820Sjeff } 534219820Sjeff ConstantPool* cp = k->constants(); 535219820Sjeff if (length != cp->length()) { 536219820Sjeff report_error("constant pool length mismatch: wrong class files?"); 537219820Sjeff return; 538219820Sjeff } 539219820Sjeff 540219820Sjeff int parsed_two_word = 0; 541219820Sjeff for (int i = 1; i < length; i++) { 542219820Sjeff int tag = parse_int("tag"); 543219820Sjeff if (had_error()) { 544219820Sjeff return; 545219820Sjeff } 546219820Sjeff switch (cp->tag_at(i).value()) { 547219820Sjeff case JVM_CONSTANT_UnresolvedClass: { 548219820Sjeff if (tag == JVM_CONSTANT_Class) { 549219820Sjeff tty->print_cr("Resolving klass %s at %d", cp->unresolved_klass_at(i)->as_utf8(), i); 550219820Sjeff Klass* k = cp->klass_at(i, CHECK); 551219820Sjeff } 552219820Sjeff break; 553219820Sjeff } 554219820Sjeff case JVM_CONSTANT_Long: 555219820Sjeff case JVM_CONSTANT_Double: 556219820Sjeff parsed_two_word = i + 1; 557219820Sjeff 558219820Sjeff case JVM_CONSTANT_ClassIndex: 559219820Sjeff case JVM_CONSTANT_StringIndex: 560219820Sjeff case JVM_CONSTANT_String: 561219820Sjeff case JVM_CONSTANT_UnresolvedClassInError: 562219820Sjeff case JVM_CONSTANT_Fieldref: 563219820Sjeff case JVM_CONSTANT_Methodref: 564219820Sjeff case JVM_CONSTANT_InterfaceMethodref: 565219820Sjeff case JVM_CONSTANT_NameAndType: 566219820Sjeff case JVM_CONSTANT_Utf8: 567219820Sjeff case JVM_CONSTANT_Integer: 568219820Sjeff case JVM_CONSTANT_Float: 569219820Sjeff if (tag != cp->tag_at(i).value()) { 570219820Sjeff report_error("tag mismatch: wrong class files?"); 571219820Sjeff return; 572219820Sjeff } 573219820Sjeff break; 574219820Sjeff 575219820Sjeff case JVM_CONSTANT_Class: 576219820Sjeff if (tag == JVM_CONSTANT_Class) { 577219820Sjeff } else if (tag == JVM_CONSTANT_UnresolvedClass) { 578219820Sjeff tty->print_cr("Warning: entry was unresolved in the replay data"); 579219820Sjeff } else { 580219820Sjeff report_error("Unexpected tag"); 581219820Sjeff return; 582219820Sjeff } 583219820Sjeff break; 584219820Sjeff 585219820Sjeff case 0: 586219820Sjeff if (parsed_two_word == i) continue; 587219820Sjeff 588219820Sjeff default: 589219820Sjeff fatal(err_msg_res("Unexpected tag: %d", cp->tag_at(i).value())); 590219820Sjeff break; 591219820Sjeff } 592219820Sjeff 593219820Sjeff } 594219820Sjeff } 595219820Sjeff 596219820Sjeff // Initialize a class and fill in the value for a static field. 597219820Sjeff // This is useful when the compile was dependent on the value of 598219820Sjeff // static fields but it's impossible to properly rerun the static 599219820Sjeff // initiailizer. 600219820Sjeff void process_staticfield(TRAPS) { 601219820Sjeff InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK); 602219820Sjeff 603219820Sjeff if (ReplaySuppressInitializers == 0 || 604219820Sjeff ReplaySuppressInitializers == 2 && k->class_loader() == NULL) { 605219820Sjeff return; 606219820Sjeff } 607219820Sjeff 608219820Sjeff assert(k->is_initialized(), "must be"); 609219820Sjeff 610219820Sjeff const char* field_name = parse_escaped_string();; 611219820Sjeff const char* field_signature = parse_string(); 612219820Sjeff fieldDescriptor fd; 613219820Sjeff Symbol* name = SymbolTable::lookup(field_name, (int)strlen(field_name), CHECK); 614219820Sjeff Symbol* sig = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK); 615219820Sjeff if (!k->find_local_field(name, sig, &fd) || 616219820Sjeff !fd.is_static() || 617219820Sjeff fd.has_initial_value()) { 618219820Sjeff report_error(field_name); 619219820Sjeff return; 620219820Sjeff } 621219820Sjeff 622219820Sjeff oop java_mirror = k->java_mirror(); 623219820Sjeff if (field_signature[0] == '[') { 624219820Sjeff int length = parse_int("array length"); 625219820Sjeff oop value = NULL; 626219820Sjeff 627219820Sjeff if (field_signature[1] == '[') { 628219820Sjeff // multi dimensional array 629219820Sjeff ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK); 630219820Sjeff int rank = 0; 631219820Sjeff while (field_signature[rank] == '[') { 632219820Sjeff rank++; 633219820Sjeff } 634219820Sjeff int* dims = NEW_RESOURCE_ARRAY(int, rank); 635219820Sjeff dims[0] = length; 636219820Sjeff for (int i = 1; i < rank; i++) { 637219820Sjeff dims[i] = 1; // These aren't relevant to the compiler 638219820Sjeff } 639219820Sjeff value = kelem->multi_allocate(rank, dims, CHECK); 640219820Sjeff } else { 641219820Sjeff if (strcmp(field_signature, "[B") == 0) { 642219820Sjeff value = oopFactory::new_byteArray(length, CHECK); 643219820Sjeff } else if (strcmp(field_signature, "[Z") == 0) { 644219820Sjeff value = oopFactory::new_boolArray(length, CHECK); 645219820Sjeff } else if (strcmp(field_signature, "[C") == 0) { 646219820Sjeff value = oopFactory::new_charArray(length, CHECK); 647219820Sjeff } else if (strcmp(field_signature, "[S") == 0) { 648219820Sjeff value = oopFactory::new_shortArray(length, CHECK); 649219820Sjeff } else if (strcmp(field_signature, "[F") == 0) { 650219820Sjeff value = oopFactory::new_singleArray(length, CHECK); 651219820Sjeff } else if (strcmp(field_signature, "[D") == 0) { 652219820Sjeff value = oopFactory::new_doubleArray(length, CHECK); 653219820Sjeff } else if (strcmp(field_signature, "[I") == 0) { 654219820Sjeff value = oopFactory::new_intArray(length, CHECK); 655219820Sjeff } else if (strcmp(field_signature, "[J") == 0) { 656219820Sjeff value = oopFactory::new_longArray(length, CHECK); 657219820Sjeff } else if (field_signature[0] == '[' && field_signature[1] == 'L') { 658219820Sjeff KlassHandle kelem = resolve_klass(field_signature + 1, CHECK); 659219820Sjeff value = oopFactory::new_objArray(kelem(), length, CHECK); 660219820Sjeff } else { 661219820Sjeff report_error("unhandled array staticfield"); 662219820Sjeff } 663219820Sjeff } 664219820Sjeff java_mirror->obj_field_put(fd.offset(), value); 665219820Sjeff } else { 666219820Sjeff const char* string_value = parse_escaped_string(); 667219820Sjeff if (strcmp(field_signature, "I") == 0) { 668219820Sjeff int value = atoi(string_value); 669219820Sjeff java_mirror->int_field_put(fd.offset(), value); 670219820Sjeff } else if (strcmp(field_signature, "B") == 0) { 671219820Sjeff int value = atoi(string_value); 672219820Sjeff java_mirror->byte_field_put(fd.offset(), value); 673219820Sjeff } else if (strcmp(field_signature, "C") == 0) { 674219820Sjeff int value = atoi(string_value); 675219820Sjeff java_mirror->char_field_put(fd.offset(), value); 676219820Sjeff } else if (strcmp(field_signature, "S") == 0) { 677219820Sjeff int value = atoi(string_value); 678219820Sjeff java_mirror->short_field_put(fd.offset(), value); 679219820Sjeff } else if (strcmp(field_signature, "Z") == 0) { 680219820Sjeff int value = atol(string_value); 681219820Sjeff java_mirror->bool_field_put(fd.offset(), value); 682219820Sjeff } else if (strcmp(field_signature, "J") == 0) { 683219820Sjeff jlong value; 684219820Sjeff if (sscanf(string_value, JLONG_FORMAT, &value) != 1) { 685219820Sjeff fprintf(stderr, "Error parsing long: %s\n", string_value); 686219820Sjeff return; 687219820Sjeff } 688219820Sjeff java_mirror->long_field_put(fd.offset(), value); 689219820Sjeff } else if (strcmp(field_signature, "F") == 0) { 690219820Sjeff float value = atof(string_value); 691219820Sjeff java_mirror->float_field_put(fd.offset(), value); 692219820Sjeff } else if (strcmp(field_signature, "D") == 0) { 693219820Sjeff double value = atof(string_value); 694219820Sjeff java_mirror->double_field_put(fd.offset(), value); 695219820Sjeff } else if (strcmp(field_signature, "Ljava/lang/String;") == 0) { 696 Handle value = java_lang_String::create_from_str(string_value, CHECK); 697 java_mirror->obj_field_put(fd.offset(), value()); 698 } else if (field_signature[0] == 'L') { 699 Symbol* klass_name = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK); 700 KlassHandle kelem = resolve_klass(field_signature, CHECK); 701 oop value = ((InstanceKlass*)kelem())->allocate_instance(CHECK); 702 java_mirror->obj_field_put(fd.offset(), value); 703 } else { 704 report_error("unhandled staticfield"); 705 } 706 } 707 } 708 709#if INCLUDE_JVMTI 710 void process_JvmtiExport(TRAPS) { 711 const char* field = parse_string(); 712 bool value = parse_int("JvmtiExport flag") != 0; 713 if (strcmp(field, "can_access_local_variables") == 0) { 714 JvmtiExport::set_can_access_local_variables(value); 715 } else if (strcmp(field, "can_hotswap_or_post_breakpoint") == 0) { 716 JvmtiExport::set_can_hotswap_or_post_breakpoint(value); 717 } else if (strcmp(field, "can_post_on_exceptions") == 0) { 718 JvmtiExport::set_can_post_on_exceptions(value); 719 } else { 720 report_error("Unrecognized JvmtiExport directive"); 721 } 722 } 723#endif // INCLUDE_JVMTI 724 725 // Create and initialize a record for a ciMethod 726 ciMethodRecord* new_ciMethod(Method* method) { 727 ciMethodRecord* rec = NEW_RESOURCE_OBJ(ciMethodRecord); 728 rec->klass = method->method_holder()->name()->as_utf8(); 729 rec->method = method->name()->as_utf8(); 730 rec->signature = method->signature()->as_utf8(); 731 ci_method_records.append(rec); 732 return rec; 733 } 734 735 // Lookup data for a ciMethod 736 ciMethodRecord* find_ciMethodRecord(Method* method) { 737 const char* klass_name = method->method_holder()->name()->as_utf8(); 738 const char* method_name = method->name()->as_utf8(); 739 const char* signature = method->signature()->as_utf8(); 740 for (int i = 0; i < ci_method_records.length(); i++) { 741 ciMethodRecord* rec = ci_method_records.at(i); 742 if (strcmp(rec->klass, klass_name) == 0 && 743 strcmp(rec->method, method_name) == 0 && 744 strcmp(rec->signature, signature) == 0) { 745 return rec; 746 } 747 } 748 return NULL; 749 } 750 751 // Create and initialize a record for a ciMethodData 752 ciMethodDataRecord* new_ciMethodData(Method* method) { 753 ciMethodDataRecord* rec = NEW_RESOURCE_OBJ(ciMethodDataRecord); 754 rec->klass = method->method_holder()->name()->as_utf8(); 755 rec->method = method->name()->as_utf8(); 756 rec->signature = method->signature()->as_utf8(); 757 ci_method_data_records.append(rec); 758 return rec; 759 } 760 761 // Lookup data for a ciMethodData 762 ciMethodDataRecord* find_ciMethodDataRecord(Method* method) { 763 const char* klass_name = method->method_holder()->name()->as_utf8(); 764 const char* method_name = method->name()->as_utf8(); 765 const char* signature = method->signature()->as_utf8(); 766 for (int i = 0; i < ci_method_data_records.length(); i++) { 767 ciMethodDataRecord* rec = ci_method_data_records.at(i); 768 if (strcmp(rec->klass, klass_name) == 0 && 769 strcmp(rec->method, method_name) == 0 && 770 strcmp(rec->signature, signature) == 0) { 771 return rec; 772 } 773 } 774 return NULL; 775 } 776 777 const char* error_message() { 778 return _error_message; 779 } 780 781 void reset() { 782 _error_message = NULL; 783 ci_method_records.clear(); 784 ci_method_data_records.clear(); 785 } 786 787 // Take an ascii string contain \u#### escapes and convert it to utf8 788 // in place. 789 static void unescape_string(char* value) { 790 char* from = value; 791 char* to = value; 792 while (*from != '\0') { 793 if (*from != '\\') { 794 *from++ = *to++; 795 } else { 796 switch (from[1]) { 797 case 'u': { 798 from += 2; 799 jchar value=0; 800 for (int i=0; i<4; i++) { 801 char c = *from++; 802 switch (c) { 803 case '0': case '1': case '2': case '3': case '4': 804 case '5': case '6': case '7': case '8': case '9': 805 value = (value << 4) + c - '0'; 806 break; 807 case 'a': case 'b': case 'c': 808 case 'd': case 'e': case 'f': 809 value = (value << 4) + 10 + c - 'a'; 810 break; 811 case 'A': case 'B': case 'C': 812 case 'D': case 'E': case 'F': 813 value = (value << 4) + 10 + c - 'A'; 814 break; 815 default: 816 ShouldNotReachHere(); 817 } 818 } 819 UNICODE::convert_to_utf8(&value, 1, to); 820 to++; 821 break; 822 } 823 case 't': *to++ = '\t'; from += 2; break; 824 case 'n': *to++ = '\n'; from += 2; break; 825 case 'r': *to++ = '\r'; from += 2; break; 826 case 'f': *to++ = '\f'; from += 2; break; 827 default: 828 ShouldNotReachHere(); 829 } 830 } 831 } 832 *from = *to; 833 } 834}; 835 836void ciReplay::replay(TRAPS) { 837 int exit_code = replay_impl(THREAD); 838 839 Threads::destroy_vm(); 840 841 vm_exit(exit_code); 842} 843 844int ciReplay::replay_impl(TRAPS) { 845 HandleMark hm; 846 ResourceMark rm; 847 // Make sure we don't run with background compilation 848 BackgroundCompilation = false; 849 850 if (ReplaySuppressInitializers > 2) { 851 // ReplaySuppressInitializers > 2 means that we want to allow 852 // normal VM bootstrap but once we get into the replay itself 853 // don't allow any intializers to be run. 854 ReplaySuppressInitializers = 1; 855 } 856 857 if (FLAG_IS_DEFAULT(ReplayDataFile)) { 858 tty->print_cr("ERROR: no compiler replay data file specified (use -XX:ReplayDataFile=replay_pid12345.txt)."); 859 return 1; 860 } 861 862 // Load and parse the replay data 863 CompileReplay rp(ReplayDataFile, THREAD); 864 int exit_code = 0; 865 if (rp.can_replay()) { 866 rp.process(THREAD); 867 } else { 868 exit_code = 1; 869 return exit_code; 870 } 871 872 if (HAS_PENDING_EXCEPTION) { 873 oop throwable = PENDING_EXCEPTION; 874 CLEAR_PENDING_EXCEPTION; 875 java_lang_Throwable::print(throwable, tty); 876 tty->cr(); 877 java_lang_Throwable::print_stack_trace(throwable, tty); 878 tty->cr(); 879 exit_code = 2; 880 } 881 882 if (rp.had_error()) { 883 tty->print_cr("Failed on %s", rp.error_message()); 884 exit_code = 1; 885 } 886 return exit_code; 887} 888 889 890void ciReplay::initialize(ciMethodData* m) { 891 if (replay_state == NULL) { 892 return; 893 } 894 895 ASSERT_IN_VM; 896 ResourceMark rm; 897 898 Method* method = m->get_MethodData()->method(); 899 ciMethodDataRecord* rec = replay_state->find_ciMethodDataRecord(method); 900 if (rec == NULL) { 901 // This indicates some mismatch with the original environment and 902 // the replay environment though it's not always enough to 903 // interfere with reproducing a bug 904 tty->print_cr("Warning: requesting ciMethodData record for method with no data: "); 905 method->print_name(tty); 906 tty->cr(); 907 } else { 908 m->_state = rec->state; 909 m->_current_mileage = rec->current_mileage; 910 if (rec->data_length != 0) { 911 assert(m->_data_size == rec->data_length * (int)sizeof(rec->data[0]), "must agree"); 912 913 // Write the correct ciObjects back into the profile data 914 ciEnv* env = ciEnv::current(); 915 for (int i = 0; i < rec->oops_length; i++) { 916 KlassHandle *h = (KlassHandle *)rec->oops_handles[i]; 917 *(ciMetadata**)(rec->data + rec->oops_offsets[i]) = 918 env->get_metadata((*h)()); 919 } 920 // Copy the updated profile data into place as intptr_ts 921#ifdef _LP64 922 Copy::conjoint_jlongs_atomic((jlong *)rec->data, (jlong *)m->_data, rec->data_length); 923#else 924 Copy::conjoint_jints_atomic((jint *)rec->data, (jint *)m->_data, rec->data_length); 925#endif 926 } 927 928 // copy in the original header 929 Copy::conjoint_jbytes(rec->orig_data, (char*)&m->_orig, rec->orig_data_length); 930 } 931} 932 933 934bool ciReplay::should_not_inline(ciMethod* method) { 935 if (replay_state == NULL) { 936 return false; 937 } 938 939 VM_ENTRY_MARK; 940 // ciMethod without a record shouldn't be inlined. 941 return replay_state->find_ciMethodRecord(method->get_Method()) == NULL; 942} 943 944 945void ciReplay::initialize(ciMethod* m) { 946 if (replay_state == NULL) { 947 return; 948 } 949 950 ASSERT_IN_VM; 951 ResourceMark rm; 952 953 Method* method = m->get_Method(); 954 ciMethodRecord* rec = replay_state->find_ciMethodRecord(method); 955 if (rec == NULL) { 956 // This indicates some mismatch with the original environment and 957 // the replay environment though it's not always enough to 958 // interfere with reproducing a bug 959 tty->print_cr("Warning: requesting ciMethod record for method with no data: "); 960 method->print_name(tty); 961 tty->cr(); 962 } else { 963 EXCEPTION_CONTEXT; 964 MethodCounters* mcs = method->method_counters(); 965 // m->_instructions_size = rec->instructions_size; 966 m->_instructions_size = -1; 967 m->_interpreter_invocation_count = rec->interpreter_invocation_count; 968 m->_interpreter_throwout_count = rec->interpreter_throwout_count; 969 if (mcs == NULL) { 970 mcs = Method::build_method_counters(method, CHECK_AND_CLEAR); 971 } 972 mcs->invocation_counter()->_counter = rec->invocation_counter; 973 mcs->backedge_counter()->_counter = rec->backedge_counter; 974 } 975} 976 977bool ciReplay::is_loaded(Method* method) { 978 if (replay_state == NULL) { 979 return true; 980 } 981 982 ASSERT_IN_VM; 983 ResourceMark rm; 984 985 ciMethodRecord* rec = replay_state->find_ciMethodRecord(method); 986 return rec != NULL; 987} 988#endif // PRODUCT 989