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 <stdarg.h> 6#include <sys/stat.h> 7 8#include "src/v8.h" 9 10#include "src/base/logging.h" 11#include "src/base/platform/platform.h" 12#include "src/utils.h" 13 14namespace v8 { 15namespace internal { 16 17 18SimpleStringBuilder::SimpleStringBuilder(int size) { 19 buffer_ = Vector<char>::New(size); 20 position_ = 0; 21} 22 23 24void SimpleStringBuilder::AddString(const char* s) { 25 AddSubstring(s, StrLength(s)); 26} 27 28 29void 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 37void SimpleStringBuilder::AddPadding(char c, int count) { 38 for (int i = 0; i < count; i++) { 39 AddCharacter(c); 40 } 41} 42 43 44void 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 62char* 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 80void PrintF(const char* format, ...) { 81 va_list arguments; 82 va_start(arguments, format); 83 base::OS::VPrint(format, arguments); 84 va_end(arguments); 85} 86 87 88void PrintF(FILE* out, const char* format, ...) { 89 va_list arguments; 90 va_start(arguments, format); 91 base::OS::VFPrint(out, format, arguments); 92 va_end(arguments); 93} 94 95 96void PrintPID(const char* format, ...) { 97 base::OS::Print("[%d] ", base::OS::GetCurrentProcessId()); 98 va_list arguments; 99 va_start(arguments, format); 100 base::OS::VPrint(format, arguments); 101 va_end(arguments); 102} 103 104 105int SNPrintF(Vector<char> str, const char* format, ...) { 106 va_list args; 107 va_start(args, format); 108 int result = VSNPrintF(str, format, args); 109 va_end(args); 110 return result; 111} 112 113 114int VSNPrintF(Vector<char> str, const char* format, va_list args) { 115 return base::OS::VSNPrintF(str.start(), str.length(), format, args); 116} 117 118 119void StrNCpy(Vector<char> dest, const char* src, size_t n) { 120 base::OS::StrNCpy(dest.start(), dest.length(), src, n); 121} 122 123 124void Flush(FILE* out) { 125 fflush(out); 126} 127 128 129char* ReadLine(const char* prompt) { 130 char* result = NULL; 131 char line_buf[256]; 132 int offset = 0; 133 bool keep_going = true; 134 fprintf(stdout, "%s", prompt); 135 fflush(stdout); 136 while (keep_going) { 137 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) { 138 // fgets got an error. Just give up. 139 if (result != NULL) { 140 DeleteArray(result); 141 } 142 return NULL; 143 } 144 int len = StrLength(line_buf); 145 if (len > 1 && 146 line_buf[len - 2] == '\\' && 147 line_buf[len - 1] == '\n') { 148 // When we read a line that ends with a "\" we remove the escape and 149 // append the remainder. 150 line_buf[len - 2] = '\n'; 151 line_buf[len - 1] = 0; 152 len -= 1; 153 } else if ((len > 0) && (line_buf[len - 1] == '\n')) { 154 // Since we read a new line we are done reading the line. This 155 // will exit the loop after copying this buffer into the result. 156 keep_going = false; 157 } 158 if (result == NULL) { 159 // Allocate the initial result and make room for the terminating '\0' 160 result = NewArray<char>(len + 1); 161 } else { 162 // Allocate a new result with enough room for the new addition. 163 int new_len = offset + len + 1; 164 char* new_result = NewArray<char>(new_len); 165 // Copy the existing input into the new array and set the new 166 // array as the result. 167 MemCopy(new_result, result, offset * kCharSize); 168 DeleteArray(result); 169 result = new_result; 170 } 171 // Copy the newly read line into the result. 172 MemCopy(result + offset, line_buf, len * kCharSize); 173 offset += len; 174 } 175 DCHECK(result != NULL); 176 result[offset] = '\0'; 177 return result; 178} 179 180 181char* ReadCharsFromFile(FILE* file, 182 int* size, 183 int extra_space, 184 bool verbose, 185 const char* filename) { 186 if (file == NULL || fseek(file, 0, SEEK_END) != 0) { 187 if (verbose) { 188 base::OS::PrintError("Cannot read from file %s.\n", filename); 189 } 190 return NULL; 191 } 192 193 // Get the size of the file and rewind it. 194 *size = ftell(file); 195 rewind(file); 196 197 char* result = NewArray<char>(*size + extra_space); 198 for (int i = 0; i < *size && feof(file) == 0;) { 199 int read = static_cast<int>(fread(&result[i], 1, *size - i, file)); 200 if (read != (*size - i) && ferror(file) != 0) { 201 fclose(file); 202 DeleteArray(result); 203 return NULL; 204 } 205 i += read; 206 } 207 return result; 208} 209 210 211char* ReadCharsFromFile(const char* filename, 212 int* size, 213 int extra_space, 214 bool verbose) { 215 FILE* file = base::OS::FOpen(filename, "rb"); 216 char* result = ReadCharsFromFile(file, size, extra_space, verbose, filename); 217 if (file != NULL) fclose(file); 218 return result; 219} 220 221 222byte* ReadBytes(const char* filename, int* size, bool verbose) { 223 char* chars = ReadCharsFromFile(filename, size, 0, verbose); 224 return reinterpret_cast<byte*>(chars); 225} 226 227 228static Vector<const char> SetVectorContents(char* chars, 229 int size, 230 bool* exists) { 231 if (!chars) { 232 *exists = false; 233 return Vector<const char>::empty(); 234 } 235 chars[size] = '\0'; 236 *exists = true; 237 return Vector<const char>(chars, size); 238} 239 240 241Vector<const char> ReadFile(const char* filename, 242 bool* exists, 243 bool verbose) { 244 int size; 245 char* result = ReadCharsFromFile(filename, &size, 1, verbose); 246 return SetVectorContents(result, size, exists); 247} 248 249 250Vector<const char> ReadFile(FILE* file, 251 bool* exists, 252 bool verbose) { 253 int size; 254 char* result = ReadCharsFromFile(file, &size, 1, verbose, ""); 255 return SetVectorContents(result, size, exists); 256} 257 258 259int WriteCharsToFile(const char* str, int size, FILE* f) { 260 int total = 0; 261 while (total < size) { 262 int write = static_cast<int>(fwrite(str, 1, size - total, f)); 263 if (write == 0) { 264 return total; 265 } 266 total += write; 267 str += write; 268 } 269 return total; 270} 271 272 273int AppendChars(const char* filename, 274 const char* str, 275 int size, 276 bool verbose) { 277 FILE* f = base::OS::FOpen(filename, "ab"); 278 if (f == NULL) { 279 if (verbose) { 280 base::OS::PrintError("Cannot open file %s for writing.\n", filename); 281 } 282 return 0; 283 } 284 int written = WriteCharsToFile(str, size, f); 285 fclose(f); 286 return written; 287} 288 289 290int WriteChars(const char* filename, 291 const char* str, 292 int size, 293 bool verbose) { 294 FILE* f = base::OS::FOpen(filename, "wb"); 295 if (f == NULL) { 296 if (verbose) { 297 base::OS::PrintError("Cannot open file %s for writing.\n", filename); 298 } 299 return 0; 300 } 301 int written = WriteCharsToFile(str, size, f); 302 fclose(f); 303 return written; 304} 305 306 307int WriteBytes(const char* filename, 308 const byte* bytes, 309 int size, 310 bool verbose) { 311 const char* str = reinterpret_cast<const char*>(bytes); 312 return WriteChars(filename, str, size, verbose); 313} 314 315 316 317void StringBuilder::AddFormatted(const char* format, ...) { 318 va_list arguments; 319 va_start(arguments, format); 320 AddFormattedList(format, arguments); 321 va_end(arguments); 322} 323 324 325void StringBuilder::AddFormattedList(const char* format, va_list list) { 326 DCHECK(!is_finalized() && position_ <= buffer_.length()); 327 int n = VSNPrintF(buffer_ + position_, format, list); 328 if (n < 0 || n >= (buffer_.length() - position_)) { 329 position_ = buffer_.length(); 330 } else { 331 position_ += n; 332 } 333} 334 335 336#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 337static void MemMoveWrapper(void* dest, const void* src, size_t size) { 338 memmove(dest, src, size); 339} 340 341 342// Initialize to library version so we can call this at any time during startup. 343static MemMoveFunction memmove_function = &MemMoveWrapper; 344 345// Defined in codegen-ia32.cc. 346MemMoveFunction CreateMemMoveFunction(); 347 348// Copy memory area to disjoint memory area. 349void MemMove(void* dest, const void* src, size_t size) { 350 if (size == 0) return; 351 // Note: here we rely on dependent reads being ordered. This is true 352 // on all architectures we currently support. 353 (*memmove_function)(dest, src, size); 354} 355 356#elif V8_OS_POSIX && V8_HOST_ARCH_ARM 357void MemCopyUint16Uint8Wrapper(uint16_t* dest, const uint8_t* src, 358 size_t chars) { 359 uint16_t* limit = dest + chars; 360 while (dest < limit) { 361 *dest++ = static_cast<uint16_t>(*src++); 362 } 363} 364 365 366MemCopyUint8Function memcopy_uint8_function = &MemCopyUint8Wrapper; 367MemCopyUint16Uint8Function memcopy_uint16_uint8_function = 368 &MemCopyUint16Uint8Wrapper; 369// Defined in codegen-arm.cc. 370MemCopyUint8Function CreateMemCopyUint8Function(MemCopyUint8Function stub); 371MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function( 372 MemCopyUint16Uint8Function stub); 373 374#elif V8_OS_POSIX && V8_HOST_ARCH_MIPS 375MemCopyUint8Function memcopy_uint8_function = &MemCopyUint8Wrapper; 376// Defined in codegen-mips.cc. 377MemCopyUint8Function CreateMemCopyUint8Function(MemCopyUint8Function stub); 378#endif 379 380 381void init_memcopy_functions() { 382#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X87 383 MemMoveFunction generated_memmove = CreateMemMoveFunction(); 384 if (generated_memmove != NULL) { 385 memmove_function = generated_memmove; 386 } 387#elif V8_OS_POSIX && V8_HOST_ARCH_ARM 388 memcopy_uint8_function = CreateMemCopyUint8Function(&MemCopyUint8Wrapper); 389 memcopy_uint16_uint8_function = 390 CreateMemCopyUint16Uint8Function(&MemCopyUint16Uint8Wrapper); 391#elif V8_OS_POSIX && V8_HOST_ARCH_MIPS 392 memcopy_uint8_function = CreateMemCopyUint8Function(&MemCopyUint8Wrapper); 393#endif 394} 395 396 397bool DoubleToBoolean(double d) { 398 // NaN, +0, and -0 should return the false object 399#if __BYTE_ORDER == __LITTLE_ENDIAN 400 union IeeeDoubleLittleEndianArchType u; 401#elif __BYTE_ORDER == __BIG_ENDIAN 402 union IeeeDoubleBigEndianArchType u; 403#endif 404 u.d = d; 405 if (u.bits.exp == 2047) { 406 // Detect NaN for IEEE double precision floating point. 407 if ((u.bits.man_low | u.bits.man_high) != 0) return false; 408 } 409 if (u.bits.exp == 0) { 410 // Detect +0, and -0 for IEEE double precision floating point. 411 if ((u.bits.man_low | u.bits.man_high) == 0) return false; 412 } 413 return true; 414} 415 416 417} } // namespace v8::internal 418