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 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 339 break; | 339 break; |
| 340 case SKIP_UNTIL_SEEN: | 340 case SKIP_UNTIL_SEEN: |
| 341 DCHECK(caller_->IsJSFunction()); | 341 DCHECK(caller_->IsJSFunction()); |
| 342 skip_next_frame_ = true; | 342 skip_next_frame_ = true; |
| 343 break; | 343 break; |
| 344 case SKIP_NONE: | 344 case SKIP_NONE: |
| 345 skip_next_frame_ = false; | 345 skip_next_frame_ = false; |
| 346 break; | 346 break; |
| 347 } | 347 } |
| 348 encountered_strict_function_ = false; | 348 encountered_strict_function_ = false; |
| 349 sloppy_frames_ = 0; | |
| 350 } | 349 } |
| 351 | 350 |
| 352 // The stack trace API should not expose receivers and function | 351 // The stack trace API should not expose receivers and function |
| 353 // objects on frames deeper than the top-most one with a strict mode | 352 // objects on frames deeper than the top-most one with a strict mode |
| 354 // function. The number of sloppy frames is stored as first element in | 353 // function. |
| 355 // the result array. | 354 bool IsStrictFrame(JSFunction* fun) { |
| 356 void CountSloppyFrames(JSFunction* fun) { | |
| 357 if (!encountered_strict_function_) { | 355 if (!encountered_strict_function_) { |
| 358 if (is_strict(fun->shared()->language_mode())) { | 356 encountered_strict_function_ = is_strict(fun->shared()->language_mode()); |
|
Toon Verwaest
2016/08/24 14:36:39
this should just be return fun->shared()->language
jgruber
2016/08/24 15:12:19
That behavior goes back to https://chromiumcoderev
| |
| 359 encountered_strict_function_ = true; | |
| 360 } else { | |
| 361 sloppy_frames_++; | |
| 362 } | |
| 363 } | 357 } |
| 358 return encountered_strict_function_; | |
| 364 } | 359 } |
| 365 | 360 |
| 366 // Determines whether the given stack frame should be displayed in a stack | 361 // Determines whether the given stack frame should be displayed in a stack |
| 367 // trace. | 362 // trace. |
| 368 bool IsVisibleInStackTrace(JSFunction* fun) { | 363 bool IsVisibleInStackTrace(JSFunction* fun) { |
| 369 return ShouldIncludeFrame(fun) && IsNotInNativeScript(fun) && | 364 return ShouldIncludeFrame(fun) && IsNotInNativeScript(fun) && |
| 370 IsInSameSecurityContext(fun); | 365 IsInSameSecurityContext(fun); |
| 371 } | 366 } |
| 372 | 367 |
| 373 int sloppy_frames() const { return sloppy_frames_; } | |
| 374 | |
| 375 private: | 368 private: |
| 376 // This mechanism excludes a number of uninteresting frames from the stack | 369 // This mechanism excludes a number of uninteresting frames from the stack |
| 377 // trace. This can be be the first frame (which will be a builtin-exit frame | 370 // trace. This can be be the first frame (which will be a builtin-exit frame |
| 378 // for the error constructor builtin) or every frame until encountering a | 371 // for the error constructor builtin) or every frame until encountering a |
| 379 // user-specified function. | 372 // user-specified function. |
| 380 bool ShouldIncludeFrame(JSFunction* fun) { | 373 bool ShouldIncludeFrame(JSFunction* fun) { |
| 381 switch (mode_) { | 374 switch (mode_) { |
| 382 case SKIP_NONE: | 375 case SKIP_NONE: |
| 383 return true; | 376 return true; |
| 384 case SKIP_FIRST: | 377 case SKIP_FIRST: |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 410 bool IsInSameSecurityContext(JSFunction* fun) { | 403 bool IsInSameSecurityContext(JSFunction* fun) { |
| 411 return isolate_->context()->HasSameSecurityTokenAs(fun->context()); | 404 return isolate_->context()->HasSameSecurityTokenAs(fun->context()); |
| 412 } | 405 } |
| 413 | 406 |
| 414 Isolate* isolate_; | 407 Isolate* isolate_; |
| 415 | 408 |
| 416 const FrameSkipMode mode_; | 409 const FrameSkipMode mode_; |
| 417 const Handle<Object> caller_; | 410 const Handle<Object> caller_; |
| 418 bool skip_next_frame_; | 411 bool skip_next_frame_; |
| 419 | 412 |
| 420 int sloppy_frames_; | |
| 421 bool encountered_strict_function_; | 413 bool encountered_strict_function_; |
| 422 }; | 414 }; |
| 423 | 415 |
| 424 // TODO(jgruber): Fix all cases in which frames give us a hole value (e.g. the | 416 // TODO(jgruber): Fix all cases in which frames give us a hole value (e.g. the |
| 425 // receiver in RegExp constructor frames. | 417 // receiver in RegExp constructor frames. |
| 426 Handle<Object> TheHoleToUndefined(Isolate* isolate, Handle<Object> in) { | 418 Handle<Object> TheHoleToUndefined(Isolate* isolate, Handle<Object> in) { |
| 427 return (in->IsTheHole(isolate)) | 419 return (in->IsTheHole(isolate)) |
| 428 ? Handle<Object>::cast(isolate->factory()->undefined_value()) | 420 ? Handle<Object>::cast(isolate->factory()->undefined_value()) |
| 429 : in; | 421 : in; |
| 430 } | 422 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 468 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); | 460 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); |
| 469 // Set initial size to the maximum inlining level + 1 for the outermost | 461 // Set initial size to the maximum inlining level + 1 for the outermost |
| 470 // function. | 462 // function. |
| 471 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); | 463 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); |
| 472 js_frame->Summarize(&frames); | 464 js_frame->Summarize(&frames); |
| 473 for (int i = frames.length() - 1; i >= 0; i--) { | 465 for (int i = frames.length() - 1; i >= 0; i--) { |
| 474 Handle<JSFunction> fun = frames[i].function(); | 466 Handle<JSFunction> fun = frames[i].function(); |
| 475 | 467 |
| 476 // Filter out internal frames that we do not want to show. | 468 // Filter out internal frames that we do not want to show. |
| 477 if (!helper.IsVisibleInStackTrace(*fun)) continue; | 469 if (!helper.IsVisibleInStackTrace(*fun)) continue; |
| 478 helper.CountSloppyFrames(*fun); | |
| 479 | 470 |
| 480 Handle<Object> recv = frames[i].receiver(); | 471 Handle<Object> recv = frames[i].receiver(); |
| 481 Handle<AbstractCode> abstract_code = frames[i].abstract_code(); | 472 Handle<AbstractCode> abstract_code = frames[i].abstract_code(); |
| 473 const int offset = frames[i].code_offset(); | |
| 474 | |
| 475 bool force_constructor = false; | |
| 482 if (frame->type() == StackFrame::BUILTIN) { | 476 if (frame->type() == StackFrame::BUILTIN) { |
| 483 // Help CallSite::IsConstructor correctly detect hand-written | 477 // Help CallSite::IsConstructor correctly detect hand-written |
| 484 // construct stubs. | 478 // construct stubs. |
| 485 Code* code = Code::cast(*abstract_code); | 479 if (Code::cast(*abstract_code)->is_construct_stub()) { |
| 486 if (code->is_construct_stub()) { | 480 force_constructor = true; |
| 487 recv = handle(heap()->call_site_constructor_symbol(), this); | |
| 488 } | 481 } |
| 489 } | 482 } |
| 490 const int offset = frames[i].code_offset(); | |
| 491 | 483 |
| 492 elements = FrameArray::AppendJSFrame(elements, | 484 int flags = 0; |
| 493 TheHoleToUndefined(this, recv), | 485 if (helper.IsStrictFrame(*fun)) flags |= FrameArray::kIsStrict; |
| 494 fun, abstract_code, offset); | 486 if (force_constructor) flags |= FrameArray::kForceConstructor; |
| 487 | |
| 488 elements = FrameArray::AppendJSFrame( | |
| 489 elements, TheHoleToUndefined(this, recv), fun, abstract_code, | |
| 490 offset, flags); | |
| 495 } | 491 } |
| 496 } break; | 492 } break; |
| 497 | 493 |
| 498 case StackFrame::BUILTIN_EXIT: { | 494 case StackFrame::BUILTIN_EXIT: { |
| 499 BuiltinExitFrame* exit_frame = BuiltinExitFrame::cast(frame); | 495 BuiltinExitFrame* exit_frame = BuiltinExitFrame::cast(frame); |
| 500 Handle<JSFunction> fun = handle(exit_frame->function(), this); | 496 Handle<JSFunction> fun = handle(exit_frame->function(), this); |
| 501 | 497 |
| 502 // Filter out internal frames that we do not want to show. | 498 // Filter out internal frames that we do not want to show. |
| 503 if (!helper.IsVisibleInStackTrace(*fun)) continue; | 499 if (!helper.IsVisibleInStackTrace(*fun)) continue; |
| 504 helper.CountSloppyFrames(*fun); | |
| 505 | 500 |
| 506 Handle<Code> code = handle(exit_frame->LookupCode(), this); | 501 Handle<Object> recv(exit_frame->receiver(), this); |
| 502 Handle<Code> code(exit_frame->LookupCode(), this); | |
| 507 int offset = | 503 int offset = |
| 508 static_cast<int>(exit_frame->pc() - code->instruction_start()); | 504 static_cast<int>(exit_frame->pc() - code->instruction_start()); |
| 509 | 505 |
| 510 // In order to help CallSite::IsConstructor detect builtin constructors, | 506 int flags = 0; |
| 511 // we reuse the receiver field to pass along a special symbol. | 507 if (helper.IsStrictFrame(*fun)) flags |= FrameArray::kIsStrict; |
| 512 Handle<Object> recv; | 508 if (exit_frame->IsConstructor()) flags |= FrameArray::kForceConstructor; |
| 513 if (exit_frame->IsConstructor()) { | |
| 514 recv = factory()->call_site_constructor_symbol(); | |
| 515 } else { | |
| 516 recv = handle(exit_frame->receiver(), this); | |
| 517 } | |
| 518 | 509 |
| 519 elements = FrameArray::AppendJSFrame( | 510 elements = FrameArray::AppendJSFrame(elements, recv, fun, |
| 520 elements, recv, fun, Handle<AbstractCode>::cast(code), offset); | 511 Handle<AbstractCode>::cast(code), |
| 512 offset, flags); | |
| 521 } break; | 513 } break; |
| 522 | 514 |
| 523 case StackFrame::WASM: { | 515 case StackFrame::WASM: { |
| 524 WasmFrame* wasm_frame = WasmFrame::cast(frame); | 516 WasmFrame* wasm_frame = WasmFrame::cast(frame); |
| 525 Handle<Object> wasm_object = handle(wasm_frame->wasm_obj(), this); | 517 Handle<Object> wasm_object(wasm_frame->wasm_obj(), this); |
| 526 const int wasm_function_index = wasm_frame->function_index(); | 518 const int wasm_function_index = wasm_frame->function_index(); |
| 527 Code* code = wasm_frame->unchecked_code(); | 519 Code* code = wasm_frame->unchecked_code(); |
| 528 Handle<AbstractCode> abstract_code = | 520 Handle<AbstractCode> abstract_code(AbstractCode::cast(code), this); |
| 529 Handle<AbstractCode>(AbstractCode::cast(code), this); | |
| 530 const int offset = | 521 const int offset = |
| 531 static_cast<int>(wasm_frame->pc() - code->instruction_start()); | 522 static_cast<int>(wasm_frame->pc() - code->instruction_start()); |
| 532 | 523 |
| 533 // TODO(wasm): The wasm object returned by the WasmFrame should always | 524 // TODO(wasm): The wasm object returned by the WasmFrame should always |
| 534 // be a wasm object. | 525 // be a wasm object. |
| 535 DCHECK(wasm::IsWasmObject(*wasm_object) || | 526 DCHECK(wasm::IsWasmObject(*wasm_object) || |
| 536 wasm_object->IsUndefined(this)); | 527 wasm_object->IsUndefined(this)); |
| 537 | 528 |
| 538 elements = FrameArray::AppendWasmFrame( | 529 elements = FrameArray::AppendWasmFrame( |
| 539 elements, wasm_object, wasm_function_index, abstract_code, offset); | 530 elements, wasm_object, wasm_function_index, abstract_code, offset, |
| 531 FrameArray::kIsWasmFrame); | |
| 540 } break; | 532 } break; |
| 541 | 533 |
| 542 default: | 534 default: |
| 543 break; | 535 break; |
| 544 } | 536 } |
| 545 } | 537 } |
| 546 | 538 |
| 547 elements->SetSloppyFrameCount(helper.sloppy_frames()); | |
| 548 elements->ShrinkToFit(); | 539 elements->ShrinkToFit(); |
| 549 | 540 |
| 550 // TODO(yangguo): Queue this structured stack trace for preprocessing on GC. | 541 // TODO(yangguo): Queue this structured stack trace for preprocessing on GC. |
| 551 return factory()->NewJSArrayWithElements(elements); | 542 return factory()->NewJSArrayWithElements(elements); |
| 552 } | 543 } |
| 553 | 544 |
| 554 MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace( | 545 MaybeHandle<JSReceiver> Isolate::CaptureAndSetDetailedStackTrace( |
| 555 Handle<JSReceiver> error_object) { | 546 Handle<JSReceiver> error_object) { |
| 556 if (capture_stack_trace_for_uncaught_exceptions_) { | 547 if (capture_stack_trace_for_uncaught_exceptions_) { |
| 557 // Capture stack trace for a detailed exception message. | 548 // Capture stack trace for a detailed exception message. |
| (...skipping 2625 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3183 // Then check whether this scope intercepts. | 3174 // Then check whether this scope intercepts. |
| 3184 if ((flag & intercept_mask_)) { | 3175 if ((flag & intercept_mask_)) { |
| 3185 intercepted_flags_ |= flag; | 3176 intercepted_flags_ |= flag; |
| 3186 return true; | 3177 return true; |
| 3187 } | 3178 } |
| 3188 return false; | 3179 return false; |
| 3189 } | 3180 } |
| 3190 | 3181 |
| 3191 } // namespace internal | 3182 } // namespace internal |
| 3192 } // namespace v8 | 3183 } // namespace v8 |
| OLD | NEW |