1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_INTERPRETER_BYTECODE_ARRAY_WRITER_H_
6#define V8_INTERPRETER_BYTECODE_ARRAY_WRITER_H_
7
8#include "src/base/compiler-specific.h"
9#include "src/codegen/source-position-table.h"
10#include "src/common/globals.h"
11#include "src/interpreter/bytecodes.h"
12
13namespace v8 {
14namespace internal {
15
16class BytecodeArray;
17class SourcePositionTableBuilder;
18
19namespace interpreter {
20
21class BytecodeLabel;
22class BytecodeLoopHeader;
23class BytecodeNode;
24class BytecodeJumpTable;
25class ConstantArrayBuilder;
26class HandlerTableBuilder;
27
28namespace bytecode_array_writer_unittest {
29class BytecodeArrayWriterUnittest;
30}  // namespace bytecode_array_writer_unittest
31
32// Class for emitting bytecode as the final stage of the bytecode
33// generation pipeline.
34class V8_EXPORT_PRIVATE BytecodeArrayWriter final {
35 public:
36  BytecodeArrayWriter(
37      Zone* zone, ConstantArrayBuilder* constant_array_builder,
38      SourcePositionTableBuilder::RecordingMode source_position_mode);
39  BytecodeArrayWriter(const BytecodeArrayWriter&) = delete;
40  BytecodeArrayWriter& operator=(const BytecodeArrayWriter&) = delete;
41
42  void Write(BytecodeNode* node);
43  void WriteJump(BytecodeNode* node, BytecodeLabel* label);
44  void WriteJumpLoop(BytecodeNode* node, BytecodeLoopHeader* loop_header);
45  void WriteSwitch(BytecodeNode* node, BytecodeJumpTable* jump_table);
46  void BindLabel(BytecodeLabel* label);
47  void BindLoopHeader(BytecodeLoopHeader* loop_header);
48  void BindJumpTableEntry(BytecodeJumpTable* jump_table, int case_value);
49  void BindHandlerTarget(HandlerTableBuilder* handler_table_builder,
50                         int handler_id);
51  void BindTryRegionStart(HandlerTableBuilder* handler_table_builder,
52                          int handler_id);
53  void BindTryRegionEnd(HandlerTableBuilder* handler_table_builder,
54                        int handler_id);
55
56  void SetFunctionEntrySourcePosition(int position);
57
58  template <typename IsolateT>
59  EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
60  Handle<BytecodeArray> ToBytecodeArray(IsolateT* isolate, int register_count,
61                                        int parameter_count,
62                                        Handle<ByteArray> handler_table);
63
64  template <typename IsolateT>
65  EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
66  Handle<ByteArray> ToSourcePositionTable(IsolateT* isolate);
67
68#ifdef DEBUG
69  // Returns -1 if they match or the offset of the first mismatching byte.
70  int CheckBytecodeMatches(BytecodeArray bytecode);
71#endif
72
73  bool RemainderOfBlockIsDead() const { return exit_seen_in_block_; }
74
75 private:
76  // Maximum sized packed bytecode is comprised of a prefix bytecode,
77  // plus the actual bytecode, plus the maximum number of operands times
78  // the maximum operand size.
79  static const size_t kMaxSizeOfPackedBytecode =
80      2 * sizeof(Bytecode) +
81      Bytecodes::kMaxOperands * static_cast<size_t>(OperandSize::kLast);
82
83  // Constants that act as placeholders for jump operands to be
84  // patched. These have operand sizes that match the sizes of
85  // reserved constant pool entries.
86  const uint32_t k8BitJumpPlaceholder = 0x7f;
87  const uint32_t k16BitJumpPlaceholder =
88      k8BitJumpPlaceholder | (k8BitJumpPlaceholder << 8);
89  const uint32_t k32BitJumpPlaceholder =
90      k16BitJumpPlaceholder | (k16BitJumpPlaceholder << 16);
91
92  void PatchJump(size_t jump_target, size_t jump_location);
93  void PatchJumpWith8BitOperand(size_t jump_location, int delta);
94  void PatchJumpWith16BitOperand(size_t jump_location, int delta);
95  void PatchJumpWith32BitOperand(size_t jump_location, int delta);
96
97  void EmitBytecode(const BytecodeNode* const node);
98  void EmitJump(BytecodeNode* node, BytecodeLabel* label);
99  void EmitJumpLoop(BytecodeNode* node, BytecodeLoopHeader* loop_header);
100  void EmitSwitch(BytecodeNode* node, BytecodeJumpTable* jump_table);
101  void UpdateSourcePositionTable(const BytecodeNode* const node);
102
103  void UpdateExitSeenInBlock(Bytecode bytecode);
104
105  void MaybeElideLastBytecode(Bytecode next_bytecode, bool has_source_info);
106  void InvalidateLastBytecode();
107
108  void StartBasicBlock();
109
110  ZoneVector<uint8_t>* bytecodes() { return &bytecodes_; }
111  SourcePositionTableBuilder* source_position_table_builder() {
112    return &source_position_table_builder_;
113  }
114  ConstantArrayBuilder* constant_array_builder() {
115    return constant_array_builder_;
116  }
117
118  ZoneVector<uint8_t> bytecodes_;
119  int unbound_jumps_;
120  SourcePositionTableBuilder source_position_table_builder_;
121  ConstantArrayBuilder* constant_array_builder_;
122
123  Bytecode last_bytecode_;
124  size_t last_bytecode_offset_;
125  bool last_bytecode_had_source_info_;
126  bool elide_noneffectful_bytecodes_;
127
128  bool exit_seen_in_block_;
129
130  friend class bytecode_array_writer_unittest::BytecodeArrayWriterUnittest;
131};
132
133}  // namespace interpreter
134}  // namespace internal
135}  // namespace v8
136
137#endif  // V8_INTERPRETER_BYTECODE_ARRAY_WRITER_H_
138