Fix replaying of captured objects during chunk building.
R=titzer@chromium.org Review URL: https://codereview.chromium.org/22819011 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16334 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
67b6605c5e
commit
e146b6e148
@ -2435,6 +2435,9 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
|
|||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
|
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
|
||||||
|
HEnvironment* env = current_block_->last_environment();
|
||||||
|
instr->ReplayEnvironment(env);
|
||||||
|
|
||||||
// There are no real uses of a captured object.
|
// There are no real uses of a captured object.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,8 @@ void HEscapeAnalysisPhase::CollectCapturedValues() {
|
|||||||
|
|
||||||
HCapturedObject* HEscapeAnalysisPhase::NewState(HInstruction* previous) {
|
HCapturedObject* HEscapeAnalysisPhase::NewState(HInstruction* previous) {
|
||||||
Zone* zone = graph()->zone();
|
Zone* zone = graph()->zone();
|
||||||
HCapturedObject* state = new(zone) HCapturedObject(number_of_values_, zone);
|
HCapturedObject* state =
|
||||||
|
new(zone) HCapturedObject(number_of_values_, number_of_objects_, zone);
|
||||||
state->InsertAfter(previous);
|
state->InsertAfter(previous);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@ -183,18 +184,9 @@ void HEscapeAnalysisPhase::AnalyzeDataFlow(HInstruction* allocate) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HValue::kSimulate: {
|
|
||||||
HSimulate* simulate = HSimulate::cast(instr);
|
|
||||||
// TODO(mstarzinger): This doesn't track deltas for values on the
|
|
||||||
// operand stack yet. Find a repro test case and fix this.
|
|
||||||
for (int i = 0; i < simulate->OperandCount(); i++) {
|
|
||||||
if (simulate->OperandAt(i) != allocate) continue;
|
|
||||||
simulate->SetOperandAt(i, state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case HValue::kArgumentsObject:
|
case HValue::kArgumentsObject:
|
||||||
case HValue::kCapturedObject: {
|
case HValue::kCapturedObject:
|
||||||
|
case HValue::kSimulate: {
|
||||||
for (int i = 0; i < instr->OperandCount(); i++) {
|
for (int i = 0; i < instr->OperandCount(); i++) {
|
||||||
if (instr->OperandAt(i) != allocate) continue;
|
if (instr->OperandAt(i) != allocate) continue;
|
||||||
instr->SetOperandAt(i, state);
|
instr->SetOperandAt(i, state);
|
||||||
@ -274,6 +266,7 @@ void HEscapeAnalysisPhase::PerformScalarReplacement() {
|
|||||||
if (!allocate->size()->IsInteger32Constant()) continue;
|
if (!allocate->size()->IsInteger32Constant()) continue;
|
||||||
int size_in_bytes = allocate->size()->GetInteger32Constant();
|
int size_in_bytes = allocate->size()->GetInteger32Constant();
|
||||||
number_of_values_ = size_in_bytes / kPointerSize;
|
number_of_values_ = size_in_bytes / kPointerSize;
|
||||||
|
number_of_objects_++;
|
||||||
block_states_.Clear();
|
block_states_.Clear();
|
||||||
|
|
||||||
// Perform actual analysis steps.
|
// Perform actual analysis steps.
|
||||||
|
@ -40,6 +40,7 @@ class HEscapeAnalysisPhase : public HPhase {
|
|||||||
explicit HEscapeAnalysisPhase(HGraph* graph)
|
explicit HEscapeAnalysisPhase(HGraph* graph)
|
||||||
: HPhase("H_Escape analysis", graph),
|
: HPhase("H_Escape analysis", graph),
|
||||||
captured_(0, zone()),
|
captured_(0, zone()),
|
||||||
|
number_of_objects_(0),
|
||||||
number_of_values_(0),
|
number_of_values_(0),
|
||||||
cumulative_values_(0),
|
cumulative_values_(0),
|
||||||
block_states_(graph->blocks()->length(), zone()) { }
|
block_states_(graph->blocks()->length(), zone()) { }
|
||||||
@ -73,6 +74,9 @@ class HEscapeAnalysisPhase : public HPhase {
|
|||||||
// List of allocations captured during collection phase.
|
// List of allocations captured during collection phase.
|
||||||
ZoneList<HInstruction*> captured_;
|
ZoneList<HInstruction*> captured_;
|
||||||
|
|
||||||
|
// Number of captured objects on which scalar replacement was done.
|
||||||
|
int number_of_objects_;
|
||||||
|
|
||||||
// Number of scalar values tracked during scalar replacement phase.
|
// Number of scalar values tracked during scalar replacement phase.
|
||||||
int number_of_values_;
|
int number_of_values_;
|
||||||
int cumulative_values_;
|
int cumulative_values_;
|
||||||
|
@ -2289,6 +2289,23 @@ void HSimulate::PrintDataTo(StringStream* stream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Replay captured objects by replacing all captured objects with the
|
||||||
|
// same capture id in the current and all outer environments.
|
||||||
|
void HCapturedObject::ReplayEnvironment(HEnvironment* env) {
|
||||||
|
ASSERT(env != NULL);
|
||||||
|
while (env != NULL) {
|
||||||
|
for (int i = 0; i < env->length(); ++i) {
|
||||||
|
HValue* value = env->values()->at(i);
|
||||||
|
if (value->IsCapturedObject() &&
|
||||||
|
HCapturedObject::cast(value)->capture_id() == this->capture_id()) {
|
||||||
|
env->SetValueAt(i, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
env = env->outer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void HEnterInlined::RegisterReturnTarget(HBasicBlock* return_target,
|
void HEnterInlined::RegisterReturnTarget(HBasicBlock* return_target,
|
||||||
Zone* zone) {
|
Zone* zone) {
|
||||||
ASSERT(return_target->IsInlineReturnTarget());
|
ASSERT(return_target->IsInlineReturnTarget());
|
||||||
|
@ -3208,8 +3208,8 @@ class HArgumentsObject V8_FINAL : public HDematerializedObject {
|
|||||||
|
|
||||||
class HCapturedObject V8_FINAL : public HDematerializedObject {
|
class HCapturedObject V8_FINAL : public HDematerializedObject {
|
||||||
public:
|
public:
|
||||||
HCapturedObject(int length, Zone* zone)
|
HCapturedObject(int length, int id, Zone* zone)
|
||||||
: HDematerializedObject(length, zone) {
|
: HDematerializedObject(length, zone), capture_id_(id) {
|
||||||
set_representation(Representation::Tagged());
|
set_representation(Representation::Tagged());
|
||||||
values_.AddBlock(NULL, length, zone); // Resize list.
|
values_.AddBlock(NULL, length, zone); // Resize list.
|
||||||
}
|
}
|
||||||
@ -3219,8 +3219,15 @@ class HCapturedObject V8_FINAL : public HDematerializedObject {
|
|||||||
// properties or elements backing store are not tracked here.
|
// properties or elements backing store are not tracked here.
|
||||||
const ZoneList<HValue*>* values() const { return &values_; }
|
const ZoneList<HValue*>* values() const { return &values_; }
|
||||||
int length() const { return values_.length(); }
|
int length() const { return values_.length(); }
|
||||||
|
int capture_id() const { return capture_id_; }
|
||||||
|
|
||||||
|
// Replay effects of this instruction on the given environment.
|
||||||
|
void ReplayEnvironment(HEnvironment* env);
|
||||||
|
|
||||||
DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
|
DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
|
||||||
|
|
||||||
|
private:
|
||||||
|
int capture_id_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -2564,6 +2564,9 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
|
|||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
|
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
|
||||||
|
HEnvironment* env = current_block_->last_environment();
|
||||||
|
instr->ReplayEnvironment(env);
|
||||||
|
|
||||||
// There are no real uses of a captured object.
|
// There are no real uses of a captured object.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -2361,6 +2361,9 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
|
|||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
|
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
|
||||||
|
HEnvironment* env = current_block_->last_environment();
|
||||||
|
instr->ReplayEnvironment(env);
|
||||||
|
|
||||||
// There are no real uses of a captured object.
|
// There are no real uses of a captured object.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -2374,6 +2374,9 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
|
|||||||
|
|
||||||
|
|
||||||
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
|
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
|
||||||
|
HEnvironment* env = current_block_->last_environment();
|
||||||
|
instr->ReplayEnvironment(env);
|
||||||
|
|
||||||
// There are no real uses of a captured object.
|
// There are no real uses of a captured object.
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -132,3 +132,44 @@
|
|||||||
delete deopt.deopt;
|
delete deopt.deopt;
|
||||||
func(); func();
|
func(); func();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
// Test deoptimization with captured objects on operand stack.
|
||||||
|
(function testDeoptOperand() {
|
||||||
|
var deopt = { deopt:false };
|
||||||
|
function constructor1() {
|
||||||
|
this.a = 1.0;
|
||||||
|
this.b = 2.3;
|
||||||
|
deopt.deopt;
|
||||||
|
assertEquals(1.0, this.a);
|
||||||
|
assertEquals(2.3, this.b);
|
||||||
|
this.b = 2.7;
|
||||||
|
this.c = 3.0;
|
||||||
|
this.d = 4.5;
|
||||||
|
}
|
||||||
|
function constructor2() {
|
||||||
|
this.e = 5.0;
|
||||||
|
this.f = new constructor1();
|
||||||
|
assertEquals(1.0, this.f.a);
|
||||||
|
assertEquals(2.7, this.f.b);
|
||||||
|
assertEquals(3.0, this.f.c);
|
||||||
|
assertEquals(4.5, this.f.d);
|
||||||
|
assertEquals(5.0, this.e);
|
||||||
|
this.e = 5.9;
|
||||||
|
this.g = 6.7;
|
||||||
|
}
|
||||||
|
function func() {
|
||||||
|
var o = new constructor2();
|
||||||
|
assertEquals(1.0, o.f.a);
|
||||||
|
assertEquals(2.7, o.f.b);
|
||||||
|
assertEquals(3.0, o.f.c);
|
||||||
|
assertEquals(4.5, o.f.d);
|
||||||
|
assertEquals(5.9, o.e);
|
||||||
|
assertEquals(6.7, o.g);
|
||||||
|
}
|
||||||
|
func(); func();
|
||||||
|
%OptimizeFunctionOnNextCall(func);
|
||||||
|
func(); func();
|
||||||
|
delete deopt.deopt;
|
||||||
|
func(); func();
|
||||||
|
})();
|
||||||
|
@ -251,8 +251,5 @@ harmony/object-observe: SKIP
|
|||||||
readonly: SKIP
|
readonly: SKIP
|
||||||
array-feedback: SKIP
|
array-feedback: SKIP
|
||||||
|
|
||||||
# TODO(mstarzinger): Enable once escape analysis is stabilized.
|
|
||||||
compiler/escape-analysis: SKIP
|
|
||||||
|
|
||||||
# Deopt every n garbage collections collides with the deopt every n times flag.
|
# Deopt every n garbage collections collides with the deopt every n times flag.
|
||||||
regress/regress-2653: SKIP
|
regress/regress-2653: SKIP
|
||||||
|
Loading…
Reference in New Issue
Block a user