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
10 #include <cstring>
11 #include <vector>
12
13 #include "src/base/functional.h"
14 #include "src/base/logging.h"
15 #include "src/base/platform/platform.h"
16 #include "src/base/platform/wrappers.h"
17 #include "src/base/strings.h"
18
19 namespace v8 {
20 namespace internal {
21
operator <<(std::ostream & os,FeedbackSlot slot)22 std::ostream& operator<<(std::ostream& os, FeedbackSlot slot) {
23 return os << "#" << slot.id_;
24 }
25
hash_value(BytecodeOffset id)26 size_t hash_value(BytecodeOffset id) {
27 base::hash<int> h;
28 return h(id.id_);
29 }
30
operator <<(std::ostream & os,BytecodeOffset id)31 std::ostream& operator<<(std::ostream& os, BytecodeOffset id) {
32 return os << id.id_;
33 }
34
PrintF(const char * format,...)35 void PrintF(const char* format, ...) {
36 va_list arguments;
37 va_start(arguments, format);
38 base::OS::VPrint(format, arguments);
39 va_end(arguments);
40 }
41
PrintF(FILE * out,const char * format,...)42 void PrintF(FILE* out, const char* format, ...) {
43 va_list arguments;
44 va_start(arguments, format);
45 base::OS::VFPrint(out, format, arguments);
46 va_end(arguments);
47 }
48
PrintPID(const char * format,...)49 void PrintPID(const char* format, ...) {
50 base::OS::Print("[%d] ", base::OS::GetCurrentProcessId());
51 va_list arguments;
52 va_start(arguments, format);
53 base::OS::VPrint(format, arguments);
54 va_end(arguments);
55 }
56
PrintIsolate(void * isolate,const char * format,...)57 void PrintIsolate(void* isolate, const char* format, ...) {
58 base::OS::Print("[%d:%p] ", base::OS::GetCurrentProcessId(), isolate);
59 va_list arguments;
60 va_start(arguments, format);
61 base::OS::VPrint(format, arguments);
62 va_end(arguments);
63 }
64
ReadLine(const char * prompt)65 char* ReadLine(const char* prompt) {
66 char* result = nullptr;
67 char line_buf[256];
68 size_t offset = 0;
69 bool keep_going = true;
70 fprintf(stdout, "%s", prompt);
71 fflush(stdout);
72 while (keep_going) {
73 if (fgets(line_buf, sizeof(line_buf), stdin) == nullptr) {
74 // fgets got an error. Just give up.
75 if (result != nullptr) {
76 DeleteArray(result);
77 }
78 return nullptr;
79 }
80 size_t len = strlen(line_buf);
81 if (len > 1 && line_buf[len - 2] == '\\' && line_buf[len - 1] == '\n') {
82 // When we read a line that ends with a "\" we remove the escape and
83 // append the remainder.
84 line_buf[len - 2] = '\n';
85 line_buf[len - 1] = 0;
86 len -= 1;
87 } else if ((len > 0) && (line_buf[len - 1] == '\n')) {
88 // Since we read a new line we are done reading the line. This
89 // will exit the loop after copying this buffer into the result.
90 keep_going = false;
91 }
92 if (result == nullptr) {
93 // Allocate the initial result and make room for the terminating '\0'
94 result = NewArray<char>(len + 1);
95 } else {
96 // Allocate a new result with enough room for the new addition.
97 size_t new_len = offset + len + 1;
98 char* new_result = NewArray<char>(new_len);
99 // Copy the existing input into the new array and set the new
100 // array as the result.
101 std::memcpy(new_result, result, offset * kCharSize);
102 DeleteArray(result);
103 result = new_result;
104 }
105 // Copy the newly read line into the result.
106 std::memcpy(result + offset, line_buf, len * kCharSize);
107 offset += len;
108 }
109 DCHECK_NOT_NULL(result);
110 result[offset] = '\0';
111 return result;
112 }
113
114 namespace {
115
ReadCharsFromFile(FILE * file,bool * exists,bool verbose,const char * filename)116 std::vector<char> ReadCharsFromFile(FILE* file, bool* exists, bool verbose,
117 const char* filename) {
118 if (file == nullptr || fseek(file, 0, SEEK_END) != 0) {
119 if (verbose) {
120 base::OS::PrintError("Cannot read from file %s.\n", filename);
121 }
122 *exists = false;
123 return std::vector<char>();
124 }
125
126 // Get the size of the file and rewind it.
127 ptrdiff_t size = ftell(file);
128 rewind(file);
129
130 std::vector<char> result(size);
131 for (ptrdiff_t i = 0; i < size && feof(file) == 0;) {
132 ptrdiff_t read = fread(result.data() + i, 1, size - i, file);
133 if (read != (size - i) && ferror(file) != 0) {
134 base::Fclose(file);
135 *exists = false;
136 return std::vector<char>();
137 }
138 i += read;
139 }
140 *exists = true;
141 return result;
142 }
143
ReadCharsFromFile(const char * filename,bool * exists,bool verbose)144 std::vector<char> ReadCharsFromFile(const char* filename, bool* exists,
145 bool verbose) {
146 FILE* file = base::OS::FOpen(filename, "rb");
147 std::vector<char> result = ReadCharsFromFile(file, exists, verbose, filename);
148 if (file != nullptr) base::Fclose(file);
149 return result;
150 }
151
VectorToString(const std::vector<char> & chars)152 std::string VectorToString(const std::vector<char>& chars) {
153 if (chars.empty()) {
154 return std::string();
155 }
156 return std::string(chars.begin(), chars.end());
157 }
158
WriteCharsToFile(const char * str,int size,FILE * f)159 int WriteCharsToFile(const char* str, int size, FILE* f) {
160 int total = 0;
161 while (total < size) {
162 int write = static_cast<int>(fwrite(str, 1, size - total, f));
163 if (write == 0) {
164 return total;
165 }
166 total += write;
167 str += write;
168 }
169 return total;
170 }
171
172 } // namespace
173
ReadFile(const char * filename,bool * exists,bool verbose)174 std::string ReadFile(const char* filename, bool* exists, bool verbose) {
175 std::vector<char> result = ReadCharsFromFile(filename, exists, verbose);
176 return VectorToString(result);
177 }
178
ReadFile(FILE * file,bool * exists,bool verbose)179 std::string ReadFile(FILE* file, bool* exists, bool verbose) {
180 std::vector<char> result = ReadCharsFromFile(file, exists, verbose, "");
181 return VectorToString(result);
182 }
183
WriteChars(const char * filename,const char * str,int size,bool verbose)184 int WriteChars(const char* filename, const char* str, int size, bool verbose) {
185 FILE* f = base::OS::FOpen(filename, "wb");
186 if (f == nullptr) {
187 if (verbose) {
188 base::OS::PrintError("Cannot open file %s for writing.\n", filename);
189 }
190 return 0;
191 }
192 int written = WriteCharsToFile(str, size, f);
193 base::Fclose(f);
194 return written;
195 }
196
WriteBytes(const char * filename,const byte * bytes,int size,bool verbose)197 int WriteBytes(const char* filename, const byte* bytes, int size,
198 bool verbose) {
199 const char* str = reinterpret_cast<const char*>(bytes);
200 return WriteChars(filename, str, size, verbose);
201 }
202
203 // Returns false iff d is NaN, +0, or -0.
DoubleToBoolean(double d)204 bool DoubleToBoolean(double d) {
205 IeeeDoubleArchType u;
206 u.d = d;
207 if (u.bits.exp == 2047) {
208 // Detect NaN for IEEE double precision floating point.
209 if ((u.bits.man_low | u.bits.man_high) != 0) return false;
210 }
211 if (u.bits.exp == 0) {
212 // Detect +0, and -0 for IEEE double precision floating point.
213 if ((u.bits.man_low | u.bits.man_high) == 0) return false;
214 }
215 return true;
216 }
217
GetCurrentStackPosition()218 uintptr_t GetCurrentStackPosition() {
219 #if V8_CC_MSVC
220 return reinterpret_cast<uintptr_t>(_AddressOfReturnAddress());
221 #else
222 return reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
223 #endif
224 }
225
226 // The filter is a pattern that matches function names in this way:
227 // "*" all; the default
228 // "-" all but the top-level function
229 // "-name" all but the function "name"
230 // "" only the top-level function
231 // "name" only the function "name"
232 // "name*" only functions starting with "name"
233 // "~" none; the tilde is not an identifier
PassesFilter(base::Vector<const char> name,base::Vector<const char> filter)234 bool PassesFilter(base::Vector<const char> name,
235 base::Vector<const char> filter) {
236 if (filter.size() == 0) return name.size() == 0;
237 auto filter_it = filter.begin();
238 bool positive_filter = true;
239 if (*filter_it == '-') {
240 ++filter_it;
241 positive_filter = false;
242 }
243 if (filter_it == filter.end()) return name.size() != 0;
244 if (*filter_it == '*') return positive_filter;
245 if (*filter_it == '~') return !positive_filter;
246
247 bool prefix_match = filter[filter.size() - 1] == '*';
248 size_t min_match_length = filter.size();
249 if (!positive_filter) min_match_length--; // Subtract 1 for leading '-'.
250 if (prefix_match) min_match_length--; // Subtract 1 for trailing '*'.
251
252 if (name.size() < min_match_length) return !positive_filter;
253
254 // TODO(sigurds): Use the new version of std::mismatch here, once we
255 // can assume C++14.
256 auto res = std::mismatch(filter_it, filter.end(), name.begin());
257 if (res.first == filter.end()) {
258 if (res.second == name.end()) {
259 // The strings match, so {name} passes if we have a {positive_filter}.
260 return positive_filter;
261 }
262 // {name} is longer than the filter, so {name} passes if we don't have a
263 // {positive_filter}.
264 return !positive_filter;
265 }
266 if (*res.first == '*') {
267 // We matched up to the wildcard, so {name} passes if we have a
268 // {positive_filter}.
269 return positive_filter;
270 }
271 // We don't match, so {name} passes if we don't have a {positive_filter}.
272 return !positive_filter;
273 }
274
275 } // namespace internal
276 } // namespace v8
277