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:
mstarzinger@chromium.org 2013-08-26 16:43:19 +00:00
parent 67b6605c5e
commit e146b6e148
10 changed files with 88 additions and 17 deletions

View File

@ -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;
} }

View File

@ -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.

View File

@ -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_;

View File

@ -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());

View File

@ -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_;
}; };

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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();
})();

View File

@ -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