Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart

Issue 2246623002: Delete CPS IR (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013, 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 library dart2js.ir_builder_task;
6
7 import 'package:js_runtime/shared/embedded_names.dart'
8 show JsBuiltin, JsGetName;
9
10 import '../closure.dart' as closure;
11 import '../common.dart';
12 import '../common/names.dart' show Identifiers, Names, Selectors;
13 import '../common/tasks.dart' show CompilerTask;
14 import '../compiler.dart' show Compiler;
15 import '../constants/expressions.dart';
16 import '../constants/values.dart' show ConstantValue;
17 import '../constants/values.dart';
18 import '../dart_types.dart';
19 import '../elements/elements.dart';
20 import '../elements/modelx.dart' show ConstructorBodyElementX;
21 import '../io/source_information.dart';
22 import '../js/js.dart' as js show js, Template, Expression, Name;
23 import '../js_backend/backend_helpers.dart' show BackendHelpers;
24 import '../js_backend/js_backend.dart'
25 show JavaScriptBackend, SyntheticConstantKind;
26 import '../native/native.dart' show NativeBehavior, HasCapturedPlaceholders;
27 import '../resolution/operators.dart' as op;
28 import '../resolution/semantic_visitor.dart';
29 import '../resolution/tree_elements.dart' show TreeElements;
30 import '../ssa/types.dart' show TypeMaskFactory;
31 import '../tree/tree.dart' as ast;
32 import '../types/types.dart' show TypeMask;
33 import '../universe/call_structure.dart' show CallStructure;
34 import '../universe/selector.dart' show Selector;
35 import '../util/util.dart';
36 import 'cps_ir_builder.dart';
37 import 'cps_ir_nodes.dart' as ir;
38 import 'type_mask_system.dart' show TypeMaskSystem;
39 // TODO(karlklose): remove.
40
41 typedef void IrBuilderCallback(Element element, ir.FunctionDefinition irNode);
42
43 class ExplicitReceiverParameter implements Local {
44 final ExecutableElement executableContext;
45
46 ExplicitReceiverParameter(this.executableContext);
47
48 String get name => 'receiver';
49 String toString() => 'ExplicitReceiverParameter($executableContext)';
50 }
51
52 /// This task provides the interface to build IR nodes from [ast.Node]s, which
53 /// is used from the [CpsFunctionCompiler] to generate code.
54 ///
55 /// This class is mainly there to correctly measure how long building the IR
56 /// takes.
57 class IrBuilderTask extends CompilerTask {
58 final SourceInformationStrategy sourceInformationStrategy;
59 final Compiler compiler;
60
61 String bailoutMessage = null;
62
63 /// If not null, this function will be called with for each
64 /// [ir.FunctionDefinition] node that has been built.
65 IrBuilderCallback builderCallback;
66
67 IrBuilderTask(Compiler compiler, this.sourceInformationStrategy,
68 [this.builderCallback])
69 : compiler = compiler,
70 super(compiler.measurer);
71
72 String get name => 'CPS builder';
73
74 ir.FunctionDefinition buildNode(
75 AstElement element, TypeMaskSystem typeMaskSystem) {
76 return measure(() {
77 bailoutMessage = null;
78
79 ResolvedAst resolvedAst = element.resolvedAst;
80 element = element.implementation;
81 return compiler.reporter.withCurrentElement(element, () {
82 SourceInformationBuilder sourceInformationBuilder =
83 sourceInformationStrategy.createBuilderForContext(resolvedAst);
84
85 IrBuilderVisitor builder = new IrBuilderVisitor(
86 resolvedAst, compiler, sourceInformationBuilder, typeMaskSystem);
87 ir.FunctionDefinition irNode = builder.buildExecutable(element);
88 if (irNode == null) {
89 bailoutMessage = builder.bailoutMessage;
90 } else if (builderCallback != null) {
91 builderCallback(element, irNode);
92 }
93 return irNode;
94 });
95 });
96 }
97 }
98
99 /// Translates the frontend AST of a method to its CPS IR.
100 ///
101 /// The visitor has an [IrBuilder] which contains an IR fragment to build upon
102 /// and the current reaching definition of local variables.
103 ///
104 /// Visiting a statement or expression extends the IR builder's fragment.
105 /// For expressions, the primitive holding the resulting value is returned.
106 /// For statements, `null` is returned.
107 // TODO(johnniwinther): Implement [SemanticDeclVisitor].
108 class IrBuilderVisitor extends ast.Visitor<ir.Primitive>
109 with
110 IrBuilderMixin<ast.Node>,
111 SemanticSendResolvedMixin<ir.Primitive, dynamic>,
112 ErrorBulkMixin<ir.Primitive, dynamic>,
113 BaseImplementationOfStaticsMixin<ir.Primitive, dynamic>,
114 BaseImplementationOfLocalsMixin<ir.Primitive, dynamic>,
115 BaseImplementationOfDynamicsMixin<ir.Primitive, dynamic>,
116 BaseImplementationOfConstantsMixin<ir.Primitive, dynamic>,
117 BaseImplementationOfNewMixin<ir.Primitive, dynamic>,
118 BaseImplementationOfCompoundsMixin<ir.Primitive, dynamic>,
119 BaseImplementationOfSetIfNullsMixin<ir.Primitive, dynamic>,
120 BaseImplementationOfIndexCompoundsMixin<ir.Primitive, dynamic>,
121 BaseImplementationOfSuperIndexSetIfNullMixin<ir.Primitive, dynamic>
122 implements SemanticSendVisitor<ir.Primitive, dynamic> {
123 final ResolvedAst resolvedAst;
124 final Compiler compiler;
125 final SourceInformationBuilder sourceInformationBuilder;
126 final TypeMaskSystem typeMaskSystem;
127
128 /// A map from try statements in the source to analysis information about
129 /// them.
130 ///
131 /// The analysis information includes the set of variables that must be
132 /// copied into [ir.MutableVariable]s on entry to the try and copied out on
133 /// exit.
134 Map<ast.Node, TryStatementInfo> tryStatements = null;
135
136 // In SSA terms, join-point continuation parameters are the phis and the
137 // continuation invocation arguments are the corresponding phi inputs. To
138 // support name introduction and renaming for source level variables, we use
139 // nested (delimited) visitors for constructing subparts of the IR that will
140 // need renaming. Each source variable is assigned an index.
141 //
142 // Each nested visitor maintains a list of free variable uses in the body.
143 // These are implemented as a list of parameters, each with their own use
144 // list of references. When the delimited subexpression is plugged into the
145 // surrounding context, the free occurrences can be captured or become free
146 // occurrences in the next outer delimited subexpression.
147 //
148 // Each nested visitor maintains a list that maps indexes of variables
149 // assigned in the delimited subexpression to their reaching definition ---
150 // that is, the definition in effect at the hole in 'current'. These are
151 // used to determine if a join-point continuation needs to be passed
152 // arguments, and what the arguments are.
153
154 /// Construct a top-level visitor.
155 IrBuilderVisitor(this.resolvedAst, this.compiler,
156 this.sourceInformationBuilder, this.typeMaskSystem);
157
158 TreeElements get elements => resolvedAst.elements;
159
160 JavaScriptBackend get backend => compiler.backend;
161 BackendHelpers get helpers => backend.helpers;
162 DiagnosticReporter get reporter => compiler.reporter;
163
164 String bailoutMessage = null;
165
166 ir.Primitive visit(ast.Node node) => node.accept(this);
167
168 @override
169 ir.Primitive apply(ast.Node node, _) => node.accept(this);
170
171 SemanticSendVisitor get sendVisitor => this;
172
173 /// Result of closure conversion for the current body of code.
174 ///
175 /// Will be initialized upon entering the body of a function.
176 /// It is computed by the [ClosureTranslator].
177 closure.ClosureClassMap closureClassMap;
178
179 /// If [node] has declarations for variables that should be boxed,
180 /// returns a [ClosureScope] naming a box to create, and enumerating the
181 /// variables that should be stored in the box.
182 ///
183 /// Also see [ClosureScope].
184 ClosureScope getClosureScopeForNode(ast.Node node) {
185 // We translate a ClosureScope from closure.dart into IR builder's variant
186 // because the IR builder should not depend on the synthetic elements
187 // created in closure.dart.
188 return new ClosureScope(closureClassMap.capturingScopes[node]);
189 }
190
191 /// Returns the [ClosureScope] for any function, possibly different from the
192 /// one currently being built.
193 ClosureScope getClosureScopeForFunction(FunctionElement function) {
194 closure.ClosureClassMap map = compiler.closureToClassMapper
195 .computeClosureToClassMapping(function.resolvedAst);
196 return new ClosureScope(map.capturingScopes[function.node]);
197 }
198
199 /// If the current function is a nested function with free variables (or a
200 /// captured reference to `this`), returns a [ClosureEnvironment]
201 /// indicating how to access these.
202 ClosureEnvironment getClosureEnvironment() {
203 return new ClosureEnvironment(closureClassMap);
204 }
205
206 IrBuilder getBuilderFor(Element element) {
207 return new IrBuilder(
208 new GlobalProgramInformation(compiler), backend.constants, element);
209 }
210
211 /// Builds the [ir.FunctionDefinition] for an executable element. In case the
212 /// function uses features that cannot be expressed in the IR, this element
213 /// returns `null`.
214 ir.FunctionDefinition buildExecutable(ExecutableElement element) {
215 return nullIfGiveup(() {
216 ir.FunctionDefinition root;
217 switch (element.kind) {
218 case ElementKind.GENERATIVE_CONSTRUCTOR:
219 root = buildConstructor(element);
220 break;
221
222 case ElementKind.GENERATIVE_CONSTRUCTOR_BODY:
223 root = buildConstructorBody(element);
224 break;
225
226 case ElementKind.FACTORY_CONSTRUCTOR:
227 case ElementKind.FUNCTION:
228 case ElementKind.GETTER:
229 case ElementKind.SETTER:
230 root = buildFunction(element);
231 break;
232
233 case ElementKind.FIELD:
234 if (Elements.isStaticOrTopLevel(element)) {
235 root = buildStaticFieldInitializer(element);
236 } else {
237 // Instance field initializers are inlined in the constructor,
238 // so we shouldn't need to build anything here.
239 // TODO(asgerf): But what should we return?
240 return null;
241 }
242 break;
243
244 default:
245 reporter.internalError(element, "Unexpected element type $element");
246 }
247 return root;
248 });
249 }
250
251 /// Loads the type variables for all super classes of [superClass] into the
252 /// IR builder's environment with their corresponding values.
253 ///
254 /// The type variables for [currentClass] must already be in the IR builder's
255 /// environment.
256 ///
257 /// Type variables are stored as [TypeVariableLocal] in the environment.
258 ///
259 /// This ensures that access to type variables mentioned inside the
260 /// constructors and initializers will happen through the local environment
261 /// instead of using 'this'.
262 void loadTypeVariablesForSuperClasses(ClassElement currentClass) {
263 if (currentClass.isObject) return;
264 loadTypeVariablesForType(currentClass.supertype);
265 if (currentClass is MixinApplicationElement) {
266 loadTypeVariablesForType(currentClass.mixinType);
267 }
268 }
269
270 /// Loads all type variables for [type] and all of its super classes into
271 /// the environment. All type variables mentioned in [type] must already
272 /// be in the environment.
273 void loadTypeVariablesForType(InterfaceType type) {
274 ClassElement clazz = type.element;
275 assert(clazz.typeVariables.length == type.typeArguments.length);
276 for (int i = 0; i < clazz.typeVariables.length; ++i) {
277 irBuilder.declareTypeVariable(
278 clazz.typeVariables[i], type.typeArguments[i]);
279 }
280 loadTypeVariablesForSuperClasses(clazz);
281 }
282
283 /// Returns the constructor body associated with the given constructor or
284 /// creates a new constructor body, if none can be found.
285 ///
286 /// Returns `null` if the constructor does not have a body.
287 ConstructorBodyElement getConstructorBody(FunctionElement constructor) {
288 // TODO(asgerf): This is largely inherited from the SSA builder.
289 // The ConstructorBodyElement has an invalid function signature, but we
290 // cannot add a BoxLocal as parameter, because BoxLocal is not an element.
291 // Instead of forging ParameterElements to forge a FunctionSignature, we
292 // need a way to create backend methods without creating more fake elements.
293 assert(constructor.isGenerativeConstructor);
294 assert(constructor.isImplementation);
295 if (constructor.isSynthesized) return null;
296 ResolvedAst resolvedAst = constructor.resolvedAst;
297 ast.FunctionExpression node = constructor.node;
298 // If we know the body doesn't have any code, we don't generate it.
299 if (!node.hasBody) return null;
300 if (node.hasEmptyBody) return null;
301 ClassElement classElement = constructor.enclosingClass;
302 ConstructorBodyElement bodyElement;
303 classElement.forEachBackendMember((Element backendMember) {
304 if (backendMember.isGenerativeConstructorBody) {
305 ConstructorBodyElement body = backendMember;
306 if (body.constructor == constructor) {
307 bodyElement = backendMember;
308 }
309 }
310 });
311 if (bodyElement == null) {
312 bodyElement = new ConstructorBodyElementX(resolvedAst, constructor);
313 classElement.addBackendMember(bodyElement);
314
315 if (constructor.isPatch) {
316 // Create origin body element for patched constructors.
317 ConstructorBodyElementX patch = bodyElement;
318 ConstructorBodyElementX origin =
319 new ConstructorBodyElementX(resolvedAst, constructor.origin);
320 origin.applyPatch(patch);
321 classElement.origin.addBackendMember(bodyElement.origin);
322 }
323 }
324 assert(bodyElement.isGenerativeConstructorBody);
325 return bodyElement;
326 }
327
328 /// The list of parameters to send from the generative constructor
329 /// to the generative constructor body.
330 ///
331 /// Boxed parameters are not in the list, instead, a [BoxLocal] is passed
332 /// containing the boxed parameters.
333 ///
334 /// For example, given the following constructor,
335 ///
336 /// Foo(x, y) : field = (() => ++x) { print(x + y) }
337 ///
338 /// the argument `x` would be replaced by a [BoxLocal]:
339 ///
340 /// Foo_body(box0, y) { print(box0.x + y) }
341 ///
342 List<Local> getConstructorBodyParameters(ConstructorBodyElement body) {
343 List<Local> parameters = <Local>[];
344 ClosureScope scope = getClosureScopeForFunction(body.constructor);
345 if (scope != null) {
346 parameters.add(scope.box);
347 }
348 body.functionSignature.orderedForEachParameter((ParameterElement param) {
349 if (scope != null && scope.capturedVariables.containsKey(param)) {
350 // Do not pass this parameter; the box will carry its value.
351 } else {
352 parameters.add(param);
353 }
354 });
355 return parameters;
356 }
357
358 /// Builds the IR for a given constructor.
359 ///
360 /// 1. Computes the type held in all own or "inherited" type variables.
361 /// 2. Evaluates all own or inherited field initializers.
362 /// 3. Creates the object and assigns its fields and runtime type.
363 /// 4. Calls constructor body and super constructor bodies.
364 /// 5. Returns the created object.
365 ir.FunctionDefinition buildConstructor(ConstructorElement constructor) {
366 // TODO(asgerf): Optimization: If constructor is redirecting, then just
367 // evaluate arguments and call the target constructor.
368 constructor = constructor.implementation;
369 ClassElement classElement = constructor.enclosingClass.implementation;
370
371 IrBuilder builder = getBuilderFor(constructor);
372
373 final bool requiresTypeInformation =
374 builder.program.requiresRuntimeTypesFor(classElement);
375
376 return withBuilder(builder, () {
377 // Setup parameters and create a box if anything is captured.
378 List<Local> parameters = <Local>[];
379 if (constructor.isGenerativeConstructor &&
380 backend.isNativeOrExtendsNative(classElement)) {
381 parameters.add(new ExplicitReceiverParameter(constructor));
382 }
383 constructor.functionSignature
384 .orderedForEachParameter((ParameterElement p) => parameters.add(p));
385
386 int firstTypeArgumentParameterIndex;
387
388 // If instances of the class may need runtime type information, we add a
389 // synthetic parameter for each type parameter.
390 if (requiresTypeInformation) {
391 firstTypeArgumentParameterIndex = parameters.length;
392 classElement.typeVariables.forEach((TypeVariableType variable) {
393 parameters.add(new closure.TypeVariableLocal(variable, constructor));
394 });
395 } else {
396 classElement.typeVariables.forEach((TypeVariableType variable) {
397 irBuilder.declareTypeVariable(variable, const DynamicType());
398 });
399 }
400
401 // Create IR parameters and setup the environment.
402 List<ir.Parameter> irParameters = builder.buildFunctionHeader(parameters,
403 closureScope: getClosureScopeForFunction(constructor));
404
405 // Create a list of the values of all type argument parameters, if any.
406 ir.Primitive typeInformation;
407 if (requiresTypeInformation) {
408 typeInformation = new ir.TypeExpression(
409 ir.TypeExpressionKind.INSTANCE,
410 classElement.thisType,
411 irParameters.sublist(firstTypeArgumentParameterIndex));
412 irBuilder.add(new ir.LetPrim(typeInformation));
413 } else {
414 typeInformation = null;
415 }
416
417 // -- Load values for type variables declared on super classes --
418 // Field initializers for super classes can reference these, so they
419 // must be available before evaluating field initializers.
420 // This could be interleaved with field initialization, but we choose do
421 // get it out of the way here to avoid complications with mixins.
422 loadTypeVariablesForSuperClasses(classElement);
423
424 /// Maps each field from this class or a superclass to its initial value.
425 Map<FieldElement, ir.Primitive> fieldValues =
426 <FieldElement, ir.Primitive>{};
427
428 // -- Evaluate field initializers ---
429 // Evaluate field initializers in constructor and super constructors.
430 List<ConstructorElement> constructorList = <ConstructorElement>[];
431 evaluateConstructorFieldInitializers(
432 constructor, constructorList, fieldValues);
433
434 // All parameters in all constructors are now bound in the environment.
435 // BoxLocals for captured parameters are also in the environment.
436 // The initial value of all fields are now bound in [fieldValues].
437
438 // --- Create the object ---
439 // Get the initial field values in the canonical order.
440 List<ir.Primitive> instanceArguments = <ir.Primitive>[];
441 List<FieldElement> fields = <FieldElement>[];
442 classElement.forEachInstanceField((ClassElement c, FieldElement field) {
443 ir.Primitive value = fieldValues[field];
444 if (value != null) {
445 fields.add(field);
446 instanceArguments.add(value);
447 } else {
448 assert(backend.isNativeOrExtendsNative(c));
449 // Native fields are initialized elsewhere.
450 }
451 }, includeSuperAndInjectedMembers: true);
452
453 ir.Primitive instance;
454 if (constructor.isGenerativeConstructor &&
455 backend.isNativeOrExtendsNative(classElement)) {
456 instance = irParameters.first;
457 instance.type =
458 new TypeMask.exact(classElement, typeMaskSystem.classWorld);
459 irBuilder.addPrimitive(new ir.ReceiverCheck.nullCheck(
460 instance, Selectors.toString_, null));
461 for (int i = 0; i < fields.length; i++) {
462 irBuilder.addPrimitive(
463 new ir.SetField(instance, fields[i], instanceArguments[i]));
464 }
465 } else {
466 instance = new ir.CreateInstance(
467 classElement,
468 instanceArguments,
469 typeInformation,
470 constructor.hasNode
471 ? sourceInformationBuilder.buildCreate(constructor.node)
472 // TODO(johnniwinther): Provide source information for creation
473 // through synthetic constructors.
474 : null);
475 irBuilder.add(new ir.LetPrim(instance));
476 }
477
478 // --- Call constructor bodies ---
479 for (ConstructorElement target in constructorList) {
480 ConstructorBodyElement bodyElement = getConstructorBody(target);
481 if (bodyElement == null) continue; // Skip if constructor has no body.
482 List<ir.Primitive> bodyArguments = <ir.Primitive>[];
483 for (Local param in getConstructorBodyParameters(bodyElement)) {
484 bodyArguments.add(irBuilder.environment.lookup(param));
485 }
486 Selector selector = new Selector.call(
487 target.memberName, new CallStructure(bodyArguments.length));
488 irBuilder.addPrimitive(new ir.InvokeMethodDirectly(
489 instance, bodyElement, selector, bodyArguments, null));
490 }
491
492 // --- step 4: return the created object ----
493 irBuilder.buildReturn(
494 value: instance,
495 sourceInformation:
496 sourceInformationBuilder.buildImplicitReturn(constructor));
497
498 return irBuilder.makeFunctionDefinition(
499 sourceInformationBuilder.buildVariableDeclaration());
500 });
501 }
502
503 /// Make a visitor suitable for translating ASTs taken from [context].
504 ///
505 /// Every visitor can only be applied to nodes in one context, because
506 /// the [elements] field is specific to that context.
507 IrBuilderVisitor makeVisitorForContext(AstElement context) {
508 ResolvedAst resolvedAst = context.resolvedAst;
509 return new IrBuilderVisitor(resolvedAst, compiler,
510 sourceInformationBuilder.forContext(resolvedAst), typeMaskSystem);
511 }
512
513 /// Builds the IR for an [expression] taken from a different [context].
514 ///
515 /// Such expressions need to be compiled with a different [sourceFile] and
516 /// [elements] mapping.
517 ir.Primitive inlineExpression(AstElement context, ast.Expression expression) {
518 IrBuilderVisitor visitor = makeVisitorForContext(context);
519 return visitor.withBuilder(irBuilder, () => visitor.visit(expression));
520 }
521
522 /// Evaluate the implicit super call in the given mixin constructor.
523 void forwardSynthesizedMixinConstructor(
524 ConstructorElement constructor,
525 List<ConstructorElement> supers,
526 Map<FieldElement, ir.Primitive> fieldValues) {
527 assert(constructor.enclosingClass.implementation.isMixinApplication);
528 assert(constructor.isSynthesized);
529 ConstructorElement target = constructor.definingConstructor.implementation;
530 // The resolver gives us the exact same FunctionSignature for the two
531 // constructors. The parameters for the synthesized constructor
532 // are already in the environment, so the target constructor's parameters
533 // are also in the environment since their elements are the same.
534 assert(constructor.functionSignature == target.functionSignature);
535 IrBuilderVisitor visitor = makeVisitorForContext(target);
536 visitor.withBuilder(irBuilder, () {
537 visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues);
538 });
539 }
540
541 /// In preparation of inlining (part of) [target], the [arguments] are moved
542 /// into the environment bindings for the corresponding parameters.
543 ///
544 /// Defaults for optional arguments are evaluated in order to ensure
545 /// all parameters are available in the environment.
546 void loadArguments(ConstructorElement target, CallStructure call,
547 List<ir.Primitive> arguments) {
548 assert(target.isImplementation);
549 assert(target.declaration == resolvedAst.element);
550 FunctionSignature signature = target.functionSignature;
551
552 // Establish a scope in case parameters are captured.
553 ClosureScope scope = getClosureScopeForFunction(target);
554 irBuilder.enterScope(scope);
555
556 // Load required parameters
557 int index = 0;
558 signature.forEachRequiredParameter((ParameterElement param) {
559 irBuilder.declareLocalVariable(param, initialValue: arguments[index]);
560 index++;
561 });
562
563 // Load optional parameters, evaluating default values for omitted ones.
564 signature.forEachOptionalParameter((ParameterElement param) {
565 ir.Primitive value;
566 // Load argument if provided.
567 if (signature.optionalParametersAreNamed) {
568 int nameIndex = call.namedArguments.indexOf(param.name);
569 if (nameIndex != -1) {
570 int translatedIndex = call.positionalArgumentCount + nameIndex;
571 value = arguments[translatedIndex];
572 }
573 } else if (index < arguments.length) {
574 value = arguments[index];
575 }
576 // Load default if argument was not provided.
577 if (value == null) {
578 if (param.initializer != null) {
579 value = visit(param.initializer);
580 } else {
581 value = irBuilder.buildNullConstant();
582 }
583 }
584 irBuilder.declareLocalVariable(param, initialValue: value);
585 index++;
586 });
587 }
588
589 /// Evaluates a call to the given constructor from an initializer list.
590 ///
591 /// Calls [loadArguments] and [evaluateConstructorFieldInitializers] in a
592 /// visitor that has the proper [TreeElements] mapping.
593 void evaluateConstructorCallFromInitializer(
594 ConstructorElement target,
595 CallStructure call,
596 List<ir.Primitive> arguments,
597 List<ConstructorElement> supers,
598 Map<FieldElement, ir.Primitive> fieldValues) {
599 IrBuilderVisitor visitor = makeVisitorForContext(target);
600 visitor.withBuilder(irBuilder, () {
601 visitor.loadArguments(target, call, arguments);
602 visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues);
603 });
604 }
605
606 /// Evaluates all field initializers on [constructor] and all constructors
607 /// invoked through `this()` or `super()` ("superconstructors").
608 ///
609 /// The resulting field values will be available in [fieldValues]. The values
610 /// are not stored in any fields.
611 ///
612 /// This procedure assumes that the parameters to [constructor] are available
613 /// in the IR builder's environment.
614 ///
615 /// The parameters to superconstructors are, however, assumed *not* to be in
616 /// the environment, but will be put there by this procedure.
617 ///
618 /// All constructors will be added to [supers], with superconstructors first.
619 void evaluateConstructorFieldInitializers(
620 ConstructorElement constructor,
621 List<ConstructorElement> supers,
622 Map<FieldElement, ir.Primitive> fieldValues) {
623 assert(constructor.isImplementation);
624 assert(constructor.declaration == resolvedAst.element);
625 ClassElement enclosingClass = constructor.enclosingClass.implementation;
626 // Evaluate declaration-site field initializers, unless this constructor
627 // redirects to another using a `this()` initializer. In that case, these
628 // will be initialized by the effective target constructor.
629 if (!constructor.isRedirectingGenerative) {
630 enclosingClass.forEachInstanceField((ClassElement c, FieldElement field) {
631 if (field.initializer != null) {
632 fieldValues[field] = inlineExpression(field, field.initializer);
633 } else {
634 if (backend.isNativeOrExtendsNative(c)) {
635 // Native field is initialized elsewhere.
636 } else {
637 // Fields without an initializer default to null.
638 // This value will be overwritten below if an initializer is found.
639 fieldValues[field] = irBuilder.buildNullConstant();
640 }
641 }
642 });
643 }
644 // If this is a mixin constructor, it does not have its own parameter list
645 // or initializer list. Directly forward to the super constructor.
646 // Note that the declaration-site initializers originating from the
647 // mixed-in class were handled above.
648 if (enclosingClass.isMixinApplication) {
649 forwardSynthesizedMixinConstructor(constructor, supers, fieldValues);
650 return;
651 }
652 // Evaluate initializing parameters, e.g. `Foo(this.x)`.
653 constructor.functionSignature
654 .orderedForEachParameter((ParameterElement parameter) {
655 if (parameter.isInitializingFormal) {
656 InitializingFormalElement fieldParameter = parameter;
657 fieldValues[fieldParameter.fieldElement] =
658 irBuilder.buildLocalGet(parameter);
659 }
660 });
661 // Evaluate constructor initializers, e.g. `Foo() : x = 50`.
662 ast.FunctionExpression node = constructor.node;
663 bool hasConstructorCall = false; // Has this() or super() initializer?
664 if (node != null && node.initializers != null) {
665 for (ast.Node initializer in node.initializers) {
666 if (initializer is ast.SendSet) {
667 // Field initializer.
668 FieldElement field = elements[initializer];
669 fieldValues[field] = visit(initializer.arguments.head);
670 } else if (initializer is ast.Send) {
671 // Super or this initializer.
672 ConstructorElement target = elements[initializer].implementation;
673 Selector selector = elements.getSelector(initializer);
674 List<ir.Primitive> arguments = initializer.arguments.mapToList(visit);
675 evaluateConstructorCallFromInitializer(
676 target, selector.callStructure, arguments, supers, fieldValues);
677 hasConstructorCall = true;
678 } else {
679 reporter.internalError(
680 initializer, "Unexpected initializer type $initializer");
681 }
682 }
683 }
684 // If no super() or this() was found, also call default superconstructor.
685 if (!hasConstructorCall && !enclosingClass.isObject) {
686 ClassElement superClass = enclosingClass.superclass;
687 FunctionElement target = superClass.lookupDefaultConstructor();
688 if (target == null) {
689 reporter.internalError(superClass, "No default constructor available.");
690 }
691 target = target.implementation;
692 evaluateConstructorCallFromInitializer(
693 target, CallStructure.NO_ARGS, const [], supers, fieldValues);
694 }
695 // Add this constructor after the superconstructors.
696 supers.add(constructor);
697 }
698
699 TryBoxedVariables _analyzeTryBoxedVariables(ast.Node node) {
700 TryBoxedVariables variables = new TryBoxedVariables(elements);
701 try {
702 variables.analyze(node);
703 } catch (e) {
704 bailoutMessage = variables.bailoutMessage;
705 rethrow;
706 }
707 return variables;
708 }
709
710 /// Builds the IR for the body of a constructor.
711 ///
712 /// This function is invoked from one or more "factory" constructors built by
713 /// [buildConstructor].
714 ir.FunctionDefinition buildConstructorBody(ConstructorBodyElement body) {
715 ConstructorElement constructor = body.constructor;
716 ast.FunctionExpression node = constructor.node;
717 closureClassMap = compiler.closureToClassMapper
718 .computeClosureToClassMapping(constructor.resolvedAst);
719
720 // We compute variables boxed in mutable variables on entry to each try
721 // block, not including variables captured by a closure (which are boxed
722 // in the heap). This duplicates some of the work of closure conversion
723 // without directly using the results. This duplication is wasteful and
724 // error-prone.
725 // TODO(kmillikin): We should combine closure conversion and try/catch
726 // variable analysis in some way.
727 TryBoxedVariables variables = _analyzeTryBoxedVariables(node);
728 tryStatements = variables.tryStatements;
729 IrBuilder builder = getBuilderFor(body);
730
731 return withBuilder(builder, () {
732 irBuilder.buildConstructorBodyHeader(
733 getConstructorBodyParameters(body), getClosureScopeForNode(node));
734 visit(node.body);
735 return irBuilder.makeFunctionDefinition(
736 sourceInformationBuilder.buildVariableDeclaration());
737 });
738 }
739
740 ir.FunctionDefinition buildFunction(FunctionElement element) {
741 assert(invariant(element, element.isImplementation));
742 ast.FunctionExpression node = element.node;
743
744 assert(!element.isSynthesized);
745 assert(node != null);
746 assert(elements[node] != null);
747
748 closureClassMap = compiler.closureToClassMapper
749 .computeClosureToClassMapping(element.resolvedAst);
750 TryBoxedVariables variables = _analyzeTryBoxedVariables(node);
751 tryStatements = variables.tryStatements;
752 IrBuilder builder = getBuilderFor(element);
753 return withBuilder(
754 builder, () => _makeFunctionBody(builder, element, node));
755 }
756
757 ir.FunctionDefinition buildStaticFieldInitializer(FieldElement element) {
758 if (!backend.constants.lazyStatics.contains(element)) {
759 return null; // Nothing to do.
760 }
761 closureClassMap = compiler.closureToClassMapper
762 .computeClosureToClassMapping(element.resolvedAst);
763 IrBuilder builder = getBuilderFor(element);
764 return withBuilder(builder, () {
765 irBuilder.buildFunctionHeader(<Local>[]);
766 ir.Primitive initialValue = visit(element.initializer);
767 ast.VariableDefinitions node = element.node;
768 ast.SendSet sendSet = node.definitions.nodes.head;
769 irBuilder.buildReturn(
770 value: initialValue,
771 sourceInformation:
772 sourceInformationBuilder.buildReturn(sendSet.assignmentOperator));
773 return irBuilder.makeFunctionDefinition(
774 sourceInformationBuilder.buildVariableDeclaration());
775 });
776 }
777
778 /// Builds the IR for a constant taken from a different [context].
779 ///
780 /// Such constants need to be compiled with a different [sourceFile] and
781 /// [elements] mapping.
782 ir.Primitive inlineConstant(AstElement context, ast.Expression exp) {
783 IrBuilderVisitor visitor = makeVisitorForContext(context);
784 return visitor.withBuilder(irBuilder, () => visitor.translateConstant(exp));
785 }
786
787 /// Creates a primitive for the default value of [parameter].
788 ir.Primitive translateDefaultValue(ParameterElement parameter) {
789 if (parameter.initializer == null ||
790 // TODO(sigmund): JS doesn't support default values, so this should be
791 // reported as an error earlier (Issue #25759).
792 backend.isJsInterop(parameter.functionDeclaration)) {
793 return irBuilder.buildNullConstant();
794 } else {
795 return inlineConstant(parameter.executableContext, parameter.initializer);
796 }
797 }
798
799 /// Normalizes the argument list of a static invocation.
800 ///
801 /// A static invocation is one where the target is known. The argument list
802 /// [arguments] is normalized by adding default values for optional arguments
803 /// that are not passed, and by sorting it in place so that named arguments
804 /// appear in a canonical order. A [CallStructure] reflecting this order
805 /// is returned.
806 CallStructure normalizeStaticArguments(CallStructure callStructure,
807 FunctionElement target, List<ir.Primitive> arguments) {
808 target = target.implementation;
809 FunctionSignature signature = target.functionSignature;
810 if (!signature.optionalParametersAreNamed &&
811 signature.parameterCount == arguments.length) {
812 return callStructure;
813 }
814
815 if (!signature.optionalParametersAreNamed) {
816 int i = signature.requiredParameterCount;
817 signature.forEachOptionalParameter((ParameterElement element) {
818 if (i < callStructure.positionalArgumentCount) {
819 ++i;
820 } else {
821 arguments.add(translateDefaultValue(element));
822 }
823 });
824 return new CallStructure(signature.parameterCount);
825 }
826
827 int offset = signature.requiredParameterCount;
828 List<ir.Primitive> namedArguments = arguments.sublist(offset);
829 arguments.length = offset;
830 List<String> normalizedNames = <String>[];
831 // Iterate over the optional parameters of the signature, and try to
832 // find them in the callStructure's named arguments. If found, we use the
833 // value in the temporary list, otherwise the default value.
834 signature.orderedOptionalParameters.forEach((ParameterElement element) {
835 int nameIndex = callStructure.namedArguments.indexOf(element.name);
836 arguments.add(nameIndex == -1
837 ? translateDefaultValue(element)
838 : namedArguments[nameIndex]);
839 normalizedNames.add(element.name);
840 });
841 return new CallStructure(signature.parameterCount, normalizedNames);
842 }
843
844 /// Normalizes the argument list of a dynamic invocation.
845 ///
846 /// A dynamic invocation is one where the target is not known. The argument
847 /// list [arguments] is normalized by sorting it in place so that the named
848 /// arguments appear in a canonical order. A [CallStructure] reflecting this
849 /// order is returned.
850 CallStructure normalizeDynamicArguments(
851 CallStructure callStructure, List<ir.Primitive> arguments) {
852 assert(arguments.length == callStructure.argumentCount);
853 if (callStructure.namedArguments.isEmpty) return callStructure;
854 int destinationIndex = callStructure.positionalArgumentCount;
855 List<ir.Primitive> namedArguments = arguments.sublist(destinationIndex);
856 for (String argName in callStructure.getOrderedNamedArguments()) {
857 int sourceIndex = callStructure.namedArguments.indexOf(argName);
858 arguments[destinationIndex++] = namedArguments[sourceIndex];
859 }
860 return new CallStructure(
861 callStructure.argumentCount, callStructure.getOrderedNamedArguments());
862 }
863
864 /// Read the value of [field].
865 ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src) {
866 ConstantValue constant = getConstantForVariable(field);
867 if (constant != null && !field.isAssignable) {
868 typeMaskSystem.associateConstantValueWithElement(constant, field);
869 return irBuilder.buildConstant(constant, sourceInformation: src);
870 } else if (backend.constants.lazyStatics.contains(field)) {
871 return irBuilder.addPrimitive(new ir.GetLazyStatic(field,
872 sourceInformation: src,
873 isFinal: compiler.world.fieldNeverChanges(field)));
874 } else {
875 return irBuilder.addPrimitive(new ir.GetStatic(field,
876 sourceInformation: src,
877 isFinal: compiler.world.fieldNeverChanges(field)));
878 }
879 }
880
881 ir.FunctionDefinition _makeFunctionBody(
882 IrBuilder builder, FunctionElement element, ast.FunctionExpression node) {
883 FunctionSignature signature = element.functionSignature;
884 List<Local> parameters = <Local>[];
885 signature.orderedForEachParameter(
886 (LocalParameterElement e) => parameters.add(e));
887
888 bool requiresRuntimeTypes = false;
889 if (element.isFactoryConstructor) {
890 requiresRuntimeTypes =
891 builder.program.requiresRuntimeTypesFor(element.enclosingElement);
892 if (requiresRuntimeTypes) {
893 // Type arguments are passed in as extra parameters.
894 for (DartType typeVariable in element.enclosingClass.typeVariables) {
895 parameters.add(new closure.TypeVariableLocal(typeVariable, element));
896 }
897 }
898 }
899
900 irBuilder.buildFunctionHeader(parameters,
901 closureScope: getClosureScopeForNode(node),
902 env: getClosureEnvironment());
903
904 if (element == helpers.jsArrayTypedConstructor) {
905 // Generate a body for JSArray<E>.typed(allocation):
906 //
907 // t1 = setRuntimeTypeInfo(allocation, TypeExpression($E));
908 // return Refinement(t1, <JSArray>);
909 //
910 assert(parameters.length == 1 || parameters.length == 2);
911 ir.Primitive allocation = irBuilder.buildLocalGet(parameters[0]);
912
913 // Only call setRuntimeTypeInfo if JSArray requires the type parameter.
914 if (requiresRuntimeTypes) {
915 assert(parameters.length == 2);
916 closure.TypeVariableLocal typeParameter = parameters[1];
917 ir.Primitive typeArgument =
918 irBuilder.buildTypeVariableAccess(typeParameter.typeVariable);
919
920 ir.Primitive typeInformation = irBuilder.addPrimitive(
921 new ir.TypeExpression(ir.TypeExpressionKind.INSTANCE,
922 element.enclosingClass.thisType, <ir.Primitive>[typeArgument]));
923
924 MethodElement helper = helpers.setRuntimeTypeInfo;
925 CallStructure callStructure = CallStructure.TWO_ARGS;
926 Selector selector = new Selector.call(helper.memberName, callStructure);
927 allocation = irBuilder.buildInvokeStatic(
928 helper,
929 selector,
930 <ir.Primitive>[allocation, typeInformation],
931 sourceInformationBuilder.buildGeneric(node));
932 }
933
934 ir.Primitive refinement = irBuilder.addPrimitive(
935 new ir.Refinement(allocation, typeMaskSystem.arrayType));
936
937 irBuilder.buildReturn(
938 value: refinement,
939 sourceInformation:
940 sourceInformationBuilder.buildImplicitReturn(element));
941 } else {
942 visit(node.body);
943 }
944 return irBuilder.makeFunctionDefinition(
945 sourceInformationBuilder.buildVariableDeclaration());
946 }
947
948 /// Builds the IR for creating an instance of the closure class corresponding
949 /// to the given nested function.
950 closure.ClosureClassElement makeSubFunction(ast.FunctionExpression node) {
951 closure.ClosureClassMap innerMap =
952 compiler.closureToClassMapper.getMappingForNestedFunction(node);
953 closure.ClosureClassElement closureClass = innerMap.closureClassElement;
954 return closureClass;
955 }
956
957 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
958 return irBuilder.buildFunctionExpression(
959 makeSubFunction(node), sourceInformationBuilder.buildCreate(node));
960 }
961
962 visitFunctionDeclaration(ast.FunctionDeclaration node) {
963 LocalFunctionElement element = elements[node.function];
964 Object inner = makeSubFunction(node.function);
965 irBuilder.declareLocalFunction(
966 element, inner, sourceInformationBuilder.buildCreate(node.function));
967 }
968
969 // ## Statements ##
970 visitBlock(ast.Block node) {
971 irBuilder.buildBlock(node.statements.nodes, build);
972 }
973
974 ir.Primitive visitBreakStatement(ast.BreakStatement node) {
975 if (!irBuilder.buildBreak(elements.getTargetOf(node))) {
976 reporter.internalError(node, "'break' target not found");
977 }
978 return null;
979 }
980
981 ir.Primitive visitContinueStatement(ast.ContinueStatement node) {
982 if (!irBuilder.buildContinue(elements.getTargetOf(node))) {
983 reporter.internalError(node, "'continue' target not found");
984 }
985 return null;
986 }
987
988 // Build(EmptyStatement, C) = C
989 ir.Primitive visitEmptyStatement(ast.EmptyStatement node) {
990 assert(irBuilder.isOpen);
991 return null;
992 }
993
994 // Build(ExpressionStatement(e), C) = C'
995 // where (C', _) = Build(e, C)
996 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) {
997 assert(irBuilder.isOpen);
998 if (node.expression is ast.Throw) {
999 // Throw expressions that occur as statements are translated differently
1000 // from ones that occur as subexpressions. This is achieved by peeking
1001 // at statement-level expressions here.
1002 irBuilder.buildThrow(visit(node.expression));
1003 } else {
1004 visit(node.expression);
1005 }
1006 return null;
1007 }
1008
1009 ir.Primitive visitRethrow(ast.Rethrow node) {
1010 assert(irBuilder.isOpen);
1011 irBuilder.buildRethrow();
1012 return null;
1013 }
1014
1015 /// Construct a method that executes the forwarding call to the target
1016 /// constructor. This is only required, if the forwarding factory
1017 /// constructor can potentially be the target of a reflective call, because
1018 /// the builder shortcuts calls to redirecting factories at the call site
1019 /// (see [handleConstructorInvoke]).
1020 visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) {
1021 ConstructorElement targetConstructor =
1022 elements.getRedirectingTargetConstructor(node).implementation;
1023 ConstructorElement redirectingConstructor =
1024 irBuilder.state.currentElement.implementation;
1025 List<ir.Primitive> arguments = <ir.Primitive>[];
1026 FunctionSignature redirectingSignature =
1027 redirectingConstructor.functionSignature;
1028 List<String> namedParameters = <String>[];
1029 redirectingSignature.forEachParameter((ParameterElement parameter) {
1030 arguments.add(irBuilder.environment.lookup(parameter));
1031 if (parameter.isNamed) {
1032 namedParameters.add(parameter.name);
1033 }
1034 });
1035 ClassElement cls = redirectingConstructor.enclosingClass;
1036 InterfaceType targetType =
1037 redirectingConstructor.computeEffectiveTargetType(cls.thisType);
1038 CallStructure callStructure =
1039 new CallStructure(redirectingSignature.parameterCount, namedParameters);
1040 callStructure =
1041 normalizeStaticArguments(callStructure, targetConstructor, arguments);
1042 ir.Primitive instance = irBuilder.buildConstructorInvocation(
1043 targetConstructor,
1044 callStructure,
1045 targetType,
1046 arguments,
1047 sourceInformationBuilder.buildNew(node));
1048 irBuilder.buildReturn(
1049 value: instance,
1050 sourceInformation: sourceInformationBuilder.buildReturn(node));
1051 }
1052
1053 visitFor(ast.For node) {
1054 List<LocalElement> loopVariables = <LocalElement>[];
1055 if (node.initializer is ast.VariableDefinitions) {
1056 ast.VariableDefinitions definitions = node.initializer;
1057 for (ast.Node node in definitions.definitions.nodes) {
1058 LocalElement loopVariable = elements[node];
1059 loopVariables.add(loopVariable);
1060 }
1061 }
1062
1063 JumpTarget target = elements.getTargetDefinition(node);
1064 irBuilder.buildFor(
1065 buildInitializer: subbuild(node.initializer),
1066 buildCondition: subbuild(node.condition),
1067 buildBody: subbuild(node.body),
1068 buildUpdate: subbuildSequence(node.update),
1069 closureScope: getClosureScopeForNode(node),
1070 loopVariables: loopVariables,
1071 target: target);
1072 }
1073
1074 visitIf(ast.If node) {
1075 irBuilder.buildIf(build(node.condition), subbuild(node.thenPart),
1076 subbuild(node.elsePart), sourceInformationBuilder.buildIf(node));
1077 }
1078
1079 visitLabeledStatement(ast.LabeledStatement node) {
1080 ast.Statement body = node.statement;
1081 if (body is ast.Loop) {
1082 visit(body);
1083 } else {
1084 JumpTarget target = elements.getTargetDefinition(body);
1085 irBuilder.buildLabeledStatement(
1086 buildBody: subbuild(body), target: target);
1087 }
1088 }
1089
1090 visitDoWhile(ast.DoWhile node) {
1091 irBuilder.buildDoWhile(
1092 buildBody: subbuild(node.body),
1093 buildCondition: subbuild(node.condition),
1094 target: elements.getTargetDefinition(node),
1095 closureScope: getClosureScopeForNode(node));
1096 }
1097
1098 visitWhile(ast.While node) {
1099 irBuilder.buildWhile(
1100 buildCondition: subbuild(node.condition),
1101 buildBody: subbuild(node.body),
1102 target: elements.getTargetDefinition(node),
1103 closureScope: getClosureScopeForNode(node));
1104 }
1105
1106 visitAsyncForIn(ast.AsyncForIn node) {
1107 // Translate await for into a loop over a StreamIterator. The source
1108 // statement:
1109 //
1110 // await for (<decl> in <stream>) <body>
1111 //
1112 // is translated as if it were:
1113 //
1114 // var iterator = new StreamIterator(<stream>);
1115 // try {
1116 // while (await iterator.hasNext()) {
1117 // <decl> = await iterator.current;
1118 // <body>
1119 // }
1120 // } finally {
1121 // await iterator.cancel();
1122 // }
1123 ir.Primitive stream = visit(node.expression);
1124 ir.Primitive dummyTypeArgument = irBuilder.buildNullConstant();
1125 ConstructorElement constructor = helpers.streamIteratorConstructor;
1126 ir.Primitive iterator = irBuilder.addPrimitive(new ir.InvokeConstructor(
1127 constructor.enclosingClass.thisType,
1128 constructor,
1129 new Selector.callConstructor(constructor.memberName, 1),
1130 <ir.Primitive>[stream, dummyTypeArgument],
1131 sourceInformationBuilder.buildGeneric(node)));
1132
1133 buildTryBody(IrBuilder builder) {
1134 ir.Node buildLoopCondition(IrBuilder builder) {
1135 ir.Primitive moveNext = builder.buildDynamicInvocation(
1136 iterator,
1137 Selectors.moveNext,
1138 elements.getMoveNextTypeMask(node),
1139 <ir.Primitive>[],
1140 sourceInformationBuilder.buildForInMoveNext(node));
1141 return builder.addPrimitive(new ir.Await(moveNext));
1142 }
1143
1144 ir.Node buildLoopBody(IrBuilder builder) {
1145 return withBuilder(builder, () {
1146 ir.Primitive current = irBuilder.buildDynamicInvocation(
1147 iterator,
1148 Selectors.current,
1149 elements.getCurrentTypeMask(node),
1150 <ir.Primitive>[],
1151 sourceInformationBuilder.buildForInCurrent(node));
1152 Element variable = elements.getForInVariable(node);
1153 SourceInformation sourceInformation =
1154 sourceInformationBuilder.buildForInSet(node);
1155 if (Elements.isLocal(variable)) {
1156 if (node.declaredIdentifier.asVariableDefinitions() != null) {
1157 irBuilder.declareLocalVariable(variable);
1158 }
1159 irBuilder.buildLocalVariableSet(
1160 variable, current, sourceInformation);
1161 } else if (Elements.isError(variable) ||
1162 Elements.isMalformed(variable)) {
1163 Selector selector =
1164 new Selector.setter(new Name(variable.name, variable.library));
1165 List<ir.Primitive> args = <ir.Primitive>[current];
1166 // Note the comparison below. It can be the case that an element
1167 // isError and isMalformed.
1168 if (Elements.isError(variable)) {
1169 irBuilder.buildStaticNoSuchMethod(
1170 selector, args, sourceInformation);
1171 } else {
1172 irBuilder.buildErroneousInvocation(
1173 variable, selector, args, sourceInformation);
1174 }
1175 } else if (Elements.isStaticOrTopLevel(variable)) {
1176 if (variable.isField) {
1177 irBuilder.addPrimitive(new ir.SetStatic(variable, current));
1178 } else {
1179 irBuilder.buildStaticSetterSet(
1180 variable, current, sourceInformation);
1181 }
1182 } else {
1183 ir.Primitive receiver = irBuilder.buildThis();
1184 ast.Node identifier = node.declaredIdentifier;
1185 irBuilder.buildDynamicSet(
1186 receiver,
1187 elements.getSelector(identifier),
1188 elements.getTypeMask(identifier),
1189 current,
1190 sourceInformation);
1191 }
1192 visit(node.body);
1193 });
1194 }
1195
1196 builder.buildWhile(
1197 buildCondition: buildLoopCondition,
1198 buildBody: buildLoopBody,
1199 target: elements.getTargetDefinition(node),
1200 closureScope: getClosureScopeForNode(node));
1201 }
1202
1203 ir.Node buildFinallyBody(IrBuilder builder) {
1204 ir.Primitive cancellation = builder.buildDynamicInvocation(
1205 iterator,
1206 Selectors.cancel,
1207 backend.dynamicType,
1208 <ir.Primitive>[],
1209 sourceInformationBuilder.buildGeneric(node));
1210 return builder.addPrimitive(new ir.Await(cancellation));
1211 }
1212
1213 irBuilder.buildTryFinally(
1214 new TryStatementInfo(), buildTryBody, buildFinallyBody);
1215 }
1216
1217 visitAwait(ast.Await node) {
1218 assert(irBuilder.isOpen);
1219 ir.Primitive value = visit(node.expression);
1220 return irBuilder.addPrimitive(new ir.Await(value));
1221 }
1222
1223 visitYield(ast.Yield node) {
1224 assert(irBuilder.isOpen);
1225 ir.Primitive value = visit(node.expression);
1226 return irBuilder.addPrimitive(new ir.Yield(value, node.hasStar));
1227 }
1228
1229 visitSyncForIn(ast.SyncForIn node) {
1230 // [node.declaredIdentifier] can be either an [ast.VariableDefinitions]
1231 // (defining a new local variable) or a send designating some existing
1232 // variable.
1233 ast.Node identifier = node.declaredIdentifier;
1234 ast.VariableDefinitions variableDeclaration =
1235 identifier.asVariableDefinitions();
1236 Element variableElement = elements.getForInVariable(node);
1237 Selector selector = elements.getSelector(identifier);
1238
1239 irBuilder.buildForIn(
1240 buildExpression: subbuild(node.expression),
1241 buildVariableDeclaration: subbuild(variableDeclaration),
1242 variableElement: variableElement,
1243 variableSelector: selector,
1244 variableMask: elements.getTypeMask(identifier),
1245 variableSetSourceInformation:
1246 sourceInformationBuilder.buildForInSet(node),
1247 currentMask: elements.getCurrentTypeMask(node),
1248 currentSourceInformation:
1249 sourceInformationBuilder.buildForInCurrent(node),
1250 moveNextMask: elements.getMoveNextTypeMask(node),
1251 moveNextSourceInformation:
1252 sourceInformationBuilder.buildForInMoveNext(node),
1253 iteratorMask: elements.getIteratorTypeMask(node),
1254 iteratorSourceInformation:
1255 sourceInformationBuilder.buildForInIterator(node),
1256 buildBody: subbuild(node.body),
1257 target: elements.getTargetDefinition(node),
1258 closureScope: getClosureScopeForNode(node));
1259 }
1260
1261 /// If compiling with trusted type annotations, assumes that [value] is
1262 /// now known to be `null` or an instance of [type].
1263 ///
1264 /// This is also where we should add type checks in checked mode, but this
1265 /// is not supported yet.
1266 ir.Primitive checkType(ir.Primitive value, DartType dartType) {
1267 if (!compiler.options.trustTypeAnnotations) return value;
1268 TypeMask type = typeMaskSystem.subtypesOf(dartType).nullable();
1269 return irBuilder.addPrimitive(new ir.Refinement(value, type));
1270 }
1271
1272 ir.Primitive checkTypeVsElement(ir.Primitive value, TypedElement element) {
1273 return checkType(value, element.type);
1274 }
1275
1276 ir.Primitive visitVariableDefinitions(ast.VariableDefinitions node) {
1277 assert(irBuilder.isOpen);
1278 for (ast.Node definition in node.definitions.nodes) {
1279 Element element = elements[definition];
1280 ir.Primitive initialValue;
1281 // Definitions are either SendSets if there is an initializer, or
1282 // Identifiers if there is no initializer.
1283 if (definition is ast.SendSet) {
1284 assert(!definition.arguments.isEmpty);
1285 assert(definition.arguments.tail.isEmpty);
1286 initialValue = visit(definition.arguments.head);
1287 initialValue = checkTypeVsElement(initialValue, element);
1288 } else {
1289 assert(definition is ast.Identifier);
1290 }
1291 irBuilder.declareLocalVariable(element, initialValue: initialValue);
1292 }
1293 return null;
1294 }
1295
1296 static final RegExp nativeRedirectionRegExp =
1297 new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$');
1298
1299 // Build(Return(e), C) = C'[InvokeContinuation(return, x)]
1300 // where (C', x) = Build(e, C)
1301 //
1302 // Return without a subexpression is translated as if it were return null.
1303 visitReturn(ast.Return node) {
1304 assert(irBuilder.isOpen);
1305 SourceInformation source = sourceInformationBuilder.buildReturn(node);
1306 if (node.beginToken.value == 'native') {
1307 FunctionElement function = irBuilder.state.currentElement;
1308 assert(backend.isNative(function));
1309 ast.Node nativeBody = node.expression;
1310 if (nativeBody != null) {
1311 ast.LiteralString jsCode = nativeBody.asLiteralString();
1312 String javaScriptCode = jsCode.dartString.slowToString();
1313 assert(invariant(
1314 nativeBody, !nativeRedirectionRegExp.hasMatch(javaScriptCode),
1315 message: "Deprecated syntax, use @JSName('name') instead."));
1316 assert(invariant(
1317 nativeBody, function.functionSignature.parameterCount == 0,
1318 message: 'native "..." syntax is restricted to '
1319 'functions with zero parameters.'));
1320 irBuilder.buildNativeFunctionBody(function, javaScriptCode,
1321 sourceInformationBuilder.buildForeignCode(node));
1322 } else {
1323 String name = backend.nativeData.getFixedBackendName(function);
1324 irBuilder.buildRedirectingNativeFunctionBody(function, name, source);
1325 }
1326 } else {
1327 irBuilder.buildReturn(
1328 value: build(node.expression), sourceInformation: source);
1329 }
1330 }
1331
1332 visitSwitchStatement(ast.SwitchStatement node) {
1333 // Dart switch cases can be labeled and be the target of continue from
1334 // within the switch. Such cases are 'recursive'. If there are any
1335 // recursive cases, we implement the switch using a pair of switches with
1336 // the second one switching over a state variable in a loop. The first
1337 // switch contains the non-recursive cases, and the second switch contains
1338 // the recursive ones.
1339 //
1340 // For example, for the Dart switch:
1341 //
1342 // switch (E) {
1343 // case 0:
1344 // BODY0;
1345 // break;
1346 // LABEL0: case 1:
1347 // BODY1;
1348 // break;
1349 // case 2:
1350 // BODY2;
1351 // continue LABEL1;
1352 // LABEL1: case 3:
1353 // BODY3;
1354 // continue LABEL0;
1355 // default:
1356 // BODY4;
1357 // }
1358 //
1359 // We translate it as if it were the JavaScript:
1360 //
1361 // var state = -1;
1362 // switch (E) {
1363 // case 0:
1364 // BODY0;
1365 // break;
1366 // case 1:
1367 // state = 0; // Recursive, label ID = 0.
1368 // break;
1369 // case 2:
1370 // BODY2;
1371 // state = 1; // Continue to label ID = 1.
1372 // break;
1373 // case 3:
1374 // state = 1; // Recursive, label ID = 1.
1375 // break;
1376 // default:
1377 // BODY4;
1378 // }
1379 // L: while (state != -1) {
1380 // case 0:
1381 // BODY1;
1382 // break L; // Break from switch becomes break from loop.
1383 // case 1:
1384 // BODY2;
1385 // state = 0; // Continue to label ID = 0.
1386 // break;
1387 // }
1388 assert(irBuilder.isOpen);
1389 // Preprocess: compute a list of cases that are the target of continue.
1390 // These are the so-called 'recursive' cases.
1391 List<JumpTarget> continueTargets = <JumpTarget>[];
1392 List<ast.Node> switchCases = node.cases.nodes.toList();
1393 for (ast.SwitchCase switchCase in switchCases) {
1394 for (ast.Node labelOrCase in switchCase.labelsAndCases) {
1395 if (labelOrCase is ast.Label) {
1396 LabelDefinition definition = elements.getLabelDefinition(labelOrCase);
1397 if (definition != null && definition.isContinueTarget) {
1398 continueTargets.add(definition.target);
1399 }
1400 }
1401 }
1402 }
1403
1404 // If any cases are continue targets, use an anonymous local value to
1405 // implement a state machine. The initial value is -1.
1406 ir.Primitive initial;
1407 int stateIndex;
1408 if (continueTargets.isNotEmpty) {
1409 initial = irBuilder.buildIntegerConstant(-1);
1410 stateIndex = irBuilder.environment.length;
1411 irBuilder.environment.extend(null, initial);
1412 }
1413
1414 // Use a simple switch for the non-recursive cases. A break will go to the
1415 // join-point after the switch. A continue to a labeled case will assign
1416 // to the state variable and go to the join-point.
1417 ir.Primitive value = visit(node.expression);
1418 JumpCollector join = new ForwardJumpCollector(irBuilder.environment,
1419 target: elements.getTargetDefinition(node));
1420 irBuilder.state.breakCollectors.add(join);
1421 for (int i = 0; i < continueTargets.length; ++i) {
1422 // The state value is i, the case's position in the list of recursive
1423 // cases.
1424 irBuilder.state.continueCollectors
1425 .add(new GotoJumpCollector(continueTargets[i], stateIndex, i, join));
1426 }
1427
1428 // For each non-default case use a pair of functions, one to translate the
1429 // condition and one to translate the body. For the default case use a
1430 // function to translate the body. Use continueTargetIterator as a pointer
1431 // to the next recursive case.
1432 Iterator<JumpTarget> continueTargetIterator = continueTargets.iterator;
1433 continueTargetIterator.moveNext();
1434 List<SwitchCaseInfo> cases = <SwitchCaseInfo>[];
1435 SubbuildFunction buildDefaultBody;
1436 for (ast.SwitchCase switchCase in switchCases) {
1437 JumpTarget nextContinueTarget = continueTargetIterator.current;
1438 if (switchCase.isDefaultCase) {
1439 if (nextContinueTarget != null &&
1440 switchCase == nextContinueTarget.statement) {
1441 // In this simple switch, recursive cases are as if they immediately
1442 // continued to themselves.
1443 buildDefaultBody = nested(() {
1444 irBuilder.buildContinue(nextContinueTarget);
1445 });
1446 continueTargetIterator.moveNext();
1447 } else {
1448 // Non-recursive cases consist of the translation of the body.
1449 // For the default case, there is implicitly a break if control
1450 // flow reaches the end.
1451 buildDefaultBody = nested(() {
1452 irBuilder.buildSequence(switchCase.statements, visit);
1453 if (irBuilder.isOpen) irBuilder.jumpTo(join);
1454 });
1455 }
1456 continue;
1457 }
1458
1459 ir.Primitive buildCondition(IrBuilder builder) {
1460 // There can be multiple cases sharing the same body, because empty
1461 // cases are allowed to fall through to the next one. Each case is
1462 // a comparison, build a short-circuited disjunction of all of them.
1463 return withBuilder(builder, () {
1464 ir.Primitive condition;
1465 for (ast.Node labelOrCase in switchCase.labelsAndCases) {
1466 if (labelOrCase is ast.CaseMatch) {
1467 ir.Primitive buildComparison() {
1468 ir.Primitive constant =
1469 translateConstant(labelOrCase.expression);
1470 return irBuilder.buildIdentical(value, constant);
1471 }
1472
1473 if (condition == null) {
1474 condition = buildComparison();
1475 } else {
1476 condition = irBuilder.buildLogicalOperator(
1477 condition,
1478 nested(buildComparison),
1479 sourceInformationBuilder.buildSwitchCase(switchCase),
1480 isLazyOr: true);
1481 }
1482 }
1483 }
1484 return condition;
1485 });
1486 }
1487
1488 SubbuildFunction buildBody;
1489 if (nextContinueTarget != null &&
1490 switchCase == nextContinueTarget.statement) {
1491 // Recursive cases are as if they immediately continued to themselves.
1492 buildBody = nested(() {
1493 irBuilder.buildContinue(nextContinueTarget);
1494 });
1495 continueTargetIterator.moveNext();
1496 } else {
1497 // Non-recursive cases consist of the translation of the body. It is a
1498 // runtime error if control-flow reaches the end of the body of any but
1499 // the last case.
1500 buildBody = (IrBuilder builder) {
1501 withBuilder(builder, () {
1502 irBuilder.buildSequence(switchCase.statements, visit);
1503 if (irBuilder.isOpen) {
1504 if (switchCase == switchCases.last) {
1505 irBuilder.jumpTo(join);
1506 } else {
1507 Element error = helpers.fallThroughError;
1508 ir.Primitive exception = irBuilder.buildInvokeStatic(
1509 error,
1510 new Selector.fromElement(error),
1511 <ir.Primitive>[],
1512 sourceInformationBuilder.buildGeneric(node));
1513 irBuilder.buildThrow(exception);
1514 }
1515 }
1516 });
1517 return null;
1518 };
1519 }
1520
1521 cases.add(new SwitchCaseInfo(buildCondition, buildBody,
1522 sourceInformationBuilder.buildSwitchCase(switchCase)));
1523 }
1524
1525 irBuilder.buildSimpleSwitch(join, cases, buildDefaultBody);
1526 irBuilder.state.breakCollectors.removeLast();
1527 irBuilder.state.continueCollectors.length -= continueTargets.length;
1528 if (continueTargets.isEmpty) return;
1529
1530 // If there were recursive cases build a while loop whose body is a
1531 // switch containing (only) the recursive cases. The condition is
1532 // 'state != initialValue' so the loop is not taken when the state variable
1533 // has not been assigned.
1534 //
1535 // 'loop' is the join-point of the exits from the inner switch which will
1536 // perform another iteration of the loop. 'exit' is the join-point of the
1537 // breaks from the switch, outside the loop.
1538 JumpCollector loop = new ForwardJumpCollector(irBuilder.environment);
1539 JumpCollector exit = new ForwardJumpCollector(irBuilder.environment,
1540 target: elements.getTargetDefinition(node));
1541 irBuilder.state.breakCollectors.add(exit);
1542 for (int i = 0; i < continueTargets.length; ++i) {
1543 irBuilder.state.continueCollectors
1544 .add(new GotoJumpCollector(continueTargets[i], stateIndex, i, loop));
1545 }
1546 cases.clear();
1547 for (int i = 0; i < continueTargets.length; ++i) {
1548 // The conditions compare to the recursive case index.
1549 ir.Primitive buildCondition(IrBuilder builder) {
1550 ir.Primitive constant = builder.buildIntegerConstant(i);
1551 return builder.buildIdentical(
1552 builder.environment.index2value[stateIndex], constant);
1553 }
1554
1555 ir.Primitive buildBody(IrBuilder builder) {
1556 withBuilder(builder, () {
1557 ast.SwitchCase switchCase = continueTargets[i].statement;
1558 irBuilder.buildSequence(switchCase.statements, visit);
1559 if (irBuilder.isOpen) {
1560 if (switchCase == switchCases.last) {
1561 irBuilder.jumpTo(exit);
1562 } else {
1563 Element error = helpers.fallThroughError;
1564 ir.Primitive exception = irBuilder.buildInvokeStatic(
1565 error,
1566 new Selector.fromElement(error),
1567 <ir.Primitive>[],
1568 sourceInformationBuilder.buildGeneric(node));
1569 irBuilder.buildThrow(exception);
1570 }
1571 }
1572 });
1573 return null;
1574 }
1575
1576 cases.add(new SwitchCaseInfo(buildCondition, buildBody,
1577 sourceInformationBuilder.buildSwitch(node)));
1578 }
1579
1580 // A loop with a simple switch in the body.
1581 IrBuilder whileBuilder = irBuilder.makeDelimitedBuilder();
1582 whileBuilder.buildWhile(buildCondition: (IrBuilder builder) {
1583 ir.Primitive condition = builder.buildIdentical(
1584 builder.environment.index2value[stateIndex], initial);
1585 return builder.buildNegation(
1586 condition, sourceInformationBuilder.buildSwitch(node));
1587 }, buildBody: (IrBuilder builder) {
1588 builder.buildSimpleSwitch(loop, cases, null);
1589 });
1590 // Jump to the exit continuation. This jump is the body of the loop exit
1591 // continuation, so the loop exit continuation can be eta-reduced. The
1592 // jump is here for simplicity because `buildWhile` does not expose the
1593 // loop's exit continuation directly and has already emitted all jumps
1594 // to it anyway.
1595 whileBuilder.jumpTo(exit);
1596 irBuilder.add(new ir.LetCont(exit.continuation, whileBuilder.root));
1597 irBuilder.environment = exit.environment;
1598 irBuilder.environment.discard(1); // Discard the state variable.
1599 irBuilder.state.breakCollectors.removeLast();
1600 irBuilder.state.continueCollectors.length -= continueTargets.length;
1601 }
1602
1603 visitTryStatement(ast.TryStatement node) {
1604 List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[];
1605 for (ast.CatchBlock catchClause in node.catchBlocks.nodes) {
1606 LocalVariableElement exceptionVariable;
1607 if (catchClause.exception != null) {
1608 exceptionVariable = elements[catchClause.exception];
1609 }
1610 LocalVariableElement stackTraceVariable;
1611 if (catchClause.trace != null) {
1612 stackTraceVariable = elements[catchClause.trace];
1613 }
1614 DartType type;
1615 if (catchClause.onKeyword != null) {
1616 type = elements.getType(catchClause.type);
1617 }
1618 catchClauseInfos.add(new CatchClauseInfo(
1619 type: type,
1620 exceptionVariable: exceptionVariable,
1621 stackTraceVariable: stackTraceVariable,
1622 buildCatchBlock: subbuild(catchClause.block),
1623 sourceInformation: sourceInformationBuilder.buildCatch(catchClause)));
1624 }
1625
1626 assert(!node.catchBlocks.isEmpty || node.finallyBlock != null);
1627 if (!node.catchBlocks.isEmpty && node.finallyBlock != null) {
1628 // Try/catch/finally is encoded in terms of try/catch and try/finally:
1629 //
1630 // try tryBlock catch (ex, st) catchBlock finally finallyBlock
1631 // ==>
1632 // try { try tryBlock catch (ex, st) catchBlock } finally finallyBlock
1633 irBuilder.buildTryFinally(tryStatements[node.finallyBlock],
1634 (IrBuilder inner) {
1635 inner.buildTryCatch(tryStatements[node.catchBlocks],
1636 subbuild(node.tryBlock), catchClauseInfos);
1637 }, subbuild(node.finallyBlock));
1638 } else if (!node.catchBlocks.isEmpty) {
1639 irBuilder.buildTryCatch(tryStatements[node.catchBlocks],
1640 subbuild(node.tryBlock), catchClauseInfos);
1641 } else {
1642 irBuilder.buildTryFinally(tryStatements[node.finallyBlock],
1643 subbuild(node.tryBlock), subbuild(node.finallyBlock));
1644 }
1645 }
1646
1647 // ## Expressions ##
1648 ir.Primitive visitConditional(ast.Conditional node) {
1649 return irBuilder.buildConditional(
1650 build(node.condition),
1651 subbuild(node.thenExpression),
1652 subbuild(node.elseExpression),
1653 sourceInformationBuilder.buildIf(node));
1654 }
1655
1656 // For all simple literals:
1657 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x]
1658 ir.Primitive visitLiteralBool(ast.LiteralBool node) {
1659 assert(irBuilder.isOpen);
1660 return irBuilder.buildBooleanConstant(node.value);
1661 }
1662
1663 ir.Primitive visitLiteralDouble(ast.LiteralDouble node) {
1664 assert(irBuilder.isOpen);
1665 return irBuilder.buildDoubleConstant(node.value);
1666 }
1667
1668 ir.Primitive visitLiteralInt(ast.LiteralInt node) {
1669 assert(irBuilder.isOpen);
1670 return irBuilder.buildIntegerConstant(node.value);
1671 }
1672
1673 ir.Primitive visitLiteralNull(ast.LiteralNull node) {
1674 assert(irBuilder.isOpen);
1675 return irBuilder.buildNullConstant();
1676 }
1677
1678 ir.Primitive visitLiteralString(ast.LiteralString node) {
1679 assert(irBuilder.isOpen);
1680 return irBuilder.buildDartStringConstant(node.dartString);
1681 }
1682
1683 ConstantValue getConstantForNode(ast.Node node) {
1684 return irBuilder.state.constants.getConstantValueForNode(node, elements);
1685 }
1686
1687 ConstantValue getConstantForVariable(VariableElement element) {
1688 ConstantExpression constant = element.constant;
1689 if (constant != null) {
1690 return irBuilder.state.constants.getConstantValue(constant);
1691 }
1692 return null;
1693 }
1694
1695 ir.Primitive buildConstantExpression(
1696 ConstantExpression expression, SourceInformation sourceInformation) {
1697 return irBuilder.buildConstant(
1698 irBuilder.state.constants.getConstantValue(expression),
1699 sourceInformation: sourceInformation);
1700 }
1701
1702 /// Returns the allocation site-specific type for a given allocation.
1703 ///
1704 /// Currently, it is an error to call this with anything that is not the
1705 /// allocation site for a List object (a literal list or a call to one
1706 /// of the List constructors).
1707 TypeMask getAllocationSiteType(ast.Node node) {
1708 return compiler.typesTask
1709 .getGuaranteedTypeOfNode(elements.analyzedElement, node);
1710 }
1711
1712 ir.Primitive visitLiteralList(ast.LiteralList node) {
1713 if (node.isConst) {
1714 return translateConstant(node);
1715 }
1716 List<ir.Primitive> values = node.elements.nodes.mapToList(visit);
1717 InterfaceType type = elements.getType(node);
1718 TypeMask allocationSiteType = getAllocationSiteType(node);
1719 // TODO(sra): In checked mode, the elements must be checked as though
1720 // operator[]= is called.
1721 ir.Primitive list = irBuilder.buildListLiteral(type, values,
1722 allocationSiteType: allocationSiteType);
1723 if (type.treatAsRaw) return list;
1724 // Call JSArray<E>.typed(allocation) to install the reified type.
1725 ConstructorElement constructor = helpers.jsArrayTypedConstructor;
1726 ir.Primitive tagged = irBuilder.buildConstructorInvocation(
1727 constructor.effectiveTarget,
1728 CallStructure.ONE_ARG,
1729 constructor.computeEffectiveTargetType(type),
1730 <ir.Primitive>[list],
1731 sourceInformationBuilder.buildNew(node));
1732
1733 if (allocationSiteType == null) return tagged;
1734
1735 return irBuilder
1736 .addPrimitive(new ir.Refinement(tagged, allocationSiteType));
1737 }
1738
1739 ir.Primitive visitLiteralMap(ast.LiteralMap node) {
1740 assert(irBuilder.isOpen);
1741 if (node.isConst) {
1742 return translateConstant(node);
1743 }
1744
1745 InterfaceType type = elements.getType(node);
1746
1747 if (node.entries.nodes.isEmpty) {
1748 if (type.treatAsRaw) {
1749 return irBuilder.buildStaticFunctionInvocation(
1750 helpers.mapLiteralUntypedEmptyMaker,
1751 <ir.Primitive>[],
1752 sourceInformationBuilder.buildNew(node));
1753 } else {
1754 ConstructorElement constructor = helpers.mapLiteralConstructorEmpty;
1755 return irBuilder.buildConstructorInvocation(
1756 constructor.effectiveTarget,
1757 CallStructure.NO_ARGS,
1758 constructor.computeEffectiveTargetType(type),
1759 <ir.Primitive>[],
1760 sourceInformationBuilder.buildNew(node));
1761 }
1762 }
1763
1764 List<ir.Primitive> keysAndValues = <ir.Primitive>[];
1765 for (ast.LiteralMapEntry entry in node.entries.nodes.toList()) {
1766 keysAndValues.add(visit(entry.key));
1767 keysAndValues.add(visit(entry.value));
1768 }
1769 ir.Primitive keysAndValuesList =
1770 irBuilder.buildListLiteral(null, keysAndValues);
1771
1772 if (type.treatAsRaw) {
1773 return irBuilder.buildStaticFunctionInvocation(
1774 helpers.mapLiteralUntypedMaker,
1775 <ir.Primitive>[keysAndValuesList],
1776 sourceInformationBuilder.buildNew(node));
1777 } else {
1778 ConstructorElement constructor = helpers.mapLiteralConstructor;
1779 return irBuilder.buildConstructorInvocation(
1780 constructor.effectiveTarget,
1781 CallStructure.ONE_ARG,
1782 constructor.computeEffectiveTargetType(type),
1783 <ir.Primitive>[keysAndValuesList],
1784 sourceInformationBuilder.buildNew(node));
1785 }
1786 }
1787
1788 ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) {
1789 assert(irBuilder.isOpen);
1790 return translateConstant(node);
1791 }
1792
1793 ir.Primitive visitParenthesizedExpression(ast.ParenthesizedExpression node) {
1794 assert(irBuilder.isOpen);
1795 return visit(node.expression);
1796 }
1797
1798 // Stores the result of visiting a CascadeReceiver, so we can return it from
1799 // its enclosing Cascade.
1800 ir.Primitive _currentCascadeReceiver;
1801
1802 ir.Primitive visitCascadeReceiver(ast.CascadeReceiver node) {
1803 assert(irBuilder.isOpen);
1804 return _currentCascadeReceiver = visit(node.expression);
1805 }
1806
1807 ir.Primitive visitCascade(ast.Cascade node) {
1808 assert(irBuilder.isOpen);
1809 var oldCascadeReceiver = _currentCascadeReceiver;
1810 // Throw away the result of visiting the expression.
1811 // Instead we return the result of visiting the CascadeReceiver.
1812 visit(node.expression);
1813 ir.Primitive receiver = _currentCascadeReceiver;
1814 _currentCascadeReceiver = oldCascadeReceiver;
1815 return receiver;
1816 }
1817
1818 @override
1819 ir.Primitive visitAssert(ast.Assert node) {
1820 assert(irBuilder.isOpen);
1821 if (compiler.options.enableUserAssertions) {
1822 return giveup(node, 'assert in checked mode not implemented');
1823 } else {
1824 // The call to assert and its argument expression must be ignored
1825 // in production mode.
1826 // Assertions can only occur in expression statements, so no value needs
1827 // to be returned.
1828 return null;
1829 }
1830 }
1831
1832 // ## Sends ##
1833 @override
1834 void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) {
1835 if (prefix != null) buildCheckDeferredIsLoaded(prefix, node);
1836 }
1837
1838 /// Create a call to check that a deferred import has already been loaded.
1839 ir.Primitive buildCheckDeferredIsLoaded(PrefixElement prefix, ast.Send node) {
1840 SourceInformation sourceInformation =
1841 sourceInformationBuilder.buildCall(node, node.selector);
1842 ir.Primitive name = irBuilder.buildStringConstant(
1843 compiler.deferredLoadTask.getImportDeferName(node, prefix));
1844 ir.Primitive uri =
1845 irBuilder.buildStringConstant('${prefix.deferredImport.uri}');
1846 return irBuilder.buildStaticFunctionInvocation(
1847 helpers.checkDeferredIsLoaded,
1848 <ir.Primitive>[name, uri],
1849 sourceInformation);
1850 }
1851
1852 ir.Primitive visitNamedArgument(ast.NamedArgument node) {
1853 assert(irBuilder.isOpen);
1854 return visit(node.expression);
1855 }
1856
1857 @override
1858 ir.Primitive visitExpressionInvoke(ast.Send node, ast.Node expression,
1859 ast.NodeList argumentsNode, CallStructure callStructure, _) {
1860 ir.Primitive receiver = visit(expression);
1861 List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit);
1862 callStructure = normalizeDynamicArguments(callStructure, arguments);
1863 return irBuilder.buildCallInvocation(receiver, callStructure, arguments,
1864 sourceInformationBuilder.buildCall(node, argumentsNode));
1865 }
1866
1867 /// Returns `true` if [node] is a super call.
1868 // TODO(johnniwinther): Remove the need for this.
1869 bool isSuperCall(ast.Send node) {
1870 return node != null && node.receiver != null && node.receiver.isSuper();
1871 }
1872
1873 @override
1874 ir.Primitive handleConstantGet(
1875 ast.Node node, ConstantExpression constant, _) {
1876 return buildConstantExpression(
1877 constant, sourceInformationBuilder.buildGet(node));
1878 }
1879
1880 /// If [node] is null, returns this.
1881 /// Otherwise visits [node] and returns the result.
1882 ir.Primitive translateReceiver(ast.Expression node) {
1883 return node != null ? visit(node) : irBuilder.buildThis();
1884 }
1885
1886 @override
1887 ir.Primitive handleDynamicGet(
1888 ast.Send node, ast.Node receiver, Name name, _) {
1889 return irBuilder.buildDynamicGet(
1890 translateReceiver(receiver),
1891 new Selector.getter(name),
1892 elements.getTypeMask(node),
1893 sourceInformationBuilder.buildGet(node));
1894 }
1895
1896 @override
1897 ir.Primitive visitIfNotNullDynamicPropertyGet(
1898 ast.Send node, ast.Node receiver, Name name, _) {
1899 ir.Primitive target = visit(receiver);
1900 return irBuilder.buildIfNotNullSend(
1901 target,
1902 nested(() => irBuilder.buildDynamicGet(
1903 target,
1904 new Selector.getter(name),
1905 elements.getTypeMask(node),
1906 sourceInformationBuilder.buildGet(node))),
1907 sourceInformationBuilder.buildIf(node));
1908 }
1909
1910 @override
1911 ir.Primitive visitDynamicTypeLiteralGet(
1912 ast.Send node, ConstantExpression constant, _) {
1913 return buildConstantExpression(
1914 constant, sourceInformationBuilder.buildGet(node));
1915 }
1916
1917 @override
1918 ir.Primitive visitLocalVariableGet(
1919 ast.Send node, LocalVariableElement element, _) {
1920 return element.isConst
1921 ? irBuilder.buildConstant(getConstantForVariable(element),
1922 sourceInformation: sourceInformationBuilder.buildGet(node))
1923 : irBuilder.buildLocalGet(element);
1924 }
1925
1926 ir.Primitive handleLocalGet(ast.Send node, LocalElement element, _) {
1927 return irBuilder.buildLocalGet(element);
1928 }
1929
1930 @override
1931 ir.Primitive handleStaticFunctionGet(
1932 ast.Send node, MethodElement function, _) {
1933 return irBuilder.addPrimitive(new ir.GetStatic(function, isFinal: true));
1934 }
1935
1936 @override
1937 ir.Primitive handleStaticGetterGet(ast.Send node, FunctionElement getter, _) {
1938 return buildStaticGetterGet(
1939 getter, node, sourceInformationBuilder.buildGet(node));
1940 }
1941
1942 /// Create a getter invocation of the static getter [getter]. This also
1943 /// handles the special case where [getter] is the `loadLibrary`
1944 /// pseudo-function on library prefixes of deferred imports.
1945 ir.Primitive buildStaticGetterGet(MethodElement getter, ast.Send node,
1946 SourceInformation sourceInformation) {
1947 if (getter.isDeferredLoaderGetter) {
1948 PrefixElement prefix = getter.enclosingElement;
1949 ir.Primitive loadId = irBuilder.buildStringConstant(
1950 compiler.deferredLoadTask.getImportDeferName(node, prefix));
1951 return irBuilder.buildStaticFunctionInvocation(
1952 compiler.loadLibraryFunction,
1953 <ir.Primitive>[loadId],
1954 sourceInformation);
1955 } else {
1956 return irBuilder.buildStaticGetterGet(getter, sourceInformation);
1957 }
1958 }
1959
1960 @override
1961 ir.Primitive visitSuperFieldGet(ast.Send node, FieldElement field, _) {
1962 return irBuilder.buildSuperFieldGet(
1963 field, sourceInformationBuilder.buildGet(node));
1964 }
1965
1966 @override
1967 ir.Primitive visitSuperGetterGet(ast.Send node, FunctionElement getter, _) {
1968 return irBuilder.buildSuperGetterGet(
1969 getter, sourceInformationBuilder.buildGet(node));
1970 }
1971
1972 @override
1973 ir.Primitive visitSuperMethodGet(ast.Send node, MethodElement method, _) {
1974 return irBuilder.buildSuperMethodGet(
1975 method, sourceInformationBuilder.buildGet(node));
1976 }
1977
1978 @override
1979 ir.Primitive visitUnresolvedSuperGet(ast.Send node, Element element, _) {
1980 return buildSuperNoSuchMethod(
1981 elements.getSelector(node),
1982 elements.getTypeMask(node),
1983 [],
1984 sourceInformationBuilder.buildGet(node));
1985 }
1986
1987 @override
1988 ir.Primitive visitUnresolvedSuperSet(
1989 ast.Send node, Element element, ast.Node rhs, _) {
1990 return buildSuperNoSuchMethod(
1991 elements.getSelector(node),
1992 elements.getTypeMask(node),
1993 [visit(rhs)],
1994 sourceInformationBuilder.buildAssignment(node));
1995 }
1996
1997 @override
1998 ir.Primitive visitThisGet(ast.Identifier node, _) {
1999 if (irBuilder.state.thisParameter == null) {
2000 // TODO(asgerf,johnniwinther): Should be in a visitInvalidThis method.
2001 // 'this' in static context. Just translate to null.
2002 assert(compiler.compilationFailed);
2003 return irBuilder.buildNullConstant();
2004 }
2005 return irBuilder.buildThis();
2006 }
2007
2008 ir.Primitive translateTypeVariableTypeLiteral(
2009 TypeVariableElement element, SourceInformation sourceInformation) {
2010 return irBuilder.buildReifyTypeVariable(element.type, sourceInformation);
2011 }
2012
2013 @override
2014 ir.Primitive visitTypeVariableTypeLiteralGet(
2015 ast.Send node, TypeVariableElement element, _) {
2016 return translateTypeVariableTypeLiteral(
2017 element, sourceInformationBuilder.buildGet(node));
2018 }
2019
2020 ir.Primitive translateLogicalOperator(ast.Expression left,
2021 ast.Expression right, SourceInformation sourceInformation,
2022 {bool isLazyOr}) {
2023 ir.Primitive leftValue = visit(left);
2024
2025 ir.Primitive buildRightValue(IrBuilder rightBuilder) {
2026 return withBuilder(rightBuilder, () => visit(right));
2027 }
2028
2029 return irBuilder.buildLogicalOperator(
2030 leftValue, buildRightValue, sourceInformation,
2031 isLazyOr: isLazyOr);
2032 }
2033
2034 @override
2035 ir.Primitive visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) {
2036 return irBuilder.buildIfNull(
2037 build(left), subbuild(right), sourceInformationBuilder.buildIf(node));
2038 }
2039
2040 @override
2041 ir.Primitive visitLogicalAnd(
2042 ast.Send node, ast.Node left, ast.Node right, _) {
2043 return translateLogicalOperator(
2044 left, right, sourceInformationBuilder.buildIf(node),
2045 isLazyOr: false);
2046 }
2047
2048 @override
2049 ir.Primitive visitLogicalOr(ast.Send node, ast.Node left, ast.Node right, _) {
2050 return translateLogicalOperator(
2051 left, right, sourceInformationBuilder.buildIf(node),
2052 isLazyOr: true);
2053 }
2054
2055 @override
2056 ir.Primitive visitAs(ast.Send node, ast.Node expression, DartType type, _) {
2057 ir.Primitive receiver = visit(expression);
2058 return irBuilder.buildTypeOperator(
2059 receiver, type, sourceInformationBuilder.buildAs(node),
2060 isTypeTest: false);
2061 }
2062
2063 @override
2064 ir.Primitive visitIs(ast.Send node, ast.Node expression, DartType type, _) {
2065 ir.Primitive value = visit(expression);
2066 return irBuilder.buildTypeOperator(
2067 value, type, sourceInformationBuilder.buildIs(node),
2068 isTypeTest: true);
2069 }
2070
2071 @override
2072 ir.Primitive visitIsNot(
2073 ast.Send node, ast.Node expression, DartType type, _) {
2074 ir.Primitive value = visit(expression);
2075 ir.Primitive check = irBuilder.buildTypeOperator(
2076 value, type, sourceInformationBuilder.buildIs(node),
2077 isTypeTest: true);
2078 return irBuilder.buildNegation(
2079 check, sourceInformationBuilder.buildIf(node));
2080 }
2081
2082 ir.Primitive translateBinary(ast.Send node, ast.Node left,
2083 op.BinaryOperator operator, ast.Node right) {
2084 ir.Primitive receiver = visit(left);
2085 Selector selector = new Selector.binaryOperator(operator.selectorName);
2086 List<ir.Primitive> arguments = <ir.Primitive>[visit(right)];
2087 CallStructure callStructure =
2088 normalizeDynamicArguments(selector.callStructure, arguments);
2089 return irBuilder.buildDynamicInvocation(
2090 receiver,
2091 new Selector(selector.kind, selector.memberName, callStructure),
2092 elements.getTypeMask(node),
2093 arguments,
2094 sourceInformationBuilder.buildCall(node, node.selector));
2095 }
2096
2097 @override
2098 ir.Primitive visitBinary(ast.Send node, ast.Node left,
2099 op.BinaryOperator operator, ast.Node right, _) {
2100 return translateBinary(node, left, operator, right);
2101 }
2102
2103 @override
2104 ir.Primitive visitIndex(ast.Send node, ast.Node receiver, ast.Node index, _) {
2105 ir.Primitive target = visit(receiver);
2106 Selector selector = new Selector.index();
2107 List<ir.Primitive> arguments = <ir.Primitive>[visit(index)];
2108 CallStructure callStructure =
2109 normalizeDynamicArguments(selector.callStructure, arguments);
2110 return irBuilder.buildDynamicInvocation(
2111 target,
2112 new Selector(selector.kind, selector.memberName, callStructure),
2113 elements.getTypeMask(node),
2114 arguments,
2115 sourceInformationBuilder.buildCall(receiver, node.selector));
2116 }
2117
2118 ir.Primitive translateSuperBinary(
2119 FunctionElement function,
2120 op.BinaryOperator operator,
2121 ast.Node argument,
2122 SourceInformation sourceInformation) {
2123 List<ir.Primitive> arguments = <ir.Primitive>[visit(argument)];
2124 return irBuilder.buildSuperMethodInvocation(
2125 function, CallStructure.ONE_ARG, arguments, sourceInformation);
2126 }
2127
2128 @override
2129 ir.Primitive visitSuperBinary(ast.Send node, FunctionElement function,
2130 op.BinaryOperator operator, ast.Node argument, _) {
2131 return translateSuperBinary(function, operator, argument,
2132 sourceInformationBuilder.buildBinary(node));
2133 }
2134
2135 @override
2136 ir.Primitive visitSuperIndex(
2137 ast.Send node, FunctionElement function, ast.Node index, _) {
2138 return irBuilder.buildSuperIndex(
2139 function, visit(index), sourceInformationBuilder.buildIndex(node));
2140 }
2141
2142 @override
2143 ir.Primitive visitEquals(ast.Send node, ast.Node left, ast.Node right, _) {
2144 return translateBinary(node, left, op.BinaryOperator.EQ, right);
2145 }
2146
2147 @override
2148 ir.Primitive visitSuperEquals(
2149 ast.Send node, FunctionElement function, ast.Node argument, _) {
2150 return translateSuperBinary(function, op.BinaryOperator.EQ, argument,
2151 sourceInformationBuilder.buildBinary(node));
2152 }
2153
2154 @override
2155 ir.Primitive visitNot(ast.Send node, ast.Node expression, _) {
2156 return irBuilder.buildNegation(
2157 visit(expression), sourceInformationBuilder.buildIf(node));
2158 }
2159
2160 @override
2161 ir.Primitive visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) {
2162 return irBuilder.buildNegation(
2163 translateBinary(node, left, op.BinaryOperator.NOT_EQ, right),
2164 sourceInformationBuilder.buildIf(node));
2165 }
2166
2167 @override
2168 ir.Primitive visitSuperNotEquals(
2169 ast.Send node, FunctionElement function, ast.Node argument, _) {
2170 return irBuilder.buildNegation(
2171 translateSuperBinary(function, op.BinaryOperator.NOT_EQ, argument,
2172 sourceInformationBuilder.buildBinary(node)),
2173 sourceInformationBuilder.buildIf(node));
2174 }
2175
2176 @override
2177 ir.Primitive visitUnary(
2178 ast.Send node, op.UnaryOperator operator, ast.Node expression, _) {
2179 // TODO(johnniwinther): Clean up the creation of selectors.
2180 Selector selector = operator.selector;
2181 ir.Primitive receiver = translateReceiver(expression);
2182 return irBuilder.buildDynamicInvocation(
2183 receiver,
2184 selector,
2185 elements.getTypeMask(node),
2186 const [],
2187 sourceInformationBuilder.buildCall(expression, node));
2188 }
2189
2190 @override
2191 ir.Primitive visitSuperUnary(
2192 ast.Send node, op.UnaryOperator operator, FunctionElement function, _) {
2193 return irBuilder.buildSuperMethodInvocation(function, CallStructure.NO_ARGS,
2194 const [], sourceInformationBuilder.buildCall(node, node));
2195 }
2196
2197 // TODO(johnniwinther): Handle this in the [IrBuilder] to ensure the correct
2198 // semantic correlation between arguments and invocation.
2199 CallStructure translateDynamicArguments(ast.NodeList nodeList,
2200 CallStructure callStructure, List<ir.Primitive> arguments) {
2201 assert(arguments.isEmpty);
2202 for (ast.Node node in nodeList) arguments.add(visit(node));
2203 return normalizeDynamicArguments(callStructure, arguments);
2204 }
2205
2206 // TODO(johnniwinther): Handle this in the [IrBuilder] to ensure the correct
2207 // semantic correlation between arguments and invocation.
2208 CallStructure translateStaticArguments(ast.NodeList nodeList, Element element,
2209 CallStructure callStructure, List<ir.Primitive> arguments) {
2210 assert(arguments.isEmpty);
2211 for (ast.Node node in nodeList) arguments.add(visit(node));
2212 return normalizeStaticArguments(callStructure, element, arguments);
2213 }
2214
2215 ir.Primitive translateCallInvoke(
2216 ir.Primitive target,
2217 ast.NodeList argumentsNode,
2218 CallStructure callStructure,
2219 SourceInformation sourceInformation) {
2220 List<ir.Primitive> arguments = <ir.Primitive>[];
2221 callStructure =
2222 translateDynamicArguments(argumentsNode, callStructure, arguments);
2223 return irBuilder.buildCallInvocation(
2224 target, callStructure, arguments, sourceInformation);
2225 }
2226
2227 @override
2228 ir.Primitive handleConstantInvoke(ast.Send node, ConstantExpression constant,
2229 ast.NodeList arguments, CallStructure callStructure, _) {
2230 ir.Primitive target = buildConstantExpression(
2231 constant, sourceInformationBuilder.buildGet(node));
2232 return translateCallInvoke(target, arguments, callStructure,
2233 sourceInformationBuilder.buildCall(node, arguments));
2234 }
2235
2236 @override
2237 ir.Primitive handleConstructorInvoke(
2238 ast.NewExpression node,
2239 ConstructorElement constructor,
2240 DartType type,
2241 ast.NodeList argumentsNode,
2242 CallStructure callStructure,
2243 _) {
2244 // TODO(sigmund): move these checks down after visiting arguments
2245 // (see issue #25355)
2246 ast.Send send = node.send;
2247 // If an allocation refers to a type using a deferred import prefix (e.g.
2248 // `new lib.A()`), we must ensure that the deferred import has already been
2249 // loaded.
2250 var prefix =
2251 compiler.deferredLoadTask.deferredPrefixElement(send, elements);
2252 if (prefix != null) buildCheckDeferredIsLoaded(prefix, send);
2253
2254 // We also emit deferred import checks when using redirecting factories that
2255 // refer to deferred prefixes.
2256 if (constructor.isRedirectingFactory && !constructor.isCyclicRedirection) {
2257 ConstructorElement current = constructor;
2258 while (current.isRedirectingFactory) {
2259 var prefix = current.redirectionDeferredPrefix;
2260 if (prefix != null) buildCheckDeferredIsLoaded(prefix, send);
2261 current = current.immediateRedirectionTarget;
2262 }
2263 }
2264
2265 List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit);
2266 if (constructor.isGenerativeConstructor &&
2267 backend.isNativeOrExtendsNative(constructor.enclosingClass)) {
2268 arguments.insert(0, irBuilder.buildNullConstant());
2269 }
2270 // Use default values from the effective target, not the immediate target.
2271 ConstructorElement target;
2272 if (constructor == compiler.symbolConstructor) {
2273 // The Symbol constructor should perform validation of its argument
2274 // which is not expressible as a Dart const constructor. Instead, the
2275 // libraries contain a dummy const constructor implementation that
2276 // doesn't perform validation and the compiler compiles a call to
2277 // (non-const) Symbol.validated when it sees new Symbol(...).
2278 target = helpers.symbolValidatedConstructor;
2279 } else {
2280 target = constructor.implementation;
2281 }
2282 while (target.isRedirectingFactory && !target.isCyclicRedirection) {
2283 target = target.effectiveTarget.implementation;
2284 }
2285
2286 callStructure = normalizeStaticArguments(callStructure, target, arguments);
2287 TypeMask allocationSiteType;
2288
2289 if (Elements.isFixedListConstructorCall(constructor, send, compiler) ||
2290 Elements.isGrowableListConstructorCall(constructor, send, compiler) ||
2291 Elements.isFilledListConstructorCall(constructor, send, compiler) ||
2292 Elements.isConstructorOfTypedArraySubclass(constructor, compiler)) {
2293 allocationSiteType = getAllocationSiteType(send);
2294 }
2295 ConstructorElement constructorImplementation = constructor.implementation;
2296 return irBuilder.buildConstructorInvocation(
2297 target,
2298 callStructure,
2299 constructorImplementation.computeEffectiveTargetType(type),
2300 arguments,
2301 sourceInformationBuilder.buildNew(node),
2302 allocationSiteType: allocationSiteType);
2303 }
2304
2305 @override
2306 ir.Primitive handleDynamicInvoke(ast.Send node, ast.Node receiver,
2307 ast.NodeList argumentsNode, Selector selector, _) {
2308 ir.Primitive target = translateReceiver(receiver);
2309 List<ir.Primitive> arguments = <ir.Primitive>[];
2310 CallStructure callStructure = translateDynamicArguments(
2311 argumentsNode, selector.callStructure, arguments);
2312 return irBuilder.buildDynamicInvocation(
2313 target,
2314 new Selector(selector.kind, selector.memberName, callStructure),
2315 elements.getTypeMask(node),
2316 arguments,
2317 sourceInformationBuilder.buildCall(node, node.selector));
2318 }
2319
2320 @override
2321 ir.Primitive visitIfNotNullDynamicPropertyInvoke(ast.Send node,
2322 ast.Node receiver, ast.NodeList argumentsNode, Selector selector, _) {
2323 ir.Primitive target = visit(receiver);
2324 return irBuilder.buildIfNotNullSend(target, nested(() {
2325 List<ir.Primitive> arguments = <ir.Primitive>[];
2326 CallStructure callStructure = translateDynamicArguments(
2327 argumentsNode, selector.callStructure, arguments);
2328 return irBuilder.buildDynamicInvocation(
2329 target,
2330 new Selector(selector.kind, selector.memberName, callStructure),
2331 elements.getTypeMask(node),
2332 arguments,
2333 sourceInformationBuilder.buildCall(node, node.selector));
2334 }), sourceInformationBuilder.buildIf(node));
2335 }
2336
2337 ir.Primitive handleLocalInvoke(ast.Send node, LocalElement element,
2338 ast.NodeList argumentsNode, CallStructure callStructure, _) {
2339 ir.Primitive function = irBuilder.buildLocalGet(element);
2340 List<ir.Primitive> arguments = <ir.Primitive>[];
2341 callStructure =
2342 translateDynamicArguments(argumentsNode, callStructure, arguments);
2343 return irBuilder.buildCallInvocation(function, callStructure, arguments,
2344 sourceInformationBuilder.buildCall(node, argumentsNode));
2345 }
2346
2347 @override
2348 ir.Primitive handleStaticFieldGet(ast.Send node, FieldElement field, _) {
2349 return buildStaticFieldGet(field, sourceInformationBuilder.buildGet(node));
2350 }
2351
2352 @override
2353 ir.Primitive handleStaticFieldInvoke(ast.Send node, FieldElement field,
2354 ast.NodeList argumentsNode, CallStructure callStructure, _) {
2355 SourceInformation src = sourceInformationBuilder.buildGet(node);
2356 ir.Primitive target = buildStaticFieldGet(field, src);
2357 List<ir.Primitive> arguments = <ir.Primitive>[];
2358 callStructure =
2359 translateDynamicArguments(argumentsNode, callStructure, arguments);
2360 return irBuilder.buildCallInvocation(target, callStructure, arguments,
2361 sourceInformationBuilder.buildCall(node, argumentsNode));
2362 }
2363
2364 @override
2365 ir.Primitive handleStaticFunctionInvoke(ast.Send node, MethodElement function,
2366 ast.NodeList argumentsNode, CallStructure callStructure, _) {
2367 if (compiler.backend.isForeign(function)) {
2368 return handleForeignCode(node, function, argumentsNode, callStructure);
2369 } else {
2370 List<ir.Primitive> arguments = <ir.Primitive>[];
2371 callStructure = translateStaticArguments(
2372 argumentsNode, function, callStructure, arguments);
2373 Selector selector = new Selector.call(function.memberName, callStructure);
2374 return irBuilder.buildInvokeStatic(function, selector, arguments,
2375 sourceInformationBuilder.buildCall(node, node.selector));
2376 }
2377 }
2378
2379 @override
2380 ir.Primitive handleStaticFunctionIncompatibleInvoke(
2381 ast.Send node,
2382 MethodElement function,
2383 ast.NodeList arguments,
2384 CallStructure callStructure,
2385 _) {
2386 return irBuilder.buildStaticNoSuchMethod(
2387 elements.getSelector(node),
2388 arguments.nodes.mapToList(visit),
2389 sourceInformationBuilder.buildCall(node, node.selector));
2390 }
2391
2392 @override
2393 ir.Primitive handleStaticGetterInvoke(ast.Send node, FunctionElement getter,
2394 ast.NodeList argumentsNode, CallStructure callStructure, _) {
2395 ir.Primitive target = buildStaticGetterGet(
2396 getter, node, sourceInformationBuilder.buildGet(node));
2397 List<ir.Primitive> arguments = <ir.Primitive>[];
2398 callStructure =
2399 translateDynamicArguments(argumentsNode, callStructure, arguments);
2400 return irBuilder.buildCallInvocation(target, callStructure, arguments,
2401 sourceInformationBuilder.buildCall(node, argumentsNode));
2402 }
2403
2404 @override
2405 ir.Primitive visitSuperFieldInvoke(ast.Send node, FieldElement field,
2406 ast.NodeList argumentsNode, CallStructure callStructure, _) {
2407 ir.Primitive target = irBuilder.buildSuperFieldGet(
2408 field, sourceInformationBuilder.buildGet(node));
2409 List<ir.Primitive> arguments = <ir.Primitive>[];
2410 callStructure =
2411 translateDynamicArguments(argumentsNode, callStructure, arguments);
2412 return irBuilder.buildCallInvocation(target, callStructure, arguments,
2413 sourceInformationBuilder.buildCall(node, argumentsNode));
2414 }
2415
2416 @override
2417 ir.Primitive visitSuperGetterInvoke(ast.Send node, FunctionElement getter,
2418 ast.NodeList argumentsNode, CallStructure callStructure, _) {
2419 ir.Primitive target = irBuilder.buildSuperGetterGet(
2420 getter, sourceInformationBuilder.buildGet(node));
2421 List<ir.Primitive> arguments = <ir.Primitive>[];
2422 callStructure =
2423 translateDynamicArguments(argumentsNode, callStructure, arguments);
2424 return irBuilder.buildCallInvocation(target, callStructure, arguments,
2425 sourceInformationBuilder.buildCall(node, argumentsNode));
2426 }
2427
2428 @override
2429 ir.Primitive visitSuperMethodInvoke(ast.Send node, MethodElement method,
2430 ast.NodeList argumentsNode, CallStructure callStructure, _) {
2431 List<ir.Primitive> arguments = <ir.Primitive>[];
2432 callStructure = translateStaticArguments(
2433 argumentsNode, method, callStructure, arguments);
2434 return irBuilder.buildSuperMethodInvocation(method, callStructure,
2435 arguments, sourceInformationBuilder.buildCall(node, node.selector));
2436 }
2437
2438 @override
2439 ir.Primitive visitSuperMethodIncompatibleInvoke(
2440 ast.Send node,
2441 MethodElement method,
2442 ast.NodeList arguments,
2443 CallStructure callStructure,
2444 _) {
2445 List<ir.Primitive> normalizedArguments = <ir.Primitive>[];
2446 CallStructure normalizedCallStructure = translateDynamicArguments(
2447 arguments, callStructure, normalizedArguments);
2448 return buildSuperNoSuchMethod(
2449 new Selector.call(method.memberName, normalizedCallStructure),
2450 elements.getTypeMask(node),
2451 normalizedArguments,
2452 sourceInformationBuilder.buildCall(node, arguments));
2453 }
2454
2455 @override
2456 ir.Primitive visitUnresolvedSuperInvoke(ast.Send node, Element element,
2457 ast.NodeList argumentsNode, Selector selector, _) {
2458 List<ir.Primitive> arguments = <ir.Primitive>[];
2459 CallStructure callStructure = translateDynamicArguments(
2460 argumentsNode, selector.callStructure, arguments);
2461 // TODO(johnniwinther): Supply a member name to the visit function instead
2462 // of looking it up in elements.
2463 return buildSuperNoSuchMethod(
2464 new Selector.call(elements.getSelector(node).memberName, callStructure),
2465 elements.getTypeMask(node),
2466 arguments,
2467 sourceInformationBuilder.buildCall(node, argumentsNode));
2468 }
2469
2470 @override
2471 ir.Primitive visitThisInvoke(
2472 ast.Send node, ast.NodeList arguments, CallStructure callStructure, _) {
2473 return translateCallInvoke(irBuilder.buildThis(), arguments, callStructure,
2474 sourceInformationBuilder.buildCall(node, arguments));
2475 }
2476
2477 @override
2478 ir.Primitive visitTypeVariableTypeLiteralInvoke(
2479 ast.Send node,
2480 TypeVariableElement element,
2481 ast.NodeList arguments,
2482 CallStructure callStructure,
2483 _) {
2484 return translateCallInvoke(
2485 translateTypeVariableTypeLiteral(
2486 element, sourceInformationBuilder.buildGet(node)),
2487 arguments,
2488 callStructure,
2489 sourceInformationBuilder.buildCall(node, arguments));
2490 }
2491
2492 @override
2493 ir.Primitive visitIndexSet(
2494 ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, _) {
2495 return irBuilder.buildDynamicIndexSet(
2496 visit(receiver),
2497 elements.getTypeMask(node),
2498 visit(index),
2499 visit(rhs),
2500 sourceInformationBuilder.buildIndexSet(node));
2501 }
2502
2503 @override
2504 ir.Primitive visitSuperIndexSet(ast.SendSet node, FunctionElement function,
2505 ast.Node index, ast.Node rhs, _) {
2506 return irBuilder.buildSuperIndexSet(function, visit(index), visit(rhs),
2507 sourceInformationBuilder.buildIndexSet(node));
2508 }
2509
2510 ir.Primitive translateIfNull(ast.SendSet node, ir.Primitive getValue(),
2511 ast.Node rhs, void setValue(ir.Primitive value)) {
2512 ir.Primitive value = getValue();
2513 // Unlike other compound operators if-null conditionally will not do the
2514 // assignment operation.
2515 return irBuilder.buildIfNull(value, nested(() {
2516 ir.Primitive newValue = build(rhs);
2517 setValue(newValue);
2518 return newValue;
2519 }), sourceInformationBuilder.buildIf(node));
2520 }
2521
2522 ir.Primitive translateCompounds(ast.SendSet node, ir.Primitive getValue(),
2523 CompoundRhs rhs, void setValue(ir.Primitive value)) {
2524 ir.Primitive value = getValue();
2525 op.BinaryOperator operator = rhs.operator;
2526 assert(operator.kind != op.BinaryOperatorKind.IF_NULL);
2527
2528 Selector operatorSelector =
2529 new Selector.binaryOperator(operator.selectorName);
2530 ir.Primitive rhsValue;
2531 if (rhs.kind == CompoundKind.ASSIGNMENT) {
2532 rhsValue = visit(rhs.rhs);
2533 } else {
2534 rhsValue = irBuilder.buildIntegerConstant(1);
2535 }
2536 List<ir.Primitive> arguments = <ir.Primitive>[rhsValue];
2537 CallStructure callStructure =
2538 normalizeDynamicArguments(operatorSelector.callStructure, arguments);
2539 TypeMask operatorTypeMask =
2540 elements.getOperatorTypeMaskInComplexSendSet(node);
2541 SourceInformation operatorSourceInformation =
2542 sourceInformationBuilder.buildCall(node, node.assignmentOperator);
2543 ir.Primitive result = irBuilder.buildDynamicInvocation(
2544 value,
2545 new Selector(
2546 operatorSelector.kind, operatorSelector.memberName, callStructure),
2547 operatorTypeMask,
2548 arguments,
2549 operatorSourceInformation);
2550 setValue(result);
2551 return rhs.kind == CompoundKind.POSTFIX ? value : result;
2552 }
2553
2554 ir.Primitive translateSetIfNull(ast.SendSet node, ir.Primitive getValue(),
2555 ast.Node rhs, void setValue(ir.Primitive value)) {
2556 ir.Primitive value = getValue();
2557 // Unlike other compound operators if-null conditionally will not do the
2558 // assignment operation.
2559 return irBuilder.buildIfNull(value, nested(() {
2560 ir.Primitive newValue = build(rhs);
2561 setValue(newValue);
2562 return newValue;
2563 }), sourceInformationBuilder.buildIf(node));
2564 }
2565
2566 @override
2567 ir.Primitive handleSuperIndexSetIfNull(
2568 ast.SendSet node,
2569 Element indexFunction,
2570 Element indexSetFunction,
2571 ast.Node index,
2572 ast.Node rhs,
2573 arg,
2574 {bool isGetterValid,
2575 bool isSetterValid}) {
2576 return translateSetIfNull(
2577 node,
2578 () {
2579 if (isGetterValid) {
2580 return irBuilder.buildSuperMethodGet(
2581 indexFunction, sourceInformationBuilder.buildIndex(node));
2582 } else {
2583 return buildSuperNoSuchGetter(
2584 indexFunction,
2585 elements.getGetterTypeMaskInComplexSendSet(node),
2586 sourceInformationBuilder.buildIndex(node));
2587 }
2588 },
2589 rhs,
2590 (ir.Primitive result) {
2591 if (isSetterValid) {
2592 return irBuilder.buildSuperMethodGet(
2593 indexSetFunction, sourceInformationBuilder.buildIndexSet(node));
2594 } else {
2595 return buildSuperNoSuchSetter(
2596 indexSetFunction,
2597 elements.getTypeMask(node),
2598 result,
2599 sourceInformationBuilder.buildIndexSet(node));
2600 }
2601 });
2602 }
2603
2604 @override
2605 ir.Primitive visitIndexSetIfNull(
2606 ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, arg) {
2607 ir.Primitive target = visit(receiver);
2608 ir.Primitive indexValue = visit(index);
2609 return translateSetIfNull(
2610 node,
2611 () {
2612 Selector selector = new Selector.index();
2613 List<ir.Primitive> arguments = <ir.Primitive>[indexValue];
2614 CallStructure callStructure =
2615 normalizeDynamicArguments(selector.callStructure, arguments);
2616 return irBuilder.buildDynamicInvocation(
2617 target,
2618 new Selector(selector.kind, selector.memberName, callStructure),
2619 elements.getGetterTypeMaskInComplexSendSet(node),
2620 arguments,
2621 sourceInformationBuilder.buildCall(receiver, node));
2622 },
2623 rhs,
2624 (ir.Primitive result) {
2625 irBuilder.buildDynamicIndexSet(target, elements.getTypeMask(node),
2626 indexValue, result, sourceInformationBuilder.buildIndexSet(node));
2627 });
2628 }
2629
2630 @override
2631 ir.Primitive handleDynamicSet(
2632 ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) {
2633 return irBuilder.buildDynamicSet(
2634 translateReceiver(receiver),
2635 new Selector.setter(name),
2636 elements.getTypeMask(node),
2637 visit(rhs),
2638 sourceInformationBuilder.buildAssignment(node));
2639 }
2640
2641 @override
2642 ir.Primitive visitIfNotNullDynamicPropertySet(
2643 ast.SendSet node, ast.Node receiver, Name name, ast.Node rhs, _) {
2644 ir.Primitive target = visit(receiver);
2645 return irBuilder.buildIfNotNullSend(
2646 target,
2647 nested(() => irBuilder.buildDynamicSet(
2648 target,
2649 new Selector.setter(name),
2650 elements.getTypeMask(node),
2651 visit(rhs),
2652 sourceInformationBuilder.buildAssignment(node))),
2653 sourceInformationBuilder.buildIf(node));
2654 }
2655
2656 @override
2657 ir.Primitive handleLocalSet(
2658 ast.SendSet node, LocalElement element, ast.Node rhs, _) {
2659 ir.Primitive value = visit(rhs);
2660 value = checkTypeVsElement(value, element);
2661 return irBuilder.buildLocalVariableSet(
2662 element, value, sourceInformationBuilder.buildAssignment(node));
2663 }
2664
2665 @override
2666 ir.Primitive handleStaticFieldSet(
2667 ast.SendSet node, FieldElement field, ast.Node rhs, _) {
2668 ir.Primitive value = visit(rhs);
2669 irBuilder.addPrimitive(new ir.SetStatic(
2670 field, value, sourceInformationBuilder.buildAssignment(node)));
2671 return value;
2672 }
2673
2674 @override
2675 ir.Primitive visitSuperFieldSet(
2676 ast.SendSet node, FieldElement field, ast.Node rhs, _) {
2677 return irBuilder.buildSuperFieldSet(
2678 field, visit(rhs), sourceInformationBuilder.buildAssignment(node));
2679 }
2680
2681 @override
2682 ir.Primitive visitSuperSetterSet(
2683 ast.SendSet node, FunctionElement setter, ast.Node rhs, _) {
2684 return irBuilder.buildSuperSetterSet(
2685 setter, visit(rhs), sourceInformationBuilder.buildAssignment(node));
2686 }
2687
2688 @override
2689 ir.Primitive visitUnresolvedSuperIndexSet(
2690 ast.Send node, Element element, ast.Node index, ast.Node rhs, arg) {
2691 return giveup(node, 'visitUnresolvedSuperIndexSet');
2692 }
2693
2694 @override
2695 ir.Primitive handleStaticSetterSet(
2696 ast.SendSet node, FunctionElement setter, ast.Node rhs, _) {
2697 return irBuilder.buildStaticSetterSet(
2698 setter, visit(rhs), sourceInformationBuilder.buildAssignment(node));
2699 }
2700
2701 @override
2702 ir.Primitive handleTypeLiteralConstantCompounds(
2703 ast.SendSet node, ConstantExpression constant, CompoundRhs rhs, arg) {
2704 SourceInformation src = sourceInformationBuilder.buildGet(node);
2705 return translateCompounds(
2706 node,
2707 () {
2708 return buildConstantExpression(constant, src);
2709 },
2710 rhs,
2711 (ir.Primitive value) {
2712 // The binary operator will throw before this.
2713 });
2714 }
2715
2716 @override
2717 ir.Primitive handleTypeLiteralConstantSetIfNulls(
2718 ast.SendSet node, ConstantExpression constant, ast.Node rhs, _) {
2719 // The type literal is never `null`.
2720 return buildConstantExpression(
2721 constant, sourceInformationBuilder.buildGet(node));
2722 }
2723
2724 @override
2725 ir.Primitive handleDynamicCompounds(
2726 ast.SendSet node, ast.Node receiver, Name name, CompoundRhs rhs, arg) {
2727 ir.Primitive target = translateReceiver(receiver);
2728 ir.Primitive helper() {
2729 return translateCompounds(
2730 node,
2731 () {
2732 return irBuilder.buildDynamicGet(
2733 target,
2734 new Selector.getter(name),
2735 elements.getGetterTypeMaskInComplexSendSet(node),
2736 sourceInformationBuilder.buildGet(node));
2737 },
2738 rhs,
2739 (ir.Primitive result) {
2740 irBuilder.buildDynamicSet(
2741 target,
2742 new Selector.setter(name),
2743 elements.getTypeMask(node),
2744 result,
2745 sourceInformationBuilder.buildAssignment(node));
2746 });
2747 }
2748
2749 return node.isConditional
2750 ? irBuilder.buildIfNotNullSend(
2751 target, nested(helper), sourceInformationBuilder.buildIf(node))
2752 : helper();
2753 }
2754
2755 @override
2756 ir.Primitive handleDynamicSetIfNulls(
2757 ast.Send node, ast.Node receiver, Name name, ast.Node rhs, _) {
2758 ir.Primitive target = translateReceiver(receiver);
2759 ir.Primitive helper() {
2760 return translateSetIfNull(
2761 node,
2762 () {
2763 return irBuilder.buildDynamicGet(
2764 target,
2765 new Selector.getter(name),
2766 elements.getGetterTypeMaskInComplexSendSet(node),
2767 sourceInformationBuilder.buildGet(node));
2768 },
2769 rhs,
2770 (ir.Primitive result) {
2771 irBuilder.buildDynamicSet(
2772 target,
2773 new Selector.setter(name),
2774 elements.getTypeMask(node),
2775 result,
2776 sourceInformationBuilder.buildAssignment(node));
2777 });
2778 }
2779
2780 return node.isConditional
2781 ? irBuilder.buildIfNotNullSend(
2782 target, nested(helper), sourceInformationBuilder.buildIf(node))
2783 : helper();
2784 }
2785
2786 ir.Primitive buildLocalNoSuchSetter(LocalElement local, ir.Primitive value,
2787 SourceInformation sourceInformation) {
2788 Selector selector = new Selector.setter(
2789 new Name(local.name, local.library, isSetter: true));
2790 return irBuilder.buildStaticNoSuchMethod(
2791 selector, [value], sourceInformation);
2792 }
2793
2794 @override
2795 ir.Primitive handleLocalCompounds(
2796 ast.SendSet node, LocalElement local, CompoundRhs rhs, arg,
2797 {bool isSetterValid}) {
2798 return translateCompounds(
2799 node,
2800 () {
2801 return irBuilder.buildLocalGet(local);
2802 },
2803 rhs,
2804 (ir.Primitive result) {
2805 if (isSetterValid) {
2806 irBuilder.buildLocalVariableSet(
2807 local, result, sourceInformationBuilder.buildAssignment(node));
2808 } else {
2809 Selector selector = new Selector.setter(
2810 new Name(local.name, local.library, isSetter: true));
2811 irBuilder.buildStaticNoSuchMethod(selector, <ir.Primitive>[result],
2812 sourceInformationBuilder.buildAssignment(node));
2813 }
2814 });
2815 }
2816
2817 @override
2818 ir.Primitive handleLocalSetIfNulls(
2819 ast.SendSet node, LocalElement local, ast.Node rhs, _,
2820 {bool isSetterValid}) {
2821 return translateSetIfNull(
2822 node,
2823 () {
2824 return irBuilder.buildLocalGet(local,
2825 sourceInformation: sourceInformationBuilder.buildGet(node));
2826 },
2827 rhs,
2828 (ir.Primitive result) {
2829 SourceInformation sourceInformation =
2830 sourceInformationBuilder.buildAssignment(node);
2831 if (isSetterValid) {
2832 irBuilder.buildLocalVariableSet(local, result, sourceInformation);
2833 } else {
2834 Selector selector = new Selector.setter(
2835 new Name(local.name, local.library, isSetter: true));
2836 irBuilder.buildStaticNoSuchMethod(
2837 selector, <ir.Primitive>[result], sourceInformation);
2838 }
2839 });
2840 }
2841
2842 @override
2843 ir.Primitive handleStaticCompounds(
2844 ast.SendSet node,
2845 Element getter,
2846 CompoundGetter getterKind,
2847 Element setter,
2848 CompoundSetter setterKind,
2849 CompoundRhs rhs,
2850 arg) {
2851 return translateCompounds(
2852 node,
2853 () {
2854 SourceInformation sourceInformation =
2855 sourceInformationBuilder.buildGet(node);
2856 switch (getterKind) {
2857 case CompoundGetter.FIELD:
2858 return buildStaticFieldGet(getter, sourceInformation);
2859 case CompoundGetter.GETTER:
2860 return buildStaticGetterGet(getter, node, sourceInformation);
2861 case CompoundGetter.METHOD:
2862 return irBuilder.addPrimitive(new ir.GetStatic(getter,
2863 sourceInformation: sourceInformation, isFinal: true));
2864 case CompoundGetter.UNRESOLVED:
2865 return irBuilder.buildStaticNoSuchMethod(
2866 new Selector.getter(new Name(getter.name, getter.library)),
2867 <ir.Primitive>[],
2868 sourceInformation);
2869 }
2870 },
2871 rhs,
2872 (ir.Primitive result) {
2873 SourceInformation sourceInformation =
2874 sourceInformationBuilder.buildAssignment(node);
2875 switch (setterKind) {
2876 case CompoundSetter.FIELD:
2877 irBuilder.addPrimitive(
2878 new ir.SetStatic(setter, result, sourceInformation));
2879 return;
2880 case CompoundSetter.SETTER:
2881 irBuilder.buildStaticSetterSet(setter, result, sourceInformation);
2882 return;
2883 case CompoundSetter.INVALID:
2884 irBuilder.buildStaticNoSuchMethod(
2885 new Selector.setter(new Name(setter.name, setter.library)),
2886 <ir.Primitive>[result],
2887 sourceInformation);
2888 return;
2889 }
2890 });
2891 }
2892
2893 @override
2894 ir.Primitive handleStaticSetIfNulls(
2895 ast.SendSet node,
2896 Element getter,
2897 CompoundGetter getterKind,
2898 Element setter,
2899 CompoundSetter setterKind,
2900 ast.Node rhs,
2901 _) {
2902 return translateSetIfNull(
2903 node,
2904 () {
2905 SourceInformation sourceInformation =
2906 sourceInformationBuilder.buildGet(node);
2907 switch (getterKind) {
2908 case CompoundGetter.FIELD:
2909 return buildStaticFieldGet(getter, sourceInformation);
2910 case CompoundGetter.GETTER:
2911 return buildStaticGetterGet(getter, node, sourceInformation);
2912 case CompoundGetter.METHOD:
2913 return irBuilder.addPrimitive(new ir.GetStatic(getter,
2914 sourceInformation: sourceInformation, isFinal: true));
2915 case CompoundGetter.UNRESOLVED:
2916 return irBuilder.buildStaticNoSuchMethod(
2917 new Selector.getter(new Name(getter.name, getter.library)),
2918 <ir.Primitive>[],
2919 sourceInformation);
2920 }
2921 },
2922 rhs,
2923 (ir.Primitive result) {
2924 SourceInformation sourceInformation =
2925 sourceInformationBuilder.buildAssignment(node);
2926 switch (setterKind) {
2927 case CompoundSetter.FIELD:
2928 irBuilder.addPrimitive(
2929 new ir.SetStatic(setter, result, sourceInformation));
2930 return;
2931 case CompoundSetter.SETTER:
2932 irBuilder.buildStaticSetterSet(setter, result, sourceInformation);
2933 return;
2934 case CompoundSetter.INVALID:
2935 irBuilder.buildStaticNoSuchMethod(
2936 new Selector.setter(new Name(setter.name, setter.library)),
2937 <ir.Primitive>[result],
2938 sourceInformation);
2939 return;
2940 }
2941 });
2942 }
2943
2944 ir.Primitive buildSuperNoSuchGetter(
2945 Element element, TypeMask mask, SourceInformation sourceInformation) {
2946 return buildSuperNoSuchMethod(
2947 new Selector.getter(new Name(element.name, element.library)),
2948 mask,
2949 const <ir.Primitive>[],
2950 sourceInformation);
2951 }
2952
2953 ir.Primitive buildSuperNoSuchSetter(Element element, TypeMask mask,
2954 ir.Primitive value, SourceInformation sourceInformation) {
2955 return buildSuperNoSuchMethod(
2956 new Selector.setter(new Name(element.name, element.library)),
2957 mask,
2958 <ir.Primitive>[value],
2959 sourceInformation);
2960 }
2961
2962 @override
2963 ir.Primitive handleSuperCompounds(
2964 ast.SendSet node,
2965 Element getter,
2966 CompoundGetter getterKind,
2967 Element setter,
2968 CompoundSetter setterKind,
2969 CompoundRhs rhs,
2970 arg) {
2971 return translateCompounds(
2972 node,
2973 () {
2974 switch (getterKind) {
2975 case CompoundGetter.FIELD:
2976 return irBuilder.buildSuperFieldGet(
2977 getter, sourceInformationBuilder.buildGet(node));
2978 case CompoundGetter.GETTER:
2979 return irBuilder.buildSuperGetterGet(
2980 getter, sourceInformationBuilder.buildGet(node));
2981 case CompoundGetter.METHOD:
2982 return irBuilder.buildSuperMethodGet(
2983 getter, sourceInformationBuilder.buildGet(node));
2984 case CompoundGetter.UNRESOLVED:
2985 return buildSuperNoSuchGetter(
2986 getter,
2987 elements.getGetterTypeMaskInComplexSendSet(node),
2988 sourceInformationBuilder.buildGet(node));
2989 }
2990 },
2991 rhs,
2992 (ir.Primitive result) {
2993 switch (setterKind) {
2994 case CompoundSetter.FIELD:
2995 irBuilder.buildSuperFieldSet(setter, result,
2996 sourceInformationBuilder.buildAssignment(node));
2997 return;
2998 case CompoundSetter.SETTER:
2999 irBuilder.buildSuperSetterSet(setter, result,
3000 sourceInformationBuilder.buildAssignment(node));
3001 return;
3002 case CompoundSetter.INVALID:
3003 buildSuperNoSuchSetter(setter, elements.getTypeMask(node), result,
3004 sourceInformationBuilder.buildAssignment(node));
3005 return;
3006 }
3007 });
3008 }
3009
3010 @override
3011 ir.Primitive handleSuperSetIfNulls(
3012 ast.SendSet node,
3013 Element getter,
3014 CompoundGetter getterKind,
3015 Element setter,
3016 CompoundSetter setterKind,
3017 ast.Node rhs,
3018 _) {
3019 return translateSetIfNull(
3020 node,
3021 () {
3022 switch (getterKind) {
3023 case CompoundGetter.FIELD:
3024 return irBuilder.buildSuperFieldGet(
3025 getter, sourceInformationBuilder.buildGet(node));
3026 case CompoundGetter.GETTER:
3027 return irBuilder.buildSuperGetterGet(
3028 getter, sourceInformationBuilder.buildGet(node));
3029 case CompoundGetter.METHOD:
3030 return irBuilder.buildSuperMethodGet(
3031 getter, sourceInformationBuilder.buildGet(node));
3032 case CompoundGetter.UNRESOLVED:
3033 return buildSuperNoSuchGetter(
3034 getter,
3035 elements.getGetterTypeMaskInComplexSendSet(node),
3036 sourceInformationBuilder.buildGet(node));
3037 }
3038 },
3039 rhs,
3040 (ir.Primitive result) {
3041 switch (setterKind) {
3042 case CompoundSetter.FIELD:
3043 irBuilder.buildSuperFieldSet(setter, result,
3044 sourceInformationBuilder.buildAssignment(node));
3045 return;
3046 case CompoundSetter.SETTER:
3047 irBuilder.buildSuperSetterSet(setter, result,
3048 sourceInformationBuilder.buildAssignment(node));
3049 return;
3050 case CompoundSetter.INVALID:
3051 buildSuperNoSuchSetter(setter, elements.getTypeMask(node), result,
3052 sourceInformationBuilder.buildAssignment(node));
3053 return;
3054 }
3055 });
3056 }
3057
3058 @override
3059 ir.Primitive handleTypeVariableTypeLiteralCompounds(ast.SendSet node,
3060 TypeVariableElement typeVariable, CompoundRhs rhs, arg) {
3061 return translateCompounds(
3062 node,
3063 () {
3064 return irBuilder.buildReifyTypeVariable(
3065 typeVariable.type, sourceInformationBuilder.buildGet(node));
3066 },
3067 rhs,
3068 (ir.Primitive value) {
3069 // The binary operator will throw before this.
3070 });
3071 }
3072
3073 @override
3074 ir.Primitive visitTypeVariableTypeLiteralSetIfNull(
3075 ast.Send node, TypeVariableElement element, ast.Node rhs, _) {
3076 // The type variable is never `null`.
3077 return translateTypeVariableTypeLiteral(
3078 element, sourceInformationBuilder.buildGet(node));
3079 }
3080
3081 @override
3082 ir.Primitive handleIndexCompounds(ast.SendSet node, ast.Node receiver,
3083 ast.Node index, CompoundRhs rhs, arg) {
3084 ir.Primitive target = visit(receiver);
3085 ir.Primitive indexValue = visit(index);
3086 return translateCompounds(
3087 node,
3088 () {
3089 Selector selector = new Selector.index();
3090 List<ir.Primitive> arguments = <ir.Primitive>[indexValue];
3091 CallStructure callStructure =
3092 normalizeDynamicArguments(selector.callStructure, arguments);
3093 return irBuilder.buildDynamicInvocation(
3094 target,
3095 new Selector(selector.kind, selector.memberName, callStructure),
3096 elements.getGetterTypeMaskInComplexSendSet(node),
3097 arguments,
3098 sourceInformationBuilder.buildCall(receiver, node));
3099 },
3100 rhs,
3101 (ir.Primitive result) {
3102 irBuilder.buildDynamicIndexSet(target, elements.getTypeMask(node),
3103 indexValue, result, sourceInformationBuilder.buildIndexSet(node));
3104 });
3105 }
3106
3107 @override
3108 ir.Primitive handleSuperIndexCompounds(
3109 ast.SendSet node,
3110 Element indexFunction,
3111 Element indexSetFunction,
3112 ast.Node index,
3113 CompoundRhs rhs,
3114 arg,
3115 {bool isGetterValid,
3116 bool isSetterValid}) {
3117 ir.Primitive indexValue = visit(index);
3118 return translateCompounds(
3119 node,
3120 () {
3121 if (isGetterValid) {
3122 return irBuilder.buildSuperIndex(indexFunction, indexValue,
3123 sourceInformationBuilder.buildIndex(node));
3124 } else {
3125 return buildSuperNoSuchMethod(
3126 new Selector.index(),
3127 elements.getGetterTypeMaskInComplexSendSet(node),
3128 <ir.Primitive>[indexValue],
3129 sourceInformationBuilder.buildIndex(node));
3130 }
3131 },
3132 rhs,
3133 (ir.Primitive result) {
3134 if (isSetterValid) {
3135 irBuilder.buildSuperIndexSet(indexSetFunction, indexValue, result,
3136 sourceInformationBuilder.buildIndexSet(node));
3137 } else {
3138 buildSuperNoSuchMethod(
3139 new Selector.indexSet(),
3140 elements.getTypeMask(node),
3141 <ir.Primitive>[indexValue, result],
3142 sourceInformationBuilder.buildIndexSet(node));
3143 }
3144 });
3145 }
3146
3147 /// Build code to handle foreign code, that is, native JavaScript code, or
3148 /// builtin values and operations of the backend.
3149 ir.Primitive handleForeignCode(ast.Send node, MethodElement function,
3150 ast.NodeList argumentList, CallStructure callStructure) {
3151 void validateArgumentCount({int minimum, int exactly}) {
3152 assert((minimum == null) != (exactly == null));
3153 int count = 0;
3154 int maximum;
3155 if (exactly != null) {
3156 minimum = exactly;
3157 maximum = exactly;
3158 }
3159 for (ast.Node argument in argumentList) {
3160 count++;
3161 if (maximum != null && count > maximum) {
3162 internalError(argument, 'Additional argument.');
3163 }
3164 }
3165 if (count < minimum) {
3166 internalError(node, 'Expected at least $minimum arguments.');
3167 }
3168 }
3169
3170 /// Call a helper method from the isolate library. The isolate library uses
3171 /// its own isolate structure, that encapsulates dart2js's isolate.
3172 ir.Primitive buildIsolateHelperInvocation(
3173 MethodElement element, CallStructure callStructure) {
3174 if (element == null) {
3175 reporter.internalError(node, 'Isolate library and compiler mismatch.');
3176 }
3177 List<ir.Primitive> arguments = <ir.Primitive>[];
3178 callStructure = translateStaticArguments(
3179 argumentList, element, callStructure, arguments);
3180 Selector selector = new Selector.call(element.memberName, callStructure);
3181 return irBuilder.buildInvokeStatic(element, selector, arguments,
3182 sourceInformationBuilder.buildCall(node, node.selector));
3183 }
3184
3185 /// Lookup the value of the enum described by [node].
3186 getEnumValue(ast.Node node, EnumClassElement enumClass, List values) {
3187 Element element = elements[node];
3188 if (element is! EnumConstantElement ||
3189 element.enclosingClass != enumClass) {
3190 internalError(node, 'expected a JsBuiltin enum value');
3191 }
3192 EnumConstantElement enumConstant = element;
3193 int index = enumConstant.index;
3194 return values[index];
3195 }
3196
3197 /// Returns the String the node evaluates to, or throws an error if the
3198 /// result is not a string constant.
3199 String expectStringConstant(ast.Node node) {
3200 ir.Primitive nameValue = visit(node);
3201 if (nameValue is ir.Constant && nameValue.value.isString) {
3202 StringConstantValue constantValue = nameValue.value;
3203 return constantValue.primitiveValue.slowToString();
3204 } else {
3205 return internalError(node, 'expected a literal string');
3206 }
3207 }
3208
3209 Link<ast.Node> argumentNodes = argumentList.nodes;
3210 NativeBehavior behavior = elements.getNativeData(node);
3211 switch (function.name) {
3212 case 'JS':
3213 validateArgumentCount(minimum: 2);
3214 // The first two arguments are the type and the foreign code template,
3215 // which already have been analyzed by the resolver and can be retrieved
3216 // using [NativeBehavior]. We can ignore these arguments in the backend.
3217 List<ir.Primitive> arguments =
3218 argumentNodes.skip(2).mapToList(visit, growable: false);
3219 if (behavior.codeTemplate.positionalArgumentCount != arguments.length) {
3220 reporter.reportErrorMessage(node, MessageKind.GENERIC, {
3221 'text': 'Mismatch between number of placeholders'
3222 ' and number of arguments.'
3223 });
3224 return irBuilder.buildNullConstant();
3225 }
3226
3227 if (HasCapturedPlaceholders.check(behavior.codeTemplate.ast)) {
3228 reporter.reportErrorMessage(node, MessageKind.JS_PLACEHOLDER_CAPTURE);
3229 return irBuilder.buildNullConstant();
3230 }
3231
3232 return irBuilder.buildForeignCode(behavior.codeTemplate, arguments,
3233 behavior, sourceInformationBuilder.buildForeignCode(node));
3234
3235 case 'DART_CLOSURE_TO_JS':
3236 // TODO(ahe): This should probably take care to wrap the closure in
3237 // another closure that saves the current isolate.
3238 case 'RAW_DART_FUNCTION_REF':
3239 validateArgumentCount(exactly: 1);
3240
3241 ast.Node argument = node.arguments.single;
3242 FunctionElement closure = elements[argument].implementation;
3243 if (!Elements.isStaticOrTopLevelFunction(closure)) {
3244 internalError(argument, 'only static or toplevel function supported');
3245 }
3246 if (closure.functionSignature.hasOptionalParameters) {
3247 internalError(
3248 argument, 'closures with optional parameters not supported');
3249 }
3250 return irBuilder.buildForeignCode(
3251 js.js.expressionTemplateYielding(
3252 backend.emitter.staticFunctionAccess(closure)),
3253 <ir.Primitive>[],
3254 NativeBehavior.PURE,
3255 sourceInformationBuilder.buildForeignCode(node),
3256 dependency: closure);
3257
3258 case 'JS_BUILTIN':
3259 // The first argument is a description of the type and effect of the
3260 // builtin, which has already been analyzed in the frontend. The second
3261 // argument must be a [JsBuiltin] value. All other arguments are
3262 // values used by the JavaScript template that is associated with the
3263 // builtin.
3264 validateArgumentCount(minimum: 2);
3265
3266 ast.Node builtin = argumentNodes.tail.head;
3267 JsBuiltin value =
3268 getEnumValue(builtin, helpers.jsBuiltinEnum, JsBuiltin.values);
3269 js.Template template = backend.emitter.builtinTemplateFor(value);
3270 List<ir.Primitive> arguments =
3271 argumentNodes.skip(2).mapToList(visit, growable: false);
3272 return irBuilder.buildForeignCode(template, arguments, behavior,
3273 sourceInformationBuilder.buildForeignCode(node));
3274
3275 case 'JS_EMBEDDED_GLOBAL':
3276 validateArgumentCount(exactly: 2);
3277
3278 String name = expectStringConstant(argumentNodes.tail.head);
3279 js.Expression access =
3280 backend.emitter.generateEmbeddedGlobalAccess(name);
3281 js.Template template = js.js.expressionTemplateYielding(access);
3282 return irBuilder.buildForeignCode(template, <ir.Primitive>[], behavior,
3283 sourceInformationBuilder.buildForeignCode(node));
3284
3285 case 'JS_INTERCEPTOR_CONSTANT':
3286 validateArgumentCount(exactly: 1);
3287
3288 ast.Node argument = argumentNodes.head;
3289 ir.Primitive argumentValue = visit(argument);
3290 if (argumentValue is ir.Constant && argumentValue.value.isType) {
3291 TypeConstantValue constant = argumentValue.value;
3292 ConstantValue interceptorValue =
3293 new InterceptorConstantValue(constant.representedType);
3294 return irBuilder.buildConstant(interceptorValue);
3295 }
3296 return internalError(argument, 'expected Type as argument');
3297
3298 case 'JS_EFFECT':
3299 return irBuilder.buildNullConstant();
3300
3301 case 'JS_GET_NAME':
3302 validateArgumentCount(exactly: 1);
3303
3304 ast.Node argument = argumentNodes.head;
3305 JsGetName id =
3306 getEnumValue(argument, helpers.jsGetNameEnum, JsGetName.values);
3307 js.Name name = backend.namer.getNameForJsGetName(argument, id);
3308 ConstantValue nameConstant = new SyntheticConstantValue(
3309 SyntheticConstantKind.NAME, js.js.quoteName(name));
3310
3311 return irBuilder.buildConstant(nameConstant);
3312
3313 case 'JS_GET_FLAG':
3314 validateArgumentCount(exactly: 1);
3315
3316 String name = expectStringConstant(argumentNodes.first);
3317 bool value = false;
3318 switch (name) {
3319 case 'MUST_RETAIN_METADATA':
3320 value = backend.mustRetainMetadata;
3321 break;
3322 case 'USE_CONTENT_SECURITY_POLICY':
3323 value = compiler.options.useContentSecurityPolicy;
3324 break;
3325 default:
3326 internalError(node, 'Unknown internal flag "$name".');
3327 }
3328 return irBuilder.buildBooleanConstant(value);
3329
3330 case 'JS_STRING_CONCAT':
3331 validateArgumentCount(exactly: 2);
3332 List<ir.Primitive> arguments = argumentNodes.mapToList(visit);
3333 return irBuilder.buildStringConcatenation(
3334 arguments, sourceInformationBuilder.buildForeignCode(node));
3335
3336 case 'JS_CURRENT_ISOLATE_CONTEXT':
3337 validateArgumentCount(exactly: 0);
3338
3339 if (!compiler.hasIsolateSupport) {
3340 // If the isolate library is not used, we just generate code
3341 // to fetch the current isolate.
3342 continue getStaticState;
3343 }
3344 return buildIsolateHelperInvocation(
3345 helpers.currentIsolate, CallStructure.NO_ARGS);
3346
3347 getStaticState:
3348 case 'JS_GET_STATIC_STATE':
3349 validateArgumentCount(exactly: 0);
3350
3351 return irBuilder.buildForeignCode(
3352 js.js.parseForeignJS(backend.namer.staticStateHolder),
3353 const <ir.Primitive>[],
3354 NativeBehavior.DEPENDS_OTHER,
3355 sourceInformationBuilder.buildForeignCode(node));
3356
3357 case 'JS_SET_STATIC_STATE':
3358 validateArgumentCount(exactly: 1);
3359
3360 ir.Primitive value = visit(argumentNodes.single);
3361 String isolateName = backend.namer.staticStateHolder;
3362 return irBuilder.buildForeignCode(
3363 js.js.parseForeignJS("$isolateName = #"),
3364 <ir.Primitive>[value],
3365 NativeBehavior.CHANGES_OTHER,
3366 sourceInformationBuilder.buildForeignCode(node));
3367
3368 case 'JS_CALL_IN_ISOLATE':
3369 validateArgumentCount(exactly: 2);
3370
3371 if (!compiler.hasIsolateSupport) {
3372 ir.Primitive closure = visit(argumentNodes.tail.head);
3373 return irBuilder.buildCallInvocation(
3374 closure,
3375 CallStructure.NO_ARGS,
3376 const <ir.Primitive>[],
3377 sourceInformationBuilder.buildForeignCode(node));
3378 }
3379 return buildIsolateHelperInvocation(
3380 helpers.callInIsolate, CallStructure.TWO_ARGS);
3381
3382 default:
3383 return giveup(node, 'unplemented native construct: ${function.name}');
3384 }
3385 }
3386
3387 /// Evaluates a string interpolation and appends each part to [accumulator]
3388 /// (after stringify conversion).
3389 void buildStringParts(ast.Node node, List<ir.Primitive> accumulator) {
3390 if (node is ast.StringJuxtaposition) {
3391 buildStringParts(node.first, accumulator);
3392 buildStringParts(node.second, accumulator);
3393 } else if (node is ast.StringInterpolation) {
3394 buildStringParts(node.string, accumulator);
3395 for (ast.StringInterpolationPart part in node.parts) {
3396 buildStringParts(part.expression, accumulator);
3397 buildStringParts(part.string, accumulator);
3398 }
3399 } else if (node is ast.LiteralString) {
3400 // Empty strings often occur at the end of a string interpolation,
3401 // do not bother to include them.
3402 if (!node.dartString.isEmpty) {
3403 accumulator.add(irBuilder.buildDartStringConstant(node.dartString));
3404 }
3405 } else if (node is ast.ParenthesizedExpression) {
3406 buildStringParts(node.expression, accumulator);
3407 } else {
3408 ir.Primitive value = visit(node);
3409 accumulator.add(irBuilder.buildStaticFunctionInvocation(
3410 helpers.stringInterpolationHelper,
3411 <ir.Primitive>[value],
3412 sourceInformationBuilder.buildStringInterpolation(node)));
3413 }
3414 }
3415
3416 ir.Primitive visitStringJuxtaposition(ast.StringJuxtaposition node) {
3417 assert(irBuilder.isOpen);
3418 List<ir.Primitive> parts = <ir.Primitive>[];
3419 buildStringParts(node, parts);
3420 return irBuilder.buildStringConcatenation(
3421 parts, sourceInformationBuilder.buildStringInterpolation(node));
3422 }
3423
3424 ir.Primitive visitStringInterpolation(ast.StringInterpolation node) {
3425 assert(irBuilder.isOpen);
3426 List<ir.Primitive> parts = <ir.Primitive>[];
3427 buildStringParts(node, parts);
3428 return irBuilder.buildStringConcatenation(
3429 parts, sourceInformationBuilder.buildStringInterpolation(node));
3430 }
3431
3432 ir.Primitive translateConstant(ast.Node node) {
3433 assert(irBuilder.isOpen);
3434 return irBuilder.buildConstant(getConstantForNode(node),
3435 sourceInformation: sourceInformationBuilder.buildGet(node));
3436 }
3437
3438 ir.Primitive visitThrow(ast.Throw node) {
3439 assert(irBuilder.isOpen);
3440 // This function is not called for throw expressions occurring as
3441 // statements.
3442 return irBuilder.buildNonTailThrow(visit(node.expression));
3443 }
3444
3445 ir.Primitive buildSuperNoSuchMethod(Selector selector, TypeMask mask,
3446 List<ir.Primitive> arguments, SourceInformation sourceInformation) {
3447 ClassElement cls = elements.analyzedElement.enclosingClass;
3448 MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_);
3449 if (!Selectors.noSuchMethod_.signatureApplies(element)) {
3450 element = compiler.coreClasses.objectClass
3451 .lookupMember(Identifiers.noSuchMethod_);
3452 }
3453 return irBuilder.buildSuperMethodInvocation(
3454 element,
3455 Selectors.noSuchMethod_.callStructure,
3456 [irBuilder.buildInvocationMirror(selector, arguments)],
3457 sourceInformation);
3458 }
3459
3460 @override
3461 ir.Primitive visitUnresolvedCompound(ast.Send node, Element element,
3462 op.AssignmentOperator operator, ast.Node rhs, _) {
3463 return irBuilder.buildStaticNoSuchMethod(
3464 new Selector.getter(new Name(element.name, element.library)),
3465 [],
3466 sourceInformationBuilder.buildGet(node));
3467 }
3468
3469 @override
3470 ir.Primitive visitUnresolvedClassConstructorInvoke(
3471 ast.NewExpression node,
3472 Element element,
3473 DartType type,
3474 ast.NodeList arguments,
3475 Selector selector,
3476 _) {
3477 // If the class is missing it's a runtime error.
3478 ir.Primitive message =
3479 irBuilder.buildStringConstant("Unresolved class: '${element.name}'");
3480 return irBuilder.buildStaticFunctionInvocation(helpers.throwRuntimeError,
3481 <ir.Primitive>[message], sourceInformationBuilder.buildNew(node));
3482 }
3483
3484 @override
3485 ir.Primitive visitUnresolvedConstructorInvoke(
3486 ast.NewExpression node,
3487 Element constructor,
3488 DartType type,
3489 ast.NodeList argumentsNode,
3490 Selector selector,
3491 _) {
3492 // If the class is there but the constructor is missing, it's an NSM error.
3493 List<ir.Primitive> arguments = <ir.Primitive>[];
3494 CallStructure callStructure = translateDynamicArguments(
3495 argumentsNode, selector.callStructure, arguments);
3496 return irBuilder.buildStaticNoSuchMethod(
3497 new Selector(selector.kind, selector.memberName, callStructure),
3498 arguments,
3499 sourceInformationBuilder.buildNew(node));
3500 }
3501
3502 @override
3503 ir.Primitive visitConstructorIncompatibleInvoke(
3504 ast.NewExpression node,
3505 ConstructorElement constructor,
3506 DartType type,
3507 ast.NodeList argumentsNode,
3508 CallStructure callStructure,
3509 _) {
3510 List<ir.Primitive> arguments = <ir.Primitive>[];
3511 callStructure =
3512 translateDynamicArguments(argumentsNode, callStructure, arguments);
3513 return irBuilder.buildStaticNoSuchMethod(
3514 new Selector.call(constructor.memberName, callStructure),
3515 arguments,
3516 sourceInformationBuilder.buildNew(node));
3517 }
3518
3519 @override
3520 ir.Primitive visitUnresolvedGet(ast.Send node, Element element, _) {
3521 return irBuilder.buildStaticNoSuchMethod(elements.getSelector(node), [],
3522 sourceInformationBuilder.buildGet(node));
3523 }
3524
3525 @override
3526 ir.Primitive visitUnresolvedInvoke(ast.Send node, Element element,
3527 ast.NodeList arguments, Selector selector, _) {
3528 return irBuilder.buildStaticNoSuchMethod(
3529 elements.getSelector(node),
3530 arguments.nodes.mapToList(visit),
3531 sourceInformationBuilder.buildCall(node, node.selector));
3532 }
3533
3534 @override
3535 ir.Primitive visitUnresolvedRedirectingFactoryConstructorInvoke(
3536 ast.NewExpression node,
3537 ConstructorElement constructor,
3538 InterfaceType type,
3539 ast.NodeList argumentsNode,
3540 CallStructure callStructure,
3541 _) {
3542 String nameString = Elements.reconstructConstructorName(constructor);
3543 Name name = new Name(nameString, constructor.library);
3544 List<ir.Primitive> arguments = <ir.Primitive>[];
3545 callStructure =
3546 translateDynamicArguments(argumentsNode, callStructure, arguments);
3547 return irBuilder.buildStaticNoSuchMethod(
3548 new Selector.call(name, callStructure),
3549 arguments,
3550 sourceInformationBuilder.buildNew(node));
3551 }
3552
3553 @override
3554 ir.Primitive visitUnresolvedSet(
3555 ast.Send node, Element element, ast.Node rhs, _) {
3556 return irBuilder.buildStaticNoSuchMethod(elements.getSelector(node),
3557 [visit(rhs)], sourceInformationBuilder.buildAssignment(node));
3558 }
3559
3560 @override
3561 ir.Primitive visitUnresolvedSuperIndex(
3562 ast.Send node, Element function, ast.Node index, _) {
3563 // Assume the index getter is missing.
3564 return buildSuperNoSuchMethod(
3565 new Selector.index(),
3566 elements.getTypeMask(node),
3567 [visit(index)],
3568 sourceInformationBuilder.buildIndex(node));
3569 }
3570
3571 @override
3572 ir.Primitive visitUnresolvedSuperBinary(ast.Send node, Element element,
3573 op.BinaryOperator operator, ast.Node argument, _) {
3574 return buildSuperNoSuchMethod(
3575 elements.getSelector(node),
3576 elements.getTypeMask(node),
3577 [visit(argument)],
3578 sourceInformationBuilder.buildCall(node, node.selector));
3579 }
3580
3581 @override
3582 ir.Primitive visitUnresolvedSuperUnary(
3583 ast.Send node, op.UnaryOperator operator, Element element, _) {
3584 return buildSuperNoSuchMethod(
3585 elements.getSelector(node),
3586 elements.getTypeMask(node),
3587 [],
3588 sourceInformationBuilder.buildCall(node, node.selector));
3589 }
3590
3591 @override
3592 ir.Primitive bulkHandleNode(ast.Node node, String message, _) {
3593 return giveup(node, "Unhandled node: ${message.replaceAll('#', '$node')}");
3594 }
3595
3596 @override
3597 ir.Primitive bulkHandleError(ast.Node node, ErroneousElement error, _) {
3598 return irBuilder.buildNullConstant();
3599 }
3600
3601 @override
3602 ir.Primitive visitClassTypeLiteralSet(
3603 ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) {
3604 InterfaceType type = constant.type;
3605 ClassElement element = type.element;
3606 return irBuilder.buildStaticNoSuchMethod(
3607 new Selector.setter(element.memberName),
3608 [visit(rhs)],
3609 sourceInformationBuilder.buildAssignment(node));
3610 }
3611
3612 @override
3613 ir.Primitive visitTypedefTypeLiteralSet(
3614 ast.SendSet node, TypeConstantExpression constant, ast.Node rhs, _) {
3615 TypedefType type = constant.type;
3616 TypedefElement element = type.element;
3617 return irBuilder.buildStaticNoSuchMethod(
3618 new Selector.setter(element.memberName),
3619 [visit(rhs)],
3620 sourceInformationBuilder.buildAssignment(node));
3621 }
3622
3623 @override
3624 ir.Primitive visitTypeVariableTypeLiteralSet(
3625 ast.SendSet node, TypeVariableElement element, ast.Node rhs, _) {
3626 return irBuilder.buildStaticNoSuchMethod(
3627 new Selector.setter(element.memberName),
3628 [visit(rhs)],
3629 sourceInformationBuilder.buildAssignment(node));
3630 }
3631
3632 @override
3633 ir.Primitive visitDynamicTypeLiteralSet(
3634 ast.SendSet node, ConstantExpression constant, ast.Node rhs, _) {
3635 return irBuilder.buildStaticNoSuchMethod(
3636 new Selector.setter(Names.dynamic_),
3637 [visit(rhs)],
3638 sourceInformationBuilder.buildAssignment(node));
3639 }
3640
3641 @override
3642 ir.Primitive visitAbstractClassConstructorInvoke(
3643 ast.NewExpression node,
3644 ConstructorElement element,
3645 InterfaceType type,
3646 ast.NodeList arguments,
3647 CallStructure callStructure,
3648 _) {
3649 for (ast.Node argument in arguments) visit(argument);
3650 ir.Primitive name =
3651 irBuilder.buildStringConstant(element.enclosingClass.name);
3652 return irBuilder.buildStaticFunctionInvocation(
3653 helpers.throwAbstractClassInstantiationError,
3654 <ir.Primitive>[name],
3655 sourceInformationBuilder.buildNew(node));
3656 }
3657
3658 @override
3659 ir.Primitive handleFinalStaticFieldSet(
3660 ast.SendSet node, FieldElement field, ast.Node rhs, _) {
3661 // TODO(asgerf): Include class name somehow for static class members?
3662 return irBuilder.buildStaticNoSuchMethod(
3663 new Selector.setter(field.memberName),
3664 [visit(rhs)],
3665 sourceInformationBuilder.buildAssignment(node));
3666 }
3667
3668 @override
3669 ir.Primitive visitFinalSuperFieldSet(
3670 ast.SendSet node, FieldElement field, ast.Node rhs, _) {
3671 return buildSuperNoSuchMethod(
3672 new Selector.setter(field.memberName),
3673 elements.getTypeMask(node),
3674 [visit(rhs)],
3675 sourceInformationBuilder.buildAssignment(node));
3676 }
3677
3678 @override
3679 ir.Primitive handleImmutableLocalSet(
3680 ast.SendSet node, LocalElement local, ast.Node rhs, _) {
3681 return irBuilder.buildStaticNoSuchMethod(
3682 new Selector.setter(new Name(local.name, local.library)),
3683 [visit(rhs)],
3684 sourceInformationBuilder.buildAssignment(node));
3685 }
3686
3687 @override
3688 ir.Primitive handleStaticFunctionSet(
3689 ast.Send node, MethodElement function, ast.Node rhs, _) {
3690 return irBuilder.buildStaticNoSuchMethod(
3691 new Selector.setter(function.memberName),
3692 [visit(rhs)],
3693 sourceInformationBuilder.buildAssignment(node));
3694 }
3695
3696 @override
3697 ir.Primitive handleStaticGetterSet(
3698 ast.SendSet node, GetterElement getter, ast.Node rhs, _) {
3699 return irBuilder.buildStaticNoSuchMethod(
3700 new Selector.setter(getter.memberName),
3701 [visit(rhs)],
3702 sourceInformationBuilder.buildAssignment(node));
3703 }
3704
3705 @override
3706 ir.Primitive handleStaticSetterGet(ast.Send node, SetterElement setter, _) {
3707 return irBuilder.buildStaticNoSuchMethod(
3708 new Selector.getter(setter.memberName),
3709 [],
3710 sourceInformationBuilder.buildGet(node));
3711 }
3712
3713 @override
3714 ir.Primitive handleStaticSetterInvoke(ast.Send node, SetterElement setter,
3715 ast.NodeList argumentsNode, CallStructure callStructure, _) {
3716 // Translate as a method call.
3717 List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit);
3718 return irBuilder.buildStaticNoSuchMethod(
3719 new Selector.call(setter.memberName, callStructure),
3720 arguments,
3721 sourceInformationBuilder.buildCall(node, argumentsNode));
3722 }
3723
3724 @override
3725 ir.Primitive visitSuperGetterSet(
3726 ast.SendSet node, GetterElement getter, ast.Node rhs, _) {
3727 return buildSuperNoSuchMethod(
3728 new Selector.setter(getter.memberName),
3729 elements.getTypeMask(node),
3730 [visit(rhs)],
3731 sourceInformationBuilder.buildAssignment(node));
3732 }
3733
3734 @override
3735 ir.Primitive visitSuperMethodSet(
3736 ast.Send node, MethodElement method, ast.Node rhs, _) {
3737 return buildSuperNoSuchMethod(
3738 new Selector.setter(method.memberName),
3739 elements.getTypeMask(node),
3740 [visit(rhs)],
3741 sourceInformationBuilder.buildAssignment(node));
3742 }
3743
3744 @override
3745 ir.Primitive visitSuperSetterGet(ast.Send node, SetterElement setter, _) {
3746 return buildSuperNoSuchMethod(
3747 new Selector.getter(setter.memberName),
3748 elements.getTypeMask(node),
3749 [],
3750 sourceInformationBuilder.buildGet(node));
3751 }
3752
3753 @override
3754 ir.Primitive visitSuperSetterInvoke(ast.Send node, SetterElement setter,
3755 ast.NodeList argumentsNode, CallStructure callStructure, _) {
3756 List<ir.Primitive> arguments = <ir.Primitive>[];
3757 callStructure =
3758 translateDynamicArguments(argumentsNode, callStructure, arguments);
3759 return buildSuperNoSuchMethod(
3760 new Selector.call(setter.memberName, callStructure),
3761 elements.getTypeMask(node),
3762 arguments,
3763 sourceInformationBuilder.buildCall(node, argumentsNode));
3764 }
3765
3766 ir.FunctionDefinition nullIfGiveup(ir.FunctionDefinition action()) {
3767 try {
3768 return action();
3769 } catch (e) {
3770 if (e == ABORT_IRNODE_BUILDER) {
3771 return null;
3772 }
3773 rethrow;
3774 }
3775 }
3776
3777 internalError(ast.Node node, String message) {
3778 reporter.internalError(node, message);
3779 }
3780
3781 @override
3782 visitNode(ast.Node node) {
3783 giveup(node, "Unhandled node");
3784 }
3785
3786 dynamic giveup(ast.Node node, [String reason]) {
3787 bailoutMessage = '($node): $reason';
3788 throw ABORT_IRNODE_BUILDER;
3789 }
3790 }
3791
3792 final String ABORT_IRNODE_BUILDER = "IrNode builder aborted";
3793
3794 /// Determines which local variables should be boxed in a mutable variable
3795 /// inside a given try block.
3796 class TryBoxedVariables extends ast.Visitor {
3797 final TreeElements elements;
3798 TryBoxedVariables(this.elements);
3799
3800 FunctionElement currentFunction;
3801 bool insideInitializer = false;
3802 Set<Local> capturedVariables = new Set<Local>();
3803
3804 /// A map containing variables boxed inside try blocks.
3805 ///
3806 /// The map is keyed by the [NodeList] of catch clauses for try/catch and
3807 /// by the finally block for try/finally. try/catch/finally is treated
3808 /// as a try/catch nested in the try block of a try/finally.
3809 Map<ast.Node, TryStatementInfo> tryStatements =
3810 <ast.Node, TryStatementInfo>{};
3811
3812 List<TryStatementInfo> tryNestingStack = <TryStatementInfo>[];
3813 bool get inTryStatement => tryNestingStack.isNotEmpty;
3814
3815 String bailoutMessage = null;
3816
3817 giveup(ast.Node node, [String reason]) {
3818 bailoutMessage = '($node): $reason';
3819 throw ABORT_IRNODE_BUILDER;
3820 }
3821
3822 void markAsCaptured(Local local) {
3823 capturedVariables.add(local);
3824 }
3825
3826 analyze(ast.Node node) {
3827 visit(node);
3828 // Variables that are captured by a closure are boxed for their entire
3829 // lifetime, so they never need to be boxed on entry to a try block.
3830 // They are not filtered out before this because we cannot identify all
3831 // of them in the same pass (they may be captured by a closure after the
3832 // try statement).
3833 for (TryStatementInfo info in tryStatements.values) {
3834 info.boxedOnEntry.removeAll(capturedVariables);
3835 }
3836 }
3837
3838 visit(ast.Node node) => node.accept(this);
3839
3840 visitNode(ast.Node node) {
3841 node.visitChildren(this);
3842 }
3843
3844 void handleSend(ast.Send node) {
3845 Element element = elements[node];
3846 if (Elements.isLocal(element) &&
3847 !element.isConst &&
3848 element.enclosingElement != currentFunction) {
3849 LocalElement local = element;
3850 markAsCaptured(local);
3851 }
3852 }
3853
3854 visitSend(ast.Send node) {
3855 handleSend(node);
3856 node.visitChildren(this);
3857 }
3858
3859 visitSendSet(ast.SendSet node) {
3860 handleSend(node);
3861 Element element = elements[node];
3862 if (Elements.isLocal(element)) {
3863 LocalElement local = element;
3864 if (insideInitializer &&
3865 (local.isRegularParameter || local.isInitializingFormal) &&
3866 local.enclosingElement == currentFunction) {
3867 assert(local.enclosingElement.isConstructor);
3868 // Initializers in an initializer-list can communicate via parameters.
3869 // If a parameter is stored in an initializer list we box it.
3870 // TODO(sigurdm): Fix this.
3871 // Though these variables do not outlive the activation of the
3872 // function, they still need to be boxed. As a simplification, we
3873 // treat them as if they are captured by a closure (i.e., they do
3874 // outlive the activation of the function).
3875 markAsCaptured(local);
3876 } else if (inTryStatement) {
3877 assert(local.isRegularParameter ||
3878 local.isVariable ||
3879 local.isInitializingFormal);
3880 // Search for the position of the try block containing the variable
3881 // declaration, or -1 if it is declared outside the outermost try.
3882 int i = tryNestingStack.length - 1;
3883 while (i >= 0 && !tryNestingStack[i].declared.contains(local)) {
3884 --i;
3885 }
3886 // If there is a next inner try, then the variable should be boxed on
3887 // entry to it.
3888 if (i + 1 < tryNestingStack.length) {
3889 tryNestingStack[i + 1].boxedOnEntry.add(local);
3890 }
3891 }
3892 }
3893 node.visitChildren(this);
3894 }
3895
3896 visitFunctionExpression(ast.FunctionExpression node) {
3897 FunctionElement savedFunction = currentFunction;
3898 currentFunction = elements[node];
3899
3900 if (currentFunction.asyncMarker != AsyncMarker.SYNC &&
3901 currentFunction.asyncMarker != AsyncMarker.SYNC_STAR &&
3902 currentFunction.asyncMarker != AsyncMarker.ASYNC) {
3903 giveup(node, "cannot handle async* functions");
3904 }
3905
3906 if (node.initializers != null) {
3907 visit(node.initializers);
3908 }
3909 visit(node.body);
3910 currentFunction = savedFunction;
3911 }
3912
3913 visitTryStatement(ast.TryStatement node) {
3914 // Try/catch/finally is treated as two simpler constructs: try/catch and
3915 // try/finally. The encoding is:
3916 //
3917 // try S0 catch (ex, st) S1 finally S2
3918 // ==>
3919 // try { try S0 catch (ex, st) S1 } finally S2
3920 //
3921 // The analysis associates variables assigned in S0 with the catch clauses
3922 // and variables assigned in S0 and S1 with the finally block.
3923 TryStatementInfo enterTryFor(ast.Node node) {
3924 TryStatementInfo info = new TryStatementInfo();
3925 tryStatements[node] = info;
3926 tryNestingStack.add(info);
3927 return info;
3928 }
3929
3930 void leaveTryFor(TryStatementInfo info) {
3931 assert(tryNestingStack.last == info);
3932 tryNestingStack.removeLast();
3933 }
3934
3935 bool hasCatch = !node.catchBlocks.isEmpty;
3936 bool hasFinally = node.finallyBlock != null;
3937 TryStatementInfo catchInfo, finallyInfo;
3938 // There is a nesting stack of try blocks, so the outer try/finally block
3939 // is added first.
3940 if (hasFinally) finallyInfo = enterTryFor(node.finallyBlock);
3941 if (hasCatch) catchInfo = enterTryFor(node.catchBlocks);
3942 visit(node.tryBlock);
3943
3944 if (hasCatch) {
3945 leaveTryFor(catchInfo);
3946 visit(node.catchBlocks);
3947 }
3948 if (hasFinally) {
3949 leaveTryFor(finallyInfo);
3950 visit(node.finallyBlock);
3951 }
3952 }
3953
3954 visitVariableDefinitions(ast.VariableDefinitions node) {
3955 if (inTryStatement) {
3956 for (ast.Node definition in node.definitions.nodes) {
3957 LocalVariableElement local = elements[definition];
3958 assert(local != null);
3959 // In the closure conversion pass we check for isInitializingFormal,
3960 // but I'm not sure it can arise.
3961 assert(!local.isInitializingFormal);
3962 tryNestingStack.last.declared.add(local);
3963 }
3964 }
3965 node.visitChildren(this);
3966 }
3967 }
3968
3969 /// The [IrBuilder]s view on the information about the program that has been
3970 /// computed in resolution and and type interence.
3971 class GlobalProgramInformation {
3972 final Compiler _compiler;
3973 JavaScriptBackend get _backend => _compiler.backend;
3974
3975 GlobalProgramInformation(this._compiler);
3976
3977 /// Returns [true], if the analysis could not determine that the type
3978 /// arguments for the class [cls] are never used in the program.
3979 bool requiresRuntimeTypesFor(ClassElement cls) {
3980 return cls.typeVariables.isNotEmpty && _backend.classNeedsRti(cls);
3981 }
3982
3983 FunctionElement get throwTypeErrorHelper => _backend.helpers.throwTypeError;
3984 Element get throwNoSuchMethod => _backend.helpers.throwNoSuchMethod;
3985
3986 ClassElement get nullClass => _compiler.coreClasses.nullClass;
3987
3988 DartType unaliasType(DartType type) => type.unaliased;
3989
3990 TypeMask getTypeMaskForForeign(NativeBehavior behavior) {
3991 if (behavior == null) {
3992 return _backend.dynamicType;
3993 }
3994 return TypeMaskFactory.fromNativeBehavior(behavior, _compiler);
3995 }
3996
3997 bool isArrayType(TypeMask type) {
3998 return type.satisfies(_backend.helpers.jsArrayClass, _compiler.world);
3999 }
4000
4001 TypeMask getTypeMaskForNativeFunction(FunctionElement function) {
4002 return _compiler.typesTask.getGuaranteedReturnTypeOfElement(function);
4003 }
4004
4005 FieldElement locateSingleField(Selector selector, TypeMask type) {
4006 return _compiler.world.locateSingleField(selector, type);
4007 }
4008
4009 bool fieldNeverChanges(FieldElement field) {
4010 return _compiler.world.fieldNeverChanges(field);
4011 }
4012
4013 Element get closureConverter {
4014 return _backend.helpers.closureConverter;
4015 }
4016
4017 void addNativeMethod(FunctionElement function) {
4018 _backend.emitter.nativeEmitter.nativeMethods.add(function);
4019 }
4020
4021 bool get trustJSInteropTypeAnnotations =>
4022 _compiler.options.trustJSInteropTypeAnnotations;
4023
4024 bool isNative(ClassElement element) => _backend.isNative(element);
4025
4026 bool isJsInterop(FunctionElement element) => _backend.isJsInterop(element);
4027
4028 bool isJsInteropAnonymous(FunctionElement element) =>
4029 _backend.jsInteropAnalysis.hasAnonymousAnnotation(element.contextClass);
4030
4031 String getJsInteropTargetPath(FunctionElement element) {
4032 return '${_backend.namer.fixedBackendPath(element)}.'
4033 '${_backend.nativeData.getFixedBackendName(element)}';
4034 }
4035
4036 DartType get jsJavascriptObjectType =>
4037 _backend.helpers.jsJavaScriptObjectClass.thisType;
4038 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698