control-flow-builders.h 6.29 KB
Newer Older
1 2 3 4 5 6 7 8 9
// Copyright 2015 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_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
#define V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_

#include "src/interpreter/bytecode-array-builder.h"

10
#include "src/interpreter/bytecode-label.h"
11
#include "src/zone/zone-containers.h"
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

namespace v8 {
namespace internal {
namespace interpreter {

class ControlFlowBuilder BASE_EMBEDDED {
 public:
  explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
      : builder_(builder) {}
  virtual ~ControlFlowBuilder() {}

 protected:
  BytecodeArrayBuilder* builder() const { return builder_; }

 private:
  BytecodeArrayBuilder* builder_;

  DISALLOW_COPY_AND_ASSIGN(ControlFlowBuilder);
};

32
class BreakableControlFlowBuilder : public ControlFlowBuilder {
33
 public:
34
  explicit BreakableControlFlowBuilder(BytecodeArrayBuilder* builder)
35
      : ControlFlowBuilder(builder), break_labels_(builder->zone()) {}
36
  virtual ~BreakableControlFlowBuilder();
37

38 39
  // This method should be called by the control flow owner before
  // destruction to update sites that emit jumps for break.
40
  void BindBreakTarget();
41

42
  // This method is called when visiting break statements in the AST.
43 44 45 46 47 48 49
  // Inserts a jump to an unbound label that is patched when the corresponding
  // BindBreakTarget is called.
  void Break() { EmitJump(&break_labels_); }
  void BreakIfTrue() { EmitJumpIfTrue(&break_labels_); }
  void BreakIfFalse() { EmitJumpIfFalse(&break_labels_); }
  void BreakIfUndefined() { EmitJumpIfUndefined(&break_labels_); }
  void BreakIfNull() { EmitJumpIfNull(&break_labels_); }
50

51
  BytecodeLabels* break_labels() { return &break_labels_; }
52

53 54 55 56 57 58
 protected:
  void EmitJump(BytecodeLabels* labels);
  void EmitJumpIfTrue(BytecodeLabels* labels);
  void EmitJumpIfFalse(BytecodeLabels* labels);
  void EmitJumpIfUndefined(BytecodeLabels* labels);
  void EmitJumpIfNull(BytecodeLabels* labels);
59 60

  // Unbound labels that identify jumps for break statements in the code.
61
  BytecodeLabels break_labels_;
62 63
};

64 65 66 67 68 69 70 71 72 73 74 75 76 77

// Class to track control flow for block statements (which can break in JS).
class BlockBuilder final : public BreakableControlFlowBuilder {
 public:
  explicit BlockBuilder(BytecodeArrayBuilder* builder)
      : BreakableControlFlowBuilder(builder) {}

  void EndBlock();

 private:
  BytecodeLabel block_end_;
};


78 79 80 81 82 83
// A class to help with co-ordinating break and continue statements with
// their loop.
class LoopBuilder final : public BreakableControlFlowBuilder {
 public:
  explicit LoopBuilder(BytecodeArrayBuilder* builder)
      : BreakableControlFlowBuilder(builder),
84 85
        continue_labels_(builder->zone()),
        header_labels_(builder->zone()) {}
86 87
  ~LoopBuilder();

88
  void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels);
89
  void JumpToHeader(int loop_depth);
90
  void BindContinueTarget();
91
  void EndLoop();
92 93

  // This method is called when visiting continue statements in the AST.
94
  // Inserts a jump to an unbound label that is patched when BindContinueTarget
95
  // is called.
96 97 98 99 100
  void Continue() { EmitJump(&continue_labels_); }
  void ContinueIfTrue() { EmitJumpIfTrue(&continue_labels_); }
  void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); }
  void ContinueIfNull() { EmitJumpIfNull(&continue_labels_); }

101
 private:
102 103
  BytecodeLabel loop_header_;

104 105 106 107
  // Unbound labels that identify jumps for continue statements in the code and
  // jumps from checking the loop condition to the header for do-while loops.
  BytecodeLabels continue_labels_;
  BytecodeLabels header_labels_;
108 109
};

110

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
// A class to help with co-ordinating break statements with their switch.
class SwitchBuilder final : public BreakableControlFlowBuilder {
 public:
  explicit SwitchBuilder(BytecodeArrayBuilder* builder, int number_of_cases)
      : BreakableControlFlowBuilder(builder),
        case_sites_(builder->zone()) {
    case_sites_.resize(number_of_cases);
  }
  ~SwitchBuilder();

  // This method should be called by the SwitchBuilder owner when the case
  // statement with |index| is emitted to update the case jump site.
  void SetCaseTarget(int index);

  // This method is called when visiting case comparison operation for |index|.
  // Inserts a JumpIfTrue to a unbound label that is patched when the
  // corresponding SetCaseTarget is called.
128
  void Case(int index) { builder()->JumpIfTrue(&case_sites_.at(index)); }
129 130 131 132

  // This method is called when all cases comparisons have been emitted if there
  // is a default case statement. Inserts a Jump to a unbound label that is
  // patched when the corresponding SetCaseTarget is called.
133
  void DefaultAt(int index) { builder()->Jump(&case_sites_.at(index)); }
134 135 136 137 138 139

 private:
  // Unbound labels that identify jumps for case statements in the code.
  ZoneVector<BytecodeLabel> case_sites_;
};

140 141 142 143

// A class to help with co-ordinating control flow in try-catch statements.
class TryCatchBuilder final : public ControlFlowBuilder {
 public:
144 145
  explicit TryCatchBuilder(BytecodeArrayBuilder* builder,
                           HandlerTable::CatchPrediction catch_prediction)
146 147
      : ControlFlowBuilder(builder),
        handler_id_(builder->NewHandlerEntry()),
148
        catch_prediction_(catch_prediction) {}
149 150 151 152 153 154 155

  void BeginTry(Register context);
  void EndTry();
  void EndCatch();

 private:
  int handler_id_;
156
  HandlerTable::CatchPrediction catch_prediction_;
157 158 159 160 161 162 163 164
  BytecodeLabel handler_;
  BytecodeLabel exit_;
};


// A class to help with co-ordinating control flow in try-finally statements.
class TryFinallyBuilder final : public ControlFlowBuilder {
 public:
165
  explicit TryFinallyBuilder(BytecodeArrayBuilder* builder,
166
                             HandlerTable::CatchPrediction catch_prediction)
167 168
      : ControlFlowBuilder(builder),
        handler_id_(builder->NewHandlerEntry()),
169
        catch_prediction_(catch_prediction),
170
        finalization_sites_(builder->zone()) {}
171 172

  void BeginTry(Register context);
173
  void LeaveTry();
174
  void EndTry();
175 176
  void BeginHandler();
  void BeginFinally();
177 178 179 180
  void EndFinally();

 private:
  int handler_id_;
181
  HandlerTable::CatchPrediction catch_prediction_;
182
  BytecodeLabel handler_;
183 184

  // Unbound labels that identify jumps to the finally block in the code.
185
  BytecodeLabels finalization_sites_;
186 187
};

188 189 190 191 192
}  // namespace interpreter
}  // namespace internal
}  // namespace v8

#endif  // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_