Fixed Lithium environment generation bug for captured objects (created
by escape analysis). Added several tests that expose the bug. Summary: LCodegen::AddToTranslation assumes that Lithium environments are generated by depth-first traversal, but LChunkBuilder::CreateEnvironment was generating them in breadth-first fashion. This fixes the CreateEnvironment to traverse the captured objects depth-first. Note: It might be worth considering representing LEnvironment by a list with the same order as the serialized translation representation rather than having two lists with a subtle relationship between them (and then serialize in a slightly different order again). R=titzer@chromium.org, mstarzinger@chromium.org LOG=N BUG= Review URL: https://codereview.chromium.org/93803003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18470 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
d8e9893c59
commit
acf24331e3
@ -926,90 +926,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LEnvironment* LChunkBuilder::CreateEnvironment(
|
|
||||||
HEnvironment* hydrogen_env,
|
|
||||||
int* argument_index_accumulator,
|
|
||||||
ZoneList<HValue*>* 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) {
|
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
|
||||||
return new(zone()) LGoto(instr->FirstSuccessor());
|
return new(zone()) LGoto(instr->FirstSuccessor());
|
||||||
}
|
}
|
||||||
|
@ -2697,18 +2697,17 @@ class LPlatformChunk V8_FINAL : public LChunk {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
|
||||||
public:
|
public:
|
||||||
LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
|
LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
|
||||||
: chunk_(NULL),
|
: LChunkBuilderBase(graph->zone()),
|
||||||
|
chunk_(NULL),
|
||||||
info_(info),
|
info_(info),
|
||||||
graph_(graph),
|
graph_(graph),
|
||||||
zone_(graph->zone()),
|
|
||||||
status_(UNUSED),
|
status_(UNUSED),
|
||||||
current_instruction_(NULL),
|
current_instruction_(NULL),
|
||||||
current_block_(NULL),
|
current_block_(NULL),
|
||||||
next_block_(NULL),
|
next_block_(NULL),
|
||||||
argument_count_(0),
|
|
||||||
allocator_(allocator),
|
allocator_(allocator),
|
||||||
position_(RelocInfo::kNoPosition),
|
position_(RelocInfo::kNoPosition),
|
||||||
instruction_pending_deoptimization_environment_(NULL),
|
instruction_pending_deoptimization_environment_(NULL),
|
||||||
@ -2750,7 +2749,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
LPlatformChunk* chunk() const { return chunk_; }
|
LPlatformChunk* chunk() const { return chunk_; }
|
||||||
CompilationInfo* info() const { return info_; }
|
CompilationInfo* info() const { return info_; }
|
||||||
HGraph* graph() const { return graph_; }
|
HGraph* graph() const { return graph_; }
|
||||||
Zone* zone() const { return zone_; }
|
|
||||||
|
|
||||||
bool is_unused() const { return status_ == UNUSED; }
|
bool is_unused() const { return status_ == UNUSED; }
|
||||||
bool is_building() const { return status_ == BUILDING; }
|
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.
|
// An input operand in register, stack slot or a constant operand.
|
||||||
// Will not be moved to a register even if one is freely available.
|
// 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.
|
// Temporary operand that must be in a register.
|
||||||
MUST_USE_RESULT LUnallocated* TempRegister();
|
MUST_USE_RESULT LUnallocated* TempRegister();
|
||||||
@ -2838,10 +2836,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
HInstruction* hinstr,
|
HInstruction* hinstr,
|
||||||
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
|
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
|
||||||
|
|
||||||
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
|
|
||||||
int* argument_index_accumulator,
|
|
||||||
ZoneList<HValue*>* objects_to_materialize);
|
|
||||||
|
|
||||||
void VisitInstruction(HInstruction* current);
|
void VisitInstruction(HInstruction* current);
|
||||||
|
|
||||||
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
|
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
|
||||||
@ -2854,12 +2848,10 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
LPlatformChunk* chunk_;
|
LPlatformChunk* chunk_;
|
||||||
CompilationInfo* info_;
|
CompilationInfo* info_;
|
||||||
HGraph* const graph_;
|
HGraph* const graph_;
|
||||||
Zone* zone_;
|
|
||||||
Status status_;
|
Status status_;
|
||||||
HInstruction* current_instruction_;
|
HInstruction* current_instruction_;
|
||||||
HBasicBlock* current_block_;
|
HBasicBlock* current_block_;
|
||||||
HBasicBlock* next_block_;
|
HBasicBlock* next_block_;
|
||||||
int argument_count_;
|
|
||||||
LAllocator* allocator_;
|
LAllocator* allocator_;
|
||||||
int position_;
|
int position_;
|
||||||
LInstruction* instruction_pending_deoptimization_environment_;
|
LInstruction* instruction_pending_deoptimization_environment_;
|
||||||
|
@ -1000,90 +1000,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LEnvironment* LChunkBuilder::CreateEnvironment(
|
|
||||||
HEnvironment* hydrogen_env,
|
|
||||||
int* argument_index_accumulator,
|
|
||||||
ZoneList<HValue*>* 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) {
|
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
|
||||||
return new(zone()) LGoto(instr->FirstSuccessor());
|
return new(zone()) LGoto(instr->FirstSuccessor());
|
||||||
}
|
}
|
||||||
|
@ -2712,18 +2712,17 @@ class LPlatformChunk V8_FINAL : public LChunk {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
|
||||||
public:
|
public:
|
||||||
LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
|
LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
|
||||||
: chunk_(NULL),
|
: LChunkBuilderBase(graph->zone()),
|
||||||
|
chunk_(NULL),
|
||||||
info_(info),
|
info_(info),
|
||||||
graph_(graph),
|
graph_(graph),
|
||||||
zone_(graph->zone()),
|
|
||||||
status_(UNUSED),
|
status_(UNUSED),
|
||||||
current_instruction_(NULL),
|
current_instruction_(NULL),
|
||||||
current_block_(NULL),
|
current_block_(NULL),
|
||||||
next_block_(NULL),
|
next_block_(NULL),
|
||||||
argument_count_(0),
|
|
||||||
allocator_(allocator),
|
allocator_(allocator),
|
||||||
instruction_pending_deoptimization_environment_(NULL),
|
instruction_pending_deoptimization_environment_(NULL),
|
||||||
pending_deoptimization_ast_id_(BailoutId::None()) { }
|
pending_deoptimization_ast_id_(BailoutId::None()) { }
|
||||||
@ -2759,7 +2758,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
LPlatformChunk* chunk() const { return chunk_; }
|
LPlatformChunk* chunk() const { return chunk_; }
|
||||||
CompilationInfo* info() const { return info_; }
|
CompilationInfo* info() const { return info_; }
|
||||||
HGraph* graph() const { return graph_; }
|
HGraph* graph() const { return graph_; }
|
||||||
Zone* zone() const { return zone_; }
|
|
||||||
|
|
||||||
bool is_unused() const { return status_ == UNUSED; }
|
bool is_unused() const { return status_ == UNUSED; }
|
||||||
bool is_building() const { return status_ == BUILDING; }
|
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.
|
// An input operand in register, stack slot or a constant operand.
|
||||||
// Will not be moved to a register even if one is freely available.
|
// 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.
|
// Temporary operand that must be in a register.
|
||||||
MUST_USE_RESULT LUnallocated* TempRegister();
|
MUST_USE_RESULT LUnallocated* TempRegister();
|
||||||
@ -2860,10 +2858,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
HInstruction* hinstr,
|
HInstruction* hinstr,
|
||||||
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
|
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
|
||||||
|
|
||||||
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
|
|
||||||
int* argument_index_accumulator,
|
|
||||||
ZoneList<HValue*>* objects_to_materialize);
|
|
||||||
|
|
||||||
void VisitInstruction(HInstruction* current);
|
void VisitInstruction(HInstruction* current);
|
||||||
|
|
||||||
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
|
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
|
||||||
@ -2878,12 +2872,10 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
LPlatformChunk* chunk_;
|
LPlatformChunk* chunk_;
|
||||||
CompilationInfo* info_;
|
CompilationInfo* info_;
|
||||||
HGraph* const graph_;
|
HGraph* const graph_;
|
||||||
Zone* zone_;
|
|
||||||
Status status_;
|
Status status_;
|
||||||
HInstruction* current_instruction_;
|
HInstruction* current_instruction_;
|
||||||
HBasicBlock* current_block_;
|
HBasicBlock* current_block_;
|
||||||
HBasicBlock* next_block_;
|
HBasicBlock* next_block_;
|
||||||
int argument_count_;
|
|
||||||
LAllocator* allocator_;
|
LAllocator* allocator_;
|
||||||
LInstruction* instruction_pending_deoptimization_environment_;
|
LInstruction* instruction_pending_deoptimization_environment_;
|
||||||
BailoutId pending_deoptimization_ast_id_;
|
BailoutId pending_deoptimization_ast_id_;
|
||||||
|
133
src/lithium.cc
133
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<HValue*>* 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<HValue*>* 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(
|
LInstruction* LChunkBuilder::CheckElideControlInstruction(
|
||||||
HControlInstruction* instr) {
|
HControlInstruction* instr) {
|
||||||
HBasicBlock* successor;
|
HBasicBlock* successor;
|
||||||
|
@ -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<HValue*>* objects_to_materialize);
|
||||||
|
void AddObjectToMaterialize(HValue* value,
|
||||||
|
ZoneList<HValue*>* objects_to_materialize,
|
||||||
|
LEnvironment* result);
|
||||||
|
|
||||||
|
Zone* zone() const { return zone_; }
|
||||||
|
|
||||||
|
int argument_count_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Zone* zone_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
int StackSlotOffset(int index);
|
int StackSlotOffset(int index);
|
||||||
|
|
||||||
enum NumberUntagDMode {
|
enum NumberUntagDMode {
|
||||||
|
@ -934,90 +934,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LEnvironment* LChunkBuilder::CreateEnvironment(
|
|
||||||
HEnvironment* hydrogen_env,
|
|
||||||
int* argument_index_accumulator,
|
|
||||||
ZoneList<HValue*>* 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) {
|
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
|
||||||
return new(zone()) LGoto(instr->FirstSuccessor());
|
return new(zone()) LGoto(instr->FirstSuccessor());
|
||||||
}
|
}
|
||||||
|
@ -2673,18 +2673,17 @@ class LPlatformChunk V8_FINAL : public LChunk {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
|
||||||
public:
|
public:
|
||||||
LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
|
LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
|
||||||
: chunk_(NULL),
|
: LChunkBuilderBase(graph->zone()),
|
||||||
|
chunk_(NULL),
|
||||||
info_(info),
|
info_(info),
|
||||||
graph_(graph),
|
graph_(graph),
|
||||||
zone_(graph->zone()),
|
|
||||||
status_(UNUSED),
|
status_(UNUSED),
|
||||||
current_instruction_(NULL),
|
current_instruction_(NULL),
|
||||||
current_block_(NULL),
|
current_block_(NULL),
|
||||||
next_block_(NULL),
|
next_block_(NULL),
|
||||||
argument_count_(0),
|
|
||||||
allocator_(allocator),
|
allocator_(allocator),
|
||||||
position_(RelocInfo::kNoPosition),
|
position_(RelocInfo::kNoPosition),
|
||||||
instruction_pending_deoptimization_environment_(NULL),
|
instruction_pending_deoptimization_environment_(NULL),
|
||||||
@ -2724,7 +2723,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
LPlatformChunk* chunk() const { return chunk_; }
|
LPlatformChunk* chunk() const { return chunk_; }
|
||||||
CompilationInfo* info() const { return info_; }
|
CompilationInfo* info() const { return info_; }
|
||||||
HGraph* graph() const { return graph_; }
|
HGraph* graph() const { return graph_; }
|
||||||
Zone* zone() const { return zone_; }
|
|
||||||
|
|
||||||
bool is_unused() const { return status_ == UNUSED; }
|
bool is_unused() const { return status_ == UNUSED; }
|
||||||
bool is_building() const { return status_ == BUILDING; }
|
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.
|
// An input operand in register, stack slot or a constant operand.
|
||||||
// Will not be moved to a register even if one is freely available.
|
// 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.
|
// Temporary operand that must be in a register.
|
||||||
MUST_USE_RESULT LUnallocated* TempRegister();
|
MUST_USE_RESULT LUnallocated* TempRegister();
|
||||||
@ -2812,10 +2810,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
HInstruction* hinstr,
|
HInstruction* hinstr,
|
||||||
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
|
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
|
||||||
|
|
||||||
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
|
|
||||||
int* argument_index_accumulator,
|
|
||||||
ZoneList<HValue*>* objects_to_materialize);
|
|
||||||
|
|
||||||
void VisitInstruction(HInstruction* current);
|
void VisitInstruction(HInstruction* current);
|
||||||
|
|
||||||
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
|
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
|
||||||
@ -2829,12 +2823,10 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
LPlatformChunk* chunk_;
|
LPlatformChunk* chunk_;
|
||||||
CompilationInfo* info_;
|
CompilationInfo* info_;
|
||||||
HGraph* const graph_;
|
HGraph* const graph_;
|
||||||
Zone* zone_;
|
|
||||||
Status status_;
|
Status status_;
|
||||||
HInstruction* current_instruction_;
|
HInstruction* current_instruction_;
|
||||||
HBasicBlock* current_block_;
|
HBasicBlock* current_block_;
|
||||||
HBasicBlock* next_block_;
|
HBasicBlock* next_block_;
|
||||||
int argument_count_;
|
|
||||||
LAllocator* allocator_;
|
LAllocator* allocator_;
|
||||||
int position_;
|
int position_;
|
||||||
LInstruction* instruction_pending_deoptimization_environment_;
|
LInstruction* instruction_pending_deoptimization_environment_;
|
||||||
|
@ -936,90 +936,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LEnvironment* LChunkBuilder::CreateEnvironment(
|
|
||||||
HEnvironment* hydrogen_env,
|
|
||||||
int* argument_index_accumulator,
|
|
||||||
ZoneList<HValue*>* 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) {
|
LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
|
||||||
return new(zone()) LGoto(instr->FirstSuccessor());
|
return new(zone()) LGoto(instr->FirstSuccessor());
|
||||||
}
|
}
|
||||||
|
@ -2630,18 +2630,17 @@ class LPlatformChunk V8_FINAL : public LChunk {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
class LChunkBuilder V8_FINAL : public LChunkBuilderBase {
|
||||||
public:
|
public:
|
||||||
LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
|
LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
|
||||||
: chunk_(NULL),
|
: LChunkBuilderBase(graph->zone()),
|
||||||
|
chunk_(NULL),
|
||||||
info_(info),
|
info_(info),
|
||||||
graph_(graph),
|
graph_(graph),
|
||||||
zone_(graph->zone()),
|
|
||||||
status_(UNUSED),
|
status_(UNUSED),
|
||||||
current_instruction_(NULL),
|
current_instruction_(NULL),
|
||||||
current_block_(NULL),
|
current_block_(NULL),
|
||||||
next_block_(NULL),
|
next_block_(NULL),
|
||||||
argument_count_(0),
|
|
||||||
allocator_(allocator),
|
allocator_(allocator),
|
||||||
instruction_pending_deoptimization_environment_(NULL),
|
instruction_pending_deoptimization_environment_(NULL),
|
||||||
pending_deoptimization_ast_id_(BailoutId::None()) { }
|
pending_deoptimization_ast_id_(BailoutId::None()) { }
|
||||||
@ -2677,7 +2676,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
LPlatformChunk* chunk() const { return chunk_; }
|
LPlatformChunk* chunk() const { return chunk_; }
|
||||||
CompilationInfo* info() const { return info_; }
|
CompilationInfo* info() const { return info_; }
|
||||||
HGraph* graph() const { return graph_; }
|
HGraph* graph() const { return graph_; }
|
||||||
Zone* zone() const { return zone_; }
|
|
||||||
|
|
||||||
bool is_unused() const { return status_ == UNUSED; }
|
bool is_unused() const { return status_ == UNUSED; }
|
||||||
bool is_building() const { return status_ == BUILDING; }
|
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.
|
// An input operand in register, stack slot or a constant operand.
|
||||||
// Will not be moved to a register even if one is freely available.
|
// 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.
|
// Temporary operand that must be in a register.
|
||||||
MUST_USE_RESULT LUnallocated* TempRegister();
|
MUST_USE_RESULT LUnallocated* TempRegister();
|
||||||
@ -2772,10 +2770,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
HInstruction* hinstr,
|
HInstruction* hinstr,
|
||||||
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
|
CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
|
||||||
|
|
||||||
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
|
|
||||||
int* argument_index_accumulator,
|
|
||||||
ZoneList<HValue*>* objects_to_materialize);
|
|
||||||
|
|
||||||
void VisitInstruction(HInstruction* current);
|
void VisitInstruction(HInstruction* current);
|
||||||
|
|
||||||
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
|
void DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block);
|
||||||
@ -2788,12 +2782,10 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
|
|||||||
LPlatformChunk* chunk_;
|
LPlatformChunk* chunk_;
|
||||||
CompilationInfo* info_;
|
CompilationInfo* info_;
|
||||||
HGraph* const graph_;
|
HGraph* const graph_;
|
||||||
Zone* zone_;
|
|
||||||
Status status_;
|
Status status_;
|
||||||
HInstruction* current_instruction_;
|
HInstruction* current_instruction_;
|
||||||
HBasicBlock* current_block_;
|
HBasicBlock* current_block_;
|
||||||
HBasicBlock* next_block_;
|
HBasicBlock* next_block_;
|
||||||
int argument_count_;
|
|
||||||
LAllocator* allocator_;
|
LAllocator* allocator_;
|
||||||
LInstruction* instruction_pending_deoptimization_environment_;
|
LInstruction* instruction_pending_deoptimization_environment_;
|
||||||
BailoutId pending_deoptimization_ast_id_;
|
BailoutId pending_deoptimization_ast_id_;
|
||||||
|
@ -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.
|
// Test materialization of a field that requires a Smi value.
|
||||||
(function testSmiField() {
|
(function testSmiField() {
|
||||||
var deopt = { deopt:false };
|
var deopt = { deopt:false };
|
||||||
|
Loading…
Reference in New Issue
Block a user