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/frames.h" | 5 #include "src/frames.h" |
| 6 | 6 |
| 7 #include <sstream> | 7 #include <sstream> |
| 8 | 8 |
| 9 #include "src/ast/ast.h" | 9 #include "src/ast/ast.h" |
| 10 #include "src/ast/scopeinfo.h" | 10 #include "src/ast/scopeinfo.h" |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 209 } else if (IsValidStackAddress(fp)) { | 209 } else if (IsValidStackAddress(fp)) { |
| 210 DCHECK(fp != NULL); | 210 DCHECK(fp != NULL); |
| 211 state.fp = fp; | 211 state.fp = fp; |
| 212 state.sp = sp; | 212 state.sp = sp; |
| 213 state.pc_address = StackFrame::ResolveReturnAddressLocation( | 213 state.pc_address = StackFrame::ResolveReturnAddressLocation( |
| 214 reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp))); | 214 reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp))); |
| 215 // StackFrame::ComputeType will read both kContextOffset and kMarkerOffset, | 215 // StackFrame::ComputeType will read both kContextOffset and kMarkerOffset, |
| 216 // we check only that kMarkerOffset is within the stack bounds and do | 216 // we check only that kMarkerOffset is within the stack bounds and do |
| 217 // compile time check that kContextOffset slot is pushed on the stack before | 217 // compile time check that kContextOffset slot is pushed on the stack before |
| 218 // kMarkerOffset. | 218 // kMarkerOffset. |
| 219 STATIC_ASSERT(StandardFrameConstants::kMarkerOffset < | 219 STATIC_ASSERT(StandardFrameConstants::kFunctionOffset < |
| 220 StandardFrameConstants::kContextOffset); | 220 StandardFrameConstants::kContextOffset); |
| 221 Address frame_marker = fp + StandardFrameConstants::kMarkerOffset; | 221 Address frame_marker = fp + StandardFrameConstants::kFunctionOffset; |
| 222 if (IsValidStackAddress(frame_marker)) { | 222 if (IsValidStackAddress(frame_marker)) { |
| 223 type = StackFrame::ComputeType(this, &state); | 223 type = StackFrame::ComputeType(this, &state); |
| 224 top_frame_type_ = type; | 224 top_frame_type_ = type; |
| 225 } else { | 225 } else { |
| 226 // Mark the frame as JAVA_SCRIPT if we cannot determine its type. | 226 // Mark the frame as JAVA_SCRIPT if we cannot determine its type. |
| 227 // The frame anyways will be skipped. | 227 // The frame anyways will be skipped. |
| 228 type = StackFrame::JAVA_SCRIPT; | 228 type = StackFrame::JAVA_SCRIPT; |
| 229 // Top frame is incomplete so we cannot reliably determine its type. | 229 // Top frame is incomplete so we cannot reliably determine its type. |
| 230 top_frame_type_ = StackFrame::NONE; | 230 top_frame_type_ = StackFrame::NONE; |
| 231 } | 231 } |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 401 ReturnAddressLocationResolver resolver) { | 401 ReturnAddressLocationResolver resolver) { |
| 402 DCHECK(return_address_location_resolver_ == NULL); | 402 DCHECK(return_address_location_resolver_ == NULL); |
| 403 return_address_location_resolver_ = resolver; | 403 return_address_location_resolver_ = resolver; |
| 404 } | 404 } |
| 405 | 405 |
| 406 | 406 |
| 407 StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator, | 407 StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator, |
| 408 State* state) { | 408 State* state) { |
| 409 DCHECK(state->fp != NULL); | 409 DCHECK(state->fp != NULL); |
| 410 | 410 |
| 411 Object* marker = Memory::Object_at( | |
| 412 state->fp + CommonFrameConstants::kContextOrFrameTypeOffset); | |
| 413 if (marker->IsSmi()) { | |
| 414 StackFrame::Type candidate = | |
| 415 static_cast<StackFrame::Type>(Smi::cast(marker)->value()); | |
| 416 switch (candidate) { | |
| 417 case ENTRY: | |
| 418 case ENTRY_CONSTRUCT: | |
| 419 case EXIT: | |
| 420 case STUB: | |
| 421 case STUB_FAILURE_TRAMPOLINE: | |
| 422 case INTERNAL: | |
| 423 case CONSTRUCT: | |
| 424 case ARGUMENTS_ADAPTOR: | |
| 425 return candidate; | |
| 426 case JAVA_SCRIPT: | |
| 427 case OPTIMIZED: | |
| 428 case INTERPRETED: | |
| 429 default: | |
| 430 // Unoptimized and optimized JavaScript frames, including interpreted | |
| 431 // frames, should never have a StackFrame::Type marker. If we find one, | |
| 432 // we're likely being called from the profiler in a bogus stack frame. | |
| 433 return NONE; | |
| 434 } | |
| 435 } | |
| 436 | |
| 437 Object* maybe_function = | |
| 438 Memory::Object_at(state->fp + StandardFrameConstants::kFunctionOffset); | |
| 411 if (!iterator->can_access_heap_objects_) { | 439 if (!iterator->can_access_heap_objects_) { |
| 412 // TODO(titzer): "can_access_heap_objects" is kind of bogus. It really | 440 // TODO(titzer): "can_access_heap_objects" is kind of bogus. It really |
| 413 // means that we are being called from the profiler, which can interrupt | 441 // means that we are being called from the profiler, which can interrupt |
| 414 // the VM with a signal at any arbitrary instruction, with essentially | 442 // the VM with a signal at any arbitrary instruction, with essentially |
| 415 // anything on the stack. So basically none of these checks are 100% | 443 // anything on the stack. So basically none of these checks are 100% |
| 416 // reliable. | 444 // reliable. |
| 417 #if defined(USE_SIMULATOR) | 445 #if defined(USE_SIMULATOR) |
| 418 MSAN_MEMORY_IS_INITIALIZED( | 446 MSAN_MEMORY_IS_INITIALIZED( |
| 419 state->fp + StandardFrameConstants::kContextOffset, kPointerSize); | 447 state->fp + StandardFrameConstants::kContextOffset, kPointerSize); |
| 420 MSAN_MEMORY_IS_INITIALIZED( | 448 MSAN_MEMORY_IS_INITIALIZED( |
| 421 state->fp + StandardFrameConstants::kMarkerOffset, kPointerSize); | 449 state->fp + StandardFrameConstants::kMarkerOffset, kPointerSize); |
| 422 #endif | 450 #endif |
| 423 if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) { | 451 if (maybe_function->IsSmi()) { |
| 424 // An adapter frame has a special SMI constant for the context and | 452 return NONE; |
| 425 // is not distinguished through the marker. | |
| 426 return ARGUMENTS_ADAPTOR; | |
| 427 } | |
| 428 Object* marker = | |
| 429 Memory::Object_at(state->fp + StandardFrameConstants::kMarkerOffset); | |
| 430 if (marker->IsSmi()) { | |
| 431 return static_cast<StackFrame::Type>(Smi::cast(marker)->value()); | |
| 432 } else { | 453 } else { |
| 433 return JAVA_SCRIPT; | 454 return JAVA_SCRIPT; |
| 434 } | 455 } |
| 435 } | 456 } |
| 436 | 457 |
| 437 // Look up the code object to figure out the type of the stack frame. | 458 // Look up the code object to figure out the type of the stack frame. |
| 438 Code* code_obj = GetContainingCode(iterator->isolate(), *(state->pc_address)); | 459 Code* code_obj = GetContainingCode(iterator->isolate(), *(state->pc_address)); |
| 439 | |
| 440 Object* marker = | |
| 441 Memory::Object_at(state->fp + StandardFrameConstants::kMarkerOffset); | |
| 442 if (code_obj != nullptr) { | 460 if (code_obj != nullptr) { |
| 443 switch (code_obj->kind()) { | 461 switch (code_obj->kind()) { |
| 444 case Code::FUNCTION: | 462 case Code::FUNCTION: |
| 445 return JAVA_SCRIPT; | 463 return JAVA_SCRIPT; |
| 446 case Code::OPTIMIZED_FUNCTION: | 464 case Code::OPTIMIZED_FUNCTION: |
| 447 return OPTIMIZED; | 465 return OPTIMIZED; |
| 448 case Code::WASM_FUNCTION: | 466 case Code::WASM_FUNCTION: |
| 449 return STUB; | 467 return STUB; |
| 450 case Code::BUILTIN: | 468 case Code::BUILTIN: |
| 451 if (!marker->IsSmi()) { | 469 DCHECK(!maybe_function->IsSmi()); |
| 452 if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) { | 470 DCHECK(code_obj->is_interpreter_entry_trampoline() || |
| 453 // An adapter frame has a special SMI constant for the context and | 471 code_obj->is_interpreter_enter_bytecode_dispatch()); |
| 454 // is not distinguished through the marker. | 472 return INTERPRETED; |
| 455 return ARGUMENTS_ADAPTOR; | |
| 456 } else { | |
| 457 // The interpreter entry trampoline has a non-SMI marker. | |
| 458 DCHECK(code_obj->is_interpreter_entry_trampoline() || | |
| 459 code_obj->is_interpreter_enter_bytecode_dispatch()); | |
| 460 return INTERPRETED; | |
| 461 } | |
| 462 } | |
| 463 break; // Marker encodes the frame type. | |
| 464 case Code::HANDLER: | |
| 465 if (!marker->IsSmi()) { | |
| 466 // Only hydrogen code stub handlers can have a non-SMI marker. | |
| 467 DCHECK(code_obj->is_hydrogen_stub()); | |
| 468 return OPTIMIZED; | |
| 469 } | |
| 470 break; // Marker encodes the frame type. | |
| 471 default: | 473 default: |
| 472 break; // Marker encodes the frame type. | 474 // All other types should have an explicit marker |
| 475 UNREACHABLE(); | |
| 476 break; | |
| 473 } | 477 } |
| 474 } | 478 } |
| 475 | 479 |
| 476 // Didn't find a code object, or the code kind wasn't specific enough. | 480 return NONE; |
| 477 // The marker should encode the frame type. | |
| 478 return static_cast<StackFrame::Type>(Smi::cast(marker)->value()); | |
| 479 } | 481 } |
| 480 | 482 |
| 481 | 483 |
| 482 #ifdef DEBUG | 484 #ifdef DEBUG |
| 483 bool StackFrame::can_access_heap_objects() const { | 485 bool StackFrame::can_access_heap_objects() const { |
| 484 return iterator_->can_access_heap_objects_; | 486 return iterator_->can_access_heap_objects_; |
| 485 } | 487 } |
| 486 #endif | 488 #endif |
| 487 | 489 |
| 488 | 490 |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 641 void StandardFrame::IterateCompiledFrame(ObjectVisitor* v) const { | 643 void StandardFrame::IterateCompiledFrame(ObjectVisitor* v) const { |
| 642 // Make sure that we're not doing "safe" stack frame iteration. We cannot | 644 // Make sure that we're not doing "safe" stack frame iteration. We cannot |
| 643 // possibly find pointers in optimized frames in that state. | 645 // possibly find pointers in optimized frames in that state. |
| 644 DCHECK(can_access_heap_objects()); | 646 DCHECK(can_access_heap_objects()); |
| 645 | 647 |
| 646 // Compute the safepoint information. | 648 // Compute the safepoint information. |
| 647 unsigned stack_slots = 0; | 649 unsigned stack_slots = 0; |
| 648 SafepointEntry safepoint_entry; | 650 SafepointEntry safepoint_entry; |
| 649 Code* code = StackFrame::GetSafepointData( | 651 Code* code = StackFrame::GetSafepointData( |
| 650 isolate(), pc(), &safepoint_entry, &stack_slots); | 652 isolate(), pc(), &safepoint_entry, &stack_slots); |
| 651 unsigned slot_space = | 653 unsigned slot_space = stack_slots * kPointerSize; |
| 652 stack_slots * kPointerSize - StandardFrameConstants::kFixedFrameSize; | |
| 653 | 654 |
| 654 // Visit the outgoing parameters. | 655 // Visit the outgoing parameters. |
|
Michael Starzinger
2016/02/23 10:57:33
nit: Comment is outdated.
danno
2016/03/07 09:33:38
Done.
| |
| 656 int frame_header_size = StandardFrameConstants::kFixedFrameSizeFromFp; | |
| 657 Object* marker = Memory::Object_at(fp() - kPointerSize); | |
| 658 if (marker->IsSmi()) { | |
| 659 StackFrame::Type candidate = | |
| 660 static_cast<StackFrame::Type>(Smi::cast(marker)->value()); | |
| 661 switch (candidate) { | |
| 662 case ENTRY: | |
| 663 case ENTRY_CONSTRUCT: | |
| 664 case EXIT: | |
| 665 case STUB_FAILURE_TRAMPOLINE: | |
| 666 case ARGUMENTS_ADAPTOR: | |
| 667 case STUB: | |
| 668 case INTERNAL: | |
| 669 case CONSTRUCT: | |
| 670 frame_header_size = TypedFrameConstants::kFixedFrameSizeFromFp; | |
| 671 break; | |
| 672 case JAVA_SCRIPT: | |
| 673 case OPTIMIZED: | |
| 674 case INTERPRETED: | |
| 675 // These frame types have a context, but they are actually stored | |
| 676 // in the place on the stack that one finds the frame type. | |
| 677 UNREACHABLE(); | |
| 678 break; | |
| 679 case NONE: | |
| 680 case NUMBER_OF_TYPES: | |
| 681 case MANUAL: | |
| 682 UNREACHABLE(); | |
| 683 break; | |
| 684 } | |
| 685 } | |
| 686 slot_space -= | |
| 687 (frame_header_size + StandardFrameConstants::kFixedFrameSizeAboveFp); | |
| 688 | |
| 689 Object** frame_header_base = &Memory::Object_at(fp() - frame_header_size); | |
| 690 Object** frame_header_limit = &Memory::Object_at(fp()); | |
| 655 Object** parameters_base = &Memory::Object_at(sp()); | 691 Object** parameters_base = &Memory::Object_at(sp()); |
| 656 Object** parameters_limit = &Memory::Object_at( | 692 Object** parameters_limit = frame_header_base - slot_space / kPointerSize; |
| 657 fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space); | |
| 658 | 693 |
| 659 // Visit the parameters that may be on top of the saved registers. | 694 // Visit the parameters that may be on top of the saved registers. |
| 660 if (safepoint_entry.argument_count() > 0) { | 695 if (safepoint_entry.argument_count() > 0) { |
| 661 v->VisitPointers(parameters_base, | 696 v->VisitPointers(parameters_base, |
| 662 parameters_base + safepoint_entry.argument_count()); | 697 parameters_base + safepoint_entry.argument_count()); |
| 663 parameters_base += safepoint_entry.argument_count(); | 698 parameters_base += safepoint_entry.argument_count(); |
| 664 } | 699 } |
| 665 | 700 |
| 666 // Skip saved double registers. | 701 // Skip saved double registers. |
| 667 if (safepoint_entry.has_doubles()) { | 702 if (safepoint_entry.has_doubles()) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 699 if ((safepoint_bits[byte_index] & (1U << bit_index)) != 0) { | 734 if ((safepoint_bits[byte_index] & (1U << bit_index)) != 0) { |
| 700 v->VisitPointer(parameters_limit + index); | 735 v->VisitPointer(parameters_limit + index); |
| 701 } | 736 } |
| 702 } | 737 } |
| 703 | 738 |
| 704 // Visit the return address in the callee and incoming arguments. | 739 // Visit the return address in the callee and incoming arguments. |
| 705 IteratePc(v, pc_address(), constant_pool_address(), code); | 740 IteratePc(v, pc_address(), constant_pool_address(), code); |
| 706 | 741 |
| 707 // Visit the context in stub frame and JavaScript frame. | 742 // Visit the context in stub frame and JavaScript frame. |
| 708 // Visit the function in JavaScript frame. | 743 // Visit the function in JavaScript frame. |
| 709 Object** fixed_base = &Memory::Object_at( | 744 v->VisitPointers(frame_header_base, frame_header_limit); |
| 710 fp() + StandardFrameConstants::kMarkerOffset); | |
| 711 Object** fixed_limit = &Memory::Object_at(fp()); | |
| 712 v->VisitPointers(fixed_base, fixed_limit); | |
| 713 } | 745 } |
| 714 | 746 |
| 715 | 747 |
| 716 void StubFrame::Iterate(ObjectVisitor* v) const { | 748 void StubFrame::Iterate(ObjectVisitor* v) const { |
| 717 IterateCompiledFrame(v); | 749 IterateCompiledFrame(v); |
| 718 } | 750 } |
| 719 | 751 |
| 720 | 752 |
| 721 Code* StubFrame::unchecked_code() const { | 753 Code* StubFrame::unchecked_code() const { |
| 722 return static_cast<Code*>(isolate()->FindCodeObject(pc())); | 754 return static_cast<Code*>(isolate()->FindCodeObject(pc())); |
| (...skipping 707 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1430 void InternalFrame::Iterate(ObjectVisitor* v) const { | 1462 void InternalFrame::Iterate(ObjectVisitor* v) const { |
| 1431 // Internal frames only have object pointers on the expression stack | 1463 // Internal frames only have object pointers on the expression stack |
| 1432 // as they never have any arguments. | 1464 // as they never have any arguments. |
| 1433 IterateExpressions(v); | 1465 IterateExpressions(v); |
| 1434 IteratePc(v, pc_address(), constant_pool_address(), LookupCode()); | 1466 IteratePc(v, pc_address(), constant_pool_address(), LookupCode()); |
| 1435 } | 1467 } |
| 1436 | 1468 |
| 1437 | 1469 |
| 1438 void StubFailureTrampolineFrame::Iterate(ObjectVisitor* v) const { | 1470 void StubFailureTrampolineFrame::Iterate(ObjectVisitor* v) const { |
| 1439 Object** base = &Memory::Object_at(sp()); | 1471 Object** base = &Memory::Object_at(sp()); |
| 1440 Object** limit = &Memory::Object_at(fp() + | 1472 Object** limit = &Memory::Object_at( |
| 1441 kFirstRegisterParameterFrameOffset); | 1473 fp() + StubFailureTrampolineFrameConstants::kFixedHeaderBottomOffset); |
| 1442 v->VisitPointers(base, limit); | 1474 v->VisitPointers(base, limit); |
| 1443 base = &Memory::Object_at(fp() + StandardFrameConstants::kMarkerOffset); | 1475 base = &Memory::Object_at(fp() + StandardFrameConstants::kFunctionOffset); |
| 1444 const int offset = StandardFrameConstants::kLastObjectOffset; | 1476 const int offset = StandardFrameConstants::kLastObjectOffset; |
| 1445 limit = &Memory::Object_at(fp() + offset) + 1; | 1477 limit = &Memory::Object_at(fp() + offset) + 1; |
| 1446 v->VisitPointers(base, limit); | 1478 v->VisitPointers(base, limit); |
| 1447 IteratePc(v, pc_address(), constant_pool_address(), LookupCode()); | 1479 IteratePc(v, pc_address(), constant_pool_address(), LookupCode()); |
| 1448 } | 1480 } |
| 1449 | 1481 |
| 1450 | 1482 |
| 1451 Address StubFailureTrampolineFrame::GetCallerStackPointer() const { | 1483 Address StubFailureTrampolineFrame::GetCallerStackPointer() const { |
| 1452 return fp() + StandardFrameConstants::kCallerSPOffset; | 1484 return fp() + StandardFrameConstants::kCallerSPOffset; |
| 1453 } | 1485 } |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1646 for (StackFrameIterator it(isolate); !it.done(); it.Advance()) { | 1678 for (StackFrameIterator it(isolate); !it.done(); it.Advance()) { |
| 1647 StackFrame* frame = AllocateFrameCopy(it.frame(), zone); | 1679 StackFrame* frame = AllocateFrameCopy(it.frame(), zone); |
| 1648 list.Add(frame, zone); | 1680 list.Add(frame, zone); |
| 1649 } | 1681 } |
| 1650 return list.ToVector(); | 1682 return list.ToVector(); |
| 1651 } | 1683 } |
| 1652 | 1684 |
| 1653 | 1685 |
| 1654 } // namespace internal | 1686 } // namespace internal |
| 1655 } // namespace v8 | 1687 } // namespace v8 |
| OLD | NEW |