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