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 } |
447 } | 431 |
432 } // namespace | |
448 | 433 |
449 Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, | 434 Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, |
450 FrameSkipMode mode, | 435 FrameSkipMode mode, |
451 Handle<Object> caller) { | 436 Handle<Object> caller) { |
452 DisallowJavascriptExecution no_js(this); | 437 DisallowJavascriptExecution no_js(this); |
453 | 438 |
454 // Get stack trace limit. | 439 // Get stack trace limit. |
455 Handle<JSObject> error = error_function(); | 440 Handle<JSObject> error = error_function(); |
456 Handle<String> stackTraceLimit = | 441 Handle<String> stackTraceLimit = |
457 factory()->InternalizeUtf8String("stackTraceLimit"); | 442 factory()->InternalizeUtf8String("stackTraceLimit"); |
458 DCHECK(!stackTraceLimit.is_null()); | 443 DCHECK(!stackTraceLimit.is_null()); |
459 Handle<Object> stack_trace_limit = | 444 Handle<Object> stack_trace_limit = |
460 JSReceiver::GetDataProperty(error, stackTraceLimit); | 445 JSReceiver::GetDataProperty(error, stackTraceLimit); |
461 if (!stack_trace_limit->IsNumber()) return factory()->undefined_value(); | 446 if (!stack_trace_limit->IsNumber()) return factory()->undefined_value(); |
462 int limit = FastD2IChecked(stack_trace_limit->Number()); | 447 int limit = FastD2IChecked(stack_trace_limit->Number()); |
463 limit = Max(limit, 0); // Ensure that limit is not negative. | 448 limit = Max(limit, 0); // Ensure that limit is not negative. |
464 | 449 |
465 int initial_size = Min(limit, 10); | 450 int initial_size = Min(limit, 10); |
466 Handle<FixedArray> elements = | 451 Handle<FrameArray> elements = FrameArray::Allocate(this, initial_size); |
467 factory()->NewFixedArrayWithHoles(initial_size * 4 + 1); | |
468 | 452 |
469 StackTraceHelper helper(this, mode, caller); | 453 StackTraceHelper helper(this, mode, caller); |
470 | 454 |
471 // First element is reserved to store the number of sloppy frames. | |
472 int cursor = 1; | |
473 int frames_seen = 0; | 455 int frames_seen = 0; |
Toon Verwaest
2016/08/23 13:14:08
Perhaps we should just encapsulate frames_seen as
jgruber
2016/08/23 15:32:13
Done.
| |
474 for (StackFrameIterator iter(this); !iter.done() && frames_seen < limit; | 456 for (StackFrameIterator iter(this); !iter.done() && frames_seen < limit; |
475 iter.Advance()) { | 457 iter.Advance()) { |
476 StackFrame* frame = iter.frame(); | 458 StackFrame* frame = iter.frame(); |
477 | 459 |
478 switch (frame->type()) { | 460 switch (frame->type()) { |
479 case StackFrame::JAVA_SCRIPT: | 461 case StackFrame::JAVA_SCRIPT: |
480 case StackFrame::OPTIMIZED: | 462 case StackFrame::OPTIMIZED: |
481 case StackFrame::INTERPRETED: | 463 case StackFrame::INTERPRETED: |
482 case StackFrame::BUILTIN: { | 464 case StackFrame::BUILTIN: { |
483 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); | 465 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); |
(...skipping 11 matching lines...) Expand all Loading... | |
495 Handle<Object> recv = frames[i].receiver(); | 477 Handle<Object> recv = frames[i].receiver(); |
496 Handle<AbstractCode> abstract_code = frames[i].abstract_code(); | 478 Handle<AbstractCode> abstract_code = frames[i].abstract_code(); |
497 if (frame->type() == StackFrame::BUILTIN) { | 479 if (frame->type() == StackFrame::BUILTIN) { |
498 // Help CallSite::IsConstructor correctly detect hand-written | 480 // Help CallSite::IsConstructor correctly detect hand-written |
499 // construct stubs. | 481 // construct stubs. |
500 Code* code = Code::cast(*abstract_code); | 482 Code* code = Code::cast(*abstract_code); |
501 if (code->is_construct_stub()) { | 483 if (code->is_construct_stub()) { |
502 recv = handle(heap()->call_site_constructor_symbol(), this); | 484 recv = handle(heap()->call_site_constructor_symbol(), this); |
503 } | 485 } |
504 } | 486 } |
505 Handle<Smi> offset(Smi::FromInt(frames[i].code_offset()), this); | 487 const int offset = frames[i].code_offset(); |
506 | 488 |
507 elements = MaybeGrow(this, elements, cursor, cursor + 4); | 489 elements = FrameArray::AppendJSFrame(elements, frames_seen, |
508 elements->set(cursor++, *TheHoleToUndefined(this, recv)); | 490 TheHoleToUndefined(this, recv), |
509 elements->set(cursor++, *fun); | 491 fun, abstract_code, offset); |
510 elements->set(cursor++, *abstract_code); | |
511 elements->set(cursor++, *offset); | |
512 frames_seen++; | 492 frames_seen++; |
513 } | 493 } |
514 } break; | 494 } break; |
515 | 495 |
516 case StackFrame::BUILTIN_EXIT: { | 496 case StackFrame::BUILTIN_EXIT: { |
517 BuiltinExitFrame* exit_frame = BuiltinExitFrame::cast(frame); | 497 BuiltinExitFrame* exit_frame = BuiltinExitFrame::cast(frame); |
518 Handle<JSFunction> fun = handle(exit_frame->function(), this); | 498 Handle<JSFunction> fun = handle(exit_frame->function(), this); |
519 | 499 |
520 // Filter out internal frames that we do not want to show. | 500 // Filter out internal frames that we do not want to show. |
521 if (!helper.IsVisibleInStackTrace(*fun)) continue; | 501 if (!helper.IsVisibleInStackTrace(*fun)) continue; |
522 helper.CountSloppyFrames(*fun); | 502 helper.CountSloppyFrames(*fun); |
523 | 503 |
524 Handle<Code> code = handle(exit_frame->LookupCode(), this); | 504 Handle<Code> code = handle(exit_frame->LookupCode(), this); |
525 int offset = | 505 int offset = |
526 static_cast<int>(exit_frame->pc() - code->instruction_start()); | 506 static_cast<int>(exit_frame->pc() - code->instruction_start()); |
527 | 507 |
528 // In order to help CallSite::IsConstructor detect builtin constructors, | 508 // In order to help CallSite::IsConstructor detect builtin constructors, |
529 // we reuse the receiver field to pass along a special symbol. | 509 // we reuse the receiver field to pass along a special symbol. |
530 Handle<Object> recv; | 510 Handle<Object> recv; |
531 if (exit_frame->IsConstructor()) { | 511 if (exit_frame->IsConstructor()) { |
532 recv = factory()->call_site_constructor_symbol(); | 512 recv = factory()->call_site_constructor_symbol(); |
533 } else { | 513 } else { |
534 recv = handle(exit_frame->receiver(), this); | 514 recv = handle(exit_frame->receiver(), this); |
535 } | 515 } |
536 | 516 |
537 elements = MaybeGrow(this, elements, cursor, cursor + 4); | 517 elements = |
538 elements->set(cursor++, *recv); | 518 FrameArray::AppendJSFrame(elements, frames_seen, recv, fun, |
539 elements->set(cursor++, *fun); | 519 Handle<AbstractCode>::cast(code), offset); |
540 elements->set(cursor++, *code); | |
541 elements->set(cursor++, Smi::FromInt(offset)); | |
542 frames_seen++; | 520 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)); |
537 | |
538 elements = FrameArray::AppendWasmFrame(elements, frames_seen, | |
539 wasm_object, wasm_function_index, | |
540 abstract_code, offset); | |
557 frames_seen++; | 541 frames_seen++; |
558 } break; | 542 } break; |
559 | 543 |
560 default: | 544 default: |
561 break; | 545 break; |
562 } | 546 } |
563 } | 547 } |
564 elements->set(0, Smi::FromInt(helper.sloppy_frames())); | 548 elements->set(0, Smi::FromInt(helper.sloppy_frames())); |
565 elements->Shrink(cursor); | 549 |
550 const int elements_length = FrameArray::LengthFor(frames_seen); | |
Toon Verwaest
2016/08/23 13:14:08
What about elements->Shrink(frames_seen) to avoid
jgruber
2016/08/23 15:32:13
Done.
| |
551 elements->Shrink(elements_length); | |
552 | |
566 Handle<JSArray> result = factory()->NewJSArrayWithElements(elements); | 553 Handle<JSArray> result = factory()->NewJSArrayWithElements(elements); |
567 result->set_length(Smi::FromInt(cursor)); | 554 result->set_length(Smi::FromInt(elements_length)); |
555 | |
568 // TODO(yangguo): Queue this structured stack trace for preprocessing on GC. | 556 // TODO(yangguo): Queue this structured stack trace for preprocessing on GC. |
569 return result; | 557 return result; |
570 } | 558 } |
571 | 559 |
572 MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace( | 560 MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace( |
573 Handle<JSReceiver> error_object) { | 561 Handle<JSReceiver> error_object) { |
574 if (capture_stack_trace_for_uncaught_exceptions_) { | 562 if (capture_stack_trace_for_uncaught_exceptions_) { |
575 // Capture stack trace for a detailed exception message. | 563 // Capture stack trace for a detailed exception message. |
576 Handle<Name> key = factory()->detailed_stack_trace_symbol(); | 564 Handle<Name> key = factory()->detailed_stack_trace_symbol(); |
577 Handle<JSArray> stack_trace = CaptureCurrentStackTrace( | 565 Handle<JSArray> stack_trace = CaptureCurrentStackTrace( |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
766 Handle<String> column_key_; | 754 Handle<String> column_key_; |
767 Handle<String> line_key_; | 755 Handle<String> line_key_; |
768 Handle<String> script_id_key_; | 756 Handle<String> script_id_key_; |
769 Handle<String> script_name_key_; | 757 Handle<String> script_name_key_; |
770 Handle<String> script_name_or_source_url_key_; | 758 Handle<String> script_name_or_source_url_key_; |
771 Handle<String> function_key_; | 759 Handle<String> function_key_; |
772 Handle<String> eval_key_; | 760 Handle<String> eval_key_; |
773 Handle<String> constructor_key_; | 761 Handle<String> constructor_key_; |
774 }; | 762 }; |
775 | 763 |
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( | 764 Handle<JSArray> Isolate::CaptureCurrentStackTrace( |
790 int frame_limit, StackTrace::StackTraceOptions options) { | 765 int frame_limit, StackTrace::StackTraceOptions options) { |
791 DisallowJavascriptExecution no_js(this); | 766 DisallowJavascriptExecution no_js(this); |
792 CaptureStackTraceHelper helper(this, options); | 767 CaptureStackTraceHelper helper(this, options); |
793 | 768 |
794 // Ensure no negative values. | 769 // Ensure no negative values. |
795 int limit = Max(frame_limit, 0); | 770 int limit = Max(frame_limit, 0); |
796 Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit); | 771 Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit); |
797 Handle<FixedArray> stack_trace_elems( | 772 Handle<FixedArray> stack_trace_elems( |
798 FixedArray::cast(stack_trace->elements()), this); | 773 FixedArray::cast(stack_trace->elements()), this); |
(...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1524 | 1499 |
1525 bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, | 1500 bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, |
1526 Handle<Object> exception) { | 1501 Handle<Object> exception) { |
1527 if (!exception->IsJSObject()) return false; | 1502 if (!exception->IsJSObject()) return false; |
1528 Handle<Name> key = factory()->stack_trace_symbol(); | 1503 Handle<Name> key = factory()->stack_trace_symbol(); |
1529 Handle<Object> property = | 1504 Handle<Object> property = |
1530 JSReceiver::GetDataProperty(Handle<JSObject>::cast(exception), key); | 1505 JSReceiver::GetDataProperty(Handle<JSObject>::cast(exception), key); |
1531 if (!property->IsJSArray()) return false; | 1506 if (!property->IsJSArray()) return false; |
1532 Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property); | 1507 Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property); |
1533 | 1508 |
1534 Handle<FixedArray> elements(FixedArray::cast(simple_stack_trace->elements())); | 1509 Handle<FrameArray> elements(FrameArray::cast(simple_stack_trace->elements())); |
1535 int elements_limit = Smi::cast(simple_stack_trace->length())->value(); | |
1536 | 1510 |
1537 for (int i = 1; i < elements_limit; i += 4) { | 1511 const int frame_count = elements->FrameCount(); |
1538 Handle<Object> fun_obj = handle(elements->get(i + 1), this); | 1512 for (int i = 0; i < frame_count; i++) { |
1539 if (fun_obj->IsSmi()) { | 1513 if (elements->IsWasmFrame(i)) { |
1540 // TODO(clemensh): handle wasm frames | 1514 // TODO(clemensh): handle wasm frames |
1541 return false; | 1515 return false; |
1542 } | 1516 } |
1543 Handle<JSFunction> fun = Handle<JSFunction>::cast(fun_obj); | 1517 |
1518 Handle<JSFunction> fun = handle(elements->Function(i), this); | |
1544 if (!fun->shared()->IsSubjectToDebugging()) continue; | 1519 if (!fun->shared()->IsSubjectToDebugging()) continue; |
1545 | 1520 |
1546 Object* script = fun->shared()->script(); | 1521 Object* script = fun->shared()->script(); |
1547 if (script->IsScript() && | 1522 if (script->IsScript() && |
1548 !(Script::cast(script)->source()->IsUndefined(this))) { | 1523 !(Script::cast(script)->source()->IsUndefined(this))) { |
1549 int pos = PositionFromStackTrace(elements, i); | 1524 AbstractCode* abstract_code = elements->Code(i); |
1525 const int code_offset = elements->Offset(i)->value(); | |
1526 const int pos = abstract_code->SourcePosition(code_offset); | |
1527 | |
1550 Handle<Script> casted_script(Script::cast(script)); | 1528 Handle<Script> casted_script(Script::cast(script)); |
1551 *target = MessageLocation(casted_script, pos, pos + 1); | 1529 *target = MessageLocation(casted_script, pos, pos + 1); |
1552 return true; | 1530 return true; |
1553 } | 1531 } |
1554 } | 1532 } |
1555 return false; | 1533 return false; |
1556 } | 1534 } |
1557 | 1535 |
1558 | 1536 |
1559 Handle<JSMessageObject> Isolate::CreateMessage(Handle<Object> exception, | 1537 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. | 3189 // Then check whether this scope intercepts. |
3212 if ((flag & intercept_mask_)) { | 3190 if ((flag & intercept_mask_)) { |
3213 intercepted_flags_ |= flag; | 3191 intercepted_flags_ |= flag; |
3214 return true; | 3192 return true; |
3215 } | 3193 } |
3216 return false; | 3194 return false; |
3217 } | 3195 } |
3218 | 3196 |
3219 } // namespace internal | 3197 } // namespace internal |
3220 } // namespace v8 | 3198 } // namespace v8 |
OLD | NEW |