ciReplay.cpp revision 3869:90273fc0a981
126762Sjkh/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
275328Sobrien * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
351144Sjkh *
475328Sobrien * This code is free software; you can redistribute it and/or modify it
551144Sjkh * under the terms of the GNU General Public License version 2 only, as
626762Sjkh * published by the Free Software Foundation.
795327Sobrien *
895327Sobrien * This code is distributed in the hope that it will be useful, but WITHOUT
951144Sjkh * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1095327Sobrien * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1126762Sjkh * 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 */
23
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"
33
34#ifndef PRODUCT
35
36// ciReplay
37
38typedef 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;
52
53typedef 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;
63
64class CompileReplay;
65static CompileReplay* replay_state;
66
67class CompileReplay : public StackObj {
68 private:
69  FILE*   stream;
70  Thread* thread;
71  Handle  protection_domain;
72  Handle  loader;
73
74  GrowableArray<ciMethodRecord*>     ci_method_records;
75  GrowableArray<ciMethodDataRecord*> ci_method_data_records;
76
77  const char* _error_message;
78
79  char* bufptr;
80  char* buffer;
81  int   buffer_length;
82  int   buffer_end;
83  int   line_no;
84
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;
96
97    test();
98  }
99
100  ~CompileReplay() {
101    if (stream != NULL) fclose(stream);
102  }
103
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  }
115
116  bool had_error() {
117    return _error_message != NULL || thread->has_pending_exception();
118  }
119
120  bool can_replay() {
121    return !(stream == NULL || had_error());
122  }
123
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  }
131
132  int parse_int(const char* label) {
133    if (had_error()) {
134      return 0;
135    }
136
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  }
146
147  intptr_t parse_intptr_t(const char* label) {
148    if (had_error()) {
149      return 0;
150    }
151
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  }
161
162  void skip_ws() {
163    // Skip any leading whitespace
164    while (*bufptr == ' ' || *bufptr == '\t') {
165      bufptr++;
166    }
167  }
168
169
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  }
184
185  char* parse_string() {
186    if (had_error()) return NULL;
187
188    skip_ws();
189    return scan_and_terminate(' ');
190  }
191
192  char* parse_quoted_string() {
193    if (had_error()) return NULL;
194
195    skip_ws();
196
197    if (*bufptr == '"') {
198      bufptr++;
199      return scan_and_terminate('"');
200    } else {
201      return scan_and_terminate(' ');
202    }
203  }
204
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  }
212
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    }
219
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  }
227
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    }
234
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  }
242
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    }
250
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  }
259
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  }
269
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  }
287
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  }
293
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  }
305
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  }
343
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  }
371
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  }
401
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  }
414
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    }
433
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");
438
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  }
462
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  }
471
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    }
503
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;
521
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;
538
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;
548
549        case 0:
550          if (parsed_two_word == i) continue;
551
552        default:
553          ShouldNotReachHere();
554          break;
555      }
556
557    }
558  }
559
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);
566
567    if (ReplaySuppressInitializers == 0 ||
568        ReplaySuppressInitializers == 2 && k->class_loader() == NULL) {
569      return;
570    }
571
572    assert(k->is_initialized(), "must be");
573
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    }
585
586    oop java_mirror = k->java_mirror();
587    if (field_signature[0] == '[') {
588      int length = parse_int("array length");
589      oop value = NULL;
590
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  }
672
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
688
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  }
698
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  }
714
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  }
724
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  }
740
741  const char* error_message() {
742    return _error_message;
743  }
744
745  void reset() {
746    _error_message = NULL;
747    ci_method_records.clear();
748    ci_method_data_records.clear();
749  }
750
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};
799
800void ciReplay::replay(TRAPS) {
801  int exit_code = replay_impl(THREAD);
802
803  Threads::destroy_vm();
804
805  vm_exit(exit_code);
806}
807
808int ciReplay::replay_impl(TRAPS) {
809  HandleMark hm;
810  ResourceMark rm;
811  // Make sure we don't run with background compilation
812  BackgroundCompilation = false;
813
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  }
820
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  }
830
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  }
840
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}
847
848
849void ciReplay::initialize(ciMethodData* m) {
850  if (replay_state == NULL) {
851    return;
852  }
853
854  ASSERT_IN_VM;
855  ResourceMark rm;
856
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");
871
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    }
886
887    // copy in the original header
888    Copy::conjoint_jbytes(rec->orig_data, (char*)&m->_orig, rec->orig_data_length);
889  }
890}
891
892
893bool ciReplay::should_not_inline(ciMethod* method) {
894  if (replay_state == NULL) {
895    return false;
896  }
897
898  VM_ENTRY_MARK;
899  // ciMethod without a record shouldn't be inlined.
900  return replay_state->find_ciMethodRecord(method->get_Method()) == NULL;
901}
902
903
904void ciReplay::initialize(ciMethod* m) {
905  if (replay_state == NULL) {
906    return;
907  }
908
909  ASSERT_IN_VM;
910  ResourceMark rm;
911
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}
930
931bool ciReplay::is_loaded(Method* method) {
932  if (replay_state == NULL) {
933    return true;
934  }
935
936  ASSERT_IN_VM;
937  ResourceMark rm;
938
939  ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
940  return rec != NULL;
941}
942#endif // PRODUCT
943