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 10 #include "src/base/functional.h" 11 #include "src/base/logging.h" 12 #include "src/base/platform/platform.h" 13 14 namespace v8 { 15 namespace internal { 16 17 18 SimpleStringBuilder::SimpleStringBuilder(int size) { 19 buffer_ = Vector<char>::New(size); 20 position_ = 0; 21 } 22 23 24 void SimpleStringBuilder::AddString(const char* s) { 25 AddSubstring(s, StrLength(s)); 26 } 27 28 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 37 void SimpleStringBuilder::AddPadding(char c, int count) { 38 for (int i = 0; i < count; i++) { 39 AddCharacter(c); 40 } 41 } 42 43 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 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 79 std::ostream& operator<<(std::ostream& os, FeedbackSlot slot) { 80 return os << "#" << slot.id_; 81 } 82 83 84 size_t hash_value(BailoutId id) { 85 base::hash<int> h; 86 return h(id.id_); 87 } 88 89 90 std::ostream& operator<<(std::ostream& os, BailoutId id) { 91 return os << id.id_; 92 } 93 94 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 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 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 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 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 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 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 148 void Flush(FILE* out) { 149 fflush(out); 150 } 151 152 153 char* ReadLine(const char* prompt) { 154 char* result = NULL; 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) == NULL) { 162 // fgets got an error. Just give up. 163 if (result != NULL) { 164 DeleteArray(result); 165 } 166 return NULL; 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 == NULL) { 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(result != NULL); 200 result[offset] = '\0'; 201 return result; 202 } 203 204 205 char* ReadCharsFromFile(FILE* file, 206 int* size, 207 int extra_space, 208 bool verbose, 209 const char* filename) { 210 if (file == NULL || fseek(file, 0, SEEK_END) != 0) { 211 if (verbose) { 212 base::OS::PrintError("Cannot read from file %s.\n", filename); 213 } 214 return NULL; 215 } 216 217 // Get the size of the file and rewind it. 218 *size = static_cast<int>(ftell(file)); 219 rewind(file); 220 221 char* result = NewArray<char>(*size + extra_space); 222 for (int i = 0; i < *size && feof(file) == 0;) { 223 int read = static_cast<int>(fread(&result[i], 1, *size - i, file)); 224 if (read != (*size - i) && ferror(file) != 0) { 225 fclose(file); 226 DeleteArray(result); 227 return NULL; 228 } 229 i += read; 230 } 231 return result; 232 } 233 234 235 char* ReadCharsFromFile(const char* filename, 236 int* size, 237 int extra_space, 238 bool verbose) { 239 FILE* file = base::OS::FOpen(filename, "rb"); 240 char* result = ReadCharsFromFile(file, size, extra_space, verbose, filename); 241 if (file != NULL) fclose(file); 242 return result; 243 } 244 245 246 byte* ReadBytes(const char* filename, int* size, bool verbose) { 247 char* chars = ReadCharsFromFile(filename, size, 0, verbose); 248 return reinterpret_cast<byte*>(chars); 249 } 250 251 252 static Vector<const char> SetVectorContents(char* chars, 253 int size, 254 bool* exists) { 255 if (!chars) { 256 *exists = false; 257 return Vector<const char>::empty(); 258 } 259 chars[size] = '\0'; 260 *exists = true; 261 return Vector<const char>(chars, size); 262 } 263 264 265 Vector<const char> ReadFile(const char* filename, 266 bool* exists, 267 bool verbose) { 268 int size; 269 char* result = ReadCharsFromFile(filename, &size, 1, verbose); 270 return SetVectorContents(result, size, exists); 271 } 272 273 274 Vector<const char> ReadFile(FILE* file, 275 bool* exists, 276 bool verbose) { 277 int size; 278 char* result = ReadCharsFromFile(file, &size, 1, verbose, ""); 279 return SetVectorContents(result, size, exists); 280 } 281 282 283 int WriteCharsToFile(const char* str, int size, FILE* f) { 284 int total = 0; 285 while (total < size) { 286 int write = static_cast<int>(fwrite(str, 1, size - total, f)); 287 if (write == 0) { 288 return total; 289 } 290 total += write; 291 str += write; 292 } 293 return total; 294 } 295 296 297 int AppendChars(const char* filename, 298 const char* str, 299 int size, 300 bool verbose) { 301 FILE* f = base::OS::FOpen(filename, "ab"); 302 if (f == NULL) { 303 if (verbose) { 304 base::OS::PrintError("Cannot open file %s for writing.\n", filename); 305 } 306 return 0; 307 } 308 int written = WriteCharsToFile(str, size, f); 309 fclose(f); 310 return written; 311 } 312 313 314 int WriteChars(const char* filename, 315 const char* str, 316 int size, 317 bool verbose) { 318 FILE* f = base::OS::FOpen(filename, "wb"); 319 if (f == NULL) { 320 if (verbose) { 321 base::OS::PrintError("Cannot open file %s for writing.\n", filename); 322 } 323 return 0; 324 } 325 int written = WriteCharsToFile(str, size, f); 326 fclose(f); 327 return written; 328 } 329 330 331 int WriteBytes(const char* filename, 332 const byte* bytes, 333 int size, 334 bool verbose) { 335 const char* str = reinterpret_cast<const char*>(bytes); 336 return WriteChars(filename, str, size, verbose); 337 } 338 339 340 341 void StringBuilder::AddFormatted(const char* format, ...) { 342 va_list arguments; 343 va_start(arguments, format); 344 AddFormattedList(format, arguments); 345 va_end(arguments); 346 } 347 348 349 void StringBuilder::AddFormattedList(const char* format, va_list list) { 350 DCHECK(!is_finalized() && position_ <= buffer_.length()); 351 int n = VSNPrintF(buffer_ + position_, format, list); 352 if (n < 0 || n >= (buffer_.length() - position_)) { 353 position_ = buffer_.length(); 354 } else { 355 position_ += n; 356 } 357 } 358 359 360 #if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 361 static void MemMoveWrapper(void* dest, const void* src, size_t size) { 362 memmove(dest, src, size); 363 } 364 365 366 // Initialize to library version so we can call this at any time during startup. 367 static MemMoveFunction memmove_function = &MemMoveWrapper; 368 369 // Defined in codegen-ia32.cc. 370 MemMoveFunction CreateMemMoveFunction(Isolate* isolate); 371 372 // Copy memory area to disjoint memory area. 373 void MemMove(void* dest, const void* src, size_t size) { 374 if (size == 0) return; 375 // Note: here we rely on dependent reads being ordered. This is true 376 // on all architectures we currently support. 377 (*memmove_function)(dest, src, size); 378 } 379 380 #elif V8_OS_POSIX && V8_HOST_ARCH_ARM 381 void MemCopyUint16Uint8Wrapper(uint16_t* dest, const uint8_t* src, 382 size_t chars) { 383 uint16_t* limit = dest + chars; 384 while (dest < limit) { 385 *dest++ = static_cast<uint16_t>(*src++); 386 } 387 } 388 389 V8_EXPORT_PRIVATE MemCopyUint8Function memcopy_uint8_function = 390 &MemCopyUint8Wrapper; 391 MemCopyUint16Uint8Function memcopy_uint16_uint8_function = 392 &MemCopyUint16Uint8Wrapper; 393 // Defined in codegen-arm.cc. 394 MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate, 395 MemCopyUint8Function stub); 396 MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function( 397 Isolate* isolate, MemCopyUint16Uint8Function stub); 398 399 #elif V8_OS_POSIX && V8_HOST_ARCH_MIPS 400 V8_EXPORT_PRIVATE MemCopyUint8Function memcopy_uint8_function = 401 &MemCopyUint8Wrapper; 402 // Defined in codegen-mips.cc. 403 MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate, 404 MemCopyUint8Function stub); 405 #endif 406 407 408 static bool g_memcopy_functions_initialized = false; 409 410 411 void init_memcopy_functions(Isolate* isolate) { 412 if (g_memcopy_functions_initialized) return; 413 g_memcopy_functions_initialized = true; 414 #if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 415 MemMoveFunction generated_memmove = CreateMemMoveFunction(isolate); 416 if (generated_memmove != NULL) { 417 memmove_function = generated_memmove; 418 } 419 #elif V8_OS_POSIX && V8_HOST_ARCH_ARM 420 memcopy_uint8_function = 421 CreateMemCopyUint8Function(isolate, &MemCopyUint8Wrapper); 422 memcopy_uint16_uint8_function = 423 CreateMemCopyUint16Uint8Function(isolate, &MemCopyUint16Uint8Wrapper); 424 #elif V8_OS_POSIX && V8_HOST_ARCH_MIPS 425 memcopy_uint8_function = 426 CreateMemCopyUint8Function(isolate, &MemCopyUint8Wrapper); 427 #endif 428 } 429 430 431 bool DoubleToBoolean(double d) { 432 // NaN, +0, and -0 should return the false object 433 IeeeDoubleArchType u; 434 435 u.d = d; 436 if (u.bits.exp == 2047) { 437 // Detect NaN for IEEE double precision floating point. 438 if ((u.bits.man_low | u.bits.man_high) != 0) return false; 439 } 440 if (u.bits.exp == 0) { 441 // Detect +0, and -0 for IEEE double precision floating point. 442 if ((u.bits.man_low | u.bits.man_high) == 0) return false; 443 } 444 return true; 445 } 446 447 448 } // namespace internal 449 } // namespace v8 450