064be2385a
This makes sure that the implicit exception edges in the graph pass the correct exception object and also fixes a bug in the dominance relationship of the value entering the finally block and it's uses. R=jarin@chromium.org TEST=cctest/test-run-jsexceptions/FinallyBreak Review URL: https://codereview.chromium.org/970253002 Cr-Commit-Position: refs/heads/master@{#26989}
196 lines
5.8 KiB
C++
196 lines
5.8 KiB
C++
// Copyright 2013 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef V8_COMPILER_CONTROL_BUILDERS_H_
|
|
#define V8_COMPILER_CONTROL_BUILDERS_H_
|
|
|
|
#include "src/compiler/ast-graph-builder.h"
|
|
#include "src/compiler/node.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
// Base class for all control builders. Also provides a common interface for
|
|
// control builders to handle 'break' statements when they are used to model
|
|
// breakable statements.
|
|
class ControlBuilder {
|
|
public:
|
|
explicit ControlBuilder(AstGraphBuilder* builder) : builder_(builder) {}
|
|
virtual ~ControlBuilder() {}
|
|
|
|
// Interface for break.
|
|
virtual void Break() { UNREACHABLE(); }
|
|
|
|
protected:
|
|
typedef AstGraphBuilder Builder;
|
|
typedef AstGraphBuilder::Environment Environment;
|
|
|
|
Zone* zone() const { return builder_->local_zone(); }
|
|
Environment* environment() { return builder_->environment(); }
|
|
void set_environment(Environment* env) { builder_->set_environment(env); }
|
|
Node* the_hole() const { return builder_->jsgraph()->TheHoleConstant(); }
|
|
|
|
Builder* builder_;
|
|
};
|
|
|
|
|
|
// Tracks control flow for a conditional statement.
|
|
class IfBuilder FINAL : public ControlBuilder {
|
|
public:
|
|
explicit IfBuilder(AstGraphBuilder* builder)
|
|
: ControlBuilder(builder),
|
|
then_environment_(NULL),
|
|
else_environment_(NULL) {}
|
|
|
|
// Primitive control commands.
|
|
void If(Node* condition, BranchHint hint = BranchHint::kNone);
|
|
void Then();
|
|
void Else();
|
|
void End();
|
|
|
|
private:
|
|
Environment* then_environment_; // Environment after the 'then' body.
|
|
Environment* else_environment_; // Environment for the 'else' body.
|
|
};
|
|
|
|
|
|
// Tracks control flow for an iteration statement.
|
|
class LoopBuilder FINAL : public ControlBuilder {
|
|
public:
|
|
explicit LoopBuilder(AstGraphBuilder* builder)
|
|
: ControlBuilder(builder),
|
|
loop_environment_(NULL),
|
|
continue_environment_(NULL),
|
|
break_environment_(NULL) {}
|
|
|
|
// Primitive control commands.
|
|
void BeginLoop(BitVector* assigned, bool is_osr = false);
|
|
void Continue();
|
|
void EndBody();
|
|
void EndLoop();
|
|
|
|
// Primitive support for break.
|
|
void Break() FINAL;
|
|
|
|
// Compound control commands for conditional break.
|
|
void BreakUnless(Node* condition);
|
|
void BreakWhen(Node* condition);
|
|
|
|
private:
|
|
Environment* loop_environment_; // Environment of the loop header.
|
|
Environment* continue_environment_; // Environment after the loop body.
|
|
Environment* break_environment_; // Environment after the loop exits.
|
|
};
|
|
|
|
|
|
// Tracks control flow for a switch statement.
|
|
class SwitchBuilder FINAL : public ControlBuilder {
|
|
public:
|
|
explicit SwitchBuilder(AstGraphBuilder* builder, int case_count)
|
|
: ControlBuilder(builder),
|
|
body_environment_(NULL),
|
|
label_environment_(NULL),
|
|
break_environment_(NULL),
|
|
body_environments_(case_count, zone()) {}
|
|
|
|
// Primitive control commands.
|
|
void BeginSwitch();
|
|
void BeginLabel(int index, Node* condition);
|
|
void EndLabel();
|
|
void DefaultAt(int index);
|
|
void BeginCase(int index);
|
|
void EndCase();
|
|
void EndSwitch();
|
|
|
|
// Primitive support for break.
|
|
void Break() FINAL;
|
|
|
|
// The number of cases within a switch is statically known.
|
|
size_t case_count() const { return body_environments_.size(); }
|
|
|
|
private:
|
|
Environment* body_environment_; // Environment after last case body.
|
|
Environment* label_environment_; // Environment for next label condition.
|
|
Environment* break_environment_; // Environment after the switch exits.
|
|
ZoneVector<Environment*> body_environments_;
|
|
};
|
|
|
|
|
|
// Tracks control flow for a block statement.
|
|
class BlockBuilder FINAL : public ControlBuilder {
|
|
public:
|
|
explicit BlockBuilder(AstGraphBuilder* builder)
|
|
: ControlBuilder(builder), break_environment_(NULL) {}
|
|
|
|
// Primitive control commands.
|
|
void BeginBlock();
|
|
void EndBlock();
|
|
|
|
// Primitive support for break.
|
|
void Break() FINAL;
|
|
|
|
private:
|
|
Environment* break_environment_; // Environment after the block exits.
|
|
};
|
|
|
|
|
|
// Tracks control flow for a try-catch statement.
|
|
class TryCatchBuilder FINAL : public ControlBuilder {
|
|
public:
|
|
explicit TryCatchBuilder(AstGraphBuilder* builder)
|
|
: ControlBuilder(builder),
|
|
catch_environment_(NULL),
|
|
exit_environment_(NULL),
|
|
exception_node_(NULL) {}
|
|
|
|
// Primitive control commands.
|
|
void BeginTry();
|
|
void Throw(Node* exception);
|
|
void EndTry();
|
|
void EndCatch();
|
|
|
|
// Returns the exception value inside the 'catch' body.
|
|
Node* GetExceptionNode() const { return exception_node_; }
|
|
|
|
private:
|
|
Environment* catch_environment_; // Environment for the 'catch' body.
|
|
Environment* exit_environment_; // Environment after the statement.
|
|
Node* exception_node_; // Node for exception in 'catch' body.
|
|
};
|
|
|
|
|
|
// Tracks control flow for a try-finally statement.
|
|
class TryFinallyBuilder FINAL : public ControlBuilder {
|
|
public:
|
|
explicit TryFinallyBuilder(AstGraphBuilder* builder)
|
|
: ControlBuilder(builder),
|
|
finally_environment_(NULL),
|
|
token_node_(NULL),
|
|
value_node_(NULL) {}
|
|
|
|
// Primitive control commands.
|
|
void BeginTry();
|
|
void LeaveTry(Node* token, Node* value);
|
|
void EndTry(Node* token, Node* value);
|
|
void EndFinally();
|
|
|
|
// Returns the dispatch token value inside the 'finally' body.
|
|
Node* GetDispatchTokenNode() const { return token_node_; }
|
|
|
|
// Returns the saved result value inside the 'finally' body.
|
|
Node* GetResultValueNode() const { return value_node_; }
|
|
|
|
private:
|
|
Environment* finally_environment_; // Environment for the 'finally' body.
|
|
Node* token_node_; // Node for token in 'finally' body.
|
|
Node* value_node_; // Node for value in 'finally' body.
|
|
};
|
|
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
#endif // V8_COMPILER_CONTROL_BUILDERS_H_
|