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