Merge V8 at 3.9.24.13
Bug: 5688872
Change-Id: Id0aa8d23375030494d3189c31774059c0f5398fc
diff --git a/src/frames.cc b/src/frames.cc
index 60b1aad..0571a81 100644
--- a/src/frames.cc
+++ b/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:
@@ -31,6 +31,7 @@
#include "deoptimizer.h"
#include "frames-inl.h"
#include "full-codegen.h"
+#include "lazy-instance.h"
#include "mark-compact.h"
#include "safepoint-table.h"
#include "scopeinfo.h"
@@ -41,6 +42,22 @@
namespace v8 {
namespace internal {
+
+static ReturnAddressLocationResolver return_address_location_resolver = NULL;
+
+
+// Resolves pc_address through the resolution address function if one is set.
+static inline Address* ResolveReturnAddressLocation(Address* pc_address) {
+ if (return_address_location_resolver == NULL) {
+ return pc_address;
+ } else {
+ return reinterpret_cast<Address*>(
+ return_address_location_resolver(
+ reinterpret_cast<uintptr_t>(pc_address)));
+ }
+}
+
+
// Iterator that supports traversing the stack handlers of a
// particular frame. Needs to know the top of the handler chain.
class StackHandlerIterator BASE_EMBEDDED {
@@ -155,8 +172,8 @@
ASSERT(fp_ != NULL);
state.fp = fp_;
state.sp = sp_;
- state.pc_address =
- reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_));
+ state.pc_address = ResolveReturnAddressLocation(
+ reinterpret_cast<Address*>(StandardFrame::ComputePCAddress(fp_)));
type = StackFrame::ComputeType(isolate(), &state);
}
if (SingletonFor(type) == NULL) return;
@@ -366,16 +383,17 @@
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 +410,16 @@
}
+#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);
@@ -408,6 +431,13 @@
}
+void StackFrame::SetReturnAddressLocationResolver(
+ ReturnAddressLocationResolver resolver) {
+ ASSERT(return_address_location_resolver == NULL);
+ return_address_location_resolver = resolver;
+}
+
+
StackFrame::Type StackFrame::ComputeType(Isolate* isolate, State* state) {
ASSERT(state->fp != NULL);
if (StandardFrame::IsArgumentsAdaptorFrame(state->fp)) {
@@ -479,11 +509,11 @@
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
- = reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset);
+ state->pc_address = ResolveReturnAddressLocation(
+ reinterpret_cast<Address*>(fp() + ExitFrameConstants::kCallerPCOffset));
}
@@ -517,7 +547,8 @@
void ExitFrame::FillState(Address fp, Address sp, State* state) {
state->sp = sp;
state->fp = fp;
- state->pc_address = reinterpret_cast<Address*>(sp - 1 * kPointerSize);
+ state->pc_address = ResolveReturnAddressLocation(
+ reinterpret_cast<Address*>(sp - 1 * kPointerSize));
}
@@ -552,7 +583,8 @@
void StandardFrame::ComputeCallerState(State* state) const {
state->sp = caller_sp();
state->fp = caller_fp();
- state->pc_address = reinterpret_cast<Address*>(ComputePCAddress(fp()));
+ state->pc_address = ResolveReturnAddressLocation(
+ reinterpret_cast<Address*>(ComputePCAddress(fp())));
}
@@ -705,6 +737,74 @@
}
+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,18 +839,16 @@
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;
+ bool is_constructor = IsConstructor();
+ int i = jsframe_count;
while (i > 0) {
opcode = static_cast<Translation::Opcode>(it.Next());
- if (opcode == Translation::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();
-
+ if (opcode == Translation::JS_FRAME) {
i--;
int ast_id = it.Next();
int function_id = it.Next();
@@ -800,11 +898,18 @@
FrameSummary summary(receiver, function, code, pc_offset, is_constructor);
frames->Add(summary);
+ is_constructor = false;
+ } else if (opcode == Translation::CONSTRUCT_STUB_FRAME) {
+ // The next encountered JS_FRAME will be marked as a constructor call.
+ it.Skip(Translation::NumberOfOperandsFor(opcode));
+ ASSERT(!is_constructor);
+ is_constructor = true;
} else {
// Skip over operands to advance to the next opcode.
it.Skip(Translation::NumberOfOperandsFor(opcode));
}
}
+ ASSERT(!is_constructor);
}
@@ -819,7 +924,8 @@
// 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 +949,9 @@
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 +966,15 @@
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 +989,11 @@
}
+int ArgumentsAdaptorFrame::GetNumberOfIncomingArguments() const {
+ return Smi::cast(GetExpression(0))->value();
+}
+
+
Address ArgumentsAdaptorFrame::GetCallerStackPointer() const {
return fp() + StandardFrameConstants::kCallerSPOffset;
}
@@ -927,11 +1040,15 @@
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 +1073,6 @@
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 +1080,8 @@
// 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 +1099,8 @@
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 +1109,7 @@
}
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 +1126,16 @@
}
// 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 +1204,7 @@
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 +1267,90 @@
// -------------------------------------------------------------------------
-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);
+ // Check if the inner pointer points into a large object chunk.
+ LargePage* large_page = heap->lo_space()->FindPage(inner_pointer);
+ if (large_page != NULL) {
+ return GcSafeCastToCode(large_page->GetObject(), inner_pointer);
+ }
- // 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;
+ // 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;
}
@@ -1232,12 +1381,12 @@
};
-static const JSCallerSavedCodeData kCallerSavedCodeData;
-
+static LazyInstance<JSCallerSavedCodeData>::type caller_saved_code_data =
+ LAZY_INSTANCE_INITIALIZER;
int JSCallerSavedCode(int n) {
ASSERT(0 <= n && n < kNumJSCallerSaved);
- return kCallerSavedCodeData.reg_code[n];
+ return caller_saved_code_data.Get().reg_code[n];
}