ciReplay.cpp revision 4592:e12c9b3740db
1/* Copyright (c) 2013, 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 */
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#include "utilities/macros.hpp"
34
35#ifndef PRODUCT
36
37// ciReplay
38
39typedef struct _ciMethodDataRecord {
40  const char* klass;
41  const char* method;
42  const char* signature;
43  int state;
44  int current_mileage;
45  intptr_t* data;
46  int data_length;
47  char* orig_data;
48  int orig_data_length;
49  int oops_length;
50  jobject* oops_handles;
51  int* oops_offsets;
52} ciMethodDataRecord;
53
54typedef struct _ciMethodRecord {
55  const char* klass;
56  const char* method;
57  const char* signature;
58  int instructions_size;
59  int interpreter_invocation_count;
60  int interpreter_throwout_count;
61  int invocation_counter;
62  int backedge_counter;
63} ciMethodRecord;
64
65class CompileReplay;
66static CompileReplay* replay_state;
67
68class CompileReplay : public StackObj {
69 private:
70  FILE*   stream;
71  Thread* thread;
72  Handle  protection_domain;
73  Handle  loader;
74
75  GrowableArray<ciMethodRecord*>     ci_method_records;
76  GrowableArray<ciMethodDataRecord*> ci_method_data_records;
77
78  const char* _error_message;
79
80  char* bufptr;
81  char* buffer;
82  int   buffer_length;
83  int   buffer_end;
84  int   line_no;
85
86 public:
87  CompileReplay(const char* filename, TRAPS) {
88    thread = THREAD;
89    loader = Handle(thread, SystemDictionary::java_system_loader());
90    stream = fopen(filename, "rt");
91    if (stream == NULL) {
92      fprintf(stderr, "ERROR: Can't open replay file %s\n", filename);
93    }
94    buffer_length = 32;
95    buffer = NEW_RESOURCE_ARRAY(char, buffer_length);
96    _error_message = NULL;
97
98    test();
99  }
100
101  ~CompileReplay() {
102    if (stream != NULL) fclose(stream);
103  }
104
105  void test() {
106    strcpy(buffer, "1 2 foo 4 bar 0x9 \"this is it\"");
107    bufptr = buffer;
108    assert(parse_int("test") == 1, "what");
109    assert(parse_int("test") == 2, "what");
110    assert(strcmp(parse_string(), "foo") == 0, "what");
111    assert(parse_int("test") == 4, "what");
112    assert(strcmp(parse_string(), "bar") == 0, "what");
113    assert(parse_intptr_t("test") == 9, "what");
114    assert(strcmp(parse_quoted_string(), "this is it") == 0, "what");
115  }
116
117  bool had_error() {
118    return _error_message != NULL || thread->has_pending_exception();
119  }
120
121  bool can_replay() {
122    return !(stream == NULL || had_error());
123  }
124
125  void report_error(const char* msg) {
126    _error_message = msg;
127    // Restore the buffer contents for error reporting
128    for (int i = 0; i < buffer_end; i++) {
129      if (buffer[i] == '\0') buffer[i] = ' ';
130    }
131  }
132
133  int parse_int(const char* label) {
134    if (had_error()) {
135      return 0;
136    }
137
138    int v = 0;
139    int read;
140    if (sscanf(bufptr, "%i%n", &v, &read) != 1) {
141      report_error(label);
142    } else {
143      bufptr += read;
144    }
145    return v;
146  }
147
148  intptr_t parse_intptr_t(const char* label) {
149    if (had_error()) {
150      return 0;
151    }
152
153    intptr_t v = 0;
154    int read;
155    if (sscanf(bufptr, INTPTR_FORMAT "%n", &v, &read) != 1) {
156      report_error(label);
157    } else {
158      bufptr += read;
159    }
160    return v;
161  }
162
163  void skip_ws() {
164    // Skip any leading whitespace
165    while (*bufptr == ' ' || *bufptr == '\t') {
166      bufptr++;
167    }
168  }
169
170
171  char* scan_and_terminate(char delim) {
172    char* str = bufptr;
173    while (*bufptr != delim && *bufptr != '\0') {
174      bufptr++;
175    }
176    if (*bufptr != '\0') {
177      *bufptr++ = '\0';
178    }
179    if (bufptr == str) {
180      // nothing here
181      return NULL;
182    }
183    return str;
184  }
185
186  char* parse_string() {
187    if (had_error()) return NULL;
188
189    skip_ws();
190    return scan_and_terminate(' ');
191  }
192
193  char* parse_quoted_string() {
194    if (had_error()) return NULL;
195
196    skip_ws();
197
198    if (*bufptr == '"') {
199      bufptr++;
200      return scan_and_terminate('"');
201    } else {
202      return scan_and_terminate(' ');
203    }
204  }
205
206  const char* parse_escaped_string() {
207    char* result = parse_quoted_string();
208    if (result != NULL) {
209      unescape_string(result);
210    }
211    return result;
212  }
213
214  // Look for the tag 'tag' followed by an
215  bool parse_tag_and_count(const char* tag, int& length) {
216    const char* t = parse_string();
217    if (t == NULL) {
218      return false;
219    }
220
221    if (strcmp(tag, t) != 0) {
222      report_error(tag);
223      return false;
224    }
225    length = parse_int("parse_tag_and_count");
226    return !had_error();
227  }
228
229  // Parse a sequence of raw data encoded as bytes and return the
230  // resulting data.
231  char* parse_data(const char* tag, int& length) {
232    if (!parse_tag_and_count(tag, length)) {
233      return NULL;
234    }
235
236    char * result = NEW_RESOURCE_ARRAY(char, length);
237    for (int i = 0; i < length; i++) {
238      int val = parse_int("data");
239      result[i] = val;
240    }
241    return result;
242  }
243
244  // Parse a standard chunk of data emitted as:
245  //   'tag' <length> # # ...
246  // Where each # is an intptr_t item
247  intptr_t* parse_intptr_data(const char* tag, int& length) {
248    if (!parse_tag_and_count(tag, length)) {
249      return NULL;
250    }
251
252    intptr_t* result = NEW_RESOURCE_ARRAY(intptr_t, length);
253    for (int i = 0; i < length; i++) {
254      skip_ws();
255      intptr_t val = parse_intptr_t("data");
256      result[i] = val;
257    }
258    return result;
259  }
260
261  // Parse a possibly quoted version of a symbol into a symbolOop
262  Symbol* parse_symbol(TRAPS) {
263    const char* str = parse_escaped_string();
264    if (str != NULL) {
265      Symbol* sym = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
266      return sym;
267    }
268    return NULL;
269  }
270
271  // Parse a valid klass name and look it up
272  Klass* parse_klass(TRAPS) {
273    const char* str = parse_escaped_string();
274    Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
275    if (klass_name != NULL) {
276      Klass* k = SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, THREAD);
277      if (HAS_PENDING_EXCEPTION) {
278        oop throwable = PENDING_EXCEPTION;
279        java_lang_Throwable::print(throwable, tty);
280        tty->cr();
281        report_error(str);
282        return NULL;
283      }
284      return k;
285    }
286    return NULL;
287  }
288
289  // Lookup a klass
290  Klass* resolve_klass(const char* klass, TRAPS) {
291    Symbol* klass_name = SymbolTable::lookup(klass, (int)strlen(klass), CHECK_NULL);
292    return SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, CHECK_NULL);
293  }
294
295  // Parse the standard tuple of <klass> <name> <signature>
296  Method* parse_method(TRAPS) {
297    InstanceKlass* k = (InstanceKlass*)parse_klass(CHECK_NULL);
298    Symbol* method_name = parse_symbol(CHECK_NULL);
299    Symbol* method_signature = parse_symbol(CHECK_NULL);
300    Method* m = k->find_method(method_name, method_signature);
301    if (m == NULL) {
302      report_error("can't find method");
303    }
304    return m;
305  }
306
307  // Process each line of the replay file executing each command until
308  // the file ends.
309  void process(TRAPS) {
310    line_no = 1;
311    int pos = 0;
312    int c = getc(stream);
313    while(c != EOF) {
314      if (pos + 1 >= buffer_length) {
315        int newl = buffer_length * 2;
316        char* newb = NEW_RESOURCE_ARRAY(char, newl);
317        memcpy(newb, buffer, pos);
318        buffer = newb;
319        buffer_length = newl;
320      }
321      if (c == '\n') {
322        // null terminate it, reset the pointer and process the line
323        buffer[pos] = '\0';
324        buffer_end = pos++;
325        bufptr = buffer;
326        process_command(CHECK);
327        if (had_error()) {
328          tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message);
329          tty->print_cr("%s", buffer);
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          fatal(err_msg_res("Unexpected tag: %d", cp->tag_at(i).value()));
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, JLONG_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  if (FLAG_IS_DEFAULT(ReplayDataFile)) {
822    tty->print_cr("ERROR: no compiler replay data file specified (use -XX:ReplayDataFile=replay_pid12345.txt).");
823    return 1;
824  }
825
826  // Load and parse the replay data
827  CompileReplay rp(ReplayDataFile, THREAD);
828  int exit_code = 0;
829  if (rp.can_replay()) {
830    rp.process(THREAD);
831  } else {
832    exit_code = 1;
833    return exit_code;
834  }
835
836  if (HAS_PENDING_EXCEPTION) {
837    oop throwable = PENDING_EXCEPTION;
838    CLEAR_PENDING_EXCEPTION;
839    java_lang_Throwable::print(throwable, tty);
840    tty->cr();
841    java_lang_Throwable::print_stack_trace(throwable, tty);
842    tty->cr();
843    exit_code = 2;
844  }
845
846  if (rp.had_error()) {
847    tty->print_cr("Failed on %s", rp.error_message());
848    exit_code = 1;
849  }
850  return exit_code;
851}
852
853
854void ciReplay::initialize(ciMethodData* m) {
855  if (replay_state == NULL) {
856    return;
857  }
858
859  ASSERT_IN_VM;
860  ResourceMark rm;
861
862  Method* method = m->get_MethodData()->method();
863  ciMethodDataRecord* rec = replay_state->find_ciMethodDataRecord(method);
864  if (rec == NULL) {
865    // This indicates some mismatch with the original environment and
866    // the replay environment though it's not always enough to
867    // interfere with reproducing a bug
868    tty->print_cr("Warning: requesting ciMethodData record for method with no data: ");
869    method->print_name(tty);
870    tty->cr();
871  } else {
872    m->_state = rec->state;
873    m->_current_mileage = rec->current_mileage;
874    if (rec->data_length != 0) {
875      assert(m->_data_size == rec->data_length * (int)sizeof(rec->data[0]), "must agree");
876
877      // Write the correct ciObjects back into the profile data
878      ciEnv* env = ciEnv::current();
879      for (int i = 0; i < rec->oops_length; i++) {
880        KlassHandle *h = (KlassHandle *)rec->oops_handles[i];
881        *(ciMetadata**)(rec->data + rec->oops_offsets[i]) =
882          env->get_metadata((*h)());
883      }
884      // Copy the updated profile data into place as intptr_ts
885#ifdef _LP64
886      Copy::conjoint_jlongs_atomic((jlong *)rec->data, (jlong *)m->_data, rec->data_length);
887#else
888      Copy::conjoint_jints_atomic((jint *)rec->data, (jint *)m->_data, rec->data_length);
889#endif
890    }
891
892    // copy in the original header
893    Copy::conjoint_jbytes(rec->orig_data, (char*)&m->_orig, rec->orig_data_length);
894  }
895}
896
897
898bool ciReplay::should_not_inline(ciMethod* method) {
899  if (replay_state == NULL) {
900    return false;
901  }
902
903  VM_ENTRY_MARK;
904  // ciMethod without a record shouldn't be inlined.
905  return replay_state->find_ciMethodRecord(method->get_Method()) == NULL;
906}
907
908
909void ciReplay::initialize(ciMethod* m) {
910  if (replay_state == NULL) {
911    return;
912  }
913
914  ASSERT_IN_VM;
915  ResourceMark rm;
916
917  Method* method = m->get_Method();
918  ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
919  if (rec == NULL) {
920    // This indicates some mismatch with the original environment and
921    // the replay environment though it's not always enough to
922    // interfere with reproducing a bug
923    tty->print_cr("Warning: requesting ciMethod record for method with no data: ");
924    method->print_name(tty);
925    tty->cr();
926  } else {
927    EXCEPTION_CONTEXT;
928    MethodCounters* mcs = method->method_counters();
929    // m->_instructions_size = rec->instructions_size;
930    m->_instructions_size = -1;
931    m->_interpreter_invocation_count = rec->interpreter_invocation_count;
932    m->_interpreter_throwout_count = rec->interpreter_throwout_count;
933    if (mcs == NULL) {
934      mcs = Method::build_method_counters(method, CHECK_AND_CLEAR);
935    }
936    mcs->invocation_counter()->_counter = rec->invocation_counter;
937    mcs->backedge_counter()->_counter = rec->backedge_counter;
938  }
939}
940
941bool ciReplay::is_loaded(Method* method) {
942  if (replay_state == NULL) {
943    return true;
944  }
945
946  ASSERT_IN_VM;
947  ResourceMark rm;
948
949  ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
950  return rec != NULL;
951}
952#endif // PRODUCT
953