OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/isolate.h" | 5 #include "src/isolate.h" |
6 | 6 |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 | 8 |
9 #include <fstream> // NOLINT(readability/streams) | 9 #include <fstream> // NOLINT(readability/streams) |
10 #include <sstream> | 10 #include <sstream> |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 uint8_t buffer[kMaxStackTraceSize]; | 308 uint8_t buffer[kMaxStackTraceSize]; |
309 int length = Min(kMaxStackTraceSize - 1, trace->length()); | 309 int length = Min(kMaxStackTraceSize - 1, trace->length()); |
310 String::WriteToFlat(*trace, buffer, 0, length); | 310 String::WriteToFlat(*trace, buffer, 0, length); |
311 buffer[length] = '\0'; | 311 buffer[length] = '\0'; |
312 // TODO(dcarney): convert buffer to utf8? | 312 // TODO(dcarney): convert buffer to utf8? |
313 base::OS::PrintError("Stacktrace (%x-%x) %p %p: %s\n", magic, magic2, ptr1, | 313 base::OS::PrintError("Stacktrace (%x-%x) %p %p: %s\n", magic, magic2, ptr1, |
314 ptr2, reinterpret_cast<char*>(buffer)); | 314 ptr2, reinterpret_cast<char*>(buffer)); |
315 base::OS::Abort(); | 315 base::OS::Abort(); |
316 } | 316 } |
317 | 317 |
318 static Handle<FixedArray> MaybeGrow(Isolate* isolate, | 318 namespace { |
319 Handle<FixedArray> elements, | |
320 int cur_position, int new_size) { | |
321 if (new_size > elements->length()) { | |
322 int new_capacity = JSObject::NewElementsCapacity(elements->length()); | |
323 Handle<FixedArray> new_elements = | |
324 isolate->factory()->NewFixedArrayWithHoles(new_capacity); | |
325 for (int i = 0; i < cur_position; i++) { | |
326 new_elements->set(i, elements->get(i)); | |
327 } | |
328 elements = new_elements; | |
329 } | |
330 DCHECK(new_size <= elements->length()); | |
331 return elements; | |
332 } | |
333 | 319 |
334 class StackTraceHelper { | 320 class StackTraceHelper { |
335 public: | 321 public: |
336 StackTraceHelper(Isolate* isolate, FrameSkipMode mode, Handle<Object> caller) | 322 StackTraceHelper(Isolate* isolate, FrameSkipMode mode, Handle<Object> caller) |
337 : isolate_(isolate), | 323 : isolate_(isolate), |
338 mode_(mode), | 324 mode_(mode), |
339 caller_(caller), | 325 caller_(caller), |
340 skip_next_frame_(true) { | 326 skip_next_frame_(true) { |
341 // The caller parameter can be used to skip a specific set of frames in the | 327 // The caller parameter can be used to skip a specific set of frames in the |
342 // stack trace. It can be: | 328 // stack trace. It can be: |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 Isolate* isolate_; | 414 Isolate* isolate_; |
429 | 415 |
430 const FrameSkipMode mode_; | 416 const FrameSkipMode mode_; |
431 const Handle<Object> caller_; | 417 const Handle<Object> caller_; |
432 bool skip_next_frame_; | 418 bool skip_next_frame_; |
433 | 419 |
434 int sloppy_frames_; | 420 int sloppy_frames_; |
435 bool encountered_strict_function_; | 421 bool encountered_strict_function_; |
436 }; | 422 }; |
437 | 423 |
438 namespace { | |
439 | |
440 // TODO(jgruber): Fix all cases in which frames give us a hole value (e.g. the | 424 // TODO(jgruber): Fix all cases in which frames give us a hole value (e.g. the |
441 // receiver in RegExp constructor frames. | 425 // receiver in RegExp constructor frames. |
442 Handle<Object> TheHoleToUndefined(Isolate* isolate, Handle<Object> in) { | 426 Handle<Object> TheHoleToUndefined(Isolate* isolate, Handle<Object> in) { |
443 return (in->IsTheHole(isolate)) | 427 return (in->IsTheHole(isolate)) |
444 ? Handle<Object>::cast(isolate->factory()->undefined_value()) | 428 ? Handle<Object>::cast(isolate->factory()->undefined_value()) |
445 : in; | 429 : in; |
446 } | 430 } |
| 431 |
| 432 bool GetStackTraceLimit(Isolate* isolate, int* result) { |
| 433 Handle<JSObject> error = isolate->error_function(); |
| 434 |
| 435 Handle<String> key = isolate->factory()->stackTraceLimit_string(); |
| 436 Handle<Object> stack_trace_limit = JSReceiver::GetDataProperty(error, key); |
| 437 if (!stack_trace_limit->IsNumber()) return false; |
| 438 |
| 439 // Ensure that limit is not negative. |
| 440 *result = Max(FastD2IChecked(stack_trace_limit->Number()), 0); |
| 441 return true; |
447 } | 442 } |
448 | 443 |
| 444 } // namespace |
| 445 |
449 Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, | 446 Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, |
450 FrameSkipMode mode, | 447 FrameSkipMode mode, |
451 Handle<Object> caller) { | 448 Handle<Object> caller) { |
452 DisallowJavascriptExecution no_js(this); | 449 DisallowJavascriptExecution no_js(this); |
453 | 450 |
454 // Get stack trace limit. | 451 int limit; |
455 Handle<JSObject> error = error_function(); | 452 if (!GetStackTraceLimit(this, &limit)) return factory()->undefined_value(); |
456 Handle<String> stackTraceLimit = | |
457 factory()->InternalizeUtf8String("stackTraceLimit"); | |
458 DCHECK(!stackTraceLimit.is_null()); | |
459 Handle<Object> stack_trace_limit = | |
460 JSReceiver::GetDataProperty(error, stackTraceLimit); | |
461 if (!stack_trace_limit->IsNumber()) return factory()->undefined_value(); | |
462 int limit = FastD2IChecked(stack_trace_limit->Number()); | |
463 limit = Max(limit, 0); // Ensure that limit is not negative. | |
464 | 453 |
465 int initial_size = Min(limit, 10); | 454 const int initial_size = Min(limit, 10); |
466 Handle<FixedArray> elements = | 455 Handle<FrameArray> elements = factory()->NewFrameArray(initial_size); |
467 factory()->NewFixedArrayWithHoles(initial_size * 4 + 1); | |
468 | 456 |
469 StackTraceHelper helper(this, mode, caller); | 457 StackTraceHelper helper(this, mode, caller); |
470 | 458 |
471 // First element is reserved to store the number of sloppy frames. | 459 for (StackFrameIterator iter(this); |
472 int cursor = 1; | 460 !iter.done() && elements->FrameCount() < limit; iter.Advance()) { |
473 int frames_seen = 0; | |
474 for (StackFrameIterator iter(this); !iter.done() && frames_seen < limit; | |
475 iter.Advance()) { | |
476 StackFrame* frame = iter.frame(); | 461 StackFrame* frame = iter.frame(); |
477 | 462 |
478 switch (frame->type()) { | 463 switch (frame->type()) { |
479 case StackFrame::JAVA_SCRIPT: | 464 case StackFrame::JAVA_SCRIPT: |
480 case StackFrame::OPTIMIZED: | 465 case StackFrame::OPTIMIZED: |
481 case StackFrame::INTERPRETED: | 466 case StackFrame::INTERPRETED: |
482 case StackFrame::BUILTIN: { | 467 case StackFrame::BUILTIN: { |
483 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); | 468 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); |
484 // Set initial size to the maximum inlining level + 1 for the outermost | 469 // Set initial size to the maximum inlining level + 1 for the outermost |
485 // function. | 470 // function. |
486 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); | 471 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); |
487 js_frame->Summarize(&frames); | 472 js_frame->Summarize(&frames); |
488 for (int i = frames.length() - 1; i >= 0; i--) { | 473 for (int i = frames.length() - 1; i >= 0; i--) { |
489 Handle<JSFunction> fun = frames[i].function(); | 474 Handle<JSFunction> fun = frames[i].function(); |
490 | 475 |
491 // Filter out internal frames that we do not want to show. | 476 // Filter out internal frames that we do not want to show. |
492 if (!helper.IsVisibleInStackTrace(*fun)) continue; | 477 if (!helper.IsVisibleInStackTrace(*fun)) continue; |
493 helper.CountSloppyFrames(*fun); | 478 helper.CountSloppyFrames(*fun); |
494 | 479 |
495 Handle<Object> recv = frames[i].receiver(); | 480 Handle<Object> recv = frames[i].receiver(); |
496 Handle<AbstractCode> abstract_code = frames[i].abstract_code(); | 481 Handle<AbstractCode> abstract_code = frames[i].abstract_code(); |
497 if (frame->type() == StackFrame::BUILTIN) { | 482 if (frame->type() == StackFrame::BUILTIN) { |
498 // Help CallSite::IsConstructor correctly detect hand-written | 483 // Help CallSite::IsConstructor correctly detect hand-written |
499 // construct stubs. | 484 // construct stubs. |
500 Code* code = Code::cast(*abstract_code); | 485 Code* code = Code::cast(*abstract_code); |
501 if (code->is_construct_stub()) { | 486 if (code->is_construct_stub()) { |
502 recv = handle(heap()->call_site_constructor_symbol(), this); | 487 recv = handle(heap()->call_site_constructor_symbol(), this); |
503 } | 488 } |
504 } | 489 } |
505 Handle<Smi> offset(Smi::FromInt(frames[i].code_offset()), this); | 490 const int offset = frames[i].code_offset(); |
506 | 491 |
507 elements = MaybeGrow(this, elements, cursor, cursor + 4); | 492 elements = FrameArray::AppendJSFrame(elements, |
508 elements->set(cursor++, *TheHoleToUndefined(this, recv)); | 493 TheHoleToUndefined(this, recv), |
509 elements->set(cursor++, *fun); | 494 fun, abstract_code, offset); |
510 elements->set(cursor++, *abstract_code); | |
511 elements->set(cursor++, *offset); | |
512 frames_seen++; | |
513 } | 495 } |
514 } break; | 496 } break; |
515 | 497 |
516 case StackFrame::BUILTIN_EXIT: { | 498 case StackFrame::BUILTIN_EXIT: { |
517 BuiltinExitFrame* exit_frame = BuiltinExitFrame::cast(frame); | 499 BuiltinExitFrame* exit_frame = BuiltinExitFrame::cast(frame); |
518 Handle<JSFunction> fun = handle(exit_frame->function(), this); | 500 Handle<JSFunction> fun = handle(exit_frame->function(), this); |
519 | 501 |
520 // Filter out internal frames that we do not want to show. | 502 // Filter out internal frames that we do not want to show. |
521 if (!helper.IsVisibleInStackTrace(*fun)) continue; | 503 if (!helper.IsVisibleInStackTrace(*fun)) continue; |
522 helper.CountSloppyFrames(*fun); | 504 helper.CountSloppyFrames(*fun); |
523 | 505 |
524 Handle<Code> code = handle(exit_frame->LookupCode(), this); | 506 Handle<Code> code = handle(exit_frame->LookupCode(), this); |
525 int offset = | 507 int offset = |
526 static_cast<int>(exit_frame->pc() - code->instruction_start()); | 508 static_cast<int>(exit_frame->pc() - code->instruction_start()); |
527 | 509 |
528 // In order to help CallSite::IsConstructor detect builtin constructors, | 510 // In order to help CallSite::IsConstructor detect builtin constructors, |
529 // we reuse the receiver field to pass along a special symbol. | 511 // we reuse the receiver field to pass along a special symbol. |
530 Handle<Object> recv; | 512 Handle<Object> recv; |
531 if (exit_frame->IsConstructor()) { | 513 if (exit_frame->IsConstructor()) { |
532 recv = factory()->call_site_constructor_symbol(); | 514 recv = factory()->call_site_constructor_symbol(); |
533 } else { | 515 } else { |
534 recv = handle(exit_frame->receiver(), this); | 516 recv = handle(exit_frame->receiver(), this); |
535 } | 517 } |
536 | 518 |
537 elements = MaybeGrow(this, elements, cursor, cursor + 4); | 519 elements = FrameArray::AppendJSFrame( |
538 elements->set(cursor++, *recv); | 520 elements, recv, fun, Handle<AbstractCode>::cast(code), offset); |
539 elements->set(cursor++, *fun); | |
540 elements->set(cursor++, *code); | |
541 elements->set(cursor++, Smi::FromInt(offset)); | |
542 frames_seen++; | |
543 } break; | 521 } break; |
544 | 522 |
545 case StackFrame::WASM: { | 523 case StackFrame::WASM: { |
546 WasmFrame* wasm_frame = WasmFrame::cast(frame); | 524 WasmFrame* wasm_frame = WasmFrame::cast(frame); |
| 525 Handle<Object> wasm_object = handle(wasm_frame->wasm_obj(), this); |
| 526 const int wasm_function_index = wasm_frame->function_index(); |
547 Code* code = wasm_frame->unchecked_code(); | 527 Code* code = wasm_frame->unchecked_code(); |
548 Handle<AbstractCode> abstract_code = | 528 Handle<AbstractCode> abstract_code = |
549 Handle<AbstractCode>(AbstractCode::cast(code), this); | 529 Handle<AbstractCode>(AbstractCode::cast(code), this); |
550 int offset = | 530 const int offset = |
551 static_cast<int>(wasm_frame->pc() - code->instruction_start()); | 531 static_cast<int>(wasm_frame->pc() - code->instruction_start()); |
552 elements = MaybeGrow(this, elements, cursor, cursor + 4); | 532 |
553 elements->set(cursor++, wasm_frame->wasm_obj()); | 533 // TODO(wasm): The wasm object returned by the WasmFrame should always |
554 elements->set(cursor++, Smi::FromInt(wasm_frame->function_index())); | 534 // be a wasm object. |
555 elements->set(cursor++, *abstract_code); | 535 DCHECK(wasm::IsWasmObject(*wasm_object) || |
556 elements->set(cursor++, Smi::FromInt(offset)); | 536 wasm_object->IsUndefined(this)); |
557 frames_seen++; | 537 |
| 538 elements = FrameArray::AppendWasmFrame( |
| 539 elements, wasm_object, wasm_function_index, abstract_code, offset); |
558 } break; | 540 } break; |
559 | 541 |
560 default: | 542 default: |
561 break; | 543 break; |
562 } | 544 } |
563 } | 545 } |
564 elements->set(0, Smi::FromInt(helper.sloppy_frames())); | 546 |
565 elements->Shrink(cursor); | 547 elements->SetSloppyFrameCount(helper.sloppy_frames()); |
566 Handle<JSArray> result = factory()->NewJSArrayWithElements(elements); | 548 elements->ShrinkToFit(); |
567 result->set_length(Smi::FromInt(cursor)); | 549 |
568 // TODO(yangguo): Queue this structured stack trace for preprocessing on GC. | 550 // TODO(yangguo): Queue this structured stack trace for preprocessing on GC. |
569 return result; | 551 return factory()->NewJSArrayWithElements(elements); |
570 } | 552 } |
571 | 553 |
572 MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace( | 554 MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace( |
573 Handle<JSReceiver> error_object) { | 555 Handle<JSReceiver> error_object) { |
574 if (capture_stack_trace_for_uncaught_exceptions_) { | 556 if (capture_stack_trace_for_uncaught_exceptions_) { |
575 // Capture stack trace for a detailed exception message. | 557 // Capture stack trace for a detailed exception message. |
576 Handle<Name> key = factory()->detailed_stack_trace_symbol(); | 558 Handle<Name> key = factory()->detailed_stack_trace_symbol(); |
577 Handle<JSArray> stack_trace = CaptureCurrentStackTrace( | 559 Handle<JSArray> stack_trace = CaptureCurrentStackTrace( |
578 stack_trace_for_uncaught_exceptions_frame_limit_, | 560 stack_trace_for_uncaught_exceptions_frame_limit_, |
579 stack_trace_for_uncaught_exceptions_options_); | 561 stack_trace_for_uncaught_exceptions_options_); |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
766 Handle<String> column_key_; | 748 Handle<String> column_key_; |
767 Handle<String> line_key_; | 749 Handle<String> line_key_; |
768 Handle<String> script_id_key_; | 750 Handle<String> script_id_key_; |
769 Handle<String> script_name_key_; | 751 Handle<String> script_name_key_; |
770 Handle<String> script_name_or_source_url_key_; | 752 Handle<String> script_name_or_source_url_key_; |
771 Handle<String> function_key_; | 753 Handle<String> function_key_; |
772 Handle<String> eval_key_; | 754 Handle<String> eval_key_; |
773 Handle<String> constructor_key_; | 755 Handle<String> constructor_key_; |
774 }; | 756 }; |
775 | 757 |
776 | |
777 int PositionFromStackTrace(Handle<FixedArray> elements, int index) { | |
778 DisallowHeapAllocation no_gc; | |
779 Object* maybe_code = elements->get(index + 2); | |
780 if (maybe_code->IsSmi()) { | |
781 return Smi::cast(maybe_code)->value(); | |
782 } else { | |
783 AbstractCode* abstract_code = AbstractCode::cast(maybe_code); | |
784 int code_offset = Smi::cast(elements->get(index + 3))->value(); | |
785 return abstract_code->SourcePosition(code_offset); | |
786 } | |
787 } | |
788 | |
789 Handle<JSArray> Isolate::CaptureCurrentStackTrace( | 758 Handle<JSArray> Isolate::CaptureCurrentStackTrace( |
790 int frame_limit, StackTrace::StackTraceOptions options) { | 759 int frame_limit, StackTrace::StackTraceOptions options) { |
791 DisallowJavascriptExecution no_js(this); | 760 DisallowJavascriptExecution no_js(this); |
792 CaptureStackTraceHelper helper(this, options); | 761 CaptureStackTraceHelper helper(this, options); |
793 | 762 |
794 // Ensure no negative values. | 763 // Ensure no negative values. |
795 int limit = Max(frame_limit, 0); | 764 int limit = Max(frame_limit, 0); |
796 Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit); | 765 Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit); |
797 Handle<FixedArray> stack_trace_elems( | 766 Handle<FixedArray> stack_trace_elems( |
798 FixedArray::cast(stack_trace->elements()), this); | 767 FixedArray::cast(stack_trace->elements()), this); |
(...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1524 | 1493 |
1525 bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, | 1494 bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, |
1526 Handle<Object> exception) { | 1495 Handle<Object> exception) { |
1527 if (!exception->IsJSObject()) return false; | 1496 if (!exception->IsJSObject()) return false; |
1528 Handle<Name> key = factory()->stack_trace_symbol(); | 1497 Handle<Name> key = factory()->stack_trace_symbol(); |
1529 Handle<Object> property = | 1498 Handle<Object> property = |
1530 JSReceiver::GetDataProperty(Handle<JSObject>::cast(exception), key); | 1499 JSReceiver::GetDataProperty(Handle<JSObject>::cast(exception), key); |
1531 if (!property->IsJSArray()) return false; | 1500 if (!property->IsJSArray()) return false; |
1532 Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property); | 1501 Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property); |
1533 | 1502 |
1534 Handle<FixedArray> elements(FixedArray::cast(simple_stack_trace->elements())); | 1503 Handle<FrameArray> elements(FrameArray::cast(simple_stack_trace->elements())); |
1535 int elements_limit = Smi::cast(simple_stack_trace->length())->value(); | |
1536 | 1504 |
1537 for (int i = 1; i < elements_limit; i += 4) { | 1505 const int frame_count = elements->FrameCount(); |
1538 Handle<Object> fun_obj = handle(elements->get(i + 1), this); | 1506 for (int i = 0; i < frame_count; i++) { |
1539 if (fun_obj->IsSmi()) { | 1507 if (elements->IsWasmFrame(i)) { |
1540 // TODO(clemensh): handle wasm frames | 1508 // TODO(clemensh): handle wasm frames |
1541 return false; | 1509 return false; |
1542 } | 1510 } |
1543 Handle<JSFunction> fun = Handle<JSFunction>::cast(fun_obj); | 1511 |
| 1512 Handle<JSFunction> fun = handle(elements->Function(i), this); |
1544 if (!fun->shared()->IsSubjectToDebugging()) continue; | 1513 if (!fun->shared()->IsSubjectToDebugging()) continue; |
1545 | 1514 |
1546 Object* script = fun->shared()->script(); | 1515 Object* script = fun->shared()->script(); |
1547 if (script->IsScript() && | 1516 if (script->IsScript() && |
1548 !(Script::cast(script)->source()->IsUndefined(this))) { | 1517 !(Script::cast(script)->source()->IsUndefined(this))) { |
1549 int pos = PositionFromStackTrace(elements, i); | 1518 AbstractCode* abstract_code = elements->Code(i); |
| 1519 const int code_offset = elements->Offset(i)->value(); |
| 1520 const int pos = abstract_code->SourcePosition(code_offset); |
| 1521 |
1550 Handle<Script> casted_script(Script::cast(script)); | 1522 Handle<Script> casted_script(Script::cast(script)); |
1551 *target = MessageLocation(casted_script, pos, pos + 1); | 1523 *target = MessageLocation(casted_script, pos, pos + 1); |
1552 return true; | 1524 return true; |
1553 } | 1525 } |
1554 } | 1526 } |
1555 return false; | 1527 return false; |
1556 } | 1528 } |
1557 | 1529 |
1558 | 1530 |
1559 Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception, | 1531 Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception, |
(...skipping 1651 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3211 // Then check whether this scope intercepts. | 3183 // Then check whether this scope intercepts. |
3212 if ((flag & intercept_mask_)) { | 3184 if ((flag & intercept_mask_)) { |
3213 intercepted_flags_ |= flag; | 3185 intercepted_flags_ |= flag; |
3214 return true; | 3186 return true; |
3215 } | 3187 } |
3216 return false; | 3188 return false; |
3217 } | 3189 } |
3218 | 3190 |
3219 } // namespace internal | 3191 } // namespace internal |
3220 } // namespace v8 | 3192 } // namespace v8 |
OLD | NEW |