comparison src/share/vm/ci/ciReplay.cpp @ 6972:bd7a7ce2e264

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