| 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 |