Wed, 08 Jan 2014 10:25:50 -0800
8028468: Add inlining information into ciReplay
Summary: Allow dump and replay inlining for specified method during a program execution.
Reviewed-by: roland, twisti
hseigel@4465 | 1 | /* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. |
minqi@4267 | 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
minqi@4267 | 3 | * |
minqi@4267 | 4 | * This code is free software; you can redistribute it and/or modify it |
minqi@4267 | 5 | * under the terms of the GNU General Public License version 2 only, as |
minqi@4267 | 6 | * published by the Free Software Foundation. |
minqi@4267 | 7 | * |
minqi@4267 | 8 | * This code is distributed in the hope that it will be useful, but WITHOUT |
minqi@4267 | 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
minqi@4267 | 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
minqi@4267 | 11 | * version 2 for more details (a copy is included in the LICENSE file that |
minqi@4267 | 12 | * accompanied this code). |
minqi@4267 | 13 | * |
minqi@4267 | 14 | * You should have received a copy of the GNU General Public License version |
minqi@4267 | 15 | * 2 along with this work; if not, write to the Free Software Foundation, |
minqi@4267 | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
minqi@4267 | 17 | * |
minqi@4267 | 18 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
minqi@4267 | 19 | * or visit www.oracle.com if you need additional information or have any |
minqi@4267 | 20 | * questions. |
minqi@4267 | 21 | * |
minqi@4267 | 22 | */ |
minqi@4267 | 23 | |
minqi@4267 | 24 | #include "precompiled.hpp" |
minqi@4267 | 25 | #include "ci/ciMethodData.hpp" |
minqi@4267 | 26 | #include "ci/ciReplay.hpp" |
kvn@6217 | 27 | #include "ci/ciSymbol.hpp" |
kvn@6217 | 28 | #include "ci/ciKlass.hpp" |
minqi@4267 | 29 | #include "ci/ciUtilities.hpp" |
minqi@4267 | 30 | #include "compiler/compileBroker.hpp" |
minqi@4267 | 31 | #include "memory/allocation.inline.hpp" |
minqi@4267 | 32 | #include "memory/oopFactory.hpp" |
minqi@4267 | 33 | #include "memory/resourceArea.hpp" |
minqi@4267 | 34 | #include "utilities/copy.hpp" |
jprovino@4542 | 35 | #include "utilities/macros.hpp" |
minqi@4267 | 36 | |
coleenp@4304 | 37 | #ifndef PRODUCT |
minqi@4267 | 38 | |
minqi@4267 | 39 | // ciReplay |
minqi@4267 | 40 | |
minqi@4267 | 41 | typedef struct _ciMethodDataRecord { |
kvn@6217 | 42 | const char* _klass_name; |
kvn@6217 | 43 | const char* _method_name; |
kvn@6217 | 44 | const char* _signature; |
kvn@6217 | 45 | |
kvn@6217 | 46 | int _state; |
kvn@6217 | 47 | int _current_mileage; |
kvn@6217 | 48 | |
kvn@6217 | 49 | intptr_t* _data; |
kvn@6217 | 50 | char* _orig_data; |
kvn@6217 | 51 | jobject* _oops_handles; |
kvn@6217 | 52 | int* _oops_offsets; |
kvn@6217 | 53 | int _data_length; |
kvn@6217 | 54 | int _orig_data_length; |
kvn@6217 | 55 | int _oops_length; |
minqi@4267 | 56 | } ciMethodDataRecord; |
minqi@4267 | 57 | |
minqi@4267 | 58 | typedef struct _ciMethodRecord { |
kvn@6217 | 59 | const char* _klass_name; |
kvn@6217 | 60 | const char* _method_name; |
kvn@6217 | 61 | const char* _signature; |
kvn@6217 | 62 | |
kvn@6217 | 63 | int _instructions_size; |
kvn@6217 | 64 | int _interpreter_invocation_count; |
kvn@6217 | 65 | int _interpreter_throwout_count; |
kvn@6217 | 66 | int _invocation_counter; |
kvn@6217 | 67 | int _backedge_counter; |
minqi@4267 | 68 | } ciMethodRecord; |
minqi@4267 | 69 | |
kvn@6217 | 70 | typedef struct _ciInlineRecord { |
kvn@6217 | 71 | const char* _klass_name; |
kvn@6217 | 72 | const char* _method_name; |
kvn@6217 | 73 | const char* _signature; |
kvn@6217 | 74 | |
kvn@6217 | 75 | int _inline_depth; |
kvn@6217 | 76 | int _inline_bci; |
kvn@6217 | 77 | } ciInlineRecord; |
kvn@6217 | 78 | |
kvn@6217 | 79 | class CompileReplay; |
minqi@4267 | 80 | static CompileReplay* replay_state; |
minqi@4267 | 81 | |
minqi@4267 | 82 | class CompileReplay : public StackObj { |
minqi@4267 | 83 | private: |
kvn@6217 | 84 | FILE* _stream; |
kvn@6217 | 85 | Thread* _thread; |
kvn@6217 | 86 | Handle _protection_domain; |
kvn@6217 | 87 | Handle _loader; |
minqi@4267 | 88 | |
kvn@6217 | 89 | GrowableArray<ciMethodRecord*> _ci_method_records; |
kvn@6217 | 90 | GrowableArray<ciMethodDataRecord*> _ci_method_data_records; |
kvn@6217 | 91 | |
kvn@6217 | 92 | // Use pointer because we may need to return inline records |
kvn@6217 | 93 | // without destroying them. |
kvn@6217 | 94 | GrowableArray<ciInlineRecord*>* _ci_inline_records; |
minqi@4267 | 95 | |
minqi@4267 | 96 | const char* _error_message; |
minqi@4267 | 97 | |
kvn@6217 | 98 | char* _bufptr; |
kvn@6217 | 99 | char* _buffer; |
kvn@6217 | 100 | int _buffer_length; |
kvn@6217 | 101 | int _buffer_pos; |
kvn@6217 | 102 | |
kvn@6217 | 103 | // "compile" data |
kvn@6217 | 104 | ciKlass* _iklass; |
kvn@6217 | 105 | Method* _imethod; |
kvn@6217 | 106 | int _entry_bci; |
kvn@6217 | 107 | int _comp_level; |
minqi@4267 | 108 | |
minqi@4267 | 109 | public: |
minqi@4267 | 110 | CompileReplay(const char* filename, TRAPS) { |
kvn@6217 | 111 | _thread = THREAD; |
kvn@6217 | 112 | _loader = Handle(_thread, SystemDictionary::java_system_loader()); |
kvn@6217 | 113 | _protection_domain = Handle(); |
kvn@6217 | 114 | |
kvn@6217 | 115 | _stream = fopen(filename, "rt"); |
kvn@6217 | 116 | if (_stream == NULL) { |
vlivanov@5027 | 117 | fprintf(stderr, "ERROR: Can't open replay file %s\n", filename); |
minqi@4267 | 118 | } |
kvn@6217 | 119 | |
kvn@6217 | 120 | _ci_inline_records = NULL; |
minqi@4267 | 121 | _error_message = NULL; |
minqi@4267 | 122 | |
kvn@6217 | 123 | _buffer_length = 32; |
kvn@6217 | 124 | _buffer = NEW_RESOURCE_ARRAY(char, _buffer_length); |
kvn@6217 | 125 | _bufptr = _buffer; |
kvn@6217 | 126 | _buffer_pos = 0; |
kvn@6217 | 127 | |
kvn@6217 | 128 | _imethod = NULL; |
kvn@6217 | 129 | _iklass = NULL; |
kvn@6217 | 130 | _entry_bci = 0; |
kvn@6217 | 131 | _comp_level = 0; |
kvn@6217 | 132 | |
minqi@4267 | 133 | test(); |
minqi@4267 | 134 | } |
minqi@4267 | 135 | |
minqi@4267 | 136 | ~CompileReplay() { |
kvn@6217 | 137 | if (_stream != NULL) fclose(_stream); |
minqi@4267 | 138 | } |
minqi@4267 | 139 | |
minqi@4267 | 140 | void test() { |
kvn@6217 | 141 | strcpy(_buffer, "1 2 foo 4 bar 0x9 \"this is it\""); |
kvn@6217 | 142 | _bufptr = _buffer; |
minqi@4267 | 143 | assert(parse_int("test") == 1, "what"); |
minqi@4267 | 144 | assert(parse_int("test") == 2, "what"); |
minqi@4267 | 145 | assert(strcmp(parse_string(), "foo") == 0, "what"); |
minqi@4267 | 146 | assert(parse_int("test") == 4, "what"); |
minqi@4267 | 147 | assert(strcmp(parse_string(), "bar") == 0, "what"); |
minqi@4267 | 148 | assert(parse_intptr_t("test") == 9, "what"); |
minqi@4267 | 149 | assert(strcmp(parse_quoted_string(), "this is it") == 0, "what"); |
minqi@4267 | 150 | } |
minqi@4267 | 151 | |
minqi@4267 | 152 | bool had_error() { |
kvn@6217 | 153 | return _error_message != NULL || _thread->has_pending_exception(); |
minqi@4267 | 154 | } |
minqi@4267 | 155 | |
minqi@4267 | 156 | bool can_replay() { |
kvn@6217 | 157 | return !(_stream == NULL || had_error()); |
minqi@4267 | 158 | } |
minqi@4267 | 159 | |
minqi@4267 | 160 | void report_error(const char* msg) { |
minqi@4267 | 161 | _error_message = msg; |
kvn@6217 | 162 | // Restore the _buffer contents for error reporting |
kvn@6217 | 163 | for (int i = 0; i < _buffer_pos; i++) { |
kvn@6217 | 164 | if (_buffer[i] == '\0') _buffer[i] = ' '; |
minqi@4267 | 165 | } |
minqi@4267 | 166 | } |
minqi@4267 | 167 | |
minqi@4267 | 168 | int parse_int(const char* label) { |
minqi@4267 | 169 | if (had_error()) { |
minqi@4267 | 170 | return 0; |
minqi@4267 | 171 | } |
minqi@4267 | 172 | |
minqi@4267 | 173 | int v = 0; |
minqi@4267 | 174 | int read; |
kvn@6217 | 175 | if (sscanf(_bufptr, "%i%n", &v, &read) != 1) { |
minqi@4267 | 176 | report_error(label); |
minqi@4267 | 177 | } else { |
kvn@6217 | 178 | _bufptr += read; |
minqi@4267 | 179 | } |
minqi@4267 | 180 | return v; |
minqi@4267 | 181 | } |
minqi@4267 | 182 | |
minqi@4267 | 183 | intptr_t parse_intptr_t(const char* label) { |
minqi@4267 | 184 | if (had_error()) { |
minqi@4267 | 185 | return 0; |
minqi@4267 | 186 | } |
minqi@4267 | 187 | |
minqi@4267 | 188 | intptr_t v = 0; |
minqi@4267 | 189 | int read; |
kvn@6217 | 190 | if (sscanf(_bufptr, INTPTR_FORMAT "%n", &v, &read) != 1) { |
minqi@4267 | 191 | report_error(label); |
minqi@4267 | 192 | } else { |
kvn@6217 | 193 | _bufptr += read; |
minqi@4267 | 194 | } |
minqi@4267 | 195 | return v; |
minqi@4267 | 196 | } |
minqi@4267 | 197 | |
minqi@4267 | 198 | void skip_ws() { |
minqi@4267 | 199 | // Skip any leading whitespace |
kvn@6217 | 200 | while (*_bufptr == ' ' || *_bufptr == '\t') { |
kvn@6217 | 201 | _bufptr++; |
minqi@4267 | 202 | } |
minqi@4267 | 203 | } |
minqi@4267 | 204 | |
minqi@4267 | 205 | |
minqi@4267 | 206 | char* scan_and_terminate(char delim) { |
kvn@6217 | 207 | char* str = _bufptr; |
kvn@6217 | 208 | while (*_bufptr != delim && *_bufptr != '\0') { |
kvn@6217 | 209 | _bufptr++; |
minqi@4267 | 210 | } |
kvn@6217 | 211 | if (*_bufptr != '\0') { |
kvn@6217 | 212 | *_bufptr++ = '\0'; |
minqi@4267 | 213 | } |
kvn@6217 | 214 | if (_bufptr == str) { |
minqi@4267 | 215 | // nothing here |
minqi@4267 | 216 | return NULL; |
minqi@4267 | 217 | } |
minqi@4267 | 218 | return str; |
minqi@4267 | 219 | } |
minqi@4267 | 220 | |
minqi@4267 | 221 | char* parse_string() { |
minqi@4267 | 222 | if (had_error()) return NULL; |
minqi@4267 | 223 | |
minqi@4267 | 224 | skip_ws(); |
minqi@4267 | 225 | return scan_and_terminate(' '); |
minqi@4267 | 226 | } |
minqi@4267 | 227 | |
minqi@4267 | 228 | char* parse_quoted_string() { |
minqi@4267 | 229 | if (had_error()) return NULL; |
minqi@4267 | 230 | |
minqi@4267 | 231 | skip_ws(); |
minqi@4267 | 232 | |
kvn@6217 | 233 | if (*_bufptr == '"') { |
kvn@6217 | 234 | _bufptr++; |
minqi@4267 | 235 | return scan_and_terminate('"'); |
minqi@4267 | 236 | } else { |
minqi@4267 | 237 | return scan_and_terminate(' '); |
minqi@4267 | 238 | } |
minqi@4267 | 239 | } |
minqi@4267 | 240 | |
minqi@4267 | 241 | const char* parse_escaped_string() { |
minqi@4267 | 242 | char* result = parse_quoted_string(); |
minqi@4267 | 243 | if (result != NULL) { |
minqi@4267 | 244 | unescape_string(result); |
minqi@4267 | 245 | } |
minqi@4267 | 246 | return result; |
minqi@4267 | 247 | } |
minqi@4267 | 248 | |
minqi@4267 | 249 | // Look for the tag 'tag' followed by an |
minqi@4267 | 250 | bool parse_tag_and_count(const char* tag, int& length) { |
minqi@4267 | 251 | const char* t = parse_string(); |
minqi@4267 | 252 | if (t == NULL) { |
minqi@4267 | 253 | return false; |
minqi@4267 | 254 | } |
minqi@4267 | 255 | |
minqi@4267 | 256 | if (strcmp(tag, t) != 0) { |
minqi@4267 | 257 | report_error(tag); |
minqi@4267 | 258 | return false; |
minqi@4267 | 259 | } |
minqi@4267 | 260 | length = parse_int("parse_tag_and_count"); |
minqi@4267 | 261 | return !had_error(); |
minqi@4267 | 262 | } |
minqi@4267 | 263 | |
minqi@4267 | 264 | // Parse a sequence of raw data encoded as bytes and return the |
minqi@4267 | 265 | // resulting data. |
minqi@4267 | 266 | char* parse_data(const char* tag, int& length) { |
minqi@4267 | 267 | if (!parse_tag_and_count(tag, length)) { |
minqi@4267 | 268 | return NULL; |
minqi@4267 | 269 | } |
minqi@4267 | 270 | |
minqi@4267 | 271 | char * result = NEW_RESOURCE_ARRAY(char, length); |
minqi@4267 | 272 | for (int i = 0; i < length; i++) { |
minqi@4267 | 273 | int val = parse_int("data"); |
minqi@4267 | 274 | result[i] = val; |
minqi@4267 | 275 | } |
minqi@4267 | 276 | return result; |
minqi@4267 | 277 | } |
minqi@4267 | 278 | |
minqi@4267 | 279 | // Parse a standard chunk of data emitted as: |
minqi@4267 | 280 | // 'tag' <length> # # ... |
minqi@4267 | 281 | // Where each # is an intptr_t item |
minqi@4267 | 282 | intptr_t* parse_intptr_data(const char* tag, int& length) { |
minqi@4267 | 283 | if (!parse_tag_and_count(tag, length)) { |
minqi@4267 | 284 | return NULL; |
minqi@4267 | 285 | } |
minqi@4267 | 286 | |
minqi@4267 | 287 | intptr_t* result = NEW_RESOURCE_ARRAY(intptr_t, length); |
minqi@4267 | 288 | for (int i = 0; i < length; i++) { |
minqi@4267 | 289 | skip_ws(); |
minqi@4267 | 290 | intptr_t val = parse_intptr_t("data"); |
minqi@4267 | 291 | result[i] = val; |
minqi@4267 | 292 | } |
minqi@4267 | 293 | return result; |
minqi@4267 | 294 | } |
minqi@4267 | 295 | |
minqi@4267 | 296 | // Parse a possibly quoted version of a symbol into a symbolOop |
minqi@4267 | 297 | Symbol* parse_symbol(TRAPS) { |
minqi@4267 | 298 | const char* str = parse_escaped_string(); |
minqi@4267 | 299 | if (str != NULL) { |
minqi@4267 | 300 | Symbol* sym = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL); |
minqi@4267 | 301 | return sym; |
minqi@4267 | 302 | } |
minqi@4267 | 303 | return NULL; |
minqi@4267 | 304 | } |
minqi@4267 | 305 | |
minqi@4267 | 306 | // Parse a valid klass name and look it up |
minqi@4267 | 307 | Klass* parse_klass(TRAPS) { |
minqi@4267 | 308 | const char* str = parse_escaped_string(); |
minqi@4267 | 309 | Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL); |
minqi@4267 | 310 | if (klass_name != NULL) { |
kvn@6217 | 311 | Klass* k = NULL; |
kvn@6217 | 312 | if (_iklass != NULL) { |
kvn@6217 | 313 | k = (Klass*)_iklass->find_klass(ciSymbol::make(klass_name->as_C_string()))->constant_encoding(); |
kvn@6217 | 314 | } else { |
kvn@6217 | 315 | k = SystemDictionary::resolve_or_fail(klass_name, _loader, _protection_domain, true, THREAD); |
kvn@6217 | 316 | } |
minqi@4267 | 317 | if (HAS_PENDING_EXCEPTION) { |
minqi@4267 | 318 | oop throwable = PENDING_EXCEPTION; |
minqi@4267 | 319 | java_lang_Throwable::print(throwable, tty); |
minqi@4267 | 320 | tty->cr(); |
minqi@4267 | 321 | report_error(str); |
minqi@4267 | 322 | return NULL; |
minqi@4267 | 323 | } |
minqi@4267 | 324 | return k; |
minqi@4267 | 325 | } |
minqi@4267 | 326 | return NULL; |
minqi@4267 | 327 | } |
minqi@4267 | 328 | |
minqi@4267 | 329 | // Lookup a klass |
minqi@4267 | 330 | Klass* resolve_klass(const char* klass, TRAPS) { |
minqi@4267 | 331 | Symbol* klass_name = SymbolTable::lookup(klass, (int)strlen(klass), CHECK_NULL); |
kvn@6217 | 332 | return SystemDictionary::resolve_or_fail(klass_name, _loader, _protection_domain, true, CHECK_NULL); |
minqi@4267 | 333 | } |
minqi@4267 | 334 | |
minqi@4267 | 335 | // Parse the standard tuple of <klass> <name> <signature> |
minqi@4267 | 336 | Method* parse_method(TRAPS) { |
minqi@4267 | 337 | InstanceKlass* k = (InstanceKlass*)parse_klass(CHECK_NULL); |
minqi@4267 | 338 | Symbol* method_name = parse_symbol(CHECK_NULL); |
minqi@4267 | 339 | Symbol* method_signature = parse_symbol(CHECK_NULL); |
minqi@4267 | 340 | Method* m = k->find_method(method_name, method_signature); |
minqi@4267 | 341 | if (m == NULL) { |
minqi@5449 | 342 | report_error("Can't find method"); |
minqi@4267 | 343 | } |
minqi@4267 | 344 | return m; |
minqi@4267 | 345 | } |
minqi@4267 | 346 | |
kvn@6217 | 347 | int get_line(int c) { |
kvn@6217 | 348 | while(c != EOF) { |
kvn@6217 | 349 | if (_buffer_pos + 1 >= _buffer_length) { |
kvn@6217 | 350 | int new_length = _buffer_length * 2; |
kvn@6217 | 351 | // Next call will throw error in case of OOM. |
kvn@6217 | 352 | _buffer = REALLOC_RESOURCE_ARRAY(char, _buffer, _buffer_length, new_length); |
kvn@6217 | 353 | _buffer_length = new_length; |
kvn@6217 | 354 | } |
kvn@6217 | 355 | if (c == '\n') { |
kvn@6217 | 356 | c = getc(_stream); // get next char |
kvn@6217 | 357 | break; |
kvn@6217 | 358 | } else if (c == '\r') { |
kvn@6217 | 359 | // skip LF |
kvn@6217 | 360 | } else { |
kvn@6217 | 361 | _buffer[_buffer_pos++] = c; |
kvn@6217 | 362 | } |
kvn@6217 | 363 | c = getc(_stream); |
kvn@6217 | 364 | } |
kvn@6217 | 365 | // null terminate it, reset the pointer |
kvn@6217 | 366 | _buffer[_buffer_pos] = '\0'; // NL or EOF |
kvn@6217 | 367 | _buffer_pos = 0; |
kvn@6217 | 368 | _bufptr = _buffer; |
kvn@6217 | 369 | return c; |
kvn@6217 | 370 | } |
kvn@6217 | 371 | |
minqi@4267 | 372 | // Process each line of the replay file executing each command until |
minqi@4267 | 373 | // the file ends. |
minqi@4267 | 374 | void process(TRAPS) { |
kvn@6217 | 375 | int line_no = 1; |
kvn@6217 | 376 | int c = getc(_stream); |
minqi@4267 | 377 | while(c != EOF) { |
kvn@6217 | 378 | c = get_line(c); |
kvn@6217 | 379 | process_command(CHECK); |
kvn@6217 | 380 | if (had_error()) { |
kvn@6217 | 381 | tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message); |
kvn@6217 | 382 | tty->print_cr("%s", _buffer); |
kvn@6217 | 383 | return; |
minqi@4267 | 384 | } |
kvn@6217 | 385 | line_no++; |
minqi@4267 | 386 | } |
minqi@4267 | 387 | } |
minqi@4267 | 388 | |
minqi@4267 | 389 | void process_command(TRAPS) { |
minqi@4267 | 390 | char* cmd = parse_string(); |
minqi@4267 | 391 | if (cmd == NULL) { |
minqi@4267 | 392 | return; |
minqi@4267 | 393 | } |
minqi@4267 | 394 | if (strcmp("#", cmd) == 0) { |
minqi@4267 | 395 | // ignore |
minqi@4267 | 396 | } else if (strcmp("compile", cmd) == 0) { |
minqi@4267 | 397 | process_compile(CHECK); |
minqi@4267 | 398 | } else if (strcmp("ciMethod", cmd) == 0) { |
minqi@4267 | 399 | process_ciMethod(CHECK); |
minqi@4267 | 400 | } else if (strcmp("ciMethodData", cmd) == 0) { |
minqi@4267 | 401 | process_ciMethodData(CHECK); |
minqi@4267 | 402 | } else if (strcmp("staticfield", cmd) == 0) { |
minqi@4267 | 403 | process_staticfield(CHECK); |
minqi@4267 | 404 | } else if (strcmp("ciInstanceKlass", cmd) == 0) { |
minqi@4267 | 405 | process_ciInstanceKlass(CHECK); |
minqi@4267 | 406 | } else if (strcmp("instanceKlass", cmd) == 0) { |
minqi@4267 | 407 | process_instanceKlass(CHECK); |
minqi@4267 | 408 | #if INCLUDE_JVMTI |
minqi@4267 | 409 | } else if (strcmp("JvmtiExport", cmd) == 0) { |
minqi@4267 | 410 | process_JvmtiExport(CHECK); |
minqi@4267 | 411 | #endif // INCLUDE_JVMTI |
minqi@4267 | 412 | } else { |
minqi@4267 | 413 | report_error("unknown command"); |
minqi@4267 | 414 | } |
minqi@4267 | 415 | } |
minqi@4267 | 416 | |
iignatyev@5029 | 417 | // validation of comp_level |
iignatyev@5029 | 418 | bool is_valid_comp_level(int comp_level) { |
iignatyev@5029 | 419 | const int msg_len = 256; |
iignatyev@5029 | 420 | char* msg = NULL; |
iignatyev@5029 | 421 | if (!is_compile(comp_level)) { |
iignatyev@5029 | 422 | msg = NEW_RESOURCE_ARRAY(char, msg_len); |
iignatyev@5029 | 423 | jio_snprintf(msg, msg_len, "%d isn't compilation level", comp_level); |
iignatyev@5029 | 424 | } else if (!TieredCompilation && (comp_level != CompLevel_highest_tier)) { |
iignatyev@5029 | 425 | msg = NEW_RESOURCE_ARRAY(char, msg_len); |
iignatyev@5029 | 426 | switch (comp_level) { |
iignatyev@5029 | 427 | case CompLevel_simple: |
iignatyev@5029 | 428 | jio_snprintf(msg, msg_len, "compilation level %d requires Client VM or TieredCompilation", comp_level); |
iignatyev@5029 | 429 | break; |
iignatyev@5029 | 430 | case CompLevel_full_optimization: |
iignatyev@5029 | 431 | jio_snprintf(msg, msg_len, "compilation level %d requires Server VM", comp_level); |
iignatyev@5029 | 432 | break; |
iignatyev@5029 | 433 | default: |
iignatyev@5029 | 434 | jio_snprintf(msg, msg_len, "compilation level %d requires TieredCompilation", comp_level); |
iignatyev@5029 | 435 | } |
iignatyev@5029 | 436 | } |
iignatyev@5029 | 437 | if (msg != NULL) { |
iignatyev@5029 | 438 | report_error(msg); |
iignatyev@5029 | 439 | return false; |
iignatyev@5029 | 440 | } |
iignatyev@5029 | 441 | return true; |
iignatyev@5029 | 442 | } |
iignatyev@5029 | 443 | |
kvn@6217 | 444 | // compile <klass> <name> <signature> <entry_bci> <comp_level> inline <count> <depth> <bci> <klass> <name> <signature> ... |
kvn@6217 | 445 | void* process_inline(ciMethod* imethod, Method* m, int entry_bci, int comp_level, TRAPS) { |
kvn@6217 | 446 | _imethod = m; |
kvn@6217 | 447 | _iklass = imethod->holder(); |
kvn@6217 | 448 | _entry_bci = entry_bci; |
kvn@6217 | 449 | _comp_level = comp_level; |
kvn@6217 | 450 | int line_no = 1; |
kvn@6217 | 451 | int c = getc(_stream); |
kvn@6217 | 452 | while(c != EOF) { |
kvn@6217 | 453 | c = get_line(c); |
kvn@6217 | 454 | // Expecting only lines with "compile" command in inline replay file. |
kvn@6217 | 455 | char* cmd = parse_string(); |
kvn@6217 | 456 | if (cmd == NULL || strcmp("compile", cmd) != 0) { |
kvn@6217 | 457 | return NULL; |
kvn@6217 | 458 | } |
kvn@6217 | 459 | process_compile(CHECK_NULL); |
kvn@6217 | 460 | if (had_error()) { |
kvn@6217 | 461 | tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message); |
kvn@6217 | 462 | tty->print_cr("%s", _buffer); |
kvn@6217 | 463 | return NULL; |
kvn@6217 | 464 | } |
kvn@6217 | 465 | if (_ci_inline_records != NULL && _ci_inline_records->length() > 0) { |
kvn@6217 | 466 | // Found inlining record for the requested method. |
kvn@6217 | 467 | return _ci_inline_records; |
kvn@6217 | 468 | } |
kvn@6217 | 469 | line_no++; |
kvn@6217 | 470 | } |
kvn@6217 | 471 | return NULL; |
kvn@6217 | 472 | } |
kvn@6217 | 473 | |
kvn@6217 | 474 | // compile <klass> <name> <signature> <entry_bci> <comp_level> inline <count> <depth> <bci> <klass> <name> <signature> ... |
minqi@4267 | 475 | void process_compile(TRAPS) { |
minqi@4267 | 476 | Method* method = parse_method(CHECK); |
minqi@5449 | 477 | if (had_error()) return; |
minqi@4267 | 478 | int entry_bci = parse_int("entry_bci"); |
iignatyev@5029 | 479 | const char* comp_level_label = "comp_level"; |
iignatyev@5029 | 480 | int comp_level = parse_int(comp_level_label); |
iignatyev@5029 | 481 | // old version w/o comp_level |
iignatyev@5029 | 482 | if (had_error() && (error_message() == comp_level_label)) { |
iignatyev@5029 | 483 | comp_level = CompLevel_full_optimization; |
iignatyev@5029 | 484 | } |
iignatyev@5029 | 485 | if (!is_valid_comp_level(comp_level)) { |
iignatyev@5029 | 486 | return; |
iignatyev@5029 | 487 | } |
kvn@6217 | 488 | if (_imethod != NULL) { |
kvn@6217 | 489 | // Replay Inlining |
kvn@6217 | 490 | if (entry_bci != _entry_bci || comp_level != _comp_level) { |
kvn@6217 | 491 | return; |
kvn@6217 | 492 | } |
kvn@6217 | 493 | const char* iklass_name = _imethod->method_holder()->name()->as_utf8(); |
kvn@6217 | 494 | const char* imethod_name = _imethod->name()->as_utf8(); |
kvn@6217 | 495 | const char* isignature = _imethod->signature()->as_utf8(); |
kvn@6217 | 496 | const char* klass_name = method->method_holder()->name()->as_utf8(); |
kvn@6217 | 497 | const char* method_name = method->name()->as_utf8(); |
kvn@6217 | 498 | const char* signature = method->signature()->as_utf8(); |
kvn@6217 | 499 | if (strcmp(iklass_name, klass_name) != 0 || |
kvn@6217 | 500 | strcmp(imethod_name, method_name) != 0 || |
kvn@6217 | 501 | strcmp(isignature, signature) != 0) { |
kvn@6217 | 502 | return; |
kvn@6217 | 503 | } |
kvn@6217 | 504 | } |
kvn@6217 | 505 | int inline_count = 0; |
kvn@6217 | 506 | if (parse_tag_and_count("inline", inline_count)) { |
kvn@6217 | 507 | // Record inlining data |
kvn@6217 | 508 | _ci_inline_records = new GrowableArray<ciInlineRecord*>(); |
kvn@6217 | 509 | for (int i = 0; i < inline_count; i++) { |
kvn@6217 | 510 | int depth = parse_int("inline_depth"); |
kvn@6217 | 511 | int bci = parse_int("inline_bci"); |
kvn@6217 | 512 | if (had_error()) { |
kvn@6217 | 513 | break; |
kvn@6217 | 514 | } |
kvn@6217 | 515 | Method* inl_method = parse_method(CHECK); |
kvn@6217 | 516 | if (had_error()) { |
kvn@6217 | 517 | break; |
kvn@6217 | 518 | } |
kvn@6217 | 519 | new_ciInlineRecord(inl_method, bci, depth); |
kvn@6217 | 520 | } |
kvn@6217 | 521 | } |
kvn@6217 | 522 | if (_imethod != NULL) { |
kvn@6217 | 523 | return; // Replay Inlining |
kvn@6217 | 524 | } |
minqi@4267 | 525 | Klass* k = method->method_holder(); |
minqi@4267 | 526 | ((InstanceKlass*)k)->initialize(THREAD); |
minqi@4267 | 527 | if (HAS_PENDING_EXCEPTION) { |
minqi@4267 | 528 | oop throwable = PENDING_EXCEPTION; |
minqi@4267 | 529 | java_lang_Throwable::print(throwable, tty); |
minqi@4267 | 530 | tty->cr(); |
minqi@4267 | 531 | if (ReplayIgnoreInitErrors) { |
minqi@4267 | 532 | CLEAR_PENDING_EXCEPTION; |
minqi@4267 | 533 | ((InstanceKlass*)k)->set_init_state(InstanceKlass::fully_initialized); |
minqi@4267 | 534 | } else { |
minqi@4267 | 535 | return; |
minqi@4267 | 536 | } |
minqi@4267 | 537 | } |
minqi@4267 | 538 | // Make sure the existence of a prior compile doesn't stop this one |
iignatyev@5029 | 539 | nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code(); |
minqi@4267 | 540 | if (nm != NULL) { |
minqi@4267 | 541 | nm->make_not_entrant(); |
minqi@4267 | 542 | } |
minqi@4267 | 543 | replay_state = this; |
iignatyev@5029 | 544 | CompileBroker::compile_method(method, entry_bci, comp_level, |
minqi@4267 | 545 | methodHandle(), 0, "replay", THREAD); |
minqi@4267 | 546 | replay_state = NULL; |
minqi@4267 | 547 | reset(); |
minqi@4267 | 548 | } |
minqi@4267 | 549 | |
minqi@4267 | 550 | // ciMethod <klass> <name> <signature> <invocation_counter> <backedge_counter> <interpreter_invocation_count> <interpreter_throwout_count> <instructions_size> |
minqi@4267 | 551 | // |
minqi@4267 | 552 | // |
minqi@4267 | 553 | void process_ciMethod(TRAPS) { |
minqi@4267 | 554 | Method* method = parse_method(CHECK); |
minqi@5449 | 555 | if (had_error()) return; |
minqi@4267 | 556 | ciMethodRecord* rec = new_ciMethod(method); |
kvn@6217 | 557 | rec->_invocation_counter = parse_int("invocation_counter"); |
kvn@6217 | 558 | rec->_backedge_counter = parse_int("backedge_counter"); |
kvn@6217 | 559 | rec->_interpreter_invocation_count = parse_int("interpreter_invocation_count"); |
kvn@6217 | 560 | rec->_interpreter_throwout_count = parse_int("interpreter_throwout_count"); |
kvn@6217 | 561 | rec->_instructions_size = parse_int("instructions_size"); |
minqi@4267 | 562 | } |
minqi@4267 | 563 | |
minqi@4267 | 564 | // ciMethodData <klass> <name> <signature> <state> <current mileage> orig <length> # # ... data <length> # # ... oops <length> |
minqi@4267 | 565 | void process_ciMethodData(TRAPS) { |
minqi@4267 | 566 | Method* method = parse_method(CHECK); |
minqi@5449 | 567 | if (had_error()) return; |
minqi@4267 | 568 | /* jsut copied from Method, to build interpret data*/ |
minqi@4267 | 569 | if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) { |
minqi@4267 | 570 | return; |
minqi@4267 | 571 | } |
minqi@4267 | 572 | // methodOopDesc::build_interpreter_method_data(method, CHECK); |
minqi@4267 | 573 | { |
minqi@4267 | 574 | // Grab a lock here to prevent multiple |
minqi@4267 | 575 | // MethodData*s from being created. |
minqi@4267 | 576 | MutexLocker ml(MethodData_lock, THREAD); |
minqi@4267 | 577 | if (method->method_data() == NULL) { |
minqi@4267 | 578 | ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); |
minqi@4267 | 579 | MethodData* method_data = MethodData::allocate(loader_data, method, CHECK); |
minqi@4267 | 580 | method->set_method_data(method_data); |
minqi@4267 | 581 | } |
minqi@4267 | 582 | } |
minqi@4267 | 583 | |
minqi@4267 | 584 | // collect and record all the needed information for later |
minqi@4267 | 585 | ciMethodDataRecord* rec = new_ciMethodData(method); |
kvn@6217 | 586 | rec->_state = parse_int("state"); |
kvn@6217 | 587 | rec->_current_mileage = parse_int("current_mileage"); |
minqi@4267 | 588 | |
kvn@6217 | 589 | rec->_orig_data = parse_data("orig", rec->_orig_data_length); |
kvn@6217 | 590 | if (rec->_orig_data == NULL) { |
minqi@4267 | 591 | return; |
minqi@4267 | 592 | } |
kvn@6217 | 593 | rec->_data = parse_intptr_data("data", rec->_data_length); |
kvn@6217 | 594 | if (rec->_data == NULL) { |
minqi@4267 | 595 | return; |
minqi@4267 | 596 | } |
kvn@6217 | 597 | if (!parse_tag_and_count("oops", rec->_oops_length)) { |
minqi@4267 | 598 | return; |
minqi@4267 | 599 | } |
kvn@6217 | 600 | rec->_oops_handles = NEW_RESOURCE_ARRAY(jobject, rec->_oops_length); |
kvn@6217 | 601 | rec->_oops_offsets = NEW_RESOURCE_ARRAY(int, rec->_oops_length); |
kvn@6217 | 602 | for (int i = 0; i < rec->_oops_length; i++) { |
minqi@4267 | 603 | int offset = parse_int("offset"); |
minqi@4267 | 604 | if (had_error()) { |
minqi@4267 | 605 | return; |
minqi@4267 | 606 | } |
minqi@4267 | 607 | Klass* k = parse_klass(CHECK); |
kvn@6217 | 608 | rec->_oops_offsets[i] = offset; |
minqi@5103 | 609 | KlassHandle *kh = NEW_C_HEAP_OBJ(KlassHandle, mtCompiler); |
minqi@5103 | 610 | ::new ((void*)kh) KlassHandle(THREAD, k); |
kvn@6217 | 611 | rec->_oops_handles[i] = (jobject)kh; |
minqi@4267 | 612 | } |
minqi@4267 | 613 | } |
minqi@4267 | 614 | |
minqi@4267 | 615 | // instanceKlass <name> |
minqi@4267 | 616 | // |
minqi@4267 | 617 | // Loads and initializes the klass 'name'. This can be used to |
minqi@4267 | 618 | // create particular class loading environments |
minqi@4267 | 619 | void process_instanceKlass(TRAPS) { |
minqi@4267 | 620 | // just load the referenced class |
minqi@4267 | 621 | Klass* k = parse_klass(CHECK); |
minqi@4267 | 622 | } |
minqi@4267 | 623 | |
minqi@4267 | 624 | // ciInstanceKlass <name> <is_linked> <is_initialized> <length> tag # # # ... |
minqi@4267 | 625 | // |
minqi@4267 | 626 | // Load the klass 'name' and link or initialize it. Verify that the |
minqi@4267 | 627 | // constant pool is the same length as 'length' and make sure the |
minqi@4267 | 628 | // constant pool tags are in the same state. |
minqi@4267 | 629 | void process_ciInstanceKlass(TRAPS) { |
minqi@4267 | 630 | InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK); |
minqi@4267 | 631 | int is_linked = parse_int("is_linked"); |
minqi@4267 | 632 | int is_initialized = parse_int("is_initialized"); |
minqi@4267 | 633 | int length = parse_int("length"); |
minqi@4267 | 634 | if (is_initialized) { |
minqi@4267 | 635 | k->initialize(THREAD); |
minqi@4267 | 636 | if (HAS_PENDING_EXCEPTION) { |
minqi@4267 | 637 | oop throwable = PENDING_EXCEPTION; |
minqi@4267 | 638 | java_lang_Throwable::print(throwable, tty); |
minqi@4267 | 639 | tty->cr(); |
minqi@4267 | 640 | if (ReplayIgnoreInitErrors) { |
minqi@4267 | 641 | CLEAR_PENDING_EXCEPTION; |
minqi@4267 | 642 | k->set_init_state(InstanceKlass::fully_initialized); |
minqi@4267 | 643 | } else { |
minqi@4267 | 644 | return; |
minqi@4267 | 645 | } |
minqi@4267 | 646 | } |
minqi@4267 | 647 | } else if (is_linked) { |
minqi@4267 | 648 | k->link_class(CHECK); |
minqi@4267 | 649 | } |
minqi@4267 | 650 | ConstantPool* cp = k->constants(); |
minqi@4267 | 651 | if (length != cp->length()) { |
minqi@4267 | 652 | report_error("constant pool length mismatch: wrong class files?"); |
minqi@4267 | 653 | return; |
minqi@4267 | 654 | } |
minqi@4267 | 655 | |
minqi@4267 | 656 | int parsed_two_word = 0; |
minqi@4267 | 657 | for (int i = 1; i < length; i++) { |
minqi@4267 | 658 | int tag = parse_int("tag"); |
minqi@4267 | 659 | if (had_error()) { |
minqi@4267 | 660 | return; |
minqi@4267 | 661 | } |
minqi@4267 | 662 | switch (cp->tag_at(i).value()) { |
minqi@4267 | 663 | case JVM_CONSTANT_UnresolvedClass: { |
minqi@4267 | 664 | if (tag == JVM_CONSTANT_Class) { |
minqi@4267 | 665 | tty->print_cr("Resolving klass %s at %d", cp->unresolved_klass_at(i)->as_utf8(), i); |
minqi@4267 | 666 | Klass* k = cp->klass_at(i, CHECK); |
minqi@4267 | 667 | } |
minqi@4267 | 668 | break; |
minqi@4267 | 669 | } |
minqi@4267 | 670 | case JVM_CONSTANT_Long: |
minqi@4267 | 671 | case JVM_CONSTANT_Double: |
minqi@4267 | 672 | parsed_two_word = i + 1; |
minqi@4267 | 673 | |
minqi@4267 | 674 | case JVM_CONSTANT_ClassIndex: |
minqi@4267 | 675 | case JVM_CONSTANT_StringIndex: |
minqi@4267 | 676 | case JVM_CONSTANT_String: |
minqi@4267 | 677 | case JVM_CONSTANT_UnresolvedClassInError: |
minqi@4267 | 678 | case JVM_CONSTANT_Fieldref: |
minqi@4267 | 679 | case JVM_CONSTANT_Methodref: |
minqi@4267 | 680 | case JVM_CONSTANT_InterfaceMethodref: |
minqi@4267 | 681 | case JVM_CONSTANT_NameAndType: |
minqi@4267 | 682 | case JVM_CONSTANT_Utf8: |
minqi@4267 | 683 | case JVM_CONSTANT_Integer: |
minqi@4267 | 684 | case JVM_CONSTANT_Float: |
kvn@6217 | 685 | case JVM_CONSTANT_MethodHandle: |
kvn@6217 | 686 | case JVM_CONSTANT_MethodType: |
kvn@6217 | 687 | case JVM_CONSTANT_InvokeDynamic: |
minqi@4267 | 688 | if (tag != cp->tag_at(i).value()) { |
minqi@4267 | 689 | report_error("tag mismatch: wrong class files?"); |
minqi@4267 | 690 | return; |
minqi@4267 | 691 | } |
minqi@4267 | 692 | break; |
minqi@4267 | 693 | |
minqi@4267 | 694 | case JVM_CONSTANT_Class: |
minqi@4267 | 695 | if (tag == JVM_CONSTANT_Class) { |
minqi@4267 | 696 | } else if (tag == JVM_CONSTANT_UnresolvedClass) { |
minqi@4267 | 697 | tty->print_cr("Warning: entry was unresolved in the replay data"); |
minqi@4267 | 698 | } else { |
minqi@4267 | 699 | report_error("Unexpected tag"); |
minqi@4267 | 700 | return; |
minqi@4267 | 701 | } |
minqi@4267 | 702 | break; |
minqi@4267 | 703 | |
minqi@4267 | 704 | case 0: |
minqi@4267 | 705 | if (parsed_two_word == i) continue; |
minqi@4267 | 706 | |
minqi@4267 | 707 | default: |
vlivanov@5027 | 708 | fatal(err_msg_res("Unexpected tag: %d", cp->tag_at(i).value())); |
minqi@4267 | 709 | break; |
minqi@4267 | 710 | } |
minqi@4267 | 711 | |
minqi@4267 | 712 | } |
minqi@4267 | 713 | } |
minqi@4267 | 714 | |
minqi@4267 | 715 | // Initialize a class and fill in the value for a static field. |
minqi@4267 | 716 | // This is useful when the compile was dependent on the value of |
minqi@4267 | 717 | // static fields but it's impossible to properly rerun the static |
minqi@4267 | 718 | // initiailizer. |
minqi@4267 | 719 | void process_staticfield(TRAPS) { |
minqi@4267 | 720 | InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK); |
minqi@4267 | 721 | |
minqi@4267 | 722 | if (ReplaySuppressInitializers == 0 || |
minqi@4267 | 723 | ReplaySuppressInitializers == 2 && k->class_loader() == NULL) { |
minqi@4267 | 724 | return; |
minqi@4267 | 725 | } |
minqi@4267 | 726 | |
minqi@4267 | 727 | assert(k->is_initialized(), "must be"); |
minqi@4267 | 728 | |
minqi@4267 | 729 | const char* field_name = parse_escaped_string();; |
minqi@4267 | 730 | const char* field_signature = parse_string(); |
minqi@4267 | 731 | fieldDescriptor fd; |
minqi@4267 | 732 | Symbol* name = SymbolTable::lookup(field_name, (int)strlen(field_name), CHECK); |
minqi@4267 | 733 | Symbol* sig = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK); |
minqi@4267 | 734 | if (!k->find_local_field(name, sig, &fd) || |
minqi@4267 | 735 | !fd.is_static() || |
minqi@4267 | 736 | fd.has_initial_value()) { |
minqi@4267 | 737 | report_error(field_name); |
minqi@4267 | 738 | return; |
minqi@4267 | 739 | } |
minqi@4267 | 740 | |
minqi@4267 | 741 | oop java_mirror = k->java_mirror(); |
minqi@4267 | 742 | if (field_signature[0] == '[') { |
minqi@4267 | 743 | int length = parse_int("array length"); |
minqi@4267 | 744 | oop value = NULL; |
minqi@4267 | 745 | |
minqi@4267 | 746 | if (field_signature[1] == '[') { |
minqi@4267 | 747 | // multi dimensional array |
minqi@4267 | 748 | ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK); |
minqi@4267 | 749 | int rank = 0; |
minqi@4267 | 750 | while (field_signature[rank] == '[') { |
minqi@4267 | 751 | rank++; |
minqi@4267 | 752 | } |
minqi@4267 | 753 | int* dims = NEW_RESOURCE_ARRAY(int, rank); |
minqi@4267 | 754 | dims[0] = length; |
minqi@4267 | 755 | for (int i = 1; i < rank; i++) { |
minqi@4267 | 756 | dims[i] = 1; // These aren't relevant to the compiler |
minqi@4267 | 757 | } |
minqi@4267 | 758 | value = kelem->multi_allocate(rank, dims, CHECK); |
minqi@4267 | 759 | } else { |
minqi@4267 | 760 | if (strcmp(field_signature, "[B") == 0) { |
minqi@4267 | 761 | value = oopFactory::new_byteArray(length, CHECK); |
minqi@4267 | 762 | } else if (strcmp(field_signature, "[Z") == 0) { |
minqi@4267 | 763 | value = oopFactory::new_boolArray(length, CHECK); |
minqi@4267 | 764 | } else if (strcmp(field_signature, "[C") == 0) { |
minqi@4267 | 765 | value = oopFactory::new_charArray(length, CHECK); |
minqi@4267 | 766 | } else if (strcmp(field_signature, "[S") == 0) { |
minqi@4267 | 767 | value = oopFactory::new_shortArray(length, CHECK); |
minqi@4267 | 768 | } else if (strcmp(field_signature, "[F") == 0) { |
minqi@4267 | 769 | value = oopFactory::new_singleArray(length, CHECK); |
minqi@4267 | 770 | } else if (strcmp(field_signature, "[D") == 0) { |
minqi@4267 | 771 | value = oopFactory::new_doubleArray(length, CHECK); |
minqi@4267 | 772 | } else if (strcmp(field_signature, "[I") == 0) { |
minqi@4267 | 773 | value = oopFactory::new_intArray(length, CHECK); |
minqi@4267 | 774 | } else if (strcmp(field_signature, "[J") == 0) { |
minqi@4267 | 775 | value = oopFactory::new_longArray(length, CHECK); |
minqi@4267 | 776 | } else if (field_signature[0] == '[' && field_signature[1] == 'L') { |
minqi@4267 | 777 | KlassHandle kelem = resolve_klass(field_signature + 1, CHECK); |
minqi@4267 | 778 | value = oopFactory::new_objArray(kelem(), length, CHECK); |
minqi@4267 | 779 | } else { |
minqi@4267 | 780 | report_error("unhandled array staticfield"); |
minqi@4267 | 781 | } |
minqi@4267 | 782 | } |
minqi@4267 | 783 | java_mirror->obj_field_put(fd.offset(), value); |
minqi@4267 | 784 | } else { |
minqi@4267 | 785 | const char* string_value = parse_escaped_string(); |
minqi@4267 | 786 | if (strcmp(field_signature, "I") == 0) { |
minqi@4267 | 787 | int value = atoi(string_value); |
minqi@4267 | 788 | java_mirror->int_field_put(fd.offset(), value); |
minqi@4267 | 789 | } else if (strcmp(field_signature, "B") == 0) { |
minqi@4267 | 790 | int value = atoi(string_value); |
minqi@4267 | 791 | java_mirror->byte_field_put(fd.offset(), value); |
minqi@4267 | 792 | } else if (strcmp(field_signature, "C") == 0) { |
minqi@4267 | 793 | int value = atoi(string_value); |
minqi@4267 | 794 | java_mirror->char_field_put(fd.offset(), value); |
minqi@4267 | 795 | } else if (strcmp(field_signature, "S") == 0) { |
minqi@4267 | 796 | int value = atoi(string_value); |
minqi@4267 | 797 | java_mirror->short_field_put(fd.offset(), value); |
minqi@4267 | 798 | } else if (strcmp(field_signature, "Z") == 0) { |
minqi@4267 | 799 | int value = atol(string_value); |
minqi@4267 | 800 | java_mirror->bool_field_put(fd.offset(), value); |
minqi@4267 | 801 | } else if (strcmp(field_signature, "J") == 0) { |
minqi@4267 | 802 | jlong value; |
hseigel@4465 | 803 | if (sscanf(string_value, JLONG_FORMAT, &value) != 1) { |
minqi@4267 | 804 | fprintf(stderr, "Error parsing long: %s\n", string_value); |
minqi@4267 | 805 | return; |
minqi@4267 | 806 | } |
minqi@4267 | 807 | java_mirror->long_field_put(fd.offset(), value); |
minqi@4267 | 808 | } else if (strcmp(field_signature, "F") == 0) { |
minqi@4267 | 809 | float value = atof(string_value); |
minqi@4267 | 810 | java_mirror->float_field_put(fd.offset(), value); |
minqi@4267 | 811 | } else if (strcmp(field_signature, "D") == 0) { |
minqi@4267 | 812 | double value = atof(string_value); |
minqi@4267 | 813 | java_mirror->double_field_put(fd.offset(), value); |
minqi@4267 | 814 | } else if (strcmp(field_signature, "Ljava/lang/String;") == 0) { |
minqi@4267 | 815 | Handle value = java_lang_String::create_from_str(string_value, CHECK); |
minqi@4267 | 816 | java_mirror->obj_field_put(fd.offset(), value()); |
minqi@4267 | 817 | } else if (field_signature[0] == 'L') { |
minqi@4267 | 818 | Symbol* klass_name = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK); |
minqi@4267 | 819 | KlassHandle kelem = resolve_klass(field_signature, CHECK); |
minqi@4267 | 820 | oop value = ((InstanceKlass*)kelem())->allocate_instance(CHECK); |
minqi@4267 | 821 | java_mirror->obj_field_put(fd.offset(), value); |
minqi@4267 | 822 | } else { |
minqi@4267 | 823 | report_error("unhandled staticfield"); |
minqi@4267 | 824 | } |
minqi@4267 | 825 | } |
minqi@4267 | 826 | } |
minqi@4267 | 827 | |
minqi@4267 | 828 | #if INCLUDE_JVMTI |
minqi@4267 | 829 | void process_JvmtiExport(TRAPS) { |
minqi@4267 | 830 | const char* field = parse_string(); |
minqi@4267 | 831 | bool value = parse_int("JvmtiExport flag") != 0; |
minqi@4267 | 832 | if (strcmp(field, "can_access_local_variables") == 0) { |
minqi@4267 | 833 | JvmtiExport::set_can_access_local_variables(value); |
minqi@4267 | 834 | } else if (strcmp(field, "can_hotswap_or_post_breakpoint") == 0) { |
minqi@4267 | 835 | JvmtiExport::set_can_hotswap_or_post_breakpoint(value); |
minqi@4267 | 836 | } else if (strcmp(field, "can_post_on_exceptions") == 0) { |
minqi@4267 | 837 | JvmtiExport::set_can_post_on_exceptions(value); |
minqi@4267 | 838 | } else { |
minqi@4267 | 839 | report_error("Unrecognized JvmtiExport directive"); |
minqi@4267 | 840 | } |
minqi@4267 | 841 | } |
minqi@4267 | 842 | #endif // INCLUDE_JVMTI |
minqi@4267 | 843 | |
minqi@4267 | 844 | // Create and initialize a record for a ciMethod |
minqi@4267 | 845 | ciMethodRecord* new_ciMethod(Method* method) { |
minqi@4267 | 846 | ciMethodRecord* rec = NEW_RESOURCE_OBJ(ciMethodRecord); |
kvn@6217 | 847 | rec->_klass_name = method->method_holder()->name()->as_utf8(); |
kvn@6217 | 848 | rec->_method_name = method->name()->as_utf8(); |
kvn@6217 | 849 | rec->_signature = method->signature()->as_utf8(); |
kvn@6217 | 850 | _ci_method_records.append(rec); |
minqi@4267 | 851 | return rec; |
minqi@4267 | 852 | } |
minqi@4267 | 853 | |
minqi@4267 | 854 | // Lookup data for a ciMethod |
minqi@4267 | 855 | ciMethodRecord* find_ciMethodRecord(Method* method) { |
minqi@4267 | 856 | const char* klass_name = method->method_holder()->name()->as_utf8(); |
minqi@4267 | 857 | const char* method_name = method->name()->as_utf8(); |
minqi@4267 | 858 | const char* signature = method->signature()->as_utf8(); |
kvn@6217 | 859 | for (int i = 0; i < _ci_method_records.length(); i++) { |
kvn@6217 | 860 | ciMethodRecord* rec = _ci_method_records.at(i); |
kvn@6217 | 861 | if (strcmp(rec->_klass_name, klass_name) == 0 && |
kvn@6217 | 862 | strcmp(rec->_method_name, method_name) == 0 && |
kvn@6217 | 863 | strcmp(rec->_signature, signature) == 0) { |
minqi@4267 | 864 | return rec; |
minqi@4267 | 865 | } |
minqi@4267 | 866 | } |
minqi@4267 | 867 | return NULL; |
minqi@4267 | 868 | } |
minqi@4267 | 869 | |
minqi@4267 | 870 | // Create and initialize a record for a ciMethodData |
minqi@4267 | 871 | ciMethodDataRecord* new_ciMethodData(Method* method) { |
minqi@4267 | 872 | ciMethodDataRecord* rec = NEW_RESOURCE_OBJ(ciMethodDataRecord); |
kvn@6217 | 873 | rec->_klass_name = method->method_holder()->name()->as_utf8(); |
kvn@6217 | 874 | rec->_method_name = method->name()->as_utf8(); |
kvn@6217 | 875 | rec->_signature = method->signature()->as_utf8(); |
kvn@6217 | 876 | _ci_method_data_records.append(rec); |
minqi@4267 | 877 | return rec; |
minqi@4267 | 878 | } |
minqi@4267 | 879 | |
minqi@4267 | 880 | // Lookup data for a ciMethodData |
minqi@4267 | 881 | ciMethodDataRecord* find_ciMethodDataRecord(Method* method) { |
minqi@4267 | 882 | const char* klass_name = method->method_holder()->name()->as_utf8(); |
minqi@4267 | 883 | const char* method_name = method->name()->as_utf8(); |
minqi@4267 | 884 | const char* signature = method->signature()->as_utf8(); |
kvn@6217 | 885 | for (int i = 0; i < _ci_method_data_records.length(); i++) { |
kvn@6217 | 886 | ciMethodDataRecord* rec = _ci_method_data_records.at(i); |
kvn@6217 | 887 | if (strcmp(rec->_klass_name, klass_name) == 0 && |
kvn@6217 | 888 | strcmp(rec->_method_name, method_name) == 0 && |
kvn@6217 | 889 | strcmp(rec->_signature, signature) == 0) { |
minqi@4267 | 890 | return rec; |
minqi@4267 | 891 | } |
minqi@4267 | 892 | } |
minqi@4267 | 893 | return NULL; |
minqi@4267 | 894 | } |
minqi@4267 | 895 | |
kvn@6217 | 896 | // Create and initialize a record for a ciInlineRecord |
kvn@6217 | 897 | ciInlineRecord* new_ciInlineRecord(Method* method, int bci, int depth) { |
kvn@6217 | 898 | ciInlineRecord* rec = NEW_RESOURCE_OBJ(ciInlineRecord); |
kvn@6217 | 899 | rec->_klass_name = method->method_holder()->name()->as_utf8(); |
kvn@6217 | 900 | rec->_method_name = method->name()->as_utf8(); |
kvn@6217 | 901 | rec->_signature = method->signature()->as_utf8(); |
kvn@6217 | 902 | rec->_inline_bci = bci; |
kvn@6217 | 903 | rec->_inline_depth = depth; |
kvn@6217 | 904 | _ci_inline_records->append(rec); |
kvn@6217 | 905 | return rec; |
kvn@6217 | 906 | } |
kvn@6217 | 907 | |
kvn@6217 | 908 | // Lookup inlining data for a ciMethod |
kvn@6217 | 909 | ciInlineRecord* find_ciInlineRecord(Method* method, int bci, int depth) { |
kvn@6217 | 910 | if (_ci_inline_records != NULL) { |
kvn@6217 | 911 | return find_ciInlineRecord(_ci_inline_records, method, bci, depth); |
kvn@6217 | 912 | } |
kvn@6217 | 913 | return NULL; |
kvn@6217 | 914 | } |
kvn@6217 | 915 | |
kvn@6217 | 916 | static ciInlineRecord* find_ciInlineRecord(GrowableArray<ciInlineRecord*>* records, |
kvn@6217 | 917 | Method* method, int bci, int depth) { |
kvn@6217 | 918 | if (records != NULL) { |
kvn@6217 | 919 | const char* klass_name = method->method_holder()->name()->as_utf8(); |
kvn@6217 | 920 | const char* method_name = method->name()->as_utf8(); |
kvn@6217 | 921 | const char* signature = method->signature()->as_utf8(); |
kvn@6217 | 922 | for (int i = 0; i < records->length(); i++) { |
kvn@6217 | 923 | ciInlineRecord* rec = records->at(i); |
kvn@6217 | 924 | if ((rec->_inline_bci == bci) && |
kvn@6217 | 925 | (rec->_inline_depth == depth) && |
kvn@6217 | 926 | (strcmp(rec->_klass_name, klass_name) == 0) && |
kvn@6217 | 927 | (strcmp(rec->_method_name, method_name) == 0) && |
kvn@6217 | 928 | (strcmp(rec->_signature, signature) == 0)) { |
kvn@6217 | 929 | return rec; |
kvn@6217 | 930 | } |
kvn@6217 | 931 | } |
kvn@6217 | 932 | } |
kvn@6217 | 933 | return NULL; |
kvn@6217 | 934 | } |
kvn@6217 | 935 | |
minqi@4267 | 936 | const char* error_message() { |
minqi@4267 | 937 | return _error_message; |
minqi@4267 | 938 | } |
minqi@4267 | 939 | |
minqi@4267 | 940 | void reset() { |
minqi@4267 | 941 | _error_message = NULL; |
kvn@6217 | 942 | _ci_method_records.clear(); |
kvn@6217 | 943 | _ci_method_data_records.clear(); |
minqi@4267 | 944 | } |
minqi@4267 | 945 | |
minqi@4267 | 946 | // Take an ascii string contain \u#### escapes and convert it to utf8 |
minqi@4267 | 947 | // in place. |
minqi@4267 | 948 | static void unescape_string(char* value) { |
minqi@4267 | 949 | char* from = value; |
minqi@4267 | 950 | char* to = value; |
minqi@4267 | 951 | while (*from != '\0') { |
minqi@4267 | 952 | if (*from != '\\') { |
minqi@4267 | 953 | *from++ = *to++; |
minqi@4267 | 954 | } else { |
minqi@4267 | 955 | switch (from[1]) { |
minqi@4267 | 956 | case 'u': { |
minqi@4267 | 957 | from += 2; |
minqi@4267 | 958 | jchar value=0; |
minqi@4267 | 959 | for (int i=0; i<4; i++) { |
minqi@4267 | 960 | char c = *from++; |
minqi@4267 | 961 | switch (c) { |
minqi@4267 | 962 | case '0': case '1': case '2': case '3': case '4': |
minqi@4267 | 963 | case '5': case '6': case '7': case '8': case '9': |
minqi@4267 | 964 | value = (value << 4) + c - '0'; |
minqi@4267 | 965 | break; |
minqi@4267 | 966 | case 'a': case 'b': case 'c': |
minqi@4267 | 967 | case 'd': case 'e': case 'f': |
minqi@4267 | 968 | value = (value << 4) + 10 + c - 'a'; |
minqi@4267 | 969 | break; |
minqi@4267 | 970 | case 'A': case 'B': case 'C': |
minqi@4267 | 971 | case 'D': case 'E': case 'F': |
minqi@4267 | 972 | value = (value << 4) + 10 + c - 'A'; |
minqi@4267 | 973 | break; |
minqi@4267 | 974 | default: |
minqi@4267 | 975 | ShouldNotReachHere(); |
minqi@4267 | 976 | } |
minqi@4267 | 977 | } |
minqi@4267 | 978 | UNICODE::convert_to_utf8(&value, 1, to); |
minqi@4267 | 979 | to++; |
minqi@4267 | 980 | break; |
minqi@4267 | 981 | } |
minqi@4267 | 982 | case 't': *to++ = '\t'; from += 2; break; |
minqi@4267 | 983 | case 'n': *to++ = '\n'; from += 2; break; |
minqi@4267 | 984 | case 'r': *to++ = '\r'; from += 2; break; |
minqi@4267 | 985 | case 'f': *to++ = '\f'; from += 2; break; |
minqi@4267 | 986 | default: |
minqi@4267 | 987 | ShouldNotReachHere(); |
minqi@4267 | 988 | } |
minqi@4267 | 989 | } |
minqi@4267 | 990 | } |
minqi@4267 | 991 | *from = *to; |
minqi@4267 | 992 | } |
minqi@4267 | 993 | }; |
minqi@4267 | 994 | |
minqi@4267 | 995 | void ciReplay::replay(TRAPS) { |
minqi@4267 | 996 | int exit_code = replay_impl(THREAD); |
minqi@4267 | 997 | |
minqi@4267 | 998 | Threads::destroy_vm(); |
minqi@4267 | 999 | |
minqi@4267 | 1000 | vm_exit(exit_code); |
minqi@4267 | 1001 | } |
minqi@4267 | 1002 | |
kvn@6217 | 1003 | void* ciReplay::load_inline_data(ciMethod* method, int entry_bci, int comp_level) { |
kvn@6217 | 1004 | if (FLAG_IS_DEFAULT(InlineDataFile)) { |
kvn@6217 | 1005 | tty->print_cr("ERROR: no inline replay data file specified (use -XX:InlineDataFile=inline_pid12345.txt)."); |
kvn@6217 | 1006 | return NULL; |
kvn@6217 | 1007 | } |
kvn@6217 | 1008 | |
kvn@6217 | 1009 | VM_ENTRY_MARK; |
kvn@6217 | 1010 | // Load and parse the replay data |
kvn@6217 | 1011 | CompileReplay rp(InlineDataFile, THREAD); |
kvn@6217 | 1012 | if (!rp.can_replay()) { |
kvn@6217 | 1013 | tty->print_cr("ciReplay: !rp.can_replay()"); |
kvn@6217 | 1014 | return NULL; |
kvn@6217 | 1015 | } |
kvn@6217 | 1016 | void* data = rp.process_inline(method, method->get_Method(), entry_bci, comp_level, THREAD); |
kvn@6217 | 1017 | if (HAS_PENDING_EXCEPTION) { |
kvn@6217 | 1018 | oop throwable = PENDING_EXCEPTION; |
kvn@6217 | 1019 | CLEAR_PENDING_EXCEPTION; |
kvn@6217 | 1020 | java_lang_Throwable::print(throwable, tty); |
kvn@6217 | 1021 | tty->cr(); |
kvn@6217 | 1022 | java_lang_Throwable::print_stack_trace(throwable, tty); |
kvn@6217 | 1023 | tty->cr(); |
kvn@6217 | 1024 | return NULL; |
kvn@6217 | 1025 | } |
kvn@6217 | 1026 | |
kvn@6217 | 1027 | if (rp.had_error()) { |
kvn@6217 | 1028 | tty->print_cr("ciReplay: Failed on %s", rp.error_message()); |
kvn@6217 | 1029 | return NULL; |
kvn@6217 | 1030 | } |
kvn@6217 | 1031 | return data; |
kvn@6217 | 1032 | } |
kvn@6217 | 1033 | |
minqi@4267 | 1034 | int ciReplay::replay_impl(TRAPS) { |
minqi@4267 | 1035 | HandleMark hm; |
minqi@4267 | 1036 | ResourceMark rm; |
minqi@4267 | 1037 | // Make sure we don't run with background compilation |
minqi@4267 | 1038 | BackgroundCompilation = false; |
minqi@4267 | 1039 | |
minqi@4267 | 1040 | if (ReplaySuppressInitializers > 2) { |
minqi@4267 | 1041 | // ReplaySuppressInitializers > 2 means that we want to allow |
minqi@4267 | 1042 | // normal VM bootstrap but once we get into the replay itself |
minqi@4267 | 1043 | // don't allow any intializers to be run. |
minqi@4267 | 1044 | ReplaySuppressInitializers = 1; |
minqi@4267 | 1045 | } |
minqi@4267 | 1046 | |
vlivanov@5027 | 1047 | if (FLAG_IS_DEFAULT(ReplayDataFile)) { |
vlivanov@5027 | 1048 | tty->print_cr("ERROR: no compiler replay data file specified (use -XX:ReplayDataFile=replay_pid12345.txt)."); |
vlivanov@5027 | 1049 | return 1; |
vlivanov@5027 | 1050 | } |
vlivanov@5027 | 1051 | |
minqi@4267 | 1052 | // Load and parse the replay data |
minqi@4267 | 1053 | CompileReplay rp(ReplayDataFile, THREAD); |
minqi@4267 | 1054 | int exit_code = 0; |
minqi@4267 | 1055 | if (rp.can_replay()) { |
minqi@4267 | 1056 | rp.process(THREAD); |
minqi@4267 | 1057 | } else { |
minqi@4267 | 1058 | exit_code = 1; |
minqi@4267 | 1059 | return exit_code; |
minqi@4267 | 1060 | } |
minqi@4267 | 1061 | |
minqi@4267 | 1062 | if (HAS_PENDING_EXCEPTION) { |
minqi@4267 | 1063 | oop throwable = PENDING_EXCEPTION; |
minqi@4267 | 1064 | CLEAR_PENDING_EXCEPTION; |
minqi@4267 | 1065 | java_lang_Throwable::print(throwable, tty); |
minqi@4267 | 1066 | tty->cr(); |
minqi@4267 | 1067 | java_lang_Throwable::print_stack_trace(throwable, tty); |
minqi@4267 | 1068 | tty->cr(); |
minqi@4267 | 1069 | exit_code = 2; |
minqi@4267 | 1070 | } |
minqi@4267 | 1071 | |
minqi@4267 | 1072 | if (rp.had_error()) { |
minqi@4267 | 1073 | tty->print_cr("Failed on %s", rp.error_message()); |
minqi@4267 | 1074 | exit_code = 1; |
minqi@4267 | 1075 | } |
minqi@4267 | 1076 | return exit_code; |
minqi@4267 | 1077 | } |
minqi@4267 | 1078 | |
minqi@4267 | 1079 | void ciReplay::initialize(ciMethodData* m) { |
minqi@4267 | 1080 | if (replay_state == NULL) { |
minqi@4267 | 1081 | return; |
minqi@4267 | 1082 | } |
minqi@4267 | 1083 | |
minqi@4267 | 1084 | ASSERT_IN_VM; |
minqi@4267 | 1085 | ResourceMark rm; |
minqi@4267 | 1086 | |
minqi@4267 | 1087 | Method* method = m->get_MethodData()->method(); |
minqi@4267 | 1088 | ciMethodDataRecord* rec = replay_state->find_ciMethodDataRecord(method); |
minqi@4267 | 1089 | if (rec == NULL) { |
minqi@4267 | 1090 | // This indicates some mismatch with the original environment and |
minqi@4267 | 1091 | // the replay environment though it's not always enough to |
minqi@4267 | 1092 | // interfere with reproducing a bug |
minqi@4267 | 1093 | tty->print_cr("Warning: requesting ciMethodData record for method with no data: "); |
minqi@4267 | 1094 | method->print_name(tty); |
minqi@4267 | 1095 | tty->cr(); |
minqi@4267 | 1096 | } else { |
kvn@6217 | 1097 | m->_state = rec->_state; |
kvn@6217 | 1098 | m->_current_mileage = rec->_current_mileage; |
kvn@6217 | 1099 | if (rec->_data_length != 0) { |
kvn@6217 | 1100 | assert(m->_data_size == rec->_data_length * (int)sizeof(rec->_data[0]), "must agree"); |
minqi@4267 | 1101 | |
minqi@4267 | 1102 | // Write the correct ciObjects back into the profile data |
minqi@4267 | 1103 | ciEnv* env = ciEnv::current(); |
kvn@6217 | 1104 | for (int i = 0; i < rec->_oops_length; i++) { |
kvn@6217 | 1105 | KlassHandle *h = (KlassHandle *)rec->_oops_handles[i]; |
kvn@6217 | 1106 | *(ciMetadata**)(rec->_data + rec->_oops_offsets[i]) = |
minqi@4267 | 1107 | env->get_metadata((*h)()); |
minqi@4267 | 1108 | } |
minqi@4267 | 1109 | // Copy the updated profile data into place as intptr_ts |
minqi@4267 | 1110 | #ifdef _LP64 |
kvn@6217 | 1111 | Copy::conjoint_jlongs_atomic((jlong *)rec->_data, (jlong *)m->_data, rec->_data_length); |
minqi@4267 | 1112 | #else |
kvn@6217 | 1113 | Copy::conjoint_jints_atomic((jint *)rec->_data, (jint *)m->_data, rec->_data_length); |
minqi@4267 | 1114 | #endif |
minqi@4267 | 1115 | } |
minqi@4267 | 1116 | |
minqi@4267 | 1117 | // copy in the original header |
kvn@6217 | 1118 | Copy::conjoint_jbytes(rec->_orig_data, (char*)&m->_orig, rec->_orig_data_length); |
minqi@4267 | 1119 | } |
minqi@4267 | 1120 | } |
minqi@4267 | 1121 | |
minqi@4267 | 1122 | |
minqi@4267 | 1123 | bool ciReplay::should_not_inline(ciMethod* method) { |
minqi@4267 | 1124 | if (replay_state == NULL) { |
minqi@4267 | 1125 | return false; |
minqi@4267 | 1126 | } |
minqi@4267 | 1127 | VM_ENTRY_MARK; |
minqi@4267 | 1128 | // ciMethod without a record shouldn't be inlined. |
minqi@4267 | 1129 | return replay_state->find_ciMethodRecord(method->get_Method()) == NULL; |
minqi@4267 | 1130 | } |
minqi@4267 | 1131 | |
kvn@6217 | 1132 | bool ciReplay::should_inline(void* data, ciMethod* method, int bci, int inline_depth) { |
kvn@6217 | 1133 | if (data != NULL) { |
kvn@6217 | 1134 | GrowableArray<ciInlineRecord*>* records = (GrowableArray<ciInlineRecord*>*)data; |
kvn@6217 | 1135 | VM_ENTRY_MARK; |
kvn@6217 | 1136 | // Inline record are ordered by bci and depth. |
kvn@6217 | 1137 | return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) != NULL; |
kvn@6217 | 1138 | } else if (replay_state != NULL) { |
kvn@6217 | 1139 | VM_ENTRY_MARK; |
kvn@6217 | 1140 | // Inline record are ordered by bci and depth. |
kvn@6217 | 1141 | return replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth) != NULL; |
kvn@6217 | 1142 | } |
kvn@6217 | 1143 | return false; |
kvn@6217 | 1144 | } |
kvn@6217 | 1145 | |
kvn@6217 | 1146 | bool ciReplay::should_not_inline(void* data, ciMethod* method, int bci, int inline_depth) { |
kvn@6217 | 1147 | if (data != NULL) { |
kvn@6217 | 1148 | GrowableArray<ciInlineRecord*>* records = (GrowableArray<ciInlineRecord*>*)data; |
kvn@6217 | 1149 | VM_ENTRY_MARK; |
kvn@6217 | 1150 | // Inline record are ordered by bci and depth. |
kvn@6217 | 1151 | return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) == NULL; |
kvn@6217 | 1152 | } else if (replay_state != NULL) { |
kvn@6217 | 1153 | VM_ENTRY_MARK; |
kvn@6217 | 1154 | // Inline record are ordered by bci and depth. |
kvn@6217 | 1155 | return replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth) == NULL; |
kvn@6217 | 1156 | } |
kvn@6217 | 1157 | return false; |
kvn@6217 | 1158 | } |
minqi@4267 | 1159 | |
minqi@4267 | 1160 | void ciReplay::initialize(ciMethod* m) { |
minqi@4267 | 1161 | if (replay_state == NULL) { |
minqi@4267 | 1162 | return; |
minqi@4267 | 1163 | } |
minqi@4267 | 1164 | |
minqi@4267 | 1165 | ASSERT_IN_VM; |
minqi@4267 | 1166 | ResourceMark rm; |
minqi@4267 | 1167 | |
minqi@4267 | 1168 | Method* method = m->get_Method(); |
minqi@4267 | 1169 | ciMethodRecord* rec = replay_state->find_ciMethodRecord(method); |
minqi@4267 | 1170 | if (rec == NULL) { |
minqi@4267 | 1171 | // This indicates some mismatch with the original environment and |
minqi@4267 | 1172 | // the replay environment though it's not always enough to |
minqi@4267 | 1173 | // interfere with reproducing a bug |
minqi@4267 | 1174 | tty->print_cr("Warning: requesting ciMethod record for method with no data: "); |
minqi@4267 | 1175 | method->print_name(tty); |
minqi@4267 | 1176 | tty->cr(); |
minqi@4267 | 1177 | } else { |
jiangli@4936 | 1178 | EXCEPTION_CONTEXT; |
kvn@6217 | 1179 | // m->_instructions_size = rec->_instructions_size; |
minqi@4267 | 1180 | m->_instructions_size = -1; |
kvn@6217 | 1181 | m->_interpreter_invocation_count = rec->_interpreter_invocation_count; |
kvn@6217 | 1182 | m->_interpreter_throwout_count = rec->_interpreter_throwout_count; |
twisti@5907 | 1183 | MethodCounters* mcs = method->get_method_counters(CHECK_AND_CLEAR); |
twisti@5907 | 1184 | guarantee(mcs != NULL, "method counters allocation failed"); |
kvn@6217 | 1185 | mcs->invocation_counter()->_counter = rec->_invocation_counter; |
kvn@6217 | 1186 | mcs->backedge_counter()->_counter = rec->_backedge_counter; |
minqi@4267 | 1187 | } |
minqi@4267 | 1188 | } |
minqi@4267 | 1189 | |
minqi@4267 | 1190 | bool ciReplay::is_loaded(Method* method) { |
minqi@4267 | 1191 | if (replay_state == NULL) { |
minqi@4267 | 1192 | return true; |
minqi@4267 | 1193 | } |
minqi@4267 | 1194 | |
minqi@4267 | 1195 | ASSERT_IN_VM; |
minqi@4267 | 1196 | ResourceMark rm; |
minqi@4267 | 1197 | |
minqi@4267 | 1198 | ciMethodRecord* rec = replay_state->find_ciMethodRecord(method); |
minqi@4267 | 1199 | return rec != NULL; |
minqi@4267 | 1200 | } |
coleenp@4304 | 1201 | #endif // PRODUCT |