• 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/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