diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index e2b29df02f..da90a6705c 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -926,90 +926,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { } -LEnvironment* LChunkBuilder::CreateEnvironment( - HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList* objects_to_materialize) { - if (hydrogen_env == NULL) return NULL; - - LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(), - argument_index_accumulator, - objects_to_materialize); - BailoutId ast_id = hydrogen_env->ast_id(); - ASSERT(!ast_id.IsNone() || - hydrogen_env->frame_type() != JS_FUNCTION); - int value_count = hydrogen_env->length() - hydrogen_env->specials_count(); - LEnvironment* result = new(zone()) LEnvironment( - hydrogen_env->closure(), - hydrogen_env->frame_type(), - ast_id, - hydrogen_env->parameter_count(), - argument_count_, - value_count, - outer, - hydrogen_env->entry(), - zone()); - int argument_index = *argument_index_accumulator; - int object_index = objects_to_materialize->length(); - for (int i = 0; i < hydrogen_env->length(); ++i) { - if (hydrogen_env->is_special_index(i)) continue; - - LOperand* op; - HValue* value = hydrogen_env->values()->at(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else if (value->IsPushArgument()) { - op = new(zone()) LArgument(argument_index++); - } else { - op = UseAny(value); - } - result->AddValue(op, - value->representation(), - value->CheckFlag(HInstruction::kUint32)); - } - - for (int i = object_index; i < objects_to_materialize->length(); ++i) { - HValue* object_to_materialize = objects_to_materialize->at(i); - int previously_materialized_object = -1; - for (int prev = 0; prev < i; ++prev) { - if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) { - previously_materialized_object = prev; - break; - } - } - int length = object_to_materialize->OperandCount(); - bool is_arguments = object_to_materialize->IsArgumentsObject(); - if (previously_materialized_object >= 0) { - result->AddDuplicateObject(previously_materialized_object); - continue; - } else { - result->AddNewObject(is_arguments ? length - 1 : length, is_arguments); - } - for (int i = is_arguments ? 1 : 0; i < length; ++i) { - LOperand* op; - HValue* value = object_to_materialize->OperandAt(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else { - ASSERT(!value->IsPushArgument()); - op = UseAny(value); - } - result->AddValue(op, - value->representation(), - value->CheckFlag(HInstruction::kUint32)); - } - } - - if (hydrogen_env->frame_type() == JS_FUNCTION) { - *argument_index_accumulator = argument_index; - } - - return result; -} - - LInstruction* LChunkBuilder::DoGoto(HGoto* instr) { return new(zone()) LGoto(instr->FirstSuccessor()); } diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 5c320310be..3a540a2722 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -2697,18 +2697,17 @@ class LPlatformChunk V8_FINAL : public LChunk { }; -class LChunkBuilder V8_FINAL BASE_EMBEDDED { +class LChunkBuilder V8_FINAL : public LChunkBuilderBase { public: LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator) - : chunk_(NULL), + : LChunkBuilderBase(graph->zone()), + chunk_(NULL), info_(info), graph_(graph), - zone_(graph->zone()), status_(UNUSED), current_instruction_(NULL), current_block_(NULL), next_block_(NULL), - argument_count_(0), allocator_(allocator), position_(RelocInfo::kNoPosition), instruction_pending_deoptimization_environment_(NULL), @@ -2750,7 +2749,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { LPlatformChunk* chunk() const { return chunk_; } CompilationInfo* info() const { return info_; } HGraph* graph() const { return graph_; } - Zone* zone() const { return zone_; } bool is_unused() const { return status_ == UNUSED; } bool is_building() const { return status_ == BUILDING; } @@ -2800,7 +2798,7 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { // An input operand in register, stack slot or a constant operand. // Will not be moved to a register even if one is freely available. - MUST_USE_RESULT LOperand* UseAny(HValue* value); + virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) V8_OVERRIDE; // Temporary operand that must be in a register. MUST_USE_RESULT LUnallocated* TempRegister(); @@ -2838,10 +2836,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { HInstruction* hinstr, CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); - LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList* objects_to_materialize); - void VisitInstruction(HInstruction* current); void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block); @@ -2854,12 +2848,10 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { LPlatformChunk* chunk_; CompilationInfo* info_; HGraph* const graph_; - Zone* zone_; Status status_; HInstruction* current_instruction_; HBasicBlock* current_block_; HBasicBlock* next_block_; - int argument_count_; LAllocator* allocator_; int position_; LInstruction* instruction_pending_deoptimization_environment_; diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 6bf6179dee..2649b618c1 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -1000,90 +1000,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { } -LEnvironment* LChunkBuilder::CreateEnvironment( - HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList* objects_to_materialize) { - if (hydrogen_env == NULL) return NULL; - - LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(), - argument_index_accumulator, - objects_to_materialize); - BailoutId ast_id = hydrogen_env->ast_id(); - ASSERT(!ast_id.IsNone() || - hydrogen_env->frame_type() != JS_FUNCTION); - int value_count = hydrogen_env->length() - hydrogen_env->specials_count(); - LEnvironment* result = - new(zone()) LEnvironment(hydrogen_env->closure(), - hydrogen_env->frame_type(), - ast_id, - hydrogen_env->parameter_count(), - argument_count_, - value_count, - outer, - hydrogen_env->entry(), - zone()); - int argument_index = *argument_index_accumulator; - int object_index = objects_to_materialize->length(); - for (int i = 0; i < hydrogen_env->length(); ++i) { - if (hydrogen_env->is_special_index(i)) continue; - - LOperand* op; - HValue* value = hydrogen_env->values()->at(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else if (value->IsPushArgument()) { - op = new(zone()) LArgument(argument_index++); - } else { - op = UseAny(value); - } - result->AddValue(op, - value->representation(), - value->CheckFlag(HInstruction::kUint32)); - } - - for (int i = object_index; i < objects_to_materialize->length(); ++i) { - HValue* object_to_materialize = objects_to_materialize->at(i); - int previously_materialized_object = -1; - for (int prev = 0; prev < i; ++prev) { - if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) { - previously_materialized_object = prev; - break; - } - } - int length = object_to_materialize->OperandCount(); - bool is_arguments = object_to_materialize->IsArgumentsObject(); - if (previously_materialized_object >= 0) { - result->AddDuplicateObject(previously_materialized_object); - continue; - } else { - result->AddNewObject(is_arguments ? length - 1 : length, is_arguments); - } - for (int i = is_arguments ? 1 : 0; i < length; ++i) { - LOperand* op; - HValue* value = object_to_materialize->OperandAt(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else { - ASSERT(!value->IsPushArgument()); - op = UseAny(value); - } - result->AddValue(op, - value->representation(), - value->CheckFlag(HInstruction::kUint32)); - } - } - - if (hydrogen_env->frame_type() == JS_FUNCTION) { - *argument_index_accumulator = argument_index; - } - - return result; -} - - LInstruction* LChunkBuilder::DoGoto(HGoto* instr) { return new(zone()) LGoto(instr->FirstSuccessor()); } diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 31a1e624ec..62815f33b9 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -2712,18 +2712,17 @@ class LPlatformChunk V8_FINAL : public LChunk { }; -class LChunkBuilder V8_FINAL BASE_EMBEDDED { +class LChunkBuilder V8_FINAL : public LChunkBuilderBase { public: LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator) - : chunk_(NULL), + : LChunkBuilderBase(graph->zone()), + chunk_(NULL), info_(info), graph_(graph), - zone_(graph->zone()), status_(UNUSED), current_instruction_(NULL), current_block_(NULL), next_block_(NULL), - argument_count_(0), allocator_(allocator), instruction_pending_deoptimization_environment_(NULL), pending_deoptimization_ast_id_(BailoutId::None()) { } @@ -2759,7 +2758,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { LPlatformChunk* chunk() const { return chunk_; } CompilationInfo* info() const { return info_; } HGraph* graph() const { return graph_; } - Zone* zone() const { return zone_; } bool is_unused() const { return status_ == UNUSED; } bool is_building() const { return status_ == BUILDING; } @@ -2814,7 +2812,7 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { // An input operand in register, stack slot or a constant operand. // Will not be moved to a register even if one is freely available. - MUST_USE_RESULT LOperand* UseAny(HValue* value); + virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) V8_OVERRIDE; // Temporary operand that must be in a register. MUST_USE_RESULT LUnallocated* TempRegister(); @@ -2860,10 +2858,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { HInstruction* hinstr, CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); - LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList* objects_to_materialize); - void VisitInstruction(HInstruction* current); void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block); @@ -2878,12 +2872,10 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { LPlatformChunk* chunk_; CompilationInfo* info_; HGraph* const graph_; - Zone* zone_; Status status_; HInstruction* current_instruction_; HBasicBlock* current_block_; HBasicBlock* next_block_; - int argument_count_; LAllocator* allocator_; LInstruction* instruction_pending_deoptimization_environment_; BailoutId pending_deoptimization_ast_id_; diff --git a/src/lithium.cc b/src/lithium.cc index 414d5f4ede..b2fb4ead7c 100644 --- a/src/lithium.cc +++ b/src/lithium.cc @@ -463,6 +463,139 @@ void LChunk::set_allocated_double_registers(BitVector* allocated_registers) { } +LEnvironment* LChunkBuilderBase::CreateEnvironment( + HEnvironment* hydrogen_env, + int* argument_index_accumulator, + ZoneList* objects_to_materialize) { + if (hydrogen_env == NULL) return NULL; + + LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(), + argument_index_accumulator, + objects_to_materialize); + BailoutId ast_id = hydrogen_env->ast_id(); + ASSERT(!ast_id.IsNone() || + hydrogen_env->frame_type() != JS_FUNCTION); + int value_count = hydrogen_env->length() - hydrogen_env->specials_count(); + LEnvironment* result = + new(zone()) LEnvironment(hydrogen_env->closure(), + hydrogen_env->frame_type(), + ast_id, + hydrogen_env->parameter_count(), + argument_count_, + value_count, + outer, + hydrogen_env->entry(), + zone()); + int argument_index = *argument_index_accumulator; + + // Store the environment description into the environment + // (with holes for nested objects) + for (int i = 0; i < hydrogen_env->length(); ++i) { + if (hydrogen_env->is_special_index(i)) continue; + + LOperand* op; + HValue* value = hydrogen_env->values()->at(i); + if (value->IsArgumentsObject() || value->IsCapturedObject()) { + op = LEnvironment::materialization_marker(); + } else if (value->IsPushArgument()) { + op = new(zone()) LArgument(argument_index++); + } else { + op = UseAny(value); + } + result->AddValue(op, + value->representation(), + value->CheckFlag(HInstruction::kUint32)); + } + + // Recursively store the nested objects into the environment + for (int i = 0; i < hydrogen_env->length(); ++i) { + if (hydrogen_env->is_special_index(i)) continue; + + HValue* value = hydrogen_env->values()->at(i); + if (value->IsArgumentsObject() || value->IsCapturedObject()) { + AddObjectToMaterialize(value, objects_to_materialize, result); + } + } + + if (hydrogen_env->frame_type() == JS_FUNCTION) { + *argument_index_accumulator = argument_index; + } + + return result; +} + + +// Add an object to the supplied environment and object materialization list. +// +// Notes: +// +// We are building three lists here: +// +// 1. In the result->object_mapping_ list (added to by the +// LEnvironment::Add*Object methods), we store the lengths (number +// of fields) of the captured objects in depth-first traversal order, or +// in case of duplicated objects, we store the index to the duplicate object +// (with a tag to differentiate between captured and duplicated objects). +// +// 2. The object fields are stored in the result->values_ list +// (added to by the LEnvironment.AddValue method) sequentially as lists +// of fields with holes for nested objects (the holes will be expanded +// later by LCodegen::AddToTranslation according to the +// LEnvironment.object_mapping_ list). +// +// 3. The auxiliary objects_to_materialize array stores the hydrogen values +// in the same order as result->object_mapping_ list. This is used +// to detect duplicate values and calculate the corresponding object index. +void LChunkBuilderBase::AddObjectToMaterialize(HValue* value, + ZoneList* objects_to_materialize, LEnvironment* result) { + int object_index = objects_to_materialize->length(); + // Store the hydrogen value into the de-duplication array + objects_to_materialize->Add(value, zone()); + // Find out whether we are storing a duplicated value + int previously_materialized_object = -1; + for (int prev = 0; prev < object_index; ++prev) { + if (objects_to_materialize->at(prev) == value) { + previously_materialized_object = prev; + break; + } + } + // Store the captured object length (or duplicated object index) + // into the environment. For duplicated objects, we stop here. + int length = value->OperandCount(); + bool is_arguments = value->IsArgumentsObject(); + if (previously_materialized_object >= 0) { + result->AddDuplicateObject(previously_materialized_object); + return; + } else { + result->AddNewObject(is_arguments ? length - 1 : length, is_arguments); + } + // Store the captured object's fields into the environment + for (int i = is_arguments ? 1 : 0; i < length; ++i) { + LOperand* op; + HValue* arg_value = value->OperandAt(i); + if (arg_value->IsArgumentsObject() || arg_value->IsCapturedObject()) { + // Insert a hole for nested objects + op = LEnvironment::materialization_marker(); + } else { + ASSERT(!arg_value->IsPushArgument()); + // For ordinary values, tell the register allocator we need the value + // to be alive here + op = UseAny(arg_value); + } + result->AddValue(op, + arg_value->representation(), + arg_value->CheckFlag(HInstruction::kUint32)); + } + // Recursively store all the nested captured objects into the environment + for (int i = is_arguments ? 1 : 0; i < length; ++i) { + HValue* arg_value = value->OperandAt(i); + if (arg_value->IsArgumentsObject() || arg_value->IsCapturedObject()) { + AddObjectToMaterialize(arg_value, objects_to_materialize, result); + } + } +} + + LInstruction* LChunkBuilder::CheckElideControlInstruction( HControlInstruction* instr) { HBasicBlock* successor; diff --git a/src/lithium.h b/src/lithium.h index d4395f2d7e..754f88da82 100644 --- a/src/lithium.h +++ b/src/lithium.h @@ -791,6 +791,35 @@ class LChunk : public ZoneObject { }; +class LChunkBuilderBase BASE_EMBEDDED { + public: + explicit LChunkBuilderBase(Zone* zone) + : argument_count_(0), + zone_(zone) { } + + virtual ~LChunkBuilderBase() { } + + protected: + // An input operand in register, stack slot or a constant operand. + // Will not be moved to a register even if one is freely available. + virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0; + + LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, + int* argument_index_accumulator, + ZoneList* objects_to_materialize); + void AddObjectToMaterialize(HValue* value, + ZoneList* objects_to_materialize, + LEnvironment* result); + + Zone* zone() const { return zone_; } + + int argument_count_; + + private: + Zone* zone_; +}; + + int StackSlotOffset(int index); enum NumberUntagDMode { diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index 155ef6309c..7ad3a97f5c 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -934,90 +934,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { } -LEnvironment* LChunkBuilder::CreateEnvironment( - HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList* objects_to_materialize) { - if (hydrogen_env == NULL) return NULL; - - LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(), - argument_index_accumulator, - objects_to_materialize); - BailoutId ast_id = hydrogen_env->ast_id(); - ASSERT(!ast_id.IsNone() || - hydrogen_env->frame_type() != JS_FUNCTION); - int value_count = hydrogen_env->length() - hydrogen_env->specials_count(); - LEnvironment* result = new(zone()) LEnvironment( - hydrogen_env->closure(), - hydrogen_env->frame_type(), - ast_id, - hydrogen_env->parameter_count(), - argument_count_, - value_count, - outer, - hydrogen_env->entry(), - zone()); - int argument_index = *argument_index_accumulator; - int object_index = objects_to_materialize->length(); - for (int i = 0; i < hydrogen_env->length(); ++i) { - if (hydrogen_env->is_special_index(i)) continue; - - LOperand* op; - HValue* value = hydrogen_env->values()->at(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else if (value->IsPushArgument()) { - op = new(zone()) LArgument(argument_index++); - } else { - op = UseAny(value); - } - result->AddValue(op, - value->representation(), - value->CheckFlag(HInstruction::kUint32)); - } - - for (int i = object_index; i < objects_to_materialize->length(); ++i) { - HValue* object_to_materialize = objects_to_materialize->at(i); - int previously_materialized_object = -1; - for (int prev = 0; prev < i; ++prev) { - if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) { - previously_materialized_object = prev; - break; - } - } - int length = object_to_materialize->OperandCount(); - bool is_arguments = object_to_materialize->IsArgumentsObject(); - if (previously_materialized_object >= 0) { - result->AddDuplicateObject(previously_materialized_object); - continue; - } else { - result->AddNewObject(is_arguments ? length - 1 : length, is_arguments); - } - for (int i = is_arguments ? 1 : 0; i < length; ++i) { - LOperand* op; - HValue* value = object_to_materialize->OperandAt(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else { - ASSERT(!value->IsPushArgument()); - op = UseAny(value); - } - result->AddValue(op, - value->representation(), - value->CheckFlag(HInstruction::kUint32)); - } - } - - if (hydrogen_env->frame_type() == JS_FUNCTION) { - *argument_index_accumulator = argument_index; - } - - return result; -} - - LInstruction* LChunkBuilder::DoGoto(HGoto* instr) { return new(zone()) LGoto(instr->FirstSuccessor()); } diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h index f0a75c1dab..0cb21a65b0 100644 --- a/src/mips/lithium-mips.h +++ b/src/mips/lithium-mips.h @@ -2673,18 +2673,17 @@ class LPlatformChunk V8_FINAL : public LChunk { }; -class LChunkBuilder V8_FINAL BASE_EMBEDDED { +class LChunkBuilder V8_FINAL : public LChunkBuilderBase { public: LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator) - : chunk_(NULL), + : LChunkBuilderBase(graph->zone()), + chunk_(NULL), info_(info), graph_(graph), - zone_(graph->zone()), status_(UNUSED), current_instruction_(NULL), current_block_(NULL), next_block_(NULL), - argument_count_(0), allocator_(allocator), position_(RelocInfo::kNoPosition), instruction_pending_deoptimization_environment_(NULL), @@ -2724,7 +2723,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { LPlatformChunk* chunk() const { return chunk_; } CompilationInfo* info() const { return info_; } HGraph* graph() const { return graph_; } - Zone* zone() const { return zone_; } bool is_unused() const { return status_ == UNUSED; } bool is_building() const { return status_ == BUILDING; } @@ -2774,7 +2772,7 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { // An input operand in register, stack slot or a constant operand. // Will not be moved to a register even if one is freely available. - MUST_USE_RESULT LOperand* UseAny(HValue* value); + virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) V8_OVERRIDE; // Temporary operand that must be in a register. MUST_USE_RESULT LUnallocated* TempRegister(); @@ -2812,10 +2810,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { HInstruction* hinstr, CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); - LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList* objects_to_materialize); - void VisitInstruction(HInstruction* current); void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block); @@ -2829,12 +2823,10 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { LPlatformChunk* chunk_; CompilationInfo* info_; HGraph* const graph_; - Zone* zone_; Status status_; HInstruction* current_instruction_; HBasicBlock* current_block_; HBasicBlock* next_block_; - int argument_count_; LAllocator* allocator_; int position_; LInstruction* instruction_pending_deoptimization_environment_; diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index 6388863868..93b1f8786c 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -936,90 +936,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) { } -LEnvironment* LChunkBuilder::CreateEnvironment( - HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList* objects_to_materialize) { - if (hydrogen_env == NULL) return NULL; - - LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(), - argument_index_accumulator, - objects_to_materialize); - BailoutId ast_id = hydrogen_env->ast_id(); - ASSERT(!ast_id.IsNone() || - hydrogen_env->frame_type() != JS_FUNCTION); - int value_count = hydrogen_env->length() - hydrogen_env->specials_count(); - LEnvironment* result = new(zone()) LEnvironment( - hydrogen_env->closure(), - hydrogen_env->frame_type(), - ast_id, - hydrogen_env->parameter_count(), - argument_count_, - value_count, - outer, - hydrogen_env->entry(), - zone()); - int argument_index = *argument_index_accumulator; - int object_index = objects_to_materialize->length(); - for (int i = 0; i < hydrogen_env->length(); ++i) { - if (hydrogen_env->is_special_index(i)) continue; - - LOperand* op; - HValue* value = hydrogen_env->values()->at(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else if (value->IsPushArgument()) { - op = new(zone()) LArgument(argument_index++); - } else { - op = UseAny(value); - } - result->AddValue(op, - value->representation(), - value->CheckFlag(HInstruction::kUint32)); - } - - for (int i = object_index; i < objects_to_materialize->length(); ++i) { - HValue* object_to_materialize = objects_to_materialize->at(i); - int previously_materialized_object = -1; - for (int prev = 0; prev < i; ++prev) { - if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) { - previously_materialized_object = prev; - break; - } - } - int length = object_to_materialize->OperandCount(); - bool is_arguments = object_to_materialize->IsArgumentsObject(); - if (previously_materialized_object >= 0) { - result->AddDuplicateObject(previously_materialized_object); - continue; - } else { - result->AddNewObject(is_arguments ? length - 1 : length, is_arguments); - } - for (int i = is_arguments ? 1 : 0; i < length; ++i) { - LOperand* op; - HValue* value = object_to_materialize->OperandAt(i); - if (value->IsArgumentsObject() || value->IsCapturedObject()) { - objects_to_materialize->Add(value, zone()); - op = LEnvironment::materialization_marker(); - } else { - ASSERT(!value->IsPushArgument()); - op = UseAny(value); - } - result->AddValue(op, - value->representation(), - value->CheckFlag(HInstruction::kUint32)); - } - } - - if (hydrogen_env->frame_type() == JS_FUNCTION) { - *argument_index_accumulator = argument_index; - } - - return result; -} - - LInstruction* LChunkBuilder::DoGoto(HGoto* instr) { return new(zone()) LGoto(instr->FirstSuccessor()); } diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index 962000ad43..b04d607624 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -2630,18 +2630,17 @@ class LPlatformChunk V8_FINAL : public LChunk { }; -class LChunkBuilder V8_FINAL BASE_EMBEDDED { +class LChunkBuilder V8_FINAL : public LChunkBuilderBase { public: LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator) - : chunk_(NULL), + : LChunkBuilderBase(graph->zone()), + chunk_(NULL), info_(info), graph_(graph), - zone_(graph->zone()), status_(UNUSED), current_instruction_(NULL), current_block_(NULL), next_block_(NULL), - argument_count_(0), allocator_(allocator), instruction_pending_deoptimization_environment_(NULL), pending_deoptimization_ast_id_(BailoutId::None()) { } @@ -2677,7 +2676,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { LPlatformChunk* chunk() const { return chunk_; } CompilationInfo* info() const { return info_; } HGraph* graph() const { return graph_; } - Zone* zone() const { return zone_; } bool is_unused() const { return status_ == UNUSED; } bool is_building() const { return status_ == BUILDING; } @@ -2730,7 +2728,7 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { // An input operand in register, stack slot or a constant operand. // Will not be moved to a register even if one is freely available. - MUST_USE_RESULT LOperand* UseAny(HValue* value); + virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) V8_OVERRIDE; // Temporary operand that must be in a register. MUST_USE_RESULT LUnallocated* TempRegister(); @@ -2772,10 +2770,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { HInstruction* hinstr, CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY); - LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, - int* argument_index_accumulator, - ZoneList* objects_to_materialize); - void VisitInstruction(HInstruction* current); void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block); @@ -2788,12 +2782,10 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED { LPlatformChunk* chunk_; CompilationInfo* info_; HGraph* const graph_; - Zone* zone_; Status status_; HInstruction* current_instruction_; HBasicBlock* current_block_; HBasicBlock* next_block_; - int argument_count_; LAllocator* allocator_; LInstruction* instruction_pending_deoptimization_environment_; BailoutId pending_deoptimization_ast_id_; diff --git a/test/mjsunit/compiler/escape-analysis.js b/test/mjsunit/compiler/escape-analysis.js index dccc476925..b12e7bfca0 100644 --- a/test/mjsunit/compiler/escape-analysis.js +++ b/test/mjsunit/compiler/escape-analysis.js @@ -303,6 +303,101 @@ })(); +// Test non-shallow nested graph of captured objects with duplicates +(function testDeepDuplicate() { + function constructor1() { + this.x = 23; + } + function constructor2(nested) { + this.a = 17; + this.b = nested; + this.c = 42; + } + function deep(shouldDeopt) { + var o1 = new constructor1(); + var o2 = new constructor2(o1); + var o3 = new constructor2(o1); + assertEquals(17, o2.a); + assertEquals(23, o2.b.x); + assertEquals(42, o2.c); + o3.c = 54; + o1.x = 99; + if (shouldDeopt) %DeoptimizeFunction(deep); + assertEquals(99, o1.x); + assertEquals(99, o2.b.x); + assertEquals(99, o3.b.x); + assertEquals(54, o3.c); + assertEquals(17, o3.a); + assertEquals(42, o2.c); + assertEquals(17, o2.a); + o3.b.x = 1; + assertEquals(1, o1.x); + } + deep(false); deep(false); + %OptimizeFunctionOnNextCall(deep); + deep(false); deep(false); + deep(true); deep(true); +})(); + + +// Test non-shallow nested graph of captured objects with inline +(function testDeepInline() { + function h() { + return { y : 3 }; + } + + function g(x) { + var u = { x : h() }; + %DeoptimizeFunction(f); + return u; + } + + function f() { + var l = { dummy : { } }; + var r = g(l); + assertEquals(3, r.x.y); + } + + f(); f(); f(); + %OptimizeFunctionOnNextCall(f); + f(); +})(); + + +// Test two nested objects +(function testTwoNestedObjects() { + function f() { + var l = { x : { y : 111 } }; + var l2 = { x : { y : 111 } }; + %DeoptimizeFunction(f); + assertEquals(111, l.x.y); + assertEquals(111, l2.x.y); + } + + f(); f(); f(); + %OptimizeFunctionOnNextCall(f); + f(); +})(); + + +// Test a nested object and a duplicate +(function testTwoObjectsWithDuplicate() { + function f() { + var l = { x : { y : 111 } }; + var dummy = { d : 0 }; + var l2 = l.x; + %DeoptimizeFunction(f); + assertEquals(111, l.x.y); + assertEquals(111, l2.y); + assertEquals(0, dummy.d); + } + + f(); f(); f(); + %OptimizeFunctionOnNextCall(f); + f(); +})(); + + // Test materialization of a field that requires a Smi value. (function testSmiField() { var deopt = { deopt:false };