|  | // Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | #ifndef RUNTIME_VM_KERNEL_BINARY_H_ | 
|  | #define RUNTIME_VM_KERNEL_BINARY_H_ | 
|  |  | 
|  | #if !defined(DART_PRECOMPILED_RUNTIME) | 
|  |  | 
|  | #include <map> | 
|  |  | 
|  | #include "vm/kernel.h" | 
|  | #include "vm/kernel_to_il.h" | 
|  | #include "vm/object.h" | 
|  |  | 
|  | namespace dart { | 
|  | namespace kernel { | 
|  |  | 
|  | static const uint32_t kMagicProgramFile = 0x90ABCDEFu; | 
|  |  | 
|  | // Keep in sync with package:dynamo/lib/binary/tag.dart | 
|  | enum Tag { | 
|  | kNothing = 0, | 
|  | kSomething = 1, | 
|  |  | 
|  | kClass = 2, | 
|  |  | 
|  | kFunctionNode = 3, | 
|  | kField = 4, | 
|  | kConstructor = 5, | 
|  | kProcedure = 6, | 
|  |  | 
|  | kInvalidInitializer = 7, | 
|  | kFieldInitializer = 8, | 
|  | kSuperInitializer = 9, | 
|  | kRedirectingInitializer = 10, | 
|  | kLocalInitializer = 11, | 
|  |  | 
|  | kDirectPropertyGet = 15, | 
|  | kDirectPropertySet = 16, | 
|  | kDirectMethodInvocation = 17, | 
|  | kConstStaticInvocation = 18, | 
|  | kInvalidExpression = 19, | 
|  | kVariableGet = 20, | 
|  | kVariableSet = 21, | 
|  | kPropertyGet = 22, | 
|  | kPropertySet = 23, | 
|  | kSuperPropertyGet = 24, | 
|  | kSuperPropertySet = 25, | 
|  | kStaticGet = 26, | 
|  | kStaticSet = 27, | 
|  | kMethodInvocation = 28, | 
|  | kSuperMethodInvocation = 29, | 
|  | kStaticInvocation = 30, | 
|  | kConstructorInvocation = 31, | 
|  | kConstConstructorInvocation = 32, | 
|  | kNot = 33, | 
|  | kLogicalExpression = 34, | 
|  | kConditionalExpression = 35, | 
|  | kStringConcatenation = 36, | 
|  | kIsExpression = 37, | 
|  | kAsExpression = 38, | 
|  | kStringLiteral = 39, | 
|  | kDoubleLiteral = 40, | 
|  | kTrueLiteral = 41, | 
|  | kFalseLiteral = 42, | 
|  | kNullLiteral = 43, | 
|  | kSymbolLiteral = 44, | 
|  | kTypeLiteral = 45, | 
|  | kThisExpression = 46, | 
|  | kRethrow = 47, | 
|  | kThrow = 48, | 
|  | kListLiteral = 49, | 
|  | kMapLiteral = 50, | 
|  | kAwaitExpression = 51, | 
|  | kFunctionExpression = 52, | 
|  | kLet = 53, | 
|  |  | 
|  | kPositiveIntLiteral = 55, | 
|  | kNegativeIntLiteral = 56, | 
|  | kBigIntLiteral = 57, | 
|  | kConstListLiteral = 58, | 
|  | kConstMapLiteral = 59, | 
|  |  | 
|  | kInvalidStatement = 60, | 
|  | kExpressionStatement = 61, | 
|  | kBlock = 62, | 
|  | kEmptyStatement = 63, | 
|  | kAssertStatement = 64, | 
|  | kLabeledStatement = 65, | 
|  | kBreakStatement = 66, | 
|  | kWhileStatement = 67, | 
|  | kDoStatement = 68, | 
|  | kForStatement = 69, | 
|  | kForInStatement = 70, | 
|  | kSwitchStatement = 71, | 
|  | kContinueSwitchStatement = 72, | 
|  | kIfStatement = 73, | 
|  | kReturnStatement = 74, | 
|  | kTryCatch = 75, | 
|  | kTryFinally = 76, | 
|  | kYieldStatement = 77, | 
|  | kVariableDeclaration = 78, | 
|  | kFunctionDeclaration = 79, | 
|  | kAsyncForInStatement = 80, | 
|  |  | 
|  | kTypedefType = 87, | 
|  | kVectorType = 88, | 
|  | kBottomType = 89, | 
|  | kInvalidType = 90, | 
|  | kDynamicType = 91, | 
|  | kVoidType = 92, | 
|  | kInterfaceType = 93, | 
|  | kFunctionType = 94, | 
|  | kTypeParameterType = 95, | 
|  | kSimpleInterfaceType = 96, | 
|  | kSimpleFunctionType = 97, | 
|  |  | 
|  | kVectorCreation = 102, | 
|  | kVectorGet = 103, | 
|  | kVectorSet = 104, | 
|  | kVectorCopy = 105, | 
|  |  | 
|  | kClosureCreation = 106, | 
|  |  | 
|  | kSpecializedTagHighBit = 0x80,  // 10000000 | 
|  | kSpecializedTagMask = 0xF8,     // 11111000 | 
|  | kSpecializedPayloadMask = 0x7,  // 00000111 | 
|  |  | 
|  | kSpecializedVariableGet = 128, | 
|  | kSpecializedVariableSet = 136, | 
|  | kSpecialIntLiteral = 144, | 
|  | }; | 
|  |  | 
|  | static const int SpecializedIntLiteralBias = 3; | 
|  |  | 
|  | class Reader { | 
|  | public: | 
|  | Reader(const uint8_t* buffer, intptr_t size) | 
|  | : raw_buffer_(buffer), typed_data_(NULL), size_(size), offset_(0) {} | 
|  |  | 
|  | explicit Reader(const TypedData& typed_data) | 
|  | : raw_buffer_(NULL), | 
|  | typed_data_(&typed_data), | 
|  | size_(typed_data.IsNull() ? 0 : typed_data.Length()), | 
|  | offset_(0) {} | 
|  |  | 
|  | uint32_t ReadUInt32() { | 
|  | ASSERT(offset_ + 4 <= size_); | 
|  |  | 
|  | const uint8_t* buffer = this->buffer(); | 
|  | uint32_t value = (buffer[offset_ + 0] << 24) | (buffer[offset_ + 1] << 16) | | 
|  | (buffer[offset_ + 2] << 8) | (buffer[offset_ + 3] << 0); | 
|  | offset_ += 4; | 
|  | return value; | 
|  | } | 
|  |  | 
|  | uint32_t ReadUInt() { | 
|  | ASSERT(offset_ + 1 <= size_); | 
|  |  | 
|  | const uint8_t* buffer = this->buffer(); | 
|  | uint8_t byte0 = buffer[offset_]; | 
|  | if ((byte0 & 0x80) == 0) { | 
|  | // 0... | 
|  | offset_++; | 
|  | return byte0; | 
|  | } else if ((byte0 & 0xc0) == 0x80) { | 
|  | // 10... | 
|  | ASSERT(offset_ + 2 <= size_); | 
|  | uint32_t value = ((byte0 & ~0x80) << 8) | (buffer[offset_ + 1]); | 
|  | offset_ += 2; | 
|  | return value; | 
|  | } else { | 
|  | // 11... | 
|  | ASSERT(offset_ + 4 <= size_); | 
|  | uint32_t value = ((byte0 & ~0xc0) << 24) | (buffer[offset_ + 1] << 16) | | 
|  | (buffer[offset_ + 2] << 8) | (buffer[offset_ + 3] << 0); | 
|  | offset_ += 4; | 
|  | return value; | 
|  | } | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Read and return a TokenPosition from this reader. | 
|  | */ | 
|  | TokenPosition ReadPosition() { | 
|  | // Position is saved as unsigned, | 
|  | // but actually ranges from -1 and up (thus the -1) | 
|  | intptr_t value = ReadUInt() - 1; | 
|  | TokenPosition result = TokenPosition(value); | 
|  | max_position_ = Utils::Maximum(max_position_, result); | 
|  | if (min_position_.IsNoSource()) { | 
|  | min_position_ = result; | 
|  | } else if (result.IsReal()) { | 
|  | min_position_ = Utils::Minimum(min_position_, result); | 
|  | } | 
|  |  | 
|  | return result; | 
|  | } | 
|  |  | 
|  | intptr_t ReadListLength() { return ReadUInt(); } | 
|  |  | 
|  | uint8_t ReadByte() { return buffer()[offset_++]; } | 
|  |  | 
|  | uint8_t PeekByte() { return buffer()[offset_]; } | 
|  |  | 
|  | bool ReadBool() { return (ReadByte() & 1) == 1; } | 
|  |  | 
|  | word ReadFlags() { return ReadByte(); } | 
|  |  | 
|  | Tag ReadTag(uint8_t* payload = NULL) { | 
|  | uint8_t byte = ReadByte(); | 
|  | bool has_payload = (byte & kSpecializedTagHighBit) != 0; | 
|  | if (has_payload) { | 
|  | if (payload != NULL) { | 
|  | *payload = byte & kSpecializedPayloadMask; | 
|  | } | 
|  | return static_cast<Tag>(byte & kSpecializedTagMask); | 
|  | } else { | 
|  | return static_cast<Tag>(byte); | 
|  | } | 
|  | } | 
|  |  | 
|  | Tag PeekTag(uint8_t* payload = NULL) { | 
|  | uint8_t byte = PeekByte(); | 
|  | bool has_payload = (byte & kSpecializedTagHighBit) != 0; | 
|  | if (has_payload) { | 
|  | if (payload != NULL) { | 
|  | *payload = byte & kSpecializedPayloadMask; | 
|  | } | 
|  | return static_cast<Tag>(byte & kSpecializedTagMask); | 
|  | } else { | 
|  | return static_cast<Tag>(byte); | 
|  | } | 
|  | } | 
|  |  | 
|  | void EnsureEnd() { | 
|  | if (offset_ != size_) { | 
|  | FATAL2( | 
|  | "Reading Kernel file: Expected to be at EOF " | 
|  | "(offset: %" Pd ", size: %" Pd ")", | 
|  | offset_, size_); | 
|  | } | 
|  | } | 
|  |  | 
|  | // The largest position read yet (since last reset). | 
|  | // This is automatically updated when calling ReadPosition, | 
|  | // but can be overwritten (e.g. via the PositionScope class). | 
|  | TokenPosition max_position() { return max_position_; } | 
|  | // The smallest position read yet (since last reset). | 
|  | // This is automatically updated when calling ReadPosition, | 
|  | // but can be overwritten (e.g. via the PositionScope class). | 
|  | TokenPosition min_position() { return min_position_; } | 
|  |  | 
|  | // A canonical name reference of -1 indicates none (for optional names), not | 
|  | // the root name as in the canonical name table. | 
|  | NameIndex ReadCanonicalNameReference() { return NameIndex(ReadUInt() - 1); } | 
|  |  | 
|  | intptr_t offset() { return offset_; } | 
|  | void set_offset(intptr_t offset) { offset_ = offset; } | 
|  |  | 
|  | intptr_t size() { return size_; } | 
|  | void set_size(intptr_t size) { size_ = size; } | 
|  |  | 
|  | const TypedData* typed_data() { return typed_data_; } | 
|  | void set_typed_data(const TypedData* typed_data) { typed_data_ = typed_data; } | 
|  |  | 
|  | const uint8_t* raw_buffer() { return raw_buffer_; } | 
|  | void set_raw_buffer(const uint8_t* raw_buffer) { raw_buffer_ = raw_buffer; } | 
|  |  | 
|  | TypedData& CopyDataToVMHeap(Zone* zone, | 
|  | intptr_t from_byte, | 
|  | intptr_t to_byte) { | 
|  | intptr_t size = to_byte - from_byte; | 
|  | TypedData& data = TypedData::Handle( | 
|  | zone, TypedData::New(kTypedDataUint8ArrayCid, size, Heap::kOld)); | 
|  | { | 
|  | NoSafepointScope no_safepoint; | 
|  | memmove(data.DataAddr(0), buffer() + from_byte, size); | 
|  | } | 
|  | return data; | 
|  | } | 
|  |  | 
|  | uint8_t* CopyDataIntoZone(Zone* zone, intptr_t offset, intptr_t length) { | 
|  | uint8_t* buffer_ = zone->Alloc<uint8_t>(length); | 
|  | { | 
|  | NoSafepointScope no_safepoint; | 
|  | memmove(buffer_, buffer() + offset, length); | 
|  | } | 
|  | return buffer_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | const uint8_t* buffer() { | 
|  | if (raw_buffer_ != NULL) { | 
|  | return raw_buffer_; | 
|  | } | 
|  | NoSafepointScope no_safepoint; | 
|  | return reinterpret_cast<uint8_t*>(typed_data_->DataAddr(0)); | 
|  | } | 
|  |  | 
|  | const uint8_t* raw_buffer_; | 
|  | const TypedData* typed_data_; | 
|  | intptr_t size_; | 
|  | intptr_t offset_; | 
|  | TokenPosition max_position_; | 
|  | TokenPosition min_position_; | 
|  | intptr_t current_script_id_; | 
|  |  | 
|  | friend class PositionScope; | 
|  | friend class Program; | 
|  | }; | 
|  |  | 
|  | // A helper class that resets the readers min and max positions both upon | 
|  | // initialization and upon destruction, i.e. when created the min an max | 
|  | // positions will be reset to "noSource", when destructing the min and max will | 
|  | // be reset to have they value they would have had, if they hadn't been reset in | 
|  | // the first place. | 
|  | class PositionScope { | 
|  | public: | 
|  | explicit PositionScope(Reader* reader) | 
|  | : reader_(reader), | 
|  | min_(reader->min_position_), | 
|  | max_(reader->max_position_) { | 
|  | reader->min_position_ = reader->max_position_ = TokenPosition::kNoSource; | 
|  | } | 
|  |  | 
|  | ~PositionScope() { | 
|  | if (reader_->min_position_.IsNoSource()) { | 
|  | reader_->min_position_ = min_; | 
|  | } else if (min_.IsReal()) { | 
|  | reader_->min_position_ = Utils::Minimum(reader_->min_position_, min_); | 
|  | } | 
|  | reader_->max_position_ = Utils::Maximum(reader_->max_position_, max_); | 
|  | } | 
|  |  | 
|  | private: | 
|  | Reader* reader_; | 
|  | TokenPosition min_; | 
|  | TokenPosition max_; | 
|  | }; | 
|  |  | 
|  | }  // namespace kernel | 
|  | }  // namespace dart | 
|  |  | 
|  | #endif  // !defined(DART_PRECOMPILED_RUNTIME) | 
|  | #endif  // RUNTIME_VM_KERNEL_BINARY_H_ |