1// Copyright 2016 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_CODEGEN_SOURCE_POSITION_TABLE_H_
6#define V8_CODEGEN_SOURCE_POSITION_TABLE_H_
7
8#include "src/base/export-template.h"
9#include "src/base/vector.h"
10#include "src/codegen/source-position.h"
11#include "src/common/assert-scope.h"
12#include "src/common/checks.h"
13#include "src/common/globals.h"
14#include "src/zone/zone-containers.h"
15
16namespace v8 {
17namespace internal {
18
19class ByteArray;
20template <typename T>
21class Handle;
22class Isolate;
23class Zone;
24
25struct PositionTableEntry {
26  PositionTableEntry()
27      : code_offset(kFunctionEntryBytecodeOffset),
28        source_position(0),
29        is_statement(false) {}
30  PositionTableEntry(int offset, int64_t source, bool statement)
31      : code_offset(offset), source_position(source), is_statement(statement) {}
32
33  int code_offset;
34  int64_t source_position;
35  bool is_statement;
36};
37
38class V8_EXPORT_PRIVATE SourcePositionTableBuilder {
39 public:
40  enum RecordingMode {
41    // Indicates that source positions are never to be generated. (Resulting in
42    // an empty table).
43    OMIT_SOURCE_POSITIONS,
44    // Indicates that source positions are not currently required, but may be
45    // generated later.
46    LAZY_SOURCE_POSITIONS,
47    // Indicates that source positions should be immediately generated.
48    RECORD_SOURCE_POSITIONS
49  };
50
51  explicit SourcePositionTableBuilder(
52      Zone* zone, RecordingMode mode = RECORD_SOURCE_POSITIONS);
53
54  void AddPosition(size_t code_offset, SourcePosition source_position,
55                   bool is_statement);
56
57  template <typename IsolateT>
58  EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
59  Handle<ByteArray> ToSourcePositionTable(IsolateT* isolate);
60  base::OwnedVector<byte> ToSourcePositionTableVector();
61
62  inline bool Omit() const { return mode_ != RECORD_SOURCE_POSITIONS; }
63  inline bool Lazy() const { return mode_ == LAZY_SOURCE_POSITIONS; }
64
65 private:
66  void AddEntry(const PositionTableEntry& entry);
67
68  RecordingMode mode_;
69  ZoneVector<byte> bytes_;
70#ifdef ENABLE_SLOW_DCHECKS
71  ZoneVector<PositionTableEntry> raw_entries_;
72#endif
73  PositionTableEntry previous_;  // Previously written entry, to compute delta.
74};
75
76class V8_EXPORT_PRIVATE SourcePositionTableIterator {
77 public:
78  // Filter that applies when advancing the iterator. If the filter isn't
79  // satisfied, we advance the iterator again.
80  enum IterationFilter { kJavaScriptOnly = 0, kExternalOnly = 1, kAll = 2 };
81  // Filter that applies only to the first entry of the source position table.
82  // If it is kSkipFunctionEntry, it will skip the FunctionEntry entry if it
83  // exists.
84  enum FunctionEntryFilter {
85    kSkipFunctionEntry = 0,
86    kDontSkipFunctionEntry = 1
87  };
88
89  // Used for saving/restoring the iterator.
90  struct IndexAndPositionState {
91    int index_;
92    PositionTableEntry position_;
93    IterationFilter iteration_filter_;
94    FunctionEntryFilter function_entry_filter_;
95  };
96
97  // We expose three flavours of the iterator, depending on the argument passed
98  // to the constructor:
99
100  // Handlified iterator allows allocation, but it needs a handle (and thus
101  // a handle scope). This is the preferred version.
102  explicit SourcePositionTableIterator(
103      Handle<ByteArray> byte_array,
104      IterationFilter iteration_filter = kJavaScriptOnly,
105      FunctionEntryFilter function_entry_filter = kSkipFunctionEntry);
106
107  // Non-handlified iterator does not need a handle scope, but it disallows
108  // allocation during its lifetime. This is useful if there is no handle
109  // scope around.
110  explicit SourcePositionTableIterator(
111      ByteArray byte_array, IterationFilter iteration_filter = kJavaScriptOnly,
112      FunctionEntryFilter function_entry_filter = kSkipFunctionEntry);
113
114  // Handle-safe iterator based on an a vector located outside the garbage
115  // collected heap, allows allocation during its lifetime.
116  explicit SourcePositionTableIterator(
117      base::Vector<const byte> bytes,
118      IterationFilter iteration_filter = kJavaScriptOnly,
119      FunctionEntryFilter function_entry_filter = kSkipFunctionEntry);
120
121  void Advance();
122
123  int code_offset() const {
124    DCHECK(!done());
125    return current_.code_offset;
126  }
127  SourcePosition source_position() const {
128    DCHECK(!done());
129    return SourcePosition::FromRaw(current_.source_position);
130  }
131  bool is_statement() const {
132    DCHECK(!done());
133    return current_.is_statement;
134  }
135  bool done() const { return index_ == kDone; }
136
137  IndexAndPositionState GetState() const {
138    return {index_, current_, iteration_filter_, function_entry_filter_};
139  }
140
141  void RestoreState(const IndexAndPositionState& saved_state) {
142    index_ = saved_state.index_;
143    current_ = saved_state.position_;
144    iteration_filter_ = saved_state.iteration_filter_;
145    function_entry_filter_ = saved_state.function_entry_filter_;
146  }
147
148 private:
149  // Initializes the source position interator with the first valid bytecode.
150  // Also sets the FunctionEntry SourcePosition if it exists.
151  void Initialize();
152
153  static const int kDone = -1;
154
155  base::Vector<const byte> raw_table_;
156  Handle<ByteArray> table_;
157  int index_ = 0;
158  PositionTableEntry current_;
159  IterationFilter iteration_filter_;
160  FunctionEntryFilter function_entry_filter_;
161  DISALLOW_GARBAGE_COLLECTION(no_gc)
162};
163
164}  // namespace internal
165}  // namespace v8
166
167#endif  // V8_CODEGEN_SOURCE_POSITION_TABLE_H_
168