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) {
}
void TargetCollector::AddTarget(JumpTarget* target) {
void TargetCollector::AddTarget(BreakTarget* target) {
// Add the label to the collector, but discard duplicates.
int length = targets_->length();
for (int i = 0; i < length; i++) {
......
......@@ -200,7 +200,7 @@ class BreakableStatement: public Statement {
virtual BreakableStatement* AsBreakableStatement() { return this; }
// Code generation
JumpTarget* break_target() { return &break_target_; }
BreakTarget* break_target() { return &break_target_; }
// Used during code generation for restoring the stack when a
// break/continue crosses a statement that keeps stuff on the stack.
......@@ -219,7 +219,7 @@ class BreakableStatement: public Statement {
private:
ZoneStringList* labels_;
Type type_;
JumpTarget break_target_;
BreakTarget break_target_;
int break_stack_height_;
};
......@@ -276,7 +276,7 @@ class IterationStatement: public BreakableStatement {
Statement* body() const { return body_; }
// Code generation
JumpTarget* continue_target() { return &continue_target_; }
BreakTarget* continue_target() { return &continue_target_; }
protected:
explicit IterationStatement(ZoneStringList* labels)
......@@ -288,7 +288,7 @@ class IterationStatement: public BreakableStatement {
private:
Statement* body_;
JumpTarget continue_target_;
BreakTarget continue_target_;
};
......@@ -451,12 +451,12 @@ class CaseClause: public ZoneObject {
CHECK(!is_default());
return label_;
}
JumpTarget* body_target() { return &body_target_; }
BreakTarget* body_target() { return &body_target_; }
ZoneList<Statement*>* statements() const { return statements_; }
private:
Expression* label_;
JumpTarget body_target_;
BreakTarget body_target_;
ZoneList<Statement*>* statements_;
};
......@@ -517,23 +517,23 @@ class IfStatement: public Statement {
// stack in the compiler; this should probably be reworked.
class TargetCollector: public Node {
public:
explicit TargetCollector(ZoneList<JumpTarget*>* targets)
explicit TargetCollector(ZoneList<BreakTarget*>* targets)
: targets_(targets) {
}
// 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
// references to something on the stack.
void AddTarget(JumpTarget* target);
void AddTarget(BreakTarget* target);
// Virtual behaviour. TargetCollectors are never part of the AST.
virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
virtual TargetCollector* AsTargetCollector() { return this; }
ZoneList<JumpTarget*>* targets() { return targets_; }
ZoneList<BreakTarget*>* targets() { return targets_; }
private:
ZoneList<JumpTarget*>* targets_;
ZoneList<BreakTarget*>* targets_;
};
......@@ -542,16 +542,16 @@ class TryStatement: public Statement {
explicit TryStatement(Block* try_block)
: try_block_(try_block), escaping_targets_(NULL) { }
void set_escaping_targets(ZoneList<JumpTarget*>* targets) {
void set_escaping_targets(ZoneList<BreakTarget*>* targets) {
escaping_targets_ = targets;
}
Block* try_block() const { return try_block_; }
ZoneList<JumpTarget*>* escaping_targets() const { return escaping_targets_; }
ZoneList<BreakTarget*>* escaping_targets() const { return escaping_targets_; }
private:
Block* try_block_;
ZoneList<JumpTarget*>* escaping_targets_;
ZoneList<BreakTarget*>* escaping_targets_;
};
......
......@@ -4020,11 +4020,6 @@ bool CodeGenerator::HasValidEntryRegisters() { return true; }
#endif
bool CodeGenerator::IsActualFunctionReturn(JumpTarget* target) {
return (target == &function_return_ && !function_return_is_shadowed_);
}
#undef __
#define __ masm->
......
......@@ -427,10 +427,6 @@ class CodeGenerator: public AstVisitor {
void CodeForStatementPosition(Node* node);
void CodeForSourcePosition(int pos);
// Is the given jump target the actual (ie, non-shadowed) function return
// target?
bool IsActualFunctionReturn(JumpTarget* target);
#ifdef DEBUG
// True if the registers are valid for entry to a block.
bool HasValidEntryRegisters();
......@@ -453,7 +449,7 @@ class CodeGenerator: public AstVisitor {
int break_stack_height_;
// Jump targets
JumpTarget function_return_;
BreakTarget function_return_;
// True if the function return is shadowed (ie, jumping to the target
// function_return_ does not jump to the true function return, but rather
......
......@@ -2235,7 +2235,7 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
// indication of when it is safe to do so.
static const bool test_at_bottom = false;
JumpTarget body; // Uninitialized.
JumpTarget body(this); // Initialized as forward-only.
IncrementLoopNesting();
// If the condition is always false and has no side effects, we
......@@ -2254,13 +2254,12 @@ void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
// Continue is the test at the bottom, no need to label the
// test at the top. The body is a backward target.
node->continue_target()->Initialize(this);
body.Initialize(this, JumpTarget::BIDIRECTIONAL);
body.make_bidirectional();
} else {
// Label the test at the top as the continue target. The
// body is a forward-only target.
node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
node->continue_target()->Bind();
body.Initialize(this);
}
// Compile the test with the body as the true target and
// preferred fall-through and with the break target as the
......
......@@ -622,7 +622,7 @@ class CodeGenerator: public AstVisitor {
// Jump targets.
// 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
// function_return_ does not jump to the true function return, but rather
......
......@@ -37,35 +37,13 @@ namespace v8 { namespace internal {
JumpTarget::JumpTarget(CodeGenerator* cgen, Directionality direction)
: cgen_(cgen),
masm_(cgen == NULL ? NULL : cgen->masm()),
direction_(direction),
reaching_frames_(0),
merge_labels_(0),
entry_frame_(NULL),
is_bound_(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,
}
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);
destination->cgen_ = cgen_;
destination->masm_ = masm_;
......@@ -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::ShadowTarget(JumpTarget* shadowed) {
ShadowTarget::ShadowTarget(BreakTarget* shadowed) {
ASSERT(shadowed != NULL);
other_target_ = shadowed;
......@@ -574,7 +568,7 @@ void ShadowTarget::StopShadowing() {
// The states of this target, which was shadowed, and the original
// target, which was shadowing, are swapped.
JumpTarget temp;
BreakTarget temp;
other_target_->CopyTo(&temp);
CopyTo(other_target_);
temp.CopyTo(this);
......
......@@ -58,20 +58,8 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
explicit JumpTarget(CodeGenerator* cgen,
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(); }
// 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.
CodeGenerator* code_generator() const { return cgen_; }
......@@ -82,6 +70,8 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
entry_frame_ = frame;
}
void make_bidirectional() { direction_ = BIDIRECTIONAL; }
// Predicates testing the state of the encapsulated label.
bool is_bound() const { return is_bound_; }
bool is_linked() const { return is_linked_; }
......@@ -97,13 +87,6 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
// left dangling.
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
// jump and there will be no current frame after the jump.
void Jump();
......@@ -170,7 +153,6 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
// Used to emit code.
MacroAssembler* masm_;
private:
// Directionality flag set at initialization time.
Directionality direction_;
......@@ -194,6 +176,7 @@ class JumpTarget : public ZoneObject { // Shadows are dynamically allocated.
bool is_bound_;
bool is_linked_;
private:
// Add a virtual frame reaching this labeled block via a forward
// jump, and a fresh label for its merge code.
void AddReachingFrame(VirtualFrame* frame);
......@@ -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
// by another one (represented by the original during shadowing). They are
// used to catch jumps to labels in certain contexts, e.g. try blocks.
// After shadowing ends, the formerly shadowed target is again represented
// by the original and the ShadowTarget can be used as a jump target in its
// own right, representing the formerly shadowing target.
class ShadowTarget : public JumpTarget {
// A shadow break target represents a break target that is temporarily
// shadowed by another one (represented by the original during
// shadowing). They are used to catch jumps to labels in certain
// contexts, e.g. try blocks. After shadowing ends, the formerly
// shadowed target is again represented by the original and the
// ShadowTarget can be used as a jump target in its own right,
// representing the formerly shadowing target.
class ShadowTarget : public BreakTarget {
public:
// Construct a shadow jump target. After construction the shadow
// target object holds the state of the original jump target, and
// the original target is actually a fresh one that intercepts jumps
// intended for the shadowed one.
explicit ShadowTarget(JumpTarget* shadowed);
// target object holds the state of the original target, and the
// original target is actually a fresh one that intercepts control
// flow intended for the shadowed one.
explicit ShadowTarget(BreakTarget* shadowed);
virtual ~ShadowTarget() {
ASSERT(!is_shadowing_);
......@@ -239,12 +260,12 @@ class ShadowTarget : public JumpTarget {
// During shadowing, the currently shadowing target. After
// shadowing, the target that was shadowed.
JumpTarget* other_target() const { return other_target_; }
BreakTarget* other_target() const { return other_target_; }
private:
// During shadowing, the currently shadowing target. After
// shadowing, the target that was shadowed.
JumpTarget* other_target_;
BreakTarget* other_target_;
#ifdef DEBUG
bool is_shadowing_;
......
......@@ -207,7 +207,7 @@ class Parser {
BreakableStatement* LookupBreakTarget(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.
Literal* NewNumberLiteral(double value);
......@@ -2052,7 +2052,7 @@ Block* Parser::WithHelper(Expression* obj,
bool is_catch_block,
bool* ok) {
// 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);
Statement* stat;
{ Target target(this, &collector);
......@@ -2197,7 +2197,7 @@ TryStatement* Parser::ParseTryStatement(bool* 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);
Block* try_block;
......@@ -2220,7 +2220,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
// 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
// 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);
bool has_catch = false;
if (tok == Token::CATCH) {
......@@ -3580,10 +3580,10 @@ IterationStatement* Parser::LookupContinueTarget(Handle<String> label,
}
void Parser::RegisterTargetUse(JumpTarget* target, int index) {
// Register that a jump target found at the given index in the target
// stack has been used from the top of the target stack. Add the jump
// target to any TargetCollectors passed on the stack.
void Parser::RegisterTargetUse(BreakTarget* target, int index) {
// Register that a break target found at the given index in the
// target stack has been used from the top of the target stack. Add
// the break target to any TargetCollectors passed on the stack.
for (int i = target_stack_->length(); i-- > index;) {
TargetCollector* collector = target_stack_->at(i)->AsTargetCollector();
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