Mercurial > hg > truffle
comparison src/share/vm/ci/ciReplay.cpp @ 6988:2cb439954abf
Merge with http://hg.openjdk.java.net/hsx/hsx25/hotspot/
author | Gilles Duboscq <duboscq@ssw.jku.at> |
---|---|
date | Mon, 19 Nov 2012 15:36:13 +0100 |
parents | bd7a7ce2e264 |
children | 90273fc0a981 |
comparison
equal
deleted
inserted
replaced
6963:dd0dd0321e2a | 6988:2cb439954abf |
---|---|
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 |