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