1// Copyright (c) 2017, 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_KERNEL_BINARY_H_
6#define RUNTIME_VM_KERNEL_BINARY_H_
7
8#if !defined(DART_PRECOMPILED_RUNTIME)
9
10#include "platform/unaligned.h"
11#include "vm/kernel.h"
12#include "vm/object.h"
13
14namespace dart {
15namespace kernel {
16
17// Keep in sync with package:kernel/lib/binary/tag.dart,
18// package:kernel/binary.md.
19
20static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
21
22// Both version numbers are inclusive.
23static const uint32_t kMinSupportedKernelFormatVersion = 45;
24static const uint32_t kMaxSupportedKernelFormatVersion = 45;
25
26// Keep in sync with package:kernel/lib/binary/tag.dart
27#define KERNEL_TAG_LIST(V) \
28 V(Nothing, 0) \
29 V(Something, 1) \
30 V(Class, 2) \
31 V(Extension, 115) \
32 V(FunctionNode, 3) \
33 V(Field, 4) \
34 V(Constructor, 5) \
35 V(Procedure, 6) \
36 V(RedirectingFactoryConstructor, 108) \
37 V(InvalidInitializer, 7) \
38 V(FieldInitializer, 8) \
39 V(SuperInitializer, 9) \
40 V(RedirectingInitializer, 10) \
41 V(LocalInitializer, 11) \
42 V(AssertInitializer, 12) \
43 V(CheckLibraryIsLoaded, 13) \
44 V(LoadLibrary, 14) \
45 V(DirectPropertyGet, 15) \
46 V(DirectPropertySet, 16) \
47 V(DirectMethodInvocation, 17) \
48 V(ConstStaticInvocation, 18) \
49 V(InvalidExpression, 19) \
50 V(VariableGet, 20) \
51 V(VariableSet, 21) \
52 V(PropertyGet, 22) \
53 V(PropertySet, 23) \
54 V(SuperPropertyGet, 24) \
55 V(SuperPropertySet, 25) \
56 V(StaticGet, 26) \
57 V(StaticSet, 27) \
58 V(MethodInvocation, 28) \
59 V(SuperMethodInvocation, 29) \
60 V(StaticInvocation, 30) \
61 V(ConstructorInvocation, 31) \
62 V(ConstConstructorInvocation, 32) \
63 V(Not, 33) \
64 V(NullCheck, 117) \
65 V(LogicalExpression, 34) \
66 V(ConditionalExpression, 35) \
67 V(StringConcatenation, 36) \
68 V(ListConcatenation, 111) \
69 V(SetConcatenation, 112) \
70 V(MapConcatenation, 113) \
71 V(InstanceCreation, 114) \
72 V(FileUriExpression, 116) \
73 V(IsExpression, 37) \
74 V(AsExpression, 38) \
75 V(StringLiteral, 39) \
76 V(DoubleLiteral, 40) \
77 V(TrueLiteral, 41) \
78 V(FalseLiteral, 42) \
79 V(NullLiteral, 43) \
80 V(SymbolLiteral, 44) \
81 V(TypeLiteral, 45) \
82 V(ThisExpression, 46) \
83 V(Rethrow, 47) \
84 V(Throw, 48) \
85 V(ListLiteral, 49) \
86 V(SetLiteral, 109) \
87 V(MapLiteral, 50) \
88 V(AwaitExpression, 51) \
89 V(FunctionExpression, 52) \
90 V(Let, 53) \
91 V(BlockExpression, 82) \
92 V(Instantiation, 54) \
93 V(PositiveIntLiteral, 55) \
94 V(NegativeIntLiteral, 56) \
95 V(BigIntLiteral, 57) \
96 V(ConstListLiteral, 58) \
97 V(ConstSetLiteral, 110) \
98 V(ConstMapLiteral, 59) \
99 V(ExpressionStatement, 61) \
100 V(Block, 62) \
101 V(EmptyStatement, 63) \
102 V(AssertStatement, 64) \
103 V(LabeledStatement, 65) \
104 V(BreakStatement, 66) \
105 V(WhileStatement, 67) \
106 V(DoStatement, 68) \
107 V(ForStatement, 69) \
108 V(ForInStatement, 70) \
109 V(SwitchStatement, 71) \
110 V(ContinueSwitchStatement, 72) \
111 V(IfStatement, 73) \
112 V(ReturnStatement, 74) \
113 V(TryCatch, 75) \
114 V(TryFinally, 76) \
115 V(YieldStatement, 77) \
116 V(VariableDeclaration, 78) \
117 V(FunctionDeclaration, 79) \
118 V(AsyncForInStatement, 80) \
119 V(AssertBlock, 81) \
120 V(TypedefType, 87) \
121 V(BottomType, 89) \
122 V(NeverType, 98) \
123 V(InvalidType, 90) \
124 V(DynamicType, 91) \
125 V(VoidType, 92) \
126 V(InterfaceType, 93) \
127 V(FunctionType, 94) \
128 V(TypeParameterType, 95) \
129 V(SimpleInterfaceType, 96) \
130 V(SimpleFunctionType, 97) \
131 V(ConstantExpression, 106) \
132 V(SpecializedVariableGet, 128) \
133 V(SpecializedVariableSet, 136) \
134 V(SpecializedIntLiteral, 144)
135
136static const intptr_t kSpecializedTagHighBit = 0x80;
137static const intptr_t kSpecializedTagMask = 0xf8;
138static const intptr_t kSpecializedPayloadMask = 0x7;
139
140enum Tag {
141#define DECLARE(Name, value) k##Name = value,
142 KERNEL_TAG_LIST(DECLARE)
143#undef DECLARE
144};
145
146// Keep in sync with package:kernel/lib/binary/tag.dart
147enum ConstantTag {
148 kNullConstant = 0,
149 kBoolConstant = 1,
150 kIntConstant = 2,
151 kDoubleConstant = 3,
152 kStringConstant = 4,
153 kSymbolConstant = 5,
154 kMapConstant = 6,
155 kListConstant = 7,
156 kSetConstant = 13,
157 kInstanceConstant = 8,
158 kPartialInstantiationConstant = 9,
159 kTearOffConstant = 10,
160 kTypeLiteralConstant = 11,
161 // These constants are not expected to be seen by the VM, because all
162 // constants are fully evaluated.
163 kUnevaluatedConstant = 12,
164};
165
166// Keep in sync with package:kernel/lib/ast.dart
167enum class KernelNullability : int8_t {
168 kUndetermined = 0,
169 kNullable = 1,
170 kNonNullable = 2,
171 kLegacy = 3,
172};
173
174// Keep in sync with package:kernel/lib/ast.dart
175enum Variance {
176 kUnrelated = 0,
177 kCovariant = 1,
178 kContravariant = 2,
179 kInvariant = 3,
180 kLegacyCovariant = 4,
181};
182
183// Keep in sync with package:kernel/lib/ast.dart
184enum AsExpressionFlags {
185 kAsExpressionFlagTypeError = 1 << 0,
186 kAsExpressionFlagCovarianceCheck = 1 << 1,
187 kAsExpressionFlagForDynamic = 1 << 2,
188 kAsExpressionFlagForNonNullableByDefault = 1 << 3,
189};
190
191// Keep in sync with package:kernel/lib/ast.dart
192enum IsExpressionFlags {
193 kIsExpressionFlagForNonNullableByDefault = 1 << 0,
194};
195
196// Keep in sync with package:kernel/lib/ast.dart
197enum class NamedTypeFlags : uint8_t {
198 kIsRequired = 1 << 0,
199};
200
201static const int SpecializedIntLiteralBias = 3;
202static const int LibraryCountFieldCountFromEnd = 1;
203static const int KernelFormatVersionOffset = 4;
204static const int SourceTableFieldCountFromFirstLibraryOffsetPre41 = 6;
205static const int SourceTableFieldCountFromFirstLibraryOffset41Plus = 7;
206
207static const int HeaderSize = 8; // 'magic', 'formatVersion'.
208
209class Reader : public ValueObject {
210 public:
211 Reader(const uint8_t* buffer, intptr_t size)
212 : thread_(NULL),
213 raw_buffer_(buffer),
214 typed_data_(NULL),
215 size_(size),
216 offset_(0) {}
217
218 explicit Reader(const ExternalTypedData& typed_data)
219 : thread_(Thread::Current()),
220 raw_buffer_(NULL),
221 typed_data_(&typed_data),
222 size_(typed_data.IsNull() ? 0 : typed_data.Length()),
223 offset_(0) {}
224
225 uint32_t ReadFromIndex(intptr_t end_offset,
226 intptr_t fields_before,
227 intptr_t list_size,
228 intptr_t list_index) {
229 intptr_t org_offset = offset();
230 uint32_t result =
231 ReadFromIndexNoReset(end_offset, fields_before, list_size, list_index);
232 set_offset(org_offset);
233 return result;
234 }
235
236 uint32_t ReadUInt32At(intptr_t offset) const {
237 ASSERT((size_ >= 4) && (offset >= 0) && (offset <= size_ - 4));
238 uint32_t value;
239 if (raw_buffer_ != NULL) {
240 value = LoadUnaligned(
241 reinterpret_cast<const uint32_t*>(raw_buffer_ + offset));
242 } else {
243 value = typed_data_->GetUint32(offset);
244 }
245 return Utils::BigEndianToHost32(value);
246 }
247
248 uint32_t ReadFromIndexNoReset(intptr_t end_offset,
249 intptr_t fields_before,
250 intptr_t list_size,
251 intptr_t list_index) {
252 set_offset(end_offset - (fields_before + list_size - list_index) * 4);
253 return ReadUInt32();
254 }
255
256 uint32_t ReadUInt32() {
257 uint32_t value = ReadUInt32At(offset_);
258 offset_ += 4;
259 return value;
260 }
261
262 double ReadDouble() {
263 ASSERT((size_ >= 8) && (offset_ >= 0) && (offset_ <= size_ - 8));
264 double value = LoadUnaligned(
265 reinterpret_cast<const double*>(&this->buffer()[offset_]));
266 offset_ += 8;
267 return value;
268 }
269
270 uint32_t ReadUInt() {
271 ASSERT((size_ >= 1) && (offset_ >= 0) && (offset_ <= size_ - 1));
272
273 const uint8_t* buffer = this->buffer();
274 uint8_t byte0 = buffer[offset_];
275 if ((byte0 & 0x80) == 0) {
276 // 0...
277 offset_++;
278 return byte0;
279 } else if ((byte0 & 0xc0) == 0x80) {
280 // 10...
281 ASSERT((size_ >= 2) && (offset_ >= 0) && (offset_ <= size_ - 2));
282 uint32_t value = ((byte0 & ~0x80) << 8) | (buffer[offset_ + 1]);
283 offset_ += 2;
284 return value;
285 } else {
286 // 11...
287 ASSERT((size_ >= 4) && (offset_ >= 0) && (offset_ <= size_ - 4));
288 uint32_t value = ((byte0 & ~0xc0) << 24) | (buffer[offset_ + 1] << 16) |
289 (buffer[offset_ + 2] << 8) | (buffer[offset_ + 3] << 0);
290 offset_ += 4;
291 return value;
292 }
293 }
294
295 intptr_t ReadSLEB128() {
296 const uint8_t* buffer = this->buffer();
297 return Utils::DecodeSLEB128<intptr_t>(buffer, size_, &offset_);
298 }
299
300 int64_t ReadSLEB128AsInt64() {
301 const uint8_t* buffer = this->buffer();
302 return Utils::DecodeSLEB128<int64_t>(buffer, size_, &offset_);
303 }
304
305 /**
306 * Read and return a TokenPosition from this reader.
307 */
308 TokenPosition ReadPosition() {
309 // Position is saved as unsigned,
310 // but actually ranges from -1 and up (thus the -1)
311 intptr_t value = ReadUInt() - 1;
312 TokenPosition result = TokenPosition(value);
313 max_position_ = Utils::Maximum(max_position_, result);
314 if (min_position_.IsNoSource()) {
315 min_position_ = result;
316 } else if (result.IsReal()) {
317 min_position_ = Utils::Minimum(min_position_, result);
318 }
319
320 return result;
321 }
322
323 intptr_t ReadListLength() { return ReadUInt(); }
324
325 uint8_t ReadByte() { return buffer()[offset_++]; }
326
327 uint8_t PeekByte() { return buffer()[offset_]; }
328
329 void ReadBytes(uint8_t* buffer, uint8_t size) {
330 for (int i = 0; i < size; i++) {
331 buffer[i] = ReadByte();
332 }
333 }
334
335 bool ReadBool() { return (ReadByte() & 1) == 1; }
336
337 uint8_t ReadFlags() { return ReadByte(); }
338
339 static const char* TagName(Tag tag);
340
341 Tag ReadTag(uint8_t* payload = NULL) {
342 uint8_t byte = ReadByte();
343 bool has_payload = (byte & kSpecializedTagHighBit) != 0;
344 if (has_payload) {
345 if (payload != NULL) {
346 *payload = byte & kSpecializedPayloadMask;
347 }
348 return static_cast<Tag>(byte & kSpecializedTagMask);
349 } else {
350 return static_cast<Tag>(byte);
351 }
352 }
353
354 Tag PeekTag(uint8_t* payload = NULL) {
355 uint8_t byte = PeekByte();
356 bool has_payload = (byte & kSpecializedTagHighBit) != 0;
357 if (has_payload) {
358 if (payload != NULL) {
359 *payload = byte & kSpecializedPayloadMask;
360 }
361 return static_cast<Tag>(byte & kSpecializedTagMask);
362 } else {
363 return static_cast<Tag>(byte);
364 }
365 }
366
367 static Nullability ConvertNullability(KernelNullability kernel_nullability) {
368 switch (kernel_nullability) {
369 case KernelNullability::kNullable:
370 return Nullability::kNullable;
371 case KernelNullability::kLegacy:
372 return Nullability::kLegacy;
373 case KernelNullability::kNonNullable:
374 case KernelNullability::kUndetermined:
375 return Nullability::kNonNullable;
376 }
377 UNREACHABLE();
378 }
379
380 Nullability ReadNullability() {
381 const uint8_t byte = ReadByte();
382 return ConvertNullability(static_cast<KernelNullability>(byte));
383 }
384
385 Variance ReadVariance() {
386 uint8_t byte = ReadByte();
387 return static_cast<Variance>(byte);
388 }
389
390 void EnsureEnd() {
391 if (offset_ != size_) {
392 FATAL2(
393 "Reading Kernel file: Expected to be at EOF "
394 "(offset: %" Pd ", size: %" Pd ")",
395 offset_, size_);
396 }
397 }
398
399 // The largest position read yet (since last reset).
400 // This is automatically updated when calling ReadPosition,
401 // but can be overwritten (e.g. via the PositionScope class).
402 TokenPosition max_position() { return max_position_; }
403 // The smallest position read yet (since last reset).
404 // This is automatically updated when calling ReadPosition,
405 // but can be overwritten (e.g. via the PositionScope class).
406 TokenPosition min_position() { return min_position_; }
407
408 // A canonical name reference of -1 indicates none (for optional names), not
409 // the root name as in the canonical name table.
410 NameIndex ReadCanonicalNameReference() { return NameIndex(ReadUInt() - 1); }
411
412 intptr_t offset() const { return offset_; }
413 void set_offset(intptr_t offset) { offset_ = offset; }
414
415 intptr_t size() const { return size_; }
416 void set_size(intptr_t size) { size_ = size; }
417
418 const ExternalTypedData* typed_data() const { return typed_data_; }
419 void set_typed_data(const ExternalTypedData* typed_data) {
420 typed_data_ = typed_data;
421 }
422
423 const uint8_t* raw_buffer() const { return raw_buffer_; }
424 void set_raw_buffer(const uint8_t* raw_buffer) { raw_buffer_ = raw_buffer; }
425
426 ExternalTypedDataPtr ExternalDataFromTo(intptr_t start, intptr_t end) {
427 return ExternalTypedData::New(kExternalTypedDataUint8ArrayCid,
428 const_cast<uint8_t*>(buffer() + start),
429 end - start, Heap::kOld);
430 }
431
432 const uint8_t* BufferAt(intptr_t offset) {
433 ASSERT((offset >= 0) && (offset < size_));
434 return &buffer()[offset];
435 }
436
437 TypedDataPtr ReadLineStartsData(intptr_t line_start_count);
438
439 private:
440 const uint8_t* buffer() const {
441 if (raw_buffer_ != NULL) {
442 return raw_buffer_;
443 }
444 NoSafepointScope no_safepoint(thread_);
445 return reinterpret_cast<uint8_t*>(typed_data_->DataAddr(0));
446 }
447
448 Thread* thread_;
449 const uint8_t* raw_buffer_;
450 const ExternalTypedData* typed_data_;
451 intptr_t size_;
452 intptr_t offset_;
453 TokenPosition max_position_;
454 TokenPosition min_position_;
455 intptr_t current_script_id_;
456
457 friend class PositionScope;
458 friend class Program;
459};
460
461// A helper class that saves the current reader position, goes to another reader
462// position, and upon destruction, resets to the original reader position.
463class AlternativeReadingScope {
464 public:
465 AlternativeReadingScope(Reader* reader, intptr_t new_position)
466 : reader_(reader), saved_offset_(reader_->offset()) {
467 reader_->set_offset(new_position);
468 }
469
470 explicit AlternativeReadingScope(Reader* reader)
471 : reader_(reader), saved_offset_(reader_->offset()) {}
472
473 ~AlternativeReadingScope() { reader_->set_offset(saved_offset_); }
474
475 intptr_t saved_offset() { return saved_offset_; }
476
477 private:
478 Reader* const reader_;
479 const intptr_t saved_offset_;
480
481 DISALLOW_COPY_AND_ASSIGN(AlternativeReadingScope);
482};
483
484// Similar to AlternativeReadingScope, but also switches reading to another
485// typed data array.
486class AlternativeReadingScopeWithNewData {
487 public:
488 AlternativeReadingScopeWithNewData(Reader* reader,
489 const ExternalTypedData* new_typed_data,
490 intptr_t new_position)
491 : reader_(reader),
492 saved_size_(reader_->size()),
493 saved_raw_buffer_(reader_->raw_buffer()),
494 saved_typed_data_(reader_->typed_data()),
495 saved_offset_(reader_->offset()) {
496 reader_->set_raw_buffer(nullptr);
497 reader_->set_typed_data(new_typed_data);
498 reader_->set_size(new_typed_data->Length());
499 reader_->set_offset(new_position);
500 }
501
502 ~AlternativeReadingScopeWithNewData() {
503 reader_->set_raw_buffer(saved_raw_buffer_);
504 reader_->set_typed_data(saved_typed_data_);
505 reader_->set_size(saved_size_);
506 reader_->set_offset(saved_offset_);
507 }
508
509 intptr_t saved_offset() { return saved_offset_; }
510
511 private:
512 Reader* reader_;
513 intptr_t saved_size_;
514 const uint8_t* saved_raw_buffer_;
515 const ExternalTypedData* saved_typed_data_;
516 intptr_t saved_offset_;
517
518 DISALLOW_COPY_AND_ASSIGN(AlternativeReadingScopeWithNewData);
519};
520
521// A helper class that resets the readers min and max positions both upon
522// initialization and upon destruction, i.e. when created the min an max
523// positions will be reset to "noSource", when destructing the min and max will
524// be reset to have they value they would have had, if they hadn't been reset in
525// the first place.
526class PositionScope {
527 public:
528 explicit PositionScope(Reader* reader)
529 : reader_(reader),
530 min_(reader->min_position_),
531 max_(reader->max_position_) {
532 reader->min_position_ = reader->max_position_ = TokenPosition::kNoSource;
533 }
534
535 ~PositionScope() {
536 if (reader_->min_position_.IsNoSource()) {
537 reader_->min_position_ = min_;
538 } else if (min_.IsReal()) {
539 reader_->min_position_ = Utils::Minimum(reader_->min_position_, min_);
540 }
541 reader_->max_position_ = Utils::Maximum(reader_->max_position_, max_);
542 }
543
544 private:
545 Reader* reader_;
546 TokenPosition min_;
547 TokenPosition max_;
548
549 DISALLOW_COPY_AND_ASSIGN(PositionScope);
550};
551
552} // namespace kernel
553} // namespace dart
554
555#endif // !defined(DART_PRECOMPILED_RUNTIME)
556#endif // RUNTIME_VM_KERNEL_BINARY_H_
557