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
16namespace v8 {
17namespace internal {
18
19SimpleStringBuilder::SimpleStringBuilder(int size) {
20 buffer_ = Vector<char>::New(size);
21 position_ = 0;
22}
23
24
25void SimpleStringBuilder::AddString(const char* s) {
26 AddSubstring(s, StrLength(s));
27}
28
29
30void 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
38void SimpleStringBuilder::AddPadding(char c, int count) {
39 for (int i = 0; i < count; i++) {
40 AddCharacter(c);
41 }
42}
43
44
45void 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
63char* 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
80std::ostream& operator<<(std::ostream& os, FeedbackSlot slot) {
81 return os << "#" << slot.id_;
82}
83
84
85size_t hash_value(BailoutId id) {
86 base::hash<int> h;
87 return h(id.id_);
88}
89
90
91std::ostream& operator<<(std::ostream& os, BailoutId id) {
92 return os << id.id_;
93}
94
95
96void 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
104void 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
112void 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
121void 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
130int 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
139int VSNPrintF(Vector<char> str, const char* format, va_list args) {
140 return base::OS::VSNPrintF(str.start(), str.length(), format, args);
141}
142
143
144void StrNCpy(Vector<char> dest, const char* src, size_t n) {
145 base::OS::StrNCpy(dest.start(), dest.length(), src, n);
146}
147
148
149void Flush(FILE* out) {
150 fflush(out);
151}
152
153
154char* 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
205namespace {
206
207std::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
235std::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
243std::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
252std::string ReadFile(const char* filename, bool* exists, bool verbose) {
253 std::vector<char> result = ReadCharsFromFile(filename, exists, verbose);
254 return VectorToString(result);
255}
256
257std::string ReadFile(FILE* file, bool* exists, bool verbose) {
258 std::vector<char> result = ReadCharsFromFile(file, exists, verbose, "");
259 return VectorToString(result);
260}
261
262
263int 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
277int 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
294int 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
311int 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
321void 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
329void 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.
340bool 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
354uintptr_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
370bool 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