Mercurial > hg > graal-jvmci-8
comparison src/share/vm/classfile/javaClasses.cpp @ 7624:b14da2e6f2dc
7174978: NPG: Fix bactrace builder for class redefinition
Summary: Remove Method* from backtrace but save version so redefine classes doesn't give inaccurate line numbers. Removed old Merlin API with duplicate code.
Reviewed-by: dholmes, sspitsyn
author | coleenp |
---|---|
date | Thu, 17 Jan 2013 13:40:31 -0500 |
parents | ade95d680b42 |
children | c73c3f2c5b3b |
comparison
equal
deleted
inserted
replaced
7623:203f64878aab | 7624:b14da2e6f2dc |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. | 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | 4 * |
5 * This code is free software; you can redistribute it and/or modify it | 5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as | 6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
1156 if (msg != NULL) { | 1156 if (msg != NULL) { |
1157 st->print(": %s", java_lang_String::as_utf8_string(msg)); | 1157 st->print(": %s", java_lang_String::as_utf8_string(msg)); |
1158 } | 1158 } |
1159 } | 1159 } |
1160 | 1160 |
1161 // Print stack trace element to resource allocated buffer | 1161 // After this many redefines, the stack trace is unreliable. |
1162 char* java_lang_Throwable::print_stack_element_to_buffer(Method* method, int bci) { | 1162 const int MAX_VERSION = USHRT_MAX; |
1163 // Get strings and string lengths | 1163 |
1164 InstanceKlass* klass = method->method_holder(); | 1164 // Helper backtrace functions to store bci|version together. |
1165 const char* klass_name = klass->external_name(); | 1165 static inline int merge_bci_and_version(int bci, int version) { |
1166 int buf_len = (int)strlen(klass_name); | 1166 // only store u2 for version, checking for overflow. |
1167 char* source_file_name; | 1167 if (version > USHRT_MAX || version < 0) version = MAX_VERSION; |
1168 if (klass->source_file_name() == NULL) { | 1168 assert((jushort)bci == bci, "bci should be short"); |
1169 source_file_name = NULL; | 1169 return build_int_from_shorts(version, bci); |
1170 } | |
1171 | |
1172 static inline int bci_at(unsigned int merged) { | |
1173 return extract_high_short_from_int(merged); | |
1174 } | |
1175 static inline int version_at(unsigned int merged) { | |
1176 return extract_low_short_from_int(merged); | |
1177 } | |
1178 | |
1179 static inline bool version_matches(Method* method, int version) { | |
1180 return (method->constants()->version() == version && version < MAX_VERSION); | |
1181 } | |
1182 | |
1183 static inline int get_line_number(Method* method, int bci) { | |
1184 int line_number = 0; | |
1185 if (method->is_native()) { | |
1186 // Negative value different from -1 below, enabling Java code in | |
1187 // class java.lang.StackTraceElement to distinguish "native" from | |
1188 // "no LineNumberTable". JDK tests for -2. | |
1189 line_number = -2; | |
1170 } else { | 1190 } else { |
1171 source_file_name = klass->source_file_name()->as_C_string(); | 1191 // Returns -1 if no LineNumberTable, and otherwise actual line number |
1172 buf_len += (int)strlen(source_file_name); | 1192 line_number = method->line_number_from_bci(bci); |
1173 } | 1193 if (line_number == -1 && ShowHiddenFrames) { |
1174 char* method_name = method->name()->as_C_string(); | 1194 line_number = bci + 1000000; |
1175 buf_len += (int)strlen(method_name); | 1195 } |
1176 | 1196 } |
1177 // Allocate temporary buffer with extra space for formatting and line number | 1197 return line_number; |
1178 char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64); | |
1179 | |
1180 // Print stack trace line in buffer | |
1181 sprintf(buf, "\tat %s.%s", klass_name, method_name); | |
1182 if (method->is_native()) { | |
1183 strcat(buf, "(Native Method)"); | |
1184 } else { | |
1185 int line_number = method->line_number_from_bci(bci); | |
1186 if (source_file_name != NULL && (line_number != -1)) { | |
1187 // Sourcename and linenumber | |
1188 sprintf(buf + (int)strlen(buf), "(%s:%d)", source_file_name, line_number); | |
1189 } else if (source_file_name != NULL) { | |
1190 // Just sourcename | |
1191 sprintf(buf + (int)strlen(buf), "(%s)", source_file_name); | |
1192 } else { | |
1193 // Neither soucename and linenumber | |
1194 sprintf(buf + (int)strlen(buf), "(Unknown Source)"); | |
1195 } | |
1196 nmethod* nm = method->code(); | |
1197 if (WizardMode && nm != NULL) { | |
1198 sprintf(buf + (int)strlen(buf), "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm); | |
1199 } | |
1200 } | |
1201 | |
1202 return buf; | |
1203 } | |
1204 | |
1205 | |
1206 void java_lang_Throwable::print_stack_element(Handle stream, Method* method, int bci) { | |
1207 ResourceMark rm; | |
1208 char* buf = print_stack_element_to_buffer(method, bci); | |
1209 print_to_stream(stream, buf); | |
1210 } | |
1211 | |
1212 void java_lang_Throwable::print_stack_element(outputStream *st, Method* method, int bci) { | |
1213 ResourceMark rm; | |
1214 char* buf = print_stack_element_to_buffer(method, bci); | |
1215 st->print_cr("%s", buf); | |
1216 } | |
1217 | |
1218 void java_lang_Throwable::print_to_stream(Handle stream, const char* str) { | |
1219 if (stream.is_null()) { | |
1220 tty->print_cr("%s", str); | |
1221 } else { | |
1222 EXCEPTION_MARK; | |
1223 JavaValue result(T_VOID); | |
1224 Handle arg (THREAD, oopFactory::new_charArray(str, THREAD)); | |
1225 if (!HAS_PENDING_EXCEPTION) { | |
1226 JavaCalls::call_virtual(&result, | |
1227 stream, | |
1228 KlassHandle(THREAD, stream->klass()), | |
1229 vmSymbols::println_name(), | |
1230 vmSymbols::char_array_void_signature(), | |
1231 arg, | |
1232 THREAD); | |
1233 } | |
1234 // Ignore any exceptions. we are in the middle of exception handling. Same as classic VM. | |
1235 if (HAS_PENDING_EXCEPTION) CLEAR_PENDING_EXCEPTION; | |
1236 } | |
1237 | |
1238 } | |
1239 | |
1240 | |
1241 const char* java_lang_Throwable::no_stack_trace_message() { | |
1242 return "\t<<no stack trace available>>"; | |
1243 } | |
1244 | |
1245 | |
1246 // Currently used only for exceptions occurring during startup | |
1247 void java_lang_Throwable::print_stack_trace(oop throwable, outputStream* st) { | |
1248 Thread *THREAD = Thread::current(); | |
1249 Handle h_throwable(THREAD, throwable); | |
1250 while (h_throwable.not_null()) { | |
1251 objArrayHandle result (THREAD, objArrayOop(backtrace(h_throwable()))); | |
1252 if (result.is_null()) { | |
1253 st->print_cr(no_stack_trace_message()); | |
1254 return; | |
1255 } | |
1256 | |
1257 while (result.not_null()) { | |
1258 typeArrayHandle methods (THREAD, | |
1259 typeArrayOop(result->obj_at(trace_methods_offset))); | |
1260 typeArrayHandle bcis (THREAD, | |
1261 typeArrayOop(result->obj_at(trace_bcis_offset))); | |
1262 | |
1263 if (methods.is_null() || bcis.is_null()) { | |
1264 st->print_cr(no_stack_trace_message()); | |
1265 return; | |
1266 } | |
1267 | |
1268 int length = methods()->length(); | |
1269 for (int index = 0; index < length; index++) { | |
1270 Method* method = ((Method*)methods()->metadata_at(index)); | |
1271 if (method == NULL) goto handle_cause; | |
1272 int bci = bcis->ushort_at(index); | |
1273 print_stack_element(st, method, bci); | |
1274 } | |
1275 result = objArrayHandle(THREAD, objArrayOop(result->obj_at(trace_next_offset))); | |
1276 } | |
1277 handle_cause: | |
1278 { | |
1279 EXCEPTION_MARK; | |
1280 JavaValue result(T_OBJECT); | |
1281 JavaCalls::call_virtual(&result, | |
1282 h_throwable, | |
1283 KlassHandle(THREAD, h_throwable->klass()), | |
1284 vmSymbols::getCause_name(), | |
1285 vmSymbols::void_throwable_signature(), | |
1286 THREAD); | |
1287 // Ignore any exceptions. we are in the middle of exception handling. Same as classic VM. | |
1288 if (HAS_PENDING_EXCEPTION) { | |
1289 CLEAR_PENDING_EXCEPTION; | |
1290 h_throwable = Handle(); | |
1291 } else { | |
1292 h_throwable = Handle(THREAD, (oop) result.get_jobject()); | |
1293 if (h_throwable.not_null()) { | |
1294 st->print("Caused by: "); | |
1295 print(h_throwable, st); | |
1296 st->cr(); | |
1297 } | |
1298 } | |
1299 } | |
1300 } | |
1301 } | |
1302 | |
1303 | |
1304 void java_lang_Throwable::print_stack_trace(oop throwable, oop print_stream) { | |
1305 // Note: this is no longer used in Merlin, but we support it for compatibility. | |
1306 Thread *thread = Thread::current(); | |
1307 Handle stream(thread, print_stream); | |
1308 objArrayHandle result (thread, objArrayOop(backtrace(throwable))); | |
1309 if (result.is_null()) { | |
1310 print_to_stream(stream, no_stack_trace_message()); | |
1311 return; | |
1312 } | |
1313 | |
1314 while (result.not_null()) { | |
1315 typeArrayHandle methods(thread, | |
1316 typeArrayOop(result->obj_at(trace_methods_offset))); | |
1317 typeArrayHandle bcis (thread, | |
1318 typeArrayOop(result->obj_at(trace_bcis_offset))); | |
1319 | |
1320 if (methods.is_null() || bcis.is_null()) { | |
1321 print_to_stream(stream, no_stack_trace_message()); | |
1322 return; | |
1323 } | |
1324 | |
1325 int length = methods()->length(); | |
1326 for (int index = 0; index < length; index++) { | |
1327 Method* method = ((Method*)methods()->metadata_at(index)); | |
1328 if (method == NULL) return; | |
1329 int bci = bcis->ushort_at(index); | |
1330 print_stack_element(stream, method, bci); | |
1331 } | |
1332 result = objArrayHandle(thread, objArrayOop(result->obj_at(trace_next_offset))); | |
1333 } | |
1334 } | 1198 } |
1335 | 1199 |
1336 // This class provides a simple wrapper over the internal structure of | 1200 // This class provides a simple wrapper over the internal structure of |
1337 // exception backtrace to insulate users of the backtrace from needing | 1201 // exception backtrace to insulate users of the backtrace from needing |
1338 // to know what it looks like. | 1202 // to know what it looks like. |
1348 | 1212 |
1349 public: | 1213 public: |
1350 | 1214 |
1351 enum { | 1215 enum { |
1352 trace_methods_offset = java_lang_Throwable::trace_methods_offset, | 1216 trace_methods_offset = java_lang_Throwable::trace_methods_offset, |
1353 trace_bcis_offset = java_lang_Throwable::trace_bcis_offset, | 1217 trace_bcis_offset = java_lang_Throwable::trace_bcis_offset, |
1354 trace_mirrors_offset = java_lang_Throwable::trace_mirrors_offset, | 1218 trace_mirrors_offset = java_lang_Throwable::trace_mirrors_offset, |
1355 trace_next_offset = java_lang_Throwable::trace_next_offset, | 1219 trace_next_offset = java_lang_Throwable::trace_next_offset, |
1356 trace_size = java_lang_Throwable::trace_size, | 1220 trace_size = java_lang_Throwable::trace_size, |
1357 trace_chunk_size = java_lang_Throwable::trace_chunk_size | 1221 trace_chunk_size = java_lang_Throwable::trace_chunk_size |
1358 }; | 1222 }; |
1359 | 1223 |
1224 // get info out of chunks | |
1225 static typeArrayOop get_methods(objArrayHandle chunk) { | |
1226 typeArrayOop methods = typeArrayOop(chunk->obj_at(trace_methods_offset)); | |
1227 assert(methods != NULL, "method array should be initialized in backtrace"); | |
1228 return methods; | |
1229 } | |
1230 static typeArrayOop get_bcis(objArrayHandle chunk) { | |
1231 typeArrayOop bcis = typeArrayOop(chunk->obj_at(trace_bcis_offset)); | |
1232 assert(bcis != NULL, "bci array should be initialized in backtrace"); | |
1233 return bcis; | |
1234 } | |
1235 static objArrayOop get_mirrors(objArrayHandle chunk) { | |
1236 objArrayOop mirrors = objArrayOop(chunk->obj_at(trace_mirrors_offset)); | |
1237 assert(mirrors != NULL, "mirror array should be initialized in backtrace"); | |
1238 return mirrors; | |
1239 } | |
1240 | |
1360 // constructor for new backtrace | 1241 // constructor for new backtrace |
1361 BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL) { | 1242 BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL) { |
1362 expand(CHECK); | 1243 expand(CHECK); |
1363 _backtrace = _head; | 1244 _backtrace = _head; |
1364 _index = 0; | 1245 _index = 0; |
1365 } | 1246 } |
1366 | 1247 |
1248 BacktraceBuilder(objArrayHandle backtrace) { | |
1249 _methods = get_methods(backtrace); | |
1250 _bcis = get_bcis(backtrace); | |
1251 _mirrors = get_mirrors(backtrace); | |
1252 assert(_methods->length() == _bcis->length() && | |
1253 _methods->length() == _mirrors->length(), | |
1254 "method and source information arrays should match"); | |
1255 | |
1256 // head is the preallocated backtrace | |
1257 _backtrace = _head = backtrace(); | |
1258 _index = 0; | |
1259 } | |
1260 | |
1367 void expand(TRAPS) { | 1261 void expand(TRAPS) { |
1368 objArrayHandle old_head(THREAD, _head); | 1262 objArrayHandle old_head(THREAD, _head); |
1369 Pause_No_Safepoint_Verifier pnsv(&_nsv); | 1263 Pause_No_Safepoint_Verifier pnsv(&_nsv); |
1370 | 1264 |
1371 objArrayOop head = oopFactory::new_objectArray(trace_size, CHECK); | 1265 objArrayOop head = oopFactory::new_objectArray(trace_size, CHECK); |
1372 objArrayHandle new_head(THREAD, head); | 1266 objArrayHandle new_head(THREAD, head); |
1373 | 1267 |
1374 typeArrayOop methods = oopFactory::new_metaDataArray(trace_chunk_size, CHECK); | 1268 typeArrayOop methods = oopFactory::new_shortArray(trace_chunk_size, CHECK); |
1375 typeArrayHandle new_methods(THREAD, methods); | 1269 typeArrayHandle new_methods(THREAD, methods); |
1376 | 1270 |
1377 typeArrayOop bcis = oopFactory::new_shortArray(trace_chunk_size, CHECK); | 1271 typeArrayOop bcis = oopFactory::new_intArray(trace_chunk_size, CHECK); |
1378 typeArrayHandle new_bcis(THREAD, bcis); | 1272 typeArrayHandle new_bcis(THREAD, bcis); |
1379 | 1273 |
1380 objArrayOop mirrors = oopFactory::new_objectArray(trace_chunk_size, CHECK); | 1274 objArrayOop mirrors = oopFactory::new_objectArray(trace_chunk_size, CHECK); |
1381 objArrayHandle new_mirrors(THREAD, mirrors); | 1275 objArrayHandle new_mirrors(THREAD, mirrors); |
1382 | 1276 |
1387 new_head->obj_at_put(trace_bcis_offset, new_bcis()); | 1281 new_head->obj_at_put(trace_bcis_offset, new_bcis()); |
1388 new_head->obj_at_put(trace_mirrors_offset, new_mirrors()); | 1282 new_head->obj_at_put(trace_mirrors_offset, new_mirrors()); |
1389 | 1283 |
1390 _head = new_head(); | 1284 _head = new_head(); |
1391 _methods = new_methods(); | 1285 _methods = new_methods(); |
1392 _bcis = new_bcis(); | 1286 _bcis = new_bcis(); |
1393 _mirrors = new_mirrors(); | 1287 _mirrors = new_mirrors(); |
1394 _index = 0; | 1288 _index = 0; |
1395 } | 1289 } |
1396 | 1290 |
1397 oop backtrace() { | 1291 oop backtrace() { |
1401 inline void push(Method* method, int bci, TRAPS) { | 1295 inline void push(Method* method, int bci, TRAPS) { |
1402 // Smear the -1 bci to 0 since the array only holds unsigned | 1296 // Smear the -1 bci to 0 since the array only holds unsigned |
1403 // shorts. The later line number lookup would just smear the -1 | 1297 // shorts. The later line number lookup would just smear the -1 |
1404 // to a 0 even if it could be recorded. | 1298 // to a 0 even if it could be recorded. |
1405 if (bci == SynchronizationEntryBCI) bci = 0; | 1299 if (bci == SynchronizationEntryBCI) bci = 0; |
1406 assert(bci == (jushort)bci, "doesn't fit"); | |
1407 | 1300 |
1408 if (_index >= trace_chunk_size) { | 1301 if (_index >= trace_chunk_size) { |
1409 methodHandle mhandle(THREAD, method); | 1302 methodHandle mhandle(THREAD, method); |
1410 expand(CHECK); | 1303 expand(CHECK); |
1411 method = mhandle(); | 1304 method = mhandle(); |
1412 } | 1305 } |
1413 | 1306 |
1414 _methods->metadata_at_put(_index, method); | 1307 _methods->short_at_put(_index, method->method_idnum()); |
1415 _bcis->ushort_at_put(_index, bci); | 1308 _bcis->int_at_put(_index, merge_bci_and_version(bci, method->constants()->version())); |
1416 // we need to save the mirrors in the backtrace to keep the methods from | 1309 |
1417 // being unloaded if their class loader is unloaded while we still have | 1310 // We need to save the mirrors in the backtrace to keep the class |
1418 // this stack trace. | 1311 // from being unloaded while we still have this stack trace. |
1312 assert(method->method_holder()->java_mirror() != NULL, "never push null for mirror"); | |
1419 _mirrors->obj_at_put(_index, method->method_holder()->java_mirror()); | 1313 _mirrors->obj_at_put(_index, method->method_holder()->java_mirror()); |
1420 _index++; | 1314 _index++; |
1421 } | 1315 } |
1422 | 1316 |
1423 Method* current_method() { | |
1424 assert(_index >= 0 && _index < trace_chunk_size, "out of range"); | |
1425 return ((Method*)_methods->metadata_at(_index)); | |
1426 } | |
1427 | |
1428 jushort current_bci() { | |
1429 assert(_index >= 0 && _index < trace_chunk_size, "out of range"); | |
1430 return _bcis->ushort_at(_index); | |
1431 } | |
1432 }; | 1317 }; |
1433 | 1318 |
1319 // Print stack trace element to resource allocated buffer | |
1320 char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, | |
1321 int method_id, int version, int bci) { | |
1322 | |
1323 // Get strings and string lengths | |
1324 InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); | |
1325 const char* klass_name = holder->external_name(); | |
1326 int buf_len = (int)strlen(klass_name); | |
1327 | |
1328 // pushing to the stack trace added one. | |
1329 Method* method = holder->method_with_idnum(method_id); | |
1330 char* method_name = method->name()->as_C_string(); | |
1331 buf_len += (int)strlen(method_name); | |
1332 | |
1333 char* source_file_name = NULL; | |
1334 if (version_matches(method, version)) { | |
1335 Symbol* source = holder->source_file_name(); | |
1336 if (source != NULL) { | |
1337 source_file_name = source->as_C_string(); | |
1338 buf_len += (int)strlen(source_file_name); | |
1339 } | |
1340 } | |
1341 | |
1342 // Allocate temporary buffer with extra space for formatting and line number | |
1343 char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64); | |
1344 | |
1345 // Print stack trace line in buffer | |
1346 sprintf(buf, "\tat %s.%s", klass_name, method_name); | |
1347 | |
1348 if (!version_matches(method, version)) { | |
1349 strcat(buf, "(Redefined)"); | |
1350 } else { | |
1351 int line_number = get_line_number(method, bci); | |
1352 if (line_number == -2) { | |
1353 strcat(buf, "(Native Method)"); | |
1354 } else { | |
1355 if (source_file_name != NULL && (line_number != -1)) { | |
1356 // Sourcename and linenumber | |
1357 sprintf(buf + (int)strlen(buf), "(%s:%d)", source_file_name, line_number); | |
1358 } else if (source_file_name != NULL) { | |
1359 // Just sourcename | |
1360 sprintf(buf + (int)strlen(buf), "(%s)", source_file_name); | |
1361 } else { | |
1362 // Neither sourcename nor linenumber | |
1363 sprintf(buf + (int)strlen(buf), "(Unknown Source)"); | |
1364 } | |
1365 nmethod* nm = method->code(); | |
1366 if (WizardMode && nm != NULL) { | |
1367 sprintf(buf + (int)strlen(buf), "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm); | |
1368 } | |
1369 } | |
1370 } | |
1371 | |
1372 return buf; | |
1373 } | |
1374 | |
1375 void java_lang_Throwable::print_stack_element(outputStream *st, Handle mirror, | |
1376 int method_id, int version, int bci) { | |
1377 ResourceMark rm; | |
1378 char* buf = print_stack_element_to_buffer(mirror, method_id, version, bci); | |
1379 st->print_cr("%s", buf); | |
1380 } | |
1381 | |
1382 void java_lang_Throwable::print_stack_element(outputStream *st, methodHandle method, int bci) { | |
1383 Handle mirror = method->method_holder()->java_mirror(); | |
1384 int method_id = method->method_idnum(); | |
1385 int version = method->constants()->version(); | |
1386 print_stack_element(st, mirror, method_id, version, bci); | |
1387 } | |
1388 | |
1389 const char* java_lang_Throwable::no_stack_trace_message() { | |
1390 return "\t<<no stack trace available>>"; | |
1391 } | |
1392 | |
1393 | |
1394 // Currently used only for exceptions occurring during startup | |
1395 void java_lang_Throwable::print_stack_trace(oop throwable, outputStream* st) { | |
1396 Thread *THREAD = Thread::current(); | |
1397 Handle h_throwable(THREAD, throwable); | |
1398 while (h_throwable.not_null()) { | |
1399 objArrayHandle result (THREAD, objArrayOop(backtrace(h_throwable()))); | |
1400 if (result.is_null()) { | |
1401 st->print_cr(no_stack_trace_message()); | |
1402 return; | |
1403 } | |
1404 | |
1405 while (result.not_null()) { | |
1406 | |
1407 // Get method id, bci, version and mirror from chunk | |
1408 typeArrayHandle methods (THREAD, BacktraceBuilder::get_methods(result)); | |
1409 typeArrayHandle bcis (THREAD, BacktraceBuilder::get_bcis(result)); | |
1410 objArrayHandle mirrors (THREAD, BacktraceBuilder::get_mirrors(result)); | |
1411 | |
1412 int length = methods()->length(); | |
1413 for (int index = 0; index < length; index++) { | |
1414 Handle mirror(THREAD, mirrors->obj_at(index)); | |
1415 // NULL mirror means end of stack trace | |
1416 if (mirror.is_null()) goto handle_cause; | |
1417 int method = methods->short_at(index); | |
1418 int version = version_at(bcis->int_at(index)); | |
1419 int bci = bci_at(bcis->int_at(index)); | |
1420 print_stack_element(st, mirror, method, version, bci); | |
1421 } | |
1422 result = objArrayHandle(THREAD, objArrayOop(result->obj_at(trace_next_offset))); | |
1423 } | |
1424 handle_cause: | |
1425 { | |
1426 EXCEPTION_MARK; | |
1427 JavaValue cause(T_OBJECT); | |
1428 JavaCalls::call_virtual(&cause, | |
1429 h_throwable, | |
1430 KlassHandle(THREAD, h_throwable->klass()), | |
1431 vmSymbols::getCause_name(), | |
1432 vmSymbols::void_throwable_signature(), | |
1433 THREAD); | |
1434 // Ignore any exceptions. we are in the middle of exception handling. Same as classic VM. | |
1435 if (HAS_PENDING_EXCEPTION) { | |
1436 CLEAR_PENDING_EXCEPTION; | |
1437 h_throwable = Handle(); | |
1438 } else { | |
1439 h_throwable = Handle(THREAD, (oop) cause.get_jobject()); | |
1440 if (h_throwable.not_null()) { | |
1441 st->print("Caused by: "); | |
1442 print(h_throwable, st); | |
1443 st->cr(); | |
1444 } | |
1445 } | |
1446 } | |
1447 } | |
1448 } | |
1434 | 1449 |
1435 void java_lang_Throwable::fill_in_stack_trace(Handle throwable, methodHandle method, TRAPS) { | 1450 void java_lang_Throwable::fill_in_stack_trace(Handle throwable, methodHandle method, TRAPS) { |
1436 if (!StackTraceInThrowable) return; | 1451 if (!StackTraceInThrowable) return; |
1437 ResourceMark rm(THREAD); | 1452 ResourceMark rm(THREAD); |
1438 | 1453 |
1589 void java_lang_Throwable::allocate_backtrace(Handle throwable, TRAPS) { | 1604 void java_lang_Throwable::allocate_backtrace(Handle throwable, TRAPS) { |
1590 // Allocate stack trace - backtrace is created but not filled in | 1605 // Allocate stack trace - backtrace is created but not filled in |
1591 | 1606 |
1592 // No-op if stack trace is disabled | 1607 // No-op if stack trace is disabled |
1593 if (!StackTraceInThrowable) return; | 1608 if (!StackTraceInThrowable) return; |
1594 | 1609 BacktraceBuilder bt(CHECK); // creates a backtrace |
1595 objArrayOop h_oop = oopFactory::new_objectArray(trace_size, CHECK); | 1610 set_backtrace(throwable(), bt.backtrace()); |
1596 objArrayHandle backtrace (THREAD, h_oop); | |
1597 typeArrayOop m_oop = oopFactory::new_metaDataArray(trace_chunk_size, CHECK); | |
1598 typeArrayHandle methods (THREAD, m_oop); | |
1599 typeArrayOop b = oopFactory::new_shortArray(trace_chunk_size, CHECK); | |
1600 typeArrayHandle bcis(THREAD, b); | |
1601 objArrayOop mirror_oop = oopFactory::new_objectArray(trace_chunk_size, CHECK); | |
1602 objArrayHandle mirrors (THREAD, mirror_oop); | |
1603 | |
1604 // backtrace has space for one chunk (next is NULL) | |
1605 backtrace->obj_at_put(trace_methods_offset, methods()); | |
1606 backtrace->obj_at_put(trace_bcis_offset, bcis()); | |
1607 backtrace->obj_at_put(trace_mirrors_offset, mirrors()); | |
1608 set_backtrace(throwable(), backtrace()); | |
1609 } | 1611 } |
1610 | 1612 |
1611 | 1613 |
1612 void java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(Handle throwable) { | 1614 void java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(Handle throwable) { |
1613 // Fill in stack trace into preallocated backtrace (no GC) | 1615 // Fill in stack trace into preallocated backtrace (no GC) |
1615 // No-op if stack trace is disabled | 1617 // No-op if stack trace is disabled |
1616 if (!StackTraceInThrowable) return; | 1618 if (!StackTraceInThrowable) return; |
1617 | 1619 |
1618 assert(throwable->is_a(SystemDictionary::Throwable_klass()), "sanity check"); | 1620 assert(throwable->is_a(SystemDictionary::Throwable_klass()), "sanity check"); |
1619 | 1621 |
1620 objArrayOop backtrace = (objArrayOop)java_lang_Throwable::backtrace(throwable()); | 1622 JavaThread* THREAD = JavaThread::current(); |
1621 assert(backtrace != NULL, "backtrace not preallocated"); | 1623 |
1622 | 1624 objArrayHandle backtrace (THREAD, (objArrayOop)java_lang_Throwable::backtrace(throwable())); |
1623 oop m = backtrace->obj_at(trace_methods_offset); | 1625 assert(backtrace.not_null(), "backtrace should have been preallocated"); |
1624 typeArrayOop methods = typeArrayOop(m); | 1626 |
1625 assert(methods != NULL && methods->length() > 0, "method array not preallocated"); | 1627 ResourceMark rm(THREAD); |
1626 | 1628 vframeStream st(THREAD); |
1627 oop b = backtrace->obj_at(trace_bcis_offset); | 1629 |
1628 typeArrayOop bcis = typeArrayOop(b); | 1630 BacktraceBuilder bt(backtrace); |
1629 assert(bcis != NULL, "bci array not preallocated"); | |
1630 | |
1631 oop mr = backtrace->obj_at(trace_mirrors_offset); | |
1632 objArrayOop mirrors = objArrayOop(mr); | |
1633 assert(mirrors != NULL, "bci array not preallocated"); | |
1634 | |
1635 assert(methods->length() == bcis->length() && | |
1636 methods->length() == mirrors->length(), | |
1637 "method and bci arrays should match"); | |
1638 | |
1639 JavaThread* thread = JavaThread::current(); | |
1640 ResourceMark rm(thread); | |
1641 vframeStream st(thread); | |
1642 | 1631 |
1643 // Unlike fill_in_stack_trace we do not skip fillInStackTrace or throwable init | 1632 // Unlike fill_in_stack_trace we do not skip fillInStackTrace or throwable init |
1644 // methods as preallocated errors aren't created by "java" code. | 1633 // methods as preallocated errors aren't created by "java" code. |
1645 | 1634 |
1646 // fill in as much stack trace as possible | 1635 // fill in as much stack trace as possible |
1636 typeArrayOop methods = BacktraceBuilder::get_methods(backtrace); | |
1647 int max_chunks = MIN2(methods->length(), (int)MaxJavaStackTraceDepth); | 1637 int max_chunks = MIN2(methods->length(), (int)MaxJavaStackTraceDepth); |
1648 int chunk_count = 0; | 1638 int chunk_count = 0; |
1649 | 1639 |
1650 for (;!st.at_end(); st.next()) { | 1640 for (;!st.at_end(); st.next()) { |
1651 // Add entry and smear the -1 bci to 0 since the array only holds | 1641 bt.push(st.method(), st.bci(), CHECK); |
1652 // unsigned shorts. The later line number lookup would just smear | |
1653 // the -1 to a 0 even if it could be recorded. | |
1654 int bci = st.bci(); | |
1655 if (bci == SynchronizationEntryBCI) bci = 0; | |
1656 assert(bci == (jushort)bci, "doesn't fit"); | |
1657 bcis->ushort_at_put(chunk_count, bci); | |
1658 methods->metadata_at_put(chunk_count, st.method()); | |
1659 mirrors->obj_at_put(chunk_count, | |
1660 st.method()->method_holder()->java_mirror()); | |
1661 | |
1662 chunk_count++; | 1642 chunk_count++; |
1663 | 1643 |
1664 // Bail-out for deep stacks | 1644 // Bail-out for deep stacks |
1665 if (chunk_count >= max_chunks) break; | 1645 if (chunk_count >= max_chunks) break; |
1666 } | 1646 } |
1670 // can be removed in a JDK using this JVM version | 1650 // can be removed in a JDK using this JVM version |
1671 if (JDK_Version::is_gte_jdk17x_version()) { | 1651 if (JDK_Version::is_gte_jdk17x_version()) { |
1672 java_lang_Throwable::set_stacktrace(throwable(), java_lang_Throwable::unassigned_stacktrace()); | 1652 java_lang_Throwable::set_stacktrace(throwable(), java_lang_Throwable::unassigned_stacktrace()); |
1673 assert(java_lang_Throwable::unassigned_stacktrace() != NULL, "not initialized"); | 1653 assert(java_lang_Throwable::unassigned_stacktrace() != NULL, "not initialized"); |
1674 } | 1654 } |
1675 | |
1676 } | 1655 } |
1677 | 1656 |
1678 | 1657 |
1679 int java_lang_Throwable::get_stack_trace_depth(oop throwable, TRAPS) { | 1658 int java_lang_Throwable::get_stack_trace_depth(oop throwable, TRAPS) { |
1680 if (throwable == NULL) { | 1659 if (throwable == NULL) { |
1689 if (next == NULL) break; | 1668 if (next == NULL) break; |
1690 depth += trace_chunk_size; | 1669 depth += trace_chunk_size; |
1691 chunk = next; | 1670 chunk = next; |
1692 } | 1671 } |
1693 assert(chunk != NULL && chunk->obj_at(trace_next_offset) == NULL, "sanity check"); | 1672 assert(chunk != NULL && chunk->obj_at(trace_next_offset) == NULL, "sanity check"); |
1694 // Count element in remaining partial chunk | 1673 // Count element in remaining partial chunk. NULL value for mirror |
1695 typeArrayOop methods = typeArrayOop(chunk->obj_at(trace_methods_offset)); | 1674 // marks the end of the stack trace elements that are saved. |
1696 typeArrayOop bcis = typeArrayOop(chunk->obj_at(trace_bcis_offset)); | 1675 objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk); |
1697 assert(methods != NULL && bcis != NULL, "sanity check"); | 1676 assert(mirrors != NULL, "sanity check"); |
1698 for (int i = 0; i < methods->length(); i++) { | 1677 for (int i = 0; i < mirrors->length(); i++) { |
1699 if (methods->metadata_at(i) == NULL) break; | 1678 if (mirrors->obj_at(i) == NULL) break; |
1700 depth++; | 1679 depth++; |
1701 } | 1680 } |
1702 } | 1681 } |
1703 return depth; | 1682 return depth; |
1704 } | 1683 } |
1720 skip_chunks--; | 1699 skip_chunks--; |
1721 } | 1700 } |
1722 if (chunk == NULL) { | 1701 if (chunk == NULL) { |
1723 THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); | 1702 THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); |
1724 } | 1703 } |
1725 // Get method,bci from chunk | 1704 // Get method id, bci, version and mirror from chunk |
1726 typeArrayOop methods = typeArrayOop(chunk->obj_at(trace_methods_offset)); | 1705 typeArrayOop methods = BacktraceBuilder::get_methods(chunk); |
1727 typeArrayOop bcis = typeArrayOop(chunk->obj_at(trace_bcis_offset)); | 1706 typeArrayOop bcis = BacktraceBuilder::get_bcis(chunk); |
1728 assert(methods != NULL && bcis != NULL, "sanity check"); | 1707 objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk); |
1729 methodHandle method(THREAD, ((Method*)methods->metadata_at(chunk_index))); | 1708 |
1730 int bci = bcis->ushort_at(chunk_index); | 1709 assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check"); |
1710 | |
1711 int method = methods->short_at(chunk_index); | |
1712 int version = version_at(bcis->int_at(chunk_index)); | |
1713 int bci = bci_at(bcis->int_at(chunk_index)); | |
1714 Handle mirror(THREAD, mirrors->obj_at(chunk_index)); | |
1715 | |
1731 // Chunk can be partial full | 1716 // Chunk can be partial full |
1732 if (method.is_null()) { | 1717 if (mirror.is_null()) { |
1733 THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); | 1718 THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); |
1734 } | 1719 } |
1735 | 1720 |
1736 oop element = java_lang_StackTraceElement::create(method, bci, CHECK_0); | 1721 oop element = java_lang_StackTraceElement::create(mirror, method, version, bci, CHECK_0); |
1737 return element; | 1722 return element; |
1738 } | 1723 } |
1739 | 1724 |
1740 oop java_lang_StackTraceElement::create(methodHandle method, int bci, TRAPS) { | 1725 oop java_lang_StackTraceElement::create(Handle mirror, int method_id, int version, int bci, TRAPS) { |
1741 // SystemDictionary::stackTraceElement_klass() will be null for pre-1.4 JDKs | |
1742 assert(JDK_Version::is_gte_jdk14x_version(), "should only be called in >= 1.4"); | |
1743 | |
1744 // Allocate java.lang.StackTraceElement instance | 1726 // Allocate java.lang.StackTraceElement instance |
1745 Klass* k = SystemDictionary::StackTraceElement_klass(); | 1727 Klass* k = SystemDictionary::StackTraceElement_klass(); |
1746 assert(k != NULL, "must be loaded in 1.4+"); | 1728 assert(k != NULL, "must be loaded in 1.4+"); |
1747 instanceKlassHandle ik (THREAD, k); | 1729 instanceKlassHandle ik (THREAD, k); |
1748 if (ik->should_be_initialized()) { | 1730 if (ik->should_be_initialized()) { |
1750 } | 1732 } |
1751 | 1733 |
1752 Handle element = ik->allocate_instance_handle(CHECK_0); | 1734 Handle element = ik->allocate_instance_handle(CHECK_0); |
1753 // Fill in class name | 1735 // Fill in class name |
1754 ResourceMark rm(THREAD); | 1736 ResourceMark rm(THREAD); |
1755 const char* str = method->method_holder()->external_name(); | 1737 InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); |
1738 const char* str = holder->external_name(); | |
1756 oop classname = StringTable::intern((char*) str, CHECK_0); | 1739 oop classname = StringTable::intern((char*) str, CHECK_0); |
1757 java_lang_StackTraceElement::set_declaringClass(element(), classname); | 1740 java_lang_StackTraceElement::set_declaringClass(element(), classname); |
1741 | |
1758 // Fill in method name | 1742 // Fill in method name |
1743 Method* method = holder->method_with_idnum(method_id); | |
1759 oop methodname = StringTable::intern(method->name(), CHECK_0); | 1744 oop methodname = StringTable::intern(method->name(), CHECK_0); |
1760 java_lang_StackTraceElement::set_methodName(element(), methodname); | 1745 java_lang_StackTraceElement::set_methodName(element(), methodname); |
1761 // Fill in source file name | 1746 |
1762 Symbol* source = method->method_holder()->source_file_name(); | 1747 if (!version_matches(method, version)) { |
1763 if (ShowHiddenFrames && source == NULL) | 1748 // The method was redefined, accurate line number information isn't available |
1764 source = vmSymbols::unknown_class_name(); | 1749 java_lang_StackTraceElement::set_fileName(element(), NULL); |
1765 oop filename = StringTable::intern(source, CHECK_0); | 1750 java_lang_StackTraceElement::set_lineNumber(element(), -1); |
1766 java_lang_StackTraceElement::set_fileName(element(), filename); | |
1767 // File in source line number | |
1768 int line_number; | |
1769 if (method->is_native()) { | |
1770 // Negative value different from -1 below, enabling Java code in | |
1771 // class java.lang.StackTraceElement to distinguish "native" from | |
1772 // "no LineNumberTable". | |
1773 line_number = -2; | |
1774 } else { | 1751 } else { |
1775 // Returns -1 if no LineNumberTable, and otherwise actual line number | 1752 // Fill in source file name and line number. |
1776 line_number = method->line_number_from_bci(bci); | 1753 Symbol* source = holder->source_file_name(); |
1777 if (line_number == -1 && ShowHiddenFrames) { | 1754 if (ShowHiddenFrames && source == NULL) |
1778 line_number = bci + 1000000; | 1755 source = vmSymbols::unknown_class_name(); |
1779 } | 1756 oop filename = StringTable::intern(source, CHECK_0); |
1780 } | 1757 java_lang_StackTraceElement::set_fileName(element(), filename); |
1781 java_lang_StackTraceElement::set_lineNumber(element(), line_number); | 1758 |
1782 | 1759 int line_number = get_line_number(method, bci); |
1760 java_lang_StackTraceElement::set_lineNumber(element(), line_number); | |
1761 } | |
1783 return element(); | 1762 return element(); |
1784 } | 1763 } |
1785 | 1764 |
1765 oop java_lang_StackTraceElement::create(methodHandle method, int bci, TRAPS) { | |
1766 Handle mirror (THREAD, method->method_holder()->java_mirror()); | |
1767 int method_id = method->method_idnum(); | |
1768 return create(mirror, method_id, method->constants()->version(), bci, THREAD); | |
1769 } | |
1786 | 1770 |
1787 void java_lang_reflect_AccessibleObject::compute_offsets() { | 1771 void java_lang_reflect_AccessibleObject::compute_offsets() { |
1788 Klass* k = SystemDictionary::reflect_AccessibleObject_klass(); | 1772 Klass* k = SystemDictionary::reflect_AccessibleObject_klass(); |
1789 compute_offset(override_offset, k, vmSymbols::override_name(), vmSymbols::bool_signature()); | 1773 compute_offset(override_offset, k, vmSymbols::override_name(), vmSymbols::bool_signature()); |
1790 } | 1774 } |