1// Copyright (c) 2018, 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_COMPILER_FRONTEND_BYTECODE_READER_H_
6#define RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_READER_H_
7
8#if defined(DART_PRECOMPILED_RUNTIME)
9#error "AOT runtime should not use compiler sources (including header files)"
10#endif // defined(DART_PRECOMPILED_RUNTIME)
11
12#include "vm/compiler/frontend/kernel_translation_helper.h"
13#include "vm/constants_kbc.h"
14#include "vm/object.h"
15
16namespace dart {
17namespace kernel {
18
19class BytecodeComponentData;
20
21// Helper class which provides access to bytecode metadata.
22class BytecodeMetadataHelper : public MetadataHelper {
23 public:
24 static const char* tag() { return "vm.bytecode"; }
25
26 explicit BytecodeMetadataHelper(KernelReaderHelper* helper,
27 ActiveClass* active_class);
28
29 void ParseBytecodeFunction(ParsedFunction* parsed_function);
30
31 // Read all library declarations.
32 bool ReadLibraries();
33
34 // Read specific library declaration.
35 void ReadLibrary(const Library& library);
36
37 // Scan through libraries in the bytecode component and figure out if any of
38 // them will replace libraries which are already loaded.
39 // Return true if bytecode component is found.
40 bool FindModifiedLibrariesForHotReload(BitVector* modified_libs,
41 bool* is_empty_program,
42 intptr_t* p_num_classes,
43 intptr_t* p_num_procedures);
44
45 LibraryPtr GetMainLibrary();
46
47 ArrayPtr GetBytecodeComponent();
48 ArrayPtr ReadBytecodeComponent();
49
50 private:
51 ActiveClass* const active_class_;
52
53 DISALLOW_COPY_AND_ASSIGN(BytecodeMetadataHelper);
54};
55
56// Helper class for reading bytecode.
57class BytecodeReaderHelper : public ValueObject {
58 public:
59 explicit BytecodeReaderHelper(TranslationHelper* translation_helper,
60 ActiveClass* active_class,
61 BytecodeComponentData* bytecode_component);
62
63 Reader& reader() { return reader_; }
64
65 void ReadCode(const Function& function, intptr_t code_offset);
66
67 ArrayPtr CreateForwarderChecks(const Function& function);
68
69 void ReadMembers(const Class& cls, bool discard_fields);
70
71 void ReadFieldDeclarations(const Class& cls, bool discard_fields);
72 void ReadFunctionDeclarations(const Class& cls);
73 void ReadClassDeclaration(const Class& cls);
74 void ReadLibraryDeclaration(const Library& library, bool lookup_classes);
75 void ReadLibraryDeclarations(intptr_t num_libraries);
76 void FindAndReadSpecificLibrary(const Library& library,
77 intptr_t num_libraries);
78 void FindModifiedLibrariesForHotReload(BitVector* modified_libs,
79 intptr_t num_libraries);
80
81 void ParseBytecodeFunction(ParsedFunction* parsed_function,
82 const Function& function);
83
84 LibraryPtr ReadMain();
85
86 ArrayPtr ReadBytecodeComponent(intptr_t md_offset);
87 void ResetObjects();
88
89 // Fills in [is_covariant] and [is_generic_covariant_impl] vectors
90 // according to covariance attributes of [function] parameters.
91 //
92 // [function] should be declared in bytecode.
93 // [is_covariant] and [is_generic_covariant_impl] should contain bitvectors
94 // of function.NumParameters() length.
95 void ReadParameterCovariance(const Function& function,
96 BitVector* is_covariant,
97 BitVector* is_generic_covariant_impl);
98
99 // Returns an flattened array of tuples {isFinal, defaultValue, metadata},
100 // or an Error.
101 ObjectPtr BuildParameterDescriptor(const Function& function);
102
103 // Read bytecode PackedObject.
104 ObjectPtr ReadObject();
105
106 private:
107 // These constants should match corresponding constants in class ObjectHandle
108 // (pkg/vm/lib/bytecode/object_table.dart).
109 static const int kReferenceBit = 1 << 0;
110 static const int kIndexShift = 1;
111 static const int kKindShift = 1;
112 static const int kKindMask = 0x0f;
113 static const int kFlagBit0 = 1 << 5;
114 static const int kFlagBit1 = 1 << 6;
115 static const int kFlagBit2 = 1 << 7;
116 static const int kFlagBit3 = 1 << 8;
117 static const int kFlagBit4 = 1 << 9;
118 static const int kFlagBit5 = 1 << 10;
119 static const int kTagMask = (kFlagBit0 | kFlagBit1 | kFlagBit2 | kFlagBit3);
120 static const int kNullabilityMask = (kFlagBit4 | kFlagBit5);
121 static const int kFlagsMask = (kTagMask | kNullabilityMask);
122
123 // Code flags, must be in sync with Code constants in
124 // pkg/vm/lib/bytecode/declarations.dart.
125 struct Code {
126 static const int kHasExceptionsTableFlag = 1 << 0;
127 static const int kHasSourcePositionsFlag = 1 << 1;
128 static const int kHasNullableFieldsFlag = 1 << 2;
129 static const int kHasClosuresFlag = 1 << 3;
130 static const int kHasParameterFlagsFlag = 1 << 4;
131 static const int kHasForwardingStubTargetFlag = 1 << 5;
132 static const int kHasDefaultFunctionTypeArgsFlag = 1 << 6;
133 static const int kHasLocalVariablesFlag = 1 << 7;
134 };
135
136 // Closure code flags, must be in sync with ClosureCode constants in
137 // pkg/vm/lib/bytecode/declarations.dart.
138 struct ClosureCode {
139 static const int kHasExceptionsTableFlag = 1 << 0;
140 static const int kHasSourcePositionsFlag = 1 << 1;
141 static const int kHasLocalVariablesFlag = 1 << 2;
142 };
143
144 // Parameter flags, must be in sync with ParameterDeclaration constants in
145 // pkg/vm/lib/bytecode/declarations.dart.
146 struct Parameter {
147 static const int kIsCovariantFlag = 1 << 0;
148 static const int kIsGenericCovariantImplFlag = 1 << 1;
149 static const int kIsFinalFlag = 1 << 2;
150 static const int kIsRequiredFlag = 1 << 3;
151 };
152
153 class FunctionTypeScope : public ValueObject {
154 public:
155 explicit FunctionTypeScope(BytecodeReaderHelper* bytecode_reader)
156 : bytecode_reader_(bytecode_reader),
157 saved_type_parameters_(
158 bytecode_reader->function_type_type_parameters_) {}
159
160 ~FunctionTypeScope() {
161 bytecode_reader_->function_type_type_parameters_ = saved_type_parameters_;
162 }
163
164 private:
165 BytecodeReaderHelper* bytecode_reader_;
166 const TypeArguments* const saved_type_parameters_;
167 };
168
169 class FunctionScope : public ValueObject {
170 public:
171 FunctionScope(BytecodeReaderHelper* bytecode_reader,
172 const Function& function,
173 const String& name,
174 const Class& cls)
175 : bytecode_reader_(bytecode_reader) {
176 ASSERT(bytecode_reader_->scoped_function_.IsNull());
177 ASSERT(bytecode_reader_->scoped_function_name_.IsNull());
178 ASSERT(bytecode_reader_->scoped_function_class_.IsNull());
179 ASSERT(name.IsSymbol());
180 bytecode_reader_->scoped_function_ = function.raw();
181 bytecode_reader_->scoped_function_name_ = name.raw();
182 bytecode_reader_->scoped_function_class_ = cls.raw();
183 }
184
185 ~FunctionScope() {
186 bytecode_reader_->scoped_function_ = Function::null();
187 bytecode_reader_->scoped_function_name_ = String::null();
188 bytecode_reader_->scoped_function_class_ = Class::null();
189 }
190
191 private:
192 BytecodeReaderHelper* bytecode_reader_;
193 };
194
195 void ReadClosureDeclaration(const Function& function, intptr_t closureIndex);
196 TypePtr ReadFunctionSignature(const Function& func,
197 bool has_optional_positional_params,
198 bool has_optional_named_params,
199 bool has_type_params,
200 bool has_positional_param_names,
201 bool has_parameter_flags,
202 Nullability nullability);
203 void ReadTypeParametersDeclaration(const Class& parameterized_class,
204 const Function& parameterized_function);
205
206 // Read portion of constant pool corresponding to one function/closure.
207 // Start with [start_index], and stop when reaching EndClosureFunctionScope.
208 // Return index of the last read constant pool entry.
209 intptr_t ReadConstantPool(const Function& function,
210 const ObjectPool& pool,
211 intptr_t start_index);
212
213 BytecodePtr ReadBytecode(const ObjectPool& pool);
214 void ReadExceptionsTable(const Bytecode& bytecode, bool has_exceptions_table);
215 void ReadSourcePositions(const Bytecode& bytecode, bool has_source_positions);
216 void ReadLocalVariables(const Bytecode& bytecode, bool has_local_variables);
217 TypedDataPtr NativeEntry(const Function& function,
218 const String& external_name);
219 StringPtr ConstructorName(const Class& cls, const String& name);
220
221 ObjectPtr ReadObjectContents(uint32_t header);
222 ObjectPtr ReadConstObject(intptr_t tag);
223 ObjectPtr ReadType(intptr_t tag, Nullability nullability);
224 StringPtr ReadString(bool is_canonical = true);
225 ScriptPtr ReadSourceFile(const String& uri, intptr_t offset);
226 TypeArgumentsPtr ReadTypeArguments();
227 void ReadAttributes(const Object& key);
228 PatchClassPtr GetPatchClass(const Class& cls, const Script& script);
229 void ParseForwarderFunction(ParsedFunction* parsed_function,
230 const Function& function,
231 const Function& target);
232
233 bool IsExpressionEvaluationLibrary(const Library& library) const {
234 return expression_evaluation_library_ != nullptr &&
235 expression_evaluation_library_->raw() == library.raw();
236 }
237
238 // Similar to cls.EnsureClassDeclaration, but may be more efficient if
239 // class is from the current kernel binary.
240 void LoadReferencedClass(const Class& cls);
241
242 Reader reader_;
243 TranslationHelper& translation_helper_;
244 ActiveClass* const active_class_;
245 Thread* const thread_;
246 Zone* const zone_;
247 BytecodeComponentData* bytecode_component_;
248 Array* closures_ = nullptr;
249 const TypeArguments* function_type_type_parameters_ = nullptr;
250 GrowableObjectArray* pending_recursive_types_ = nullptr;
251 PatchClass* patch_class_ = nullptr;
252 Array* functions_ = nullptr;
253 intptr_t function_index_ = 0;
254 Function& scoped_function_;
255 String& scoped_function_name_;
256 Class& scoped_function_class_;
257 Library* expression_evaluation_library_ = nullptr;
258 bool loading_native_wrappers_library_ = false;
259 bool reading_type_arguments_of_recursive_type_ = false;
260
261 DISALLOW_COPY_AND_ASSIGN(BytecodeReaderHelper);
262};
263
264class BytecodeComponentData : ValueObject {
265 public:
266 enum {
267 kVersion,
268 kStringsHeaderOffset,
269 kStringsContentsOffset,
270 kObjectOffsetsOffset,
271 kNumObjects,
272 kObjectsContentsOffset,
273 kMainOffset,
274 kNumLibraries,
275 kLibraryIndexOffset,
276 kLibrariesOffset,
277 kNumClasses,
278 kClassesOffset,
279 kMembersOffset,
280 kNumCodes,
281 kCodesOffset,
282 kSourcePositionsOffset,
283 kSourceFilesOffset,
284 kLineStartsOffset,
285 kLocalVariablesOffset,
286 kAnnotationsOffset,
287 kNumFields
288 };
289
290 explicit BytecodeComponentData(Array* data) : data_(*data) {}
291
292 void Init(const Array& data) { data_ = data.raw(); }
293
294 intptr_t GetVersion() const;
295 intptr_t GetStringsHeaderOffset() const;
296 intptr_t GetStringsContentsOffset() const;
297 intptr_t GetObjectOffsetsOffset() const;
298 intptr_t GetNumObjects() const;
299 intptr_t GetObjectsContentsOffset() const;
300 intptr_t GetMainOffset() const;
301 intptr_t GetNumLibraries() const;
302 intptr_t GetLibraryIndexOffset() const;
303 intptr_t GetLibrariesOffset() const;
304 intptr_t GetNumClasses() const;
305 intptr_t GetClassesOffset() const;
306 intptr_t GetMembersOffset() const;
307 intptr_t GetNumCodes() const;
308 intptr_t GetCodesOffset() const;
309 intptr_t GetSourcePositionsOffset() const;
310 intptr_t GetSourceFilesOffset() const;
311 intptr_t GetLineStartsOffset() const;
312 intptr_t GetLocalVariablesOffset() const;
313 intptr_t GetAnnotationsOffset() const;
314 void SetObject(intptr_t index, const Object& obj) const;
315 ObjectPtr GetObject(intptr_t index) const;
316
317 bool IsNull() const { return data_.IsNull(); }
318
319 static ArrayPtr New(Zone* zone,
320 intptr_t version,
321 intptr_t num_objects,
322 intptr_t strings_header_offset,
323 intptr_t strings_contents_offset,
324 intptr_t object_offsets_offset,
325 intptr_t objects_contents_offset,
326 intptr_t main_offset,
327 intptr_t num_libraries,
328 intptr_t library_index_offset,
329 intptr_t libraries_offset,
330 intptr_t num_classes,
331 intptr_t classes_offset,
332 intptr_t members_offset,
333 intptr_t num_codes,
334 intptr_t codes_offset,
335 intptr_t source_positions_offset,
336 intptr_t source_files_offset,
337 intptr_t line_starts_offset,
338 intptr_t local_variables_offset,
339 intptr_t annotations_offset,
340 Heap::Space space);
341
342 private:
343 Array& data_;
344};
345
346class BytecodeReader : public AllStatic {
347 public:
348 // Reads bytecode for the given function and sets its bytecode field.
349 // Returns error (if any), or null.
350 static ErrorPtr ReadFunctionBytecode(Thread* thread,
351 const Function& function);
352
353 // Read annotations for the given annotation field.
354 static ObjectPtr ReadAnnotation(const Field& annotation_field);
355 // Read the |count| annotations following given annotation field.
356 static ArrayPtr ReadExtendedAnnotations(const Field& annotation_field,
357 intptr_t count);
358
359 static void ResetObjectTable(const KernelProgramInfo& info);
360
361 // Read declaration of the given library.
362 static void LoadLibraryDeclaration(const Library& library);
363
364 // Read declaration of the given class.
365 static void LoadClassDeclaration(const Class& cls);
366
367 // Read members of the given class.
368 static void FinishClassLoading(const Class& cls);
369
370 // Value of attribute [name] of Function/Field [key].
371 static ObjectPtr GetBytecodeAttribute(const Object& key, const String& name);
372
373#if !defined(PRODUCT)
374 // Compute local variable descriptors for [function] with [bytecode].
375 static LocalVarDescriptorsPtr ComputeLocalVarDescriptors(
376 Zone* zone,
377 const Function& function,
378 const Bytecode& bytecode);
379#endif
380};
381
382class InferredTypeBytecodeAttribute : public AllStatic {
383 public:
384 // Number of array elements per entry in InferredType bytecode
385 // attribute (PC, type, flags).
386 static constexpr intptr_t kNumElements = 3;
387
388 // Field type is the first entry with PC = -1.
389 static constexpr intptr_t kFieldTypePC = -1;
390
391 // Returns PC at given index.
392 static intptr_t GetPCAt(const Array& attr, intptr_t index) {
393 return Smi::Value(Smi::RawCast(attr.At(index)));
394 }
395
396 // Returns InferredType metadata at given index.
397 static InferredTypeMetadata GetInferredTypeAt(Zone* zone,
398 const Array& attr,
399 intptr_t index);
400};
401
402class BytecodeSourcePositionsIterator : ValueObject {
403 public:
404 // These constants should match corresponding constants in class
405 // SourcePositions (pkg/vm/lib/bytecode/source_positions.dart).
406 static const intptr_t kSyntheticCodeMarker = -1;
407 static const intptr_t kYieldPointMarker = -2;
408
409 BytecodeSourcePositionsIterator(Zone* zone, const Bytecode& bytecode)
410 : reader_(ExternalTypedData::Handle(zone, bytecode.GetBinary(zone))) {
411 if (bytecode.HasSourcePositions()) {
412 reader_.set_offset(bytecode.source_positions_binary_offset());
413 pairs_remaining_ = reader_.ReadUInt();
414 }
415 }
416
417 bool MoveNext() {
418 if (pairs_remaining_ == 0) {
419 return false;
420 }
421 ASSERT(pairs_remaining_ > 0);
422 --pairs_remaining_;
423 cur_bci_ += reader_.ReadUInt();
424 cur_token_pos_ += reader_.ReadSLEB128();
425 is_yield_point_ = false;
426 if (cur_token_pos_ == kYieldPointMarker) {
427 const bool result = MoveNext();
428 is_yield_point_ = true;
429 return result;
430 }
431 return true;
432 }
433
434 uword PcOffset() const { return cur_bci_; }
435
436 TokenPosition TokenPos() const {
437 return (cur_token_pos_ == kSyntheticCodeMarker)
438 ? TokenPosition::kNoSource
439 : TokenPosition(cur_token_pos_);
440 }
441
442 bool IsYieldPoint() const { return is_yield_point_; }
443
444 private:
445 Reader reader_;
446 intptr_t pairs_remaining_ = 0;
447 intptr_t cur_bci_ = 0;
448 intptr_t cur_token_pos_ = 0;
449 bool is_yield_point_ = false;
450};
451
452class BytecodeLocalVariablesIterator : ValueObject {
453 public:
454 // These constants should match corresponding constants in
455 // pkg/vm/lib/bytecode/local_variable_table.dart.
456 enum {
457 kInvalid,
458 kScope,
459 kVariableDeclaration,
460 kContextVariable,
461 };
462
463 static const intptr_t kKindMask = 0xF;
464 static const intptr_t kIsCapturedFlag = 1 << 4;
465
466 BytecodeLocalVariablesIterator(Zone* zone, const Bytecode& bytecode)
467 : reader_(ExternalTypedData::Handle(zone, bytecode.GetBinary(zone))),
468 object_pool_(ObjectPool::Handle(zone, bytecode.object_pool())) {
469 if (bytecode.HasLocalVariablesInfo()) {
470 reader_.set_offset(bytecode.local_variables_binary_offset());
471 entries_remaining_ = reader_.ReadUInt();
472 }
473 }
474
475 bool MoveNext() {
476 if (entries_remaining_ <= 0) {
477 // Finished looking at the last entry, now we're done.
478 entries_remaining_ = -1;
479 return false;
480 }
481 --entries_remaining_;
482 cur_kind_and_flags_ = reader_.ReadByte();
483 cur_start_pc_ += reader_.ReadSLEB128();
484 switch (Kind()) {
485 case kScope:
486 cur_end_pc_ = cur_start_pc_ + reader_.ReadUInt();
487 cur_index_ = reader_.ReadSLEB128();
488 cur_token_pos_ = reader_.ReadPosition();
489 cur_end_token_pos_ = reader_.ReadPosition();
490 break;
491 case kVariableDeclaration:
492 cur_index_ = reader_.ReadSLEB128();
493 cur_name_ = reader_.ReadUInt();
494 cur_type_ = reader_.ReadUInt();
495 cur_declaration_token_pos_ = reader_.ReadPosition();
496 cur_token_pos_ = reader_.ReadPosition();
497 break;
498 case kContextVariable:
499 cur_index_ = reader_.ReadSLEB128();
500 break;
501 }
502 return true;
503 }
504
505 // Returns true after iterator moved past the last entry and
506 // MoveNext() returned false.
507 bool IsDone() const { return entries_remaining_ < 0; }
508
509 intptr_t Kind() const { return cur_kind_and_flags_ & kKindMask; }
510 bool IsScope() const { return Kind() == kScope; }
511 bool IsVariableDeclaration() const { return Kind() == kVariableDeclaration; }
512 bool IsContextVariable() const { return Kind() == kContextVariable; }
513
514 intptr_t StartPC() const { return cur_start_pc_; }
515 intptr_t EndPC() const {
516 ASSERT(IsScope() || IsVariableDeclaration());
517 return cur_end_pc_;
518 }
519 intptr_t ContextLevel() const {
520 ASSERT(IsScope());
521 return cur_index_;
522 }
523 TokenPosition StartTokenPos() const {
524 ASSERT(IsScope() || IsVariableDeclaration());
525 return cur_token_pos_;
526 }
527 TokenPosition EndTokenPos() const {
528 ASSERT(IsScope() || IsVariableDeclaration());
529 return cur_end_token_pos_;
530 }
531 intptr_t Index() const {
532 ASSERT(IsVariableDeclaration() || IsContextVariable());
533 return cur_index_;
534 }
535 StringPtr Name() const {
536 ASSERT(IsVariableDeclaration());
537 return String::RawCast(object_pool_.ObjectAt(cur_name_));
538 }
539 AbstractTypePtr Type() const {
540 ASSERT(IsVariableDeclaration());
541 return AbstractType::RawCast(object_pool_.ObjectAt(cur_type_));
542 }
543 TokenPosition DeclarationTokenPos() const {
544 ASSERT(IsVariableDeclaration());
545 return cur_declaration_token_pos_;
546 }
547 bool IsCaptured() const {
548 ASSERT(IsVariableDeclaration());
549 return (cur_kind_and_flags_ & kIsCapturedFlag) != 0;
550 }
551
552 private:
553 Reader reader_;
554 const ObjectPool& object_pool_;
555 intptr_t entries_remaining_ = 0;
556 intptr_t cur_kind_and_flags_ = 0;
557 intptr_t cur_start_pc_ = 0;
558 intptr_t cur_end_pc_ = 0;
559 intptr_t cur_index_ = -1;
560 intptr_t cur_name_ = -1;
561 intptr_t cur_type_ = -1;
562 TokenPosition cur_token_pos_ = TokenPosition::kNoSource;
563 TokenPosition cur_declaration_token_pos_ = TokenPosition::kNoSource;
564 TokenPosition cur_end_token_pos_ = TokenPosition::kNoSource;
565};
566
567class BytecodeAttributesMapTraits {
568 public:
569 static const char* Name() { return "BytecodeAttributesMapTraits"; }
570 static bool ReportStats() { return false; }
571
572 static bool IsMatch(const Object& a, const Object& b) {
573 return a.raw() == b.raw();
574 }
575
576 static uword Hash(const Object& key) {
577 return String::HashRawSymbol(key.IsFunction() ? Function::Cast(key).name()
578 : Field::Cast(key).name());
579 }
580};
581typedef UnorderedHashMap<BytecodeAttributesMapTraits> BytecodeAttributesMap;
582
583bool IsStaticFieldGetterGeneratedAsInitializer(const Function& function,
584 Zone* zone);
585
586} // namespace kernel
587} // namespace dart
588
589#endif // RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_READER_H_
590