1// Copyright 2014 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_STRINGS_STRING_STREAM_H_
6#define V8_STRINGS_STRING_STREAM_H_
7
8#include <memory>
9
10#include "src/base/small-vector.h"
11#include "src/base/strings.h"
12#include "src/base/vector.h"
13#include "src/handles/handles.h"
14#include "src/objects/heap-object.h"
15#include "src/utils/allocation.h"
16
17namespace v8 {
18namespace internal {
19
20// Forward declarations.
21class ByteArray;
22
23class StringAllocator {
24 public:
25  virtual ~StringAllocator() = default;
26  // Allocate a number of bytes.
27  virtual char* allocate(unsigned bytes) = 0;
28  // Allocate a larger number of bytes and copy the old buffer to the new one.
29  // bytes is an input and output parameter passing the old size of the buffer
30  // and returning the new size.  If allocation fails then we return the old
31  // buffer and do not increase the size.
32  virtual char* grow(unsigned* bytes) = 0;
33};
34
35// Normal allocator uses new[] and delete[].
36class HeapStringAllocator final : public StringAllocator {
37 public:
38  ~HeapStringAllocator() override { DeleteArray(space_); }
39  char* allocate(unsigned bytes) override;
40  char* grow(unsigned* bytes) override;
41
42 private:
43  char* space_;
44};
45
46class FixedStringAllocator final : public StringAllocator {
47 public:
48  FixedStringAllocator(char* buffer, unsigned length)
49      : buffer_(buffer), length_(length) {}
50  ~FixedStringAllocator() override = default;
51  FixedStringAllocator(const FixedStringAllocator&) = delete;
52  FixedStringAllocator& operator=(const FixedStringAllocator&) = delete;
53
54  char* allocate(unsigned bytes) override;
55  char* grow(unsigned* bytes) override;
56
57 private:
58  char* buffer_;
59  unsigned length_;
60};
61
62template <std::size_t kInlineSize>
63class SmallStringOptimizedAllocator final : public StringAllocator {
64 public:
65  using SmallVector = base::SmallVector<char, kInlineSize>;
66
67  explicit SmallStringOptimizedAllocator(SmallVector* vector) V8_NOEXCEPT
68      : vector_(vector) {}
69
70  char* allocate(unsigned bytes) override {
71    vector_->resize_no_init(bytes);
72    return vector_->data();
73  }
74
75  char* grow(unsigned* bytes) override {
76    unsigned new_bytes = *bytes * 2;
77    // Check for overflow.
78    if (new_bytes <= *bytes) {
79      return vector_->data();
80    }
81    vector_->resize_no_init(new_bytes);
82    *bytes = new_bytes;
83    return vector_->data();
84  }
85
86 private:
87  SmallVector* vector_;
88};
89
90class StringStream final {
91  class FmtElm final {
92   public:
93    FmtElm(int value) : FmtElm(INT) {  // NOLINT
94      data_.u_int_ = value;
95    }
96    explicit FmtElm(double value) : FmtElm(DOUBLE) {  // NOLINT
97      data_.u_double_ = value;
98    }
99    FmtElm(const char* value) : FmtElm(C_STR) {  // NOLINT
100      data_.u_c_str_ = value;
101    }
102    FmtElm(const base::Vector<const base::uc16>& value)  // NOLINT
103        : FmtElm(LC_STR) {
104      data_.u_lc_str_ = &value;
105    }
106    FmtElm(Object value) : FmtElm(OBJ) {  // NOLINT
107      data_.u_obj_ = value.ptr();
108    }
109    FmtElm(Handle<Object> value) : FmtElm(HANDLE) {  // NOLINT
110      data_.u_handle_ = value.location();
111    }
112    FmtElm(void* value) : FmtElm(POINTER) {  // NOLINT
113      data_.u_pointer_ = value;
114    }
115
116   private:
117    friend class StringStream;
118    enum Type { INT, DOUBLE, C_STR, LC_STR, OBJ, HANDLE, POINTER };
119
120#ifdef DEBUG
121    Type type_;
122    explicit FmtElm(Type type) : type_(type) {}
123#else
124    explicit FmtElm(Type) {}
125#endif
126
127    union {
128      int u_int_;
129      double u_double_;
130      const char* u_c_str_;
131      const base::Vector<const base::uc16>* u_lc_str_;
132      Address u_obj_;
133      Address* u_handle_;
134      void* u_pointer_;
135    } data_;
136  };
137
138 public:
139  enum ObjectPrintMode { kPrintObjectConcise, kPrintObjectVerbose };
140  explicit StringStream(StringAllocator* allocator,
141                        ObjectPrintMode object_print_mode = kPrintObjectVerbose)
142      : allocator_(allocator),
143        object_print_mode_(object_print_mode),
144        capacity_(kInitialCapacity),
145        length_(0),
146        buffer_(allocator_->allocate(kInitialCapacity)) {
147    buffer_[0] = 0;
148  }
149
150  bool Put(char c);
151  bool Put(String str);
152  bool Put(String str, int start, int end);
153  void Add(const char* format) { Add(base::CStrVector(format)); }
154  void Add(base::Vector<const char> format) {
155    Add(format, base::Vector<FmtElm>());
156  }
157
158  template <typename... Args>
159  void Add(const char* format, Args... args) {
160    Add(base::CStrVector(format), args...);
161  }
162
163  template <typename... Args>
164  void Add(base::Vector<const char> format, Args... args) {
165    FmtElm elems[]{args...};
166    Add(format, base::ArrayVector(elems));
167  }
168
169  // Getting the message out.
170  void OutputToFile(FILE* out);
171  void OutputToStdOut() { OutputToFile(stdout); }
172  void Log(Isolate* isolate);
173  Handle<String> ToString(Isolate* isolate);
174  std::unique_ptr<char[]> ToCString() const;
175  int length() const { return length_; }
176
177  // Object printing support.
178  void PrintName(Object o);
179  void PrintFixedArray(FixedArray array, unsigned int limit);
180  void PrintByteArray(ByteArray ba);
181  void PrintUsingMap(JSObject js_object);
182  void PrintPrototype(JSFunction fun, Object receiver);
183  void PrintSecurityTokenIfChanged(JSFunction function);
184  // NOTE: Returns the code in the output parameter.
185  void PrintFunction(JSFunction function, Object receiver, Code* code);
186
187  // Reset the stream.
188  void Reset() {
189    length_ = 0;
190    buffer_[0] = 0;
191  }
192
193  // Mentioned object cache support.
194  void PrintMentionedObjectCache(Isolate* isolate);
195  V8_EXPORT_PRIVATE static void ClearMentionedObjectCache(Isolate* isolate);
196#ifdef DEBUG
197  bool IsMentionedObjectCacheClear(Isolate* isolate);
198#endif
199
200  static const int kInitialCapacity = 16;
201
202 private:
203  void Add(base::Vector<const char> format, base::Vector<FmtElm> elms);
204  void PrintObject(Object obj);
205
206  StringAllocator* allocator_;
207  ObjectPrintMode object_print_mode_;
208  unsigned capacity_;
209  unsigned length_;  // does not include terminating 0-character
210  char* buffer_;
211
212  bool full() const { return (capacity_ - length_) == 1; }
213  int space() const { return capacity_ - length_; }
214
215  DISALLOW_IMPLICIT_CONSTRUCTORS(StringStream);
216};
217
218}  // namespace internal
219}  // namespace v8
220
221#endif  // V8_STRINGS_STRING_STREAM_H_
222