src/share/vm/ci/ciReplay.cpp

Mon, 12 Nov 2012 14:03:53 -0800

author
minqi
date
Mon, 12 Nov 2012 14:03:53 -0800
changeset 4267
bd7a7ce2e264
child 4304
90273fc0a981
permissions
-rw-r--r--

6830717: replay of compilations would help with debugging
Summary: When java process crashed in compiler thread, repeat the compilation process will help finding root cause. This is done with using SA dump application class data and replay data from core dump, then use debug version of jvm to recompile the problematic java method.
Reviewed-by: kvn, twisti, sspitsyn
Contributed-by: yumin.qi@oracle.com

     1 /* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  *
     4  * This code is free software; you can redistribute it and/or modify it
     5  * under the terms of the GNU General Public License version 2 only, as
     6  * published by the Free Software Foundation.
     7  *
     8  * This code is distributed in the hope that it will be useful, but WITHOUT
     9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    11  * version 2 for more details (a copy is included in the LICENSE file that
    12  * accompanied this code).
    13  *
    14  * You should have received a copy of the GNU General Public License version
    15  * 2 along with this work; if not, write to the Free Software Foundation,
    16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    17  *
    18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    19  * or visit www.oracle.com if you need additional information or have any
    20  * questions.
    21  *
    22  */
    24 #include "precompiled.hpp"
    25 #include "ci/ciMethodData.hpp"
    26 #include "ci/ciReplay.hpp"
    27 #include "ci/ciUtilities.hpp"
    28 #include "compiler/compileBroker.hpp"
    29 #include "memory/allocation.inline.hpp"
    30 #include "memory/oopFactory.hpp"
    31 #include "memory/resourceArea.hpp"
    32 #include "utilities/copy.hpp"
    34 #ifdef ASSERT
    36 // ciReplay
    38 typedef struct _ciMethodDataRecord {
    39   const char* klass;
    40   const char* method;
    41   const char* signature;
    42   int state;
    43   int current_mileage;
    44   intptr_t* data;
    45   int data_length;
    46   char* orig_data;
    47   int orig_data_length;
    48   int oops_length;
    49   jobject* oops_handles;
    50   int* oops_offsets;
    51 } ciMethodDataRecord;
    53 typedef struct _ciMethodRecord {
    54   const char* klass;
    55   const char* method;
    56   const char* signature;
    57   int instructions_size;
    58   int interpreter_invocation_count;
    59   int interpreter_throwout_count;
    60   int invocation_counter;
    61   int backedge_counter;
    62 } ciMethodRecord;
    64 class CompileReplay;
    65 static CompileReplay* replay_state;
    67 class CompileReplay : public StackObj {
    68  private:
    69   FILE*   stream;
    70   Thread* thread;
    71   Handle  protection_domain;
    72   Handle  loader;
    74   GrowableArray<ciMethodRecord*>     ci_method_records;
    75   GrowableArray<ciMethodDataRecord*> ci_method_data_records;
    77   const char* _error_message;
    79   char* bufptr;
    80   char* buffer;
    81   int   buffer_length;
    82   int   buffer_end;
    83   int   line_no;
    85  public:
    86   CompileReplay(const char* filename, TRAPS) {
    87     thread = THREAD;
    88     loader = Handle(thread, SystemDictionary::java_system_loader());
    89     stream = fopen(filename, "rt");
    90     if (stream == NULL) {
    91       fprintf(stderr, "Can't open replay file %s\n", filename);
    92     }
    93     buffer_length = 32;
    94     buffer = NEW_RESOURCE_ARRAY(char, buffer_length);
    95     _error_message = NULL;
    97     test();
    98   }
   100   ~CompileReplay() {
   101     if (stream != NULL) fclose(stream);
   102   }
   104   void test() {
   105     strcpy(buffer, "1 2 foo 4 bar 0x9 \"this is it\"");
   106     bufptr = buffer;
   107     assert(parse_int("test") == 1, "what");
   108     assert(parse_int("test") == 2, "what");
   109     assert(strcmp(parse_string(), "foo") == 0, "what");
   110     assert(parse_int("test") == 4, "what");
   111     assert(strcmp(parse_string(), "bar") == 0, "what");
   112     assert(parse_intptr_t("test") == 9, "what");
   113     assert(strcmp(parse_quoted_string(), "this is it") == 0, "what");
   114   }
   116   bool had_error() {
   117     return _error_message != NULL || thread->has_pending_exception();
   118   }
   120   bool can_replay() {
   121     return !(stream == NULL || had_error());
   122   }
   124   void report_error(const char* msg) {
   125     _error_message = msg;
   126     // Restore the buffer contents for error reporting
   127     for (int i = 0; i < buffer_end; i++) {
   128       if (buffer[i] == '\0') buffer[i] = ' ';
   129     }
   130   }
   132   int parse_int(const char* label) {
   133     if (had_error()) {
   134       return 0;
   135     }
   137     int v = 0;
   138     int read;
   139     if (sscanf(bufptr, "%i%n", &v, &read) != 1) {
   140       report_error(label);
   141     } else {
   142       bufptr += read;
   143     }
   144     return v;
   145   }
   147   intptr_t parse_intptr_t(const char* label) {
   148     if (had_error()) {
   149       return 0;
   150     }
   152     intptr_t v = 0;
   153     int read;
   154     if (sscanf(bufptr, INTPTR_FORMAT "%n", &v, &read) != 1) {
   155       report_error(label);
   156     } else {
   157       bufptr += read;
   158     }
   159     return v;
   160   }
   162   void skip_ws() {
   163     // Skip any leading whitespace
   164     while (*bufptr == ' ' || *bufptr == '\t') {
   165       bufptr++;
   166     }
   167   }
   170   char* scan_and_terminate(char delim) {
   171     char* str = bufptr;
   172     while (*bufptr != delim && *bufptr != '\0') {
   173       bufptr++;
   174     }
   175     if (*bufptr != '\0') {
   176       *bufptr++ = '\0';
   177     }
   178     if (bufptr == str) {
   179       // nothing here
   180       return NULL;
   181     }
   182     return str;
   183   }
   185   char* parse_string() {
   186     if (had_error()) return NULL;
   188     skip_ws();
   189     return scan_and_terminate(' ');
   190   }
   192   char* parse_quoted_string() {
   193     if (had_error()) return NULL;
   195     skip_ws();
   197     if (*bufptr == '"') {
   198       bufptr++;
   199       return scan_and_terminate('"');
   200     } else {
   201       return scan_and_terminate(' ');
   202     }
   203   }
   205   const char* parse_escaped_string() {
   206     char* result = parse_quoted_string();
   207     if (result != NULL) {
   208       unescape_string(result);
   209     }
   210     return result;
   211   }
   213   // Look for the tag 'tag' followed by an
   214   bool parse_tag_and_count(const char* tag, int& length) {
   215     const char* t = parse_string();
   216     if (t == NULL) {
   217       return false;
   218     }
   220     if (strcmp(tag, t) != 0) {
   221       report_error(tag);
   222       return false;
   223     }
   224     length = parse_int("parse_tag_and_count");
   225     return !had_error();
   226   }
   228   // Parse a sequence of raw data encoded as bytes and return the
   229   // resulting data.
   230   char* parse_data(const char* tag, int& length) {
   231     if (!parse_tag_and_count(tag, length)) {
   232       return NULL;
   233     }
   235     char * result = NEW_RESOURCE_ARRAY(char, length);
   236     for (int i = 0; i < length; i++) {
   237       int val = parse_int("data");
   238       result[i] = val;
   239     }
   240     return result;
   241   }
   243   // Parse a standard chunk of data emitted as:
   244   //   'tag' <length> # # ...
   245   // Where each # is an intptr_t item
   246   intptr_t* parse_intptr_data(const char* tag, int& length) {
   247     if (!parse_tag_and_count(tag, length)) {
   248       return NULL;
   249     }
   251     intptr_t* result = NEW_RESOURCE_ARRAY(intptr_t, length);
   252     for (int i = 0; i < length; i++) {
   253       skip_ws();
   254       intptr_t val = parse_intptr_t("data");
   255       result[i] = val;
   256     }
   257     return result;
   258   }
   260   // Parse a possibly quoted version of a symbol into a symbolOop
   261   Symbol* parse_symbol(TRAPS) {
   262     const char* str = parse_escaped_string();
   263     if (str != NULL) {
   264       Symbol* sym = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
   265       return sym;
   266     }
   267     return NULL;
   268   }
   270   // Parse a valid klass name and look it up
   271   Klass* parse_klass(TRAPS) {
   272     const char* str = parse_escaped_string();
   273     Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
   274     if (klass_name != NULL) {
   275       Klass* k = SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, THREAD);
   276       if (HAS_PENDING_EXCEPTION) {
   277         oop throwable = PENDING_EXCEPTION;
   278         java_lang_Throwable::print(throwable, tty);
   279         tty->cr();
   280         report_error(str);
   281         return NULL;
   282       }
   283       return k;
   284     }
   285     return NULL;
   286   }
   288   // Lookup a klass
   289   Klass* resolve_klass(const char* klass, TRAPS) {
   290     Symbol* klass_name = SymbolTable::lookup(klass, (int)strlen(klass), CHECK_NULL);
   291     return SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, CHECK_NULL);
   292   }
   294   // Parse the standard tuple of <klass> <name> <signature>
   295   Method* parse_method(TRAPS) {
   296     InstanceKlass* k = (InstanceKlass*)parse_klass(CHECK_NULL);
   297     Symbol* method_name = parse_symbol(CHECK_NULL);
   298     Symbol* method_signature = parse_symbol(CHECK_NULL);
   299     Method* m = k->find_method(method_name, method_signature);
   300     if (m == NULL) {
   301       report_error("can't find method");
   302     }
   303     return m;
   304   }
   306   // Process each line of the replay file executing each command until
   307   // the file ends.
   308   void process(TRAPS) {
   309     line_no = 1;
   310     int pos = 0;
   311     int c = getc(stream);
   312     while(c != EOF) {
   313       if (pos + 1 >= buffer_length) {
   314         int newl = buffer_length * 2;
   315         char* newb = NEW_RESOURCE_ARRAY(char, newl);
   316         memcpy(newb, buffer, pos);
   317         buffer = newb;
   318         buffer_length = newl;
   319       }
   320       if (c == '\n') {
   321         // null terminate it, reset the pointer and process the line
   322         buffer[pos] = '\0';
   323         buffer_end = pos++;
   324         bufptr = buffer;
   325         process_command(CHECK);
   326         if (had_error()) {
   327           tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message);
   328           tty->print_cr("%s", buffer);
   329           assert(false, "error");
   330           return;
   331         }
   332         pos = 0;
   333         buffer_end = 0;
   334         line_no++;
   335       } else if (c == '\r') {
   336         // skip LF
   337       } else {
   338         buffer[pos++] = c;
   339       }
   340       c = getc(stream);
   341     }
   342   }
   344   void process_command(TRAPS) {
   345     char* cmd = parse_string();
   346     if (cmd == NULL) {
   347       return;
   348     }
   349     if (strcmp("#", cmd) == 0) {
   350       // ignore
   351     } else if (strcmp("compile", cmd) == 0) {
   352       process_compile(CHECK);
   353     } else if (strcmp("ciMethod", cmd) == 0) {
   354       process_ciMethod(CHECK);
   355     } else if (strcmp("ciMethodData", cmd) == 0) {
   356       process_ciMethodData(CHECK);
   357     } else if (strcmp("staticfield", cmd) == 0) {
   358       process_staticfield(CHECK);
   359     } else if (strcmp("ciInstanceKlass", cmd) == 0) {
   360       process_ciInstanceKlass(CHECK);
   361     } else if (strcmp("instanceKlass", cmd) == 0) {
   362       process_instanceKlass(CHECK);
   363 #if INCLUDE_JVMTI
   364     } else if (strcmp("JvmtiExport", cmd) == 0) {
   365       process_JvmtiExport(CHECK);
   366 #endif // INCLUDE_JVMTI
   367     } else {
   368       report_error("unknown command");
   369     }
   370   }
   372   // compile <klass> <name> <signature> <entry_bci>
   373   void process_compile(TRAPS) {
   374     // methodHandle method;
   375     Method* method = parse_method(CHECK);
   376     int entry_bci = parse_int("entry_bci");
   377     Klass* k = method->method_holder();
   378     ((InstanceKlass*)k)->initialize(THREAD);
   379     if (HAS_PENDING_EXCEPTION) {
   380       oop throwable = PENDING_EXCEPTION;
   381       java_lang_Throwable::print(throwable, tty);
   382       tty->cr();
   383       if (ReplayIgnoreInitErrors) {
   384         CLEAR_PENDING_EXCEPTION;
   385         ((InstanceKlass*)k)->set_init_state(InstanceKlass::fully_initialized);
   386       } else {
   387         return;
   388       }
   389     }
   390     // Make sure the existence of a prior compile doesn't stop this one
   391     nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, CompLevel_full_optimization, true) : method->code();
   392     if (nm != NULL) {
   393       nm->make_not_entrant();
   394     }
   395     replay_state = this;
   396     CompileBroker::compile_method(method, entry_bci, CompLevel_full_optimization,
   397                                   methodHandle(), 0, "replay", THREAD);
   398     replay_state = NULL;
   399     reset();
   400   }
   402   // ciMethod <klass> <name> <signature> <invocation_counter> <backedge_counter> <interpreter_invocation_count> <interpreter_throwout_count> <instructions_size>
   403   //
   404   //
   405   void process_ciMethod(TRAPS) {
   406     Method* method = parse_method(CHECK);
   407     ciMethodRecord* rec = new_ciMethod(method);
   408     rec->invocation_counter = parse_int("invocation_counter");
   409     rec->backedge_counter = parse_int("backedge_counter");
   410     rec->interpreter_invocation_count = parse_int("interpreter_invocation_count");
   411     rec->interpreter_throwout_count = parse_int("interpreter_throwout_count");
   412     rec->instructions_size = parse_int("instructions_size");
   413   }
   415   // ciMethodData <klass> <name> <signature> <state> <current mileage> orig <length> # # ... data <length> # # ... oops <length>
   416   void process_ciMethodData(TRAPS) {
   417     Method* method = parse_method(CHECK);
   418     /* jsut copied from Method, to build interpret data*/
   419     if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) {
   420       return;
   421     }
   422     // methodOopDesc::build_interpreter_method_data(method, CHECK);
   423     {
   424       // Grab a lock here to prevent multiple
   425       // MethodData*s from being created.
   426       MutexLocker ml(MethodData_lock, THREAD);
   427       if (method->method_data() == NULL) {
   428         ClassLoaderData* loader_data = method->method_holder()->class_loader_data();
   429         MethodData* method_data = MethodData::allocate(loader_data, method, CHECK);
   430         method->set_method_data(method_data);
   431       }
   432     }
   434     // collect and record all the needed information for later
   435     ciMethodDataRecord* rec = new_ciMethodData(method);
   436     rec->state = parse_int("state");
   437     rec->current_mileage = parse_int("current_mileage");
   439     rec->orig_data = parse_data("orig", rec->orig_data_length);
   440     if (rec->orig_data == NULL) {
   441       return;
   442     }
   443     rec->data = parse_intptr_data("data", rec->data_length);
   444     if (rec->data == NULL) {
   445       return;
   446     }
   447     if (!parse_tag_and_count("oops", rec->oops_length)) {
   448       return;
   449     }
   450     rec->oops_handles = NEW_RESOURCE_ARRAY(jobject, rec->oops_length);
   451     rec->oops_offsets = NEW_RESOURCE_ARRAY(int, rec->oops_length);
   452     for (int i = 0; i < rec->oops_length; i++) {
   453       int offset = parse_int("offset");
   454       if (had_error()) {
   455         return;
   456       }
   457       Klass* k = parse_klass(CHECK);
   458       rec->oops_offsets[i] = offset;
   459       rec->oops_handles[i] = (jobject)(new KlassHandle(THREAD, k));
   460     }
   461   }
   463   // instanceKlass <name>
   464   //
   465   // Loads and initializes the klass 'name'.  This can be used to
   466   // create particular class loading environments
   467   void process_instanceKlass(TRAPS) {
   468     // just load the referenced class
   469     Klass* k = parse_klass(CHECK);
   470   }
   472   // ciInstanceKlass <name> <is_linked> <is_initialized> <length> tag # # # ...
   473   //
   474   // Load the klass 'name' and link or initialize it.  Verify that the
   475   // constant pool is the same length as 'length' and make sure the
   476   // constant pool tags are in the same state.
   477   void process_ciInstanceKlass(TRAPS) {
   478     InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK);
   479     int is_linked = parse_int("is_linked");
   480     int is_initialized = parse_int("is_initialized");
   481     int length = parse_int("length");
   482     if (is_initialized) {
   483       k->initialize(THREAD);
   484       if (HAS_PENDING_EXCEPTION) {
   485         oop throwable = PENDING_EXCEPTION;
   486         java_lang_Throwable::print(throwable, tty);
   487         tty->cr();
   488         if (ReplayIgnoreInitErrors) {
   489           CLEAR_PENDING_EXCEPTION;
   490           k->set_init_state(InstanceKlass::fully_initialized);
   491         } else {
   492           return;
   493         }
   494       }
   495     } else if (is_linked) {
   496       k->link_class(CHECK);
   497     }
   498     ConstantPool* cp = k->constants();
   499     if (length != cp->length()) {
   500       report_error("constant pool length mismatch: wrong class files?");
   501       return;
   502     }
   504     int parsed_two_word = 0;
   505     for (int i = 1; i < length; i++) {
   506       int tag = parse_int("tag");
   507       if (had_error()) {
   508         return;
   509       }
   510       switch (cp->tag_at(i).value()) {
   511         case JVM_CONSTANT_UnresolvedClass: {
   512           if (tag == JVM_CONSTANT_Class) {
   513             tty->print_cr("Resolving klass %s at %d", cp->unresolved_klass_at(i)->as_utf8(), i);
   514             Klass* k = cp->klass_at(i, CHECK);
   515           }
   516           break;
   517         }
   518         case JVM_CONSTANT_Long:
   519         case JVM_CONSTANT_Double:
   520           parsed_two_word = i + 1;
   522         case JVM_CONSTANT_ClassIndex:
   523         case JVM_CONSTANT_StringIndex:
   524         case JVM_CONSTANT_String:
   525         case JVM_CONSTANT_UnresolvedClassInError:
   526         case JVM_CONSTANT_Fieldref:
   527         case JVM_CONSTANT_Methodref:
   528         case JVM_CONSTANT_InterfaceMethodref:
   529         case JVM_CONSTANT_NameAndType:
   530         case JVM_CONSTANT_Utf8:
   531         case JVM_CONSTANT_Integer:
   532         case JVM_CONSTANT_Float:
   533           if (tag != cp->tag_at(i).value()) {
   534             report_error("tag mismatch: wrong class files?");
   535             return;
   536           }
   537           break;
   539         case JVM_CONSTANT_Class:
   540           if (tag == JVM_CONSTANT_Class) {
   541           } else if (tag == JVM_CONSTANT_UnresolvedClass) {
   542             tty->print_cr("Warning: entry was unresolved in the replay data");
   543           } else {
   544             report_error("Unexpected tag");
   545             return;
   546           }
   547           break;
   549         case 0:
   550           if (parsed_two_word == i) continue;
   552         default:
   553           ShouldNotReachHere();
   554           break;
   555       }
   557     }
   558   }
   560   // Initialize a class and fill in the value for a static field.
   561   // This is useful when the compile was dependent on the value of
   562   // static fields but it's impossible to properly rerun the static
   563   // initiailizer.
   564   void process_staticfield(TRAPS) {
   565     InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK);
   567     if (ReplaySuppressInitializers == 0 ||
   568         ReplaySuppressInitializers == 2 && k->class_loader() == NULL) {
   569       return;
   570     }
   572     assert(k->is_initialized(), "must be");
   574     const char* field_name = parse_escaped_string();;
   575     const char* field_signature = parse_string();
   576     fieldDescriptor fd;
   577     Symbol* name = SymbolTable::lookup(field_name, (int)strlen(field_name), CHECK);
   578     Symbol* sig = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
   579     if (!k->find_local_field(name, sig, &fd) ||
   580         !fd.is_static() ||
   581         fd.has_initial_value()) {
   582       report_error(field_name);
   583       return;
   584     }
   586     oop java_mirror = k->java_mirror();
   587     if (field_signature[0] == '[') {
   588       int length = parse_int("array length");
   589       oop value = NULL;
   591       if (field_signature[1] == '[') {
   592         // multi dimensional array
   593         ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK);
   594         int rank = 0;
   595         while (field_signature[rank] == '[') {
   596           rank++;
   597         }
   598         int* dims = NEW_RESOURCE_ARRAY(int, rank);
   599         dims[0] = length;
   600         for (int i = 1; i < rank; i++) {
   601           dims[i] = 1; // These aren't relevant to the compiler
   602         }
   603         value = kelem->multi_allocate(rank, dims, CHECK);
   604       } else {
   605         if (strcmp(field_signature, "[B") == 0) {
   606           value = oopFactory::new_byteArray(length, CHECK);
   607         } else if (strcmp(field_signature, "[Z") == 0) {
   608           value = oopFactory::new_boolArray(length, CHECK);
   609         } else if (strcmp(field_signature, "[C") == 0) {
   610           value = oopFactory::new_charArray(length, CHECK);
   611         } else if (strcmp(field_signature, "[S") == 0) {
   612           value = oopFactory::new_shortArray(length, CHECK);
   613         } else if (strcmp(field_signature, "[F") == 0) {
   614           value = oopFactory::new_singleArray(length, CHECK);
   615         } else if (strcmp(field_signature, "[D") == 0) {
   616           value = oopFactory::new_doubleArray(length, CHECK);
   617         } else if (strcmp(field_signature, "[I") == 0) {
   618           value = oopFactory::new_intArray(length, CHECK);
   619         } else if (strcmp(field_signature, "[J") == 0) {
   620           value = oopFactory::new_longArray(length, CHECK);
   621         } else if (field_signature[0] == '[' && field_signature[1] == 'L') {
   622           KlassHandle kelem = resolve_klass(field_signature + 1, CHECK);
   623           value = oopFactory::new_objArray(kelem(), length, CHECK);
   624         } else {
   625           report_error("unhandled array staticfield");
   626         }
   627       }
   628       java_mirror->obj_field_put(fd.offset(), value);
   629     } else {
   630       const char* string_value = parse_escaped_string();
   631       if (strcmp(field_signature, "I") == 0) {
   632         int value = atoi(string_value);
   633         java_mirror->int_field_put(fd.offset(), value);
   634       } else if (strcmp(field_signature, "B") == 0) {
   635         int value = atoi(string_value);
   636         java_mirror->byte_field_put(fd.offset(), value);
   637       } else if (strcmp(field_signature, "C") == 0) {
   638         int value = atoi(string_value);
   639         java_mirror->char_field_put(fd.offset(), value);
   640       } else if (strcmp(field_signature, "S") == 0) {
   641         int value = atoi(string_value);
   642         java_mirror->short_field_put(fd.offset(), value);
   643       } else if (strcmp(field_signature, "Z") == 0) {
   644         int value = atol(string_value);
   645         java_mirror->bool_field_put(fd.offset(), value);
   646       } else if (strcmp(field_signature, "J") == 0) {
   647         jlong value;
   648         if (sscanf(string_value, INT64_FORMAT, &value) != 1) {
   649           fprintf(stderr, "Error parsing long: %s\n", string_value);
   650           return;
   651         }
   652         java_mirror->long_field_put(fd.offset(), value);
   653       } else if (strcmp(field_signature, "F") == 0) {
   654         float value = atof(string_value);
   655         java_mirror->float_field_put(fd.offset(), value);
   656       } else if (strcmp(field_signature, "D") == 0) {
   657         double value = atof(string_value);
   658         java_mirror->double_field_put(fd.offset(), value);
   659       } else if (strcmp(field_signature, "Ljava/lang/String;") == 0) {
   660         Handle value = java_lang_String::create_from_str(string_value, CHECK);
   661         java_mirror->obj_field_put(fd.offset(), value());
   662       } else if (field_signature[0] == 'L') {
   663         Symbol* klass_name = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
   664         KlassHandle kelem = resolve_klass(field_signature, CHECK);
   665         oop value = ((InstanceKlass*)kelem())->allocate_instance(CHECK);
   666         java_mirror->obj_field_put(fd.offset(), value);
   667       } else {
   668         report_error("unhandled staticfield");
   669       }
   670     }
   671   }
   673 #if INCLUDE_JVMTI
   674   void process_JvmtiExport(TRAPS) {
   675     const char* field = parse_string();
   676     bool value = parse_int("JvmtiExport flag") != 0;
   677     if (strcmp(field, "can_access_local_variables") == 0) {
   678       JvmtiExport::set_can_access_local_variables(value);
   679     } else if (strcmp(field, "can_hotswap_or_post_breakpoint") == 0) {
   680       JvmtiExport::set_can_hotswap_or_post_breakpoint(value);
   681     } else if (strcmp(field, "can_post_on_exceptions") == 0) {
   682       JvmtiExport::set_can_post_on_exceptions(value);
   683     } else {
   684       report_error("Unrecognized JvmtiExport directive");
   685     }
   686   }
   687 #endif // INCLUDE_JVMTI
   689   // Create and initialize a record for a ciMethod
   690   ciMethodRecord* new_ciMethod(Method* method) {
   691     ciMethodRecord* rec = NEW_RESOURCE_OBJ(ciMethodRecord);
   692     rec->klass =  method->method_holder()->name()->as_utf8();
   693     rec->method = method->name()->as_utf8();
   694     rec->signature = method->signature()->as_utf8();
   695     ci_method_records.append(rec);
   696     return rec;
   697   }
   699   // Lookup data for a ciMethod
   700   ciMethodRecord* find_ciMethodRecord(Method* method) {
   701     const char* klass_name =  method->method_holder()->name()->as_utf8();
   702     const char* method_name = method->name()->as_utf8();
   703     const char* signature = method->signature()->as_utf8();
   704     for (int i = 0; i < ci_method_records.length(); i++) {
   705       ciMethodRecord* rec = ci_method_records.at(i);
   706       if (strcmp(rec->klass, klass_name) == 0 &&
   707           strcmp(rec->method, method_name) == 0 &&
   708           strcmp(rec->signature, signature) == 0) {
   709         return rec;
   710       }
   711     }
   712     return NULL;
   713   }
   715   // Create and initialize a record for a ciMethodData
   716   ciMethodDataRecord* new_ciMethodData(Method* method) {
   717     ciMethodDataRecord* rec = NEW_RESOURCE_OBJ(ciMethodDataRecord);
   718     rec->klass =  method->method_holder()->name()->as_utf8();
   719     rec->method = method->name()->as_utf8();
   720     rec->signature = method->signature()->as_utf8();
   721     ci_method_data_records.append(rec);
   722     return rec;
   723   }
   725   // Lookup data for a ciMethodData
   726   ciMethodDataRecord* find_ciMethodDataRecord(Method* method) {
   727     const char* klass_name =  method->method_holder()->name()->as_utf8();
   728     const char* method_name = method->name()->as_utf8();
   729     const char* signature = method->signature()->as_utf8();
   730     for (int i = 0; i < ci_method_data_records.length(); i++) {
   731       ciMethodDataRecord* rec = ci_method_data_records.at(i);
   732       if (strcmp(rec->klass, klass_name) == 0 &&
   733           strcmp(rec->method, method_name) == 0 &&
   734           strcmp(rec->signature, signature) == 0) {
   735         return rec;
   736       }
   737     }
   738     return NULL;
   739   }
   741   const char* error_message() {
   742     return _error_message;
   743   }
   745   void reset() {
   746     _error_message = NULL;
   747     ci_method_records.clear();
   748     ci_method_data_records.clear();
   749   }
   751   // Take an ascii string contain \u#### escapes and convert it to utf8
   752   // in place.
   753   static void unescape_string(char* value) {
   754     char* from = value;
   755     char* to = value;
   756     while (*from != '\0') {
   757       if (*from != '\\') {
   758         *from++ = *to++;
   759       } else {
   760         switch (from[1]) {
   761           case 'u': {
   762             from += 2;
   763             jchar value=0;
   764             for (int i=0; i<4; i++) {
   765               char c = *from++;
   766               switch (c) {
   767                 case '0': case '1': case '2': case '3': case '4':
   768                 case '5': case '6': case '7': case '8': case '9':
   769                   value = (value << 4) + c - '0';
   770                   break;
   771                 case 'a': case 'b': case 'c':
   772                 case 'd': case 'e': case 'f':
   773                   value = (value << 4) + 10 + c - 'a';
   774                   break;
   775                 case 'A': case 'B': case 'C':
   776                 case 'D': case 'E': case 'F':
   777                   value = (value << 4) + 10 + c - 'A';
   778                   break;
   779                 default:
   780                   ShouldNotReachHere();
   781               }
   782             }
   783             UNICODE::convert_to_utf8(&value, 1, to);
   784             to++;
   785             break;
   786           }
   787           case 't': *to++ = '\t'; from += 2; break;
   788           case 'n': *to++ = '\n'; from += 2; break;
   789           case 'r': *to++ = '\r'; from += 2; break;
   790           case 'f': *to++ = '\f'; from += 2; break;
   791           default:
   792             ShouldNotReachHere();
   793         }
   794       }
   795     }
   796     *from = *to;
   797   }
   798 };
   800 void ciReplay::replay(TRAPS) {
   801   int exit_code = replay_impl(THREAD);
   803   Threads::destroy_vm();
   805   vm_exit(exit_code);
   806 }
   808 int ciReplay::replay_impl(TRAPS) {
   809   HandleMark hm;
   810   ResourceMark rm;
   811   // Make sure we don't run with background compilation
   812   BackgroundCompilation = false;
   814   if (ReplaySuppressInitializers > 2) {
   815     // ReplaySuppressInitializers > 2 means that we want to allow
   816     // normal VM bootstrap but once we get into the replay itself
   817     // don't allow any intializers to be run.
   818     ReplaySuppressInitializers = 1;
   819   }
   821   // Load and parse the replay data
   822   CompileReplay rp(ReplayDataFile, THREAD);
   823   int exit_code = 0;
   824   if (rp.can_replay()) {
   825     rp.process(THREAD);
   826   } else {
   827     exit_code = 1;
   828     return exit_code;
   829   }
   831   if (HAS_PENDING_EXCEPTION) {
   832     oop throwable = PENDING_EXCEPTION;
   833     CLEAR_PENDING_EXCEPTION;
   834     java_lang_Throwable::print(throwable, tty);
   835     tty->cr();
   836     java_lang_Throwable::print_stack_trace(throwable, tty);
   837     tty->cr();
   838     exit_code = 2;
   839   }
   841   if (rp.had_error()) {
   842     tty->print_cr("Failed on %s", rp.error_message());
   843     exit_code = 1;
   844   }
   845   return exit_code;
   846 }
   849 void ciReplay::initialize(ciMethodData* m) {
   850   if (replay_state == NULL) {
   851     return;
   852   }
   854   ASSERT_IN_VM;
   855   ResourceMark rm;
   857   Method* method = m->get_MethodData()->method();
   858   ciMethodDataRecord* rec = replay_state->find_ciMethodDataRecord(method);
   859   if (rec == NULL) {
   860     // This indicates some mismatch with the original environment and
   861     // the replay environment though it's not always enough to
   862     // interfere with reproducing a bug
   863     tty->print_cr("Warning: requesting ciMethodData record for method with no data: ");
   864     method->print_name(tty);
   865     tty->cr();
   866   } else {
   867     m->_state = rec->state;
   868     m->_current_mileage = rec->current_mileage;
   869     if (rec->data_length != 0) {
   870       assert(m->_data_size == rec->data_length * (int)sizeof(rec->data[0]), "must agree");
   872       // Write the correct ciObjects back into the profile data
   873       ciEnv* env = ciEnv::current();
   874       for (int i = 0; i < rec->oops_length; i++) {
   875         KlassHandle *h = (KlassHandle *)rec->oops_handles[i];
   876         *(ciMetadata**)(rec->data + rec->oops_offsets[i]) =
   877           env->get_metadata((*h)());
   878       }
   879       // Copy the updated profile data into place as intptr_ts
   880 #ifdef _LP64
   881       Copy::conjoint_jlongs_atomic((jlong *)rec->data, (jlong *)m->_data, rec->data_length);
   882 #else
   883       Copy::conjoint_jints_atomic((jint *)rec->data, (jint *)m->_data, rec->data_length);
   884 #endif
   885     }
   887     // copy in the original header
   888     Copy::conjoint_jbytes(rec->orig_data, (char*)&m->_orig, rec->orig_data_length);
   889   }
   890 }
   893 bool ciReplay::should_not_inline(ciMethod* method) {
   894   if (replay_state == NULL) {
   895     return false;
   896   }
   898   VM_ENTRY_MARK;
   899   // ciMethod without a record shouldn't be inlined.
   900   return replay_state->find_ciMethodRecord(method->get_Method()) == NULL;
   901 }
   904 void ciReplay::initialize(ciMethod* m) {
   905   if (replay_state == NULL) {
   906     return;
   907   }
   909   ASSERT_IN_VM;
   910   ResourceMark rm;
   912   Method* method = m->get_Method();
   913   ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
   914   if (rec == NULL) {
   915     // This indicates some mismatch with the original environment and
   916     // the replay environment though it's not always enough to
   917     // interfere with reproducing a bug
   918     tty->print_cr("Warning: requesting ciMethod record for method with no data: ");
   919     method->print_name(tty);
   920     tty->cr();
   921   } else {
   922     // m->_instructions_size = rec->instructions_size;
   923     m->_instructions_size = -1;
   924     m->_interpreter_invocation_count = rec->interpreter_invocation_count;
   925     m->_interpreter_throwout_count = rec->interpreter_throwout_count;
   926     method->invocation_counter()->_counter = rec->invocation_counter;
   927     method->backedge_counter()->_counter = rec->backedge_counter;
   928   }
   929 }
   931 bool ciReplay::is_loaded(Method* method) {
   932   if (replay_state == NULL) {
   933     return true;
   934   }
   936   ASSERT_IN_VM;
   937   ResourceMark rm;
   939   ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
   940   return rec != NULL;
   941 }
   942 #endif

mercurial