| Index: runtime/vm/kernel_binary.h
|
| diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..116ea7d96df4b3ea93736b0c0b0631f17cdac2d1
|
| --- /dev/null
|
| +++ b/runtime/vm/kernel_binary.h
|
| @@ -0,0 +1,544 @@
|
| +// 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,
|
| +
|
| + 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,
|
| +
|
| + kInvalidType = 90,
|
| + kDynamicType = 91,
|
| + kVoidType = 92,
|
| + kInterfaceType = 93,
|
| + kFunctionType = 94,
|
| + kTypeParameterType = 95,
|
| + kSimpleInterfaceType = 96,
|
| + kSimpleFunctionType = 97,
|
| +
|
| + kSpecializedTagHighBit = 0x80, // 10000000
|
| + kSpecializedTagMask = 0xF8, // 11111000
|
| + kSpecializedPayloadMask = 0x7, // 00000111
|
| +
|
| + kSpecializedVariableGet = 128,
|
| + kSpecializedVariableSet = 136,
|
| + kSpecialIntLiteral = 144,
|
| +};
|
| +
|
| +
|
| +static const int SpecializedIntLiteralBias = 3;
|
| +
|
| +
|
| +template <typename T>
|
| +class BlockStack {
|
| + public:
|
| + BlockStack() : current_count_(0) {}
|
| +
|
| + void EnterScope() {
|
| + variable_count_.Add(current_count_);
|
| + current_count_ = 0;
|
| + }
|
| +
|
| + void LeaveScope() {
|
| + variables_.TruncateTo(variables_.length() - current_count_);
|
| + current_count_ = variable_count_[variable_count_.length() - 1];
|
| + variable_count_.RemoveLast();
|
| + }
|
| +
|
| + T* Lookup(int index) {
|
| + ASSERT(index < variables_.length());
|
| + return variables_[index];
|
| + }
|
| +
|
| + void Push(T* v) {
|
| + variables_.Add(v);
|
| + current_count_++;
|
| + }
|
| +
|
| + void Push(List<T>* decl) {
|
| + for (intptr_t i = 0; i < decl->length(); i++) {
|
| + variables_.Add(decl[i]);
|
| + current_count_++;
|
| + }
|
| + }
|
| +
|
| + void Pop(T* decl) {
|
| + variables_.RemoveLast();
|
| + current_count_--;
|
| + }
|
| +
|
| + void Pop(List<T>* decl) {
|
| + variables_.TruncateTo(variables_.length() - decl->length());
|
| + current_count_ -= decl->length();
|
| + }
|
| +
|
| + private:
|
| + int current_count_;
|
| + MallocGrowableArray<T*> variables_;
|
| + MallocGrowableArray<int> variable_count_;
|
| +};
|
| +
|
| +
|
| +template <typename T>
|
| +class BlockMap {
|
| + public:
|
| + BlockMap() : current_count_(0), stack_height_(0) {}
|
| +
|
| + void EnterScope() {
|
| + variable_count_.Add(current_count_);
|
| + current_count_ = 0;
|
| + }
|
| +
|
| + void LeaveScope() {
|
| + stack_height_ -= current_count_;
|
| + current_count_ = variable_count_[variable_count_.length() - 1];
|
| + variable_count_.RemoveLast();
|
| + }
|
| +
|
| + int Lookup(T* object) {
|
| + typename MallocMap<T, int>::Pair* result = variables_.LookupPair(object);
|
| + ASSERT(result != NULL);
|
| + if (result == NULL) FATAL("lookup failure");
|
| + return RawPointerKeyValueTrait<T, int>::ValueOf(*result);
|
| + }
|
| +
|
| + void Push(T* v) {
|
| + ASSERT(variables_.LookupPair(v) == NULL);
|
| + int index = stack_height_++;
|
| + variables_.Insert(v, index);
|
| + current_count_++;
|
| + }
|
| +
|
| + void Set(T* v, int index) {
|
| + typename MallocMap<T, int>::Pair* entry = variables_.LookupPair(v);
|
| + ASSERT(entry != NULL);
|
| + entry->value = index;
|
| + }
|
| +
|
| + void Push(List<T>* decl) {
|
| + for (intptr_t i = 0; i < decl->length(); i++) {
|
| + Push(decl[i]);
|
| + }
|
| + }
|
| +
|
| + void Pop(T* v) {
|
| + current_count_--;
|
| + stack_height_--;
|
| + }
|
| +
|
| + private:
|
| + int current_count_;
|
| + int stack_height_;
|
| + MallocMap<T, int> variables_;
|
| + MallocGrowableArray<int> variable_count_;
|
| +};
|
| +
|
| +
|
| +template <typename T>
|
| +class VariableScope {
|
| + public:
|
| + explicit VariableScope(T* builder) : builder_(builder) {
|
| + builder_->variables().EnterScope();
|
| + }
|
| + ~VariableScope() { builder_->variables().LeaveScope(); }
|
| +
|
| + private:
|
| + T* builder_;
|
| +};
|
| +
|
| +
|
| +template <typename T>
|
| +class TypeParameterScope {
|
| + public:
|
| + explicit TypeParameterScope(T* builder) : builder_(builder) {
|
| + builder_->type_parameters().EnterScope();
|
| + }
|
| + ~TypeParameterScope() { builder_->type_parameters().LeaveScope(); }
|
| +
|
| + private:
|
| + T* builder_;
|
| +};
|
| +
|
| +
|
| +template <typename T>
|
| +class SwitchCaseScope {
|
| + public:
|
| + explicit SwitchCaseScope(T* builder) : builder_(builder) {
|
| + builder_->switch_cases().EnterScope();
|
| + }
|
| + ~SwitchCaseScope() { builder_->switch_cases().LeaveScope(); }
|
| +
|
| + private:
|
| + T* builder_;
|
| +};
|
| +
|
| +
|
| +// Unlike other scopes, labels from enclosing functions are not visible in
|
| +// nested functions. The LabelScope class is used to hide outer labels.
|
| +template <typename Builder, typename Block>
|
| +class LabelScope {
|
| + public:
|
| + explicit LabelScope(Builder* builder) : builder_(builder) {
|
| + outer_block_ = builder_->labels();
|
| + builder_->set_labels(&block_);
|
| + }
|
| + ~LabelScope() { builder_->set_labels(outer_block_); }
|
| +
|
| + private:
|
| + Builder* builder_;
|
| + Block block_;
|
| + Block* outer_block_;
|
| +};
|
| +
|
| +
|
| +class ReaderHelper {
|
| + public:
|
| + ReaderHelper() : program_(NULL), labels_(NULL) {}
|
| +
|
| + Program* program() { return program_; }
|
| + void set_program(Program* program) { program_ = program; }
|
| +
|
| + BlockStack<VariableDeclaration>& variables() { return scope_; }
|
| + BlockStack<TypeParameter>& type_parameters() { return type_parameters_; }
|
| + BlockStack<SwitchCase>& switch_cases() { return switch_cases_; }
|
| +
|
| + BlockStack<LabeledStatement>* labels() { return labels_; }
|
| + void set_labels(BlockStack<LabeledStatement>* labels) { labels_ = labels; }
|
| +
|
| + CanonicalName* GetCanonicalName(int index) { return canonical_names_[index]; }
|
| + void SetCanonicalName(int index, CanonicalName* name) {
|
| + canonical_names_[index] = name;
|
| + }
|
| + void SetCanonicalNameCount(int count) { canonical_names_.SetLength(count); }
|
| +
|
| + private:
|
| + Program* program_;
|
| + MallocGrowableArray<CanonicalName*> canonical_names_;
|
| + BlockStack<VariableDeclaration> scope_;
|
| + BlockStack<TypeParameter> type_parameters_;
|
| + BlockStack<SwitchCase> switch_cases_;
|
| + BlockStack<LabeledStatement>* labels_;
|
| +};
|
| +
|
| +
|
| +class Reader {
|
| + public:
|
| + Reader(const uint8_t* buffer, intptr_t size)
|
| + : buffer_(buffer), size_(size), offset_(0) {}
|
| +
|
| + uint32_t ReadUInt32() {
|
| + ASSERT(offset_ + 4 <= size_);
|
| +
|
| + 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_);
|
| + 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;
|
| + }
|
| + }
|
| +
|
| + void add_token_position(
|
| + MallocGrowableArray<MallocGrowableArray<intptr_t>*>* list,
|
| + TokenPosition position) {
|
| + intptr_t size = list->length();
|
| + while (size <= current_script_id_) {
|
| + MallocGrowableArray<intptr_t>* tmp = new MallocGrowableArray<intptr_t>();
|
| + list->Add(tmp);
|
| + size = list->length();
|
| + }
|
| + list->At(current_script_id_)->Add(position.value());
|
| + }
|
| +
|
| + void record_token_position(TokenPosition position) {
|
| + if (position.IsReal() && helper()->program() != NULL) {
|
| + add_token_position(&helper()->program()->valid_token_positions, position);
|
| + }
|
| + }
|
| +
|
| + void record_yield_token_position(TokenPosition position) {
|
| + if (helper()->program() != NULL) {
|
| + add_token_position(&helper()->program()->yield_token_positions, position);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Read and return a TokenPosition from this reader.
|
| + * @param record specifies whether or not the read position is saved as a
|
| + * valid token position in the current script.
|
| + * If not be sure to record it later by calling record_token_position (after
|
| + * setting the correct current_script_id).
|
| + */
|
| + TokenPosition ReadPosition(bool record = true) {
|
| + // 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);
|
| + }
|
| +
|
| + if (record) {
|
| + record_token_position(result);
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + intptr_t ReadListLength() { return ReadUInt(); }
|
| +
|
| + uint8_t ReadByte() { 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);
|
| + }
|
| + }
|
| +
|
| + const uint8_t* Consume(int count) {
|
| + ASSERT(offset_ + count <= size_);
|
| + const uint8_t* old = buffer_ + offset_;
|
| + offset_ += count;
|
| + return old;
|
| + }
|
| +
|
| + void EnsureEnd() {
|
| + if (offset_ != size_) {
|
| + FATAL2(
|
| + "Reading Kernel file: Expected to be at EOF "
|
| + "(offset: %" Pd ", size: %" Pd ")",
|
| + offset_, size_);
|
| + }
|
| + }
|
| +
|
| + void DumpOffset(const char* str) {
|
| + OS::PrintErr("@%" Pd " %s\n", offset_, str);
|
| + }
|
| +
|
| + // 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_; }
|
| + // The current script id for what we are currently processing.
|
| + // Note though that this is only a convenience helper and has to be set
|
| + // manually.
|
| + intptr_t current_script_id() { return current_script_id_; }
|
| + void set_current_script_id(intptr_t script_id) {
|
| + current_script_id_ = script_id;
|
| + }
|
| +
|
| + template <typename T, typename RT>
|
| + T* ReadOptional() {
|
| + Tag tag = ReadTag();
|
| + if (tag == kNothing) {
|
| + return NULL;
|
| + }
|
| + ASSERT(tag == kSomething);
|
| + return RT::ReadFrom(this);
|
| + }
|
| +
|
| + template <typename T>
|
| + T* ReadOptional() {
|
| + return ReadOptional<T, T>();
|
| + }
|
| +
|
| + ReaderHelper* helper() { return &builder_; }
|
| +
|
| + CanonicalName* ReadCanonicalNameReference() {
|
| + int index = ReadUInt();
|
| + if (index == 0) return NULL;
|
| + CanonicalName* name = builder_.GetCanonicalName(index - 1);
|
| + ASSERT(name != NULL);
|
| + return name;
|
| + }
|
| +
|
| + intptr_t offset() { return offset_; }
|
| + void set_offset(intptr_t offset) { offset_ = offset; }
|
| + intptr_t size() { return size_; }
|
| +
|
| + const uint8_t* buffer() { return buffer_; }
|
| +
|
| + private:
|
| + const uint8_t* buffer_;
|
| + intptr_t size_;
|
| + intptr_t offset_;
|
| + ReaderHelper builder_;
|
| + TokenPosition max_position_;
|
| + TokenPosition min_position_;
|
| + intptr_t current_script_id_;
|
| +
|
| + friend class PositionScope;
|
| +};
|
| +
|
| +
|
| +// 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_
|
|
|