| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "ast.h" |
| 31 #include "deoptimizer.h" |
| 30 #include "frames-inl.h" | 32 #include "frames-inl.h" |
| 33 #include "full-codegen.h" |
| 31 #include "mark-compact.h" | 34 #include "mark-compact.h" |
| 35 #include "safepoint-table.h" |
| 32 #include "scopeinfo.h" | 36 #include "scopeinfo.h" |
| 33 #include "string-stream.h" | 37 #include "string-stream.h" |
| 34 | 38 |
| 35 namespace v8 { | 39 namespace v8 { |
| 36 namespace internal { | 40 namespace internal { |
| 37 | 41 |
| 38 | 42 |
| 39 int SafeStackFrameIterator::active_count_ = 0; | 43 int SafeStackFrameIterator::active_count_ = 0; |
| 40 | 44 |
| 41 // Iterator that supports traversing the stack handlers of a | 45 // Iterator that supports traversing the stack handlers of a |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 thread_(Isolate::Current()->thread_local_top()), | 78 thread_(Isolate::Current()->thread_local_top()), |
| 75 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) { | 79 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) { |
| 76 Reset(); | 80 Reset(); |
| 77 } | 81 } |
| 78 StackFrameIterator::StackFrameIterator(ThreadLocalTop* t) | 82 StackFrameIterator::StackFrameIterator(ThreadLocalTop* t) |
| 79 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) | 83 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) |
| 80 frame_(NULL), handler_(NULL), thread_(t), | 84 frame_(NULL), handler_(NULL), thread_(t), |
| 81 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) { | 85 fp_(NULL), sp_(NULL), advance_(&StackFrameIterator::AdvanceWithHandler) { |
| 82 Reset(); | 86 Reset(); |
| 83 } | 87 } |
| 84 StackFrameIterator::StackFrameIterator(bool use_top, Address fp, Address sp) | 88 StackFrameIterator::StackFrameIterator(Isolate* isolate, |
| 89 bool use_top, Address fp, Address sp) |
| 85 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) | 90 : STACK_FRAME_TYPE_LIST(INITIALIZE_SINGLETON) |
| 86 frame_(NULL), handler_(NULL), | 91 frame_(NULL), handler_(NULL), |
| 87 thread_(use_top ? Isolate::Current()->thread_local_top() : NULL), | 92 thread_(use_top ? isolate->thread_local_top() : NULL), |
| 88 fp_(use_top ? NULL : fp), sp_(sp), | 93 fp_(use_top ? NULL : fp), sp_(sp), |
| 89 advance_(use_top ? &StackFrameIterator::AdvanceWithHandler : | 94 advance_(use_top ? &StackFrameIterator::AdvanceWithHandler : |
| 90 &StackFrameIterator::AdvanceWithoutHandler) { | 95 &StackFrameIterator::AdvanceWithoutHandler) { |
| 91 if (use_top || fp != NULL) { | 96 if (use_top || fp != NULL) { |
| 92 Reset(); | 97 Reset(); |
| 93 } | 98 } |
| 94 } | 99 } |
| 95 | 100 |
| 96 #undef INITIALIZE_SINGLETON | 101 #undef INITIALIZE_SINGLETON |
| 97 | 102 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 StackFrame::State state; | 215 StackFrame::State state; |
| 211 ExitFrame::FillState(fp, sp, &state); | 216 ExitFrame::FillState(fp, sp, &state); |
| 212 if (!validator_.IsValid(reinterpret_cast<Address>(state.pc_address))) { | 217 if (!validator_.IsValid(reinterpret_cast<Address>(state.pc_address))) { |
| 213 return false; | 218 return false; |
| 214 } | 219 } |
| 215 return *state.pc_address != NULL; | 220 return *state.pc_address != NULL; |
| 216 } | 221 } |
| 217 | 222 |
| 218 | 223 |
| 219 SafeStackFrameIterator::SafeStackFrameIterator( | 224 SafeStackFrameIterator::SafeStackFrameIterator( |
| 225 Isolate* isolate, |
| 220 Address fp, Address sp, Address low_bound, Address high_bound) : | 226 Address fp, Address sp, Address low_bound, Address high_bound) : |
| 221 maintainer_(), | 227 maintainer_(), |
| 222 stack_validator_(low_bound, high_bound), | 228 stack_validator_(low_bound, high_bound), |
| 223 is_valid_top_(IsValidTop(low_bound, high_bound)), | 229 is_valid_top_(IsValidTop(isolate, low_bound, high_bound)), |
| 224 is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)), | 230 is_valid_fp_(IsWithinBounds(low_bound, high_bound, fp)), |
| 225 is_working_iterator_(is_valid_top_ || is_valid_fp_), | 231 is_working_iterator_(is_valid_top_ || is_valid_fp_), |
| 226 iteration_done_(!is_working_iterator_), | 232 iteration_done_(!is_working_iterator_), |
| 227 iterator_(is_valid_top_, is_valid_fp_ ? fp : NULL, sp) { | 233 iterator_(isolate, is_valid_top_, is_valid_fp_ ? fp : NULL, sp) { |
| 228 } | 234 } |
| 229 | 235 |
| 230 | 236 |
| 231 bool SafeStackFrameIterator::IsValidTop(Address low_bound, Address high_bound) { | 237 bool SafeStackFrameIterator::IsValidTop(Isolate* isolate, |
| 232 ThreadLocalTop* top = Isolate::Current()->thread_local_top(); | 238 Address low_bound, Address high_bound) { |
| 239 ThreadLocalTop* top = isolate->thread_local_top(); |
| 233 Address fp = Isolate::c_entry_fp(top); | 240 Address fp = Isolate::c_entry_fp(top); |
| 234 ExitFrameValidator validator(low_bound, high_bound); | 241 ExitFrameValidator validator(low_bound, high_bound); |
| 235 if (!validator.IsValidFP(fp)) return false; | 242 if (!validator.IsValidFP(fp)) return false; |
| 236 return Isolate::handler(top) != NULL; | 243 return Isolate::handler(top) != NULL; |
| 237 } | 244 } |
| 238 | 245 |
| 239 | 246 |
| 240 void SafeStackFrameIterator::Advance() { | 247 void SafeStackFrameIterator::Advance() { |
| 241 ASSERT(is_working_iterator_); | 248 ASSERT(is_working_iterator_); |
| 242 ASSERT(!done()); | 249 ASSERT(!done()); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 iteration_done_ = false; | 309 iteration_done_ = false; |
| 303 } | 310 } |
| 304 } | 311 } |
| 305 | 312 |
| 306 | 313 |
| 307 // ------------------------------------------------------------------------- | 314 // ------------------------------------------------------------------------- |
| 308 | 315 |
| 309 | 316 |
| 310 #ifdef ENABLE_LOGGING_AND_PROFILING | 317 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 311 SafeStackTraceFrameIterator::SafeStackTraceFrameIterator( | 318 SafeStackTraceFrameIterator::SafeStackTraceFrameIterator( |
| 319 Isolate* isolate, |
| 312 Address fp, Address sp, Address low_bound, Address high_bound) : | 320 Address fp, Address sp, Address low_bound, Address high_bound) : |
| 313 SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) { | 321 SafeJavaScriptFrameIterator(isolate, fp, sp, low_bound, high_bound) { |
| 314 if (!done() && !frame()->is_java_script()) Advance(); | 322 if (!done() && !frame()->is_java_script()) Advance(); |
| 315 } | 323 } |
| 316 | 324 |
| 317 | 325 |
| 318 void SafeStackTraceFrameIterator::Advance() { | 326 void SafeStackTraceFrameIterator::Advance() { |
| 319 while (true) { | 327 while (true) { |
| 320 SafeJavaScriptFrameIterator::Advance(); | 328 SafeJavaScriptFrameIterator::Advance(); |
| 321 if (done()) return; | 329 if (done()) return; |
| 322 if (frame()->is_java_script()) return; | 330 if (frame()->is_java_script()) return; |
| 323 } | 331 } |
| 324 } | 332 } |
| 325 #endif | 333 #endif |
| 326 | 334 |
| 327 | 335 |
| 336 Code* StackFrame::GetSafepointData(Address pc, |
| 337 uint8_t** safepoint_entry, |
| 338 unsigned* stack_slots) { |
| 339 Isolate* isolate = Isolate::Current(); |
| 340 PcToCodeCache::PcToCodeCacheEntry* entry = |
| 341 isolate->pc_to_code_cache()->GetCacheEntry(pc); |
| 342 uint8_t* cached_safepoint_entry = entry->safepoint_entry; |
| 343 if (cached_safepoint_entry == NULL) { |
| 344 cached_safepoint_entry = entry->code->GetSafepointEntry(pc); |
| 345 ASSERT(cached_safepoint_entry != NULL); // No safepoint found. |
| 346 entry->safepoint_entry = cached_safepoint_entry; |
| 347 } else { |
| 348 ASSERT(cached_safepoint_entry == entry->code->GetSafepointEntry(pc)); |
| 349 } |
| 350 |
| 351 // Fill in the results and return the code. |
| 352 Code* code = entry->code; |
| 353 *safepoint_entry = cached_safepoint_entry; |
| 354 *stack_slots = code->stack_slots(); |
| 355 return code; |
| 356 } |
| 357 |
| 358 |
| 328 bool StackFrame::HasHandler() const { | 359 bool StackFrame::HasHandler() const { |
| 329 StackHandlerIterator it(this, top_handler()); | 360 StackHandlerIterator it(this, top_handler()); |
| 330 return !it.done(); | 361 return !it.done(); |
| 331 } | 362 } |
| 332 | 363 |
| 364 |
| 333 void StackFrame::IteratePc(ObjectVisitor* v, | 365 void StackFrame::IteratePc(ObjectVisitor* v, |
| 334 Address* pc_address, | 366 Address* pc_address, |
| 335 Code* holder) { | 367 Code* holder) { |
| 336 Address pc = *pc_address; | 368 Address pc = *pc_address; |
| 337 ASSERT(holder->contains(pc)); | 369 ASSERT(holder->contains(pc)); |
| 338 unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start()); | 370 unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start()); |
| 339 Object* code = holder; | 371 Object* code = holder; |
| 340 v->VisitPointer(&code); | 372 v->VisitPointer(&code); |
| 341 if (code != holder) { | 373 if (code != holder) { |
| 342 holder = reinterpret_cast<Code*>(code); | 374 holder = reinterpret_cast<Code*>(code); |
| 343 pc = holder->instruction_start() + pc_offset; | 375 pc = holder->instruction_start() + pc_offset; |
| 344 *pc_address = pc; | 376 *pc_address = pc; |
| 345 } | 377 } |
| 346 } | 378 } |
| 347 | 379 |
| 348 | 380 |
| 349 StackFrame::Type StackFrame::ComputeType(State* state) { | 381 StackFrame::Type StackFrame::ComputeType(State* state) { |
| 350 ASSERT(state->fp != NULL); | 382 ASSERT(state->fp != NULL); |
| 351 if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) { | 383 if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) { |
| 352 return ARGUMENTS_ADAPTOR; | 384 return ARGUMENTS_ADAPTOR; |
| 353 } | 385 } |
| 354 // The marker and function offsets overlap. If the marker isn't a | 386 // The marker and function offsets overlap. If the marker isn't a |
| 355 // smi then the frame is a JavaScript frame -- and the marker is | 387 // smi then the frame is a JavaScript frame -- and the marker is |
| 356 // really the function. | 388 // really the function. |
| 357 const int offset = StandardFrameConstants::kMarkerOffset; | 389 const int offset = StandardFrameConstants::kMarkerOffset; |
| 358 Object* marker = Memory::Object_at(state->fp + offset); | 390 Object* marker = Memory::Object_at(state->fp + offset); |
| 359 if (!marker->IsSmi()) return JAVA_SCRIPT; | 391 if (!marker->IsSmi()) { |
| 392 // If we're using a "safe" stack iterator, we treat optimized |
| 393 // frames as normal JavaScript frames to avoid having to look |
| 394 // into the heap to determine the state. This is safe as long |
| 395 // as nobody tries to GC... |
| 396 if (SafeStackFrameIterator::is_active()) return JAVA_SCRIPT; |
| 397 Code::Kind kind = GetContainingCode(Isolate::Current(), |
| 398 *(state->pc_address))->kind(); |
| 399 ASSERT(kind == Code::FUNCTION || kind == Code::OPTIMIZED_FUNCTION); |
| 400 return (kind == Code::OPTIMIZED_FUNCTION) ? OPTIMIZED : JAVA_SCRIPT; |
| 401 } |
| 360 return static_cast<StackFrame::Type>(Smi::cast(marker)->value()); | 402 return static_cast<StackFrame::Type>(Smi::cast(marker)->value()); |
| 361 } | 403 } |
| 362 | 404 |
| 363 | 405 |
| 364 | 406 |
| 365 StackFrame::Type StackFrame::GetCallerState(State* state) const { | 407 StackFrame::Type StackFrame::GetCallerState(State* state) const { |
| 366 ComputeCallerState(state); | 408 ComputeCallerState(state); |
| 367 return ComputeType(state); | 409 return ComputeType(state); |
| 368 } | 410 } |
| 369 | 411 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 482 | 524 |
| 483 bool StandardFrame::IsExpressionInsideHandler(int n) const { | 525 bool StandardFrame::IsExpressionInsideHandler(int n) const { |
| 484 Address address = GetExpressionAddress(n); | 526 Address address = GetExpressionAddress(n); |
| 485 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) { | 527 for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) { |
| 486 if (it.handler()->includes(address)) return true; | 528 if (it.handler()->includes(address)) return true; |
| 487 } | 529 } |
| 488 return false; | 530 return false; |
| 489 } | 531 } |
| 490 | 532 |
| 491 | 533 |
| 534 void OptimizedFrame::Iterate(ObjectVisitor* v) const { |
| 535 #ifdef DEBUG |
| 536 // Make sure that optimized frames do not contain any stack handlers. |
| 537 StackHandlerIterator it(this, top_handler()); |
| 538 ASSERT(it.done()); |
| 539 #endif |
| 540 |
| 541 // Make sure that we're not doing "safe" stack frame iteration. We cannot |
| 542 // possibly find pointers in optimized frames in that state. |
| 543 ASSERT(!SafeStackFrameIterator::is_active()); |
| 544 |
| 545 // Compute the safepoint information. |
| 546 unsigned stack_slots = 0; |
| 547 uint8_t* safepoint_entry = NULL; |
| 548 Code* code = StackFrame::GetSafepointData( |
| 549 pc(), &safepoint_entry, &stack_slots); |
| 550 unsigned slot_space = stack_slots * kPointerSize; |
| 551 |
| 552 // Visit the outgoing parameters. This is usually dealt with by the |
| 553 // callee, but while GC'ing we artificially lower the number of |
| 554 // arguments to zero and let the caller deal with it. |
| 555 Object** parameters_base = &Memory::Object_at(sp()); |
| 556 Object** parameters_limit = &Memory::Object_at( |
| 557 fp() + JavaScriptFrameConstants::kFunctionOffset - slot_space); |
| 558 |
| 559 // Visit the registers that contain pointers if any. |
| 560 if (SafepointTable::HasRegisters(safepoint_entry)) { |
| 561 for (int i = kNumSafepointRegisters - 1; i >=0; i--) { |
| 562 if (SafepointTable::HasRegisterAt(safepoint_entry, i)) { |
| 563 int reg_stack_index = MacroAssembler::SafepointRegisterStackIndex(i); |
| 564 v->VisitPointer(parameters_base + reg_stack_index); |
| 565 } |
| 566 } |
| 567 // Skip the words containing the register values. |
| 568 parameters_base += kNumSafepointRegisters; |
| 569 } |
| 570 |
| 571 // We're done dealing with the register bits. |
| 572 safepoint_entry += kNumSafepointRegisters >> kBitsPerByteLog2; |
| 573 |
| 574 // Visit the rest of the parameters. |
| 575 v->VisitPointers(parameters_base, parameters_limit); |
| 576 |
| 577 // Visit pointer spill slots and locals. |
| 578 for (unsigned index = 0; index < stack_slots; index++) { |
| 579 int byte_index = index >> kBitsPerByteLog2; |
| 580 int bit_index = index & (kBitsPerByte - 1); |
| 581 if ((safepoint_entry[byte_index] & (1U << bit_index)) != 0) { |
| 582 v->VisitPointer(parameters_limit + index); |
| 583 } |
| 584 } |
| 585 |
| 586 // Visit the context and the function. |
| 587 Object** fixed_base = &Memory::Object_at( |
| 588 fp() + JavaScriptFrameConstants::kFunctionOffset); |
| 589 Object** fixed_limit = &Memory::Object_at(fp()); |
| 590 v->VisitPointers(fixed_base, fixed_limit); |
| 591 |
| 592 // Visit the return address in the callee and incoming arguments. |
| 593 IteratePc(v, pc_address(), code); |
| 594 IterateArguments(v); |
| 595 } |
| 596 |
| 597 |
| 492 Object* JavaScriptFrame::GetParameter(int index) const { | 598 Object* JavaScriptFrame::GetParameter(int index) const { |
| 493 ASSERT(index >= 0 && index < ComputeParametersCount()); | 599 ASSERT(index >= 0 && index < ComputeParametersCount()); |
| 494 const int offset = JavaScriptFrameConstants::kParam0Offset; | 600 const int offset = JavaScriptFrameConstants::kParam0Offset; |
| 495 return Memory::Object_at(caller_sp() + offset - (index * kPointerSize)); | 601 return Memory::Object_at(caller_sp() + offset - (index * kPointerSize)); |
| 496 } | 602 } |
| 497 | 603 |
| 498 | 604 |
| 499 int JavaScriptFrame::ComputeParametersCount() const { | 605 int JavaScriptFrame::ComputeParametersCount() const { |
| 500 Address base = caller_sp() + JavaScriptFrameConstants::kReceiverOffset; | 606 Address base = caller_sp() + JavaScriptFrameConstants::kReceiverOffset; |
| 501 Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset; | 607 Address limit = fp() + JavaScriptFrameConstants::kSavedRegistersOffset; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 519 } | 625 } |
| 520 | 626 |
| 521 | 627 |
| 522 int JavaScriptFrame::GetProvidedParametersCount() const { | 628 int JavaScriptFrame::GetProvidedParametersCount() const { |
| 523 return ComputeParametersCount(); | 629 return ComputeParametersCount(); |
| 524 } | 630 } |
| 525 | 631 |
| 526 | 632 |
| 527 Address JavaScriptFrame::GetCallerStackPointer() const { | 633 Address JavaScriptFrame::GetCallerStackPointer() const { |
| 528 int arguments; | 634 int arguments; |
| 529 if (HEAP->gc_state() != Heap::NOT_IN_GC || | 635 if (SafeStackFrameIterator::is_active() || |
| 530 SafeStackFrameIterator::is_active()) { | 636 HEAP->gc_state() != Heap::NOT_IN_GC) { |
| 531 // If the we are currently iterating the safe stack the | 637 // If the we are currently iterating the safe stack the |
| 532 // arguments for frames are traversed as if they were | 638 // arguments for frames are traversed as if they were |
| 533 // expression stack elements of the calling frame. The reason for | 639 // expression stack elements of the calling frame. The reason for |
| 534 // this rather strange decision is that we cannot access the | 640 // this rather strange decision is that we cannot access the |
| 535 // function during mark-compact GCs when objects may have been marked. | 641 // function during mark-compact GCs when objects may have been marked. |
| 536 // In fact accessing heap objects (like function->shared() below) | 642 // In fact accessing heap objects (like function->shared() below) |
| 537 // at all during GC is problematic. | 643 // at all during GC is problematic. |
| 538 arguments = 0; | 644 arguments = 0; |
| 539 } else { | 645 } else { |
| 540 // Compute the number of arguments by getting the number of formal | 646 // Compute the number of arguments by getting the number of formal |
| 541 // parameters of the function. We must remember to take the | 647 // parameters of the function. We must remember to take the |
| 542 // receiver into account (+1). | 648 // receiver into account (+1). |
| 543 JSFunction* function = JSFunction::cast(this->function()); | 649 JSFunction* function = JSFunction::cast(this->function()); |
| 544 arguments = function->shared()->formal_parameter_count() + 1; | 650 arguments = function->shared()->formal_parameter_count() + 1; |
| 545 } | 651 } |
| 546 const int offset = StandardFrameConstants::kCallerSPOffset; | 652 const int offset = StandardFrameConstants::kCallerSPOffset; |
| 547 return fp() + offset + (arguments * kPointerSize); | 653 return fp() + offset + (arguments * kPointerSize); |
| 548 } | 654 } |
| 549 | 655 |
| 550 | 656 |
| 657 void JavaScriptFrame::GetFunctions(List<JSFunction*>* functions) { |
| 658 ASSERT(functions->length() == 0); |
| 659 functions->Add(JSFunction::cast(function())); |
| 660 } |
| 661 |
| 662 |
| 663 void JavaScriptFrame::Summarize(List<FrameSummary>* functions) { |
| 664 ASSERT(functions->length() == 0); |
| 665 Code* code_pointer = LookupCode(Isolate::Current()); |
| 666 int offset = pc() - code_pointer->address(); |
| 667 FrameSummary summary(receiver(), |
| 668 JSFunction::cast(function()), |
| 669 code_pointer, |
| 670 offset, |
| 671 IsConstructor()); |
| 672 functions->Add(summary); |
| 673 } |
| 674 |
| 675 |
| 676 void FrameSummary::Print() { |
| 677 PrintF("receiver: "); |
| 678 receiver_->ShortPrint(); |
| 679 PrintF("\nfunction: "); |
| 680 function_->shared()->DebugName()->ShortPrint(); |
| 681 PrintF("\ncode: "); |
| 682 code_->ShortPrint(); |
| 683 if (code_->kind() == Code::FUNCTION) PrintF(" NON-OPT"); |
| 684 if (code_->kind() == Code::OPTIMIZED_FUNCTION) PrintF(" OPT"); |
| 685 PrintF("\npc: %d\n", offset_); |
| 686 } |
| 687 |
| 688 |
| 689 void OptimizedFrame::Summarize(List<FrameSummary>* frames) { |
| 690 ASSERT(frames->length() == 0); |
| 691 ASSERT(is_optimized()); |
| 692 |
| 693 int deopt_index = AstNode::kNoNumber; |
| 694 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index); |
| 695 |
| 696 // BUG(3243555): Since we don't have a lazy-deopt registered at |
| 697 // throw-statements, we can't use the translation at the call-site of |
| 698 // throw. An entry with no deoptimization index indicates a call-site |
| 699 // without a lazy-deopt. As a consequence we are not allowed to inline |
| 700 // functions containing throw. |
| 701 if (deopt_index == Safepoint::kNoDeoptimizationIndex) { |
| 702 JavaScriptFrame::Summarize(frames); |
| 703 return; |
| 704 } |
| 705 |
| 706 TranslationIterator it(data->TranslationByteArray(), |
| 707 data->TranslationIndex(deopt_index)->value()); |
| 708 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next()); |
| 709 ASSERT(opcode == Translation::BEGIN); |
| 710 int frame_count = it.Next(); |
| 711 |
| 712 // We create the summary in reverse order because the frames |
| 713 // in the deoptimization translation are ordered bottom-to-top. |
| 714 int i = frame_count; |
| 715 while (i > 0) { |
| 716 opcode = static_cast<Translation::Opcode>(it.Next()); |
| 717 if (opcode == Translation::FRAME) { |
| 718 // We don't inline constructor calls, so only the first, outermost |
| 719 // frame can be a constructor frame in case of inlining. |
| 720 bool is_constructor = (i == frame_count) && IsConstructor(); |
| 721 |
| 722 i--; |
| 723 int ast_id = it.Next(); |
| 724 int function_id = it.Next(); |
| 725 it.Next(); // Skip height. |
| 726 JSFunction* function = |
| 727 JSFunction::cast(data->LiteralArray()->get(function_id)); |
| 728 |
| 729 // The translation commands are ordered and the receiver is always |
| 730 // at the first position. Since we are always at a call when we need |
| 731 // to construct a stack trace, the receiver is always in a stack slot. |
| 732 opcode = static_cast<Translation::Opcode>(it.Next()); |
| 733 ASSERT(opcode == Translation::STACK_SLOT); |
| 734 int input_slot_index = it.Next(); |
| 735 |
| 736 // Get the correct receiver in the optimized frame. |
| 737 Object* receiver = NULL; |
| 738 // Positive index means the value is spilled to the locals area. Negative |
| 739 // means it is stored in the incoming parameter area. |
| 740 if (input_slot_index >= 0) { |
| 741 receiver = GetExpression(input_slot_index); |
| 742 } else { |
| 743 // Index -1 overlaps with last parameter, -n with the first parameter, |
| 744 // (-n - 1) with the receiver with n being the number of parameters |
| 745 // of the outermost, optimized frame. |
| 746 int parameter_count = ComputeParametersCount(); |
| 747 int parameter_index = input_slot_index + parameter_count; |
| 748 receiver = (parameter_index == -1) |
| 749 ? this->receiver() |
| 750 : this->GetParameter(parameter_index); |
| 751 } |
| 752 |
| 753 Code* code = function->shared()->code(); |
| 754 DeoptimizationOutputData* output_data = |
| 755 DeoptimizationOutputData::cast(code->deoptimization_data()); |
| 756 unsigned entry = Deoptimizer::GetOutputInfo(output_data, |
| 757 ast_id, |
| 758 function->shared()); |
| 759 unsigned pc_offset = |
| 760 FullCodeGenerator::PcField::decode(entry) + Code::kHeaderSize; |
| 761 ASSERT(pc_offset > 0); |
| 762 |
| 763 FrameSummary summary(receiver, function, code, pc_offset, is_constructor); |
| 764 frames->Add(summary); |
| 765 } else { |
| 766 // Skip over operands to advance to the next opcode. |
| 767 it.Skip(Translation::NumberOfOperandsFor(opcode)); |
| 768 } |
| 769 } |
| 770 } |
| 771 |
| 772 |
| 773 DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData( |
| 774 int* deopt_index) { |
| 775 ASSERT(is_optimized()); |
| 776 |
| 777 JSFunction* opt_function = JSFunction::cast(function()); |
| 778 Code* code = opt_function->code(); |
| 779 |
| 780 // The code object may have been replaced by lazy deoptimization. Fall |
| 781 // back to a slow search in this case to find the original optimized |
| 782 // code object. |
| 783 if (!code->contains(pc())) { |
| 784 code = Isolate::Current()->pc_to_code_cache()->GcSafeFindCodeForPc(pc()); |
| 785 } |
| 786 ASSERT(code != NULL); |
| 787 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION); |
| 788 |
| 789 SafepointTable table(code); |
| 790 unsigned pc_offset = pc() - code->instruction_start(); |
| 791 for (unsigned i = 0; i < table.length(); i++) { |
| 792 if (table.GetPcOffset(i) == pc_offset) { |
| 793 *deopt_index = table.GetDeoptimizationIndex(i); |
| 794 break; |
| 795 } |
| 796 } |
| 797 ASSERT(*deopt_index != AstNode::kNoNumber); |
| 798 |
| 799 return DeoptimizationInputData::cast(code->deoptimization_data()); |
| 800 } |
| 801 |
| 802 |
| 803 void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) { |
| 804 ASSERT(functions->length() == 0); |
| 805 ASSERT(is_optimized()); |
| 806 |
| 807 int deopt_index = AstNode::kNoNumber; |
| 808 DeoptimizationInputData* data = GetDeoptimizationData(&deopt_index); |
| 809 |
| 810 TranslationIterator it(data->TranslationByteArray(), |
| 811 data->TranslationIndex(deopt_index)->value()); |
| 812 Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next()); |
| 813 ASSERT(opcode == Translation::BEGIN); |
| 814 int frame_count = it.Next(); |
| 815 |
| 816 // We insert the frames in reverse order because the frames |
| 817 // in the deoptimization translation are ordered bottom-to-top. |
| 818 while (frame_count > 0) { |
| 819 opcode = static_cast<Translation::Opcode>(it.Next()); |
| 820 if (opcode == Translation::FRAME) { |
| 821 frame_count--; |
| 822 it.Next(); // Skip ast id. |
| 823 int function_id = it.Next(); |
| 824 it.Next(); // Skip height. |
| 825 JSFunction* function = |
| 826 JSFunction::cast(data->LiteralArray()->get(function_id)); |
| 827 functions->Add(function); |
| 828 } else { |
| 829 // Skip over operands to advance to the next opcode. |
| 830 it.Skip(Translation::NumberOfOperandsFor(opcode)); |
| 831 } |
| 832 } |
| 833 } |
| 834 |
| 835 |
| 551 Address ArgumentsAdaptorFrame::GetCallerStackPointer() const { | 836 Address ArgumentsAdaptorFrame::GetCallerStackPointer() const { |
| 552 const int arguments = Smi::cast(GetExpression(0))->value(); | 837 const int arguments = Smi::cast(GetExpression(0))->value(); |
| 553 const int offset = StandardFrameConstants::kCallerSPOffset; | 838 const int offset = StandardFrameConstants::kCallerSPOffset; |
| 554 return fp() + offset + (arguments + 1) * kPointerSize; | 839 return fp() + offset + (arguments + 1) * kPointerSize; |
| 555 } | 840 } |
| 556 | 841 |
| 557 | 842 |
| 558 Address InternalFrame::GetCallerStackPointer() const { | 843 Address InternalFrame::GetCallerStackPointer() const { |
| 559 // Internal frames have no arguments. The stack pointer of the | 844 // Internal frames have no arguments. The stack pointer of the |
| 560 // caller is at a fixed offset from the frame pointer. | 845 // caller is at a fixed offset from the frame pointer. |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 784 // Traverse the pointers in the handler itself. | 1069 // Traverse the pointers in the handler itself. |
| 785 handler->Iterate(v, LookupCode(Isolate::Current())); | 1070 handler->Iterate(v, LookupCode(Isolate::Current())); |
| 786 } | 1071 } |
| 787 v->VisitPointers(base, limit); | 1072 v->VisitPointers(base, limit); |
| 788 } | 1073 } |
| 789 | 1074 |
| 790 | 1075 |
| 791 void JavaScriptFrame::Iterate(ObjectVisitor* v) const { | 1076 void JavaScriptFrame::Iterate(ObjectVisitor* v) const { |
| 792 IterateExpressions(v); | 1077 IterateExpressions(v); |
| 793 IteratePc(v, pc_address(), LookupCode(Isolate::Current())); | 1078 IteratePc(v, pc_address(), LookupCode(Isolate::Current())); |
| 1079 IterateArguments(v); |
| 1080 } |
| 794 | 1081 |
| 1082 |
| 1083 void JavaScriptFrame::IterateArguments(ObjectVisitor* v) const { |
| 795 // Traverse callee-saved registers, receiver, and parameters. | 1084 // Traverse callee-saved registers, receiver, and parameters. |
| 796 const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset; | 1085 const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset; |
| 797 const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset; | 1086 const int kLimitOffset = JavaScriptFrameConstants::kReceiverOffset; |
| 798 Object** base = &Memory::Object_at(fp() + kBaseOffset); | 1087 Object** base = &Memory::Object_at(fp() + kBaseOffset); |
| 799 Object** limit = &Memory::Object_at(caller_sp() + kLimitOffset) + 1; | 1088 Object** limit = &Memory::Object_at(caller_sp() + kLimitOffset) + 1; |
| 800 v->VisitPointers(base, limit); | 1089 v->VisitPointers(base, limit); |
| 801 } | 1090 } |
| 802 | 1091 |
| 803 | 1092 |
| 804 void InternalFrame::Iterate(ObjectVisitor* v) const { | 1093 void InternalFrame::Iterate(ObjectVisitor* v) const { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 847 HeapObject* previous = NULL; | 1136 HeapObject* previous = NULL; |
| 848 while (true) { | 1137 while (true) { |
| 849 HeapObject* next = iterator.next(); | 1138 HeapObject* next = iterator.next(); |
| 850 if (next == NULL || next->address() >= pc) { | 1139 if (next == NULL || next->address() >= pc) { |
| 851 return GcSafeCastToCode(previous, pc); | 1140 return GcSafeCastToCode(previous, pc); |
| 852 } | 1141 } |
| 853 previous = next; | 1142 previous = next; |
| 854 } | 1143 } |
| 855 } | 1144 } |
| 856 | 1145 |
| 1146 |
| 857 PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) { | 1147 PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) { |
| 858 COUNTERS->pc_to_code()->Increment(); | 1148 COUNTERS->pc_to_code()->Increment(); |
| 859 ASSERT(IsPowerOf2(kPcToCodeCacheSize)); | 1149 ASSERT(IsPowerOf2(kPcToCodeCacheSize)); |
| 860 uint32_t hash = ComputeIntegerHash( | 1150 uint32_t hash = ComputeIntegerHash( |
| 861 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc))); | 1151 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc))); |
| 862 uint32_t index = hash & (kPcToCodeCacheSize - 1); | 1152 uint32_t index = hash & (kPcToCodeCacheSize - 1); |
| 863 PcToCodeCacheEntry* entry = cache(index); | 1153 PcToCodeCacheEntry* entry = cache(index); |
| 864 if (entry->pc == pc) { | 1154 if (entry->pc == pc) { |
| 865 COUNTERS->pc_to_code_cached()->Increment(); | 1155 COUNTERS->pc_to_code_cached()->Increment(); |
| 866 ASSERT(entry->code == GcSafeFindCodeForPc(pc)); | 1156 ASSERT(entry->code == GcSafeFindCodeForPc(pc)); |
| 867 } else { | 1157 } else { |
| 868 // Because this code may be interrupted by a profiling signal that | 1158 // Because this code may be interrupted by a profiling signal that |
| 869 // also queries the cache, we cannot update pc before the code has | 1159 // also queries the cache, we cannot update pc before the code has |
| 870 // been set. Otherwise, we risk trying to use a cache entry before | 1160 // been set. Otherwise, we risk trying to use a cache entry before |
| 871 // the code has been computed. | 1161 // the code has been computed. |
| 872 entry->code = GcSafeFindCodeForPc(pc); | 1162 entry->code = GcSafeFindCodeForPc(pc); |
| 1163 entry->safepoint_entry = NULL; |
| 873 entry->pc = pc; | 1164 entry->pc = pc; |
| 874 } | 1165 } |
| 875 return entry; | 1166 return entry; |
| 876 } | 1167 } |
| 877 | 1168 |
| 878 | 1169 |
| 879 // ------------------------------------------------------------------------- | 1170 // ------------------------------------------------------------------------- |
| 880 | 1171 |
| 881 int NumRegs(RegList reglist) { | 1172 int NumRegs(RegList reglist) { |
| 882 int n = 0; | 1173 int n = 0; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 940 ZoneList<StackFrame*> list(10); | 1231 ZoneList<StackFrame*> list(10); |
| 941 for (StackFrameIterator it; !it.done(); it.Advance()) { | 1232 for (StackFrameIterator it; !it.done(); it.Advance()) { |
| 942 StackFrame* frame = AllocateFrameCopy(it.frame()); | 1233 StackFrame* frame = AllocateFrameCopy(it.frame()); |
| 943 list.Add(frame); | 1234 list.Add(frame); |
| 944 } | 1235 } |
| 945 return list.ToVector(); | 1236 return list.ToVector(); |
| 946 } | 1237 } |
| 947 | 1238 |
| 948 | 1239 |
| 949 } } // namespace v8::internal | 1240 } } // namespace v8::internal |
| OLD | NEW |