1 | // Copyright (c) 2016, 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 | #if !defined(DART_PRECOMPILED_RUNTIME) |
5 | |
6 | #include "vm/kernel_binary.h" |
7 | |
8 | #include <memory> |
9 | |
10 | #include "platform/globals.h" |
11 | #include "vm/compiler/frontend/kernel_to_il.h" |
12 | #include "vm/dart_api_impl.h" |
13 | #include "vm/flags.h" |
14 | #include "vm/growable_array.h" |
15 | #include "vm/kernel.h" |
16 | #include "vm/object.h" |
17 | #include "vm/os.h" |
18 | #include "vm/version.h" |
19 | |
20 | namespace dart { |
21 | |
22 | namespace kernel { |
23 | |
24 | const char* Reader::TagName(Tag tag) { |
25 | switch (tag) { |
26 | #define CASE(Name, value) \ |
27 | case k##Name: \ |
28 | return #Name; |
29 | KERNEL_TAG_LIST(CASE) |
30 | #undef CASE |
31 | default: |
32 | break; |
33 | } |
34 | return "Unknown" ; |
35 | } |
36 | |
37 | TypedDataPtr Reader::ReadLineStartsData(intptr_t line_start_count) { |
38 | TypedData& line_starts_data = TypedData::Handle( |
39 | TypedData::New(kTypedDataInt8ArrayCid, line_start_count, Heap::kOld)); |
40 | |
41 | const intptr_t start_offset = offset(); |
42 | intptr_t i = 0; |
43 | for (; i < line_start_count; ++i) { |
44 | const intptr_t delta = ReadUInt(); |
45 | if (delta > kMaxInt8) { |
46 | break; |
47 | } |
48 | line_starts_data.SetInt8(i, static_cast<int8_t>(delta)); |
49 | } |
50 | |
51 | if (i < line_start_count) { |
52 | // Slow path: choose representation between Int16 and Int32 typed data. |
53 | set_offset(start_offset); |
54 | intptr_t max_delta = 0; |
55 | for (intptr_t i = 0; i < line_start_count; ++i) { |
56 | const intptr_t delta = ReadUInt(); |
57 | if (delta > max_delta) { |
58 | max_delta = delta; |
59 | } |
60 | } |
61 | |
62 | ASSERT(max_delta > kMaxInt8); |
63 | const intptr_t cid = (max_delta <= kMaxInt16) ? kTypedDataInt16ArrayCid |
64 | : kTypedDataInt32ArrayCid; |
65 | line_starts_data = TypedData::New(cid, line_start_count, Heap::kOld); |
66 | |
67 | set_offset(start_offset); |
68 | for (intptr_t i = 0; i < line_start_count; ++i) { |
69 | const intptr_t delta = ReadUInt(); |
70 | if (cid == kTypedDataInt16ArrayCid) { |
71 | line_starts_data.SetInt16(i << 1, static_cast<int16_t>(delta)); |
72 | } else { |
73 | line_starts_data.SetInt32(i << 2, delta); |
74 | } |
75 | } |
76 | } |
77 | |
78 | return line_starts_data.raw(); |
79 | } |
80 | |
81 | const char* kKernelInvalidFilesize = |
82 | "File size is too small to be a valid kernel file" ; |
83 | const char* kKernelInvalidMagicIdentifier = "Invalid magic identifier" ; |
84 | const char* kKernelInvalidBinaryFormatVersion = |
85 | "Invalid kernel binary format version" ; |
86 | const char* kKernelInvalidSizeIndicated = |
87 | "Invalid kernel binary: Indicated size is invalid" ; |
88 | const char* kKernelInvalidSdkHash = "Invalid SDK hash" ; |
89 | |
90 | const int kSdkHashSizeInBytes = 10; |
91 | const char* kSdkHashNull = "0000000000" ; |
92 | |
93 | std::unique_ptr<Program> Program::ReadFrom(Reader* reader, const char** error) { |
94 | if (reader->size() < 70) { |
95 | // A kernel file (v43) currently contains at least the following: |
96 | // * Magic number (32) |
97 | // * Kernel version (32) |
98 | // * SDK Hash (10 * 8) |
99 | // * List of problems (8) |
100 | // * Length of source map (32) |
101 | // * Length of canonical name table (8) |
102 | // * Metadata length (32) |
103 | // * Length of string table (8) |
104 | // * Length of constant table (8) |
105 | // * Component index (11 * 32) |
106 | // |
107 | // so is at least 74 bytes. |
108 | // (Technically it will also contain an empty entry in both source map and |
109 | // string table, taking up another 8 bytes.) |
110 | if (error != nullptr) { |
111 | *error = kKernelInvalidFilesize; |
112 | } |
113 | return nullptr; |
114 | } |
115 | |
116 | uint32_t magic = reader->ReadUInt32(); |
117 | if (magic != kMagicProgramFile) { |
118 | if (error != nullptr) { |
119 | *error = kKernelInvalidMagicIdentifier; |
120 | } |
121 | return nullptr; |
122 | } |
123 | |
124 | uint32_t formatVersion = reader->ReadUInt32(); |
125 | if ((formatVersion < kMinSupportedKernelFormatVersion) || |
126 | (formatVersion > kMaxSupportedKernelFormatVersion)) { |
127 | if (error != nullptr) { |
128 | *error = kKernelInvalidBinaryFormatVersion; |
129 | } |
130 | return nullptr; |
131 | } |
132 | |
133 | uint8_t sdkHash[kSdkHashSizeInBytes + 1]; |
134 | reader->ReadBytes(sdkHash, kSdkHashSizeInBytes); |
135 | sdkHash[kSdkHashSizeInBytes] = 0; // Null terminate. |
136 | if (strcmp(Version::SdkHash(), kSdkHashNull) != 0 && |
137 | strcmp((const char*)sdkHash, kSdkHashNull) != 0 && |
138 | strcmp((const char*)sdkHash, Version::SdkHash()) != 0) { |
139 | if (error != nullptr) { |
140 | *error = kKernelInvalidSdkHash; |
141 | } |
142 | return nullptr; |
143 | } |
144 | |
145 | std::unique_ptr<Program> program(new Program()); |
146 | program->binary_version_ = formatVersion; |
147 | program->typed_data_ = reader->typed_data(); |
148 | program->kernel_data_ = reader->buffer(); |
149 | program->kernel_data_size_ = reader->size(); |
150 | |
151 | // Dill files can be concatenated (e.g. cat a.dill b.dill > c.dill). Find out |
152 | // if this dill contains more than one program. |
153 | int subprogram_count = 0; |
154 | reader->set_offset(reader->size() - 4); |
155 | while (reader->offset() > 0) { |
156 | intptr_t size = reader->ReadUInt32(); |
157 | intptr_t start = reader->offset() - size; |
158 | if (start < 0 || size <= 0) { |
159 | if (error != nullptr) { |
160 | *error = kKernelInvalidSizeIndicated; |
161 | } |
162 | return nullptr; |
163 | } |
164 | ++subprogram_count; |
165 | if (subprogram_count > 1) break; |
166 | reader->set_offset(start - 4); |
167 | } |
168 | program->single_program_ = subprogram_count == 1; |
169 | |
170 | // Read backwards at the end. |
171 | program->library_count_ = reader->ReadFromIndexNoReset( |
172 | reader->size_, LibraryCountFieldCountFromEnd, 1, 0); |
173 | intptr_t count_from_first_library_offset = |
174 | SourceTableFieldCountFromFirstLibraryOffset41Plus; |
175 | program->source_table_offset_ = reader->ReadFromIndexNoReset( |
176 | reader->size_, |
177 | LibraryCountFieldCountFromEnd + 1 + program->library_count_ + 1 + |
178 | count_from_first_library_offset, |
179 | 1, 0); |
180 | program->name_table_offset_ = reader->ReadUInt32(); |
181 | program->metadata_payloads_offset_ = reader->ReadUInt32(); |
182 | program->metadata_mappings_offset_ = reader->ReadUInt32(); |
183 | program->string_table_offset_ = reader->ReadUInt32(); |
184 | program->constant_table_offset_ = reader->ReadUInt32(); |
185 | |
186 | program->main_method_reference_ = NameIndex(reader->ReadUInt32() - 1); |
187 | NNBDCompiledMode compilation_mode = |
188 | static_cast<NNBDCompiledMode>(reader->ReadUInt32()); |
189 | program->compilation_mode_ = compilation_mode; |
190 | |
191 | return program; |
192 | } |
193 | |
194 | std::unique_ptr<Program> Program::ReadFromFile( |
195 | const char* script_uri, const char** error /* = nullptr */) { |
196 | Thread* thread = Thread::Current(); |
197 | Isolate* isolate = thread->isolate(); |
198 | if (script_uri == NULL) { |
199 | return nullptr; |
200 | } |
201 | if (!isolate->HasTagHandler()) { |
202 | return nullptr; |
203 | } |
204 | std::unique_ptr<kernel::Program> kernel_program; |
205 | |
206 | const String& uri = String::Handle(String::New(script_uri)); |
207 | const Object& ret = Object::Handle( |
208 | isolate->CallTagHandler(Dart_kKernelTag, Object::null_object(), uri)); |
209 | if (ret.IsExternalTypedData()) { |
210 | const auto& typed_data = ExternalTypedData::Handle( |
211 | thread->zone(), ExternalTypedData::RawCast(ret.raw())); |
212 | kernel_program = kernel::Program::ReadFromTypedData(typed_data); |
213 | return kernel_program; |
214 | } else if (error != nullptr) { |
215 | Api::Scope api_scope(thread); |
216 | Dart_Handle retval = Api::NewHandle(thread, ret.raw()); |
217 | { |
218 | TransitionVMToNative transition(thread); |
219 | *error = Dart_GetError(retval); |
220 | } |
221 | } |
222 | return kernel_program; |
223 | } |
224 | |
225 | std::unique_ptr<Program> Program::ReadFromBuffer(const uint8_t* buffer, |
226 | intptr_t buffer_length, |
227 | const char** error) { |
228 | kernel::Reader reader(buffer, buffer_length); |
229 | return kernel::Program::ReadFrom(&reader, error); |
230 | } |
231 | |
232 | std::unique_ptr<Program> Program::ReadFromTypedData( |
233 | const ExternalTypedData& typed_data, const char** error) { |
234 | kernel::Reader reader(typed_data); |
235 | return kernel::Program::ReadFrom(&reader, error); |
236 | } |
237 | |
238 | } // namespace kernel |
239 | } // namespace dart |
240 | #endif // !defined(DART_PRECOMPILED_RUNTIME) |
241 | |