| Index: src/frames.cc
|
| ===================================================================
|
| --- src/frames.cc (revision 5368)
|
| +++ src/frames.cc (working copy)
|
| @@ -36,6 +36,11 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| +PcToCodeCache::PcToCodeCacheEntry
|
| + PcToCodeCache::cache_[PcToCodeCache::kPcToCodeCacheSize];
|
| +
|
| +int SafeStackFrameIterator::active_count_ = 0;
|
| +
|
| // Iterator that supports traversing the stack handlers of a
|
| // particular frame. Needs to know the top of the handler chain.
|
| class StackHandlerIterator BASE_EMBEDDED {
|
| @@ -88,7 +93,6 @@
|
| if (use_top || fp != NULL) {
|
| Reset();
|
| }
|
| - JavaScriptFrame_.DisableHeapAccess();
|
| }
|
|
|
| #undef INITIALIZE_SINGLETON
|
| @@ -201,7 +205,7 @@
|
|
|
| SafeStackFrameIterator::SafeStackFrameIterator(
|
| Address fp, Address sp, Address low_bound, Address high_bound) :
|
| - low_bound_(low_bound), high_bound_(high_bound),
|
| + maintainer_(), low_bound_(low_bound), high_bound_(high_bound),
|
| is_valid_top_(
|
| IsWithinBounds(low_bound, high_bound,
|
| Top::c_entry_fp(Top::GetCurrentThread())) &&
|
| @@ -302,70 +306,43 @@
|
| #endif
|
|
|
|
|
| -// -------------------------------------------------------------------------
|
| -
|
| -
|
| -void StackHandler::Cook(Code* code) {
|
| - ASSERT(code->contains(pc()));
|
| - set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
|
| -}
|
| -
|
| -
|
| -void StackHandler::Uncook(Code* code) {
|
| - set_pc(code->instruction_start() + OffsetFrom(pc()));
|
| - ASSERT(code->contains(pc()));
|
| -}
|
| -
|
| -
|
| -// -------------------------------------------------------------------------
|
| -
|
| -
|
| bool StackFrame::HasHandler() const {
|
| StackHandlerIterator it(this, top_handler());
|
| return !it.done();
|
| }
|
|
|
| -
|
| -void StackFrame::CookFramesForThread(ThreadLocalTop* thread) {
|
| - ASSERT(!thread->stack_is_cooked());
|
| - for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
|
| - it.frame()->Cook();
|
| +void StackFrame::IteratePc(ObjectVisitor* v,
|
| + Address* pc_address,
|
| + Code* holder) {
|
| + Address pc = *pc_address;
|
| + ASSERT(holder->contains(pc));
|
| + unsigned pc_offset = pc - holder->instruction_start();
|
| + Object* code = holder;
|
| + v->VisitPointer(&code);
|
| + if (code != holder) {
|
| + holder = reinterpret_cast<Code*>(code);
|
| + pc = holder->instruction_start() + pc_offset;
|
| + *pc_address = pc;
|
| }
|
| - thread->set_stack_is_cooked(true);
|
| }
|
|
|
|
|
| -void StackFrame::UncookFramesForThread(ThreadLocalTop* thread) {
|
| - ASSERT(thread->stack_is_cooked());
|
| - for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
|
| - it.frame()->Uncook();
|
| +StackFrame::Type StackFrame::ComputeType(State* state) {
|
| + ASSERT(state->fp != NULL);
|
| + if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
|
| + return ARGUMENTS_ADAPTOR;
|
| }
|
| - thread->set_stack_is_cooked(false);
|
| + // The marker and function offsets overlap. If the marker isn't a
|
| + // smi then the frame is a JavaScript frame -- and the marker is
|
| + // really the function.
|
| + const int offset = StandardFrameConstants::kMarkerOffset;
|
| + Object* marker = Memory::Object_at(state->fp + offset);
|
| + if (!marker->IsSmi()) return JAVA_SCRIPT;
|
| + return static_cast<StackFrame::Type>(Smi::cast(marker)->value());
|
| }
|
|
|
|
|
| -void StackFrame::Cook() {
|
| - Code* code = this->code();
|
| - ASSERT(code->IsCode());
|
| - for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
|
| - it.handler()->Cook(code);
|
| - }
|
| - ASSERT(code->contains(pc()));
|
| - set_pc(AddressFrom<Address>(pc() - code->instruction_start()));
|
| -}
|
|
|
| -
|
| -void StackFrame::Uncook() {
|
| - Code* code = this->code();
|
| - ASSERT(code->IsCode());
|
| - for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
|
| - it.handler()->Uncook(code);
|
| - }
|
| - set_pc(code->instruction_start() + OffsetFrom(pc()));
|
| - ASSERT(code->contains(pc()));
|
| -}
|
| -
|
| -
|
| StackFrame::Type StackFrame::GetCallerState(State* state) const {
|
| ComputeCallerState(state);
|
| return ComputeType(state);
|
| @@ -425,6 +402,14 @@
|
| }
|
|
|
|
|
| +void ExitFrame::Iterate(ObjectVisitor* v) const {
|
| + // The arguments are traversed as part of the expression stack of
|
| + // the calling frame.
|
| + IteratePc(v, pc_address(), code());
|
| + v->VisitPointer(&code_slot());
|
| +}
|
| +
|
| +
|
| Address ExitFrame::GetCallerStackPointer() const {
|
| return fp() + ExitFrameConstants::kCallerSPDisplacement;
|
| }
|
| @@ -499,6 +484,49 @@
|
| }
|
|
|
|
|
| +int JavaScriptFrame::GetProvidedParametersCount() const {
|
| + return ComputeParametersCount();
|
| +}
|
| +
|
| +
|
| +Address JavaScriptFrame::GetCallerStackPointer() const {
|
| + int arguments;
|
| + if (Heap::gc_state() != Heap::NOT_IN_GC ||
|
| + SafeStackFrameIterator::is_active()) {
|
| + // If the we are currently iterating the safe stack the
|
| + // arguments for frames are traversed as if they were
|
| + // expression stack elements of the calling frame. The reason for
|
| + // this rather strange decision is that we cannot access the
|
| + // function during mark-compact GCs when objects may have been marked.
|
| + // In fact accessing heap objects (like function->shared() below)
|
| + // at all during GC is problematic.
|
| + arguments = 0;
|
| + } else {
|
| + // Compute the number of arguments by getting the number of formal
|
| + // parameters of the function. We must remember to take the
|
| + // receiver into account (+1).
|
| + JSFunction* function = JSFunction::cast(this->function());
|
| + arguments = function->shared()->formal_parameter_count() + 1;
|
| + }
|
| + const int offset = StandardFrameConstants::kCallerSPOffset;
|
| + return fp() + offset + (arguments * kPointerSize);
|
| +}
|
| +
|
| +
|
| +Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
|
| + const int arguments = Smi::cast(GetExpression(0))->value();
|
| + const int offset = StandardFrameConstants::kCallerSPOffset;
|
| + return fp() + offset + (arguments + 1) * kPointerSize;
|
| +}
|
| +
|
| +
|
| +Address InternalFrame::GetCallerStackPointer() const {
|
| + // Internal frames have no arguments. The stack pointer of the
|
| + // caller is at a fixed offset from the frame pointer.
|
| + return fp() + StandardFrameConstants::kCallerSPOffset;
|
| +}
|
| +
|
| +
|
| Code* ArgumentsAdaptorFrame::unchecked_code() const {
|
| return Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline);
|
| }
|
| @@ -694,13 +722,14 @@
|
| ASSERT(!it.done());
|
| StackHandler* handler = it.handler();
|
| ASSERT(handler->is_entry());
|
| - handler->Iterate(v);
|
| - // Make sure that there's the entry frame does not contain more than
|
| - // one stack handler.
|
| + handler->Iterate(v, code());
|
| #ifdef DEBUG
|
| + // Make sure that the entry frame does not contain more than one
|
| + // stack handler.
|
| it.Advance();
|
| ASSERT(it.done());
|
| #endif
|
| + IteratePc(v, pc_address(), code());
|
| }
|
|
|
|
|
| @@ -717,7 +746,7 @@
|
| v->VisitPointers(base, reinterpret_cast<Object**>(address));
|
| base = reinterpret_cast<Object**>(address + StackHandlerConstants::kSize);
|
| // Traverse the pointers in the handler itself.
|
| - handler->Iterate(v);
|
| + handler->Iterate(v, code());
|
| }
|
| v->VisitPointers(base, limit);
|
| }
|
| @@ -725,6 +754,7 @@
|
|
|
| void JavaScriptFrame::Iterate(ObjectVisitor* v) const {
|
| IterateExpressions(v);
|
| + IteratePc(v, pc_address(), code());
|
|
|
| // Traverse callee-saved registers, receiver, and parameters.
|
| const int kBaseOffset = JavaScriptFrameConstants::kSavedRegistersOffset;
|
| @@ -739,6 +769,7 @@
|
| // Internal frames only have object pointers on the expression stack
|
| // as they never have any arguments.
|
| IterateExpressions(v);
|
| + IteratePc(v, pc_address(), code());
|
| }
|
|
|
|
|
| @@ -760,6 +791,56 @@
|
| // -------------------------------------------------------------------------
|
|
|
|
|
| +Code* PcToCodeCache::GcSafeCastToCode(HeapObject* object, Address pc) {
|
| + Code* code = reinterpret_cast<Code*>(object);
|
| + ASSERT(code != NULL && code->contains(pc));
|
| + return code;
|
| +}
|
| +
|
| +
|
| +Code* PcToCodeCache::GcSafeFindCodeForPc(Address pc) {
|
| + // Check if the pc points into a large object chunk.
|
| + LargeObjectChunk* chunk = Heap::lo_space()->FindChunkContainingPc(pc);
|
| + if (chunk != NULL) return GcSafeCastToCode(chunk->GetObject(), pc);
|
| +
|
| + // Iterate through the 8K page until we reach the end or find an
|
| + // object starting after the pc.
|
| + Page* page = Page::FromAddress(pc);
|
| + HeapObjectIterator iterator(page, Heap::GcSafeSizeOfOldObjectFunction());
|
| + HeapObject* previous = NULL;
|
| + while (true) {
|
| + HeapObject* next = iterator.next();
|
| + if (next == NULL || next->address() >= pc) {
|
| + return GcSafeCastToCode(previous, pc);
|
| + }
|
| + previous = next;
|
| + }
|
| +}
|
| +
|
| +PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) {
|
| + Counters::pc_to_code.Increment();
|
| + ASSERT(IsPowerOf2(kPcToCodeCacheSize));
|
| + uint32_t hash = ComputeIntegerHash(
|
| + static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc)));
|
| + uint32_t index = hash & (kPcToCodeCacheSize - 1);
|
| + PcToCodeCacheEntry* entry = cache(index);
|
| + if (entry->pc == pc) {
|
| + Counters::pc_to_code_cached.Increment();
|
| + ASSERT(entry->code == GcSafeFindCodeForPc(pc));
|
| + } else {
|
| + // Because this code may be interrupted by a profiling signal that
|
| + // also queries the cache, we cannot update pc before the code has
|
| + // been set. Otherwise, we risk trying to use a cache entry before
|
| + // the code has been computed.
|
| + entry->code = GcSafeFindCodeForPc(pc);
|
| + entry->pc = pc;
|
| + }
|
| + return entry;
|
| +}
|
| +
|
| +
|
| +// -------------------------------------------------------------------------
|
| +
|
| int NumRegs(RegList reglist) {
|
| int n = 0;
|
| while (reglist != 0) {
|
|
|