blob: b72d6d5f0f5c8ff9be33dfc420726c670ca35707 [file] [log] [blame]
// 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"
#include "src/interpreter/bytecode-label.h"
#include "src/zone-containers.h"
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);
};
class BreakableControlFlowBuilder : public ControlFlowBuilder {
public:
explicit BreakableControlFlowBuilder(BytecodeArrayBuilder* builder)
: ControlFlowBuilder(builder),
break_sites_(builder->zone()) {}
virtual ~BreakableControlFlowBuilder();
// This method should be called by the control flow owner before
// destruction to update sites that emit jumps for break.
void SetBreakTarget(const BytecodeLabel& break_target);
// This method is called when visiting break statements in the AST.
// Inserts a jump to a unbound label that is patched when the corresponding
// SetBreakTarget is called.
void Break() { EmitJump(&break_sites_); }
void BreakIfTrue() { EmitJumpIfTrue(&break_sites_); }
void BreakIfFalse() { EmitJumpIfFalse(&break_sites_); }
void BreakIfUndefined() { EmitJumpIfUndefined(&break_sites_); }
void BreakIfNull() { EmitJumpIfNull(&break_sites_); }
protected:
void EmitJump(ZoneVector<BytecodeLabel>* labels);
void EmitJump(ZoneVector<BytecodeLabel>* labels, int index);
void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels);
void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels, int index);
void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels);
void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels, int index);
void EmitJumpIfUndefined(ZoneVector<BytecodeLabel>* labels);
void EmitJumpIfNull(ZoneVector<BytecodeLabel>* labels);
void BindLabels(const BytecodeLabel& target, ZoneVector<BytecodeLabel>* site);
// Unbound labels that identify jumps for break statements in the code.
ZoneVector<BytecodeLabel> break_sites_;
};
// 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_;
};
// 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),
continue_sites_(builder->zone()) {}
~LoopBuilder();
void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels);
void JumpToHeader() { builder()->Jump(&loop_header_); }
void JumpToHeaderIfTrue() { builder()->JumpIfTrue(&loop_header_); }
void SetContinueTarget();
void EndLoop();
// This method is called when visiting continue statements in the AST.
// Inserts a jump to an unbound label that is patched when SetContinueTarget
// is called.
void Continue() { EmitJump(&continue_sites_); }
void ContinueIfTrue() { EmitJumpIfTrue(&continue_sites_); }
void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_sites_); }
void ContinueIfNull() { EmitJumpIfNull(&continue_sites_); }
private:
BytecodeLabel loop_header_;
BytecodeLabel loop_end_;
// Unbound labels that identify jumps for continue statements in the code.
ZoneVector<BytecodeLabel> continue_sites_;
};
// 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.
void Case(int index) { EmitJumpIfTrue(&case_sites_, index); }
// 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.
void DefaultAt(int index) { EmitJump(&case_sites_, index); }
private:
// Unbound labels that identify jumps for case statements in the code.
ZoneVector<BytecodeLabel> case_sites_;
};
// A class to help with co-ordinating control flow in try-catch statements.
class TryCatchBuilder final : public ControlFlowBuilder {
public:
explicit TryCatchBuilder(BytecodeArrayBuilder* builder)
: ControlFlowBuilder(builder), handler_id_(builder->NewHandlerEntry()) {}
void BeginTry(Register context);
void EndTry();
void EndCatch();
private:
int handler_id_;
BytecodeLabel handler_;
BytecodeLabel exit_;
};
// A class to help with co-ordinating control flow in try-finally statements.
class TryFinallyBuilder final : public ControlFlowBuilder {
public:
explicit TryFinallyBuilder(BytecodeArrayBuilder* builder, bool will_catch)
: ControlFlowBuilder(builder),
handler_id_(builder->NewHandlerEntry()),
finalization_sites_(builder->zone()),
will_catch_(will_catch) {}
void BeginTry(Register context);
void LeaveTry();
void EndTry();
void BeginHandler();
void BeginFinally();
void EndFinally();
private:
int handler_id_;
BytecodeLabel handler_;
// Unbound labels that identify jumps to the finally block in the code.
ZoneVector<BytecodeLabel> finalization_sites_;
// Conservative prediction of whether exceptions thrown into the handler for
// this finally block will be caught. Note that such a prediction depends on
// whether this try-finally is nested inside a surrounding try-catch.
bool will_catch_;
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_