Index: src/codegen-arm.cc |
=================================================================== |
--- src/codegen-arm.cc (revision 292) |
+++ src/codegen-arm.cc (working copy) |
@@ -101,9 +101,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 { |
@@ -112,33 +121,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(ArmCodeGenerator* 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(ArmCodeGenerator* 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(ArmCodeGenerator* 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: |
+ ArmCodeGenerator* owner_; |
AccessType access_; |
Reference* ref_; |
Label* true_target_; |
Label* false_target_; |
+ CodeGenState* previous_; |
}; |
@@ -153,6 +168,9 @@ |
MacroAssembler* masm() { return masm_; } |
+ CodeGenState* state() { return state_; } |
+ void set_state(CodeGenState* state) { state_ = state; } |
+ |
private: |
// Assembler |
MacroAssembler* masm_; // to generate code |
@@ -243,7 +261,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 |
@@ -341,6 +364,51 @@ |
}; |
+// ------------------------------------------------------------------------- |
+// 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 |
@@ -456,8 +524,7 @@ |
ZoneList<Statement*>* body = fun->body(); |
// Initialize state. |
- { CodeGenState state; |
- state_ = &state; |
+ { CodeGenState state(this); |
scope_ = scope; |
cc_reg_ = al; |
@@ -609,8 +676,6 @@ |
#endif |
VisitStatements(body); |
} |
- |
- state_ = NULL; |
} |
// exit |
@@ -717,11 +782,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()) { |
// Convert the TOS value to a boolean in the condition code register. |
ToBoolean(true_target, false_target); |
@@ -869,18 +932,6 @@ |
} |
-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, |
Scope* scope, |
Reference* ref, |
@@ -953,7 +1004,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 |
@@ -963,7 +1013,6 @@ |
masm->ldr(r2, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); |
masm->cmp(r2, Operand(Factory::the_hole_value())); |
masm->b(ne, &exit); |
- may_skip_write = true; |
} |
// We must execute the store. |
@@ -983,7 +1032,6 @@ |
// Skip write barrier if the written value is a smi. |
masm->tst(r0, Operand(kSmiTagMask)); |
masm->b(eq, &exit); |
- may_skip_write = true; |
// r2 is loaded with context when calling SlotOperand above. |
int offset = FixedArray::kHeaderSize + index() * kPointerSize; |
masm->mov(r3, Operand(offset)); |
@@ -991,7 +1039,9 @@ |
} |
// 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 || type() == Slot::CONTEXT) { |
+ masm->bind(&exit); |
+ } |
} |
} |