1 // Copyright 2011 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 #include "src/utils/utils.h"
6
7 #include <stdarg.h>
8 #include <sys/stat.h>
9 #include <vector>
10
11 #include "src/base/functional.h"
12 #include "src/base/logging.h"
13 #include "src/base/platform/platform.h"
14 #include "src/utils/memcopy.h"
15
16 namespace v8 {
17 namespace internal {
18
SimpleStringBuilder(int size)19 SimpleStringBuilder::SimpleStringBuilder(int size) {
20 buffer_ = Vector<char>::New(size);
21 position_ = 0;
22 }
23
AddString(const char * s)24 void SimpleStringBuilder::AddString(const char* s) {
25 size_t len = strlen(s);
26 DCHECK_GE(kMaxInt, len);
27 AddSubstring(s, static_cast<int>(len));
28 }
29
AddSubstring(const char * s,int n)30 void SimpleStringBuilder::AddSubstring(const char* s, int n) {
31 DCHECK(!is_finalized() && position_ + n <= buffer_.length());
32 DCHECK_LE(n, strlen(s));
33 MemCopy(&buffer_[position_], s, n * kCharSize);
34 position_ += n;
35 }
36
AddPadding(char c,int count)37 void SimpleStringBuilder::AddPadding(char c, int count) {
38 for (int i = 0; i < count; i++) {
39 AddCharacter(c);
40 }
41 }
42
AddDecimalInteger(int32_t value)43 void SimpleStringBuilder::AddDecimalInteger(int32_t value) {
44 uint32_t number = static_cast<uint32_t>(value);
45 if (value < 0) {
46 AddCharacter('-');
47 number = static_cast<uint32_t>(-value);
48 }
49 int digits = 1;
50 for (uint32_t factor = 10; digits < 10; digits++, factor *= 10) {
51 if (factor > number) break;
52 }
53 position_ += digits;
54 for (int i = 1; i <= digits; i++) {
55 buffer_[position_ - i] = '0' + static_cast<char>(number % 10);
56 number /= 10;
57 }
58 }
59
Finalize()60 char* SimpleStringBuilder::Finalize() {
61 DCHECK(!is_finalized() && position_ <= buffer_.length());
62 // If there is no space for null termination, overwrite last character.
63 if (position_ == buffer_.length()) {
64 position_--;
65 // Print ellipsis.
66 for (int i = 3; i > 0 && position_ > i; --i) buffer_[position_ - i] = '.';
67 }
68 buffer_[position_] = '\0';
69 // Make sure nobody managed to add a 0-character to the
70 // buffer while building the string.
71 DCHECK(strlen(buffer_.begin()) == static_cast<size_t>(position_));
72 position_ = -1;
73 DCHECK(is_finalized());
74 return buffer_.begin();
75 }
76
operator <<(std::ostream & os,FeedbackSlot slot)77 std::ostream& operator<<(std::ostream& os, FeedbackSlot slot) {
78 return os << "#" << slot.id_;
79 }
80
hash_value(BailoutId id)81 size_t hash_value(BailoutId id) {
82 base::hash<int> h;
83 return h(id.id_);
84 }
85
operator <<(std::ostream & os,BailoutId id)86 std::ostream& operator<<(std::ostream& os, BailoutId id) {
87 return os << id.id_;
88 }
89
PrintF(const char * format,...)90 void PrintF(const char* format, ...) {
91 va_list arguments;
92 va_start(arguments, format);
93 base::OS::VPrint(format, arguments);
94 va_end(arguments);
95 }
96
PrintF(FILE * out,const char * format,...)97 void PrintF(FILE* out, const char* format, ...) {
98 va_list arguments;
99 va_start(arguments, format);
100 base::OS::VFPrint(out, format, arguments);
101 va_end(arguments);
102 }
103
PrintPID(const char * format,...)104 void PrintPID(const char* format, ...) {
105 base::OS::Print("[%d] ", base::OS::GetCurrentProcessId());
106 va_list arguments;
107 va_start(arguments, format);
108 base::OS::VPrint(format, arguments);
109 va_end(arguments);
110 }
111
PrintIsolate(void * isolate,const char * format,...)112 void PrintIsolate(void* isolate, const char* format, ...) {
113 base::OS::Print("[%d:%p] ", base::OS::GetCurrentProcessId(), isolate);
114 va_list arguments;
115 va_start(arguments, format);
116 base::OS::VPrint(format, arguments);
117 va_end(arguments);
118 }
119
SNPrintF(Vector<char> str,const char * format,...)120 int SNPrintF(Vector<char> str, const char* format, ...) {
121 va_list args;
122 va_start(args, format);
123 int result = VSNPrintF(str, format, args);
124 va_end(args);
125 return result;
126 }
127
VSNPrintF(Vector<char> str,const char * format,va_list args)128 int VSNPrintF(Vector<char> str, const char* format, va_list args) {
129 return base::OS::VSNPrintF(str.begin(), str.length(), format, args);
130 }
131
StrNCpy(Vector<char> dest,const char * src,size_t n)132 void StrNCpy(Vector<char> dest, const char* src, size_t n) {
133 base::OS::StrNCpy(dest.begin(), dest.length(), src, n);
134 }
135
ReadLine(const char * prompt)136 char* ReadLine(const char* prompt) {
137 char* result = nullptr;
138 char line_buf[256];
139 size_t offset = 0;
140 bool keep_going = true;
141 fprintf(stdout, "%s", prompt);
142 fflush(stdout);
143 while (keep_going) {
144 if (fgets(line_buf, sizeof(line_buf), stdin) == nullptr) {
145 // fgets got an error. Just give up.
146 if (result != nullptr) {
147 DeleteArray(result);
148 }
149 return nullptr;
150 }
151 size_t len = strlen(line_buf);
152 if (len > 1 && line_buf[len - 2] == '\\' && line_buf[len - 1] == '\n') {
153 // When we read a line that ends with a "\" we remove the escape and
154 // append the remainder.
155 line_buf[len - 2] = '\n';
156 line_buf[len - 1] = 0;
157 len -= 1;
158 } else if ((len > 0) && (line_buf[len - 1] == '\n')) {
159 // Since we read a new line we are done reading the line. This
160 // will exit the loop after copying this buffer into the result.
161 keep_going = false;
162 }
163 if (result == nullptr) {
164 // Allocate the initial result and make room for the terminating '\0'
165 result = NewArray<char>(len + 1);
166 } else {
167 // Allocate a new result with enough room for the new addition.
168 size_t new_len = offset + len + 1;
169 char* new_result = NewArray<char>(new_len);
170 // Copy the existing input into the new array and set the new
171 // array as the result.
172 MemCopy(new_result, result, offset * kCharSize);
173 DeleteArray(result);
174 result = new_result;
175 }
176 // Copy the newly read line into the result.
177 MemCopy(result + offset, line_buf, len * kCharSize);
178 offset += len;
179 }
180 DCHECK_NOT_NULL(result);
181 result[offset] = '\0';
182 return result;
183 }
184
185 namespace {
186
ReadCharsFromFile(FILE * file,bool * exists,bool verbose,const char * filename)187 std::vector<char> ReadCharsFromFile(FILE* file, bool* exists, bool verbose,
188 const char* filename) {
189 if (file == nullptr || fseek(file, 0, SEEK_END) != 0) {
190 if (verbose) {
191 base::OS::PrintError("Cannot read from file %s.\n", filename);
192 }
193 *exists = false;
194 return std::vector<char>();
195 }
196
197 // Get the size of the file and rewind it.
198 ptrdiff_t size = ftell(file);
199 rewind(file);
200
201 std::vector<char> result(size);
202 for (ptrdiff_t i = 0; i < size && feof(file) == 0;) {
203 ptrdiff_t read = fread(result.data() + i, 1, size - i, file);
204 if (read != (size - i) && ferror(file) != 0) {
205 fclose(file);
206 *exists = false;
207 return std::vector<char>();
208 }
209 i += read;
210 }
211 *exists = true;
212 return result;
213 }
214
ReadCharsFromFile(const char * filename,bool * exists,bool verbose)215 std::vector<char> ReadCharsFromFile(const char* filename, bool* exists,
216 bool verbose) {
217 FILE* file = base::OS::FOpen(filename, "rb");
218 std::vector<char> result = ReadCharsFromFile(file, exists, verbose, filename);
219 if (file != nullptr) fclose(file);
220 return result;
221 }
222
VectorToString(const std::vector<char> & chars)223 std::string VectorToString(const std::vector<char>& chars) {
224 if (chars.empty()) {
225 return std::string();
226 }
227 return std::string(chars.begin(), chars.end());
228 }
229
WriteCharsToFile(const char * str,int size,FILE * f)230 int WriteCharsToFile(const char* str, int size, FILE* f) {
231 int total = 0;
232 while (total < size) {
233 int write = static_cast<int>(fwrite(str, 1, size - total, f));
234 if (write == 0) {
235 return total;
236 }
237 total += write;
238 str += write;
239 }
240 return total;
241 }
242
243 } // namespace
244
ReadFile(const char * filename,bool * exists,bool verbose)245 std::string ReadFile(const char* filename, bool* exists, bool verbose) {
246 std::vector<char> result = ReadCharsFromFile(filename, exists, verbose);
247 return VectorToString(result);
248 }
249
ReadFile(FILE * file,bool * exists,bool verbose)250 std::string ReadFile(FILE* file, bool* exists, bool verbose) {
251 std::vector<char> result = ReadCharsFromFile(file, exists, verbose, "");
252 return VectorToString(result);
253 }
254
WriteChars(const char * filename,const char * str,int size,bool verbose)255 int WriteChars(const char* filename, const char* str, int size, bool verbose) {
256 FILE* f = base::OS::FOpen(filename, "wb");
257 if (f == nullptr) {
258 if (verbose) {
259 base::OS::PrintError("Cannot open file %s for writing.\n", filename);
260 }
261 return 0;
262 }
263 int written = WriteCharsToFile(str, size, f);
264 fclose(f);
265 return written;
266 }
267
WriteBytes(const char * filename,const byte * bytes,int size,bool verbose)268 int WriteBytes(const char* filename, const byte* bytes, int size,
269 bool verbose) {
270 const char* str = reinterpret_cast<const char*>(bytes);
271 return WriteChars(filename, str, size, verbose);
272 }
273
AddFormatted(const char * format,...)274 void StringBuilder::AddFormatted(const char* format, ...) {
275 va_list arguments;
276 va_start(arguments, format);
277 AddFormattedList(format, arguments);
278 va_end(arguments);
279 }
280
AddFormattedList(const char * format,va_list list)281 void StringBuilder::AddFormattedList(const char* format, va_list list) {
282 DCHECK(!is_finalized() && position_ <= buffer_.length());
283 int n = VSNPrintF(buffer_ + position_, format, list);
284 if (n < 0 || n >= (buffer_.length() - position_)) {
285 position_ = buffer_.length();
286 } else {
287 position_ += n;
288 }
289 }
290
291 // Returns false iff d is NaN, +0, or -0.
DoubleToBoolean(double d)292 bool DoubleToBoolean(double d) {
293 IeeeDoubleArchType u;
294 u.d = d;
295 if (u.bits.exp == 2047) {
296 // Detect NaN for IEEE double precision floating point.
297 if ((u.bits.man_low | u.bits.man_high) != 0) return false;
298 }
299 if (u.bits.exp == 0) {
300 // Detect +0, and -0 for IEEE double precision floating point.
301 if ((u.bits.man_low | u.bits.man_high) == 0) return false;
302 }
303 return true;
304 }
305
GetCurrentStackPosition()306 uintptr_t GetCurrentStackPosition() {
307 #if V8_CC_MSVC
308 return reinterpret_cast<uintptr_t>(_AddressOfReturnAddress());
309 #else
310 return reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
311 #endif
312 }
313
314 // The filter is a pattern that matches function names in this way:
315 // "*" all; the default
316 // "-" all but the top-level function
317 // "-name" all but the function "name"
318 // "" only the top-level function
319 // "name" only the function "name"
320 // "name*" only functions starting with "name"
321 // "~" none; the tilde is not an identifier
PassesFilter(Vector<const char> name,Vector<const char> filter)322 bool PassesFilter(Vector<const char> name, Vector<const char> filter) {
323 if (filter.size() == 0) return name.size() == 0;
324 auto filter_it = filter.begin();
325 bool positive_filter = true;
326 if (*filter_it == '-') {
327 ++filter_it;
328 positive_filter = false;
329 }
330 if (filter_it == filter.end()) return name.size() != 0;
331 if (*filter_it == '*') return positive_filter;
332 if (*filter_it == '~') return !positive_filter;
333
334 bool prefix_match = filter[filter.size() - 1] == '*';
335 size_t min_match_length = filter.size();
336 if (!positive_filter) min_match_length--; // Subtract 1 for leading '-'.
337 if (prefix_match) min_match_length--; // Subtract 1 for trailing '*'.
338
339 if (name.size() < min_match_length) return !positive_filter;
340
341 // TODO(sigurds): Use the new version of std::mismatch here, once we
342 // can assume C++14.
343 auto res = std::mismatch(filter_it, filter.end(), name.begin());
344 if (res.first == filter.end()) {
345 if (res.second == name.end()) {
346 // The strings match, so {name} passes if we have a {positive_filter}.
347 return positive_filter;
348 }
349 // {name} is longer than the filter, so {name} passes if we don't have a
350 // {positive_filter}.
351 return !positive_filter;
352 }
353 if (*res.first == '*') {
354 // We matched up to the wildcard, so {name} passes if we have a
355 // {positive_filter}.
356 return positive_filter;
357 }
358 // We don't match, so {name} passes if we don't have a {positive_filter}.
359 return !positive_filter;
360 }
361
362 } // namespace internal
363 } // namespace v8
364