|  | // Copyright (c) 2016, 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. | 
|  | #if !defined(DART_PRECOMPILED_RUNTIME) | 
|  |  | 
|  | #include "vm/kernel_binary.h" | 
|  | #include "platform/globals.h" | 
|  | #include "vm/compiler/frontend/kernel_to_il.h" | 
|  | #include "vm/dart_api_impl.h" | 
|  | #include "vm/flags.h" | 
|  | #include "vm/growable_array.h" | 
|  | #include "vm/kernel.h" | 
|  | #include "vm/os.h" | 
|  |  | 
|  | namespace dart { | 
|  |  | 
|  | namespace kernel { | 
|  |  | 
|  | const char* Reader::TagName(Tag tag) { | 
|  | switch (tag) { | 
|  | #define CASE(Name, value)                                                      \ | 
|  | case k##Name:                                                                \ | 
|  | return #Name; | 
|  | KERNEL_TAG_LIST(CASE) | 
|  | #undef CASE | 
|  | default: | 
|  | break; | 
|  | } | 
|  | return "Unknown"; | 
|  | } | 
|  |  | 
|  | const char* kKernelInvalidFilesize = | 
|  | "File size is too small to be a valid kernel file"; | 
|  | const char* kKernelInvalidMagicIdentifier = "Invalid magic identifier"; | 
|  | const char* kKernelInvalidBinaryFormatVersion = | 
|  | "Invalid kernel binary format version"; | 
|  | const char* kKernelInvalidSizeIndicated = | 
|  | "Invalid kernel binary: Indicated size is invalid"; | 
|  |  | 
|  | Program* Program::ReadFrom(Reader* reader, const char** error) { | 
|  | if (reader->size() < 59) { | 
|  | // A kernel file currently contains at least the following: | 
|  | //   * Magic number (32) | 
|  | //   * Kernel version (32) | 
|  | //   * Length of source map (32) | 
|  | //   * Length of canonical name table (8) | 
|  | //   * Metadata length (32) | 
|  | //   * Length of string table (8) | 
|  | //   * Length of constant table (8) | 
|  | //   * Component index (10 * 32) | 
|  | // | 
|  | // so is at least 59 bytes. | 
|  | // (Technically it will also contain an empty entry in both source map and | 
|  | // string table, taking up another 8 bytes.) | 
|  | if (error != nullptr) { | 
|  | *error = kKernelInvalidFilesize; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | uint32_t magic = reader->ReadUInt32(); | 
|  | if (magic != kMagicProgramFile) { | 
|  | if (error != nullptr) { | 
|  | *error = kKernelInvalidMagicIdentifier; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | uint32_t formatVersion = reader->ReadUInt32(); | 
|  | if (formatVersion != kBinaryFormatVersion) { | 
|  | if (error != nullptr) { | 
|  | *error = kKernelInvalidBinaryFormatVersion; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | Program* program = new Program(); | 
|  | program->kernel_data_ = reader->buffer(); | 
|  | program->kernel_data_size_ = reader->size(); | 
|  |  | 
|  | // Dill files can be concatenated (e.g. cat a.dill b.dill > c.dill). Find out | 
|  | // if this dill contains more than one program. | 
|  | int subprogram_count = 0; | 
|  | reader->set_offset(reader->size() - 4); | 
|  | while (reader->offset() > 0) { | 
|  | intptr_t size = reader->ReadUInt32(); | 
|  | intptr_t start = reader->offset() - size; | 
|  | if (start < 0) { | 
|  | if (error != nullptr) { | 
|  | *error = kKernelInvalidSizeIndicated; | 
|  | } | 
|  | delete program; | 
|  | return nullptr; | 
|  | } | 
|  | ++subprogram_count; | 
|  | if (subprogram_count > 1) break; | 
|  | reader->set_offset(start - 4); | 
|  | } | 
|  | program->single_program_ = subprogram_count == 1; | 
|  |  | 
|  | // Read backwards at the end. | 
|  | program->library_count_ = reader->ReadFromIndexNoReset( | 
|  | reader->size_, LibraryCountFieldCountFromEnd, 1, 0); | 
|  | program->source_table_offset_ = reader->ReadFromIndexNoReset( | 
|  | reader->size_, | 
|  | LibraryCountFieldCountFromEnd + 1 + program->library_count_ + 1 + | 
|  | SourceTableFieldCountFromFirstLibraryOffset, | 
|  | 1, 0); | 
|  | program->name_table_offset_ = reader->ReadUInt32(); | 
|  | program->metadata_payloads_offset_ = reader->ReadUInt32(); | 
|  | program->metadata_mappings_offset_ = reader->ReadUInt32(); | 
|  | program->string_table_offset_ = reader->ReadUInt32(); | 
|  | program->constant_table_offset_ = reader->ReadUInt32(); | 
|  |  | 
|  | program->main_method_reference_ = NameIndex(reader->ReadUInt32() - 1); | 
|  |  | 
|  | return program; | 
|  | } | 
|  |  | 
|  | Program* Program::ReadFromFile(const char* script_uri, | 
|  | const char** error /* = nullptr */) { | 
|  | Thread* thread = Thread::Current(); | 
|  | if (script_uri == NULL) { | 
|  | return NULL; | 
|  | } | 
|  | kernel::Program* kernel_program = NULL; | 
|  |  | 
|  | const String& uri = String::Handle(String::New(script_uri)); | 
|  | const Object& ret = Object::Handle(thread->isolate()->CallTagHandler( | 
|  | Dart_kKernelTag, Object::null_object(), uri)); | 
|  | Api::Scope api_scope(thread); | 
|  | Dart_Handle retval = Api::NewHandle(thread, ret.raw()); | 
|  | { | 
|  | TransitionVMToNative transition(thread); | 
|  | if (!Dart_IsError(retval)) { | 
|  | Dart_TypedData_Type data_type; | 
|  | uint8_t* data; | 
|  | ASSERT(Dart_IsTypedData(retval)); | 
|  |  | 
|  | uint8_t* kernel_buffer; | 
|  | intptr_t kernel_buffer_size; | 
|  | Dart_Handle val = Dart_TypedDataAcquireData( | 
|  | retval, &data_type, reinterpret_cast<void**>(&data), | 
|  | &kernel_buffer_size); | 
|  | ASSERT(!Dart_IsError(val)); | 
|  | ASSERT(data_type == Dart_TypedData_kUint8); | 
|  | kernel_buffer = reinterpret_cast<uint8_t*>(malloc(kernel_buffer_size)); | 
|  | memmove(kernel_buffer, data, kernel_buffer_size); | 
|  | Dart_TypedDataReleaseData(retval); | 
|  |  | 
|  | kernel_program = | 
|  | kernel::Program::ReadFromBuffer(kernel_buffer, kernel_buffer_size); | 
|  | } else if (error != nullptr) { | 
|  | *error = Dart_GetError(retval); | 
|  | } | 
|  | } | 
|  | return kernel_program; | 
|  | } | 
|  |  | 
|  | Program* Program::ReadFromBuffer(const uint8_t* buffer, | 
|  | intptr_t buffer_length, | 
|  | const char** error) { | 
|  | kernel::Reader reader(buffer, buffer_length); | 
|  | return kernel::Program::ReadFrom(&reader, error); | 
|  | } | 
|  |  | 
|  | Program* Program::ReadFromTypedData(const ExternalTypedData& typed_data, | 
|  | const char** error) { | 
|  | kernel::Reader reader(typed_data); | 
|  | return kernel::Program::ReadFrom(&reader, error); | 
|  | } | 
|  |  | 
|  | }  // namespace kernel | 
|  | }  // namespace dart | 
|  | #endif  // !defined(DART_PRECOMPILED_RUNTIME) |