// 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_(nullptr),
else_environment_(nullptr) {}
// 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_(nullptr),
continue_environment_(nullptr),
break_environment_(nullptr),
assigned_(nullptr) {}
// Primitive control commands.
void BeginLoop(BitVector* assigned, bool is_osr = false);
void Continue();
void EndBody();
void EndLoop();
// Primitive support for break.
void Break() final;
// Loop exit support. Used to introduce explicit loop exit control
// node and variable markers.
void ExitLoop(Node** extra_value_to_rename = nullptr);
// 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.
BitVector* assigned_; // Assigned values in the environment.
};
// Tracks control flow for a switch statement.
class SwitchBuilder final : public ControlBuilder {
public:
explicit SwitchBuilder(AstGraphBuilder* builder, int case_count)
: ControlBuilder(builder),
body_environment_(nullptr),
label_environment_(nullptr),
break_environment_(nullptr),
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_(nullptr) {}
// Primitive control commands.
void BeginBlock();
void EndBlock();
// Primitive support for break.
void Break() final;
// Compound control commands for conditional break.
void BreakWhen(Node* condition, BranchHint = BranchHint::kNone);
void BreakUnless(Node* condition, BranchHint hint = BranchHint::kNone);
private:
Environment* break_environment_; // Environment after the block exits.
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_CONTROL_BUILDERS_H_