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_FLOW_GRAPH_BUILDER_H_
6#define RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_FLOW_GRAPH_BUILDER_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/backend/il.h"
13#include "vm/compiler/frontend/base_flow_graph_builder.h"
14#include "vm/compiler/frontend/kernel_translation_helper.h" // For InferredTypeMetadata
15#include "vm/constants_kbc.h"
16
17namespace dart {
18namespace kernel {
19
20class BytecodeLocalVariablesIterator;
21
22// This class builds flow graph from bytecode. It is used either to compile
23// from bytecode, or generate bytecode interpreter (the latter is not
24// fully implemented yet).
25// TODO(alexmarkov): extend this class and IL to generate an interpreter in
26// addition to compiling bytecode.
27class BytecodeFlowGraphBuilder {
28 public:
29 BytecodeFlowGraphBuilder(BaseFlowGraphBuilder* flow_graph_builder,
30 ParsedFunction* parsed_function,
31 ZoneGrowableArray<const ICData*>* ic_data_array)
32 : flow_graph_builder_(flow_graph_builder),
33 zone_(flow_graph_builder->zone_),
34 is_generating_interpreter_(
35 false), // TODO(alexmarkov): pass as argument
36 parsed_function_(parsed_function),
37 ic_data_array_(ic_data_array),
38 object_pool_(ObjectPool::Handle(zone_)),
39 bytecode_length_(0),
40 pc_(0),
41 position_(TokenPosition::kNoSource),
42 local_vars_(zone_, 0),
43 parameters_(zone_, 0),
44 exception_var_(nullptr),
45 stacktrace_var_(nullptr),
46 scratch_var_(nullptr),
47 prologue_info_(-1, -1),
48 throw_no_such_method_(nullptr),
49 inferred_types_attribute_(Array::Handle(zone_)) {}
50
51 FlowGraph* BuildGraph();
52
53 // Create parameter variables without building a flow graph.
54 void CreateParameterVariables();
55
56 protected:
57 // Returns `true` if building a flow graph for a bytecode interpreter, or
58 // `false` if compiling a function from bytecode.
59 bool is_generating_interpreter() const { return is_generating_interpreter_; }
60
61 private:
62 // Operand of bytecode instruction, either intptr_t value (if compiling
63 // bytecode) or Definition (if generating interpreter).
64 class Operand {
65 public:
66 explicit Operand(Definition* definition)
67 : definition_(definition), value_(0) {
68 ASSERT(definition != nullptr);
69 }
70
71 explicit Operand(intptr_t value) : definition_(nullptr), value_(value) {}
72
73 Definition* definition() const {
74 ASSERT(definition_ != nullptr);
75 return definition_;
76 }
77
78 intptr_t value() const {
79 ASSERT(definition_ == nullptr);
80 return value_;
81 }
82
83 private:
84 Definition* definition_;
85 intptr_t value_;
86 };
87
88 // Constant from a constant pool.
89 // It is either Object (if compiling bytecode) or Definition
90 // (if generating interpreter).
91 class Constant {
92 public:
93 explicit Constant(Definition* definition)
94 : definition_(definition), value_(Object::null_object()) {
95 ASSERT(definition != nullptr);
96 }
97
98 explicit Constant(Zone* zone, const Object& value)
99 : definition_(nullptr), value_(value) {}
100
101 Definition* definition() const {
102 ASSERT(definition_ != nullptr);
103 return definition_;
104 }
105
106 const Object& value() const {
107 ASSERT(definition_ == nullptr);
108 return value_;
109 }
110
111 private:
112 Definition* definition_;
113 const Object& value_;
114 };
115
116 // Scope declared in bytecode local variables information.
117 class BytecodeScope : public ZoneAllocated {
118 public:
119 BytecodeScope(Zone* zone,
120 intptr_t end_pc,
121 intptr_t context_level,
122 BytecodeScope* parent)
123 : end_pc_(end_pc),
124 context_level_(context_level),
125 parent_(parent),
126 hidden_vars_(zone, 4) {}
127
128 const intptr_t end_pc_;
129 const intptr_t context_level_;
130 BytecodeScope* const parent_;
131 ZoneGrowableArray<LocalVariable*> hidden_vars_;
132 };
133
134 Operand DecodeOperandA();
135 Operand DecodeOperandB();
136 Operand DecodeOperandC();
137 Operand DecodeOperandD();
138 Operand DecodeOperandE();
139 Operand DecodeOperandF();
140 Operand DecodeOperandX();
141 Operand DecodeOperandY();
142 Operand DecodeOperandT();
143 Constant ConstantAt(Operand entry_index, intptr_t add_index = 0);
144 void PushConstant(Constant constant);
145 Constant PopConstant();
146 void LoadStackSlots(intptr_t num_slots);
147 void AllocateLocalVariables(Operand frame_size,
148 intptr_t num_param_locals = 0);
149 LocalVariable* AllocateParameter(intptr_t param_index,
150 VariableIndex var_index);
151 void AllocateFixedParameters();
152
153 // Allocates parameters and local variables in case of EntryOptional.
154 // Returns pointer to the instruction after EntryOptional/LoadConstant/Frame
155 // bytecodes.
156 const KBCInstr* AllocateParametersAndLocalsForEntryOptional();
157
158 LocalVariable* LocalVariableAt(intptr_t local_index);
159 void StoreLocal(Operand local_index);
160 void LoadLocal(Operand local_index);
161 Value* Pop();
162 intptr_t GetStackDepth() const;
163 bool IsStackEmpty() const;
164 InferredTypeMetadata GetInferredType(intptr_t pc);
165 void PropagateStackState(intptr_t target_pc);
166 void DropUnusedValuesFromStack();
167 void BuildJumpIfStrictCompare(Token::Kind cmp_kind);
168 void BuildPrimitiveOp(const String& name,
169 Token::Kind token_kind,
170 const AbstractType& static_receiver_type,
171 int num_args);
172 void BuildIntOp(const String& name, Token::Kind token_kind, int num_args);
173 void BuildDoubleOp(const String& name, Token::Kind token_kind, int num_args);
174 void BuildDirectCallCommon(bool is_unchecked_call);
175 void BuildInterfaceCallCommon(bool is_unchecked_call,
176 bool is_instantiated_call);
177
178 void BuildInstruction(KernelBytecode::Opcode opcode);
179 void BuildFfiAsFunction();
180 void BuildFfiNativeCallbackFunction();
181 void BuildDebugStepCheck();
182
183#define DECLARE_BUILD_METHOD(name, encoding, kind, op1, op2, op3) \
184 void Build##name();
185 KERNEL_BYTECODES_LIST(DECLARE_BUILD_METHOD)
186#undef DECLARE_BUILD_METHOD
187
188 intptr_t GetTryIndex(const PcDescriptors& descriptors, intptr_t pc);
189 JoinEntryInstr* EnsureControlFlowJoin(const PcDescriptors& descriptors,
190 intptr_t pc);
191 bool RequiresScratchVar(const KBCInstr* instr);
192 void CollectControlFlow(const PcDescriptors& descriptors,
193 const ExceptionHandlers& handlers,
194 GraphEntryInstr* graph_entry);
195
196 // Update current scope, context level and local variables for the given PC.
197 // Returns next PC where scope might need an update.
198 intptr_t UpdateScope(BytecodeLocalVariablesIterator* iter, intptr_t pc);
199
200 // Figure out entry points style.
201 UncheckedEntryPointStyle ChooseEntryPointStyle(
202 const KBCInstr* jump_if_unchecked);
203
204 Thread* thread() const { return flow_graph_builder_->thread_; }
205 Isolate* isolate() const { return thread()->isolate(); }
206
207 ParsedFunction* parsed_function() const {
208 ASSERT(!is_generating_interpreter());
209 return parsed_function_;
210 }
211 const Function& function() const { return parsed_function()->function(); }
212
213 BaseFlowGraphBuilder* flow_graph_builder_;
214 Zone* zone_;
215 bool is_generating_interpreter_;
216
217 // The following members are available only when compiling bytecode.
218
219 ParsedFunction* parsed_function_;
220 ZoneGrowableArray<const ICData*>* ic_data_array_;
221 ObjectPool& object_pool_;
222 const KBCInstr* raw_bytecode_ = nullptr;
223 intptr_t bytecode_length_;
224 intptr_t pc_;
225 intptr_t next_pc_ = -1;
226 const KBCInstr* bytecode_instr_ = nullptr;
227 TokenPosition position_;
228 intptr_t last_yield_point_pc_ = 0;
229 intptr_t last_yield_point_index_ = 0;
230 Fragment code_;
231 ZoneGrowableArray<LocalVariable*> local_vars_;
232 ZoneGrowableArray<LocalVariable*> parameters_;
233 LocalVariable* exception_var_;
234 LocalVariable* stacktrace_var_;
235 LocalVariable* scratch_var_;
236 IntMap<JoinEntryInstr*> jump_targets_;
237 IntMap<Value*> stack_states_;
238 PrologueInfo prologue_info_;
239 JoinEntryInstr* throw_no_such_method_;
240 GraphEntryInstr* graph_entry_ = nullptr;
241 UncheckedEntryPointStyle entry_point_style_ = UncheckedEntryPointStyle::kNone;
242 bool build_debug_step_checks_ = false;
243 bool seen_parameters_scope_ = false;
244 BytecodeScope* current_scope_ = nullptr;
245 Array& inferred_types_attribute_;
246 intptr_t inferred_types_index_ = 0;
247};
248
249} // namespace kernel
250} // namespace dart
251
252#endif // RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_FLOW_GRAPH_BUILDER_H_
253