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/heap/heap.h"
25#include "vm/heap/safepoint.h"
26#include "vm/isolate.h"
27#include "vm/longjump.h"
28#include "vm/native_arguments.h"
29#include "vm/native_entry.h"
30#include "vm/object.h"
31#include "vm/object_store.h"
32#include "vm/os.h"
33#include "vm/regexp_assembler.h"
34#include "vm/resolver.h"
35#include "vm/scopes.h"
36#include "vm/stack_frame.h"
37#include "vm/symbols.h"
38#include "vm/tags.h"
39#include "vm/timeline.h"
40#include "vm/zone.h"
41
42namespace dart {
43
44// Quick access to the current thread, isolate and zone.
45#define T (thread())
46#define I (isolate())
47#define Z (zone())
48
49ParsedFunction::ParsedFunction(Thread* thread, const Function& function)
50 : thread_(thread),
51 function_(function),
52 code_(Code::Handle(zone(), function.unoptimized_code())),
53 scope_(NULL),
54 regexp_compile_data_(NULL),
55 function_type_arguments_(NULL),
56 parent_type_arguments_(NULL),
57 current_context_var_(NULL),
58 arg_desc_var_(NULL),
59 expression_temp_var_(NULL),
60 entry_points_temp_var_(NULL),
61 finally_return_temp_var_(NULL),
62 guarded_fields_(new ZoneGrowableArray<const Field*>()),
63 default_parameter_values_(NULL),
64 raw_type_arguments_var_(NULL),
65 first_parameter_index_(),
66 num_stack_locals_(0),
67 have_seen_await_expr_(false),
68 kernel_scopes_(NULL),
69 default_function_type_arguments_(TypeArguments::ZoneHandle(zone())) {
70 ASSERT(function.IsZoneHandle());
71 // Every function has a local variable for the current context.
72 LocalVariable* temp = new (zone())
73 LocalVariable(function.token_pos(), function.token_pos(),
74 Symbols::CurrentContextVar(), Object::dynamic_type());
75 current_context_var_ = temp;
76
77 const bool reify_generic_argument = function.IsGeneric();
78
79 const bool load_optional_arguments = function.HasOptionalParameters();
80
81 const bool check_arguments =
82 function_.IsClosureFunction() || function.IsFfiTrampoline();
83
84 const bool need_argument_descriptor =
85 load_optional_arguments || check_arguments || reify_generic_argument;
86
87 if (need_argument_descriptor) {
88 arg_desc_var_ = new (zone())
89 LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
90 Symbols::ArgDescVar(), Object::dynamic_type());
91 }
92}
93
94void ParsedFunction::AddToGuardedFields(const Field* field) const {
95 if ((field->guarded_cid() == kDynamicCid) ||
96 (field->guarded_cid() == kIllegalCid)) {
97 return;
98 }
99
100 for (intptr_t j = 0; j < guarded_fields_->length(); j++) {
101 const Field* other = (*guarded_fields_)[j];
102 if (field->Original() == other->Original()) {
103 // Abort background compilation early if the guarded state of this field
104 // has changed during compilation. We will not be able to commit
105 // the resulting code anyway.
106 if (Compiler::IsBackgroundCompilation()) {
107 if (!other->IsConsistentWith(*field)) {
108 Compiler::AbortBackgroundCompilation(
109 DeoptId::kNone,
110 "Field's guarded state changed during compilation");
111 }
112 }
113 return;
114 }
115 }
116
117 // Note: the list of guarded fields must contain copies during background
118 // compilation because we will look at their guarded_cid when copying
119 // the array of guarded fields from callee into the caller during
120 // inlining.
121 ASSERT(!field->IsOriginal() || Thread::Current()->IsMutatorThread());
122 guarded_fields_->Add(&Field::ZoneHandle(Z, field->raw()));
123}
124
125void ParsedFunction::Bailout(const char* origin, const char* reason) const {
126 Report::MessageF(Report::kBailout, Script::Handle(function_.script()),
127 function_.token_pos(), Report::AtLocation,
128 "%s Bailout in %s: %s", origin,
129 String::Handle(function_.name()).ToCString(), reason);
130 UNREACHABLE();
131}
132
133kernel::ScopeBuildingResult* ParsedFunction::EnsureKernelScopes() {
134 if (kernel_scopes_ == NULL) {
135 kernel::ScopeBuilder builder(this);
136 kernel_scopes_ = builder.BuildScopes();
137 }
138 return kernel_scopes_;
139}
140
141LocalVariable* ParsedFunction::EnsureExpressionTemp() {
142 if (!has_expression_temp_var()) {
143 LocalVariable* temp =
144 new (Z) LocalVariable(function_.token_pos(), function_.token_pos(),
145 Symbols::ExprTemp(), Object::dynamic_type());
146 ASSERT(temp != NULL);
147 set_expression_temp_var(temp);
148 }
149 ASSERT(has_expression_temp_var());
150 return expression_temp_var();
151}
152
153LocalVariable* ParsedFunction::EnsureEntryPointsTemp() {
154 if (!has_entry_points_temp_var()) {
155 LocalVariable* temp = new (Z)
156 LocalVariable(function_.token_pos(), function_.token_pos(),
157 Symbols::EntryPointsTemp(), Object::dynamic_type());
158 ASSERT(temp != NULL);
159 set_entry_points_temp_var(temp);
160 }
161 ASSERT(has_entry_points_temp_var());
162 return entry_points_temp_var();
163}
164
165void ParsedFunction::EnsureFinallyReturnTemp(bool is_async) {
166 if (!has_finally_return_temp_var()) {
167 LocalVariable* temp =
168 new (Z) LocalVariable(function_.token_pos(), function_.token_pos(),
169 Symbols::FinallyRetVal(), Object::dynamic_type());
170 ASSERT(temp != NULL);
171 temp->set_is_final();
172 if (is_async) {
173 temp->set_is_captured();
174 }
175 set_finally_return_temp_var(temp);
176 }
177 ASSERT(has_finally_return_temp_var());
178}
179
180void ParsedFunction::SetRegExpCompileData(
181 RegExpCompileData* regexp_compile_data) {
182 ASSERT(regexp_compile_data_ == NULL);
183 ASSERT(regexp_compile_data != NULL);
184 regexp_compile_data_ = regexp_compile_data;
185}
186
187void ParsedFunction::AllocateVariables() {
188 ASSERT(!function().IsIrregexpFunction());
189 LocalScope* scope = this->scope();
190 const intptr_t num_fixed_params = function().num_fixed_parameters();
191 const intptr_t num_opt_params = function().NumOptionalParameters();
192 const intptr_t num_params = num_fixed_params + num_opt_params;
193
194 // Before we start allocating indices to variables, we'll setup the
195 // parameters array, which can be used to access the raw parameters (i.e. not
196 // the potentially variables which are in the context)
197
198 raw_parameters_ = new (Z) ZoneGrowableArray<LocalVariable*>(Z, num_params);
199 for (intptr_t param = 0; param < num_params; ++param) {
200 LocalVariable* variable = ParameterVariable(param);
201 LocalVariable* raw_parameter = variable;
202 if (variable->is_captured()) {
203 String& tmp = String::ZoneHandle(Z);
204 tmp = Symbols::FromConcat(T, Symbols::OriginalParam(), variable->name());
205
206 RELEASE_ASSERT(scope->LocalLookupVariable(tmp) == NULL);
207 raw_parameter = new LocalVariable(
208 variable->declaration_token_pos(), variable->token_pos(), tmp,
209 variable->type(), variable->parameter_type(),
210 variable->parameter_value());
211 if (variable->is_explicit_covariant_parameter()) {
212 raw_parameter->set_is_explicit_covariant_parameter();
213 }
214 raw_parameter->set_type_check_mode(variable->type_check_mode());
215 if (function().HasOptionalParameters()) {
216 bool ok = scope->AddVariable(raw_parameter);
217 ASSERT(ok);
218
219 // Currently our optimizer cannot prove liveness of variables properly
220 // when a function has try/catch. It therefore makes the conservative
221 // estimate that all [LocalVariable]s in the frame are live and spills
222 // them before call sites (in some shape or form).
223 //
224 // Since we are guaranteed to not need that, we tell the try/catch
225 // sync moves mechanism not to care about this variable.
226 //
227 // Receiver (this variable) is an exception from this rule because
228 // it is immutable and we don't reload captured it from the context but
229 // instead use raw_parameter to access it. This means we must still
230 // consider it when emitting the catch entry moves.
231 const bool is_receiver_var =
232 function().HasThisParameter() && receiver_var_ == variable;
233 if (!is_receiver_var) {
234 raw_parameter->set_is_captured_parameter(true);
235 }
236
237 } else {
238 raw_parameter->set_index(
239 VariableIndex(function().NumParameters() - param));
240 }
241 }
242 raw_parameters_->Add(raw_parameter);
243 }
244 if (function_type_arguments_ != NULL) {
245 LocalVariable* raw_type_args_parameter = function_type_arguments_;
246 if (function_type_arguments_->is_captured()) {
247 String& tmp = String::ZoneHandle(Z);
248 tmp = Symbols::FromConcat(T, Symbols::OriginalParam(),
249 function_type_arguments_->name());
250
251 ASSERT(scope->LocalLookupVariable(tmp) == NULL);
252 raw_type_args_parameter =
253 new LocalVariable(raw_type_args_parameter->declaration_token_pos(),
254 raw_type_args_parameter->token_pos(), tmp,
255 raw_type_args_parameter->type());
256 bool ok = scope->AddVariable(raw_type_args_parameter);
257 ASSERT(ok);
258 }
259 raw_type_arguments_var_ = raw_type_args_parameter;
260 }
261
262 // The copy parameters implementation will still write to local variables
263 // which we assign indices as with the old CopyParams implementation.
264 VariableIndex parameter_index_start;
265 VariableIndex reamining_local_variables_start;
266 {
267 // Compute start indices to parameters and locals, and the number of
268 // parameters to copy.
269 if (num_opt_params == 0) {
270 parameter_index_start = first_parameter_index_ =
271 VariableIndex(num_params);
272 reamining_local_variables_start = VariableIndex(0);
273 } else {
274 parameter_index_start = first_parameter_index_ = VariableIndex(0);
275 reamining_local_variables_start = VariableIndex(-num_params);
276 }
277 }
278
279 if (function_type_arguments_ != NULL && num_opt_params > 0) {
280 reamining_local_variables_start =
281 VariableIndex(reamining_local_variables_start.value() - 1);
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 first_local_index =
288 VariableIndex(parameter_index_start.value() > 0 ? 0 : -num_params);
289 VariableIndex next_free_index = scope->AllocateVariables(
290 parameter_index_start, num_params, first_local_index, NULL,
291 &found_captured_variables);
292
293 num_stack_locals_ = -next_free_index.value();
294}
295
296void ParsedFunction::AllocateIrregexpVariables(intptr_t num_stack_locals) {
297 ASSERT(function().IsIrregexpFunction());
298 ASSERT(function().NumOptionalParameters() == 0);
299 const intptr_t num_params = function().num_fixed_parameters();
300 ASSERT(num_params == RegExpMacroAssembler::kParamCount);
301 // Compute start indices to parameters and locals, and the number of
302 // parameters to copy.
303 first_parameter_index_ = VariableIndex(num_params);
304
305 // Frame indices are relative to the frame pointer and are decreasing.
306 num_stack_locals_ = num_stack_locals;
307}
308
309void ParsedFunction::AllocateBytecodeVariables(intptr_t num_stack_locals) {
310 ASSERT(!function().IsIrregexpFunction());
311 first_parameter_index_ = VariableIndex(function().num_fixed_parameters());
312 num_stack_locals_ = num_stack_locals;
313}
314
315void ParsedFunction::SetCovariantParameters(
316 const BitVector* covariant_parameters) {
317 ASSERT(covariant_parameters_ == nullptr);
318 ASSERT(covariant_parameters->length() == function_.NumParameters());
319 covariant_parameters_ = covariant_parameters;
320}
321
322void ParsedFunction::SetGenericCovariantImplParameters(
323 const BitVector* generic_covariant_impl_parameters) {
324 ASSERT(generic_covariant_impl_parameters_ == nullptr);
325 ASSERT(generic_covariant_impl_parameters->length() ==
326 function_.NumParameters());
327 generic_covariant_impl_parameters_ = generic_covariant_impl_parameters;
328}
329
330bool ParsedFunction::IsCovariantParameter(intptr_t i) const {
331 ASSERT(covariant_parameters_ != nullptr);
332 ASSERT((i >= 0) && (i < function_.NumParameters()));
333 return covariant_parameters_->Contains(i);
334}
335
336bool ParsedFunction::IsGenericCovariantImplParameter(intptr_t i) const {
337 ASSERT(generic_covariant_impl_parameters_ != nullptr);
338 ASSERT((i >= 0) && (i < function_.NumParameters()));
339 return generic_covariant_impl_parameters_->Contains(i);
340}
341
342} // namespace dart
343
344#endif // DART_PRECOMPILED_RUNTIME
345