utils.cc 10.5 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// 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 13
#include "src/base/logging.h"
#include "src/base/platform/platform.h"
14
#include "src/utils/memcopy.h"
15

16 17
namespace v8 {
namespace internal {
18

19
SimpleStringBuilder::SimpleStringBuilder(int size) {
20
  buffer_ = Vector<char>::New(size);
21 22 23
  position_ = 0;
}

24
void SimpleStringBuilder::AddString(const char* s) {
25 26 27
  size_t len = strlen(s);
  DCHECK_GE(kMaxInt, len);
  AddSubstring(s, static_cast<int>(len));
28 29
}

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 35 36
  position_ += n;
}

37 38 39
void SimpleStringBuilder::AddPadding(char c, int count) {
  for (int i = 0; i < count; i++) {
    AddCharacter(c);
40 41 42
  }
}

43 44 45 46 47 48 49 50 51 52 53 54 55 56
void SimpleStringBuilder::AddDecimalInteger(int32_t value) {
  uint32_t number = static_cast<uint32_t>(value);
  if (value < 0) {
    AddCharacter('-');
    number = static_cast<uint32_t>(-value);
  }
  int digits = 1;
  for (uint32_t factor = 10; digits < 10; digits++, factor *= 10) {
    if (factor > number) break;
  }
  position_ += digits;
  for (int i = 1; i <= digits; i++) {
    buffer_[position_ - i] = '0' + static_cast<char>(number % 10);
    number /= 10;
57 58 59
  }
}

60
char* SimpleStringBuilder::Finalize() {
61
  DCHECK(!is_finalized() && position_ <= buffer_.length());
62 63 64 65 66 67
  // If there is no space for null termination, overwrite last character.
  if (position_ == buffer_.length()) {
    position_--;
    // Print ellipsis.
    for (int i = 3; i > 0 && position_ > i; --i) buffer_[position_ - i] = '.';
  }
68 69 70
  buffer_[position_] = '\0';
  // Make sure nobody managed to add a 0-character to the
  // 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
}

77
std::ostream& operator<<(std::ostream& os, FeedbackSlot slot) {
78 79 80
  return os << "#" << slot.id_;
}

81 82 83 84 85 86 87 88 89
size_t hash_value(BailoutId id) {
  base::hash<int> h;
  return h(id.id_);
}

std::ostream& operator<<(std::ostream& os, BailoutId id) {
  return os << id.id_;
}

90 91 92
void PrintF(const char* format, ...) {
  va_list arguments;
  va_start(arguments, format);
93
  base::OS::VPrint(format, arguments);
94 95 96 97 98 99
  va_end(arguments);
}

void PrintF(FILE* out, const char* format, ...) {
  va_list arguments;
  va_start(arguments, format);
100
  base::OS::VFPrint(out, format, arguments);
101 102 103 104
  va_end(arguments);
}

void PrintPID(const char* format, ...) {
105
  base::OS::Print("[%d] ", base::OS::GetCurrentProcessId());
106 107
  va_list arguments;
  va_start(arguments, format);
108
  base::OS::VPrint(format, arguments);
109 110 111
  va_end(arguments);
}

112 113 114 115 116 117 118 119
void PrintIsolate(void* isolate, const char* format, ...) {
  base::OS::Print("[%d:%p] ", base::OS::GetCurrentProcessId(), isolate);
  va_list arguments;
  va_start(arguments, format);
  base::OS::VPrint(format, arguments);
  va_end(arguments);
}

120 121 122 123 124 125 126 127 128
int SNPrintF(Vector<char> str, const char* format, ...) {
  va_list args;
  va_start(args, format);
  int result = VSNPrintF(str, format, args);
  va_end(args);
  return result;
}

int VSNPrintF(Vector<char> str, const char* format, va_list args) {
129
  return base::OS::VSNPrintF(str.begin(), str.length(), format, args);
130 131 132
}

void StrNCpy(Vector<char> dest, const char* src, size_t n) {
133
  base::OS::StrNCpy(dest.begin(), dest.length(), src, n);
134 135
}

136
char* ReadLine(const char* prompt) {
137
  char* result = nullptr;
138
  char line_buf[256];
139
  size_t offset = 0;
140 141 142 143
  bool keep_going = true;
  fprintf(stdout, "%s", prompt);
  fflush(stdout);
  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 148
        DeleteArray(result);
      }
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 154 155 156 157 158 159 160 161 162
      // When we read a line that ends with a "\" we remove the escape and
      // append the remainder.
      line_buf[len - 2] = '\n';
      line_buf[len - 1] = 0;
      len -= 1;
    } else if ((len > 0) && (line_buf[len - 1] == '\n')) {
      // Since we read a new line we are done reading the line. This
      // will exit the loop after copying this buffer into the result.
      keep_going = false;
    }
163
    if (result == nullptr) {
164 165 166 167
      // Allocate the initial result and make room for the terminating '\0'
      result = NewArray<char>(len + 1);
    } else {
      // Allocate a new result with enough room for the new addition.
168
      size_t new_len = offset + len + 1;
169 170 171
      char* new_result = NewArray<char>(new_len);
      // Copy the existing input into the new array and set the new
      // array as the result.
172
      MemCopy(new_result, result, offset * kCharSize);
173 174 175 176
      DeleteArray(result);
      result = new_result;
    }
    // Copy the newly read line into the result.
177
    MemCopy(result + offset, line_buf, len * kCharSize);
178 179
    offset += len;
  }
180
  DCHECK_NOT_NULL(result);
181 182 183 184
  result[offset] = '\0';
  return result;
}

185
namespace {
186

187 188
std::vector<char> ReadCharsFromFile(FILE* file, bool* exists, bool verbose,
                                    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 194
    *exists = false;
    return std::vector<char>();
195 196 197
  }

  // Get the size of the file and rewind it.
198
  ptrdiff_t size = ftell(file);
199 200
  rewind(file);

201 202 203 204
  std::vector<char> result(size);
  for (ptrdiff_t i = 0; i < size && feof(file) == 0;) {
    ptrdiff_t read = fread(result.data() + i, 1, size - i, file);
    if (read != (size - i) && ferror(file) != 0) {
205
      fclose(file);
206 207
      *exists = false;
      return std::vector<char>();
208 209 210
    }
    i += read;
  }
211
  *exists = true;
212 213 214
  return result;
}

215 216
std::vector<char> ReadCharsFromFile(const char* filename, bool* exists,
                                    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 221 222
  return result;
}

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 230 231 232 233 234 235 236 237 238 239 240 241 242
}

int WriteCharsToFile(const char* str, int size, FILE* f) {
  int total = 0;
  while (total < size) {
    int write = static_cast<int>(fwrite(str, 1, size - total, f));
    if (write == 0) {
      return total;
    }
    total += write;
    str += write;
  }
  return total;
}

243 244 245 246 247 248 249 250 251 252
}  // namespace

std::string ReadFile(const char* filename, bool* exists, bool verbose) {
  std::vector<char> result = ReadCharsFromFile(filename, exists, verbose);
  return VectorToString(result);
}

std::string ReadFile(FILE* file, bool* exists, bool verbose) {
  std::vector<char> result = ReadCharsFromFile(file, exists, verbose, "");
  return VectorToString(result);
253 254
}

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 262 263 264 265 266 267
    }
    return 0;
  }
  int written = WriteCharsToFile(str, size, f);
  fclose(f);
  return written;
}

268
int WriteBytes(const char* filename, const byte* bytes, int size,
269 270 271 272 273 274 275 276 277 278 279 280 281
               bool verbose) {
  const char* str = reinterpret_cast<const char*>(bytes);
  return WriteChars(filename, str, size, verbose);
}

void StringBuilder::AddFormatted(const char* format, ...) {
  va_list arguments;
  va_start(arguments, format);
  AddFormattedList(format, arguments);
  va_end(arguments);
}

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 285 286 287 288 289 290
  if (n < 0 || n >= (buffer_.length() - position_)) {
    position_ = buffer_.length();
  } else {
    position_ += n;
  }
}

291
// Returns false iff d is NaN, +0, or -0.
292
bool DoubleToBoolean(double d) {
293
  IeeeDoubleArchType u;
294 295 296 297 298 299 300 301 302 303 304 305
  u.d = d;
  if (u.bits.exp == 2047) {
    // Detect NaN for IEEE double precision floating point.
    if ((u.bits.man_low | u.bits.man_high) != 0) return false;
  }
  if (u.bits.exp == 0) {
    // Detect +0, and -0 for IEEE double precision floating point.
    if ((u.bits.man_low | u.bits.man_high) == 0) return false;
  }
  return true;
}

306 307 308 309 310 311 312 313
uintptr_t GetCurrentStackPosition() {
#if V8_CC_MSVC
  return reinterpret_cast<uintptr_t>(_AddressOfReturnAddress());
#else
  return reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
#endif
}

314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
// The filter is a pattern that matches function names in this way:
//   "*"      all; the default
//   "-"      all but the top-level function
//   "-name"  all but the function "name"
//   ""       only the top-level function
//   "name"   only the function "name"
//   "name*"  only functions starting with "name"
//   "~"      none; the tilde is not an identifier
bool PassesFilter(Vector<const char> name, Vector<const char> filter) {
  if (filter.size() == 0) return name.size() == 0;
  auto filter_it = filter.begin();
  bool positive_filter = true;
  if (*filter_it == '-') {
    ++filter_it;
    positive_filter = false;
  }
  if (filter_it == filter.end()) return name.size() != 0;
  if (*filter_it == '*') return positive_filter;
  if (*filter_it == '~') return !positive_filter;

  bool prefix_match = filter[filter.size() - 1] == '*';
  size_t min_match_length = filter.size();
  if (!positive_filter) min_match_length--;  // Subtract 1 for leading '-'.
  if (prefix_match) min_match_length--;      // Subtract 1 for trailing '*'.

  if (name.size() < min_match_length) return !positive_filter;

  // TODO(sigurds): Use the new version of std::mismatch here, once we
  // can assume C++14.
  auto res = std::mismatch(filter_it, filter.end(), name.begin());
  if (res.first == filter.end()) {
    if (res.second == name.end()) {
      // The strings match, so {name} passes if we have a {positive_filter}.
      return positive_filter;
    }
    // {name} is longer than the filter, so {name} passes if we don't have a
    // {positive_filter}.
    return !positive_filter;
  }
  if (*res.first == '*') {
    // We matched up to the wildcard, so {name} passes if we have a
    // {positive_filter}.
    return positive_filter;
  }
  // We don't match, so {name} passes if we don't have a {positive_filter}.
  return !positive_filter;
}
361

362 363
}  // namespace internal
}  // namespace v8