1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_DATASTREAM_H_
6#define RUNTIME_VM_DATASTREAM_H_
7
8#include "include/dart_api.h"
9#include "platform/assert.h"
10#include "platform/utils.h"
11#include "vm/allocation.h"
12#include "vm/exceptions.h"
13#include "vm/globals.h"
14#include "vm/os.h"
15
16namespace dart {
17
18static const int8_t kDataBitsPerByte = 7;
19static const int8_t kByteMask = (1 << kDataBitsPerByte) - 1;
20static const int8_t kMaxUnsignedDataPerByte = kByteMask;
21static const int8_t kMinDataPerByte = -(1 << (kDataBitsPerByte - 1));
22static const int8_t kMaxDataPerByte = (~kMinDataPerByte & kByteMask); // NOLINT
23static const uint8_t kEndByteMarker = (255 - kMaxDataPerByte);
24static const uint8_t kEndUnsignedByteMarker = (255 - kMaxUnsignedDataPerByte);
25
26typedef uint8_t* (*ReAlloc)(uint8_t* ptr, intptr_t old_size, intptr_t new_size);
27typedef void (*DeAlloc)(uint8_t* ptr);
28
29// Stream for reading various types from a buffer.
30class ReadStream : public ValueObject {
31 public:
32 ReadStream(const uint8_t* buffer, intptr_t size)
33 : buffer_(buffer), current_(buffer), end_(buffer + size) {}
34
35 void SetStream(const uint8_t* buffer, intptr_t size) {
36 buffer_ = buffer;
37 current_ = buffer;
38 end_ = buffer + size;
39 }
40
41 template <int N, typename T>
42 class Raw {};
43
44 template <typename T>
45 class Raw<1, T> {
46 public:
47 static T Read(ReadStream* st) { return bit_cast<T>(st->ReadByte()); }
48 };
49
50 template <typename T>
51 class Raw<2, T> {
52 public:
53 static T Read(ReadStream* st) { return bit_cast<T>(st->Read16()); }
54 };
55
56 template <typename T>
57 class Raw<4, T> {
58 public:
59 static T Read(ReadStream* st) { return bit_cast<T>(st->Read32()); }
60 };
61
62 template <typename T>
63 class Raw<8, T> {
64 public:
65 static T Read(ReadStream* st) { return bit_cast<T>(st->Read64()); }
66 };
67
68 // Reads 'len' bytes from the stream.
69 void ReadBytes(uint8_t* addr, intptr_t len) {
70 ASSERT((end_ - current_) >= len);
71 if (len != 0) {
72 memmove(addr, current_, len);
73 }
74 current_ += len;
75 }
76
77 template <typename T = intptr_t>
78 T ReadUnsigned() {
79 return Read<T>(kEndUnsignedByteMarker);
80 }
81
82 intptr_t Position() const { return current_ - buffer_; }
83 void SetPosition(intptr_t value) {
84 ASSERT((end_ - buffer_) > value);
85 current_ = buffer_ + value;
86 }
87
88 void Align(intptr_t alignment) {
89 intptr_t position_before = Position();
90 intptr_t position_after = Utils::RoundUp(position_before, alignment);
91 Advance(position_after - position_before);
92 }
93
94 const uint8_t* AddressOfCurrentPosition() const { return current_; }
95
96 void Advance(intptr_t value) {
97 ASSERT((end_ - current_) >= value);
98 current_ = current_ + value;
99 }
100
101 intptr_t PendingBytes() const {
102 ASSERT(end_ >= current_);
103 return (end_ - current_);
104 }
105
106 template <typename T>
107 T Read() {
108 return Read<T>(kEndByteMarker);
109 }
110
111 uword ReadWordWith32BitReads() {
112 constexpr intptr_t kNumBytesPerRead32 = sizeof(uint32_t);
113 constexpr intptr_t kNumRead32PerWord = sizeof(uword) / kNumBytesPerRead32;
114 constexpr intptr_t kNumBitsPerRead32 = kNumBytesPerRead32 * kBitsPerByte;
115
116 uword value = 0;
117 for (intptr_t j = 0; j < kNumRead32PerWord; j++) {
118 const auto partial_value = Raw<kNumBytesPerRead32, uint32_t>::Read(this);
119 value |= (static_cast<uword>(partial_value) << (j * kNumBitsPerRead32));
120 }
121 return value;
122 }
123
124 private:
125 uint16_t Read16() { return Read16(kEndByteMarker); }
126
127 uint32_t Read32() { return Read32(kEndByteMarker); }
128
129 uint64_t Read64() { return Read64(kEndByteMarker); }
130
131 template <typename T>
132 T Read(uint8_t end_byte_marker) {
133 using Unsigned = typename std::make_unsigned<T>::type;
134 const uint8_t* c = current_;
135 ASSERT(c < end_);
136 Unsigned b = *c++;
137 if (b > kMaxUnsignedDataPerByte) {
138 current_ = c;
139 return b - end_byte_marker;
140 }
141 T r = 0;
142 uint8_t s = 0;
143 do {
144 r |= static_cast<Unsigned>(b) << s;
145 s += kDataBitsPerByte;
146 ASSERT(c < end_);
147 b = *c++;
148 } while (b <= kMaxUnsignedDataPerByte);
149 current_ = c;
150 return r | (static_cast<Unsigned>(b - end_byte_marker) << s);
151 }
152
153 uint16_t Read16(uint8_t end_byte_marker) {
154 const uint8_t* c = current_;
155 ASSERT(c < end_);
156 uint16_t b = *c++;
157 if (b > kMaxUnsignedDataPerByte) {
158 current_ = c;
159 return b - end_byte_marker;
160 }
161 uint16_t r = b;
162 ASSERT(c < end_);
163 b = *c++;
164 if (b > kMaxUnsignedDataPerByte) {
165 current_ = c;
166 return r | (static_cast<uint16_t>(b - end_byte_marker) << 7);
167 }
168
169 r |= b << 7;
170 ASSERT(c < end_);
171 b = *c++;
172 ASSERT(b > kMaxUnsignedDataPerByte);
173 current_ = c;
174 return r | (static_cast<uint16_t>(b - end_byte_marker) << 14);
175 }
176
177 uint32_t Read32(uint8_t end_byte_marker) {
178 const uint8_t* c = current_;
179 ASSERT(c < end_);
180 uint32_t b = *c++;
181 if (b > kMaxUnsignedDataPerByte) {
182 current_ = c;
183 return b - end_byte_marker;
184 }
185
186 uint32_t r = b;
187 ASSERT(c < end_);
188 b = *c++;
189 if (b > kMaxUnsignedDataPerByte) {
190 current_ = c;
191 return r | (static_cast<uint32_t>(b - end_byte_marker) << 7);
192 }
193
194 r |= b << 7;
195 ASSERT(c < end_);
196 b = *c++;
197 if (b > kMaxUnsignedDataPerByte) {
198 current_ = c;
199 return r | (static_cast<uint32_t>(b - end_byte_marker) << 14);
200 }
201
202 r |= b << 14;
203 ASSERT(c < end_);
204 b = *c++;
205 if (b > kMaxUnsignedDataPerByte) {
206 current_ = c;
207 return r | (static_cast<uint32_t>(b - end_byte_marker) << 21);
208 }
209
210 r |= b << 21;
211 ASSERT(c < end_);
212 b = *c++;
213 ASSERT(b > kMaxUnsignedDataPerByte);
214 current_ = c;
215 return r | (static_cast<uint32_t>(b - end_byte_marker) << 28);
216 }
217
218 uint64_t Read64(uint8_t end_byte_marker) {
219 const uint8_t* c = current_;
220 ASSERT(c < end_);
221 uint64_t b = *c++;
222 if (b > kMaxUnsignedDataPerByte) {
223 current_ = c;
224 return b - end_byte_marker;
225 }
226 uint64_t r = b;
227 ASSERT(c < end_);
228 b = *c++;
229 if (b > kMaxUnsignedDataPerByte) {
230 current_ = c;
231 return r | (static_cast<uint64_t>(b - end_byte_marker) << 7);
232 }
233
234 r |= b << 7;
235 ASSERT(c < end_);
236 b = *c++;
237 if (b > kMaxUnsignedDataPerByte) {
238 current_ = c;
239 return r | (static_cast<uint64_t>(b - end_byte_marker) << 14);
240 }
241
242 r |= b << 14;
243 ASSERT(c < end_);
244 b = *c++;
245 if (b > kMaxUnsignedDataPerByte) {
246 current_ = c;
247 return r | (static_cast<uint64_t>(b - end_byte_marker) << 21);
248 }
249
250 r |= b << 21;
251 ASSERT(c < end_);
252 b = *c++;
253 if (b > kMaxUnsignedDataPerByte) {
254 current_ = c;
255 return r | (static_cast<uint64_t>(b - end_byte_marker) << 28);
256 }
257
258 r |= b << 28;
259 ASSERT(c < end_);
260 b = *c++;
261 if (b > kMaxUnsignedDataPerByte) {
262 current_ = c;
263 return r | (static_cast<uint64_t>(b - end_byte_marker) << 35);
264 }
265
266 r |= b << 35;
267 ASSERT(c < end_);
268 b = *c++;
269 if (b > kMaxUnsignedDataPerByte) {
270 current_ = c;
271 return r | (static_cast<uint64_t>(b - end_byte_marker) << 42);
272 }
273
274 r |= b << 42;
275 ASSERT(c < end_);
276 b = *c++;
277 if (b > kMaxUnsignedDataPerByte) {
278 current_ = c;
279 return r | (static_cast<uint64_t>(b - end_byte_marker) << 49);
280 }
281
282 r |= b << 49;
283 ASSERT(c < end_);
284 b = *c++;
285 if (b > kMaxUnsignedDataPerByte) {
286 current_ = c;
287 return r | (static_cast<uint64_t>(b - end_byte_marker) << 56);
288 }
289
290 r |= b << 56;
291 ASSERT(c < end_);
292 b = *c++;
293 ASSERT(b > kMaxUnsignedDataPerByte);
294 current_ = c;
295 return r | (static_cast<uint64_t>(b - end_byte_marker) << 63);
296 }
297
298 uint8_t ReadByte() {
299 ASSERT(current_ < end_);
300 return *current_++;
301 }
302
303 private:
304 const uint8_t* buffer_;
305 const uint8_t* current_;
306 const uint8_t* end_;
307
308 DISALLOW_COPY_AND_ASSIGN(ReadStream);
309};
310
311// Stream for writing various types into a buffer.
312class WriteStream : public ValueObject {
313 public:
314 WriteStream(uint8_t** buffer, ReAlloc alloc, intptr_t initial_size)
315 : buffer_(buffer),
316 end_(NULL),
317 current_(NULL),
318 current_size_(0),
319 alloc_(alloc),
320 initial_size_(initial_size) {
321 ASSERT(buffer != NULL);
322 ASSERT(alloc != NULL);
323 *buffer_ = reinterpret_cast<uint8_t*>(alloc_(NULL, 0, initial_size_));
324 if (*buffer_ == NULL) {
325 Exceptions::ThrowOOM();
326 }
327 current_ = *buffer_;
328 current_size_ = initial_size_;
329 end_ = *buffer_ + initial_size_;
330 }
331
332 uint8_t* buffer() const { return *buffer_; }
333 void set_buffer(uint8_t* value) { *buffer_ = value; }
334 intptr_t bytes_written() const { return current_ - *buffer_; }
335
336 intptr_t Position() const { return current_ - *buffer_; }
337 void SetPosition(intptr_t value) { current_ = *buffer_ + value; }
338
339 void Align(intptr_t alignment) {
340 intptr_t position_before = Position();
341 intptr_t position_after = Utils::RoundUp(position_before, alignment);
342 memset(current_, 0, position_after - position_before);
343 SetPosition(position_after);
344 }
345
346 template <int N, typename T>
347 class Raw {};
348
349 template <typename T>
350 class Raw<1, T> {
351 public:
352 static void Write(WriteStream* st, T value) {
353 st->WriteByte(bit_cast<int8_t>(value));
354 }
355 };
356
357 template <typename T>
358 class Raw<2, T> {
359 public:
360 static void Write(WriteStream* st, T value) {
361 st->Write<int16_t>(bit_cast<int16_t>(value));
362 }
363 };
364
365 template <typename T>
366 class Raw<4, T> {
367 public:
368 static void Write(WriteStream* st, T value) {
369 st->Write<int32_t>(bit_cast<int32_t>(value));
370 }
371 };
372
373 template <typename T>
374 class Raw<8, T> {
375 public:
376 static void Write(WriteStream* st, T value) {
377 st->Write<int64_t>(bit_cast<int64_t>(value));
378 }
379 };
380
381 void WriteWordWith32BitWrites(uword value) {
382 constexpr intptr_t kNumBytesPerWrite32 = sizeof(uint32_t);
383 constexpr intptr_t kNumWrite32PerWord = sizeof(uword) / kNumBytesPerWrite32;
384 constexpr intptr_t kNumBitsPerWrite32 = kNumBytesPerWrite32 * kBitsPerByte;
385
386 const uint32_t mask = Utils::NBitMask(kNumBitsPerWrite32);
387 for (intptr_t j = 0; j < kNumWrite32PerWord; j++) {
388 const uint32_t shifted_value = (value >> (j * kNumBitsPerWrite32));
389 Raw<kNumBytesPerWrite32, uint32_t>::Write(this, shifted_value & mask);
390 }
391 }
392
393 template <typename T>
394 void WriteUnsigned(T value) {
395 ASSERT(value >= 0);
396 while (value > kMaxUnsignedDataPerByte) {
397 WriteByte(static_cast<uint8_t>(value & kByteMask));
398 value = value >> kDataBitsPerByte;
399 }
400 WriteByte(static_cast<uint8_t>(value + kEndUnsignedByteMarker));
401 }
402
403 void WriteBytes(const void* addr, intptr_t len) {
404 if ((end_ - current_) < len) {
405 Resize(len);
406 }
407 ASSERT((end_ - current_) >= len);
408 if (len != 0) {
409 memmove(current_, addr, len);
410 }
411 current_ += len;
412 }
413
414 void WriteWord(uword value) {
415 const intptr_t len = sizeof(uword);
416 if ((end_ - current_) < len) {
417 Resize(len);
418 }
419 ASSERT((end_ - current_) >= len);
420 *reinterpret_cast<uword*>(current_) = value;
421 current_ += len;
422 }
423
424 void WriteTargetWord(uword value) {
425#if defined(IS_SIMARM_X64)
426 RELEASE_ASSERT(Utils::IsInt(32, static_cast<word>(value)));
427 const intptr_t len = sizeof(uint32_t);
428 if ((end_ - current_) < len) {
429 Resize(len);
430 }
431 ASSERT((end_ - current_) >= len);
432 *reinterpret_cast<uint32_t*>(current_) = static_cast<uint32_t>(value);
433 current_ += len;
434#else // defined(IS_SIMARM_X64)
435 WriteWord(value);
436#endif // defined(IS_SIMARM_X64)
437 }
438
439 void Print(const char* format, ...) {
440 va_list args;
441 va_start(args, format);
442 VPrint(format, args);
443 va_end(args);
444 }
445
446 void VPrint(const char* format, va_list args) {
447 // Measure.
448 va_list measure_args;
449 va_copy(measure_args, args);
450 intptr_t len = Utils::VSNPrint(NULL, 0, format, measure_args);
451 va_end(measure_args);
452
453 // Alloc.
454 if ((end_ - current_) < (len + 1)) {
455 Resize(len + 1);
456 }
457 ASSERT((end_ - current_) >= (len + 1));
458
459 // Print.
460 va_list print_args;
461 va_copy(print_args, args);
462 Utils::VSNPrint(reinterpret_cast<char*>(current_), len + 1, format,
463 print_args);
464 va_end(print_args);
465 current_ += len; // Not len + 1 to swallow the terminating NUL.
466 }
467
468 template <typename T>
469 void Write(T value) {
470 T v = value;
471 while (v < kMinDataPerByte || v > kMaxDataPerByte) {
472 WriteByte(static_cast<uint8_t>(v & kByteMask));
473 v = v >> kDataBitsPerByte;
474 }
475 WriteByte(static_cast<uint8_t>(v + kEndByteMarker));
476 }
477
478 template <typename T>
479 void WriteFixed(T value) {
480 const intptr_t len = sizeof(T);
481 if ((end_ - current_) < len) {
482 Resize(len);
483 }
484 ASSERT((end_ - current_) >= len);
485 *reinterpret_cast<T*>(current_) = static_cast<T>(value);
486 current_ += len;
487 }
488
489 private:
490 DART_FORCE_INLINE void WriteByte(uint8_t value) {
491 if (current_ >= end_) {
492 Resize(1);
493 }
494 ASSERT(current_ < end_);
495 *current_++ = value;
496 }
497
498 void Resize(intptr_t size_needed) {
499 intptr_t position = current_ - *buffer_;
500 intptr_t increment_size = current_size_;
501 if (size_needed > increment_size) {
502 increment_size = Utils::RoundUp(size_needed, initial_size_);
503 }
504 intptr_t new_size = current_size_ + increment_size;
505 ASSERT(new_size > current_size_);
506 *buffer_ =
507 reinterpret_cast<uint8_t*>(alloc_(*buffer_, current_size_, new_size));
508 if (*buffer_ == NULL) {
509 Exceptions::ThrowOOM();
510 }
511 current_ = *buffer_ + position;
512 current_size_ = new_size;
513 end_ = *buffer_ + new_size;
514 ASSERT(end_ > *buffer_);
515 }
516
517 private:
518 uint8_t** const buffer_;
519 uint8_t* end_;
520 uint8_t* current_;
521 intptr_t current_size_;
522 ReAlloc alloc_;
523 intptr_t initial_size_;
524
525 DISALLOW_COPY_AND_ASSIGN(WriteStream);
526};
527
528class StreamingWriteStream : public ValueObject {
529 public:
530 explicit StreamingWriteStream(intptr_t initial_capacity,
531 Dart_StreamingWriteCallback callback,
532 void* callback_data);
533 ~StreamingWriteStream();
534
535 intptr_t position() const { return flushed_size_ + (cursor_ - buffer_); }
536
537 void Align(intptr_t alignment) {
538 intptr_t padding = Utils::RoundUp(position(), alignment) - position();
539 EnsureAvailable(padding);
540 memset(cursor_, 0, padding);
541 cursor_ += padding;
542 }
543
544 void Print(const char* format, ...) {
545 va_list args;
546 va_start(args, format);
547 VPrint(format, args);
548 va_end(args);
549 }
550 void VPrint(const char* format, va_list args);
551
552 void WriteBytes(const uint8_t* buffer, intptr_t size) {
553 EnsureAvailable(size);
554 if (size != 0) {
555 memmove(cursor_, buffer, size);
556 }
557 cursor_ += size;
558 }
559
560 private:
561 void EnsureAvailable(intptr_t needed) {
562 intptr_t available = limit_ - cursor_;
563 if (available >= needed) return;
564 EnsureAvailableSlowPath(needed);
565 }
566
567 void EnsureAvailableSlowPath(intptr_t needed);
568 void Flush();
569
570 uint8_t* buffer_;
571 uint8_t* cursor_;
572 uint8_t* limit_;
573 intptr_t flushed_size_;
574 Dart_StreamingWriteCallback callback_;
575 void* callback_data_;
576
577 DISALLOW_COPY_AND_ASSIGN(StreamingWriteStream);
578};
579
580} // namespace dart
581
582#endif // RUNTIME_VM_DATASTREAM_H_
583