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