| Index: src/deoptimizer.cc
|
| diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
|
| index 50d6f0b39956ea60626080da59402a5796cec9db..525f9782d18f2709bf5b5d3a8dd7a39fefcc7957 100644
|
| --- a/src/deoptimizer.cc
|
| +++ b/src/deoptimizer.cc
|
| @@ -602,6 +602,12 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
|
| deferred_objects_double_values_(0),
|
| deferred_objects_(0),
|
| deferred_heap_numbers_(0),
|
| + jsframe_functions_(0),
|
| + jsframe_has_adapted_arguments_(0),
|
| + materialized_values_(NULL),
|
| + materialized_objects_(NULL),
|
| + materialization_value_index_(0),
|
| + materialization_object_index_(0),
|
| trace_(false) {
|
| // For COMPILED_STUBs called from builtins, the function pointer is a SMI
|
| // indicating an internal frame.
|
| @@ -1208,7 +1214,15 @@ void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
|
| unsigned output_offset = output_frame_size;
|
| for (int i = 0; i < parameter_count; ++i) {
|
| output_offset -= kPointerSize;
|
| + int deferred_object_index = deferred_objects_.length();
|
| DoTranslateCommand(iterator, frame_index, output_offset);
|
| + // The allocated receiver of a construct stub frame is passed as the
|
| + // receiver parameter through the translation. It might be encoding
|
| + // a captured object, patch the slot address for a captured object.
|
| + if (i == 0 && deferred_objects_.length() > deferred_object_index) {
|
| + ASSERT(!deferred_objects_[deferred_object_index].is_arguments());
|
| + deferred_objects_[deferred_object_index].patch_slot_address(top_address);
|
| + }
|
| }
|
|
|
| // Read caller's PC from the previous frame.
|
| @@ -1633,9 +1647,89 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
|
| }
|
|
|
|
|
| +Handle<Object> Deoptimizer::MaterializeNextHeapObject() {
|
| + int object_index = materialization_object_index_++;
|
| + ObjectMaterializationDescriptor desc = deferred_objects_[object_index];
|
| + const int length = desc.object_length();
|
| +
|
| + if (desc.duplicate_object() >= 0) {
|
| + // Found a previously materialized object by de-duplication.
|
| + object_index = desc.duplicate_object();
|
| + materialized_objects_->Add(Handle<Object>());
|
| + } else if (desc.is_arguments() && ArgumentsObjectIsAdapted(object_index)) {
|
| + // Use the arguments adapter frame we just built to materialize the
|
| + // arguments object. FunctionGetArguments can't throw an exception.
|
| + Handle<JSFunction> function = ArgumentsObjectFunction(object_index);
|
| + Handle<JSObject> arguments = Handle<JSObject>::cast(
|
| + Accessors::FunctionGetArguments(function));
|
| + materialized_objects_->Add(arguments);
|
| + materialization_value_index_ += length;
|
| + } else if (desc.is_arguments()) {
|
| + // Construct an arguments object and copy the parameters to a newly
|
| + // allocated arguments object backing store.
|
| + Handle<JSFunction> function = ArgumentsObjectFunction(object_index);
|
| + Handle<JSObject> arguments =
|
| + isolate_->factory()->NewArgumentsObject(function, length);
|
| + Handle<FixedArray> array = isolate_->factory()->NewFixedArray(length);
|
| + ASSERT(array->length() == length);
|
| + arguments->set_elements(*array);
|
| + materialized_objects_->Add(arguments);
|
| + for (int i = 0; i < length; ++i) {
|
| + array->set(i, *MaterializeNextValue());
|
| + }
|
| + } else {
|
| + // Dispatch on the instance type of the object to be materialized.
|
| + Handle<Map> map = Handle<Map>::cast(MaterializeNextValue());
|
| + switch (map->instance_type()) {
|
| + case HEAP_NUMBER_TYPE: {
|
| + Handle<HeapNumber> number =
|
| + Handle<HeapNumber>::cast(MaterializeNextValue());
|
| + materialized_objects_->Add(number);
|
| + materialization_value_index_ += kDoubleSize / kPointerSize - 1;
|
| + break;
|
| + }
|
| + case JS_OBJECT_TYPE: {
|
| + Handle<JSObject> object =
|
| + isolate_->factory()->NewJSObjectFromMap(map, NOT_TENURED, false);
|
| + materialized_objects_->Add(object);
|
| + object->set_properties(FixedArray::cast(*MaterializeNextValue()));
|
| + object->set_elements(FixedArray::cast(*MaterializeNextValue()));
|
| + for (int i = 0; i < length - 3; ++i) {
|
| + object->FastPropertyAtPut(i, *MaterializeNextValue());
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + PrintF("[couldn't handle instance type %d]\n", map->instance_type());
|
| + UNREACHABLE();
|
| + }
|
| + }
|
| +
|
| + return materialized_objects_->at(object_index);
|
| +}
|
| +
|
| +
|
| +Handle<Object> Deoptimizer::MaterializeNextValue() {
|
| + int value_index = materialization_value_index_++;
|
| + Handle<Object> value = materialized_values_->at(value_index);
|
| + if (*value == isolate_->heap()->arguments_marker()) {
|
| + value = MaterializeNextHeapObject();
|
| + }
|
| + return value;
|
| +}
|
| +
|
| +
|
| void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
|
| ASSERT_NE(DEBUGGER, bailout_type_);
|
|
|
| + // Walk all JavaScript output frames with the given frame iterator.
|
| + for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
|
| + if (frame_index != 0) it->Advance();
|
| + JavaScriptFrame* frame = it->frame();
|
| + jsframe_functions_.Add(handle(frame->function(), isolate_));
|
| + jsframe_has_adapted_arguments_.Add(frame->has_adapted_arguments());
|
| + }
|
| +
|
| // Handlify all tagged object values before triggering any allocation.
|
| List<Handle<Object> > values(deferred_objects_tagged_values_.length());
|
| for (int i = 0; i < deferred_objects_tagged_values_.length(); ++i) {
|
| @@ -1652,7 +1746,7 @@ void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
|
| HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i];
|
| Handle<Object> num = isolate_->factory()->NewNumber(d.value());
|
| if (trace_) {
|
| - PrintF("Materializing a new heap number %p [%e] in slot %p\n",
|
| + PrintF("Materialized a new heap number %p [%e] in slot %p\n",
|
| reinterpret_cast<void*>(*num),
|
| d.value(),
|
| d.slot_address());
|
| @@ -1660,62 +1754,52 @@ void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
|
| Memory::Object_at(d.slot_address()) = *num;
|
| }
|
|
|
| - // Materialize all heap numbers required for arguments objects.
|
| + // Materialize all heap numbers required for arguments/captured objects.
|
| for (int i = 0; i < values.length(); i++) {
|
| if (!values.at(i)->IsTheHole()) continue;
|
| double double_value = deferred_objects_double_values_[i];
|
| Handle<Object> num = isolate_->factory()->NewNumber(double_value);
|
| if (trace_) {
|
| - PrintF("Materializing a new heap number %p [%e] for arguments object\n",
|
| + PrintF("Materialized a new heap number %p [%e] for object\n",
|
| reinterpret_cast<void*>(*num), double_value);
|
| }
|
| values.Set(i, 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(frame->function(), isolate_);
|
| - Handle<JSObject> arguments;
|
| - for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
|
| - if (frame->GetExpression(i) == isolate_->heap()->arguments_marker()) {
|
| - ObjectMaterializationDescriptor descriptor =
|
| - deferred_objects_.RemoveLast();
|
| - const int length = descriptor.object_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.
|
| - arguments = Handle<JSObject>::cast(
|
| - Accessors::FunctionGetArguments(function));
|
| - 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 (trace_) {
|
| - PrintF("Materializing %sarguments object of length %d for %p: ",
|
| - frame->has_adapted_arguments() ? "(adapted) " : "",
|
| - arguments->elements()->length(),
|
| + // Materialize arguments/captured objects.
|
| + if (!deferred_objects_.is_empty()) {
|
| + List<Handle<Object> > materialized_objects(deferred_objects_.length());
|
| + materialized_objects_ = &materialized_objects;
|
| + materialized_values_ = &values;
|
| +
|
| + while (materialization_object_index_ < deferred_objects_.length()) {
|
| + int object_index = materialization_object_index_;
|
| + ObjectMaterializationDescriptor descriptor =
|
| + deferred_objects_.at(object_index);
|
| +
|
| + // Find a previously materialized object by de-duplication or
|
| + // materialize a new instance of the object if necessary. Store
|
| + // the materialized object into the frame slot.
|
| + Handle<Object> object = MaterializeNextHeapObject();
|
| + Memory::Object_at(descriptor.slot_address()) = *object;
|
| + if (trace_) {
|
| + if (descriptor.is_arguments()) {
|
| + PrintF("Materialized %sarguments object of length %d for %p: ",
|
| + ArgumentsObjectIsAdapted(object_index) ? "(adapted) " : "",
|
| + Handle<JSObject>::cast(object)->elements()->length(),
|
| + reinterpret_cast<void*>(descriptor.slot_address()));
|
| + } else {
|
| + PrintF("Materialized captured object of size %d for %p: ",
|
| + Handle<HeapObject>::cast(object)->Size(),
|
| reinterpret_cast<void*>(descriptor.slot_address()));
|
| - arguments->ShortPrint();
|
| - PrintF("\n");
|
| }
|
| + object->ShortPrint();
|
| + PrintF("\n");
|
| }
|
| }
|
| +
|
| + ASSERT(materialization_object_index_ == materialized_objects_->length());
|
| + ASSERT(materialization_value_index_ == materialized_values_->length());
|
| }
|
| }
|
|
|
| @@ -1786,10 +1870,10 @@ static const char* TraceValueType(bool is_smi, bool is_native = false) {
|
|
|
|
|
| void Deoptimizer::DoTranslateObject(TranslationIterator* iterator,
|
| - int object_opcode,
|
| + int object_index,
|
| int field_index) {
|
| disasm::NameConverter converter;
|
| - Address object_slot = deferred_objects_.last().slot_address();
|
| + Address object_slot = deferred_objects_[object_index].slot_address();
|
|
|
| Translation::Opcode opcode =
|
| static_cast<Translation::Opcode>(iterator->Next());
|
| @@ -1802,7 +1886,6 @@ void Deoptimizer::DoTranslateObject(TranslationIterator* iterator,
|
| case Translation::GETTER_STUB_FRAME:
|
| case Translation::SETTER_STUB_FRAME:
|
| case Translation::COMPILED_STUB_FRAME:
|
| - case Translation::ARGUMENTS_OBJECT:
|
| UNREACHABLE();
|
| return;
|
|
|
| @@ -1972,6 +2055,50 @@ void Deoptimizer::DoTranslateObject(TranslationIterator* iterator,
|
| AddObjectTaggedValue(value);
|
| return;
|
| }
|
| +
|
| + case Translation::DUPLICATED_OBJECT: {
|
| + int object_index = iterator->Next();
|
| + if (trace_) {
|
| + PrintF(" nested @0x%08" V8PRIxPTR ": [field #%d] <- ",
|
| + reinterpret_cast<intptr_t>(object_slot),
|
| + field_index);
|
| + isolate_->heap()->arguments_marker()->ShortPrint();
|
| + PrintF(" ; duplicate of object #%d\n", object_index);
|
| + }
|
| + // Use the materialization marker value as a sentinel and fill in
|
| + // the object after the deoptimized frame is built.
|
| + intptr_t value = reinterpret_cast<intptr_t>(
|
| + isolate_->heap()->arguments_marker());
|
| + AddObjectDuplication(0, object_index);
|
| + AddObjectTaggedValue(value);
|
| + return;
|
| + }
|
| +
|
| + case Translation::ARGUMENTS_OBJECT:
|
| + case Translation::CAPTURED_OBJECT: {
|
| + int length = iterator->Next();
|
| + bool is_args = opcode == Translation::ARGUMENTS_OBJECT;
|
| + if (trace_) {
|
| + PrintF(" nested @0x%08" V8PRIxPTR ": [field #%d] <- ",
|
| + reinterpret_cast<intptr_t>(object_slot),
|
| + field_index);
|
| + isolate_->heap()->arguments_marker()->ShortPrint();
|
| + PrintF(" ; object (length = %d, is_args = %d)\n", length, is_args);
|
| + }
|
| + // Use the materialization marker value as a sentinel and fill in
|
| + // the object after the deoptimized frame is built.
|
| + intptr_t value = reinterpret_cast<intptr_t>(
|
| + isolate_->heap()->arguments_marker());
|
| + AddObjectStart(0, length, is_args);
|
| + AddObjectTaggedValue(value);
|
| + // We save the object values on the side and materialize the actual
|
| + // object after the deoptimized frame is built.
|
| + int object_index = deferred_objects_.length() - 1;
|
| + for (int i = 0; i < length; i++) {
|
| + DoTranslateObject(iterator, object_index, i);
|
| + }
|
| + return;
|
| + }
|
| }
|
| }
|
|
|
| @@ -2211,25 +2338,48 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
| return;
|
| }
|
|
|
| - case Translation::ARGUMENTS_OBJECT: {
|
| + case Translation::DUPLICATED_OBJECT: {
|
| + int object_index = iterator->Next();
|
| + if (trace_) {
|
| + PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
|
| + output_[frame_index]->GetTop() + output_offset,
|
| + output_offset);
|
| + isolate_->heap()->arguments_marker()->ShortPrint();
|
| + PrintF(" ; duplicate of object #%d\n", object_index);
|
| + }
|
| + // Use the materialization marker value as a sentinel and fill in
|
| + // the object after the deoptimized frame is built.
|
| + intptr_t value = reinterpret_cast<intptr_t>(
|
| + isolate_->heap()->arguments_marker());
|
| + AddObjectDuplication(output_[frame_index]->GetTop() + output_offset,
|
| + object_index);
|
| + output_[frame_index]->SetFrameSlot(output_offset, value);
|
| + return;
|
| + }
|
| +
|
| + case Translation::ARGUMENTS_OBJECT:
|
| + case Translation::CAPTURED_OBJECT: {
|
| int length = iterator->Next();
|
| + bool is_args = opcode == Translation::ARGUMENTS_OBJECT;
|
| if (trace_) {
|
| PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
|
| output_[frame_index]->GetTop() + output_offset,
|
| output_offset);
|
| isolate_->heap()->arguments_marker()->ShortPrint();
|
| - PrintF(" ; arguments object (length = %d)\n", length);
|
| + PrintF(" ; object (length = %d, is_args = %d)\n", length, is_args);
|
| }
|
| - // Use the arguments marker value as a sentinel and fill in the arguments
|
| - // object after the deoptimized frame is built.
|
| + // Use the materialization marker value as a sentinel and fill in
|
| + // the object after the deoptimized frame is built.
|
| intptr_t value = reinterpret_cast<intptr_t>(
|
| isolate_->heap()->arguments_marker());
|
| - AddObjectStart(output_[frame_index]->GetTop() + output_offset, length);
|
| + AddObjectStart(output_[frame_index]->GetTop() + output_offset,
|
| + length, is_args);
|
| output_[frame_index]->SetFrameSlot(output_offset, value);
|
| - // We save the argument values on the side and materialize the actual
|
| - // arguments object after the deoptimized frame is built.
|
| + // We save the object values on the side and materialize the actual
|
| + // object after the deoptimized frame is built.
|
| + int object_index = deferred_objects_.length() - 1;
|
| for (int i = 0; i < length; i++) {
|
| - DoTranslateObject(iterator, Translation::ARGUMENTS_OBJECT, i);
|
| + DoTranslateObject(iterator, object_index, i);
|
| }
|
| return;
|
| }
|
| @@ -2406,7 +2556,9 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator,
|
| break;
|
| }
|
|
|
| - case Translation::ARGUMENTS_OBJECT: {
|
| + case Translation::DUPLICATED_OBJECT:
|
| + case Translation::ARGUMENTS_OBJECT:
|
| + case Translation::CAPTURED_OBJECT: {
|
| // Optimized code assumes that the argument object has not been
|
| // materialized and so bypasses it when doing arguments access.
|
| // We should have bailed out before starting the frame
|
| @@ -2554,9 +2706,16 @@ Object* Deoptimizer::ComputeLiteral(int index) const {
|
| }
|
|
|
|
|
| -void Deoptimizer::AddObjectStart(intptr_t slot_address, int length) {
|
| +void Deoptimizer::AddObjectStart(intptr_t slot, int length, bool is_args) {
|
| ObjectMaterializationDescriptor object_desc(
|
| - reinterpret_cast<Address>(slot_address), length);
|
| + reinterpret_cast<Address>(slot), jsframe_count_, length, -1, is_args);
|
| + deferred_objects_.Add(object_desc);
|
| +}
|
| +
|
| +
|
| +void Deoptimizer::AddObjectDuplication(intptr_t slot, int object_index) {
|
| + ObjectMaterializationDescriptor object_desc(
|
| + reinterpret_cast<Address>(slot), jsframe_count_, -1, object_index, false);
|
| deferred_objects_.Add(object_desc);
|
| }
|
|
|
| @@ -2784,6 +2943,18 @@ void Translation::BeginArgumentsObject(int args_length) {
|
| }
|
|
|
|
|
| +void Translation::BeginCapturedObject(int length) {
|
| + buffer_->Add(CAPTURED_OBJECT, zone());
|
| + buffer_->Add(length, zone());
|
| +}
|
| +
|
| +
|
| +void Translation::DuplicateObject(int object_index) {
|
| + buffer_->Add(DUPLICATED_OBJECT, zone());
|
| + buffer_->Add(object_index, zone());
|
| +}
|
| +
|
| +
|
| void Translation::StoreRegister(Register reg) {
|
| buffer_->Add(REGISTER, zone());
|
| buffer_->Add(reg.code(), zone());
|
| @@ -2852,7 +3023,9 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
|
| switch (opcode) {
|
| case GETTER_STUB_FRAME:
|
| case SETTER_STUB_FRAME:
|
| + case DUPLICATED_OBJECT:
|
| case ARGUMENTS_OBJECT:
|
| + case CAPTURED_OBJECT:
|
| case REGISTER:
|
| case INT32_REGISTER:
|
| case UINT32_REGISTER:
|
| @@ -2912,8 +3085,12 @@ const char* Translation::StringFor(Opcode opcode) {
|
| return "DOUBLE_STACK_SLOT";
|
| case LITERAL:
|
| return "LITERAL";
|
| + case DUPLICATED_OBJECT:
|
| + return "DUPLICATED_OBJECT";
|
| case ARGUMENTS_OBJECT:
|
| return "ARGUMENTS_OBJECT";
|
| + case CAPTURED_OBJECT:
|
| + return "CAPTURED_OBJECT";
|
| }
|
| UNREACHABLE();
|
| return "";
|
| @@ -2957,7 +3134,9 @@ SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator,
|
| // Peeled off before getting here.
|
| break;
|
|
|
| + case Translation::DUPLICATED_OBJECT:
|
| case Translation::ARGUMENTS_OBJECT:
|
| + case Translation::CAPTURED_OBJECT:
|
| // This can be only emitted for local slots not for argument slots.
|
| break;
|
|
|
|
|