| 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 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 break; | 349 break; |
| 350 case SKIP_UNTIL_SEEN: | 350 case SKIP_UNTIL_SEEN: |
| 351 DCHECK(caller_->IsJSFunction()); | 351 DCHECK(caller_->IsJSFunction()); |
| 352 skip_next_frame_ = true; | 352 skip_next_frame_ = true; |
| 353 break; | 353 break; |
| 354 case SKIP_NONE: | 354 case SKIP_NONE: |
| 355 skip_next_frame_ = false; | 355 skip_next_frame_ = false; |
| 356 break; | 356 break; |
| 357 } | 357 } |
| 358 encountered_strict_function_ = false; | 358 encountered_strict_function_ = false; |
| 359 sloppy_frames_ = 0; | |
| 360 } | 359 } |
| 361 | 360 |
| 362 // The stack trace API should not expose receivers and function | 361 // The stack trace API should not expose receivers and function |
| 363 // objects on frames deeper than the top-most one with a strict mode | 362 // objects on frames deeper than the top-most one with a strict mode |
| 364 // function. The number of sloppy frames is stored as first element in | 363 // function. |
| 365 // the result array. | 364 bool IsStrictFrame(JSFunction* fun) { |
| 366 void CountSloppyFrames(JSFunction* fun) { | |
| 367 if (!encountered_strict_function_) { | 365 if (!encountered_strict_function_) { |
| 368 if (is_strict(fun->shared()->language_mode())) { | 366 encountered_strict_function_ = is_strict(fun->shared()->language_mode()); |
| 369 encountered_strict_function_ = true; | |
| 370 } else { | |
| 371 sloppy_frames_++; | |
| 372 } | |
| 373 } | 367 } |
| 368 return encountered_strict_function_; |
| 374 } | 369 } |
| 375 | 370 |
| 376 // Determines whether the given stack frame should be displayed in a stack | 371 // Determines whether the given stack frame should be displayed in a stack |
| 377 // trace. | 372 // trace. |
| 378 bool IsVisibleInStackTrace(JSFunction* fun) { | 373 bool IsVisibleInStackTrace(JSFunction* fun) { |
| 379 return ShouldIncludeFrame(fun) && IsNotInNativeScript(fun) && | 374 return ShouldIncludeFrame(fun) && IsNotInNativeScript(fun) && |
| 380 IsInSameSecurityContext(fun); | 375 IsInSameSecurityContext(fun); |
| 381 } | 376 } |
| 382 | 377 |
| 383 int sloppy_frames() const { return sloppy_frames_; } | |
| 384 | |
| 385 private: | 378 private: |
| 386 // This mechanism excludes a number of uninteresting frames from the stack | 379 // This mechanism excludes a number of uninteresting frames from the stack |
| 387 // trace. This can be be the first frame (which will be a builtin-exit frame | 380 // trace. This can be be the first frame (which will be a builtin-exit frame |
| 388 // for the error constructor builtin) or every frame until encountering a | 381 // for the error constructor builtin) or every frame until encountering a |
| 389 // user-specified function. | 382 // user-specified function. |
| 390 bool ShouldIncludeFrame(JSFunction* fun) { | 383 bool ShouldIncludeFrame(JSFunction* fun) { |
| 391 switch (mode_) { | 384 switch (mode_) { |
| 392 case SKIP_NONE: | 385 case SKIP_NONE: |
| 393 return true; | 386 return true; |
| 394 case SKIP_FIRST: | 387 case SKIP_FIRST: |
| (...skipping 25 matching lines...) Expand all Loading... |
| 420 bool IsInSameSecurityContext(JSFunction* fun) { | 413 bool IsInSameSecurityContext(JSFunction* fun) { |
| 421 return isolate_->context()->HasSameSecurityTokenAs(fun->context()); | 414 return isolate_->context()->HasSameSecurityTokenAs(fun->context()); |
| 422 } | 415 } |
| 423 | 416 |
| 424 Isolate* isolate_; | 417 Isolate* isolate_; |
| 425 | 418 |
| 426 const FrameSkipMode mode_; | 419 const FrameSkipMode mode_; |
| 427 const Handle<Object> caller_; | 420 const Handle<Object> caller_; |
| 428 bool skip_next_frame_; | 421 bool skip_next_frame_; |
| 429 | 422 |
| 430 int sloppy_frames_; | |
| 431 bool encountered_strict_function_; | 423 bool encountered_strict_function_; |
| 432 }; | 424 }; |
| 433 | 425 |
| 434 namespace { | 426 namespace { |
| 435 | 427 |
| 436 // TODO(jgruber): Fix all cases in which frames give us a hole value (e.g. the | 428 // TODO(jgruber): Fix all cases in which frames give us a hole value (e.g. the |
| 437 // receiver in RegExp constructor frames. | 429 // receiver in RegExp constructor frames. |
| 438 Handle<Object> TheHoleToUndefined(Isolate* isolate, Handle<Object> in) { | 430 Handle<Object> TheHoleToUndefined(Isolate* isolate, Handle<Object> in) { |
| 439 return (in->IsTheHole(isolate)) | 431 return (in->IsTheHole(isolate)) |
| 440 ? Handle<Object>::cast(isolate->factory()->undefined_value()) | 432 ? Handle<Object>::cast(isolate->factory()->undefined_value()) |
| 441 : in; | 433 : in; |
| 442 } | 434 } |
| 435 |
| 436 bool GetStackTraceLimit(Isolate* isolate, int* result) { |
| 437 Handle<JSObject> error = isolate->error_function(); |
| 438 Handle<String> stackTraceLimit = |
| 439 isolate->factory()->InternalizeUtf8String("stackTraceLimit"); |
| 440 DCHECK(!stackTraceLimit.is_null()); |
| 441 |
| 442 Handle<Object> stack_trace_limit = |
| 443 JSReceiver::GetDataProperty(error, stackTraceLimit); |
| 444 if (!stack_trace_limit->IsNumber()) return false; |
| 445 |
| 446 // Ensure that limit is not negative. |
| 447 *result = Max(FastD2IChecked(stack_trace_limit->Number()), 0); |
| 448 return true; |
| 443 } | 449 } |
| 444 | 450 |
| 451 } // namespace |
| 452 |
| 445 Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, | 453 Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, |
| 446 FrameSkipMode mode, | 454 FrameSkipMode mode, |
| 447 Handle<Object> caller) { | 455 Handle<Object> caller) { |
| 448 DisallowJavascriptExecution no_js(this); | 456 DisallowJavascriptExecution no_js(this); |
| 449 | 457 |
| 450 // Get stack trace limit. | 458 int limit; |
| 451 Handle<JSObject> error = error_function(); | 459 if (!GetStackTraceLimit(this, &limit)) return factory()->undefined_value(); |
| 452 Handle<String> stackTraceLimit = | |
| 453 factory()->InternalizeUtf8String("stackTraceLimit"); | |
| 454 DCHECK(!stackTraceLimit.is_null()); | |
| 455 Handle<Object> stack_trace_limit = | |
| 456 JSReceiver::GetDataProperty(error, stackTraceLimit); | |
| 457 if (!stack_trace_limit->IsNumber()) return factory()->undefined_value(); | |
| 458 int limit = FastD2IChecked(stack_trace_limit->Number()); | |
| 459 limit = Max(limit, 0); // Ensure that limit is not negative. | |
| 460 | 460 |
| 461 int initial_size = Min(limit, 10); | 461 using ESTF = EncodedStackTraceFrame; |
| 462 Handle<FixedArray> elements = | 462 int initial_size = Min(limit, 10) * ESTF::kElementsPerFrame; |
| 463 factory()->NewFixedArrayWithHoles(initial_size * 4 + 1); | 463 Handle<FixedArray> elements = factory()->NewFixedArrayWithHoles(initial_size); |
| 464 | 464 |
| 465 int cursor = 0; |
| 466 int frames_seen = 0; |
| 465 StackTraceHelper helper(this, mode, caller); | 467 StackTraceHelper helper(this, mode, caller); |
| 466 | 468 |
| 467 // First element is reserved to store the number of sloppy frames. | |
| 468 int cursor = 1; | |
| 469 int frames_seen = 0; | |
| 470 for (StackFrameIterator iter(this); !iter.done() && frames_seen < limit; | 469 for (StackFrameIterator iter(this); !iter.done() && frames_seen < limit; |
| 471 iter.Advance()) { | 470 iter.Advance()) { |
| 472 StackFrame* frame = iter.frame(); | 471 StackFrame* frame = iter.frame(); |
| 473 | 472 |
| 474 switch (frame->type()) { | 473 switch (frame->type()) { |
| 475 case StackFrame::JAVA_SCRIPT: | 474 case StackFrame::JAVA_SCRIPT: |
| 476 case StackFrame::OPTIMIZED: | 475 case StackFrame::OPTIMIZED: |
| 477 case StackFrame::INTERPRETED: | 476 case StackFrame::INTERPRETED: |
| 478 case StackFrame::BUILTIN: { | 477 case StackFrame::BUILTIN: { |
| 479 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); | 478 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); |
| 480 // Set initial size to the maximum inlining level + 1 for the outermost | 479 // Set initial size to the maximum inlining level + 1 for the outermost |
| 481 // function. | 480 // function. |
| 482 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); | 481 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); |
| 483 js_frame->Summarize(&frames); | 482 js_frame->Summarize(&frames); |
| 484 for (int i = frames.length() - 1; i >= 0; i--) { | 483 for (int i = frames.length() - 1; i >= 0; i--) { |
| 485 Handle<JSFunction> fun = frames[i].function(); | 484 Handle<JSFunction> fun = frames[i].function(); |
| 486 | 485 |
| 487 // Filter out internal frames that we do not want to show. | 486 // Filter out internal frames that we do not want to show. |
| 488 if (!helper.IsVisibleInStackTrace(*fun)) continue; | 487 if (!helper.IsVisibleInStackTrace(*fun)) continue; |
| 489 helper.CountSloppyFrames(*fun); | |
| 490 | 488 |
| 491 Handle<Object> recv = frames[i].receiver(); | 489 Handle<Object> recv = frames[i].receiver(); |
| 492 Handle<AbstractCode> abstract_code = frames[i].abstract_code(); | 490 Handle<AbstractCode> abstract_code = frames[i].abstract_code(); |
| 491 const int offset = frames[i].code_offset(); |
| 492 |
| 493 bool force_constructor = false; |
| 493 if (frame->type() == StackFrame::BUILTIN) { | 494 if (frame->type() == StackFrame::BUILTIN) { |
| 494 // Help CallSite::IsConstructor correctly detect hand-written | 495 // Help CallSite::IsConstructor correctly detect hand-written |
| 495 // construct stubs. | 496 // construct stubs. |
| 496 Code* code = Code::cast(*abstract_code); | 497 if (Code::cast(*abstract_code)->is_construct_stub()) { |
| 497 if (code->is_construct_stub()) { | 498 force_constructor = true; |
| 498 recv = handle(heap()->call_site_constructor_symbol(), this); | |
| 499 } | 499 } |
| 500 } | 500 } |
| 501 Handle<Smi> offset(Smi::FromInt(frames[i].code_offset()), this); | |
| 502 | 501 |
| 503 elements = MaybeGrow(this, elements, cursor, cursor + 4); | 502 int flags = 0; |
| 503 if (helper.IsStrictFrame(*fun)) flags |= StackTraceFrame::kIsStrict; |
| 504 if (force_constructor) flags |= StackTraceFrame::kForceConstructor; |
| 505 |
| 506 elements = MaybeGrow(this, elements, cursor, |
| 507 cursor + ESTF::kElementsPerFrame); |
| 504 elements->set(cursor++, *TheHoleToUndefined(this, recv)); | 508 elements->set(cursor++, *TheHoleToUndefined(this, recv)); |
| 505 elements->set(cursor++, *fun); | 509 elements->set(cursor++, *fun); |
| 506 elements->set(cursor++, *abstract_code); | 510 elements->set(cursor++, *abstract_code); |
| 507 elements->set(cursor++, *offset); | 511 elements->set(cursor++, Smi::FromInt(offset)); |
| 512 elements->set(cursor++, Smi::FromInt(flags)); |
| 508 frames_seen++; | 513 frames_seen++; |
| 509 } | 514 } |
| 510 } break; | 515 } break; |
| 511 | 516 |
| 512 case StackFrame::BUILTIN_EXIT: { | 517 case StackFrame::BUILTIN_EXIT: { |
| 513 BuiltinExitFrame* exit_frame = BuiltinExitFrame::cast(frame); | 518 BuiltinExitFrame* exit_frame = BuiltinExitFrame::cast(frame); |
| 514 Handle<JSFunction> fun = handle(exit_frame->function(), this); | 519 Handle<JSFunction> fun = handle(exit_frame->function(), this); |
| 515 | 520 |
| 516 // Filter out internal frames that we do not want to show. | 521 // Filter out internal frames that we do not want to show. |
| 517 if (!helper.IsVisibleInStackTrace(*fun)) continue; | 522 if (!helper.IsVisibleInStackTrace(*fun)) continue; |
| 518 helper.CountSloppyFrames(*fun); | |
| 519 | 523 |
| 524 Handle<Object> recv = handle(exit_frame->receiver(), this); |
| 520 Handle<Code> code = handle(exit_frame->LookupCode(), this); | 525 Handle<Code> code = handle(exit_frame->LookupCode(), this); |
| 521 int offset = | 526 const int offset = |
| 522 static_cast<int>(exit_frame->pc() - code->instruction_start()); | 527 static_cast<int>(exit_frame->pc() - code->instruction_start()); |
| 523 | 528 |
| 524 // In order to help CallSite::IsConstructor detect builtin constructors, | 529 int flags = 0; |
| 525 // we reuse the receiver field to pass along a special symbol. | 530 if (helper.IsStrictFrame(*fun)) flags |= StackTraceFrame::kIsStrict; |
| 526 Handle<Object> recv; | 531 if (exit_frame->IsConstructor()) |
| 527 if (exit_frame->IsConstructor()) { | 532 flags |= StackTraceFrame::kForceConstructor; |
| 528 recv = factory()->call_site_constructor_symbol(); | |
| 529 } else { | |
| 530 recv = handle(exit_frame->receiver(), this); | |
| 531 } | |
| 532 | 533 |
| 533 elements = MaybeGrow(this, elements, cursor, cursor + 4); | 534 elements = |
| 535 MaybeGrow(this, elements, cursor, cursor + ESTF::kElementsPerFrame); |
| 534 elements->set(cursor++, *recv); | 536 elements->set(cursor++, *recv); |
| 535 elements->set(cursor++, *fun); | 537 elements->set(cursor++, *fun); |
| 536 elements->set(cursor++, *code); | 538 elements->set(cursor++, *code); |
| 537 elements->set(cursor++, Smi::FromInt(offset)); | 539 elements->set(cursor++, Smi::FromInt(offset)); |
| 540 elements->set(cursor++, Smi::FromInt(flags)); |
| 538 frames_seen++; | 541 frames_seen++; |
| 539 } break; | 542 } break; |
| 540 | 543 |
| 541 case StackFrame::WASM: { | 544 case StackFrame::WASM: { |
| 542 WasmFrame* wasm_frame = WasmFrame::cast(frame); | 545 WasmFrame* wasm_frame = WasmFrame::cast(frame); |
| 543 Code* code = wasm_frame->unchecked_code(); | 546 Code* code = wasm_frame->unchecked_code(); |
| 544 Handle<AbstractCode> abstract_code = | 547 Handle<AbstractCode> abstract_code = |
| 545 Handle<AbstractCode>(AbstractCode::cast(code), this); | 548 Handle<AbstractCode>(AbstractCode::cast(code), this); |
| 546 int offset = | 549 const int offset = |
| 547 static_cast<int>(wasm_frame->pc() - code->instruction_start()); | 550 static_cast<int>(wasm_frame->pc() - code->instruction_start()); |
| 548 elements = MaybeGrow(this, elements, cursor, cursor + 4); | 551 |
| 552 // TODO(wasm): The wasm object returned by the WasmFrame should always |
| 553 // be a wasm object. |
| 554 DCHECK(wasm::IsWasmObject(wasm_frame->wasm_obj()) || |
| 555 wasm_frame->wasm_obj()->IsUndefined(this)); |
| 556 |
| 557 elements = |
| 558 MaybeGrow(this, elements, cursor, cursor + ESTF::kElementsPerFrame); |
| 549 elements->set(cursor++, wasm_frame->wasm_obj()); | 559 elements->set(cursor++, wasm_frame->wasm_obj()); |
| 550 elements->set(cursor++, Smi::FromInt(wasm_frame->function_index())); | 560 elements->set(cursor++, Smi::FromInt(wasm_frame->function_index())); |
| 551 elements->set(cursor++, *abstract_code); | 561 elements->set(cursor++, *abstract_code); |
| 552 elements->set(cursor++, Smi::FromInt(offset)); | 562 elements->set(cursor++, Smi::FromInt(offset)); |
| 563 elements->set(cursor++, Smi::FromInt(StackTraceFrame::kIsWasmFrame)); |
| 553 frames_seen++; | 564 frames_seen++; |
| 554 } break; | 565 } break; |
| 555 | 566 |
| 556 default: | 567 default: |
| 557 break; | 568 break; |
| 558 } | 569 } |
| 559 } | 570 } |
| 560 elements->set(0, Smi::FromInt(helper.sloppy_frames())); | 571 |
| 572 DCHECK_EQ(0, cursor % ESTF::kElementsPerFrame); |
| 561 elements->Shrink(cursor); | 573 elements->Shrink(cursor); |
| 562 Handle<JSArray> result = factory()->NewJSArrayWithElements(elements); | 574 Handle<JSArray> result = factory()->NewJSArrayWithElements(elements); |
| 563 result->set_length(Smi::FromInt(cursor)); | 575 result->set_length(Smi::FromInt(cursor)); |
| 576 |
| 564 // TODO(yangguo): Queue this structured stack trace for preprocessing on GC. | 577 // TODO(yangguo): Queue this structured stack trace for preprocessing on GC. |
| 565 return result; | 578 return result; |
| 566 } | 579 } |
| 567 | 580 |
| 568 MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace( | 581 MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace( |
| 569 Handle<JSReceiver> error_object) { | 582 Handle<JSReceiver> error_object) { |
| 570 if (capture_stack_trace_for_uncaught_exceptions_) { | 583 if (capture_stack_trace_for_uncaught_exceptions_) { |
| 571 // Capture stack trace for a detailed exception message. | 584 // Capture stack trace for a detailed exception message. |
| 572 Handle<Name> key = factory()->detailed_stack_trace_symbol(); | 585 Handle<Name> key = factory()->detailed_stack_trace_symbol(); |
| 573 Handle<JSArray> stack_trace = CaptureCurrentStackTrace( | 586 Handle<JSArray> stack_trace = CaptureCurrentStackTrace( |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 Handle<String> column_key_; | 775 Handle<String> column_key_; |
| 763 Handle<String> line_key_; | 776 Handle<String> line_key_; |
| 764 Handle<String> script_id_key_; | 777 Handle<String> script_id_key_; |
| 765 Handle<String> script_name_key_; | 778 Handle<String> script_name_key_; |
| 766 Handle<String> script_name_or_source_url_key_; | 779 Handle<String> script_name_or_source_url_key_; |
| 767 Handle<String> function_key_; | 780 Handle<String> function_key_; |
| 768 Handle<String> eval_key_; | 781 Handle<String> eval_key_; |
| 769 Handle<String> constructor_key_; | 782 Handle<String> constructor_key_; |
| 770 }; | 783 }; |
| 771 | 784 |
| 772 | |
| 773 int PositionFromStackTrace(Handle<FixedArray> elements, int index) { | |
| 774 DisallowHeapAllocation no_gc; | |
| 775 Object* maybe_code = elements->get(index + 2); | |
| 776 if (maybe_code->IsSmi()) { | |
| 777 return Smi::cast(maybe_code)->value(); | |
| 778 } else { | |
| 779 AbstractCode* abstract_code = AbstractCode::cast(maybe_code); | |
| 780 int code_offset = Smi::cast(elements->get(index + 3))->value(); | |
| 781 return abstract_code->SourcePosition(code_offset); | |
| 782 } | |
| 783 } | |
| 784 | |
| 785 Handle<JSArray> Isolate::CaptureCurrentStackTrace( | 785 Handle<JSArray> Isolate::CaptureCurrentStackTrace( |
| 786 int frame_limit, StackTrace::StackTraceOptions options) { | 786 int frame_limit, StackTrace::StackTraceOptions options) { |
| 787 DisallowJavascriptExecution no_js(this); | 787 DisallowJavascriptExecution no_js(this); |
| 788 CaptureStackTraceHelper helper(this, options); | 788 CaptureStackTraceHelper helper(this, options); |
| 789 | 789 |
| 790 // Ensure no negative values. | 790 // Ensure no negative values. |
| 791 int limit = Max(frame_limit, 0); | 791 int limit = Max(frame_limit, 0); |
| 792 Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit); | 792 Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit); |
| 793 Handle<FixedArray> stack_trace_elems( | 793 Handle<FixedArray> stack_trace_elems( |
| 794 FixedArray::cast(stack_trace->elements()), this); | 794 FixedArray::cast(stack_trace->elements()), this); |
| (...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1419 | 1419 |
| 1420 Object* Isolate::PromoteScheduledException() { | 1420 Object* Isolate::PromoteScheduledException() { |
| 1421 Object* thrown = scheduled_exception(); | 1421 Object* thrown = scheduled_exception(); |
| 1422 clear_scheduled_exception(); | 1422 clear_scheduled_exception(); |
| 1423 // Re-throw the exception to avoid getting repeated error reporting. | 1423 // Re-throw the exception to avoid getting repeated error reporting. |
| 1424 return ReThrow(thrown); | 1424 return ReThrow(thrown); |
| 1425 } | 1425 } |
| 1426 | 1426 |
| 1427 | 1427 |
| 1428 void Isolate::PrintCurrentStackTrace(FILE* out) { | 1428 void Isolate::PrintCurrentStackTrace(FILE* out) { |
| 1429 StackTraceFrameIterator it(this); | 1429 for (StackTraceFrameIterator it(this); !it.done(); it.Advance()) { |
| 1430 while (!it.done()) { | 1430 if (!it.is_javascript()) continue; |
| 1431 |
| 1431 HandleScope scope(this); | 1432 HandleScope scope(this); |
| 1433 JavaScriptFrame* frame = it.javascript_frame(); |
| 1434 |
| 1432 // Find code position if recorded in relocation info. | 1435 // Find code position if recorded in relocation info. |
| 1433 StandardFrame* frame = it.frame(); | 1436 AbstractCode* abstract_code = AbstractCode::cast(frame->LookupCode()); |
| 1434 AbstractCode* abstract_code; | 1437 const int code_offset = |
| 1435 int code_offset; | 1438 static_cast<int>(frame->pc() - abstract_code->instruction_start()); |
| 1436 if (frame->is_interpreted()) { | 1439 |
| 1437 InterpretedFrame* iframe = reinterpret_cast<InterpretedFrame*>(frame); | 1440 Handle<StackTraceFrame> st_frame = factory()->NewStackTraceFrame(); |
| 1438 abstract_code = AbstractCode::cast(iframe->GetBytecodeArray()); | 1441 |
| 1439 code_offset = iframe->GetBytecodeOffset(); | 1442 st_frame->set_receiver(frame->receiver()); |
| 1440 } else { | 1443 st_frame->set_function(frame->function()); |
| 1441 DCHECK(frame->is_java_script() || frame->is_wasm()); | 1444 st_frame->set_abstract_code(abstract_code); |
| 1442 Code* code = frame->LookupCode(); | 1445 st_frame->set_offset(code_offset); |
| 1443 abstract_code = AbstractCode::cast(code); | 1446 |
| 1444 code_offset = static_cast<int>(frame->pc() - code->instruction_start()); | |
| 1445 } | |
| 1446 int pos = abstract_code->SourcePosition(code_offset); | |
| 1447 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); | |
| 1448 Handle<Object> pos_obj(Smi::FromInt(pos), this); | |
| 1449 // Fetch function and receiver. | |
| 1450 Handle<JSFunction> fun(js_frame->function(), this); | |
| 1451 Handle<Object> recv(js_frame->receiver(), this); | |
| 1452 // Advance to the next JavaScript frame and determine if the | |
| 1453 // current frame is the top-level frame. | |
| 1454 it.Advance(); | |
| 1455 Handle<Object> is_top_level = factory()->ToBoolean(it.done()); | |
| 1456 // Generate and print stack trace line. | 1447 // Generate and print stack trace line. |
| 1457 Handle<String> line = | 1448 Handle<String> line = st_frame->ToString(); |
| 1458 Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level); | |
| 1459 if (line->length() > 0) { | 1449 if (line->length() > 0) { |
| 1460 line->PrintOn(out); | 1450 line->PrintOn(out); |
| 1461 PrintF(out, "\n"); | 1451 PrintF(out, "\n"); |
| 1462 } | 1452 } |
| 1463 } | 1453 } |
| 1464 } | 1454 } |
| 1465 | 1455 |
| 1466 bool Isolate::ComputeLocation(MessageLocation* target) { | 1456 bool Isolate::ComputeLocation(MessageLocation* target) { |
| 1467 StackTraceFrameIterator it(this); | 1457 StackTraceFrameIterator it(this); |
| 1468 if (it.done()) return false; | 1458 if (it.done()) return false; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1506 Handle<Name> script_symbol = factory()->error_script_symbol(); | 1496 Handle<Name> script_symbol = factory()->error_script_symbol(); |
| 1507 Handle<Object> script = JSReceiver::GetDataProperty( | 1497 Handle<Object> script = JSReceiver::GetDataProperty( |
| 1508 Handle<JSObject>::cast(exception), script_symbol); | 1498 Handle<JSObject>::cast(exception), script_symbol); |
| 1509 if (!script->IsScript()) return false; | 1499 if (!script->IsScript()) return false; |
| 1510 | 1500 |
| 1511 Handle<Script> cast_script(Script::cast(*script)); | 1501 Handle<Script> cast_script(Script::cast(*script)); |
| 1512 *target = MessageLocation(cast_script, start_pos_value, end_pos_value); | 1502 *target = MessageLocation(cast_script, start_pos_value, end_pos_value); |
| 1513 return true; | 1503 return true; |
| 1514 } | 1504 } |
| 1515 | 1505 |
| 1506 namespace { |
| 1507 |
| 1508 int PositionFromStackTrace(Handle<FixedArray> elements, int index) { |
| 1509 DisallowHeapAllocation no_gc; |
| 1510 using ESTF = EncodedStackTraceFrame; |
| 1511 Object* maybe_code = elements->get(index + ESTF::kCodeOffset); |
| 1512 if (maybe_code->IsSmi()) { |
| 1513 return Smi::cast(maybe_code)->value(); |
| 1514 } else { |
| 1515 AbstractCode* abstract_code = AbstractCode::cast(maybe_code); |
| 1516 int code_offset = |
| 1517 Smi::cast(elements->get(index + ESTF::kOffsetOffset))->value(); |
| 1518 return abstract_code->SourcePosition(code_offset); |
| 1519 } |
| 1520 } |
| 1521 |
| 1522 } // namespace |
| 1516 | 1523 |
| 1517 bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, | 1524 bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target, |
| 1518 Handle<Object> exception) { | 1525 Handle<Object> exception) { |
| 1519 if (!exception->IsJSObject()) return false; | 1526 if (!exception->IsJSObject()) return false; |
| 1520 Handle<Name> key = factory()->stack_trace_symbol(); | 1527 Handle<Name> key = factory()->stack_trace_symbol(); |
| 1521 Handle<Object> property = | 1528 Handle<Object> property = |
| 1522 JSReceiver::GetDataProperty(Handle<JSObject>::cast(exception), key); | 1529 JSReceiver::GetDataProperty(Handle<JSObject>::cast(exception), key); |
| 1523 if (!property->IsJSArray()) return false; | 1530 if (!property->IsJSArray()) return false; |
| 1524 Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property); | 1531 Handle<JSArray> simple_stack_trace = Handle<JSArray>::cast(property); |
| 1525 | 1532 |
| 1526 Handle<FixedArray> elements(FixedArray::cast(simple_stack_trace->elements())); | 1533 Handle<FixedArray> elements(FixedArray::cast(simple_stack_trace->elements())); |
| 1527 int elements_limit = Smi::cast(simple_stack_trace->length())->value(); | 1534 int elements_limit = Smi::cast(simple_stack_trace->length())->value(); |
| 1528 | 1535 |
| 1529 for (int i = 1; i < elements_limit; i += 4) { | 1536 using ESTF = EncodedStackTraceFrame; |
| 1530 Handle<Object> fun_obj = handle(elements->get(i + 1), this); | 1537 for (int i = 0; i < elements_limit; i += ESTF::kElementsPerFrame) { |
| 1538 Handle<Object> fun_obj = |
| 1539 handle(elements->get(i + ESTF::kFunctionOffset), this); |
| 1531 if (fun_obj->IsSmi()) { | 1540 if (fun_obj->IsSmi()) { |
| 1532 // TODO(clemensh): handle wasm frames | 1541 // TODO(clemensh): handle wasm frames |
| 1533 return false; | 1542 return false; |
| 1534 } | 1543 } |
| 1535 Handle<JSFunction> fun = Handle<JSFunction>::cast(fun_obj); | 1544 Handle<JSFunction> fun = Handle<JSFunction>::cast(fun_obj); |
| 1536 if (!fun->shared()->IsSubjectToDebugging()) continue; | 1545 if (!fun->shared()->IsSubjectToDebugging()) continue; |
| 1537 | 1546 |
| 1538 Object* script = fun->shared()->script(); | 1547 Object* script = fun->shared()->script(); |
| 1539 if (script->IsScript() && | 1548 if (script->IsScript() && |
| 1540 !(Script::cast(script)->source()->IsUndefined(this))) { | 1549 !(Script::cast(script)->source()->IsUndefined(this))) { |
| (...skipping 1662 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3203 // Then check whether this scope intercepts. | 3212 // Then check whether this scope intercepts. |
| 3204 if ((flag & intercept_mask_)) { | 3213 if ((flag & intercept_mask_)) { |
| 3205 intercepted_flags_ |= flag; | 3214 intercepted_flags_ |= flag; |
| 3206 return true; | 3215 return true; |
| 3207 } | 3216 } |
| 3208 return false; | 3217 return false; |
| 3209 } | 3218 } |
| 3210 | 3219 |
| 3211 } // namespace internal | 3220 } // namespace internal |
| 3212 } // namespace v8 | 3221 } // namespace v8 |
| OLD | NEW |