1// Copyright (c) 2012, 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#include "vm/parser.h"
6#include "vm/flags.h"
7
8#ifndef DART_PRECOMPILED_RUNTIME
9
10#include "lib/invocation_mirror.h"
11#include "platform/utils.h"
12#include "vm/bit_vector.h"
13#include "vm/bootstrap.h"
14#include "vm/class_finalizer.h"
15#include "vm/compiler/aot/precompiler.h"
16#include "vm/compiler/backend/il_printer.h"
17#include "vm/compiler/frontend/scope_builder.h"
18#include "vm/compiler/jit/compiler.h"
19#include "vm/dart_api_impl.h"
20#include "vm/dart_entry.h"
21#include "vm/growable_array.h"
22#include "vm/handles.h"
23#include "vm/hash_table.h"
24#include "vm/isolate.h"
25#include "vm/longjump.h"
26#include "vm/native_arguments.h"
27#include "vm/native_entry.h"
28#include "vm/object.h"
29#include "vm/object_store.h"
30#include "vm/os.h"
31#include "vm/regexp_assembler.h"
32#include "vm/resolver.h"
33#include "vm/scopes.h"
34#include "vm/stack_frame.h"
35#include "vm/symbols.h"
36#include "vm/tags.h"
37#include "vm/timeline.h"
38#include "vm/zone.h"
39
40namespace dart {
41
42// Quick access to the current thread, isolate and zone.
43#define T (thread())
44#define I (isolate())
45#define Z (zone())
46
47ParsedFunction::ParsedFunction(Thread* thread, const Function& function)
48 : thread_(thread),
49 function_(function),
50 code_(Code::Handle(zone: zone(), ptr: function.unoptimized_code())),
51 scope_(nullptr),
52 regexp_compile_data_(nullptr),
53 function_type_arguments_(nullptr),
54 parent_type_arguments_(nullptr),
55 current_context_var_(nullptr),
56 arg_desc_var_(nullptr),
57 expression_temp_var_(nullptr),
58 entry_points_temp_var_(nullptr),
59 finally_return_temp_var_(nullptr),
60 dynamic_closure_call_vars_(nullptr),
61 guarded_fields_(),
62 default_parameter_values_(nullptr),
63 raw_type_arguments_var_(nullptr),
64 first_parameter_index_(),
65 num_stack_locals_(0),
66 have_seen_await_expr_(false),
67 kernel_scopes_(nullptr) {
68 DEBUG_ASSERT(function.IsNotTemporaryScopedHandle());
69 // Every function has a local variable for the current context.
70 LocalVariable* temp = new (zone())
71 LocalVariable(function.token_pos(), function.token_pos(),
72 Symbols::CurrentContextVar(), Object::dynamic_type());
73 current_context_var_ = temp;
74
75 if (function.PrologueNeedsArgumentsDescriptor()) {
76 arg_desc_var_ = new (zone())
77 LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
78 Symbols::ArgDescVar(), Object::dynamic_type());
79 }
80
81 // The code generated by the prologue builder for loading optional arguments
82 // requires the expression temporary variable.
83 if (function.HasOptionalParameters()) {
84 EnsureExpressionTemp();
85 }
86}
87
88void ParsedFunction::AddToGuardedFields(const Field* field) const {
89 if ((field->guarded_cid() == kDynamicCid) ||
90 (field->guarded_cid() == kIllegalCid)) {
91 return;
92 }
93
94 const Field** other = guarded_fields_.Lookup(key: field);
95 if (other != nullptr) {
96 ASSERT(field->Original() == (*other)->Original());
97 // Abort background compilation early if the guarded state of this field
98 // has changed during compilation. We will not be able to commit
99 // the resulting code anyway.
100 if (Compiler::IsBackgroundCompilation()) {
101 if (!(*other)->IsConsistentWith(field: *field)) {
102 Compiler::AbortBackgroundCompilation(
103 deopt_id: DeoptId::kNone, msg: "Field's guarded state changed during compilation");
104 }
105 }
106 return;
107 }
108
109 // Note: the list of guarded fields must contain copies during optimizing
110 // compilation because we will look at their guarded_cid when copying
111 // the array of guarded fields from callee into the caller during
112 // inlining.
113 ASSERT(field->IsOriginal() ==
114 !CompilerState::Current().should_clone_fields());
115 guarded_fields_.Insert(kv: &Field::ZoneHandle(Z, ptr: field->ptr()));
116}
117
118void ParsedFunction::Bailout(const char* origin, const char* reason) const {
119 Report::MessageF(kind: Report::kBailout, script: Script::Handle(ptr: function_.script()),
120 token_pos: function_.token_pos(), report_after_token: Report::AtLocation,
121 format: "%s Bailout in %s: %s", origin,
122 String::Handle(ptr: function_.name()).ToCString(), reason);
123 UNREACHABLE();
124}
125
126kernel::ScopeBuildingResult* ParsedFunction::EnsureKernelScopes() {
127 if (kernel_scopes_ == nullptr) {
128 kernel::ScopeBuilder builder(this);
129 kernel_scopes_ = builder.BuildScopes();
130 }
131 return kernel_scopes_;
132}
133
134LocalVariable* ParsedFunction::EnsureExpressionTemp() {
135 if (!has_expression_temp_var()) {
136 LocalVariable* temp =
137 new (Z) LocalVariable(function_.token_pos(), function_.token_pos(),
138 Symbols::ExprTemp(), Object::dynamic_type());
139 ASSERT(temp != nullptr);
140 set_expression_temp_var(temp);
141 }
142 ASSERT(has_expression_temp_var());
143 return expression_temp_var();
144}
145
146LocalVariable* ParsedFunction::EnsureEntryPointsTemp() {
147 if (!has_entry_points_temp_var()) {
148 LocalVariable* temp = new (Z)
149 LocalVariable(function_.token_pos(), function_.token_pos(),
150 Symbols::EntryPointsTemp(), Object::dynamic_type());
151 ASSERT(temp != nullptr);
152 set_entry_points_temp_var(temp);
153 }
154 ASSERT(has_entry_points_temp_var());
155 return entry_points_temp_var();
156}
157
158void ParsedFunction::EnsureFinallyReturnTemp(bool is_async) {
159 if (!has_finally_return_temp_var()) {
160 LocalVariable* temp =
161 new (Z) LocalVariable(function_.token_pos(), function_.token_pos(),
162 Symbols::FinallyRetVal(), Object::dynamic_type());
163 ASSERT(temp != nullptr);
164 temp->set_is_final();
165 if (is_async) {
166 temp->set_is_captured();
167 }
168 set_finally_return_temp_var(temp);
169 }
170 ASSERT(has_finally_return_temp_var());
171}
172
173void ParsedFunction::SetRegExpCompileData(
174 RegExpCompileData* regexp_compile_data) {
175 ASSERT(regexp_compile_data_ == nullptr);
176 ASSERT(regexp_compile_data != nullptr);
177 regexp_compile_data_ = regexp_compile_data;
178}
179
180void ParsedFunction::AllocateVariables() {
181 ASSERT(!function().IsIrregexpFunction());
182 LocalScope* scope = this->scope();
183 const intptr_t num_fixed_params = function().num_fixed_parameters();
184 const intptr_t num_opt_params = function().NumOptionalParameters();
185 const intptr_t num_params = num_fixed_params + num_opt_params;
186 const bool copy_parameters = function().MakesCopyOfParameters();
187
188 // Before we start allocating indices to variables, we'll setup the
189 // parameters array, which can be used to access the raw parameters (i.e. not
190 // the potentially variables which are in the context)
191
192 raw_parameters_ = new (Z) ZoneGrowableArray<LocalVariable*>(Z, num_params);
193 for (intptr_t param = 0; param < num_params; ++param) {
194 LocalVariable* variable = ParameterVariable(i: param);
195 LocalVariable* raw_parameter = variable;
196 if (variable->is_captured()) {
197 String& tmp = String::ZoneHandle(Z);
198 tmp = Symbols::FromConcat(T, str1: Symbols::OriginalParam(), str2: variable->name());
199
200 RELEASE_ASSERT(scope->LocalLookupVariable(
201 tmp, variable->kernel_offset()) == nullptr);
202 raw_parameter = new LocalVariable(
203 variable->declaration_token_pos(), variable->token_pos(), tmp,
204 variable->type(), variable->kernel_offset(),
205 variable->parameter_type(), variable->parameter_value());
206 raw_parameter->set_annotations_offset(variable->annotations_offset());
207 if (variable->is_explicit_covariant_parameter()) {
208 raw_parameter->set_is_explicit_covariant_parameter();
209 }
210 if (variable->needs_covariant_check_in_method()) {
211 raw_parameter->set_needs_covariant_check_in_method();
212 }
213 raw_parameter->set_type_check_mode(variable->type_check_mode());
214 if (copy_parameters) {
215 bool ok = scope->AddVariable(variable: raw_parameter);
216 ASSERT(ok);
217
218 // Currently our optimizer cannot prove liveness of variables properly
219 // when a function has try/catch. It therefore makes the conservative
220 // estimate that all [LocalVariable]s in the frame are live and spills
221 // them before call sites (in some shape or form).
222 //
223 // Since we are guaranteed to not need that, we tell the try/catch
224 // sync moves mechanism not to care about this variable.
225 //
226 // Receiver (this variable) is an exception from this rule because
227 // it is immutable and we don't reload captured it from the context but
228 // instead use raw_parameter to access it. This means we must still
229 // consider it when emitting the catch entry moves.
230 const bool is_receiver_var =
231 function().HasThisParameter() && receiver_var_ == variable;
232 if (!is_receiver_var) {
233 raw_parameter->set_is_captured_parameter(true);
234 }
235
236 } else {
237 raw_parameter->set_index(
238 VariableIndex(function().NumParameters() - param));
239 }
240 }
241 raw_parameters_->Add(value: raw_parameter);
242 }
243 if (function_type_arguments_ != nullptr) {
244 LocalVariable* raw_type_args_parameter = function_type_arguments_;
245 if (function_type_arguments_->is_captured()) {
246 String& tmp = String::ZoneHandle(Z);
247 tmp = Symbols::FromConcat(T, str1: Symbols::OriginalParam(),
248 str2: function_type_arguments_->name());
249
250 ASSERT(scope->LocalLookupVariable(
251 tmp, function_type_arguments_->kernel_offset()) == nullptr);
252 raw_type_args_parameter =
253 new LocalVariable(function_type_arguments_->declaration_token_pos(),
254 function_type_arguments_->token_pos(), tmp,
255 function_type_arguments_->type(),
256 function_type_arguments_->kernel_offset());
257 bool ok = scope->AddVariable(variable: raw_type_args_parameter);
258 ASSERT(ok);
259 }
260 raw_type_arguments_var_ = raw_type_args_parameter;
261 }
262
263 // The copy parameters implementation will still write to local variables
264 // which we assign indices as with the old CopyParams implementation.
265 VariableIndex first_local_index;
266 {
267 // Compute start indices to parameters and locals, and the number of
268 // parameters to copy.
269 if (!copy_parameters) {
270 ASSERT(suspend_state_var() == nullptr);
271 first_parameter_index_ = VariableIndex(num_params);
272 first_local_index = VariableIndex(0);
273 } else {
274 // :suspend_state variable is inserted at the fixed slot
275 // before the copied parameters.
276 const intptr_t reserved_var_slot_count =
277 (suspend_state_var() != nullptr) ? 1 : 0;
278 first_parameter_index_ = VariableIndex(-reserved_var_slot_count);
279 first_local_index =
280 VariableIndex(first_parameter_index_.value() - num_params);
281 }
282 }
283
284 // Allocate parameters and local variables, either in the local frame or
285 // in the context(s).
286 bool found_captured_variables = false;
287 VariableIndex next_free_index = scope->AllocateVariables(
288 function: function(), first_parameter_index: first_parameter_index_, num_parameters: num_params, first_local_index,
289 context_owner: nullptr, found_captured_variables: &found_captured_variables);
290
291 num_stack_locals_ = -next_free_index.value();
292}
293
294void ParsedFunction::AllocateIrregexpVariables(intptr_t num_stack_locals) {
295 ASSERT(function().IsIrregexpFunction());
296 ASSERT(function().NumOptionalParameters() == 0);
297 const intptr_t num_params = function().num_fixed_parameters();
298 ASSERT(num_params == RegExpMacroAssembler::kParamCount);
299 // Compute start indices to parameters and locals, and the number of
300 // parameters to copy.
301 first_parameter_index_ = VariableIndex(num_params);
302
303 // Frame indices are relative to the frame pointer and are decreasing.
304 num_stack_locals_ = num_stack_locals;
305}
306
307void ParsedFunction::SetCovariantParameters(
308 const BitVector* covariant_parameters) {
309 ASSERT(covariant_parameters_ == nullptr);
310 ASSERT(covariant_parameters->length() == function_.NumParameters());
311 covariant_parameters_ = covariant_parameters;
312}
313
314void ParsedFunction::SetGenericCovariantImplParameters(
315 const BitVector* generic_covariant_impl_parameters) {
316 ASSERT(generic_covariant_impl_parameters_ == nullptr);
317 ASSERT(generic_covariant_impl_parameters->length() ==
318 function_.NumParameters());
319 generic_covariant_impl_parameters_ = generic_covariant_impl_parameters;
320}
321
322bool ParsedFunction::IsCovariantParameter(intptr_t i) const {
323 ASSERT(covariant_parameters_ != nullptr);
324 ASSERT((i >= 0) && (i < function_.NumParameters()));
325 return covariant_parameters_->Contains(i);
326}
327
328bool ParsedFunction::IsGenericCovariantImplParameter(intptr_t i) const {
329 ASSERT(generic_covariant_impl_parameters_ != nullptr);
330 ASSERT((i >= 0) && (i < function_.NumParameters()));
331 return generic_covariant_impl_parameters_->Contains(i);
332}
333
334ParsedFunction::DynamicClosureCallVars*
335ParsedFunction::EnsureDynamicClosureCallVars() {
336 ASSERT(function().IsDynamicClosureCallDispatcher(thread()));
337 if (dynamic_closure_call_vars_ != nullptr) return dynamic_closure_call_vars_;
338 const auto& saved_args_desc =
339 Array::Handle(zone: zone(), ptr: function().saved_args_desc());
340 const ArgumentsDescriptor descriptor(saved_args_desc);
341
342 dynamic_closure_call_vars_ =
343 new (zone()) DynamicClosureCallVars(zone(), descriptor.NamedCount());
344
345 auto const pos = function().token_pos();
346 const auto& type_Dynamic = Object::dynamic_type();
347 const auto& type_Function =
348 Type::ZoneHandle(zone: zone(), ptr: Type::DartFunctionType());
349 const auto& type_Smi = Type::ZoneHandle(zone: zone(), ptr: Type::SmiType());
350#define INIT_FIELD(Name, TypeName, Symbol) \
351 dynamic_closure_call_vars_->Name = new (zone()) LocalVariable( \
352 pos, pos, Symbols::DynamicCall##Symbol##Var(), type_##TypeName);
353 FOR_EACH_DYNAMIC_CLOSURE_CALL_VARIABLE(INIT_FIELD);
354#undef INIT_FIELD
355
356 for (intptr_t i = 0; i < descriptor.NamedCount(); i++) {
357 auto const name = OS::SCreate(
358 zone(), ":dyn_call_named_argument_%" Pd "_parameter_index", i);
359 auto const var = new (zone()) LocalVariable(
360 pos, pos, String::ZoneHandle(zone(), Symbols::New(thread(), name)),
361 type_Smi);
362 dynamic_closure_call_vars_->named_argument_parameter_indices.Add(value: var);
363 }
364
365 return dynamic_closure_call_vars_;
366}
367
368} // namespace dart
369
370#endif // DART_PRECOMPILED_RUNTIME
371

source code of dart_sdk/runtime/vm/parser.cc