diff options
Diffstat (limited to 'deps/v8/src/frames.cc')
-rw-r--r-- | deps/v8/src/frames.cc | 245 |
1 files changed, 182 insertions, 63 deletions
diff --git a/deps/v8/src/frames.cc b/deps/v8/src/frames.cc index 60b1aadfca..40df12c437 100644 --- a/deps/v8/src/frames.cc +++ b/deps/v8/src/frames.cc @@ -1,4 +1,4 @@ -// Copyright 2011 the V8 project authors. All rights reserved. +// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -366,16 +366,17 @@ void SafeStackTraceFrameIterator::Advance() { Code* StackFrame::GetSafepointData(Isolate* isolate, - Address pc, + Address inner_pointer, SafepointEntry* safepoint_entry, unsigned* stack_slots) { - PcToCodeCache::PcToCodeCacheEntry* entry = - isolate->pc_to_code_cache()->GetCacheEntry(pc); + InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* entry = + isolate->inner_pointer_to_code_cache()->GetCacheEntry(inner_pointer); if (!entry->safepoint_entry.is_valid()) { - entry->safepoint_entry = entry->code->GetSafepointEntry(pc); + entry->safepoint_entry = entry->code->GetSafepointEntry(inner_pointer); ASSERT(entry->safepoint_entry.is_valid()); } else { - ASSERT(entry->safepoint_entry.Equals(entry->code->GetSafepointEntry(pc))); + ASSERT(entry->safepoint_entry.Equals( + entry->code->GetSafepointEntry(inner_pointer))); } // Fill in the results and return the code. @@ -392,11 +393,16 @@ bool StackFrame::HasHandler() const { } +#ifdef DEBUG +static bool GcSafeCodeContains(HeapObject* object, Address addr); +#endif + + void StackFrame::IteratePc(ObjectVisitor* v, Address* pc_address, Code* holder) { Address pc = *pc_address; - ASSERT(holder->contains(pc)); + ASSERT(GcSafeCodeContains(holder, pc)); unsigned pc_offset = static_cast<unsigned>(pc - holder->instruction_start()); Object* code = holder; v->VisitPointer(&code); @@ -479,7 +485,7 @@ Code* ExitFrame::unchecked_code() const { void ExitFrame::ComputeCallerState(State* state) const { - // Setup the caller state. + // Set up the caller state. state->sp = caller_sp(); state->fp = Memory::Address_at(fp() + ExitFrameConstants::kCallerFPOffset); state->pc_address @@ -705,6 +711,74 @@ void JavaScriptFrame::Summarize(List<FrameSummary>* functions) { } +void JavaScriptFrame::PrintTop(FILE* file, + bool print_args, + bool print_line_number) { + // constructor calls + HandleScope scope; + AssertNoAllocation no_allocation; + JavaScriptFrameIterator it; + while (!it.done()) { + if (it.frame()->is_java_script()) { + JavaScriptFrame* frame = it.frame(); + if (frame->IsConstructor()) PrintF(file, "new "); + // function name + Object* maybe_fun = frame->function(); + if (maybe_fun->IsJSFunction()) { + JSFunction* fun = JSFunction::cast(maybe_fun); + fun->PrintName(); + Code* js_code = frame->unchecked_code(); + Address pc = frame->pc(); + int code_offset = + static_cast<int>(pc - js_code->instruction_start()); + PrintF("+%d", code_offset); + SharedFunctionInfo* shared = fun->shared(); + if (print_line_number) { + Code* code = Code::cast( + v8::internal::Isolate::Current()->heap()->FindCodeObject(pc)); + int source_pos = code->SourcePosition(pc); + Object* maybe_script = shared->script(); + if (maybe_script->IsScript()) { + Handle<Script> script(Script::cast(maybe_script)); + int line = GetScriptLineNumberSafe(script, source_pos) + 1; + Object* script_name_raw = script->name(); + if (script_name_raw->IsString()) { + String* script_name = String::cast(script->name()); + SmartArrayPointer<char> c_script_name = + script_name->ToCString(DISALLOW_NULLS, + ROBUST_STRING_TRAVERSAL); + PrintF(file, " at %s:%d", *c_script_name, line); + } else { + PrintF(file, "at <unknown>:%d", line); + } + } else { + PrintF(file, " at <unknown>:<unknown>"); + } + } + } else { + PrintF("<unknown>"); + } + + if (print_args) { + // function arguments + // (we are intentionally only printing the actually + // supplied parameters, not all parameters required) + PrintF(file, "(this="); + frame->receiver()->ShortPrint(file); + const int length = frame->ComputeParametersCount(); + for (int i = 0; i < length; i++) { + PrintF(file, ", "); + frame->GetParameter(i)->ShortPrint(file); + } + PrintF(file, ")"); + } + break; + } + it.Advance(); + } +} + + void FrameSummary::Print() { PrintF("receiver: "); receiver_->ShortPrint(); @@ -739,17 +813,18 @@ void OptimizedFrame::Summarize(List<FrameSummary>* frames) { data->TranslationIndex(deopt_index)->value()); Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next()); ASSERT(opcode == Translation::BEGIN); - int frame_count = it.Next(); + it.Next(); // Drop frame count. + int jsframe_count = it.Next(); // We create the summary in reverse order because the frames // in the deoptimization translation are ordered bottom-to-top. - int i = frame_count; + int i = jsframe_count; while (i > 0) { opcode = static_cast<Translation::Opcode>(it.Next()); - if (opcode == Translation::FRAME) { + if (opcode == Translation::JS_FRAME) { // We don't inline constructor calls, so only the first, outermost // frame can be a constructor frame in case of inlining. - bool is_constructor = (i == frame_count) && IsConstructor(); + bool is_constructor = (i == jsframe_count) && IsConstructor(); i--; int ast_id = it.Next(); @@ -819,7 +894,8 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData( // back to a slow search in this case to find the original optimized // code object. if (!code->contains(pc())) { - code = isolate()->pc_to_code_cache()->GcSafeFindCodeForPc(pc()); + code = isolate()->inner_pointer_to_code_cache()-> + GcSafeFindCodeForInnerPointer(pc()); } ASSERT(code != NULL); ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION); @@ -843,8 +919,9 @@ int OptimizedFrame::GetInlineCount() { Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next()); ASSERT(opcode == Translation::BEGIN); USE(opcode); - int frame_count = it.Next(); - return frame_count; + it.Next(); // Drop frame count. + int jsframe_count = it.Next(); + return jsframe_count; } @@ -859,14 +936,15 @@ void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) { data->TranslationIndex(deopt_index)->value()); Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next()); ASSERT(opcode == Translation::BEGIN); - int frame_count = it.Next(); + it.Next(); // Drop frame count. + int jsframe_count = it.Next(); // We insert the frames in reverse order because the frames // in the deoptimization translation are ordered bottom-to-top. - while (frame_count > 0) { + while (jsframe_count > 0) { opcode = static_cast<Translation::Opcode>(it.Next()); - if (opcode == Translation::FRAME) { - frame_count--; + if (opcode == Translation::JS_FRAME) { + jsframe_count--; it.Next(); // Skip ast id. int function_id = it.Next(); it.Next(); // Skip height. @@ -881,6 +959,11 @@ void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) { } +int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const { + return Smi::cast(GetExpression(0))->value(); +} + + Address ArgumentsAdaptorFrame::GetCallerStackPointer() const { return fp() + StandardFrameConstants::kCallerSPOffset; } @@ -927,11 +1010,15 @@ void JavaScriptFrame::Print(StringStream* accumulator, if (IsConstructor()) accumulator->Add("new "); accumulator->PrintFunction(function, receiver, &code); - Handle<SerializedScopeInfo> scope_info(SerializedScopeInfo::Empty()); + // Get scope information for nicer output, if possible. If code is NULL, or + // doesn't contain scope info, scope_info will return 0 for the number of + // parameters, stack local variables, context local variables, stack slots, + // or context slots. + Handle<ScopeInfo> scope_info(ScopeInfo::Empty()); if (function->IsJSFunction()) { Handle<SharedFunctionInfo> shared(JSFunction::cast(function)->shared()); - scope_info = Handle<SerializedScopeInfo>(shared->scope_info()); + scope_info = Handle<ScopeInfo>(shared->scope_info()); Object* script_obj = shared->script(); if (script_obj->IsScript()) { Handle<Script> script(Script::cast(script_obj)); @@ -956,11 +1043,6 @@ void JavaScriptFrame::Print(StringStream* accumulator, accumulator->Add("(this=%o", receiver); - // Get scope information for nicer output, if possible. If code is - // NULL, or doesn't contain scope info, info will return 0 for the - // number of parameters, stack slots, or context slots. - ScopeInfo<PreallocatedStorage> info(*scope_info); - // Print the parameters. int parameters_count = ComputeParametersCount(); for (int i = 0; i < parameters_count; i++) { @@ -968,8 +1050,8 @@ void JavaScriptFrame::Print(StringStream* accumulator, // If we have a name for the parameter we print it. Nameless // parameters are either because we have more actual parameters // than formal parameters or because we have no scope information. - if (i < info.number_of_parameters()) { - accumulator->PrintName(*info.parameter_name(i)); + if (i < scope_info->ParameterCount()) { + accumulator->PrintName(scope_info->ParameterName(i)); accumulator->Add("="); } accumulator->Add("%o", GetParameter(i)); @@ -987,8 +1069,8 @@ void JavaScriptFrame::Print(StringStream* accumulator, accumulator->Add(" {\n"); // Compute the number of locals and expression stack elements. - int stack_locals_count = info.number_of_stack_slots(); - int heap_locals_count = info.number_of_context_slots(); + int stack_locals_count = scope_info->StackLocalCount(); + int heap_locals_count = scope_info->ContextLocalCount(); int expressions_count = ComputeExpressionsCount(); // Print stack-allocated local variables. @@ -997,7 +1079,7 @@ void JavaScriptFrame::Print(StringStream* accumulator, } for (int i = 0; i < stack_locals_count; i++) { accumulator->Add(" var "); - accumulator->PrintName(*info.stack_slot_name(i)); + accumulator->PrintName(scope_info->StackLocalName(i)); accumulator->Add(" = "); if (i < expressions_count) { accumulator->Add("%o", GetExpression(i)); @@ -1014,16 +1096,16 @@ void JavaScriptFrame::Print(StringStream* accumulator, } // Print heap-allocated local variables. - if (heap_locals_count > Context::MIN_CONTEXT_SLOTS) { + if (heap_locals_count > 0) { accumulator->Add(" // heap-allocated locals\n"); } - for (int i = Context::MIN_CONTEXT_SLOTS; i < heap_locals_count; i++) { + for (int i = 0; i < heap_locals_count; i++) { accumulator->Add(" var "); - accumulator->PrintName(*info.context_slot_name(i)); + accumulator->PrintName(scope_info->ContextLocalName(i)); accumulator->Add(" = "); if (context != NULL) { if (i < context->length()) { - accumulator->Add("%o", context->get(i)); + accumulator->Add("%o", context->get(Context::MIN_CONTEXT_SLOTS + i)); } else { accumulator->Add( "// warning: missing context slot - inconsistent frame?"); @@ -1092,7 +1174,7 @@ void EntryFrame::Iterate(ObjectVisitor* v) const { StackHandlerIterator it(this, top_handler()); ASSERT(!it.done()); StackHandler* handler = it.handler(); - ASSERT(handler->is_entry()); + ASSERT(handler->is_js_entry()); handler->Iterate(v, LookupCode()); #ifdef DEBUG // Make sure that the entry frame does not contain more than one @@ -1155,53 +1237,90 @@ JavaScriptFrame* StackFrameLocator::FindJavaScriptFrame(int n) { // ------------------------------------------------------------------------- -Code* PcToCodeCache::GcSafeCastToCode(HeapObject* object, Address pc) { +static Map* GcSafeMapOfCodeSpaceObject(HeapObject* object) { + MapWord map_word = object->map_word(); + return map_word.IsForwardingAddress() ? + map_word.ToForwardingAddress()->map() : map_word.ToMap(); +} + + +static int GcSafeSizeOfCodeSpaceObject(HeapObject* object) { + return object->SizeFromMap(GcSafeMapOfCodeSpaceObject(object)); +} + + +#ifdef DEBUG +static bool GcSafeCodeContains(HeapObject* code, Address addr) { + Map* map = GcSafeMapOfCodeSpaceObject(code); + ASSERT(map == code->GetHeap()->code_map()); + Address start = code->address(); + Address end = code->address() + code->SizeFromMap(map); + return start <= addr && addr < end; +} +#endif + + +Code* InnerPointerToCodeCache::GcSafeCastToCode(HeapObject* object, + Address inner_pointer) { Code* code = reinterpret_cast<Code*>(object); - ASSERT(code != NULL && code->contains(pc)); + ASSERT(code != NULL && GcSafeCodeContains(code, inner_pointer)); return code; } -Code* PcToCodeCache::GcSafeFindCodeForPc(Address pc) { +Code* InnerPointerToCodeCache::GcSafeFindCodeForInnerPointer( + Address inner_pointer) { Heap* heap = isolate_->heap(); - // 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; + // Check if the inner pointer points into a large object chunk. + LargePage* large_page = heap->lo_space()->FindPageContainingPc(inner_pointer); + if (large_page != NULL) { + return GcSafeCastToCode(large_page->GetObject(), inner_pointer); + } + + // Iterate through the page until we reach the end or find an object starting + // after the inner pointer. + Page* page = Page::FromAddress(inner_pointer); + + Address addr = page->skip_list()->StartFor(inner_pointer); + + Address top = heap->code_space()->top(); + Address limit = heap->code_space()->limit(); + while (true) { - HeapObject* next = iterator.next(); - if (next == NULL || next->address() >= pc) { - return GcSafeCastToCode(previous, pc); + if (addr == top && addr != limit) { + addr = limit; + continue; } - previous = next; + + HeapObject* obj = HeapObject::FromAddress(addr); + int obj_size = GcSafeSizeOfCodeSpaceObject(obj); + Address next_addr = addr + obj_size; + if (next_addr > inner_pointer) return GcSafeCastToCode(obj, inner_pointer); + addr = next_addr; } } -PcToCodeCache::PcToCodeCacheEntry* PcToCodeCache::GetCacheEntry(Address pc) { +InnerPointerToCodeCache::InnerPointerToCodeCacheEntry* + InnerPointerToCodeCache::GetCacheEntry(Address inner_pointer) { isolate_->counters()->pc_to_code()->Increment(); - ASSERT(IsPowerOf2(kPcToCodeCacheSize)); + ASSERT(IsPowerOf2(kInnerPointerToCodeCacheSize)); uint32_t hash = ComputeIntegerHash( - static_cast<uint32_t>(reinterpret_cast<uintptr_t>(pc)), + static_cast<uint32_t>(reinterpret_cast<uintptr_t>(inner_pointer)), v8::internal::kZeroHashSeed); - uint32_t index = hash & (kPcToCodeCacheSize - 1); - PcToCodeCacheEntry* entry = cache(index); - if (entry->pc == pc) { + uint32_t index = hash & (kInnerPointerToCodeCacheSize - 1); + InnerPointerToCodeCacheEntry* entry = cache(index); + if (entry->inner_pointer == inner_pointer) { isolate_->counters()->pc_to_code_cached()->Increment(); - ASSERT(entry->code == GcSafeFindCodeForPc(pc)); + ASSERT(entry->code == GcSafeFindCodeForInnerPointer(inner_pointer)); } 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 + // also queries the cache, we cannot update inner_pointer 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->code = GcSafeFindCodeForInnerPointer(inner_pointer); entry->safepoint_entry.Reset(); - entry->pc = pc; + entry->inner_pointer = inner_pointer; } return entry; } |