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 |