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