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/handles/handles.h" 12 #include "src/objects/heap-object.h" 13 #include "src/utils/allocation.h" 14 #include "src/utils/vector.h" 15 16 namespace v8 { 17 namespace internal { 18 19 // Forward declarations. 20 class ByteArray; 21 22 class StringAllocator { 23 public: 24 virtual ~StringAllocator() = default; 25 // Allocate a number of bytes. 26 virtual char* allocate(unsigned bytes) = 0; 27 // Allocate a larger number of bytes and copy the old buffer to the new one. 28 // bytes is an input and output parameter passing the old size of the buffer 29 // and returning the new size. If allocation fails then we return the old 30 // buffer and do not increase the size. 31 virtual char* grow(unsigned* bytes) = 0; 32 }; 33 34 // Normal allocator uses new[] and delete[]. 35 class HeapStringAllocator final : public StringAllocator { 36 public: ~HeapStringAllocator()37 ~HeapStringAllocator() override { DeleteArray(space_); } 38 char* allocate(unsigned bytes) override; 39 char* grow(unsigned* bytes) override; 40 41 private: 42 char* space_; 43 }; 44 45 class FixedStringAllocator final : public StringAllocator { 46 public: FixedStringAllocator(char * buffer,unsigned length)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 60 template <std::size_t kInlineSize> 61 class SmallStringOptimizedAllocator final : public StringAllocator { 62 public: 63 using SmallVector = base::SmallVector<char, kInlineSize>; 64 SmallStringOptimizedAllocator(SmallVector * vector)65 explicit SmallStringOptimizedAllocator(SmallVector* vector) V8_NOEXCEPT 66 : vector_(vector) {} 67 allocate(unsigned bytes)68 char* allocate(unsigned bytes) override { 69 vector_->resize_no_init(bytes); 70 return vector_->data(); 71 } 72 grow(unsigned * bytes)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 88 class StringStream final { 89 class FmtElm final { 90 public: FmtElm(int value)91 FmtElm(int value) : FmtElm(INT) { // NOLINT 92 data_.u_int_ = value; 93 } FmtElm(double value)94 explicit FmtElm(double value) : FmtElm(DOUBLE) { // NOLINT 95 data_.u_double_ = value; 96 } FmtElm(const char * value)97 FmtElm(const char* value) : FmtElm(C_STR) { // NOLINT 98 data_.u_c_str_ = value; 99 } FmtElm(const Vector<const uc16> & value)100 FmtElm(const Vector<const uc16>& value) : FmtElm(LC_STR) { // NOLINT 101 data_.u_lc_str_ = &value; 102 } FmtElm(Object value)103 FmtElm(Object value) : FmtElm(OBJ) { // NOLINT 104 data_.u_obj_ = value.ptr(); 105 } FmtElm(Handle<Object> value)106 FmtElm(Handle<Object> value) : FmtElm(HANDLE) { // NOLINT 107 data_.u_handle_ = value.location(); 108 } FmtElm(void * value)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_; FmtElm(Type type)119 explicit FmtElm(Type type) : type_(type) {} 120 #else FmtElm(Type)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) allocator_(allocator)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); Add(const char * format)150 void Add(const char* format) { Add(CStrVector(format)); } Add(Vector<const char> format)151 void Add(Vector<const char> format) { Add(format, Vector<FmtElm>()); } 152 153 template <typename... Args> Add(const char * format,Args...args)154 void Add(const char* format, Args... args) { 155 Add(CStrVector(format), args...); 156 } 157 158 template <typename... Args> Add(Vector<const char> format,Args...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); OutputToStdOut()166 void OutputToStdOut() { OutputToFile(stdout); } 167 void Log(Isolate* isolate); 168 Handle<String> ToString(Isolate* isolate); 169 std::unique_ptr<char[]> ToCString() const; length()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. Reset()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 full()207 bool full() const { return (capacity_ - length_) == 1; } space()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_STRINGS_STRING_STREAM_H_ 217