Introduce a BreakTarget subclass of JumpTarget used to represent the

blocks labeled by "break", "continue", and "return".  BreakTargets are
the only jump targets that appear in the AST, the only ones that can
be uninitialized, and the only ones that can be shadowed.
Review URL: http://codereview.chromium.org/42008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1475 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b74c5b1e
...@@ -152,7 +152,7 @@ ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) { ...@@ -152,7 +152,7 @@ ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
} }
void TargetCollector::AddTarget(JumpTarget* target) { void TargetCollector::AddTarget(BreakTarget* target) {
// Add the label to the collector, but discard duplicates. // Add the label to the collector, but discard duplicates.
int length = targets_->length(); int length = targets_->length();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
......
...@@ -200,7 +200,7 @@ class BreakableStatement: public Statement { ...@@ -200,7 +200,7 @@ class BreakableStatement: public Statement {
virtual BreakableStatement* AsBreakableStatement() { return this; } virtual BreakableStatement* AsBreakableStatement() { return this; }
// Code generation // Code generation
JumpTarget* break_target() { return &break_target_; } BreakTarget* break_target() { return &break_target_; }
// Used during code generation for restoring the stack when a // Used during code generation for restoring the stack when a
// break/continue crosses a statement that keeps stuff on the stack. // break/continue crosses a statement that keeps stuff on the stack.
...@@ -219,7 +219,7 @@ class BreakableStatement: public Statement { ...@@ -219,7 +219,7 @@ class BreakableStatement: public Statement {
private: private:
ZoneStringList* labels_; ZoneStringList* labels_;
Type type_; Type type_;
JumpTarget break_target_; BreakTarget break_target_;
int break_stack_height_; int break_stack_height_;
}; };
...@@ -276,7 +276,7 @@ class IterationStatement: public BreakableStatement { ...@@ -276,7 +276,7 @@ class IterationStatement: public BreakableStatement {
Statement* body() const { return body_; } Statement* body() const { return body_; }
// Code generation // Code generation
JumpTarget* continue_target() { return &continue_target_; } BreakTarget* continue_target() { return &continue_target_; }
protected: protected:
explicit IterationStatement(ZoneStringList* labels) explicit IterationStatement(ZoneStringList* labels)
...@@ -288,7 +288,7 @@ class IterationStatement: public BreakableStatement { ...@@ -288,7 +288,7 @@ class IterationStatement: public BreakableStatement {
private: private:
Statement* body_; Statement* body_;
JumpTarget continue_target_; BreakTarget continue_target_;
}; };
...@@ -451,12 +451,12 @@ class CaseClause: public ZoneObject { ...@@ -451,12 +451,12 @@ class CaseClause: public ZoneObject {
CHECK(!is_default()); CHECK(!is_default());
return label_; return label_;
} }
JumpTarget* body_target() { return &body_target_; } BreakTarget* body_target() { return &body_target_; }
ZoneList<Statement*>* statements() const { return statements_; } ZoneList<Statement*>* statements() const { return statements_; }
private: private:
Expression* label_; Expression* label_;
JumpTarget body_target_; BreakTarget body_target_;
ZoneList<Statement*>* statements_; ZoneList<Statement*>* statements_;
}; };
...@@ -517,23 +517,23 @@ class IfStatement: public Statement { ...@@ -517,23 +517,23 @@ class IfStatement: public Statement {
// stack in the compiler; this should probably be reworked. // stack in the compiler; this should probably be reworked.
class TargetCollector: public Node { class TargetCollector: public Node {
public: public:
explicit TargetCollector(ZoneList<JumpTarget*>* targets) explicit TargetCollector(ZoneList<BreakTarget*>* targets)
: targets_(targets) { : targets_(targets) {
} }
// Adds a jump target to the collector. The collector stores a pointer not // Adds a jump target to the collector. The collector stores a pointer not
// a copy of the target to make binding work, so make sure not to pass in // a copy of the target to make binding work, so make sure not to pass in
// references to something on the stack. // references to something on the stack.
void AddTarget(JumpTarget* target); void AddTarget(BreakTarget* target);
// Virtual behaviour. TargetCollectors are never part of the AST. // Virtual behaviour. TargetCollectors are never part of the AST.
virtual void Accept(AstVisitor* v) { UNREACHABLE(); } virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
virtual TargetCollector* AsTargetCollector() { return this; } virtual TargetCollector* AsTargetCollector() { return this; }
ZoneList<JumpTarget*>* targets() { return targets_; } ZoneList<BreakTarget*>* targets() { return targets_; }
private: private:
ZoneList<JumpTarget*>* targets_; ZoneList<BreakTarget*>* targets_;
}; };
...@@ -542,16 +542,16 @@ class TryStatement: public Statement { ...@@ -542,16 +542,16 @@ class TryStatement: public Statement {
explicit TryStatement(Block* try_block) explicit TryStatement(Block* try_block)
: try_block_(try_block), escaping_targets_(NULL) { } : try_block_(try_block), escaping_targets_(NULL) { }
void set_escaping_targets(ZoneList<JumpTarget*>* targets) { void set_escaping_targets(ZoneList<BreakTarget*>* targets) {
escaping_targets_ = targets; escaping_targets_ = targets;
} }
Block* try_block() const { return try_block_; } Block* try_block() const { return try_block_; }
ZoneList<JumpTarget*>* escaping_targets() const { return escaping_targets_; } ZoneList<BreakTarget*>* escaping_targets() const { return escaping_targets_; }
private: private:
Block* try_block_; Block* try_block_;
ZoneList<JumpTarget*>* escaping_targets_; ZoneList<BreakTarget*>* escaping_targets_;
}; };
......
...@@ -4020,11 +4020,6 @@ bool CodeGenerator::HasValidEntryRegisters() { return true; } ...@@ -4020,11 +4020,6 @@ bool CodeGenerator::HasValidEntryRegisters() { return true; }
#endif #endif
bool CodeGenerator::IsActualFunctionReturn(JumpTarget* target) {
return (target == &function_return_ && !function_return_is_shadowed_);
}
#undef __ #undef __
#define __ masm-> #define __ masm->
......
...@@ -427,10 +427,6 @@ class CodeGenerator: public AstVisitor { ...@@ -427,10 +427,6 @@ class CodeGenerator: public AstVisitor {
void CodeForStatementPosition(Node* node); void CodeForStatementPosition(Node* node);
void CodeForSourcePosition(int pos); void CodeForSourcePosition(int pos);
// Is the given jump target the actual (ie, non-shadowed) function return
// target?
bool IsActualFunctionReturn(JumpTarget* target);
#ifdef DEBUG #ifdef DEBUG
// True if the registers are valid for entry to a block. // True if the registers are valid for entry to a block.
bool HasValidEntryRegisters(); bool HasValidEntryRegisters();
...@@ -453,7 +449,7 @@ class CodeGenerator: public AstVisitor { ...@@ -453,7 +449,7 @@ class CodeGenerator: public AstVisitor {
int break_stack_height_; int break_stack_height_;
// Jump targets // Jump targets
JumpTarget function_return_; BreakTarget function_return_;
// True if the function return is shadowed (ie, jumping to the target // True if the function return is shadowed (ie, jumping to the target
// function_return_ does not jump to the true function return, but rather // function_return_ does not jump to the true function return, but rather
......
...@@ -2235,7 +2235,7 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -2235,7 +2235,7 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
// indication of when it is safe to do so. // indication of when it is safe to do so.
static const bool test_at_bottom = false; static const bool test_at_bottom = false;
JumpTarget body; // Uninitialized. JumpTarget body(this); // Initialized as forward-only.
IncrementLoopNesting(); IncrementLoopNesting();
// If the condition is always false and has no side effects, we // If the condition is always false and has no side effects, we
...@@ -2254,13 +2254,12 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) { ...@@ -2254,13 +2254,12 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
// Continue is the test at the bottom, no need to label the // Continue is the test at the bottom, no need to label the
// test at the top. The body is a backward target. // test at the top. The body is a backward target.
node->continue_target()->Initialize(this); node->continue_target()->Initialize(this);
body.Initialize(this, JumpTarget::BIDIRECTIONAL); body.make_bidirectional();
} else { } else {
// Label the test at the top as the continue target. The // Label the test at the top as the continue target. The
// body is a forward-only target. // body is a forward-only target.
node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL); node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind(); node->continue_target()->Bind();
body.Initialize(this);
} }
// Compile the test with the body as the true target and // Compile the test with the body as the true target and
// preferred fall-through and with the break target as the // preferred fall-through and with the break target as the
......
...@@ -622,7 +622,7 @@ class CodeGenerator: public AstVisitor { ...@@ -622,7 +622,7 @@ class CodeGenerator: public AstVisitor {
// Jump targets. // Jump targets.
// The target of the return from the function. // The target of the return from the function.
JumpTarget function_return_; BreakTarget function_return_;
// True if the function return is shadowed (ie, jumping to the target // True if the function return is shadowed (ie, jumping to the target
// function_return_ does not jump to the true function return, but rather // function_return_ does not jump to the true function return, but rather
......
...@@ -37,35 +37,13 @@ namespace v8 { namespace internal { ...@@ -37,35 +37,13 @@ namespace v8 { namespace internal {
JumpTarget::JumpTarget(CodeGenerator* cgen, Directionality direction) JumpTarget::JumpTarget(CodeGenerator* cgen, Directionality direction)
: cgen_(cgen), : cgen_(cgen),
masm_(cgen == NULL ? NULL : cgen->masm()),
direction_(direction), direction_(direction),
reaching_frames_(0), reaching_frames_(0),
merge_labels_(0), merge_labels_(0),
entry_frame_(NULL), entry_frame_(NULL),
is_bound_(false), is_bound_(false),
is_linked_(false) { is_linked_(false) {
ASSERT(cgen_ != NULL);
masm_ = cgen_->masm();
}
JumpTarget::JumpTarget()
: cgen_(NULL),
masm_(NULL),
direction_(FORWARD_ONLY),
reaching_frames_(0),
merge_labels_(0),
entry_frame_(NULL),
is_bound_(false),
is_linked_(false) {
}
void JumpTarget::Initialize(CodeGenerator* cgen, Directionality direction) {
ASSERT(cgen != NULL);
ASSERT(cgen_ == NULL);
cgen_ = cgen;
masm_ = cgen->masm();
direction_ = direction;
} }
...@@ -512,7 +490,31 @@ void JumpTarget::Bind(Result* arg0, ...@@ -512,7 +490,31 @@ void JumpTarget::Bind(Result* arg0,
} }
void JumpTarget::CopyTo(JumpTarget* destination) { void JumpTarget::AddReachingFrame(VirtualFrame* frame) {
ASSERT(reaching_frames_.length() == merge_labels_.length());
Label fresh;
merge_labels_.Add(fresh);
reaching_frames_.Add(frame);
}
// -------------------------------------------------------------------------
// BreakTarget implementation.
BreakTarget::BreakTarget() : JumpTarget(NULL, FORWARD_ONLY) {
}
void BreakTarget::Initialize(CodeGenerator* cgen, Directionality direction) {
ASSERT(cgen != NULL);
ASSERT(cgen_ == NULL);
cgen_ = cgen;
masm_ = cgen->masm();
direction_ = direction;
}
void BreakTarget::CopyTo(BreakTarget* destination) {
ASSERT(destination != NULL); ASSERT(destination != NULL);
destination->cgen_ = cgen_; destination->cgen_ = cgen_;
destination->masm_ = masm_; destination->masm_ = masm_;
...@@ -531,18 +533,10 @@ void JumpTarget::CopyTo(JumpTarget* destination) { ...@@ -531,18 +533,10 @@ void JumpTarget::CopyTo(JumpTarget* destination) {
} }
void JumpTarget::AddReachingFrame(VirtualFrame* frame) {
ASSERT(reaching_frames_.length() == merge_labels_.length());
Label fresh;
merge_labels_.Add(fresh);
reaching_frames_.Add(frame);
}
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// ShadowTarget implementation. // ShadowTarget implementation.
ShadowTarget::ShadowTarget(JumpTarget* shadowed) { ShadowTarget::ShadowTarget(BreakTarget* shadowed) {
ASSERT(shadowed != NULL); ASSERT(shadowed != NULL);
other_target_ = shadowed; other_target_ = shadowed;
...@@ -574,7 +568,7 @@ void ShadowTarget::StopShadowing() { ...@@ -574,7 +568,7 @@ void ShadowTarget::StopShadowing() {
// The states of this target, which was shadowed, and the original // The states of this target, which was shadowed, and the original
// target, which was shadowing, are swapped. // target, which was shadowing, are swapped.
JumpTarget temp; BreakTarget temp;
other_target_->CopyTo(&temp); other_target_->CopyTo(&temp);
CopyTo(other_target_); CopyTo(other_target_);
temp.CopyTo(this); temp.CopyTo(this);
......
...@@ -58,20 +58,8 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated. ...@@ -58,20 +58,8 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
explicit JumpTarget(CodeGenerator* cgen, explicit JumpTarget(CodeGenerator* cgen,
Directionality direction = FORWARD_ONLY); Directionality direction = FORWARD_ONLY);
// Construct a jump target without a code generator. A code generator
// must be supplied before using the jump target as a label. This is
// useful, eg, when jump targets are embedded in AST nodes.
JumpTarget();
virtual ~JumpTarget() { Unuse(); } virtual ~JumpTarget() { Unuse(); }
// Supply a code generator and directionality to an already
// constructed jump target. This function expects to be given a
// non-null code generator, and to be called only when the code
// generator is not yet set.
void Initialize(CodeGenerator* cgen,
Directionality direction = FORWARD_ONLY);
// Accessors. // Accessors.
CodeGenerator* code_generator() const { return cgen_; } CodeGenerator* code_generator() const { return cgen_; }
...@@ -82,6 +70,8 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated. ...@@ -82,6 +70,8 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
entry_frame_ = frame; entry_frame_ = frame;
} }
void make_bidirectional() { direction_ = BIDIRECTIONAL; }
// Predicates testing the state of the encapsulated label. // Predicates testing the state of the encapsulated label.
bool is_bound() const { return is_bound_; } bool is_bound() const { return is_bound_; }
bool is_linked() const { return is_linked_; } bool is_linked() const { return is_linked_; }
...@@ -97,13 +87,6 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated. ...@@ -97,13 +87,6 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
// left dangling. // left dangling.
void Reset(); void Reset();
// Copy the state of this jump target to the destination. The lists
// of forward-reaching frames and merge-point labels are copied.
// All virtual frame pointers are copied, not the pointed-to frames.
// The previous state of the destination is overwritten, without
// deallocating pointed-to virtual frames.
void CopyTo(JumpTarget* destination);
// Emit a jump to the target. There must be a current frame at the // Emit a jump to the target. There must be a current frame at the
// jump and there will be no current frame after the jump. // jump and there will be no current frame after the jump.
void Jump(); void Jump();
...@@ -170,7 +153,6 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated. ...@@ -170,7 +153,6 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
// Used to emit code. // Used to emit code.
MacroAssembler* masm_; MacroAssembler* masm_;
private:
// Directionality flag set at initialization time. // Directionality flag set at initialization time.
Directionality direction_; Directionality direction_;
...@@ -194,6 +176,7 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated. ...@@ -194,6 +176,7 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
bool is_bound_; bool is_bound_;
bool is_linked_; bool is_linked_;
private:
// Add a virtual frame reaching this labeled block via a forward // Add a virtual frame reaching this labeled block via a forward
// jump, and a fresh label for its merge code. // jump, and a fresh label for its merge code.
void AddReachingFrame(VirtualFrame* frame); void AddReachingFrame(VirtualFrame* frame);
...@@ -211,22 +194,60 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated. ...@@ -211,22 +194,60 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Shadow jump targets // Break targets
//
// A break target is a jump target that can be used to break out of a
// statement that keeps extra state on the stack (eg, for/in or
// try/finally). They know the expected stack height at the target
// and will drop state from nested statements as part of merging.
//
// Break targets are used for return, break, and continue targets.
class BreakTarget : public JumpTarget {
public:
// Construct a break target without a code generator. A code
// generator must be supplied before using the break target as a
// label. This is useful, eg, when break targets are embedded in AST
// nodes.
BreakTarget();
// Supply a code generator and directionality to an already
// constructed jump target. This function expects to be given a
// non-null code generator, and to be called only when the code
// generator is not yet set.
void Initialize(CodeGenerator* cgen,
Directionality direction = FORWARD_ONLY);
// Copy the state of this break target to the destination. The
// lists of forward-reaching frames and merge-point labels are
// copied. All virtual frame pointers are copied, not the
// pointed-to frames. The previous state of the destination is
// overwritten, without deallocating pointed-to virtual frames.
void CopyTo(BreakTarget* destination);
private:
DISALLOW_COPY_AND_ASSIGN(BreakTarget);
};
// -------------------------------------------------------------------------
// Shadow break targets
// //
// Shadow jump targets represent a jump target that is temporarily shadowed // A shadow break target represents a break target that is temporarily
// by another one (represented by the original during shadowing). They are // shadowed by another one (represented by the original during
// used to catch jumps to labels in certain contexts, e.g. try blocks. // shadowing). They are used to catch jumps to labels in certain
// After shadowing ends, the formerly shadowed target is again represented // contexts, e.g. try blocks. After shadowing ends, the formerly
// by the original and the ShadowTarget can be used as a jump target in its // shadowed target is again represented by the original and the
// own right, representing the formerly shadowing target. // ShadowTarget can be used as a jump target in its own right,
// representing the formerly shadowing target.
class ShadowTarget : public JumpTarget {
class ShadowTarget : public BreakTarget {
public: public:
// Construct a shadow jump target. After construction the shadow // Construct a shadow jump target. After construction the shadow
// target object holds the state of the original jump target, and // target object holds the state of the original target, and the
// the original target is actually a fresh one that intercepts jumps // original target is actually a fresh one that intercepts control
// intended for the shadowed one. // flow intended for the shadowed one.
explicit ShadowTarget(JumpTarget* shadowed); explicit ShadowTarget(BreakTarget* shadowed);
virtual ~ShadowTarget() { virtual ~ShadowTarget() {
ASSERT(!is_shadowing_); ASSERT(!is_shadowing_);
...@@ -239,12 +260,12 @@ class ShadowTarget : public JumpTarget { ...@@ -239,12 +260,12 @@ class ShadowTarget : public JumpTarget {
// During shadowing, the currently shadowing target. After // During shadowing, the currently shadowing target. After
// shadowing, the target that was shadowed. // shadowing, the target that was shadowed.
JumpTarget* other_target() const { return other_target_; } BreakTarget* other_target() const { return other_target_; }
private: private:
// During shadowing, the currently shadowing target. After // During shadowing, the currently shadowing target. After
// shadowing, the target that was shadowed. // shadowing, the target that was shadowed.
JumpTarget* other_target_; BreakTarget* other_target_;
#ifdef DEBUG #ifdef DEBUG
bool is_shadowing_; bool is_shadowing_;
......
...@@ -207,7 +207,7 @@ class Parser { ...@@ -207,7 +207,7 @@ class Parser {
BreakableStatement* LookupBreakTarget(Handle<String> label, bool* ok); BreakableStatement* LookupBreakTarget(Handle<String> label, bool* ok);
IterationStatement* LookupContinueTarget(Handle<String> label, bool* ok); IterationStatement* LookupContinueTarget(Handle<String> label, bool* ok);
void RegisterTargetUse(JumpTarget* target, int index); void RegisterTargetUse(BreakTarget* target, int index);
// Create a number literal. // Create a number literal.
Literal* NewNumberLiteral(double value); Literal* NewNumberLiteral(double value);
...@@ -2052,7 +2052,7 @@ Block* Parser::WithHelper(Expression* obj, ...@@ -2052,7 +2052,7 @@ Block* Parser::WithHelper(Expression* obj,
bool is_catch_block, bool is_catch_block,
bool* ok) { bool* ok) {
// Parse the statement and collect escaping labels. // Parse the statement and collect escaping labels.
ZoneList<JumpTarget*>* target_list = NEW(ZoneList<JumpTarget*>(0)); ZoneList<BreakTarget*>* target_list = NEW(ZoneList<BreakTarget*>(0));
TargetCollector collector(target_list); TargetCollector collector(target_list);
Statement* stat; Statement* stat;
{ Target target(this, &collector); { Target target(this, &collector);
...@@ -2197,7 +2197,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { ...@@ -2197,7 +2197,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
Expect(Token::TRY, CHECK_OK); Expect(Token::TRY, CHECK_OK);
ZoneList<JumpTarget*>* target_list = NEW(ZoneList<JumpTarget*>(0)); ZoneList<BreakTarget*>* target_list = NEW(ZoneList<BreakTarget*>(0));
TargetCollector collector(target_list); TargetCollector collector(target_list);
Block* try_block; Block* try_block;
...@@ -2220,7 +2220,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { ...@@ -2220,7 +2220,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
// then we will need to collect jump targets from the catch block. Since // then we will need to collect jump targets from the catch block. Since
// we don't know yet if there will be a finally block, we always collect // we don't know yet if there will be a finally block, we always collect
// the jump targets. // the jump targets.
ZoneList<JumpTarget*>* catch_target_list = NEW(ZoneList<JumpTarget*>(0)); ZoneList<BreakTarget*>* catch_target_list = NEW(ZoneList<BreakTarget*>(0));
TargetCollector catch_collector(catch_target_list); TargetCollector catch_collector(catch_target_list);
bool has_catch = false; bool has_catch = false;
if (tok == Token::CATCH) { if (tok == Token::CATCH) {
...@@ -3580,10 +3580,10 @@ IterationStatement* Parser::LookupContinueTarget(Handle<String> label, ...@@ -3580,10 +3580,10 @@ IterationStatement* Parser::LookupContinueTarget(Handle<String> label,
} }
void Parser::RegisterTargetUse(JumpTarget* target, int index) { void Parser::RegisterTargetUse(BreakTarget* target, int index) {
// Register that a jump target found at the given index in the target // Register that a break target found at the given index in the
// stack has been used from the top of the target stack. Add the jump // target stack has been used from the top of the target stack. Add
// target to any TargetCollectors passed on the stack. // the break target to any TargetCollectors passed on the stack.
for (int i = target_stack_->length(); i-- > index;) { for (int i = target_stack_->length(); i-- > index;) {
TargetCollector* collector = target_stack_->at(i)->AsTargetCollector(); TargetCollector* collector = target_stack_->at(i)->AsTargetCollector();
if (collector != NULL) collector->AddTarget(target); if (collector != NULL) collector->AddTarget(target);
......
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