summaryrefslogtreecommitdiff
path: root/deps/v8/src/deoptimizer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/deoptimizer.cc')
-rw-r--r--deps/v8/src/deoptimizer.cc263
1 files changed, 215 insertions, 48 deletions
diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc
index d1b00f8bde..8f1711144e 100644
--- a/deps/v8/src/deoptimizer.cc
+++ b/deps/v8/src/deoptimizer.cc
@@ -27,6 +27,7 @@
#include "v8.h"
+#include "accessors.h"
#include "codegen.h"
#include "deoptimizer.h"
#include "disasm.h"
@@ -40,8 +41,11 @@ namespace v8 {
namespace internal {
DeoptimizerData::DeoptimizerData() {
- eager_deoptimization_entry_code_ = NULL;
- lazy_deoptimization_entry_code_ = NULL;
+ eager_deoptimization_entry_code_entries_ = -1;
+ lazy_deoptimization_entry_code_entries_ = -1;
+ size_t deopt_table_size = Deoptimizer::GetMaxDeoptTableSize();
+ eager_deoptimization_entry_code_ = new VirtualMemory(deopt_table_size);
+ lazy_deoptimization_entry_code_ = new VirtualMemory(deopt_table_size);
current_ = NULL;
deoptimizing_code_list_ = NULL;
#ifdef ENABLE_DEBUGGER_SUPPORT
@@ -51,16 +55,18 @@ DeoptimizerData::DeoptimizerData() {
DeoptimizerData::~DeoptimizerData() {
- if (eager_deoptimization_entry_code_ != NULL) {
- Isolate::Current()->memory_allocator()->Free(
- eager_deoptimization_entry_code_);
- eager_deoptimization_entry_code_ = NULL;
- }
- if (lazy_deoptimization_entry_code_ != NULL) {
- Isolate::Current()->memory_allocator()->Free(
- lazy_deoptimization_entry_code_);
- lazy_deoptimization_entry_code_ = NULL;
+ delete eager_deoptimization_entry_code_;
+ eager_deoptimization_entry_code_ = NULL;
+ delete lazy_deoptimization_entry_code_;
+ lazy_deoptimization_entry_code_ = NULL;
+
+ DeoptimizingCodeListNode* current = deoptimizing_code_list_;
+ while (current != NULL) {
+ DeoptimizingCodeListNode* prev = current;
+ current = current->next();
+ delete prev;
}
+ deoptimizing_code_list_ = NULL;
}
@@ -95,6 +101,20 @@ Deoptimizer* Deoptimizer::New(JSFunction* function,
}
+// No larger than 2K on all platforms
+static const int kDeoptTableMaxEpilogueCodeSize = 2 * KB;
+
+
+size_t Deoptimizer::GetMaxDeoptTableSize() {
+ int entries_size =
+ Deoptimizer::kMaxNumberOfEntries * Deoptimizer::table_entry_size_;
+ int commit_page_size = static_cast<int>(OS::CommitPageSize());
+ int page_count = ((kDeoptTableMaxEpilogueCodeSize + entries_size - 1) /
+ commit_page_size) + 1;
+ return static_cast<size_t>(commit_page_size * page_count);
+}
+
+
Deoptimizer* Deoptimizer::Grab(Isolate* isolate) {
ASSERT(isolate == Isolate::Current());
Deoptimizer* result = isolate->deoptimizer_data()->current_;
@@ -368,6 +388,8 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
output_count_(0),
jsframe_count_(0),
output_(NULL),
+ deferred_arguments_objects_values_(0),
+ deferred_arguments_objects_(0),
deferred_heap_numbers_(0) {
if (FLAG_trace_deopt && type != OSR) {
if (type == DEBUGGER) {
@@ -451,44 +473,45 @@ void Deoptimizer::DeleteFrameDescriptions() {
}
-Address Deoptimizer::GetDeoptimizationEntry(int id, BailoutType type) {
+Address Deoptimizer::GetDeoptimizationEntry(int id,
+ BailoutType type,
+ GetEntryMode mode) {
ASSERT(id >= 0);
- if (id >= kNumberOfEntries) return NULL;
- MemoryChunk* base = NULL;
+ if (id >= kMaxNumberOfEntries) return NULL;
+ VirtualMemory* base = NULL;
+ if (mode == ENSURE_ENTRY_CODE) {
+ EnsureCodeForDeoptimizationEntry(type, id);
+ } else {
+ ASSERT(mode == CALCULATE_ENTRY_ADDRESS);
+ }
DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
if (type == EAGER) {
- if (data->eager_deoptimization_entry_code_ == NULL) {
- data->eager_deoptimization_entry_code_ = CreateCode(type);
- }
base = data->eager_deoptimization_entry_code_;
} else {
- if (data->lazy_deoptimization_entry_code_ == NULL) {
- data->lazy_deoptimization_entry_code_ = CreateCode(type);
- }
base = data->lazy_deoptimization_entry_code_;
}
return
- static_cast<Address>(base->area_start()) + (id * table_entry_size_);
+ static_cast<Address>(base->address()) + (id * table_entry_size_);
}
int Deoptimizer::GetDeoptimizationId(Address addr, BailoutType type) {
- MemoryChunk* base = NULL;
+ VirtualMemory* base = NULL;
DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
if (type == EAGER) {
base = data->eager_deoptimization_entry_code_;
} else {
base = data->lazy_deoptimization_entry_code_;
}
+ Address base_casted = reinterpret_cast<Address>(base->address());
if (base == NULL ||
- addr < base->area_start() ||
- addr >= base->area_start() +
- (kNumberOfEntries * table_entry_size_)) {
+ addr < base->address() ||
+ addr >= base_casted + (kMaxNumberOfEntries * table_entry_size_)) {
return kNotDeoptimizationEntry;
}
ASSERT_EQ(0,
- static_cast<int>(addr - base->area_start()) % table_entry_size_);
- return static_cast<int>(addr - base->area_start()) / table_entry_size_;
+ static_cast<int>(addr - base_casted) % table_entry_size_);
+ return static_cast<int>(addr - base_casted) / table_entry_size_;
}
@@ -512,7 +535,7 @@ int Deoptimizer::GetOutputInfo(DeoptimizationOutputData* data,
shared->SourceCodePrint(&stream, -1);
PrintF("[source:\n%s\n]", *stream.ToCString());
- UNREACHABLE();
+ FATAL("unable to find pc offset during deoptimization");
return -1;
}
@@ -633,8 +656,21 @@ void Deoptimizer::DoComputeOutputFrames() {
}
-void Deoptimizer::MaterializeHeapNumbers() {
+void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
ASSERT_NE(DEBUGGER, bailout_type_);
+
+ // Handlify all argument object values before triggering any allocation.
+ List<Handle<Object> > values(deferred_arguments_objects_values_.length());
+ for (int i = 0; i < deferred_arguments_objects_values_.length(); ++i) {
+ values.Add(Handle<Object>(deferred_arguments_objects_values_[i]));
+ }
+
+ // Play it safe and clear all unhandlified values before we continue.
+ deferred_arguments_objects_values_.Clear();
+
+ // Materialize all heap numbers before looking at arguments because when the
+ // output frames are used to materialize arguments objects later on they need
+ // to already contain valid heap numbers.
for (int i = 0; i < deferred_heap_numbers_.length(); i++) {
HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
Handle<Object> num = isolate_->factory()->NewNumber(d.value());
@@ -644,9 +680,55 @@ void Deoptimizer::MaterializeHeapNumbers() {
d.value(),
d.slot_address());
}
-
Memory::Object_at(d.slot_address()) = *num;
}
+
+ // Materialize arguments objects one frame at a time.
+ for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
+ if (frame_index != 0) it->Advance();
+ JavaScriptFrame* frame = it->frame();
+ Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate_);
+ Handle<JSObject> arguments;
+ for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
+ if (frame->GetExpression(i) == isolate_->heap()->arguments_marker()) {
+ ArgumentsObjectMaterializationDescriptor descriptor =
+ deferred_arguments_objects_.RemoveLast();
+ const int length = descriptor.arguments_length();
+ if (arguments.is_null()) {
+ if (frame->has_adapted_arguments()) {
+ // Use the arguments adapter frame we just built to materialize the
+ // arguments object. FunctionGetArguments can't throw an exception,
+ // so cast away the doubt with an assert.
+ arguments = Handle<JSObject>(JSObject::cast(
+ Accessors::FunctionGetArguments(*function,
+ NULL)->ToObjectUnchecked()));
+ values.RewindBy(length);
+ } else {
+ // Construct an arguments object and copy the parameters to a newly
+ // allocated arguments object backing store.
+ arguments =
+ isolate_->factory()->NewArgumentsObject(function, length);
+ Handle<FixedArray> array =
+ isolate_->factory()->NewFixedArray(length);
+ ASSERT(array->length() == length);
+ for (int i = length - 1; i >= 0 ; --i) {
+ array->set(i, *values.RemoveLast());
+ }
+ arguments->set_elements(*array);
+ }
+ }
+ frame->SetExpression(i, *arguments);
+ ASSERT_EQ(Memory::Object_at(descriptor.slot_address()), *arguments);
+ if (FLAG_trace_deopt) {
+ PrintF("Materializing %sarguments object for %p: ",
+ frame->has_adapted_arguments() ? "(adapted) " : "",
+ reinterpret_cast<void*>(descriptor.slot_address()));
+ arguments->ShortPrint();
+ PrintF("\n");
+ }
+ }
+ }
+ }
}
@@ -932,8 +1014,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
}
case Translation::ARGUMENTS_OBJECT: {
- // Use the arguments marker value as a sentinel and fill in the arguments
- // object after the deoptimized frame is built.
+ int args_index = iterator->Next() + 1; // Skip receiver.
+ int args_length = iterator->Next() - 1; // Skip receiver.
if (FLAG_trace_deopt) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
output_[frame_index]->GetTop() + output_offset,
@@ -941,9 +1023,20 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
isolate_->heap()->arguments_marker()->ShortPrint();
PrintF(" ; arguments object\n");
}
+ // Use the arguments marker value as a sentinel and fill in the arguments
+ // object after the deoptimized frame is built.
intptr_t value = reinterpret_cast<intptr_t>(
isolate_->heap()->arguments_marker());
+ AddArgumentsObject(
+ output_[frame_index]->GetTop() + output_offset, args_length);
output_[frame_index]->SetFrameSlot(output_offset, value);
+ // We save the tagged argument values on the side and materialize the
+ // actual arguments object after the deoptimized frame is built.
+ for (int i = 0; i < args_length; i++) {
+ unsigned input_offset = input_->GetOffsetFromSlotIndex(args_index + i);
+ intptr_t input_value = input_->GetFrameSlot(input_offset);
+ AddArgumentsObjectValue(input_value);
+ }
return;
}
}
@@ -1285,39 +1378,63 @@ Object* Deoptimizer::ComputeLiteral(int index) const {
}
-void Deoptimizer::AddDoubleValue(intptr_t slot_address,
- double value) {
+void Deoptimizer::AddArgumentsObject(intptr_t slot_address, int argc) {
+ ArgumentsObjectMaterializationDescriptor object_desc(
+ reinterpret_cast<Address>(slot_address), argc);
+ deferred_arguments_objects_.Add(object_desc);
+}
+
+
+void Deoptimizer::AddArgumentsObjectValue(intptr_t value) {
+ deferred_arguments_objects_values_.Add(reinterpret_cast<Object*>(value));
+}
+
+
+void Deoptimizer::AddDoubleValue(intptr_t slot_address, double value) {
HeapNumberMaterializationDescriptor value_desc(
reinterpret_cast<Address>(slot_address), value);
deferred_heap_numbers_.Add(value_desc);
}
-MemoryChunk* Deoptimizer::CreateCode(BailoutType type) {
+void Deoptimizer::EnsureCodeForDeoptimizationEntry(BailoutType type,
+ int max_entry_id) {
// We cannot run this if the serializer is enabled because this will
// cause us to emit relocation information for the external
// references. This is fine because the deoptimizer's code section
// isn't meant to be serialized at all.
ASSERT(!Serializer::enabled());
+ ASSERT(type == EAGER || type == LAZY);
+ DeoptimizerData* data = Isolate::Current()->deoptimizer_data();
+ int entry_count = (type == EAGER)
+ ? data->eager_deoptimization_entry_code_entries_
+ : data->lazy_deoptimization_entry_code_entries_;
+ if (max_entry_id < entry_count) return;
+ entry_count = Min(Max(entry_count * 2, Deoptimizer::kMinNumberOfEntries),
+ Deoptimizer::kMaxNumberOfEntries);
+
MacroAssembler masm(Isolate::Current(), NULL, 16 * KB);
masm.set_emit_debug_code(false);
- GenerateDeoptimizationEntries(&masm, kNumberOfEntries, type);
+ GenerateDeoptimizationEntries(&masm, entry_count, type);
CodeDesc desc;
masm.GetCode(&desc);
ASSERT(desc.reloc_size == 0);
- MemoryChunk* chunk =
- Isolate::Current()->memory_allocator()->AllocateChunk(desc.instr_size,
- EXECUTABLE,
- NULL);
- ASSERT(chunk->area_size() >= desc.instr_size);
- if (chunk == NULL) {
- V8::FatalProcessOutOfMemory("Not enough memory for deoptimization table");
+ VirtualMemory* memory = type == EAGER
+ ? data->eager_deoptimization_entry_code_
+ : data->lazy_deoptimization_entry_code_;
+ size_t table_size = Deoptimizer::GetMaxDeoptTableSize();
+ ASSERT(static_cast<int>(table_size) >= desc.instr_size);
+ memory->Commit(memory->address(), table_size, true);
+ memcpy(memory->address(), desc.buffer, desc.instr_size);
+ CPU::FlushICache(memory->address(), desc.instr_size);
+
+ if (type == EAGER) {
+ data->eager_deoptimization_entry_code_entries_ = entry_count;
+ } else {
+ data->lazy_deoptimization_entry_code_entries_ = entry_count;
}
- memcpy(chunk->area_start(), desc.buffer, desc.instr_size);
- CPU::FlushICache(chunk->area_start(), desc.instr_size);
- return chunk;
}
@@ -1359,6 +1476,54 @@ void Deoptimizer::RemoveDeoptimizingCode(Code* code) {
}
+static Object* CutOutRelatedFunctionsList(Context* context,
+ Code* code,
+ Object* undefined) {
+ Object* result_list_head = undefined;
+ Object* head;
+ Object* current;
+ current = head = context->get(Context::OPTIMIZED_FUNCTIONS_LIST);
+ JSFunction* prev = NULL;
+ while (current != undefined) {
+ JSFunction* func = JSFunction::cast(current);
+ current = func->next_function_link();
+ if (func->code() == code) {
+ func->set_next_function_link(result_list_head);
+ result_list_head = func;
+ if (prev) {
+ prev->set_next_function_link(current);
+ } else {
+ head = current;
+ }
+ } else {
+ prev = func;
+ }
+ }
+ if (head != context->get(Context::OPTIMIZED_FUNCTIONS_LIST)) {
+ context->set(Context::OPTIMIZED_FUNCTIONS_LIST, head);
+ }
+ return result_list_head;
+}
+
+
+void Deoptimizer::ReplaceCodeForRelatedFunctions(JSFunction* function,
+ Code* code) {
+ Context* context = function->context()->native_context();
+
+ SharedFunctionInfo* shared = function->shared();
+
+ Object* undefined = Isolate::Current()->heap()->undefined_value();
+ Object* current = CutOutRelatedFunctionsList(context, code, undefined);
+
+ while (current != undefined) {
+ JSFunction* func = JSFunction::cast(current);
+ current = func->next_function_link();
+ func->set_code(shared->code());
+ func->set_next_function_link(undefined);
+ }
+}
+
+
FrameDescription::FrameDescription(uint32_t frame_size,
JSFunction* function)
: frame_size_(frame_size),
@@ -1570,8 +1735,10 @@ void Translation::StoreLiteral(int literal_id) {
}
-void Translation::StoreArgumentsObject() {
+void Translation::StoreArgumentsObject(int args_index, int args_length) {
buffer_->Add(ARGUMENTS_OBJECT, zone());
+ buffer_->Add(args_index, zone());
+ buffer_->Add(args_length, zone());
}
@@ -1582,7 +1749,6 @@ void Translation::MarkDuplicate() {
int Translation::NumberOfOperandsFor(Opcode opcode) {
switch (opcode) {
- case ARGUMENTS_OBJECT:
case DUPLICATE:
return 0;
case GETTER_STUB_FRAME:
@@ -1600,6 +1766,7 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
case BEGIN:
case ARGUMENTS_ADAPTOR_FRAME:
case CONSTRUCT_STUB_FRAME:
+ case ARGUMENTS_OBJECT:
return 2;
case JS_FRAME:
return 3;