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
parent 67b6605c
......@@ -2435,6 +2435,9 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
HEnvironment* env = current_block_->last_environment();
instr->ReplayEnvironment(env);
// There are no real uses of a captured object.
return NULL;
}
......
......@@ -65,7 +65,8 @@ void HEscapeAnalysisPhase::CollectCapturedValues() {
HCapturedObject* HEscapeAnalysisPhase::NewState(HInstruction* previous) {
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);
return state;
}
......@@ -183,18 +184,9 @@ void HEscapeAnalysisPhase::AnalyzeDataFlow(HInstruction* allocate) {
}
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::kCapturedObject: {
case HValue::kCapturedObject:
case HValue::kSimulate: {
for (int i = 0; i < instr->OperandCount(); i++) {
if (instr->OperandAt(i) != allocate) continue;
instr->SetOperandAt(i, state);
......@@ -274,6 +266,7 @@ void HEscapeAnalysisPhase::PerformScalarReplacement() {
if (!allocate->size()->IsInteger32Constant()) continue;
int size_in_bytes = allocate->size()->GetInteger32Constant();
number_of_values_ = size_in_bytes / kPointerSize;
number_of_objects_++;
block_states_.Clear();
// Perform actual analysis steps.
......
......@@ -40,6 +40,7 @@ class HEscapeAnalysisPhase : public HPhase {
explicit HEscapeAnalysisPhase(HGraph* graph)
: HPhase("H_Escape analysis", graph),
captured_(0, zone()),
number_of_objects_(0),
number_of_values_(0),
cumulative_values_(0),
block_states_(graph->blocks()->length(), zone()) { }
......@@ -73,6 +74,9 @@ class HEscapeAnalysisPhase : public HPhase {
// List of allocations captured during collection phase.
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.
int number_of_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,
Zone* zone) {
ASSERT(return_target->IsInlineReturnTarget());
......
......@@ -3208,8 +3208,8 @@ class HArgumentsObject V8_FINAL : public HDematerializedObject {
class HCapturedObject V8_FINAL : public HDematerializedObject {
public:
HCapturedObject(int length, Zone* zone)
: HDematerializedObject(length, zone) {
HCapturedObject(int length, int id, Zone* zone)
: HDematerializedObject(length, zone), capture_id_(id) {
set_representation(Representation::Tagged());
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.
const ZoneList<HValue*>* values() const { return &values_; }
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)
private:
int capture_id_;
};
......
......@@ -2564,6 +2564,9 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
HEnvironment* env = current_block_->last_environment();
instr->ReplayEnvironment(env);
// There are no real uses of a captured object.
return NULL;
}
......
......@@ -2361,6 +2361,9 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
HEnvironment* env = current_block_->last_environment();
instr->ReplayEnvironment(env);
// There are no real uses of a captured object.
return NULL;
}
......
......@@ -2374,6 +2374,9 @@ LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
HEnvironment* env = current_block_->last_environment();
instr->ReplayEnvironment(env);
// There are no real uses of a captured object.
return NULL;
}
......
......@@ -132,3 +132,44 @@
delete deopt.deopt;
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
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.
regress/regress-2653: SKIP
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment