v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
utils.h
Go to the documentation of this file.
1// Copyright 2017 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#ifndef V8_TORQUE_UTILS_H_
6#define V8_TORQUE_UTILS_H_
7
8#include <algorithm>
9#include <optional>
10#include <ostream>
11#include <queue>
12#include <streambuf>
13#include <string>
14#include <unordered_set>
15
16#include "src/base/contextual.h"
17#include "src/base/hashing.h"
19
20namespace v8::internal::torque {
21
22std::string StringLiteralUnquote(const std::string& s);
23std::string StringLiteralQuote(const std::string& s);
24
25// Decodes "file://" URIs into file paths which can then be used
26// with the standard stream API.
27V8_EXPORT_PRIVATE std::optional<std::string> FileUriDecode(
28 const std::string& s);
29
31 enum class Kind { kError, kLint };
32
33 std::string message;
34 std::optional<SourcePosition> position;
36};
37
38DECLARE_CONTEXTUAL_VARIABLE(TorqueMessages, std::vector<TorqueMessage>);
39
40template <class... Args>
41std::string ToString(Args&&... args) {
42 std::stringstream stream;
43 USE((stream << std::forward<Args>(args))...);
44 return stream.str();
45}
46
48 public:
49 MessageBuilder() = delete;
50 MessageBuilder(const std::string& message, TorqueMessage::Kind kind);
51
53 message_.position = position;
54 return *this;
55 }
56
57 [[noreturn]] void Throw() const;
58
60 // This will also get called in case the error is thrown.
61 Report();
62 }
63
64 private:
65 void Report() const;
66
68 std::vector<TorqueMessage> extra_messages_;
69};
70
71// Used for throwing exceptions. Retrieve TorqueMessage from the contextual
72// for specific error information.
74
75template <class... Args>
77 return MessageBuilder(ToString(std::forward<Args>(args)...), kind);
78}
79
80template <class... Args>
82 return Message(TorqueMessage::Kind::kError, std::forward<Args>(args)...);
83}
84template <class... Args>
86 return Message(TorqueMessage::Kind::kLint, std::forward<Args>(args)...);
87}
88
89bool IsLowerCamelCase(const std::string& s);
90bool IsUpperCamelCase(const std::string& s);
91bool IsSnakeCase(const std::string& s);
92bool IsValidNamespaceConstName(const std::string& s);
93bool IsValidTypeName(const std::string& s);
94
95template <class... Args>
96[[noreturn]] void ReportError(Args&&... args) {
97 Error(std::forward<Args>(args)...).Throw();
98}
99
100std::string CapifyStringWithUnderscores(const std::string& camellified_string);
101std::string CamelifyString(const std::string& underscore_string);
102std::string SnakeifyString(const std::string& camel_string);
103std::string DashifyString(const std::string& underscore_string);
104std::string UnderlinifyPath(std::string path);
105
106bool StartsWithSingleUnderscore(const std::string& str);
107
108void ReplaceFileContentsIfDifferent(const std::string& file_path,
109 const std::string& contents);
110
111template <class T>
113 public:
114 const T* Add(T x) { return &*(storage_.insert(std::move(x)).first); }
115
116 private:
117 std::unordered_set<T, base::hash<T>> storage_;
118};
119
120template <class T>
122 return *x;
123}
124template <class T>
126 return std::forward<T>(x);
127}
128
129template <class T, class L>
131 const T& list;
132 const std::string& separator;
134
135 friend std::ostream& operator<<(std::ostream& os, const ListPrintAdaptor& l) {
136 bool first = true;
137 for (auto& e : l.list) {
138 if (first) {
139 first = false;
140 } else {
141 os << l.separator;
142 }
143 os << DereferenceIfPointer(l.transformer(e));
144 }
145 return os;
146 }
147};
148
149template <class T>
150auto PrintList(const T& list, const std::string& separator = ", ") {
151 using ElementType = decltype(*list.begin());
152 auto id = [](ElementType el) { return el; };
153 return ListPrintAdaptor<T, decltype(id)>{list, separator, id};
154}
155
156template <class T, class L>
157auto PrintList(const T& list, const std::string& separator, L&& transformer) {
159 std::forward<L>(transformer)};
160}
161
162template <class C, class T>
163void PrintCommaSeparatedList(std::ostream& os, const T& list, C&& transform) {
164 os << PrintList(list, ", ", std::forward<C>(transform));
165}
166
167template <class T>
168void PrintCommaSeparatedList(std::ostream& os, const T& list) {
169 os << PrintList(list, ", ");
170}
171
173 size_t offset;
174
175 BottomOffset& operator=(std::size_t other_offset) {
176 this->offset = other_offset;
177 return *this;
178 }
180 ++offset;
181 return *this;
182 }
183 BottomOffset operator+(size_t x) const { return BottomOffset{offset + x}; }
184 BottomOffset operator-(size_t x) const {
186 return BottomOffset{offset - x};
187 }
188 bool operator<(const BottomOffset& other) const {
189 return offset < other.offset;
190 }
191 bool operator<=(const BottomOffset& other) const {
192 return offset <= other.offset;
193 }
194 bool operator==(const BottomOffset& other) const {
195 return offset == other.offset;
196 }
197 bool operator!=(const BottomOffset& other) const {
198 return offset != other.offset;
199 }
200};
201
202inline std::ostream& operator<<(std::ostream& out, BottomOffset from_bottom) {
203 return out << "BottomOffset{" << from_bottom.offset << "}";
204}
205
206// An iterator-style range of stack slots.
208 public:
212
213 bool operator==(const StackRange& other) const {
214 return begin_ == other.begin_ && end_ == other.end_;
215 }
216
217 void Extend(StackRange adjacent) {
218 DCHECK_EQ(end_, adjacent.begin_);
219 end_ = adjacent.end_;
220 }
221
222 size_t Size() const { return end_.offset - begin_.offset; }
223 BottomOffset begin() const { return begin_; }
224 BottomOffset end() const { return end_; }
225
226 private:
229};
230
231inline std::ostream& operator<<(std::ostream& out, StackRange range) {
232 return out << "StackRange{" << range.begin() << ", " << range.end() << "}";
233}
234
235template <class T>
236class Stack {
237 public:
238 using value_type = T;
239 Stack() = default;
240 Stack(std::initializer_list<T> initializer)
241 : Stack(std::vector<T>(initializer)) {}
242 explicit Stack(std::vector<T> v) : elements_(std::move(v)) {}
243 size_t Size() const { return elements_.size(); }
244 const T& Peek(BottomOffset from_bottom) const {
245 return elements_.at(from_bottom.offset);
246 }
247 void Poke(BottomOffset from_bottom, T x) {
248 elements_.at(from_bottom.offset) = std::move(x);
249 }
250 void Push(T x) {
251 elements_.push_back(std::move(x));
252 }
253 StackRange TopRange(size_t slot_count) const {
254 DCHECK_GE(Size(), slot_count);
255 return StackRange{AboveTop() - slot_count, AboveTop()};
256 }
257 StackRange PushMany(const std::vector<T>& v) {
258 for (const T& x : v) {
259 Push(x);
260 }
261 return TopRange(v.size());
262 }
263 const T& Top() const { return Peek(AboveTop() - 1); }
264 T Pop() {
265 T result = std::move(elements_.back());
266 elements_.pop_back();
267 return result;
268 }
269 std::vector<T> PopMany(size_t count) {
270 DCHECK_GE(elements_.size(), count);
271 std::vector<T> result;
272 result.reserve(count);
273 for (auto it = elements_.end() - count; it != elements_.end(); ++it) {
274 result.push_back(std::move(*it));
275 }
276 elements_.resize(elements_.size() - count);
277 return result;
278 }
279 // The invalid offset above the top element. This is useful for StackRange.
280 BottomOffset AboveTop() const { return BottomOffset{Size()}; }
281 // Delete the slots in {range}, moving higher slots to fill the gap.
283 DCHECK_LE(range.end(), AboveTop());
284 if (range.Size() == 0) return;
285 for (BottomOffset i = range.end(); i < AboveTop(); ++i) {
286 elements_[i.offset - range.Size()] = std::move(elements_[i.offset]);
287 }
288 elements_.resize(elements_.size() - range.Size());
289 }
290
291 bool operator==(const Stack& other) const {
292 return elements_ == other.elements_;
293 }
294 bool operator!=(const Stack& other) const {
295 return elements_ != other.elements_;
296 }
297
298 T* begin() { return elements_.data(); }
299 T* end() { return begin() + elements_.size(); }
300 const T* begin() const { return elements_.data(); }
301 const T* end() const { return begin() + elements_.size(); }
302
303 private:
304 std::vector<T> elements_;
305};
306
307template <class T>
310 return x;
311}
312
313template <class T>
314inline std::ostream& operator<<(std::ostream& os, const Stack<T>& t) {
315 os << "Stack{";
317 os << "}";
318 return os;
319}
320
321static const char* const kBaseNamespaceName = "base";
322static const char* const kTestNamespaceName = "test";
323
324// Erase elements of a container that has a constant-time erase function, like
325// std::set or std::list. Calling this on std::vector would have quadratic
326// complexity.
327template <class Container, class F>
328void EraseIf(Container* container, F f) {
329 for (auto it = container->begin(); it != container->end();) {
330 if (f(*it)) {
331 it = container->erase(it);
332 } else {
333 ++it;
334 }
335 }
336}
337
338class NullStreambuf : public std::streambuf {
339 public:
340 int overflow(int c) override {
341 setp(buffer_, buffer_ + sizeof(buffer_));
342 return (c == traits_type::eof()) ? '\0' : c;
343 }
344
345 private:
346 char buffer_[64];
347};
348
349class NullOStream : public std::ostream {
350 public:
351 NullOStream() : std::ostream(&buffer_) {}
352
353 private:
355};
356
357inline bool StringStartsWith(const std::string& s, const std::string& prefix) {
358 if (s.size() < prefix.size()) return false;
359 return s.substr(0, prefix.size()) == prefix;
360}
361inline bool StringEndsWith(const std::string& s, const std::string& suffix) {
362 if (s.size() < suffix.size()) return false;
363 return s.substr(s.size() - suffix.size()) == suffix;
364}
365
367 public:
368 IfDefScope(std::ostream& os, std::string d);
369 ~IfDefScope();
370 IfDefScope(const IfDefScope&) = delete;
371 IfDefScope& operator=(const IfDefScope&) = delete;
372
373 private:
374 std::ostream& os_;
375 std::string d_;
376};
377
379 public:
380 NamespaceScope(std::ostream& os,
381 std::initializer_list<std::string> namespaces);
385
386 private:
387 std::ostream& os_;
388 std::vector<std::string> d_;
389};
390
392 public:
393 IncludeGuardScope(std::ostream& os, std::string file_name);
397
398 private:
399 std::ostream& os_;
400 std::string d_;
401};
402
404 public:
405 explicit IncludeObjectMacrosScope(std::ostream& os);
409
410 private:
411 std::ostream& os_;
412};
413
414// A value of ResidueClass is a congruence class of integers modulo a power
415// of 2.
416// In contrast to common modulo arithmetic, we also allow addition and
417// multiplication of congruence classes with different modulus. In this case, we
418// do an abstract-interpretation style approximation to produce an as small as
419// possible congruence class. ResidueClass is used to represent partial
420// knowledge about offsets and sizes to validate alignment constraints.
421// ResidueClass(x,m) = {y \in Z | x == y mod 2^m} = {x+k2^m | k \in Z} where Z
422// is the set of all integers.
423// Notation: 2^x is 2 to the power of x.
425 public:
426 ResidueClass(size_t value, size_t modulus_log_2 =
427 kMaxModulusLog2) // NOLINT(runtime/explicit)
428 : value_(value),
429 modulus_log_2_(std::min(modulus_log_2, kMaxModulusLog2)) {
431 value_ %= size_t{1} << modulus_log_2_;
432 }
433 }
434
435 // 0 modulo 1, in other words, the class of all integers.
436 static ResidueClass Unknown() { return ResidueClass{0, 0}; }
437
438 // If the modulus corresponds to the size of size_t, it represents a concrete
439 // value.
440 std::optional<size_t> SingleValue() const {
442 return std::nullopt;
443 }
444
445 friend ResidueClass operator+(const ResidueClass& a, const ResidueClass& b) {
446 return ResidueClass{a.value_ + b.value_,
447 std::min(a.modulus_log_2_, b.modulus_log_2_)};
448 }
449
450 // Reasoning for the choice of the new modulus:
451 // {x+k2^a | k \in Z} * {y+l2^b | l \in Z}
452 // = {xy + xl2^b + yk2^a + kl2^(a+b)| k,l \in Z},
453 // which is a subset of {xy + k2^c | k \in Z}
454 // if 2^c is a common divisor of x2^b, y2^a and hence also of 2^(a+b) since
455 // x<2^a and y<2^b.
456 // So we use the gcd of x2^b and y2^a as the new modulus.
457 friend ResidueClass operator*(const ResidueClass& a, const ResidueClass& b) {
458 return ResidueClass{a.value_ * b.value_,
459 std::min(a.modulus_log_2_ + b.AlignmentLog2(),
460 b.modulus_log_2_ + a.AlignmentLog2())};
461 }
462
463 friend std::ostream& operator<<(std::ostream& os, const ResidueClass& a);
464
466 *this = *this + other;
467 return *this;
468 }
469
471 *this = *this * other;
472 return *this;
473 }
474
475 // 2^AlignmentLog2() is the larget power of 2 that divides all elements of the
476 // congruence class.
477 size_t AlignmentLog2() const;
478 size_t Alignment() const {
480 return size_t{1} << AlignmentLog2();
481 }
482
483 private:
484 // The value is the representative of the congruence class. It's always
485 // smaller than 2^modulus_log_2_.
486 size_t value_;
487 // Base 2 logarithm of the modulus.
489
490 // size_t values are modulo 2^kMaxModulusLog2, so we don't consider larger
491 // modulus.
492 static const size_t kMaxModulusLog2 = 8 * sizeof(size_t);
493};
494
495template <typename T>
496class Worklist {
497 public:
498 bool IsEmpty() const {
499 DCHECK_EQ(queue_.size(), contained_.size());
500 return queue_.empty();
501 }
502
503 bool Enqueue(T value) {
504 if (contained_.find(value) != contained_.end()) return false;
505 queue_.push(value);
506 contained_.insert(value);
507 DCHECK_EQ(queue_.size(), contained_.size());
508 return true;
509 }
510
512 DCHECK(!IsEmpty());
513 T value = queue_.front();
514 queue_.pop();
515 contained_.erase(value);
516 DCHECK_EQ(queue_.size(), contained_.size());
517 return value;
518 }
519
520 private:
521 std::queue<T> queue_;
522 std::unordered_set<T> contained_;
523};
524
525template <class T, class U, class F>
526std::vector<T> TransformVector(const std::vector<U>& v, F f) {
527 std::vector<T> result;
528 std::transform(v.begin(), v.end(), std::back_inserter(result), f);
529 return result;
530}
531template <class T, class U>
532std::vector<T> TransformVector(const std::vector<U>& v) {
533 return TransformVector<T>(v, [](const U& x) -> T { return x; });
534}
535
536} // namespace v8::internal::torque
537
538#endif // V8_TORQUE_UTILS_H_
#define T
Builtins::Kind kind
Definition builtins.cc:40
std::unordered_set< T, base::hash< T > > storage_
Definition utils.h:117
IfDefScope & operator=(const IfDefScope &)=delete
IfDefScope(const IfDefScope &)=delete
IncludeGuardScope(const IncludeGuardScope &)=delete
IncludeGuardScope & operator=(const IncludeGuardScope &)=delete
IncludeObjectMacrosScope & operator=(const IncludeObjectMacrosScope &)=delete
IncludeObjectMacrosScope(const IncludeObjectMacrosScope &)=delete
MessageBuilder & Position(SourcePosition position)
Definition utils.h:52
std::vector< TorqueMessage > extra_messages_
Definition utils.h:68
NamespaceScope(const NamespaceScope &)=delete
NamespaceScope & operator=(const NamespaceScope &)=delete
std::vector< std::string > d_
Definition utils.h:388
int overflow(int c) override
Definition utils.h:340
friend ResidueClass operator+(const ResidueClass &a, const ResidueClass &b)
Definition utils.h:445
ResidueClass & operator+=(const ResidueClass &other)
Definition utils.h:465
ResidueClass(size_t value, size_t modulus_log_2=kMaxModulusLog2)
Definition utils.h:426
ResidueClass & operator*=(const ResidueClass &other)
Definition utils.h:470
std::optional< size_t > SingleValue() const
Definition utils.h:440
static ResidueClass Unknown()
Definition utils.h:436
static const size_t kMaxModulusLog2
Definition utils.h:492
friend ResidueClass operator*(const ResidueClass &a, const ResidueClass &b)
Definition utils.h:457
friend std::ostream & operator<<(std::ostream &os, const ResidueClass &a)
Definition utils.cc:390
void Extend(StackRange adjacent)
Definition utils.h:217
bool operator==(const StackRange &other) const
Definition utils.h:213
StackRange(BottomOffset begin, BottomOffset end)
Definition utils.h:209
BottomOffset end() const
Definition utils.h:224
BottomOffset begin() const
Definition utils.h:223
BottomOffset AboveTop() const
Definition utils.h:280
const T & Top() const
Definition utils.h:263
const T & Peek(BottomOffset from_bottom) const
Definition utils.h:244
std::vector< T > PopMany(size_t count)
Definition utils.h:269
size_t Size() const
Definition utils.h:243
StackRange TopRange(size_t slot_count) const
Definition utils.h:253
StackRange PushMany(const std::vector< T > &v)
Definition utils.h:257
bool operator==(const Stack &other) const
Definition utils.h:291
void DeleteRange(StackRange range)
Definition utils.h:282
Stack(std::vector< T > v)
Definition utils.h:242
const T * begin() const
Definition utils.h:300
const T * end() const
Definition utils.h:301
void Poke(BottomOffset from_bottom, T x)
Definition utils.h:247
Stack(std::initializer_list< T > initializer)
Definition utils.h:240
std::vector< T > elements_
Definition utils.h:304
bool operator!=(const Stack &other) const
Definition utils.h:294
std::queue< T > queue_
Definition utils.h:521
std::unordered_set< T > contained_
Definition utils.h:522
#define DECLARE_CONTEXTUAL_VARIABLE(VarName,...)
Definition contextual.h:88
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
ZoneVector< RpoNumber > & result
int x
int position
Definition liveedit.cc:290
STL namespace.
bool StringEndsWith(const std::string &s, const std::string &suffix)
Definition utils.h:361
bool IsUpperCamelCase(const std::string &s)
Definition utils.cc:228
std::string CapifyStringWithUnderscores(const std::string &camellified_string)
Definition utils.cc:254
std::ostream & operator<<(std::ostream &os, Identifier *id)
Definition ast.h:263
void EraseIf(Container *container, F f)
Definition utils.h:328
std::string StringLiteralQuote(const std::string &s)
Definition utils.cc:54
void ReportError(Args &&... args)
Definition utils.h:96
void ReplaceFileContentsIfDifferent(const std::string &file_path, const std::string &contents)
Definition utils.cc:327
std::string ToString(Args &&... args)
Definition utils.h:41
static MessageBuilder Message(TorqueMessage::Kind kind, Args &&... args)
Definition utils.h:76
MessageBuilder Lint(Args &&... args)
Definition utils.h:85
T * CheckNotNull(T *x)
Definition utils.h:308
std::string SnakeifyString(const std::string &camel_string)
Definition utils.cc:295
bool IsValidTypeName(const std::string &s)
Definition utils.cc:247
std::string DashifyString(const std::string &underscore_string)
Definition utils.cc:308
bool StartsWithSingleUnderscore(const std::string &str)
Definition utils.cc:323
T & DereferenceIfPointer(T *x)
Definition utils.h:121
bool IsSnakeCase(const std::string &s)
Definition utils.cc:235
std::string CamelifyString(const std::string &underscore_string)
Definition utils.cc:278
std::optional< std::string > FileUriDecode(const std::string &uri)
Definition utils.cc:94
auto PrintList(const T &list, const std::string &separator=", ")
Definition utils.h:150
std::vector< T > TransformVector(const std::vector< U > &v, F f)
Definition utils.h:526
bool IsLowerCamelCase(const std::string &s)
Definition utils.cc:221
bool StringStartsWith(const std::string &s, const std::string &prefix)
Definition utils.h:357
static const char *const kBaseNamespaceName
Definition utils.h:321
bool IsValidNamespaceConstName(const std::string &s)
Definition utils.cc:240
void PrintCommaSeparatedList(std::ostream &os, const T &list, C &&transform)
Definition utils.h:163
std::string UnderlinifyPath(std::string path)
Definition utils.cc:314
static const char *const kTestNamespaceName
Definition utils.h:322
MessageBuilder Error(Args &&... args)
Definition utils.h:81
std::string StringLiteralUnquote(const std::string &s)
Definition utils.cc:23
constexpr int L
constexpr int U
return value
Definition map-inl.h:893
base::Vector< const char > contents
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK_NOT_NULL(val)
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
#define V8_EXPORT_PRIVATE
Definition macros.h:460
BottomOffset operator-(size_t x) const
Definition utils.h:184
BottomOffset operator+(size_t x) const
Definition utils.h:183
BottomOffset & operator=(std::size_t other_offset)
Definition utils.h:175
bool operator==(const BottomOffset &other) const
Definition utils.h:194
bool operator<(const BottomOffset &other) const
Definition utils.h:188
bool operator!=(const BottomOffset &other) const
Definition utils.h:197
BottomOffset & operator++()
Definition utils.h:179
bool operator<=(const BottomOffset &other) const
Definition utils.h:191
const std::string & separator
Definition utils.h:132
friend std::ostream & operator<<(std::ostream &os, const ListPrintAdaptor &l)
Definition utils.h:135
std::optional< SourcePosition > position
Definition utils.h:34
#define V8_NODISCARD
Definition v8config.h:693