Index: src/codegen-ia32.cc |
=================================================================== |
--- src/codegen-ia32.cc (revision 292) |
+++ src/codegen-ia32.cc (working copy) |
@@ -107,9 +107,18 @@ |
}; |
-// ----------------------------------------------------------------------------- |
+// ------------------------------------------------------------------------- |
// 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 { |
public: |
enum AccessType { |
@@ -118,33 +127,39 @@ |
LOAD_TYPEOF_EXPR |
}; |
- CodeGenState() |
- : access_(UNDEFINED), |
- ref_(NULL), |
- true_target_(NULL), |
- false_target_(NULL) { |
- } |
+ // Create an initial code generator state. Destroying the initial state |
+ // leaves the code generator with a NULL state. |
+ CodeGenState(Ia32CodeGenerator* owner); |
- CodeGenState(AccessType access, |
- Reference* ref, |
+ // Create a code generator state based on a code generator's current |
+ // 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* false_target) |
- : access_(access), |
- ref_(ref), |
- true_target_(true_target), |
- false_target_(false_target) { |
- } |
+ Label* false_target); |
+ // Create a code generator state based on a code generator's current |
+ // state. The new state has an access type of LOAD, its own reference, |
+ // 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_; } |
Reference* ref() const { return ref_; } |
Label* true_target() const { return true_target_; } |
Label* false_target() const { return false_target_; } |
private: |
+ Ia32CodeGenerator* owner_; |
AccessType access_; |
Reference* ref_; |
Label* true_target_; |
Label* false_target_; |
+ CodeGenState* previous_; |
}; |
@@ -159,6 +174,9 @@ |
MacroAssembler* masm() { return masm_; } |
+ CodeGenState* state() { return state_; } |
+ void set_state(CodeGenState* state) { state_ = state; } |
+ |
private: |
// Assembler |
MacroAssembler* masm_; // to generate code |
@@ -251,7 +269,12 @@ |
// 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 |
// 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 |
// expected on top of the expression stack, with the reference immediately |
@@ -356,6 +379,51 @@ |
}; |
+// ------------------------------------------------------------------------- |
+// 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 |
@@ -474,8 +542,7 @@ |
ZoneList<Statement*>* body = fun->body(); |
// Initialize state. |
- { CodeGenState state; |
- state_ = &state; |
+ { CodeGenState state(this); |
scope_ = scope; |
cc_reg_ = no_condition; |
@@ -659,8 +726,6 @@ |
VisitReturnStatement(&statement); |
} |
} |
- |
- state_ = NULL; |
} |
// Code generation state must be reset. |
@@ -740,11 +805,9 @@ |
access == CodeGenState::LOAD_TYPEOF_EXPR); |
ASSERT(!has_cc() && !is_referenced()); |
- CodeGenState* old_state = state_; |
- CodeGenState new_state(access, NULL, true_target, false_target); |
- state_ = &new_state; |
- Visit(x); |
- state_ = old_state; |
+ { CodeGenState new_state(this, access, true_target, false_target); |
+ Visit(x); |
+ } |
if (force_cc && !has_cc()) { |
ToBoolean(true_target, false_target); |
} |
@@ -892,18 +955,6 @@ |
} |
-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, |
Scope* scope, |
Reference* ref, |
@@ -975,7 +1026,6 @@ |
ASSERT(var()->mode() != Variable::DYNAMIC); |
Label exit; |
- bool may_skip_write = false; |
if (init_state == CONST_INIT) { |
ASSERT(var()->mode() == Variable::CONST); |
// Only the first const initialization must be executed (the slot |
@@ -985,7 +1035,6 @@ |
masm->mov(eax, Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx)); |
masm->cmp(eax, Factory::the_hole_value()); |
masm->j(not_equal, &exit); |
- may_skip_write = true; |
} |
// We must execute the store. |
@@ -1007,7 +1056,7 @@ |
} |
// If we definitely did not jump over the assignment, we do not need to |
// 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); |
} |
} |