Chromium Code Reviews| 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 |