• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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_PROFILER_OUTPUT_STREAM_WRITER_H_
6 #define V8_PROFILER_OUTPUT_STREAM_WRITER_H_
7 
8 #include <algorithm>
9 #include <string>
10 
11 #include "include/v8-profiler.h"
12 #include "src/base/logging.h"
13 #include "src/base/strings.h"
14 #include "src/base/vector.h"
15 #include "src/common/globals.h"
16 #include "src/utils/memcopy.h"
17 
18 namespace v8 {
19 namespace internal {
20 
21 template <int bytes>
22 struct MaxDecimalDigitsIn;
23 template <>
24 struct MaxDecimalDigitsIn<1> {
25   static const int kSigned = 3;
26   static const int kUnsigned = 3;
27 };
28 template <>
29 struct MaxDecimalDigitsIn<4> {
30   static const int kSigned = 11;
31   static const int kUnsigned = 10;
32 };
33 template <>
34 struct MaxDecimalDigitsIn<8> {
35   static const int kSigned = 20;
36   static const int kUnsigned = 20;
37 };
38 
39 class OutputStreamWriter {
40  public:
41   explicit OutputStreamWriter(v8::OutputStream* stream)
42       : stream_(stream),
43         chunk_size_(stream->GetChunkSize()),
44         chunk_(chunk_size_),
45         chunk_pos_(0),
46         aborted_(false) {
47     DCHECK_GT(chunk_size_, 0);
48   }
49   bool aborted() { return aborted_; }
50   void AddCharacter(char c) {
51     DCHECK_NE(c, '\0');
52     DCHECK(chunk_pos_ < chunk_size_);
53     chunk_[chunk_pos_++] = c;
54     MaybeWriteChunk();
55   }
56   void AddString(const char* s) {
57     size_t len = strlen(s);
58     DCHECK_GE(kMaxInt, len);
59     AddSubstring(s, static_cast<int>(len));
60   }
61   void AddSubstring(const char* s, int n) {
62     if (n <= 0) return;
63     DCHECK_LE(n, strlen(s));
64     const char* s_end = s + n;
65     while (s < s_end) {
66       int s_chunk_size =
67           std::min(chunk_size_ - chunk_pos_, static_cast<int>(s_end - s));
68       DCHECK_GT(s_chunk_size, 0);
69       MemCopy(chunk_.begin() + chunk_pos_, s, s_chunk_size);
70       s += s_chunk_size;
71       chunk_pos_ += s_chunk_size;
72       MaybeWriteChunk();
73     }
74   }
75   void AddNumber(unsigned n) { AddNumberImpl<unsigned>(n, "%u"); }
76   void Finalize() {
77     if (aborted_) return;
78     DCHECK(chunk_pos_ < chunk_size_);
79     if (chunk_pos_ != 0) {
80       WriteChunk();
81     }
82     stream_->EndOfStream();
83   }
84 
85  private:
86   template <typename T>
87   void AddNumberImpl(T n, const char* format) {
88     // Buffer for the longest value plus trailing \0
89     static const int kMaxNumberSize =
90         MaxDecimalDigitsIn<sizeof(T)>::kUnsigned + 1;
91     if (chunk_size_ - chunk_pos_ >= kMaxNumberSize) {
92       int result =
93           SNPrintF(chunk_.SubVector(chunk_pos_, chunk_size_), format, n);
94       DCHECK_NE(result, -1);
95       chunk_pos_ += result;
96       MaybeWriteChunk();
97     } else {
98       base::EmbeddedVector<char, kMaxNumberSize> buffer;
99       int result = SNPrintF(buffer, format, n);
100       USE(result);
101       DCHECK_NE(result, -1);
102       AddString(buffer.begin());
103     }
104   }
105   void MaybeWriteChunk() {
106     DCHECK(chunk_pos_ <= chunk_size_);
107     if (chunk_pos_ == chunk_size_) {
108       WriteChunk();
109     }
110   }
111   void WriteChunk() {
112     if (aborted_) return;
113     if (stream_->WriteAsciiChunk(chunk_.begin(), chunk_pos_) ==
114         v8::OutputStream::kAbort)
115       aborted_ = true;
116     chunk_pos_ = 0;
117   }
118 
119   v8::OutputStream* stream_;
120   int chunk_size_;
121   base::ScopedVector<char> chunk_;
122   int chunk_pos_;
123   bool aborted_;
124 };
125 
126 }  // namespace internal
127 }  // namespace v8
128 
129 #endif  // V8_PROFILER_OUTPUT_STREAM_WRITER_H_
130