1// Copyright (c) 2019, 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_BACKEND_IL_SERIALIZER_H_
6#define RUNTIME_VM_COMPILER_BACKEND_IL_SERIALIZER_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 "platform/assert.h"
13#include "platform/text_buffer.h"
14
15#include "vm/allocation.h"
16#include "vm/compiler/backend/flow_graph.h"
17#include "vm/compiler/backend/il.h"
18#include "vm/compiler/backend/sexpression.h"
19#include "vm/hash_table.h"
20#include "vm/object.h"
21#include "vm/zone.h"
22
23namespace dart {
24
25// Flow graph serialization.
26class FlowGraphSerializer : ValueObject {
27 public:
28#define FOR_EACH_BLOCK_ENTRY_KIND(M) \
29 M(Target) \
30 M(Join) \
31 M(Graph) \
32 M(Normal) \
33 M(Unchecked) \
34 M(OSR) \
35 M(Catch) \
36 M(Indirect)
37
38 enum BlockEntryKind {
39#define KIND_DECL(name) k##name,
40 FOR_EACH_BLOCK_ENTRY_KIND(KIND_DECL)
41#undef KIND_DECL
42 // clang-format off
43 kNumEntryKinds,
44 kInvalid = -1,
45 // clang-format on
46 };
47
48 // Special case: returns kTarget for a nullptr input.
49 static BlockEntryKind BlockEntryTagToKind(SExpSymbol* tag);
50 SExpSymbol* BlockEntryKindToTag(BlockEntryKind k);
51 static bool BlockEntryKindHasInitialDefs(BlockEntryKind kind);
52
53 static void SerializeToBuffer(Zone* zone,
54 const FlowGraph* flow_graph,
55 BaseTextBuffer* buffer);
56 static SExpression* SerializeToSExp(Zone* zone, const FlowGraph* flow_graph);
57
58 const FlowGraph* flow_graph() const { return flow_graph_; }
59 Zone* zone() const { return zone_; }
60
61 SExpression* FlowGraphToSExp();
62
63 SExpSymbol* BlockEntryTag(const BlockEntryInstr* entry);
64 SExpression* BlockIdToSExp(intptr_t block_id);
65 SExpression* CanonicalNameToSExp(const Object& obj);
66 SExpression* UseToSExp(const Definition* definition);
67
68 // Helper method for creating canonical names.
69 void SerializeCanonicalName(BaseTextBuffer* b, const Object& obj);
70
71 // Methods for serializing Dart values. If the argument
72 // value is the null object, the null pointer is returned.
73 SExpression* AbstractTypeToSExp(const AbstractType& typ);
74 SExpression* ArrayToSExp(const Array& arr);
75 SExpression* ClassToSExp(const Class& cls);
76 SExpression* ClosureToSExp(const Closure& c);
77 SExpression* ContextToSExp(const Context& c);
78 SExpression* CodeToSExp(const Code& c);
79 SExpression* FieldToSExp(const Field& f);
80 SExpression* FunctionToSExp(const Function& f);
81 SExpression* InstanceToSExp(const Instance& obj);
82 SExpression* TypeArgumentsToSExp(const TypeArguments& ta);
83
84 // A method for serializing a Dart value of arbitrary type. Unlike the
85 // type-specific methods, this returns the symbol "null" for the null object.
86 SExpression* ObjectToSExp(const Object& obj);
87
88 // A wrapper method for ObjectToSExp that first checks and sees if
89 // the provided value is in the constant pool. If it is, then it
90 // returns a reference to the constant definition via UseToSExp.
91 SExpression* DartValueToSExp(const Object& obj);
92
93 // A wrapper method for TypeArgumentsToSExp that also returns nullptr if the
94 // type arguments are empty and checks against the constant pool.
95 SExpression* NonEmptyTypeArgumentsToSExp(const TypeArguments& ta);
96
97 // Methods for serializing IL-specific values.
98 SExpression* LocalVariableToSExp(const LocalVariable& v);
99 SExpression* SlotToSExp(const Slot& s);
100 SExpression* ICDataToSExp(const ICData* ic_data);
101
102 // Helper methods for adding Definition-specific extra info.
103 bool HasDefinitionExtraInfo(const Definition* def);
104 void AddDefinitionExtraInfoToSExp(const Definition* def, SExpList* sexp);
105
106 // Helper methods for adding atoms to S-expression lists
107 void AddBool(SExpList* sexp, bool b);
108 void AddInteger(SExpList* sexp, intptr_t i);
109 void AddString(SExpList* sexp, const char* cstr);
110 void AddSymbol(SExpList* sexp, const char* cstr);
111 void AddExtraBool(SExpList* sexp, const char* label, bool b);
112 void AddExtraInteger(SExpList* sexp, const char* label, intptr_t i);
113 void AddExtraString(SExpList* sexp, const char* label, const char* cstr);
114 void AddExtraSymbol(SExpList* sexp, const char* label, const char* cstr);
115
116 private:
117 friend class Precompiler; // For LLVMConstantsMap.
118
119 FlowGraphSerializer(Zone* zone, const FlowGraph* flow_graph);
120 ~FlowGraphSerializer();
121
122 static const char* const initial_indent;
123
124 // Helper methods for the function level that are not used by any
125 // instruction serialization methods.
126 SExpression* FunctionEntryToSExp(const BlockEntryInstr* entry);
127 SExpression* EntriesToSExp(const GraphEntryInstr* start);
128 SExpression* ConstantPoolToSExp(const GraphEntryInstr* start);
129
130 const FlowGraph* const flow_graph_;
131 Zone* const zone_;
132 ObjectStore* const object_store_;
133
134 // A map of currently open (being serialized) recursive types. We use this
135 // to determine whether to serialize the referred types in TypeRefs.
136 IntMap<const Type*> open_recursive_types_;
137
138 // Used for --populate-llvm-constant-pool in ConstantPoolToSExp.
139 class LLVMPoolMapKeyEqualsTraits : public AllStatic {
140 public:
141 static const char* Name() { return "LLVMPoolMapKeyEqualsTraits"; }
142 static bool ReportStats() { return false; }
143
144 static bool IsMatch(const Object& a, const Object& b) {
145 return a.raw() == b.raw();
146 }
147 static uword Hash(const Object& obj) {
148 if (obj.IsSmi()) return static_cast<uword>(obj.raw());
149 if (obj.IsInstance()) return Instance::Cast(obj).CanonicalizeHash();
150 return obj.GetClassId();
151 }
152 };
153 typedef UnorderedHashMap<LLVMPoolMapKeyEqualsTraits> LLVMPoolMap;
154
155 GrowableObjectArray& llvm_constants_;
156 GrowableObjectArray& llvm_functions_;
157 LLVMPoolMap llvm_constant_map_;
158 Smi& llvm_index_;
159
160 // Handles used across functions, where the contained value is used
161 // immediately and does not need to live across calls to other serializer
162 // functions.
163 String& tmp_string_;
164
165 // Handles for use within a single function in the following cases:
166 //
167 // * The function is guaranteed to not be re-entered during execution.
168 // * The contained value is not live across any possible re-entry.
169 //
170 // Generally, the most likely source of possible re-entry is calling
171 // DartValueToSExp with a sub-element of type Object, but any call to a
172 // FlowGraphSerializer method that may eventually enter one of the methods
173 // listed below should be examined with care.
174 TypeArguments& array_type_args_; // ArrayToSExp
175 Context& closure_context_; // ClosureToSExp
176 Function& closure_function_; // ClosureToSExp
177 TypeArguments& closure_type_args_; // ClosureToSExp
178 Object& code_owner_; // CodeToSExp
179 Context& context_parent_; // ContextToSExp
180 Object& context_elem_; // ContextToSExp
181 TypeArguments& function_type_args_; // FunctionToSExp
182 Function& ic_data_target_; // ICDataToSExp
183 AbstractType& ic_data_type_; // ICDataToSExp
184 Field& instance_field_; // InstanceToSExp
185 TypeArguments& instance_type_args_; // InstanceToSExp
186 Library& serialize_library_; // SerializeCanonicalName
187 Class& serialize_owner_; // SerializeCanonicalName
188 Function& serialize_parent_; // SerializeCanonicalName
189 AbstractType& type_arguments_elem_; // TypeArgumentsToSExp
190 Class& type_class_; // AbstractTypeToSExp
191 Function& type_function_; // AbstractTypeToSExp
192 AbstractType& type_ref_type_; // AbstractTypeToSExp
193};
194
195} // namespace dart
196
197#endif // RUNTIME_VM_COMPILER_BACKEND_IL_SERIALIZER_H_
198