Change the code generator state constructor to implicitly push the state on

stack, rather than explicitly saving and restoring it.
Review URL: http://codereview.chromium.org/3002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@294 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 5e4020ed
...@@ -101,9 +101,18 @@ class Reference BASE_EMBEDDED { ...@@ -101,9 +101,18 @@ class Reference BASE_EMBEDDED {
}; };
// ----------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Code generation state // Code generation state
// The state is passed down the AST by the code generator. It is passed
// implicitly (in a member variable) to the non-static code generator member
// functions, and explicitly (as an argument) to the static member functions
// and the AST node member functions.
//
// The state is threaded through the call stack. Constructing a state
// implicitly pushes it on the owning code generator's stack of states, and
// destroying one implicitly pops it.
class CodeGenState BASE_EMBEDDED { class CodeGenState BASE_EMBEDDED {
public: public:
enum AccessType { enum AccessType {
...@@ -112,22 +121,26 @@ class CodeGenState BASE_EMBEDDED { ...@@ -112,22 +121,26 @@ class CodeGenState BASE_EMBEDDED {
LOAD_TYPEOF_EXPR LOAD_TYPEOF_EXPR
}; };
CodeGenState() // Create an initial code generator state. Destroying the initial state
: access_(UNDEFINED), // leaves the code generator with a NULL state.
ref_(NULL), CodeGenState(ArmCodeGenerator* owner);
true_target_(NULL),
false_target_(NULL) {
}
CodeGenState(AccessType access, // Create a code generator state based on a code generator's current
Reference* ref, // state. The new state has its own access type and pair of branch
// labels, and no reference.
CodeGenState(ArmCodeGenerator* owner,
AccessType access,
Label* true_target, Label* true_target,
Label* false_target) Label* false_target);
: access_(access),
ref_(ref), // Create a code generator state based on a code generator's current
true_target_(true_target), // state. The new state has an access type of LOAD, its own reference,
false_target_(false_target) { // and inherits the pair of branch labels of the current state.
} CodeGenState(ArmCodeGenerator* owner, Reference* ref);
// Destroy a code generator state and restore the owning code generator's
// previous state.
~CodeGenState();
AccessType access() const { return access_; } AccessType access() const { return access_; }
Reference* ref() const { return ref_; } Reference* ref() const { return ref_; }
...@@ -135,10 +148,12 @@ class CodeGenState BASE_EMBEDDED { ...@@ -135,10 +148,12 @@ class CodeGenState BASE_EMBEDDED {
Label* false_target() const { return false_target_; } Label* false_target() const { return false_target_; }
private: private:
ArmCodeGenerator* owner_;
AccessType access_; AccessType access_;
Reference* ref_; Reference* ref_;
Label* true_target_; Label* true_target_;
Label* false_target_; Label* false_target_;
CodeGenState* previous_;
}; };
...@@ -153,6 +168,9 @@ class ArmCodeGenerator: public CodeGenerator { ...@@ -153,6 +168,9 @@ class ArmCodeGenerator: public CodeGenerator {
MacroAssembler* masm() { return masm_; } MacroAssembler* masm() { return masm_; }
CodeGenState* state() { return state_; }
void set_state(CodeGenState* state) { state_ = state; }
private: private:
// Assembler // Assembler
MacroAssembler* masm_; // to generate code MacroAssembler* masm_; // to generate code
...@@ -243,7 +261,12 @@ class ArmCodeGenerator: public CodeGenerator { ...@@ -243,7 +261,12 @@ class ArmCodeGenerator: public CodeGenerator {
// Generate code to fetch the value of a reference. The reference is // Generate code to fetch the value of a reference. The reference is
// expected to be on top of the expression stack. It is left in place and // expected to be on top of the expression stack. It is left in place and
// its value is pushed on top of it. // its value is pushed on top of it.
void GetValue(Reference* ref); void GetValue(Reference* ref) {
ASSERT(!has_cc());
ASSERT(!ref->is_illegal());
CodeGenState new_state(this, ref);
Visit(ref->expression());
}
// Generate code to store a value in a reference. The stored value is // Generate code to store a value in a reference. The stored value is
// expected on top of the expression stack, with the reference immediately // expected on top of the expression stack, with the reference immediately
...@@ -341,6 +364,51 @@ class ArmCodeGenerator: public CodeGenerator { ...@@ -341,6 +364,51 @@ class ArmCodeGenerator: public CodeGenerator {
}; };
// -------------------------------------------------------------------------
// CodeGenState implementation.
CodeGenState::CodeGenState(ArmCodeGenerator* owner)
: owner_(owner),
access_(UNDEFINED),
ref_(NULL),
true_target_(NULL),
false_target_(NULL),
previous_(NULL) {
owner_->set_state(this);
}
CodeGenState::CodeGenState(ArmCodeGenerator* owner,
AccessType access,
Label* true_target,
Label* false_target)
: owner_(owner),
access_(access),
ref_(NULL),
true_target_(true_target),
false_target_(false_target),
previous_(owner->state()) {
owner_->set_state(this);
}
CodeGenState::CodeGenState(ArmCodeGenerator* owner, Reference* ref)
: owner_(owner),
access_(LOAD),
ref_(ref),
true_target_(owner->state()->true_target_),
false_target_(owner->state()->false_target_),
previous_(owner->state()) {
owner_->set_state(this);
}
CodeGenState::~CodeGenState() {
ASSERT(owner_->state() == this);
owner_->set_state(previous_);
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// ArmCodeGenerator implementation // ArmCodeGenerator implementation
...@@ -456,8 +524,7 @@ void ArmCodeGenerator::GenCode(FunctionLiteral* fun) { ...@@ -456,8 +524,7 @@ void ArmCodeGenerator::GenCode(FunctionLiteral* fun) {
ZoneList<Statement*>* body = fun->body(); ZoneList<Statement*>* body = fun->body();
// Initialize state. // Initialize state.
{ CodeGenState state; { CodeGenState state(this);
state_ = &state;
scope_ = scope; scope_ = scope;
cc_reg_ = al; cc_reg_ = al;
...@@ -609,8 +676,6 @@ void ArmCodeGenerator::GenCode(FunctionLiteral* fun) { ...@@ -609,8 +676,6 @@ void ArmCodeGenerator::GenCode(FunctionLiteral* fun) {
#endif #endif
VisitStatements(body); VisitStatements(body);
} }
state_ = NULL;
} }
// exit // exit
...@@ -717,11 +782,9 @@ void ArmCodeGenerator::LoadCondition(Expression* x, ...@@ -717,11 +782,9 @@ void ArmCodeGenerator::LoadCondition(Expression* x,
access == CodeGenState::LOAD_TYPEOF_EXPR); access == CodeGenState::LOAD_TYPEOF_EXPR);
ASSERT(!has_cc() && !is_referenced()); ASSERT(!has_cc() && !is_referenced());
CodeGenState* old_state = state_; { CodeGenState new_state(this, access, true_target, false_target);
CodeGenState new_state(access, NULL, true_target, false_target); Visit(x);
state_ = &new_state; }
Visit(x);
state_ = old_state;
if (force_cc && !has_cc()) { if (force_cc && !has_cc()) {
// Convert the TOS value to a boolean in the condition code register. // Convert the TOS value to a boolean in the condition code register.
ToBoolean(true_target, false_target); ToBoolean(true_target, false_target);
...@@ -869,18 +932,6 @@ void ArmCodeGenerator::UnloadReference(Reference* ref) { ...@@ -869,18 +932,6 @@ void ArmCodeGenerator::UnloadReference(Reference* ref) {
} }
void ArmCodeGenerator::GetValue(Reference* ref) {
ASSERT(!has_cc());
ASSERT(!ref->is_illegal());
CodeGenState* old_state = state_;
CodeGenState new_state(CodeGenState::LOAD, ref, true_target(),
false_target());
state_ = &new_state;
Visit(ref->expression());
state_ = old_state;
}
void Property::GenerateStoreCode(MacroAssembler* masm, void Property::GenerateStoreCode(MacroAssembler* masm,
Scope* scope, Scope* scope,
Reference* ref, Reference* ref,
...@@ -953,7 +1004,6 @@ void Slot::GenerateStoreCode(MacroAssembler* masm, ...@@ -953,7 +1004,6 @@ void Slot::GenerateStoreCode(MacroAssembler* masm,
ASSERT(var()->mode() != Variable::DYNAMIC); ASSERT(var()->mode() != Variable::DYNAMIC);
Label exit; Label exit;
bool may_skip_write = false;
if (init_state == CONST_INIT) { if (init_state == CONST_INIT) {
ASSERT(var()->mode() == Variable::CONST); ASSERT(var()->mode() == Variable::CONST);
// Only the first const initialization must be executed (the slot // Only the first const initialization must be executed (the slot
...@@ -963,7 +1013,6 @@ void Slot::GenerateStoreCode(MacroAssembler* masm, ...@@ -963,7 +1013,6 @@ void Slot::GenerateStoreCode(MacroAssembler* masm,
masm->ldr(r2, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); masm->ldr(r2, ArmCodeGenerator::SlotOperand(masm, scope, this, r2));
masm->cmp(r2, Operand(Factory::the_hole_value())); masm->cmp(r2, Operand(Factory::the_hole_value()));
masm->b(ne, &exit); masm->b(ne, &exit);
may_skip_write = true;
} }
// We must execute the store. // We must execute the store.
...@@ -983,7 +1032,6 @@ void Slot::GenerateStoreCode(MacroAssembler* masm, ...@@ -983,7 +1032,6 @@ void Slot::GenerateStoreCode(MacroAssembler* masm,
// Skip write barrier if the written value is a smi. // Skip write barrier if the written value is a smi.
masm->tst(r0, Operand(kSmiTagMask)); masm->tst(r0, Operand(kSmiTagMask));
masm->b(eq, &exit); masm->b(eq, &exit);
may_skip_write = true;
// r2 is loaded with context when calling SlotOperand above. // r2 is loaded with context when calling SlotOperand above.
int offset = FixedArray::kHeaderSize + index() * kPointerSize; int offset = FixedArray::kHeaderSize + index() * kPointerSize;
masm->mov(r3, Operand(offset)); masm->mov(r3, Operand(offset));
...@@ -991,7 +1039,9 @@ void Slot::GenerateStoreCode(MacroAssembler* masm, ...@@ -991,7 +1039,9 @@ void Slot::GenerateStoreCode(MacroAssembler* masm,
} }
// If we definitely did not jump over the assignment, we do not need to // If we definitely did not jump over the assignment, we do not need to
// bind the exit label. Doing so can defeat peephole optimization. // bind the exit label. Doing so can defeat peephole optimization.
if (may_skip_write) masm->bind(&exit); if (init_state == CONST_INIT || type() == Slot::CONTEXT) {
masm->bind(&exit);
}
} }
} }
......
...@@ -107,9 +107,18 @@ class Reference BASE_EMBEDDED { ...@@ -107,9 +107,18 @@ class Reference BASE_EMBEDDED {
}; };
// ----------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Code generation state // Code generation state
// The state is passed down the AST by the code generator. It is passed
// implicitly (in a member variable) to the non-static code generator member
// functions, and explicitly (as an argument) to the static member functions
// and the AST node member functions.
//
// The state is threaded through the call stack. Constructing a state
// implicitly pushes it on the owning code generator's stack of states, and
// destroying one implicitly pops it.
class CodeGenState BASE_EMBEDDED { class CodeGenState BASE_EMBEDDED {
public: public:
enum AccessType { enum AccessType {
...@@ -118,22 +127,26 @@ class CodeGenState BASE_EMBEDDED { ...@@ -118,22 +127,26 @@ class CodeGenState BASE_EMBEDDED {
LOAD_TYPEOF_EXPR LOAD_TYPEOF_EXPR
}; };
CodeGenState() // Create an initial code generator state. Destroying the initial state
: access_(UNDEFINED), // leaves the code generator with a NULL state.
ref_(NULL), CodeGenState(Ia32CodeGenerator* owner);
true_target_(NULL),
false_target_(NULL) {
}
CodeGenState(AccessType access, // Create a code generator state based on a code generator's current
Reference* ref, // state. The new state has its own access type and pair of branch
// labels, and no reference.
CodeGenState(Ia32CodeGenerator* owner,
AccessType access,
Label* true_target, Label* true_target,
Label* false_target) Label* false_target);
: access_(access),
ref_(ref), // Create a code generator state based on a code generator's current
true_target_(true_target), // state. The new state has an access type of LOAD, its own reference,
false_target_(false_target) { // and inherits the pair of branch labels of the current state.
} CodeGenState(Ia32CodeGenerator* owner, Reference* ref);
// Destroy a code generator state and restore the owning code generator's
// previous state.
~CodeGenState();
AccessType access() const { return access_; } AccessType access() const { return access_; }
Reference* ref() const { return ref_; } Reference* ref() const { return ref_; }
...@@ -141,10 +154,12 @@ class CodeGenState BASE_EMBEDDED { ...@@ -141,10 +154,12 @@ class CodeGenState BASE_EMBEDDED {
Label* false_target() const { return false_target_; } Label* false_target() const { return false_target_; }
private: private:
Ia32CodeGenerator* owner_;
AccessType access_; AccessType access_;
Reference* ref_; Reference* ref_;
Label* true_target_; Label* true_target_;
Label* false_target_; Label* false_target_;
CodeGenState* previous_;
}; };
...@@ -159,6 +174,9 @@ class Ia32CodeGenerator: public CodeGenerator { ...@@ -159,6 +174,9 @@ class Ia32CodeGenerator: public CodeGenerator {
MacroAssembler* masm() { return masm_; } MacroAssembler* masm() { return masm_; }
CodeGenState* state() { return state_; }
void set_state(CodeGenState* state) { state_ = state; }
private: private:
// Assembler // Assembler
MacroAssembler* masm_; // to generate code MacroAssembler* masm_; // to generate code
...@@ -251,7 +269,12 @@ class Ia32CodeGenerator: public CodeGenerator { ...@@ -251,7 +269,12 @@ class Ia32CodeGenerator: public CodeGenerator {
// Generate code to fetch the value of a reference. The reference is // Generate code to fetch the value of a reference. The reference is
// expected to be on top of the expression stack. It is left in place and // expected to be on top of the expression stack. It is left in place and
// its value is pushed on top of it. // its value is pushed on top of it.
void GetValue(Reference* ref); void GetValue(Reference* ref) {
ASSERT(!has_cc());
ASSERT(!ref->is_illegal());
CodeGenState new_state(this, ref);
Visit(ref->expression());
}
// Generate code to store a value in a reference. The stored value is // Generate code to store a value in a reference. The stored value is
// expected on top of the expression stack, with the reference immediately // expected on top of the expression stack, with the reference immediately
...@@ -356,6 +379,51 @@ class Ia32CodeGenerator: public CodeGenerator { ...@@ -356,6 +379,51 @@ class Ia32CodeGenerator: public CodeGenerator {
}; };
// -------------------------------------------------------------------------
// CodeGenState implementation.
CodeGenState::CodeGenState(Ia32CodeGenerator* owner)
: owner_(owner),
access_(UNDEFINED),
ref_(NULL),
true_target_(NULL),
false_target_(NULL),
previous_(NULL) {
owner_->set_state(this);
}
CodeGenState::CodeGenState(Ia32CodeGenerator* owner,
AccessType access,
Label* true_target,
Label* false_target)
: owner_(owner),
access_(access),
ref_(NULL),
true_target_(true_target),
false_target_(false_target),
previous_(owner->state()) {
owner_->set_state(this);
}
CodeGenState::CodeGenState(Ia32CodeGenerator* owner, Reference* ref)
: owner_(owner),
access_(LOAD),
ref_(ref),
true_target_(owner->state()->true_target_),
false_target_(owner->state()->false_target_),
previous_(owner->state()) {
owner_->set_state(this);
}
CodeGenState::~CodeGenState() {
ASSERT(owner_->state() == this);
owner_->set_state(previous_);
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Ia32CodeGenerator implementation // Ia32CodeGenerator implementation
...@@ -474,8 +542,7 @@ void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) { ...@@ -474,8 +542,7 @@ void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) {
ZoneList<Statement*>* body = fun->body(); ZoneList<Statement*>* body = fun->body();
// Initialize state. // Initialize state.
{ CodeGenState state; { CodeGenState state(this);
state_ = &state;
scope_ = scope; scope_ = scope;
cc_reg_ = no_condition; cc_reg_ = no_condition;
...@@ -659,8 +726,6 @@ void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) { ...@@ -659,8 +726,6 @@ void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) {
VisitReturnStatement(&statement); VisitReturnStatement(&statement);
} }
} }
state_ = NULL;
} }
// Code generation state must be reset. // Code generation state must be reset.
...@@ -740,11 +805,9 @@ void Ia32CodeGenerator::LoadCondition(Expression* x, ...@@ -740,11 +805,9 @@ void Ia32CodeGenerator::LoadCondition(Expression* x,
access == CodeGenState::LOAD_TYPEOF_EXPR); access == CodeGenState::LOAD_TYPEOF_EXPR);
ASSERT(!has_cc() && !is_referenced()); ASSERT(!has_cc() && !is_referenced());
CodeGenState* old_state = state_; { CodeGenState new_state(this, access, true_target, false_target);
CodeGenState new_state(access, NULL, true_target, false_target); Visit(x);
state_ = &new_state; }
Visit(x);
state_ = old_state;
if (force_cc && !has_cc()) { if (force_cc && !has_cc()) {
ToBoolean(true_target, false_target); ToBoolean(true_target, false_target);
} }
...@@ -892,18 +955,6 @@ void Ia32CodeGenerator::UnloadReference(Reference* ref) { ...@@ -892,18 +955,6 @@ void Ia32CodeGenerator::UnloadReference(Reference* ref) {
} }
void Ia32CodeGenerator::GetValue(Reference* ref) {
ASSERT(!has_cc());
ASSERT(ref->type() != Reference::ILLEGAL);
CodeGenState* old_state = state_;
CodeGenState new_state(CodeGenState::LOAD, ref, true_target(),
false_target());
state_ = &new_state;
Visit(ref->expression());
state_ = old_state;
}
void Property::GenerateStoreCode(MacroAssembler* masm, void Property::GenerateStoreCode(MacroAssembler* masm,
Scope* scope, Scope* scope,
Reference* ref, Reference* ref,
...@@ -975,7 +1026,6 @@ void Slot::GenerateStoreCode(MacroAssembler* masm, ...@@ -975,7 +1026,6 @@ void Slot::GenerateStoreCode(MacroAssembler* masm,
ASSERT(var()->mode() != Variable::DYNAMIC); ASSERT(var()->mode() != Variable::DYNAMIC);
Label exit; Label exit;
bool may_skip_write = false;
if (init_state == CONST_INIT) { if (init_state == CONST_INIT) {
ASSERT(var()->mode() == Variable::CONST); ASSERT(var()->mode() == Variable::CONST);
// Only the first const initialization must be executed (the slot // Only the first const initialization must be executed (the slot
...@@ -985,7 +1035,6 @@ void Slot::GenerateStoreCode(MacroAssembler* masm, ...@@ -985,7 +1035,6 @@ void Slot::GenerateStoreCode(MacroAssembler* masm,
masm->mov(eax, Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx)); masm->mov(eax, Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx));
masm->cmp(eax, Factory::the_hole_value()); masm->cmp(eax, Factory::the_hole_value());
masm->j(not_equal, &exit); masm->j(not_equal, &exit);
may_skip_write = true;
} }
// We must execute the store. // We must execute the store.
...@@ -1007,7 +1056,7 @@ void Slot::GenerateStoreCode(MacroAssembler* masm, ...@@ -1007,7 +1056,7 @@ void Slot::GenerateStoreCode(MacroAssembler* masm,
} }
// If we definitely did not jump over the assignment, we do not need to // If we definitely did not jump over the assignment, we do not need to
// bind the exit label. Doing so can defeat peephole optimization. // bind the exit label. Doing so can defeat peephole optimization.
if (may_skip_write) masm->bind(&exit); if (init_state == CONST_INIT) masm->bind(&exit);
} }
} }
......
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