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

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

Issue 1567403004: dart2js: Eliminate the JsIrBuilderVisitor. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 11 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
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart2js.ir_builder_task; 5 library dart2js.ir_builder_task;
6 6
7 import '../closure.dart' as closurelib; 7 import '../closure.dart' as closure;
8 import '../closure.dart' hide ClosureScope;
9 import '../common.dart'; 8 import '../common.dart';
10 import '../common/names.dart' show 9 import '../common/names.dart' show
11 Names, 10 Names,
12 Selectors; 11 Selectors;
13 import '../common/tasks.dart' show 12 import '../common/tasks.dart' show
14 CompilerTask; 13 CompilerTask;
15 import '../compiler.dart' show 14 import '../compiler.dart' show
16 Compiler; 15 Compiler;
17 import '../constants/expressions.dart'; 16 import '../constants/expressions.dart';
18 import '../dart_types.dart'; 17 import '../dart_types.dart';
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 return measure(() { 83 return measure(() {
85 bailoutMessage = null; 84 bailoutMessage = null;
86 85
87 TreeElements elementsMapping = element.resolvedAst.elements; 86 TreeElements elementsMapping = element.resolvedAst.elements;
88 element = element.implementation; 87 element = element.implementation;
89 return reporter.withCurrentElement(element, () { 88 return reporter.withCurrentElement(element, () {
90 SourceInformationBuilder sourceInformationBuilder = 89 SourceInformationBuilder sourceInformationBuilder =
91 sourceInformationStrategy.createBuilderForContext(element); 90 sourceInformationStrategy.createBuilderForContext(element);
92 91
93 IrBuilderVisitor builder = 92 IrBuilderVisitor builder =
94 new JsIrBuilderVisitor( 93 new IrBuilderVisitor(
95 elementsMapping, compiler, sourceInformationBuilder, 94 elementsMapping, compiler, sourceInformationBuilder,
96 typeMaskSystem); 95 typeMaskSystem);
97 ir.FunctionDefinition irNode = builder.buildExecutable(element); 96 ir.FunctionDefinition irNode = builder.buildExecutable(element);
98 if (irNode == null) { 97 if (irNode == null) {
99 bailoutMessage = builder.bailoutMessage; 98 bailoutMessage = builder.bailoutMessage;
100 } else if (builderCallback != null) { 99 } else if (builderCallback != null) {
101 builderCallback(element, irNode); 100 builderCallback(element, irNode);
102 } 101 }
103 return irNode; 102 return irNode;
104 }); 103 });
105 }); 104 });
106 } 105 }
107 } 106 }
108 107
109 /// Translates the frontend AST of a method to its CPS IR. 108 /// Translates the frontend AST of a method to its CPS IR.
110 /// 109 ///
111 /// The visitor has an [IrBuilder] which contains an IR fragment to build upon 110 /// The visitor has an [IrBuilder] which contains an IR fragment to build upon
112 /// and the current reaching definition of local variables. 111 /// and the current reaching definition of local variables.
113 /// 112 ///
114 /// Visiting a statement or expression extends the IR builder's fragment. 113 /// Visiting a statement or expression extends the IR builder's fragment.
115 /// For expressions, the primitive holding the resulting value is returned. 114 /// For expressions, the primitive holding the resulting value is returned.
116 /// For statements, `null` is returned. 115 /// For statements, `null` is returned.
117 // TODO(johnniwinther): Implement [SemanticDeclVisitor]. 116 // TODO(johnniwinther): Implement [SemanticDeclVisitor].
118 abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> 117 class IrBuilderVisitor extends ast.Visitor<ir.Primitive>
119 with IrBuilderMixin<ast.Node>, 118 with IrBuilderMixin<ast.Node>,
120 SemanticSendResolvedMixin<ir.Primitive, dynamic>, 119 SemanticSendResolvedMixin<ir.Primitive, dynamic>,
121 ErrorBulkMixin<ir.Primitive, dynamic>, 120 ErrorBulkMixin<ir.Primitive, dynamic>,
122 BaseImplementationOfStaticsMixin<ir.Primitive, dynamic>, 121 BaseImplementationOfStaticsMixin<ir.Primitive, dynamic>,
123 BaseImplementationOfLocalsMixin<ir.Primitive, dynamic>, 122 BaseImplementationOfLocalsMixin<ir.Primitive, dynamic>,
124 BaseImplementationOfDynamicsMixin<ir.Primitive, dynamic>, 123 BaseImplementationOfDynamicsMixin<ir.Primitive, dynamic>,
125 BaseImplementationOfConstantsMixin<ir.Primitive, dynamic>, 124 BaseImplementationOfConstantsMixin<ir.Primitive, dynamic>,
126 BaseImplementationOfNewMixin<ir.Primitive, dynamic>, 125 BaseImplementationOfNewMixin<ir.Primitive, dynamic>,
127 BaseImplementationOfCompoundsMixin<ir.Primitive, dynamic>, 126 BaseImplementationOfCompoundsMixin<ir.Primitive, dynamic>,
128 BaseImplementationOfSetIfNullsMixin<ir.Primitive, dynamic>, 127 BaseImplementationOfSetIfNullsMixin<ir.Primitive, dynamic>,
(...skipping 29 matching lines...) Expand all
158 // that is, the definition in effect at the hole in 'current'. These are 157 // that is, the definition in effect at the hole in 'current'. These are
159 // used to determine if a join-point continuation needs to be passed 158 // used to determine if a join-point continuation needs to be passed
160 // arguments, and what the arguments are. 159 // arguments, and what the arguments are.
161 160
162 /// Construct a top-level visitor. 161 /// Construct a top-level visitor.
163 IrBuilderVisitor(this.elements, 162 IrBuilderVisitor(this.elements,
164 this.compiler, 163 this.compiler,
165 this.sourceInformationBuilder, 164 this.sourceInformationBuilder,
166 this.typeMaskSystem); 165 this.typeMaskSystem);
167 166
167 JavaScriptBackend get backend => compiler.backend;
168 BackendHelpers get helpers => backend.helpers;
168 DiagnosticReporter get reporter => compiler.reporter; 169 DiagnosticReporter get reporter => compiler.reporter;
169 170
170 String bailoutMessage = null; 171 String bailoutMessage = null;
171 172
173 ir.Primitive visit(ast.Node node) => node.accept(this);
174
172 @override 175 @override
173 ir.Primitive apply(ast.Node node, _) => node.accept(this); 176 ir.Primitive apply(ast.Node node, _) => node.accept(this);
174 177
175 @override
176 SemanticSendVisitor get sendVisitor => this; 178 SemanticSendVisitor get sendVisitor => this;
177 179
178 /** 180 /// Result of closure conversion for the current body of code.
179 * Builds the [ir.FunctionDefinition] for an executable element. In case the 181 ///
180 * function uses features that cannot be expressed in the IR, this element 182 /// Will be initialized upon entering the body of a function.
181 * returns `null`. 183 /// It is computed by the [ClosureTranslator].
182 */ 184 closure.ClosureClassMap closureClassMap;
183 ir.FunctionDefinition buildExecutable(ExecutableElement element); 185
184 186 /// If [node] has declarations for variables that should be boxed,
185 ClosureClassMap get closureClassMap; 187 /// returns a [ClosureScope] naming a box to create, and enumerating the
186 ClosureScope getClosureScopeForNode(ast.Node node); 188 /// variables that should be stored in the box.
187 ClosureEnvironment getClosureEnvironment(); 189 ///
190 /// Also see [ClosureScope].
191 ClosureScope getClosureScopeForNode(ast.Node node) {
192 // We translate a ClosureScope from closure.dart into IR builder's variant
193 // because the IR builder should not depend on the synthetic elements
194 // created in closure.dart.
195 return new ClosureScope(closureClassMap.capturingScopes[node]);
196 }
197
198 /// Returns the [ClosureScope] for any function, possibly different from the
199 /// one currently being built.
200 ClosureScope getClosureScopeForFunction(FunctionElement function) {
201 closure.ClosureClassMap map =
202 compiler.closureToClassMapper.computeClosureToClassMapping(
203 function,
204 function.node,
205 elements);
206 return new ClosureScope(map.capturingScopes[function.node]);
207 }
208
209 /// If the current function is a nested function with free variables (or a
210 /// captured reference to `this`), returns a [ClosureEnvironment]
211 /// indicating how to access these.
212 ClosureEnvironment getClosureEnvironment() {
213 return new ClosureEnvironment(closureClassMap);
214 }
215
216 IrBuilder getBuilderFor(Element element) {
217 return new IrBuilder(
218 new GlobalProgramInformation(compiler),
219 backend.constants,
220 element);
221 }
222
223 /// Builds the [ir.FunctionDefinition] for an executable element. In case the
224 /// function uses features that cannot be expressed in the IR, this element
225 /// returns `null`.
226 ir.FunctionDefinition buildExecutable(ExecutableElement element) {
227 return nullIfGiveup(() {
228 ir.FunctionDefinition root;
229 switch (element.kind) {
230 case ElementKind.GENERATIVE_CONSTRUCTOR:
231 root = buildConstructor(element);
232 break;
233
234 case ElementKind.GENERATIVE_CONSTRUCTOR_BODY:
235 root = buildConstructorBody(element);
236 break;
237
238 case ElementKind.FACTORY_CONSTRUCTOR:
239 case ElementKind.FUNCTION:
240 case ElementKind.GETTER:
241 case ElementKind.SETTER:
242 root = buildFunction(element);
243 break;
244
245 case ElementKind.FIELD:
246 if (Elements.isStaticOrTopLevel(element)) {
247 root = buildStaticFieldInitializer(element);
248 } else {
249 // Instance field initializers are inlined in the constructor,
250 // so we shouldn't need to build anything here.
251 // TODO(asgerf): But what should we return?
252 return null;
253 }
254 break;
255
256 default:
257 reporter.internalError(element, "Unexpected element type $element");
258 }
259 return root;
260 });
261 }
262
263 /// Loads the type variables for all super classes of [superClass] into the
264 /// IR builder's environment with their corresponding values.
265 ///
266 /// The type variables for [currentClass] must already be in the IR builder's
267 /// environment.
268 ///
269 /// Type variables are stored as [TypeVariableLocal] in the environment.
270 ///
271 /// This ensures that access to type variables mentioned inside the
272 /// constructors and initializers will happen through the local environment
273 /// instead of using 'this'.
274 void loadTypeVariablesForSuperClasses(ClassElement currentClass) {
275 if (currentClass.isObject) return;
276 loadTypeVariablesForType(currentClass.supertype);
277 if (currentClass is MixinApplicationElement) {
278 loadTypeVariablesForType(currentClass.mixinType);
279 }
280 }
281
282 /// Loads all type variables for [type] and all of its super classes into
283 /// the environment. All type variables mentioned in [type] must already
284 /// be in the environment.
285 void loadTypeVariablesForType(InterfaceType type) {
286 ClassElement clazz = type.element;
287 assert(clazz.typeVariables.length == type.typeArguments.length);
288 for (int i = 0; i < clazz.typeVariables.length; ++i) {
289 irBuilder.declareTypeVariable(clazz.typeVariables[i],
290 type.typeArguments[i]);
291 }
292 loadTypeVariablesForSuperClasses(clazz);
293 }
294
295 /// Returns the constructor body associated with the given constructor or
296 /// creates a new constructor body, if none can be found.
297 ///
298 /// Returns `null` if the constructor does not have a body.
299 ConstructorBodyElement getConstructorBody(FunctionElement constructor) {
300 // TODO(asgerf): This is largely inherited from the SSA builder.
301 // The ConstructorBodyElement has an invalid function signature, but we
302 // cannot add a BoxLocal as parameter, because BoxLocal is not an element.
303 // Instead of forging ParameterElements to forge a FunctionSignature, we
304 // need a way to create backend methods without creating more fake elements.
305 assert(constructor.isGenerativeConstructor);
306 assert(constructor.isImplementation);
307 if (constructor.isSynthesized) return null;
308 ast.FunctionExpression node = constructor.node;
309 // If we know the body doesn't have any code, we don't generate it.
310 if (!node.hasBody()) return null;
311 if (node.hasEmptyBody()) return null;
312 ClassElement classElement = constructor.enclosingClass;
313 ConstructorBodyElement bodyElement;
314 classElement.forEachBackendMember((Element backendMember) {
315 if (backendMember.isGenerativeConstructorBody) {
316 ConstructorBodyElement body = backendMember;
317 if (body.constructor == constructor) {
318 bodyElement = backendMember;
319 }
320 }
321 });
322 if (bodyElement == null) {
323 bodyElement = new ConstructorBodyElementX(constructor);
324 classElement.addBackendMember(bodyElement);
325
326 if (constructor.isPatch) {
327 // Create origin body element for patched constructors.
328 ConstructorBodyElementX patch = bodyElement;
329 ConstructorBodyElementX origin =
330 new ConstructorBodyElementX(constructor.origin);
331 origin.applyPatch(patch);
332 classElement.origin.addBackendMember(bodyElement.origin);
333 }
334 }
335 assert(bodyElement.isGenerativeConstructorBody);
336 return bodyElement;
337 }
338
339 /// The list of parameters to send from the generative constructor
340 /// to the generative constructor body.
341 ///
342 /// Boxed parameters are not in the list, instead, a [BoxLocal] is passed
343 /// containing the boxed parameters.
344 ///
345 /// For example, given the following constructor,
346 ///
347 /// Foo(x, y) : field = (() => ++x) { print(x + y) }
348 ///
349 /// the argument `x` would be replaced by a [BoxLocal]:
350 ///
351 /// Foo_body(box0, y) { print(box0.x + y) }
352 ///
353 List<Local> getConstructorBodyParameters(ConstructorBodyElement body) {
354 List<Local> parameters = <Local>[];
355 ClosureScope scope = getClosureScopeForFunction(body.constructor);
356 if (scope != null) {
357 parameters.add(scope.box);
358 }
359 body.functionSignature.orderedForEachParameter((ParameterElement param) {
360 if (scope != null && scope.capturedVariables.containsKey(param)) {
361 // Do not pass this parameter; the box will carry its value.
362 } else {
363 parameters.add(param);
364 }
365 });
366 return parameters;
367 }
368
369 /// Builds the IR for a given constructor.
370 ///
371 /// 1. Computes the type held in all own or "inherited" type variables.
372 /// 2. Evaluates all own or inherited field initializers.
373 /// 3. Creates the object and assigns its fields and runtime type.
374 /// 4. Calls constructor body and super constructor bodies.
375 /// 5. Returns the created object.
376 ir.FunctionDefinition buildConstructor(ConstructorElement constructor) {
377 // TODO(asgerf): Optimization: If constructor is redirecting, then just
378 // evaluate arguments and call the target constructor.
379 constructor = constructor.implementation;
380 ClassElement classElement = constructor.enclosingClass.implementation;
381
382 IrBuilder builder = getBuilderFor(constructor);
383
384 final bool requiresTypeInformation =
385 builder.program.requiresRuntimeTypesFor(classElement);
386
387 return withBuilder(builder, () {
388 // Setup parameters and create a box if anything is captured.
389 List<Local> parameters = <Local>[];
390 constructor.functionSignature.orderedForEachParameter(
391 (ParameterElement p) => parameters.add(p));
392
393 int firstTypeArgumentParameterIndex;
394
395 // If instances of the class may need runtime type information, we add a
396 // synthetic parameter for each type parameter.
397 if (requiresTypeInformation) {
398 firstTypeArgumentParameterIndex = parameters.length;
399 classElement.typeVariables.forEach((TypeVariableType variable) {
400 parameters.add(new closure.TypeVariableLocal(variable, constructor));
401 });
402 } else {
403 classElement.typeVariables.forEach((TypeVariableType variable) {
404 irBuilder.declareTypeVariable(variable, const DynamicType());
405 });
406 }
407
408 // Create IR parameters and setup the environment.
409 List<ir.Parameter> irParameters = builder.buildFunctionHeader(parameters,
410 closureScope: getClosureScopeForFunction(constructor));
411
412 // Create a list of the values of all type argument parameters, if any.
413 List<ir.Primitive> typeInformation;
414 if (requiresTypeInformation) {
415 typeInformation = irParameters.sublist(firstTypeArgumentParameterIndex);
416 } else {
417 typeInformation = const <ir.Primitive>[];
418 }
419
420 // -- Load values for type variables declared on super classes --
421 // Field initializers for super classes can reference these, so they
422 // must be available before evaluating field initializers.
423 // This could be interleaved with field initialization, but we choose do
424 // get it out of the way here to avoid complications with mixins.
425 loadTypeVariablesForSuperClasses(classElement);
426
427 /// Maps each field from this class or a superclass to its initial value.
428 Map<FieldElement, ir.Primitive> fieldValues =
429 <FieldElement, ir.Primitive>{};
430
431 // -- Evaluate field initializers ---
432 // Evaluate field initializers in constructor and super constructors.
433 List<ConstructorElement> constructorList = <ConstructorElement>[];
434 evaluateConstructorFieldInitializers(
435 constructor, constructorList, fieldValues);
436
437 // All parameters in all constructors are now bound in the environment.
438 // BoxLocals for captured parameters are also in the environment.
439 // The initial value of all fields are now bound in [fieldValues].
440
441 // --- Create the object ---
442 // Get the initial field values in the canonical order.
443 List<ir.Primitive> instanceArguments = <ir.Primitive>[];
444 classElement.forEachInstanceField((ClassElement c, FieldElement field) {
445 ir.Primitive value = fieldValues[field];
446 if (value != null) {
447 instanceArguments.add(value);
448 } else {
449 assert(backend.isNativeOrExtendsNative(c));
450 // Native fields are initialized elsewhere.
451 }
452 }, includeSuperAndInjectedMembers: true);
453
454 ir.Primitive instance = new ir.CreateInstance(
455 classElement,
456 instanceArguments,
457 typeInformation,
458 constructor.hasNode
459 ? sourceInformationBuilder.buildCreate(constructor.node)
460 // TODO(johnniwinther): Provide source information for creation
461 // through synthetic constructors.
462 : null);
463 irBuilder.add(new ir.LetPrim(instance));
464
465 // --- Call constructor bodies ---
466 for (ConstructorElement target in constructorList) {
467 ConstructorBodyElement bodyElement = getConstructorBody(target);
468 if (bodyElement == null) continue; // Skip if constructor has no body.
469 List<ir.Primitive> bodyArguments = <ir.Primitive>[];
470 for (Local param in getConstructorBodyParameters(bodyElement)) {
471 bodyArguments.add(irBuilder.environment.lookup(param));
472 }
473 irBuilder.buildInvokeDirectly(bodyElement, instance, bodyArguments);
474 }
475
476 // --- step 4: return the created object ----
477 irBuilder.buildReturn(
478 value: instance,
479 sourceInformation:
480 sourceInformationBuilder.buildImplicitReturn(constructor));
481
482 return irBuilder.makeFunctionDefinition();
483 });
484 }
485
486 /// Make a visitor suitable for translating ASTs taken from [context].
487 ///
488 /// Every visitor can only be applied to nodes in one context, because
489 /// the [elements] field is specific to that context.
490 IrBuilderVisitor makeVisitorForContext(AstElement context) {
491 return new IrBuilderVisitor(
492 context.resolvedAst.elements,
493 compiler,
494 sourceInformationBuilder.forContext(context),
495 typeMaskSystem);
496 }
497
498 /// Builds the IR for an [expression] taken from a different [context].
499 ///
500 /// Such expressions need to be compiled with a different [sourceFile] and
501 /// [elements] mapping.
502 ir.Primitive inlineExpression(AstElement context, ast.Expression expression) {
503 IrBuilderVisitor visitor = makeVisitorForContext(context);
504 return visitor.withBuilder(irBuilder, () => visitor.visit(expression));
505 }
506
507 /// Evaluate the implicit super call in the given mixin constructor.
508 void forwardSynthesizedMixinConstructor(
509 ConstructorElement constructor,
510 List<ConstructorElement> supers,
511 Map<FieldElement, ir.Primitive> fieldValues) {
512 assert(constructor.enclosingClass.implementation.isMixinApplication);
513 assert(constructor.isSynthesized);
514 ConstructorElement target =
515 constructor.definingConstructor.implementation;
516 // The resolver gives us the exact same FunctionSignature for the two
517 // constructors. The parameters for the synthesized constructor
518 // are already in the environment, so the target constructor's parameters
519 // are also in the environment since their elements are the same.
520 assert(constructor.functionSignature == target.functionSignature);
521 IrBuilderVisitor visitor = makeVisitorForContext(target);
522 visitor.withBuilder(irBuilder, () {
523 visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues);
524 });
525 }
526
527 /// In preparation of inlining (part of) [target], the [arguments] are moved
528 /// into the environment bindings for the corresponding parameters.
529 ///
530 /// Defaults for optional arguments are evaluated in order to ensure
531 /// all parameters are available in the environment.
532 void loadArguments(ConstructorElement target,
533 CallStructure call,
534 List<ir.Primitive> arguments) {
535 assert(target.isImplementation);
536 assert(target == elements.analyzedElement);
537 FunctionSignature signature = target.functionSignature;
538
539 // Establish a scope in case parameters are captured.
540 ClosureScope scope = getClosureScopeForFunction(target);
541 irBuilder.enterScope(scope);
542
543 // Load required parameters
544 int index = 0;
545 signature.forEachRequiredParameter((ParameterElement param) {
546 irBuilder.declareLocalVariable(param, initialValue: arguments[index]);
547 index++;
548 });
549
550 // Load optional parameters, evaluating default values for omitted ones.
551 signature.forEachOptionalParameter((ParameterElement param) {
552 ir.Primitive value;
553 // Load argument if provided.
554 if (signature.optionalParametersAreNamed) {
555 int nameIndex = call.namedArguments.indexOf(param.name);
556 if (nameIndex != -1) {
557 int translatedIndex = call.positionalArgumentCount + nameIndex;
558 value = arguments[translatedIndex];
559 }
560 } else if (index < arguments.length) {
561 value = arguments[index];
562 }
563 // Load default if argument was not provided.
564 if (value == null) {
565 if (param.initializer != null) {
566 value = visit(param.initializer);
567 } else {
568 value = irBuilder.buildNullConstant();
569 }
570 }
571 irBuilder.declareLocalVariable(param, initialValue: value);
572 index++;
573 });
574 }
575
576 /// Evaluates a call to the given constructor from an initializer list.
577 ///
578 /// Calls [loadArguments] and [evaluateConstructorFieldInitializers] in a
579 /// visitor that has the proper [TreeElements] mapping.
580 void evaluateConstructorCallFromInitializer(
581 ConstructorElement target,
582 CallStructure call,
583 List<ir.Primitive> arguments,
584 List<ConstructorElement> supers,
585 Map<FieldElement, ir.Primitive> fieldValues) {
586 IrBuilderVisitor visitor = makeVisitorForContext(target);
587 visitor.withBuilder(irBuilder, () {
588 visitor.loadArguments(target, call, arguments);
589 visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues);
590 });
591 }
592
593 /// Evaluates all field initializers on [constructor] and all constructors
594 /// invoked through `this()` or `super()` ("superconstructors").
595 ///
596 /// The resulting field values will be available in [fieldValues]. The values
597 /// are not stored in any fields.
598 ///
599 /// This procedure assumes that the parameters to [constructor] are available
600 /// in the IR builder's environment.
601 ///
602 /// The parameters to superconstructors are, however, assumed *not* to be in
603 /// the environment, but will be put there by this procedure.
604 ///
605 /// All constructors will be added to [supers], with superconstructors first.
606 void evaluateConstructorFieldInitializers(
607 ConstructorElement constructor,
608 List<ConstructorElement> supers,
609 Map<FieldElement, ir.Primitive> fieldValues) {
610 assert(constructor.isImplementation);
611 assert(constructor == elements.analyzedElement);
612 ClassElement enclosingClass = constructor.enclosingClass.implementation;
613 // Evaluate declaration-site field initializers, unless this constructor
614 // redirects to another using a `this()` initializer. In that case, these
615 // will be initialized by the effective target constructor.
616 if (!constructor.isRedirectingGenerative) {
617 enclosingClass.forEachInstanceField((ClassElement c, FieldElement field) {
618 if (field.initializer != null) {
619 fieldValues[field] = inlineExpression(field, field.initializer);
620 } else {
621 if (backend.isNativeOrExtendsNative(c)) {
622 // Native field is initialized elsewhere.
623 } else {
624 // Fields without an initializer default to null.
625 // This value will be overwritten below if an initializer is found.
626 fieldValues[field] = irBuilder.buildNullConstant();
627 }
628 }
629 });
630 }
631 // If this is a mixin constructor, it does not have its own parameter list
632 // or initializer list. Directly forward to the super constructor.
633 // Note that the declaration-site initializers originating from the
634 // mixed-in class were handled above.
635 if (enclosingClass.isMixinApplication) {
636 forwardSynthesizedMixinConstructor(constructor, supers, fieldValues);
637 return;
638 }
639 // Evaluate initializing parameters, e.g. `Foo(this.x)`.
640 constructor.functionSignature.orderedForEachParameter(
641 (ParameterElement parameter) {
642 if (parameter.isInitializingFormal) {
643 InitializingFormalElement fieldParameter = parameter;
644 fieldValues[fieldParameter.fieldElement] =
645 irBuilder.buildLocalVariableGet(parameter);
646 }
647 });
648 // Evaluate constructor initializers, e.g. `Foo() : x = 50`.
649 ast.FunctionExpression node = constructor.node;
650 bool hasConstructorCall = false; // Has this() or super() initializer?
651 if (node != null && node.initializers != null) {
652 for(ast.Node initializer in node.initializers) {
653 if (initializer is ast.SendSet) {
654 // Field initializer.
655 FieldElement field = elements[initializer];
656 fieldValues[field] = visit(initializer.arguments.head);
657 } else if (initializer is ast.Send) {
658 // Super or this initializer.
659 ConstructorElement target = elements[initializer].implementation;
660 Selector selector = elements.getSelector(initializer);
661 List<ir.Primitive> arguments = initializer.arguments.mapToList(visit);
662 evaluateConstructorCallFromInitializer(
663 target,
664 selector.callStructure,
665 arguments,
666 supers,
667 fieldValues);
668 hasConstructorCall = true;
669 } else {
670 reporter.internalError(initializer,
671 "Unexpected initializer type $initializer");
672 }
673 }
674 }
675 // If no super() or this() was found, also call default superconstructor.
676 if (!hasConstructorCall && !enclosingClass.isObject) {
677 ClassElement superClass = enclosingClass.superclass;
678 FunctionElement target = superClass.lookupDefaultConstructor();
679 if (target == null) {
680 reporter.internalError(superClass, "No default constructor available.");
681 }
682 target = target.implementation;
683 evaluateConstructorCallFromInitializer(
684 target,
685 CallStructure.NO_ARGS,
686 const [],
687 supers,
688 fieldValues);
689 }
690 // Add this constructor after the superconstructors.
691 supers.add(constructor);
692 }
693
694 TryBoxedVariables _analyzeTryBoxedVariables(ast.Node node) {
695 TryBoxedVariables variables = new TryBoxedVariables(elements);
696 try {
697 variables.analyze(node);
698 } catch (e) {
699 bailoutMessage = variables.bailoutMessage;
700 rethrow;
701 }
702 return variables;
703 }
704
705 /// Builds the IR for the body of a constructor.
706 ///
707 /// This function is invoked from one or more "factory" constructors built by
708 /// [buildConstructor].
709 ir.FunctionDefinition buildConstructorBody(ConstructorBodyElement body) {
710 ConstructorElement constructor = body.constructor;
711 ast.FunctionExpression node = constructor.node;
712 closureClassMap =
713 compiler.closureToClassMapper.computeClosureToClassMapping(
714 constructor,
715 node,
716 elements);
717
718 // We compute variables boxed in mutable variables on entry to each try
719 // block, not including variables captured by a closure (which are boxed
720 // in the heap). This duplicates some of the work of closure conversion
721 // without directly using the results. This duplication is wasteful and
722 // error-prone.
723 // TODO(kmillikin): We should combine closure conversion and try/catch
724 // variable analysis in some way.
725 TryBoxedVariables variables = _analyzeTryBoxedVariables(node);
726 tryStatements = variables.tryStatements;
727 IrBuilder builder = getBuilderFor(body);
728
729 return withBuilder(builder, () {
730 irBuilder.buildConstructorBodyHeader(getConstructorBodyParameters(body),
731 getClosureScopeForNode(node));
732 visit(node.body);
733 return irBuilder.makeFunctionDefinition();
734 });
735 }
736
737 ir.FunctionDefinition buildFunction(FunctionElement element) {
738 assert(invariant(element, element.isImplementation));
739 ast.FunctionExpression node = element.node;
740
741 assert(!element.isSynthesized);
742 assert(node != null);
743 assert(elements[node] != null);
744
745 closureClassMap =
746 compiler.closureToClassMapper.computeClosureToClassMapping(
747 element,
748 node,
749 elements);
750 TryBoxedVariables variables = _analyzeTryBoxedVariables(node);
751 tryStatements = variables.tryStatements;
752 IrBuilder builder = getBuilderFor(element);
753 return withBuilder(builder, () => _makeFunctionBody(element, node));
754 }
755
756 ir.FunctionDefinition buildStaticFieldInitializer(FieldElement element) {
757 if (!backend.constants.lazyStatics.contains(element)) {
758 return null; // Nothing to do.
759 }
760 closureClassMap =
761 compiler.closureToClassMapper.computeClosureToClassMapping(
762 element,
763 element.node,
764 elements);
765 IrBuilder builder = getBuilderFor(element);
766 return withBuilder(builder, () {
767 irBuilder.buildFunctionHeader(<Local>[]);
768 ir.Primitive initialValue = visit(element.initializer);
769 ast.VariableDefinitions node = element.node;
770 ast.SendSet sendSet = node.definitions.nodes.head;
771 irBuilder.buildReturn(
772 value: initialValue,
773 sourceInformation:
774 sourceInformationBuilder.buildReturn(sendSet.assignmentOperator));
775 return irBuilder.makeFunctionDefinition();
776 });
777 }
778
779 /// Builds the IR for a constant taken from a different [context].
780 ///
781 /// Such constants need to be compiled with a different [sourceFile] and
782 /// [elements] mapping.
783 ir.Primitive inlineConstant(AstElement context, ast.Expression exp) {
784 IrBuilderVisitor visitor = makeVisitorForContext(context);
785 return visitor.withBuilder(irBuilder, () => visitor.translateConstant(exp));
786 }
787
788 /// Creates a primitive for the default value of [parameter].
789 ir.Primitive translateDefaultValue(ParameterElement parameter) {
790 if (parameter.initializer == null) {
791 return irBuilder.buildNullConstant();
792 } else {
793 return inlineConstant(parameter.executableContext, parameter.initializer);
794 }
795 }
188 796
189 /// Normalizes the argument list of a static invocation. 797 /// Normalizes the argument list of a static invocation.
190 /// 798 ///
191 /// A static invocation is one where the target is known. The argument list 799 /// A static invocation is one where the target is known. The argument list
192 /// [arguments] is normalized by adding default values for optional arguments 800 /// [arguments] is normalized by adding default values for optional arguments
193 /// that are not passed, and by sorting it in place so that named arguments 801 /// that are not passed, and by sorting it in place so that named arguments
194 /// appear in a canonical order. A [CallStructure] reflecting this order 802 /// appear in a canonical order. A [CallStructure] reflecting this order
195 /// is returned. 803 /// is returned.
196 CallStructure normalizeStaticArguments( 804 CallStructure normalizeStaticArguments(CallStructure callStructure,
197 CallStructure callStructure,
198 FunctionElement target, 805 FunctionElement target,
199 List<ir.Primitive> arguments); 806 List<ir.Primitive> arguments) {
807 target = target.implementation;
808 FunctionSignature signature = target.functionSignature;
809 if (!signature.optionalParametersAreNamed &&
810 signature.parameterCount == arguments.length) {
811 return callStructure;
812 }
813
814 if (!signature.optionalParametersAreNamed) {
815 int i = signature.requiredParameterCount;
816 signature.forEachOptionalParameter((ParameterElement element) {
817 if (i < callStructure.positionalArgumentCount) {
818 ++i;
819 } else {
820 arguments.add(translateDefaultValue(element));
821 }
822 });
823 return new CallStructure(signature.parameterCount);
824 }
825
826 int offset = signature.requiredParameterCount;
827 List<ir.Primitive> namedArguments = arguments.sublist(offset);
828 arguments.length = offset;
829 List<String> normalizedNames = <String>[];
830 // Iterate over the optional parameters of the signature, and try to
831 // find them in the callStructure's named arguments. If found, we use the
832 // value in the temporary list, otherwise the default value.
833 signature.orderedOptionalParameters.forEach((ParameterElement element) {
834 int nameIndex = callStructure.namedArguments.indexOf(element.name);
835 arguments.add(nameIndex == -1 ? translateDefaultValue(element)
836 : namedArguments[nameIndex]);
837 normalizedNames.add(element.name);
838 });
839 return new CallStructure(signature.parameterCount, normalizedNames);
840 }
200 841
201 /// Normalizes the argument list of a dynamic invocation. 842 /// Normalizes the argument list of a dynamic invocation.
202 /// 843 ///
203 /// A dynamic invocation is one where the target is not known. The argument 844 /// A dynamic invocation is one where the target is not known. The argument
204 /// list [arguments] is normalized by sorting it in place so that the named 845 /// list [arguments] is normalized by sorting it in place so that the named
205 /// arguments appear in a canonical order. A [CallStructure] reflecting this 846 /// arguments appear in a canonical order. A [CallStructure] reflecting this
206 /// order is returned. 847 /// order is returned.
207 CallStructure normalizeDynamicArguments( 848 CallStructure normalizeDynamicArguments(CallStructure callStructure,
208 CallStructure callStructure, 849 List<ir.Primitive> arguments) {
209 List<ir.Primitive> arguments); 850 assert(arguments.length == callStructure.argumentCount);
851 if (callStructure.namedArguments.isEmpty) return callStructure;
852 int destinationIndex = callStructure.positionalArgumentCount;
853 List<ir.Primitive> namedArguments = arguments.sublist(destinationIndex);
854 for (String argName in callStructure.getOrderedNamedArguments()) {
855 int sourceIndex = callStructure.namedArguments.indexOf(argName);
856 arguments[destinationIndex++] = namedArguments[sourceIndex];
857 }
858 return new CallStructure(callStructure.argumentCount,
859 callStructure.getOrderedNamedArguments());
860 }
210 861
211 /// Read the value of [field]. 862 /// Read the value of [field].
212 ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src); 863 ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src) {
864 ConstantValue constant = getConstantForVariable(field);
865 if (constant != null && !field.isAssignable) {
866 typeMaskSystem.associateConstantValueWithElement(constant, field);
867 return irBuilder.buildConstant(constant, sourceInformation: src);
868 } else if (backend.constants.lazyStatics.contains(field)) {
869 return irBuilder.buildStaticFieldLazyGet(field, src);
870 } else {
871 return irBuilder.buildStaticFieldGet(field, src);
872 }
873 }
213 874
214 ir.FunctionDefinition _makeFunctionBody(FunctionElement element, 875 ir.FunctionDefinition _makeFunctionBody(FunctionElement element,
215 ast.FunctionExpression node) { 876 ast.FunctionExpression node) {
216 FunctionSignature signature = element.functionSignature; 877 FunctionSignature signature = element.functionSignature;
217 List<Local> parameters = <Local>[]; 878 List<Local> parameters = <Local>[];
218 signature.orderedForEachParameter( 879 signature.orderedForEachParameter(
219 (LocalParameterElement e) => parameters.add(e)); 880 (LocalParameterElement e) => parameters.add(e));
220 881
221 if (element.isFactoryConstructor) { 882 if (element.isFactoryConstructor) {
222 // Type arguments are passed in as extra parameters. 883 // Type arguments are passed in as extra parameters.
223 for (DartType typeVariable in element.enclosingClass.typeVariables) { 884 for (DartType typeVariable in element.enclosingClass.typeVariables) {
224 parameters.add(new TypeVariableLocal(typeVariable, element)); 885 parameters.add(new closure.TypeVariableLocal(typeVariable, element));
225 } 886 }
226 } 887 }
227 888
228 irBuilder.buildFunctionHeader(parameters, 889 irBuilder.buildFunctionHeader(parameters,
229 closureScope: getClosureScopeForNode(node), 890 closureScope: getClosureScopeForNode(node),
230 env: getClosureEnvironment()); 891 env: getClosureEnvironment());
231 892
232 visit(node.body); 893 visit(node.body);
233 return irBuilder.makeFunctionDefinition(); 894 return irBuilder.makeFunctionDefinition();
234 } 895 }
235 896
236 /// Returns the allocation site-specific type for a given allocation. 897 /// Builds the IR for creating an instance of the closure class corresponding
237 /// 898 /// to the given nested function.
238 /// Currently, it is an error to call this with anything that is not the 899 closure.ClosureClassElement makeSubFunction(ast.FunctionExpression node) {
239 /// allocation site for a List object (a literal list or a call to one 900 closure.ClosureClassMap innerMap =
240 /// of the List constructors). 901 compiler.closureToClassMapper.getMappingForNestedFunction(node);
241 TypeMask getAllocationSiteType(ast.Node node) { 902 closure.ClosureClassElement closureClass = innerMap.closureClassElement;
242 return compiler.typesTask.getGuaranteedTypeOfNode( 903 return closureClass;
243 elements.analyzedElement, node); 904 }
244 } 905
245 906 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
246 ir.Primitive visit(ast.Node node) => node.accept(this); 907 return irBuilder.buildFunctionExpression(makeSubFunction(node),
908 sourceInformationBuilder.buildCreate(node));
909 }
910
911 visitFunctionDeclaration(ast.FunctionDeclaration node) {
912 LocalFunctionElement element = elements[node.function];
913 Object inner = makeSubFunction(node.function);
914 irBuilder.declareLocalFunction(element, inner,
915 sourceInformationBuilder.buildCreate(node.function));
916 }
247 917
248 // ## Statements ## 918 // ## Statements ##
249 visitBlock(ast.Block node) { 919 visitBlock(ast.Block node) {
250 irBuilder.buildBlock(node.statements.nodes, build); 920 irBuilder.buildBlock(node.statements.nodes, build);
251 } 921 }
252 922
253 ir.Primitive visitBreakStatement(ast.BreakStatement node) { 923 ir.Primitive visitBreakStatement(ast.BreakStatement node) {
254 if (!irBuilder.buildBreak(elements.getTargetOf(node))) { 924 if (!irBuilder.buildBreak(elements.getTargetOf(node))) {
255 reporter.internalError(node, "'break' target not found"); 925 reporter.internalError(node, "'break' target not found");
256 } 926 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 ir.Primitive visitRethrow(ast.Rethrow node) { 958 ir.Primitive visitRethrow(ast.Rethrow node) {
289 assert(irBuilder.isOpen); 959 assert(irBuilder.isOpen);
290 irBuilder.buildRethrow(); 960 irBuilder.buildRethrow();
291 return null; 961 return null;
292 } 962 }
293 963
294 /// Construct a method that executes the forwarding call to the target 964 /// Construct a method that executes the forwarding call to the target
295 /// constructor. This is only required, if the forwarding factory 965 /// constructor. This is only required, if the forwarding factory
296 /// constructor can potentially be the target of a reflective call, because 966 /// constructor can potentially be the target of a reflective call, because
297 /// the builder shortcuts calls to redirecting factories at the call site 967 /// the builder shortcuts calls to redirecting factories at the call site
298 /// (see [JsIrBuilderVisitor.handleConstructorInvoke]). 968 /// (see [handleConstructorInvoke]).
299 visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) { 969 visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) {
300 ConstructorElement targetConstructor = 970 ConstructorElement targetConstructor =
301 elements.getRedirectingTargetConstructor(node).implementation; 971 elements.getRedirectingTargetConstructor(node).implementation;
302 ConstructorElement redirectingConstructor = 972 ConstructorElement redirectingConstructor =
303 irBuilder.state.currentElement.implementation; 973 irBuilder.state.currentElement.implementation;
304 List<ir.Primitive> arguments = <ir.Primitive>[]; 974 List<ir.Primitive> arguments = <ir.Primitive>[];
305 FunctionSignature redirectingSignature = 975 FunctionSignature redirectingSignature =
306 redirectingConstructor.functionSignature; 976 redirectingConstructor.functionSignature;
307 List<String> namedParameters = <String>[]; 977 List<String> namedParameters = <String>[];
308 redirectingSignature.forEachParameter((ParameterElement parameter) { 978 redirectingSignature.forEachParameter((ParameterElement parameter) {
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 1135
466 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] 1136 // Build(Return(e), C) = C'[InvokeContinuation(return, x)]
467 // where (C', x) = Build(e, C) 1137 // where (C', x) = Build(e, C)
468 // 1138 //
469 // Return without a subexpression is translated as if it were return null. 1139 // Return without a subexpression is translated as if it were return null.
470 visitReturn(ast.Return node) { 1140 visitReturn(ast.Return node) {
471 assert(irBuilder.isOpen); 1141 assert(irBuilder.isOpen);
472 SourceInformation source = sourceInformationBuilder.buildReturn(node); 1142 SourceInformation source = sourceInformationBuilder.buildReturn(node);
473 if (node.beginToken.value == 'native') { 1143 if (node.beginToken.value == 'native') {
474 FunctionElement function = irBuilder.state.currentElement; 1144 FunctionElement function = irBuilder.state.currentElement;
475 assert(compiler.backend.isNative(function)); 1145 assert(backend.isNative(function));
476 ast.Node nativeBody = node.expression; 1146 ast.Node nativeBody = node.expression;
477 if (nativeBody != null) { 1147 if (nativeBody != null) {
478 ast.LiteralString jsCode = nativeBody.asLiteralString(); 1148 ast.LiteralString jsCode = nativeBody.asLiteralString();
479 String javaScriptCode = jsCode.dartString.slowToString(); 1149 String javaScriptCode = jsCode.dartString.slowToString();
480 assert(invariant(nativeBody, 1150 assert(invariant(nativeBody,
481 !nativeRedirectionRegExp.hasMatch(javaScriptCode), 1151 !nativeRedirectionRegExp.hasMatch(javaScriptCode),
482 message: "Deprecated syntax, use @JSName('name') instead.")); 1152 message: "Deprecated syntax, use @JSName('name') instead."));
483 assert(invariant(nativeBody, 1153 assert(invariant(nativeBody,
484 function.functionSignature.parameterCount == 0, 1154 function.functionSignature.parameterCount == 0,
485 message: 'native "..." syntax is restricted to ' 1155 message: 'native "..." syntax is restricted to '
486 'functions with zero parameters.')); 1156 'functions with zero parameters.'));
487 irBuilder.buildNativeFunctionBody(function, javaScriptCode); 1157 irBuilder.buildNativeFunctionBody(function, javaScriptCode);
488 } else { 1158 } else {
489 JavaScriptBackend backend = compiler.backend;
490 String name = backend.getFixedBackendName(function); 1159 String name = backend.getFixedBackendName(function);
491 irBuilder.buildRedirectingNativeFunctionBody(function, name, source); 1160 irBuilder.buildRedirectingNativeFunctionBody(function, name, source);
492 } 1161 }
493 } else { 1162 } else {
494 irBuilder.buildReturn( 1163 irBuilder.buildReturn(
495 value: build(node.expression), 1164 value: build(node.expression),
496 sourceInformation: source); 1165 sourceInformation: source);
497 } 1166 }
498 } 1167 }
499 1168
(...skipping 26 matching lines...) Expand all
526 for (ast.Node labelOrCase in switchCase.labelsAndCases) { 1195 for (ast.Node labelOrCase in switchCase.labelsAndCases) {
527 if (labelOrCase is ast.CaseMatch) { 1196 if (labelOrCase is ast.CaseMatch) {
528 ir.Primitive constant = translateConstant(labelOrCase.expression); 1197 ir.Primitive constant = translateConstant(labelOrCase.expression);
529 caseInfo.addConstant(constant); 1198 caseInfo.addConstant(constant);
530 } 1199 }
531 } 1200 }
532 } 1201 }
533 } 1202 }
534 ir.Primitive value = visit(node.expression); 1203 ir.Primitive value = visit(node.expression);
535 JumpTarget target = elements.getTargetDefinition(node); 1204 JumpTarget target = elements.getTargetDefinition(node);
536 Element error = 1205 Element error = helpers.fallThroughError;
537 (compiler.backend as JavaScriptBackend).helpers.fallThroughError;
538 irBuilder.buildSimpleSwitch(target, value, cases, defaultCase, error, 1206 irBuilder.buildSimpleSwitch(target, value, cases, defaultCase, error,
539 sourceInformationBuilder.buildGeneric(node)); 1207 sourceInformationBuilder.buildGeneric(node));
540 } 1208 }
541 1209
542 visitTryStatement(ast.TryStatement node) { 1210 visitTryStatement(ast.TryStatement node) {
543 List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[]; 1211 List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[];
544 for (ast.CatchBlock catchClause in node.catchBlocks.nodes) { 1212 for (ast.CatchBlock catchClause in node.catchBlocks.nodes) {
545 LocalVariableElement exceptionVariable; 1213 LocalVariableElement exceptionVariable;
546 if (catchClause.exception != null) { 1214 if (catchClause.exception != null) {
547 exceptionVariable = elements[catchClause.exception]; 1215 exceptionVariable = elements[catchClause.exception];
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 return irBuilder.state.constants.getConstantValueForVariable(element); 1297 return irBuilder.state.constants.getConstantValueForVariable(element);
630 } 1298 }
631 1299
632 ir.Primitive buildConstantExpression(ConstantExpression expression, 1300 ir.Primitive buildConstantExpression(ConstantExpression expression,
633 SourceInformation sourceInformation) { 1301 SourceInformation sourceInformation) {
634 return irBuilder.buildConstant( 1302 return irBuilder.buildConstant(
635 irBuilder.state.constants.getConstantValue(expression), 1303 irBuilder.state.constants.getConstantValue(expression),
636 sourceInformation: sourceInformation); 1304 sourceInformation: sourceInformation);
637 } 1305 }
638 1306
1307 /// Returns the allocation site-specific type for a given allocation.
1308 ///
1309 /// Currently, it is an error to call this with anything that is not the
1310 /// allocation site for a List object (a literal list or a call to one
1311 /// of the List constructors).
1312 TypeMask getAllocationSiteType(ast.Node node) {
1313 return compiler.typesTask.getGuaranteedTypeOfNode(
1314 elements.analyzedElement, node);
1315 }
1316
639 ir.Primitive visitLiteralList(ast.LiteralList node) { 1317 ir.Primitive visitLiteralList(ast.LiteralList node) {
640 if (node.isConst) { 1318 if (node.isConst) {
641 return translateConstant(node); 1319 return translateConstant(node);
642 } 1320 }
643 List<ir.Primitive> values = node.elements.nodes.mapToList(visit); 1321 List<ir.Primitive> values = node.elements.nodes.mapToList(visit);
644 InterfaceType type = elements.getType(node); 1322 InterfaceType type = elements.getType(node);
645 return irBuilder.buildListLiteral(type, values, 1323 return irBuilder.buildListLiteral(type, values,
646 allocationSiteType: getAllocationSiteType(node)); 1324 allocationSiteType: getAllocationSiteType(node));
647 } 1325 }
648 1326
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
706 // ## Sends ## 1384 // ## Sends ##
707 @override 1385 @override
708 void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) { 1386 void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) {
709 if (prefix != null) buildCheckDeferredIsLoaded(prefix, node); 1387 if (prefix != null) buildCheckDeferredIsLoaded(prefix, node);
710 } 1388 }
711 1389
712 /// Create a call to check that a deferred import has already been loaded. 1390 /// Create a call to check that a deferred import has already been loaded.
713 ir.Primitive buildCheckDeferredIsLoaded(PrefixElement prefix, ast.Send node) { 1391 ir.Primitive buildCheckDeferredIsLoaded(PrefixElement prefix, ast.Send node) {
714 SourceInformation sourceInformation = 1392 SourceInformation sourceInformation =
715 sourceInformationBuilder.buildCall(node, node.selector); 1393 sourceInformationBuilder.buildCall(node, node.selector);
716 JavaScriptBackend backend = compiler.backend;
717 return irBuilder.buildStaticFunctionInvocation( 1394 return irBuilder.buildStaticFunctionInvocation(
718 backend.helpers.checkDeferredIsLoaded, 1395 helpers.checkDeferredIsLoaded,
719 CallStructure.TWO_ARGS, <ir.Primitive>[ 1396 CallStructure.TWO_ARGS, <ir.Primitive>[
720 irBuilder.buildStringConstant( 1397 irBuilder.buildStringConstant(
721 compiler.deferredLoadTask.getImportDeferName(node, prefix)), 1398 compiler.deferredLoadTask.getImportDeferName(node, prefix)),
722 irBuilder.buildStringConstant('${prefix.deferredImport.uri}'), 1399 irBuilder.buildStringConstant('${prefix.deferredImport.uri}'),
723 ], sourceInformation: sourceInformation); 1400 ], sourceInformation: sourceInformation);
724 } 1401 }
725 1402
726 ir.Primitive visitNamedArgument(ast.NamedArgument node) { 1403 ir.Primitive visitNamedArgument(ast.NamedArgument node) {
727 assert(irBuilder.isOpen); 1404 assert(irBuilder.isOpen);
728 return visit(node.expression); 1405 return visit(node.expression);
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after
1156 ast.NodeList arguments, 1833 ast.NodeList arguments,
1157 CallStructure callStructure, 1834 CallStructure callStructure,
1158 _) { 1835 _) {
1159 ir.Primitive target = buildConstantExpression(constant, 1836 ir.Primitive target = buildConstantExpression(constant,
1160 sourceInformationBuilder.buildGet(node)); 1837 sourceInformationBuilder.buildGet(node));
1161 return translateCallInvoke(target, arguments, callStructure, 1838 return translateCallInvoke(target, arguments, callStructure,
1162 sourceInformationBuilder.buildCall(node, arguments)); 1839 sourceInformationBuilder.buildCall(node, arguments));
1163 } 1840 }
1164 1841
1165 @override 1842 @override
1843 ir.Primitive handleConstructorInvoke(
1844 ast.NewExpression node,
1845 ConstructorElement constructor,
1846 DartType type,
1847 ast.NodeList argumentsNode,
1848 CallStructure callStructure,
1849 _) {
1850
1851 // TODO(sigmund): move these checks down after visiting arguments
1852 // (see issue #25355)
1853 ast.Send send = node.send;
1854 // If an allocation refers to a type using a deferred import prefix (e.g.
1855 // `new lib.A()`), we must ensure that the deferred import has already been
1856 // loaded.
1857 var prefix = compiler.deferredLoadTask.deferredPrefixElement(
1858 send, elements);
1859 if (prefix != null) buildCheckDeferredIsLoaded(prefix, send);
1860
1861 // We also emit deferred import checks when using redirecting factories that
1862 // refer to deferred prefixes.
1863 if (constructor.isRedirectingFactory && !constructor.isCyclicRedirection) {
1864 ConstructorElement current = constructor;
1865 while (current.isRedirectingFactory) {
1866 var prefix = current.redirectionDeferredPrefix;
1867 if (prefix != null) buildCheckDeferredIsLoaded(prefix, send);
1868 current = current.immediateRedirectionTarget;
1869 }
1870 }
1871
1872 List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit);
1873 // Use default values from the effective target, not the immediate target.
1874 ConstructorElement target = constructor.effectiveTarget;
1875
1876 callStructure = normalizeStaticArguments(callStructure, target, arguments);
1877 TypeMask allocationSiteType;
1878
1879 if (Elements.isFixedListConstructorCall(constructor, send, compiler) ||
1880 Elements.isGrowableListConstructorCall(constructor, send, compiler) ||
1881 Elements.isFilledListConstructorCall(constructor, send, compiler) ||
1882 Elements.isConstructorOfTypedArraySubclass(constructor, compiler)) {
1883 allocationSiteType = getAllocationSiteType(send);
1884 }
1885 return irBuilder.buildConstructorInvocation(
1886 target,
1887 callStructure,
1888 constructor.computeEffectiveTargetType(type),
1889 arguments,
1890 sourceInformationBuilder.buildNew(node),
1891 allocationSiteType: allocationSiteType);
1892 }
1893
1894 @override
1166 ir.Primitive handleDynamicInvoke( 1895 ir.Primitive handleDynamicInvoke(
1167 ast.Send node, 1896 ast.Send node,
1168 ast.Node receiver, 1897 ast.Node receiver,
1169 ast.NodeList argumentsNode, 1898 ast.NodeList argumentsNode,
1170 Selector selector, 1899 Selector selector,
1171 _) { 1900 _) {
1172 ir.Primitive target = translateReceiver(receiver); 1901 ir.Primitive target = translateReceiver(receiver);
1173 List<ir.Primitive> arguments = <ir.Primitive>[]; 1902 List<ir.Primitive> arguments = <ir.Primitive>[];
1174 CallStructure callStructure = translateDynamicArguments( 1903 CallStructure callStructure = translateDynamicArguments(
1175 argumentsNode, selector.callStructure, arguments); 1904 argumentsNode, selector.callStructure, arguments);
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1257 translateDynamicArguments(argumentsNode, callStructure, arguments); 1986 translateDynamicArguments(argumentsNode, callStructure, arguments);
1258 return irBuilder.buildCallInvocation( 1987 return irBuilder.buildCallInvocation(
1259 target, 1988 target,
1260 callStructure, 1989 callStructure,
1261 arguments, 1990 arguments,
1262 sourceInformation: 1991 sourceInformation:
1263 sourceInformationBuilder.buildCall(node, argumentsNode)); 1992 sourceInformationBuilder.buildCall(node, argumentsNode));
1264 } 1993 }
1265 1994
1266 @override 1995 @override
1267 ir.Primitive handleStaticFunctionInvoke( 1996 ir.Primitive handleStaticFunctionInvoke(ast.Send node,
1268 ast.Send node,
1269 MethodElement function, 1997 MethodElement function,
1270 ast.NodeList arguments, 1998 ast.NodeList argumentsNode,
1271 CallStructure callStructure, 1999 CallStructure callStructure,
1272 _); 2000 _) {
2001 if (compiler.backend.isForeign(function)) {
2002 return handleForeignCode(node, function, argumentsNode, callStructure);
2003 } else {
2004 List<ir.Primitive> arguments = <ir.Primitive>[];
2005 callStructure = translateStaticArguments(argumentsNode, function,
2006 callStructure, arguments);
2007 return irBuilder.buildStaticFunctionInvocation(function,
2008 callStructure,
2009 arguments,
2010 sourceInformation:
2011 sourceInformationBuilder.buildCall(node, node.selector));
2012 }
2013 }
1273 2014
1274 @override 2015 @override
1275 ir.Primitive handleStaticFunctionIncompatibleInvoke( 2016 ir.Primitive handleStaticFunctionIncompatibleInvoke(
1276 ast.Send node, 2017 ast.Send node,
1277 MethodElement function, 2018 MethodElement function,
1278 ast.NodeList arguments, 2019 ast.NodeList arguments,
1279 CallStructure callStructure, _) { 2020 CallStructure callStructure, _) {
1280 return irBuilder.buildStaticNoSuchMethod( 2021 return irBuilder.buildStaticNoSuchMethod(
1281 elements.getSelector(node), 2022 elements.getSelector(node),
1282 arguments.nodes.mapToList(visit)); 2023 arguments.nodes.mapToList(visit));
(...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after
2003 irBuilder.buildSuperIndexSet(indexSetFunction, indexValue, result); 2744 irBuilder.buildSuperIndexSet(indexSetFunction, indexValue, result);
2004 } else { 2745 } else {
2005 buildInstanceNoSuchMethod( 2746 buildInstanceNoSuchMethod(
2006 new Selector.indexSet(), 2747 new Selector.indexSet(),
2007 elements.getTypeMask(node), 2748 elements.getTypeMask(node),
2008 <ir.Primitive>[indexValue, result]); 2749 <ir.Primitive>[indexValue, result]);
2009 } 2750 }
2010 }); 2751 });
2011 } 2752 }
2012 2753
2754 /// Build code to handle foreign code, that is, native JavaScript code, or
2755 /// builtin values and operations of the backend.
2756 ir.Primitive handleForeignCode(ast.Send node,
2757 MethodElement function,
2758 ast.NodeList argumentList,
2759 CallStructure callStructure) {
2760
2761 void validateArgumentCount({int minimum, int exactly}) {
2762 assert((minimum == null) != (exactly == null));
2763 int count = 0;
2764 int maximum;
2765 if (exactly != null) {
2766 minimum = exactly;
2767 maximum = exactly;
2768 }
2769 for (ast.Node argument in argumentList) {
2770 count++;
2771 if (maximum != null && count > maximum) {
2772 internalError(argument, 'Additional argument.');
2773 }
2774 }
2775 if (count < minimum) {
2776 internalError(node, 'Expected at least $minimum arguments.');
2777 }
2778 }
2779
2780 /// Call a helper method from the isolate library. The isolate library uses
2781 /// its own isolate structure, that encapsulates dart2js's isolate.
2782 ir.Primitive buildIsolateHelperInvocation(Element element,
2783 CallStructure callStructure) {
2784 if (element == null) {
2785 reporter.internalError(node,
2786 'Isolate library and compiler mismatch.');
2787 }
2788 List<ir.Primitive> arguments = <ir.Primitive>[];
2789 callStructure = translateStaticArguments(argumentList, element,
2790 callStructure, arguments);
2791 return irBuilder.buildStaticFunctionInvocation(
2792 element,
2793 callStructure,
2794 arguments,
2795 sourceInformation:
2796 sourceInformationBuilder.buildCall(node, node.selector));
2797 }
2798
2799 /// Lookup the value of the enum described by [node].
2800 getEnumValue(ast.Node node, EnumClassElement enumClass, List values) {
2801 Element element = elements[node];
2802 if (element is! FieldElement || element.enclosingClass != enumClass) {
2803 internalError(node, 'expected a JsBuiltin enum value');
2804 }
2805
2806 int index = enumClass.enumValues.indexOf(element);
2807 return values[index];
2808 }
2809
2810 /// Returns the String the node evaluates to, or throws an error if the
2811 /// result is not a string constant.
2812 String expectStringConstant(ast.Node node) {
2813 ir.Primitive nameValue = visit(node);
2814 if (nameValue is ir.Constant && nameValue.value.isString) {
2815 StringConstantValue constantValue = nameValue.value;
2816 return constantValue.primitiveValue.slowToString();
2817 } else {
2818 return internalError(node, 'expected a literal string');
2819 }
2820 }
2821
2822 Link<ast.Node> argumentNodes = argumentList.nodes;
2823 NativeBehavior behavior =
2824 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
2825 switch (function.name) {
2826 case 'JS':
2827 validateArgumentCount(minimum: 2);
2828 // The first two arguments are the type and the foreign code template,
2829 // which already have been analyzed by the resolver and can be retrieved
2830 // using [NativeBehavior]. We can ignore these arguments in the backend.
2831 List<ir.Primitive> arguments =
2832 argumentNodes.skip(2).mapToList(visit, growable: false);
2833 if (behavior.codeTemplate.positionalArgumentCount != arguments.length) {
2834 reporter.reportErrorMessage(
2835 node, MessageKind.GENERIC,
2836 {'text':
2837 'Mismatch between number of placeholders'
2838 ' and number of arguments.'});
2839 return irBuilder.buildNullConstant();
2840 }
2841
2842 if (HasCapturedPlaceholders.check(behavior.codeTemplate.ast)) {
2843 reporter.reportErrorMessage(node, MessageKind.JS_PLACEHOLDER_CAPTURE);
2844 return irBuilder.buildNullConstant();
2845 }
2846
2847 return irBuilder.buildForeignCode(behavior.codeTemplate, arguments,
2848 behavior);
2849
2850 case 'DART_CLOSURE_TO_JS':
2851 // TODO(ahe): This should probably take care to wrap the closure in
2852 // another closure that saves the current isolate.
2853 case 'RAW_DART_FUNCTION_REF':
2854 validateArgumentCount(exactly: 1);
2855
2856 ast.Node argument = node.arguments.single;
2857 FunctionElement closure = elements[argument].implementation;
2858 if (!Elements.isStaticOrTopLevelFunction(closure)) {
2859 internalError(argument,
2860 'only static or toplevel function supported');
2861 }
2862 if (closure.functionSignature.hasOptionalParameters) {
2863 internalError(argument,
2864 'closures with optional parameters not supported');
2865 }
2866 return irBuilder.buildForeignCode(
2867 js.js.expressionTemplateYielding(
2868 backend.emitter.staticFunctionAccess(closure)),
2869 <ir.Primitive>[],
2870 NativeBehavior.PURE,
2871 dependency: closure);
2872
2873 case 'JS_BUILTIN':
2874 // The first argument is a description of the type and effect of the
2875 // builtin, which has already been analyzed in the frontend. The second
2876 // argument must be a [JsBuiltin] value. All other arguments are
2877 // values used by the JavaScript template that is associated with the
2878 // builtin.
2879 validateArgumentCount(minimum: 2);
2880
2881 ast.Node builtin = argumentNodes.tail.head;
2882 JsBuiltin value = getEnumValue(builtin, helpers.jsBuiltinEnum,
2883 JsBuiltin.values);
2884 js.Template template = backend.emitter.builtinTemplateFor(value);
2885 List<ir.Primitive> arguments =
2886 argumentNodes.skip(2).mapToList(visit, growable: false);
2887 return irBuilder.buildForeignCode(template, arguments, behavior);
2888
2889 case 'JS_EMBEDDED_GLOBAL':
2890 validateArgumentCount(exactly: 2);
2891
2892 String name = expectStringConstant(argumentNodes.tail.head);
2893 js.Expression access =
2894 backend.emitter.generateEmbeddedGlobalAccess(name);
2895 js.Template template = js.js.expressionTemplateYielding(access);
2896 return irBuilder.buildForeignCode(template, <ir.Primitive>[], behavior);
2897
2898 case 'JS_INTERCEPTOR_CONSTANT':
2899 validateArgumentCount(exactly: 1);
2900
2901 ast.Node argument = argumentNodes.head;
2902 ir.Primitive argumentValue = visit(argument);
2903 if (argumentValue is ir.Constant && argumentValue.value.isType) {
2904 TypeConstantValue constant = argumentValue.value;
2905 ConstantValue interceptorValue =
2906 new InterceptorConstantValue(constant.representedType);
2907 return irBuilder.buildConstant(interceptorValue);
2908 }
2909 return internalError(argument, 'expected Type as argument');
2910
2911 case 'JS_EFFECT':
2912 return irBuilder.buildNullConstant();
2913
2914 case 'JS_GET_NAME':
2915 validateArgumentCount(exactly: 1);
2916
2917 ast.Node argument = argumentNodes.head;
2918 JsGetName id = getEnumValue(argument, helpers.jsGetNameEnum,
2919 JsGetName.values);
2920 js.Name name = backend.namer.getNameForJsGetName(argument, id);
2921 ConstantValue nameConstant =
2922 new SyntheticConstantValue(SyntheticConstantKind.NAME,
2923 js.js.quoteName(name));
2924
2925 return irBuilder.buildConstant(nameConstant);
2926
2927 case 'JS_GET_FLAG':
2928 validateArgumentCount(exactly: 1);
2929
2930 String name = expectStringConstant(argumentNodes.first);
2931 bool value = false;
2932 switch (name) {
2933 case 'MUST_RETAIN_METADATA':
2934 value = backend.mustRetainMetadata;
2935 break;
2936 case 'USE_CONTENT_SECURITY_POLICY':
2937 value = compiler.useContentSecurityPolicy;
2938 break;
2939 default:
2940 internalError(node, 'Unknown internal flag "$name".');
2941 }
2942 return irBuilder.buildBooleanConstant(value);
2943
2944 case 'JS_STRING_CONCAT':
2945 validateArgumentCount(exactly: 2);
2946 List<ir.Primitive> arguments = argumentNodes.mapToList(visit);
2947 return irBuilder.buildStringConcatenation(arguments);
2948
2949 case 'JS_CURRENT_ISOLATE_CONTEXT':
2950 validateArgumentCount(exactly: 0);
2951
2952 if (!compiler.hasIsolateSupport) {
2953 // If the isolate library is not used, we just generate code
2954 // to fetch the current isolate.
2955 continue getStaticState;
2956 }
2957 return buildIsolateHelperInvocation(helpers.currentIsolate,
2958 CallStructure.NO_ARGS);
2959
2960 getStaticState: case 'JS_GET_STATIC_STATE':
2961 validateArgumentCount(exactly: 0);
2962
2963 return irBuilder.buildForeignCode(
2964 js.js.parseForeignJS(backend.namer.staticStateHolder),
2965 const <ir.Primitive>[],
2966 NativeBehavior.PURE);
2967
2968 case 'JS_SET_STATIC_STATE':
2969 validateArgumentCount(exactly: 1);
2970
2971 ir.Primitive value = visit(argumentNodes.single);
2972 String isolateName = backend.namer.staticStateHolder;
2973 return irBuilder.buildForeignCode(
2974 js.js.parseForeignJS("$isolateName = #"),
2975 <ir.Primitive>[value],
2976 NativeBehavior.PURE);
2977
2978 case 'JS_CALL_IN_ISOLATE':
2979 validateArgumentCount(exactly: 2);
2980
2981 if (!compiler.hasIsolateSupport) {
2982 ir.Primitive closure = visit(argumentNodes.tail.head);
2983 return irBuilder.buildCallInvocation(closure, CallStructure.NO_ARGS,
2984 const <ir.Primitive>[]);
2985 }
2986 return buildIsolateHelperInvocation(helpers.callInIsolate,
2987 CallStructure.TWO_ARGS);
2988
2989 default:
2990 return giveup(node, 'unplemented native construct: ${function.name}');
2991 }
2992 }
2993
2013 /// Evaluates a string interpolation and appends each part to [accumulator] 2994 /// Evaluates a string interpolation and appends each part to [accumulator]
2014 /// (after stringify conversion). 2995 /// (after stringify conversion).
2015 void buildStringParts(ast.Node node, List<ir.Primitive> accumulator) { 2996 void buildStringParts(ast.Node node, List<ir.Primitive> accumulator) {
2016 if (node is ast.StringJuxtaposition) { 2997 if (node is ast.StringJuxtaposition) {
2017 buildStringParts(node.first, accumulator); 2998 buildStringParts(node.first, accumulator);
2018 buildStringParts(node.second, accumulator); 2999 buildStringParts(node.second, accumulator);
2019 } else if (node is ast.StringInterpolation) { 3000 } else if (node is ast.StringInterpolation) {
2020 buildStringParts(node.string, accumulator); 3001 buildStringParts(node.string, accumulator);
2021 for (ast.StringInterpolationPart part in node.parts) { 3002 for (ast.StringInterpolationPart part in node.parts) {
2022 buildStringParts(part.expression, accumulator); 3003 buildStringParts(part.expression, accumulator);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2057 sourceInformation: sourceInformationBuilder.buildGet(node)); 3038 sourceInformation: sourceInformationBuilder.buildGet(node));
2058 } 3039 }
2059 3040
2060 ir.Primitive visitThrow(ast.Throw node) { 3041 ir.Primitive visitThrow(ast.Throw node) {
2061 assert(irBuilder.isOpen); 3042 assert(irBuilder.isOpen);
2062 // This function is not called for throw expressions occurring as 3043 // This function is not called for throw expressions occurring as
2063 // statements. 3044 // statements.
2064 return irBuilder.buildNonTailThrow(visit(node.expression)); 3045 return irBuilder.buildNonTailThrow(visit(node.expression));
2065 } 3046 }
2066 3047
2067 ir.Primitive buildInstanceNoSuchMethod( 3048 ir.Primitive buildInstanceNoSuchMethod(Selector selector,
2068 Selector selector,
2069 TypeMask mask, 3049 TypeMask mask,
2070 List<ir.Primitive> arguments); 3050 List<ir.Primitive> arguments) {
2071 3051 return irBuilder.buildDynamicInvocation(
2072 ir.Primitive buildRuntimeError(String message); 3052 irBuilder.buildThis(),
2073 3053 Selectors.noSuchMethod_,
2074 ir.Primitive buildAbstractClassInstantiationError(ClassElement element); 3054 mask,
3055 [irBuilder.buildInvocationMirror(selector, arguments)]);
3056 }
3057
3058 ir.Primitive buildRuntimeError(String message) {
3059 return irBuilder.buildStaticFunctionInvocation(
3060 helpers.throwRuntimeError,
3061 new CallStructure.unnamed(1),
3062 [irBuilder.buildStringConstant(message)]);
3063 }
3064
3065 ir.Primitive buildAbstractClassInstantiationError(ClassElement element) {
3066 return irBuilder.buildStaticFunctionInvocation(
3067 helpers.throwAbstractClassInstantiationError,
3068 new CallStructure.unnamed(1),
3069 [irBuilder.buildStringConstant(element.name)]);
3070 }
2075 3071
2076 @override 3072 @override
2077 ir.Primitive visitUnresolvedCompound( 3073 ir.Primitive visitUnresolvedCompound(
2078 ast.Send node, 3074 ast.Send node,
2079 Element element, 3075 Element element,
2080 op.AssignmentOperator operator, 3076 op.AssignmentOperator operator,
2081 ast.Node rhs, _) { 3077 ast.Node rhs, _) {
2082 // TODO(asgerf): What is unresolved? The getter and/or the setter? 3078 // TODO(asgerf): What is unresolved? The getter and/or the setter?
2083 // If it was the setter, we must evaluate the right-hand side. 3079 // If it was the setter, we must evaluate the right-hand side.
2084 return irBuilder.buildStaticNoSuchMethod(elements.getSelector(node), []); 3080 return irBuilder.buildStaticNoSuchMethod(elements.getSelector(node), []);
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after
2624 } 3620 }
2625 3621
2626 Element get closureConverter { 3622 Element get closureConverter {
2627 return _backend.helpers.closureConverter; 3623 return _backend.helpers.closureConverter;
2628 } 3624 }
2629 3625
2630 void addNativeMethod(FunctionElement function) { 3626 void addNativeMethod(FunctionElement function) {
2631 _backend.emitter.nativeEmitter.nativeMethods.add(function); 3627 _backend.emitter.nativeEmitter.nativeMethods.add(function);
2632 } 3628 }
2633 } 3629 }
2634
2635 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder].
2636 class JsIrBuilderVisitor extends IrBuilderVisitor {
2637 JavaScriptBackend get backend => compiler.backend;
2638
2639 /// Result of closure conversion for the current body of code.
2640 ///
2641 /// Will be initialized upon entering the body of a function.
2642 /// It is computed by the [ClosureTranslator].
2643 ClosureClassMap closureClassMap;
2644
2645 JsIrBuilderVisitor(TreeElements elements,
2646 Compiler compiler,
2647 SourceInformationBuilder sourceInformationBuilder,
2648 TypeMaskSystem typeMaskSystem)
2649 : super(elements, compiler, sourceInformationBuilder, typeMaskSystem);
2650
2651 BackendHelpers get helpers => backend.helpers;
2652
2653 /// Builds the IR for creating an instance of the closure class corresponding
2654 /// to the given nested function.
2655 ClosureClassElement makeSubFunction(ast.FunctionExpression node) {
2656 ClosureClassMap innerMap =
2657 compiler.closureToClassMapper.getMappingForNestedFunction(node);
2658 ClosureClassElement closureClass = innerMap.closureClassElement;
2659 return closureClass;
2660 }
2661
2662 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
2663 return irBuilder.buildFunctionExpression(makeSubFunction(node),
2664 sourceInformationBuilder.buildCreate(node));
2665 }
2666
2667 visitFunctionDeclaration(ast.FunctionDeclaration node) {
2668 LocalFunctionElement element = elements[node.function];
2669 Object inner = makeSubFunction(node.function);
2670 irBuilder.declareLocalFunction(element, inner,
2671 sourceInformationBuilder.buildCreate(node.function));
2672 }
2673
2674 Map mapValues(Map map, dynamic fn(dynamic)) {
2675 Map result = {};
2676 map.forEach((key, value) {
2677 result[key] = fn(value);
2678 });
2679 return result;
2680 }
2681
2682 /// Converts closure.dart's CapturedVariable into a ClosureLocation.
2683 /// There is a 1:1 corresponce between these; we do this because the
2684 /// IR builder should not depend on synthetic elements.
2685 ClosureLocation getLocation(CapturedVariable v) {
2686 if (v is BoxFieldElement) {
2687 return new ClosureLocation(v.box, v);
2688 } else {
2689 ClosureFieldElement field = v;
2690 return new ClosureLocation(null, field);
2691 }
2692 }
2693
2694 /// If the current function is a nested function with free variables (or a
2695 /// captured reference to `this`), returns a [ClosureEnvironment]
2696 /// indicating how to access these.
2697 ClosureEnvironment getClosureEnvironment() {
2698 if (closureClassMap.closureElement == null) return null;
2699 return new ClosureEnvironment(
2700 closureClassMap.closureElement,
2701 closureClassMap.thisLocal,
2702 mapValues(closureClassMap.freeVariableMap, getLocation));
2703 }
2704
2705 /// If [node] has declarations for variables that should be boxed,
2706 /// returns a [ClosureScope] naming a box to create, and enumerating the
2707 /// variables that should be stored in the box.
2708 ///
2709 /// Also see [ClosureScope].
2710 ClosureScope getClosureScopeForNode(ast.Node node) {
2711 closurelib.ClosureScope scope = closureClassMap.capturingScopes[node];
2712 if (scope == null) return null;
2713 // We translate a ClosureScope from closure.dart into IR builder's variant
2714 // because the IR builder should not depend on the synthetic elements
2715 // created in closure.dart.
2716 return new ClosureScope(scope.boxElement,
2717 mapValues(scope.capturedVariables, getLocation),
2718 scope.boxedLoopVariables);
2719 }
2720
2721 /// Returns the [ClosureScope] for any function, possibly different from the
2722 /// one currently being built.
2723 ClosureScope getClosureScopeForFunction(FunctionElement function) {
2724 ClosureClassMap map =
2725 compiler.closureToClassMapper.computeClosureToClassMapping(
2726 function,
2727 function.node,
2728 elements);
2729 closurelib.ClosureScope scope = map.capturingScopes[function.node];
2730 if (scope == null) return null;
2731 return new ClosureScope(scope.boxElement,
2732 mapValues(scope.capturedVariables, getLocation),
2733 scope.boxedLoopVariables);
2734 }
2735
2736 ir.FunctionDefinition buildExecutable(ExecutableElement element) {
2737 return nullIfGiveup(() {
2738 ir.FunctionDefinition root;
2739 switch (element.kind) {
2740 case ElementKind.GENERATIVE_CONSTRUCTOR:
2741 root = buildConstructor(element);
2742 break;
2743
2744 case ElementKind.GENERATIVE_CONSTRUCTOR_BODY:
2745 root = buildConstructorBody(element);
2746 break;
2747
2748 case ElementKind.FACTORY_CONSTRUCTOR:
2749 case ElementKind.FUNCTION:
2750 case ElementKind.GETTER:
2751 case ElementKind.SETTER:
2752 root = buildFunction(element);
2753 break;
2754
2755 case ElementKind.FIELD:
2756 if (Elements.isStaticOrTopLevel(element)) {
2757 root = buildStaticFieldInitializer(element);
2758 } else {
2759 // Instance field initializers are inlined in the constructor,
2760 // so we shouldn't need to build anything here.
2761 // TODO(asgerf): But what should we return?
2762 return null;
2763 }
2764 break;
2765
2766 default:
2767 reporter.internalError(element, "Unexpected element type $element");
2768 }
2769 return root;
2770 });
2771 }
2772
2773 ir.FunctionDefinition buildStaticFieldInitializer(FieldElement element) {
2774 if (!backend.constants.lazyStatics.contains(element)) {
2775 return null; // Nothing to do.
2776 }
2777 closureClassMap =
2778 compiler.closureToClassMapper.computeClosureToClassMapping(
2779 element,
2780 element.node,
2781 elements);
2782 IrBuilder builder = getBuilderFor(element);
2783 return withBuilder(builder, () {
2784 irBuilder.buildFunctionHeader(<Local>[]);
2785 ir.Primitive initialValue = visit(element.initializer);
2786 ast.VariableDefinitions node = element.node;
2787 ast.SendSet sendSet = node.definitions.nodes.head;
2788 irBuilder.buildReturn(
2789 value: initialValue,
2790 sourceInformation:
2791 sourceInformationBuilder.buildReturn(sendSet.assignmentOperator));
2792 return irBuilder.makeFunctionDefinition();
2793 });
2794 }
2795
2796 /// Make a visitor suitable for translating ASTs taken from [context].
2797 ///
2798 /// Every visitor can only be applied to nodes in one context, because
2799 /// the [elements] field is specific to that context.
2800 JsIrBuilderVisitor makeVisitorForContext(AstElement context) {
2801 return new JsIrBuilderVisitor(
2802 context.resolvedAst.elements,
2803 compiler,
2804 sourceInformationBuilder.forContext(context),
2805 typeMaskSystem);
2806 }
2807
2808 /// Builds the IR for an [expression] taken from a different [context].
2809 ///
2810 /// Such expressions need to be compiled with a different [sourceFile] and
2811 /// [elements] mapping.
2812 ir.Primitive inlineExpression(AstElement context, ast.Expression expression) {
2813 JsIrBuilderVisitor visitor = makeVisitorForContext(context);
2814 return visitor.withBuilder(irBuilder, () => visitor.visit(expression));
2815 }
2816
2817 /// Builds the IR for a constant taken from a different [context].
2818 ///
2819 /// Such constants need to be compiled with a different [sourceFile] and
2820 /// [elements] mapping.
2821 ir.Primitive inlineConstant(AstElement context, ast.Expression exp) {
2822 JsIrBuilderVisitor visitor = makeVisitorForContext(context);
2823 return visitor.withBuilder(irBuilder, () => visitor.translateConstant(exp));
2824 }
2825
2826 IrBuilder getBuilderFor(Element element) {
2827 return new IrBuilder(
2828 new GlobalProgramInformation(compiler),
2829 compiler.backend.constants,
2830 element);
2831 }
2832
2833 /// Builds the IR for a given constructor.
2834 ///
2835 /// 1. Computes the type held in all own or "inherited" type variables.
2836 /// 2. Evaluates all own or inherited field initializers.
2837 /// 3. Creates the object and assigns its fields and runtime type.
2838 /// 4. Calls constructor body and super constructor bodies.
2839 /// 5. Returns the created object.
2840 ir.FunctionDefinition buildConstructor(ConstructorElement constructor) {
2841 // TODO(asgerf): Optimization: If constructor is redirecting, then just
2842 // evaluate arguments and call the target constructor.
2843 constructor = constructor.implementation;
2844 ClassElement classElement = constructor.enclosingClass.implementation;
2845
2846 IrBuilder builder = getBuilderFor(constructor);
2847
2848 final bool requiresTypeInformation =
2849 builder.program.requiresRuntimeTypesFor(classElement);
2850
2851 return withBuilder(builder, () {
2852 // Setup parameters and create a box if anything is captured.
2853 List<Local> parameters = <Local>[];
2854 constructor.functionSignature.orderedForEachParameter(
2855 (ParameterElement p) => parameters.add(p));
2856
2857 int firstTypeArgumentParameterIndex;
2858
2859 // If instances of the class may need runtime type information, we add a
2860 // synthetic parameter for each type parameter.
2861 if (requiresTypeInformation) {
2862 firstTypeArgumentParameterIndex = parameters.length;
2863 classElement.typeVariables.forEach((TypeVariableType variable) {
2864 parameters.add(new TypeVariableLocal(variable, constructor));
2865 });
2866 } else {
2867 classElement.typeVariables.forEach((TypeVariableType variable) {
2868 irBuilder.declareTypeVariable(variable, const DynamicType());
2869 });
2870 }
2871
2872 // Create IR parameters and setup the environment.
2873 List<ir.Parameter> irParameters = builder.buildFunctionHeader(parameters,
2874 closureScope: getClosureScopeForFunction(constructor));
2875
2876 // Create a list of the values of all type argument parameters, if any.
2877 List<ir.Primitive> typeInformation;
2878 if (requiresTypeInformation) {
2879 typeInformation = irParameters.sublist(firstTypeArgumentParameterIndex);
2880 } else {
2881 typeInformation = const <ir.Primitive>[];
2882 }
2883
2884 // -- Load values for type variables declared on super classes --
2885 // Field initializers for super classes can reference these, so they
2886 // must be available before evaluating field initializers.
2887 // This could be interleaved with field initialization, but we choose do
2888 // get it out of the way here to avoid complications with mixins.
2889 loadTypeVariablesForSuperClasses(classElement);
2890
2891 /// Maps each field from this class or a superclass to its initial value.
2892 Map<FieldElement, ir.Primitive> fieldValues =
2893 <FieldElement, ir.Primitive>{};
2894
2895 // -- Evaluate field initializers ---
2896 // Evaluate field initializers in constructor and super constructors.
2897 List<ConstructorElement> constructorList = <ConstructorElement>[];
2898 evaluateConstructorFieldInitializers(
2899 constructor, constructorList, fieldValues);
2900
2901 // All parameters in all constructors are now bound in the environment.
2902 // BoxLocals for captured parameters are also in the environment.
2903 // The initial value of all fields are now bound in [fieldValues].
2904
2905 // --- Create the object ---
2906 // Get the initial field values in the canonical order.
2907 List<ir.Primitive> instanceArguments = <ir.Primitive>[];
2908 classElement.forEachInstanceField((ClassElement c, FieldElement field) {
2909 ir.Primitive value = fieldValues[field];
2910 if (value != null) {
2911 instanceArguments.add(value);
2912 } else {
2913 assert(backend.isNativeOrExtendsNative(c));
2914 // Native fields are initialized elsewhere.
2915 }
2916 }, includeSuperAndInjectedMembers: true);
2917
2918 ir.Primitive instance = new ir.CreateInstance(
2919 classElement,
2920 instanceArguments,
2921 typeInformation,
2922 constructor.hasNode
2923 ? sourceInformationBuilder.buildCreate(constructor.node)
2924 // TODO(johnniwinther): Provide source information for creation
2925 // through synthetic constructors.
2926 : null);
2927 irBuilder.add(new ir.LetPrim(instance));
2928
2929 // --- Call constructor bodies ---
2930 for (ConstructorElement target in constructorList) {
2931 ConstructorBodyElement bodyElement = getConstructorBody(target);
2932 if (bodyElement == null) continue; // Skip if constructor has no body.
2933 List<ir.Primitive> bodyArguments = <ir.Primitive>[];
2934 for (Local param in getConstructorBodyParameters(bodyElement)) {
2935 bodyArguments.add(irBuilder.environment.lookup(param));
2936 }
2937 irBuilder.buildInvokeDirectly(bodyElement, instance, bodyArguments);
2938 }
2939
2940 // --- step 4: return the created object ----
2941 irBuilder.buildReturn(
2942 value: instance,
2943 sourceInformation:
2944 sourceInformationBuilder.buildImplicitReturn(constructor));
2945
2946 return irBuilder.makeFunctionDefinition();
2947 });
2948 }
2949
2950 /// Evaluates all field initializers on [constructor] and all constructors
2951 /// invoked through `this()` or `super()` ("superconstructors").
2952 ///
2953 /// The resulting field values will be available in [fieldValues]. The values
2954 /// are not stored in any fields.
2955 ///
2956 /// This procedure assumes that the parameters to [constructor] are available
2957 /// in the IR builder's environment.
2958 ///
2959 /// The parameters to superconstructors are, however, assumed *not* to be in
2960 /// the environment, but will be put there by this procedure.
2961 ///
2962 /// All constructors will be added to [supers], with superconstructors first.
2963 void evaluateConstructorFieldInitializers(
2964 ConstructorElement constructor,
2965 List<ConstructorElement> supers,
2966 Map<FieldElement, ir.Primitive> fieldValues) {
2967 assert(constructor.isImplementation);
2968 assert(constructor == elements.analyzedElement);
2969 ClassElement enclosingClass = constructor.enclosingClass.implementation;
2970 // Evaluate declaration-site field initializers, unless this constructor
2971 // redirects to another using a `this()` initializer. In that case, these
2972 // will be initialized by the effective target constructor.
2973 if (!constructor.isRedirectingGenerative) {
2974 enclosingClass.forEachInstanceField((ClassElement c, FieldElement field) {
2975 if (field.initializer != null) {
2976 fieldValues[field] = inlineExpression(field, field.initializer);
2977 } else {
2978 if (backend.isNativeOrExtendsNative(c)) {
2979 // Native field is initialized elsewhere.
2980 } else {
2981 // Fields without an initializer default to null.
2982 // This value will be overwritten below if an initializer is found.
2983 fieldValues[field] = irBuilder.buildNullConstant();
2984 }
2985 }
2986 });
2987 }
2988 // If this is a mixin constructor, it does not have its own parameter list
2989 // or initializer list. Directly forward to the super constructor.
2990 // Note that the declaration-site initializers originating from the
2991 // mixed-in class were handled above.
2992 if (enclosingClass.isMixinApplication) {
2993 forwardSynthesizedMixinConstructor(constructor, supers, fieldValues);
2994 return;
2995 }
2996 // Evaluate initializing parameters, e.g. `Foo(this.x)`.
2997 constructor.functionSignature.orderedForEachParameter(
2998 (ParameterElement parameter) {
2999 if (parameter.isInitializingFormal) {
3000 InitializingFormalElement fieldParameter = parameter;
3001 fieldValues[fieldParameter.fieldElement] =
3002 irBuilder.buildLocalVariableGet(parameter);
3003 }
3004 });
3005 // Evaluate constructor initializers, e.g. `Foo() : x = 50`.
3006 ast.FunctionExpression node = constructor.node;
3007 bool hasConstructorCall = false; // Has this() or super() initializer?
3008 if (node != null && node.initializers != null) {
3009 for(ast.Node initializer in node.initializers) {
3010 if (initializer is ast.SendSet) {
3011 // Field initializer.
3012 FieldElement field = elements[initializer];
3013 fieldValues[field] = visit(initializer.arguments.head);
3014 } else if (initializer is ast.Send) {
3015 // Super or this initializer.
3016 ConstructorElement target = elements[initializer].implementation;
3017 Selector selector = elements.getSelector(initializer);
3018 List<ir.Primitive> arguments = initializer.arguments.mapToList(visit);
3019 evaluateConstructorCallFromInitializer(
3020 target,
3021 selector.callStructure,
3022 arguments,
3023 supers,
3024 fieldValues);
3025 hasConstructorCall = true;
3026 } else {
3027 reporter.internalError(initializer,
3028 "Unexpected initializer type $initializer");
3029 }
3030 }
3031 }
3032 // If no super() or this() was found, also call default superconstructor.
3033 if (!hasConstructorCall && !enclosingClass.isObject) {
3034 ClassElement superClass = enclosingClass.superclass;
3035 FunctionElement target = superClass.lookupDefaultConstructor();
3036 if (target == null) {
3037 reporter.internalError(superClass, "No default constructor available.");
3038 }
3039 target = target.implementation;
3040 evaluateConstructorCallFromInitializer(
3041 target,
3042 CallStructure.NO_ARGS,
3043 const [],
3044 supers,
3045 fieldValues);
3046 }
3047 // Add this constructor after the superconstructors.
3048 supers.add(constructor);
3049 }
3050
3051 /// Evaluates a call to the given constructor from an initializer list.
3052 ///
3053 /// Calls [loadArguments] and [evaluateConstructorFieldInitializers] in a
3054 /// visitor that has the proper [TreeElements] mapping.
3055 void evaluateConstructorCallFromInitializer(
3056 ConstructorElement target,
3057 CallStructure call,
3058 List<ir.Primitive> arguments,
3059 List<ConstructorElement> supers,
3060 Map<FieldElement, ir.Primitive> fieldValues) {
3061 JsIrBuilderVisitor visitor = makeVisitorForContext(target);
3062 visitor.withBuilder(irBuilder, () {
3063 visitor.loadArguments(target, call, arguments);
3064 visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues);
3065 });
3066 }
3067
3068 /// Evaluate the implicit super call in the given mixin constructor.
3069 void forwardSynthesizedMixinConstructor(
3070 ConstructorElement constructor,
3071 List<ConstructorElement> supers,
3072 Map<FieldElement, ir.Primitive> fieldValues) {
3073 assert(constructor.enclosingClass.implementation.isMixinApplication);
3074 assert(constructor.isSynthesized);
3075 ConstructorElement target =
3076 constructor.definingConstructor.implementation;
3077 // The resolver gives us the exact same FunctionSignature for the two
3078 // constructors. The parameters for the synthesized constructor
3079 // are already in the environment, so the target constructor's parameters
3080 // are also in the environment since their elements are the same.
3081 assert(constructor.functionSignature == target.functionSignature);
3082 JsIrBuilderVisitor visitor = makeVisitorForContext(target);
3083 visitor.withBuilder(irBuilder, () {
3084 visitor.evaluateConstructorFieldInitializers(target, supers, fieldValues);
3085 });
3086 }
3087
3088 /// Loads the type variables for all super classes of [superClass] into the
3089 /// IR builder's environment with their corresponding values.
3090 ///
3091 /// The type variables for [currentClass] must already be in the IR builder's
3092 /// environment.
3093 ///
3094 /// Type variables are stored as [TypeVariableLocal] in the environment.
3095 ///
3096 /// This ensures that access to type variables mentioned inside the
3097 /// constructors and initializers will happen through the local environment
3098 /// instead of using 'this'.
3099 void loadTypeVariablesForSuperClasses(ClassElement currentClass) {
3100 if (currentClass.isObject) return;
3101 loadTypeVariablesForType(currentClass.supertype);
3102 if (currentClass is MixinApplicationElement) {
3103 loadTypeVariablesForType(currentClass.mixinType);
3104 }
3105 }
3106
3107 /// Loads all type variables for [type] and all of its super classes into
3108 /// the environment. All type variables mentioned in [type] must already
3109 /// be in the environment.
3110 void loadTypeVariablesForType(InterfaceType type) {
3111 ClassElement clazz = type.element;
3112 assert(clazz.typeVariables.length == type.typeArguments.length);
3113 for (int i = 0; i < clazz.typeVariables.length; ++i) {
3114 irBuilder.declareTypeVariable(clazz.typeVariables[i],
3115 type.typeArguments[i]);
3116 }
3117 loadTypeVariablesForSuperClasses(clazz);
3118 }
3119
3120 /// In preparation of inlining (part of) [target], the [arguments] are moved
3121 /// into the environment bindings for the corresponding parameters.
3122 ///
3123 /// Defaults for optional arguments are evaluated in order to ensure
3124 /// all parameters are available in the environment.
3125 void loadArguments(ConstructorElement target,
3126 CallStructure call,
3127 List<ir.Primitive> arguments) {
3128 assert(target.isImplementation);
3129 assert(target == elements.analyzedElement);
3130 FunctionSignature signature = target.functionSignature;
3131
3132 // Establish a scope in case parameters are captured.
3133 ClosureScope scope = getClosureScopeForFunction(target);
3134 irBuilder.enterScope(scope);
3135
3136 // Load required parameters
3137 int index = 0;
3138 signature.forEachRequiredParameter((ParameterElement param) {
3139 irBuilder.declareLocalVariable(param, initialValue: arguments[index]);
3140 index++;
3141 });
3142
3143 // Load optional parameters, evaluating default values for omitted ones.
3144 signature.forEachOptionalParameter((ParameterElement param) {
3145 ir.Primitive value;
3146 // Load argument if provided.
3147 if (signature.optionalParametersAreNamed) {
3148 int nameIndex = call.namedArguments.indexOf(param.name);
3149 if (nameIndex != -1) {
3150 int translatedIndex = call.positionalArgumentCount + nameIndex;
3151 value = arguments[translatedIndex];
3152 }
3153 } else if (index < arguments.length) {
3154 value = arguments[index];
3155 }
3156 // Load default if argument was not provided.
3157 if (value == null) {
3158 if (param.initializer != null) {
3159 value = visit(param.initializer);
3160 } else {
3161 value = irBuilder.buildNullConstant();
3162 }
3163 }
3164 irBuilder.declareLocalVariable(param, initialValue: value);
3165 index++;
3166 });
3167 }
3168
3169 /**
3170 * Returns the constructor body associated with the given constructor or
3171 * creates a new constructor body, if none can be found.
3172 *
3173 * Returns `null` if the constructor does not have a body.
3174 */
3175 ConstructorBodyElement getConstructorBody(FunctionElement constructor) {
3176 // TODO(asgerf): This is largely inherited from the SSA builder.
3177 // The ConstructorBodyElement has an invalid function signature, but we
3178 // cannot add a BoxLocal as parameter, because BoxLocal is not an element.
3179 // Instead of forging ParameterElements to forge a FunctionSignature, we
3180 // need a way to create backend methods without creating more fake elements.
3181 assert(constructor.isGenerativeConstructor);
3182 assert(constructor.isImplementation);
3183 if (constructor.isSynthesized) return null;
3184 ast.FunctionExpression node = constructor.node;
3185 // If we know the body doesn't have any code, we don't generate it.
3186 if (!node.hasBody()) return null;
3187 if (node.hasEmptyBody()) return null;
3188 ClassElement classElement = constructor.enclosingClass;
3189 ConstructorBodyElement bodyElement;
3190 classElement.forEachBackendMember((Element backendMember) {
3191 if (backendMember.isGenerativeConstructorBody) {
3192 ConstructorBodyElement body = backendMember;
3193 if (body.constructor == constructor) {
3194 bodyElement = backendMember;
3195 }
3196 }
3197 });
3198 if (bodyElement == null) {
3199 bodyElement = new ConstructorBodyElementX(constructor);
3200 classElement.addBackendMember(bodyElement);
3201
3202 if (constructor.isPatch) {
3203 // Create origin body element for patched constructors.
3204 ConstructorBodyElementX patch = bodyElement;
3205 ConstructorBodyElementX origin =
3206 new ConstructorBodyElementX(constructor.origin);
3207 origin.applyPatch(patch);
3208 classElement.origin.addBackendMember(bodyElement.origin);
3209 }
3210 }
3211 assert(bodyElement.isGenerativeConstructorBody);
3212 return bodyElement;
3213 }
3214
3215 /// The list of parameters to send from the generative constructor
3216 /// to the generative constructor body.
3217 ///
3218 /// Boxed parameters are not in the list, instead, a [BoxLocal] is passed
3219 /// containing the boxed parameters.
3220 ///
3221 /// For example, given the following constructor,
3222 ///
3223 /// Foo(x, y) : field = (() => ++x) { print(x + y) }
3224 ///
3225 /// the argument `x` would be replaced by a [BoxLocal]:
3226 ///
3227 /// Foo_body(box0, y) { print(box0.x + y) }
3228 ///
3229 List<Local> getConstructorBodyParameters(ConstructorBodyElement body) {
3230 List<Local> parameters = <Local>[];
3231 ClosureScope scope = getClosureScopeForFunction(body.constructor);
3232 if (scope != null) {
3233 parameters.add(scope.box);
3234 }
3235 body.functionSignature.orderedForEachParameter((ParameterElement param) {
3236 if (scope != null && scope.capturedVariables.containsKey(param)) {
3237 // Do not pass this parameter; the box will carry its value.
3238 } else {
3239 parameters.add(param);
3240 }
3241 });
3242 return parameters;
3243 }
3244
3245 TryBoxedVariables _analyzeTryBoxedVariables(ast.Node node) {
3246 TryBoxedVariables variables = new TryBoxedVariables(elements);
3247 try {
3248 variables.analyze(node);
3249 } catch (e) {
3250 bailoutMessage = variables.bailoutMessage;
3251 rethrow;
3252 }
3253 return variables;
3254 }
3255
3256 /// Builds the IR for the body of a constructor.
3257 ///
3258 /// This function is invoked from one or more "factory" constructors built by
3259 /// [buildConstructor].
3260 ir.FunctionDefinition buildConstructorBody(ConstructorBodyElement body) {
3261 ConstructorElement constructor = body.constructor;
3262 ast.FunctionExpression node = constructor.node;
3263 closureClassMap =
3264 compiler.closureToClassMapper.computeClosureToClassMapping(
3265 constructor,
3266 node,
3267 elements);
3268
3269 // We compute variables boxed in mutable variables on entry to each try
3270 // block, not including variables captured by a closure (which are boxed
3271 // in the heap). This duplicates some of the work of closure conversion
3272 // without directly using the results. This duplication is wasteful and
3273 // error-prone.
3274 // TODO(kmillikin): We should combine closure conversion and try/catch
3275 // variable analysis in some way.
3276 TryBoxedVariables variables = _analyzeTryBoxedVariables(node);
3277 tryStatements = variables.tryStatements;
3278 IrBuilder builder = getBuilderFor(body);
3279
3280 return withBuilder(builder, () {
3281 irBuilder.buildConstructorBodyHeader(getConstructorBodyParameters(body),
3282 getClosureScopeForNode(node));
3283 visit(node.body);
3284 return irBuilder.makeFunctionDefinition();
3285 });
3286 }
3287
3288 ir.FunctionDefinition buildFunction(FunctionElement element) {
3289 assert(invariant(element, element.isImplementation));
3290 ast.FunctionExpression node = element.node;
3291
3292 assert(!element.isSynthesized);
3293 assert(node != null);
3294 assert(elements[node] != null);
3295
3296 closureClassMap =
3297 compiler.closureToClassMapper.computeClosureToClassMapping(
3298 element,
3299 node,
3300 elements);
3301 TryBoxedVariables variables = _analyzeTryBoxedVariables(node);
3302 tryStatements = variables.tryStatements;
3303 IrBuilder builder = getBuilderFor(element);
3304 return withBuilder(builder, () => _makeFunctionBody(element, node));
3305 }
3306
3307 /// Creates a primitive for the default value of [parameter].
3308 ir.Primitive translateDefaultValue(ParameterElement parameter) {
3309 if (parameter.initializer == null) {
3310 return irBuilder.buildNullConstant();
3311 } else {
3312 return inlineConstant(parameter.executableContext, parameter.initializer);
3313 }
3314 }
3315
3316 CallStructure normalizeStaticArguments(CallStructure callStructure,
3317 FunctionElement target,
3318 List<ir.Primitive> arguments) {
3319 target = target.implementation;
3320 FunctionSignature signature = target.functionSignature;
3321 if (!signature.optionalParametersAreNamed &&
3322 signature.parameterCount == arguments.length) {
3323 return callStructure;
3324 }
3325
3326 if (!signature.optionalParametersAreNamed) {
3327 int i = signature.requiredParameterCount;
3328 signature.forEachOptionalParameter((ParameterElement element) {
3329 if (i < callStructure.positionalArgumentCount) {
3330 ++i;
3331 } else {
3332 arguments.add(translateDefaultValue(element));
3333 }
3334 });
3335 return new CallStructure(signature.parameterCount);
3336 }
3337
3338 int offset = signature.requiredParameterCount;
3339 List<ir.Primitive> namedArguments = arguments.sublist(offset);
3340 arguments.length = offset;
3341 List<String> normalizedNames = <String>[];
3342 // Iterate over the optional parameters of the signature, and try to
3343 // find them in the callStructure's named arguments. If found, we use the
3344 // value in the temporary list, otherwise the default value.
3345 signature.orderedOptionalParameters.forEach((ParameterElement element) {
3346 int nameIndex = callStructure.namedArguments.indexOf(element.name);
3347 arguments.add(nameIndex == -1 ? translateDefaultValue(element)
3348 : namedArguments[nameIndex]);
3349 normalizedNames.add(element.name);
3350 });
3351 return new CallStructure(signature.parameterCount, normalizedNames);
3352 }
3353
3354 CallStructure normalizeDynamicArguments(CallStructure callStructure,
3355 List<ir.Primitive> arguments) {
3356 assert(arguments.length == callStructure.argumentCount);
3357 if (callStructure.namedArguments.isEmpty) return callStructure;
3358 int destinationIndex = callStructure.positionalArgumentCount;
3359 List<ir.Primitive> namedArguments = arguments.sublist(destinationIndex);
3360 for (String argName in callStructure.getOrderedNamedArguments()) {
3361 int sourceIndex = callStructure.namedArguments.indexOf(argName);
3362 arguments[destinationIndex++] = namedArguments[sourceIndex];
3363 }
3364 return new CallStructure(callStructure.argumentCount,
3365 callStructure.getOrderedNamedArguments());
3366 }
3367
3368 @override
3369 ir.Primitive handleConstructorInvoke(
3370 ast.NewExpression node,
3371 ConstructorElement constructor,
3372 DartType type,
3373 ast.NodeList argumentsNode,
3374 CallStructure callStructure,
3375 _) {
3376
3377 // TODO(sigmund): move these checks down after visiting arguments
3378 // (see issue #25355)
3379 ast.Send send = node.send;
3380 // If an allocation refers to a type using a deferred import prefix (e.g.
3381 // `new lib.A()`), we must ensure that the deferred import has already been
3382 // loaded.
3383 var prefix = compiler.deferredLoadTask.deferredPrefixElement(
3384 send, elements);
3385 if (prefix != null) buildCheckDeferredIsLoaded(prefix, send);
3386
3387 // We also emit deferred import checks when using redirecting factories that
3388 // refer to deferred prefixes.
3389 if (constructor.isRedirectingFactory && !constructor.isCyclicRedirection) {
3390 ConstructorElement current = constructor;
3391 while (current.isRedirectingFactory) {
3392 var prefix = current.redirectionDeferredPrefix;
3393 if (prefix != null) buildCheckDeferredIsLoaded(prefix, send);
3394 current = current.immediateRedirectionTarget;
3395 }
3396 }
3397
3398 List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit);
3399 // Use default values from the effective target, not the immediate target.
3400 ConstructorElement target = constructor.effectiveTarget;
3401
3402 callStructure = normalizeStaticArguments(callStructure, target, arguments);
3403 TypeMask allocationSiteType;
3404
3405 if (Elements.isFixedListConstructorCall(constructor, send, compiler) ||
3406 Elements.isGrowableListConstructorCall(constructor, send, compiler) ||
3407 Elements.isFilledListConstructorCall(constructor, send, compiler) ||
3408 Elements.isConstructorOfTypedArraySubclass(constructor, compiler)) {
3409 allocationSiteType = getAllocationSiteType(send);
3410 }
3411 return irBuilder.buildConstructorInvocation(
3412 target,
3413 callStructure,
3414 constructor.computeEffectiveTargetType(type),
3415 arguments,
3416 sourceInformationBuilder.buildNew(node),
3417 allocationSiteType: allocationSiteType);
3418 }
3419
3420 @override
3421 ir.Primitive buildInstanceNoSuchMethod(Selector selector,
3422 TypeMask mask,
3423 List<ir.Primitive> arguments) {
3424 return irBuilder.buildDynamicInvocation(
3425 irBuilder.buildThis(),
3426 Selectors.noSuchMethod_,
3427 mask,
3428 [irBuilder.buildInvocationMirror(selector, arguments)]);
3429 }
3430
3431 @override
3432 ir.Primitive buildRuntimeError(String message) {
3433 return irBuilder.buildStaticFunctionInvocation(
3434 backend.helpers.throwRuntimeError,
3435 new CallStructure.unnamed(1),
3436 [irBuilder.buildStringConstant(message)]);
3437 }
3438
3439 @override
3440 ir.Primitive buildAbstractClassInstantiationError(ClassElement element) {
3441 return irBuilder.buildStaticFunctionInvocation(
3442 backend.helpers.throwAbstractClassInstantiationError,
3443 new CallStructure.unnamed(1),
3444 [irBuilder.buildStringConstant(element.name)]);
3445 }
3446
3447 @override
3448 ir.Primitive handleStaticFieldGet(ast.Send node, FieldElement field, _) {
3449 SourceInformation src = sourceInformationBuilder.buildGet(node);
3450 return buildStaticFieldGet(field, src);
3451 }
3452
3453 ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src) {
3454 ConstantValue constant = getConstantForVariable(field);
3455 if (constant != null && !field.isAssignable) {
3456 typeMaskSystem.associateConstantValueWithElement(constant, field);
3457 return irBuilder.buildConstant(constant, sourceInformation: src);
3458 } else if (backend.constants.lazyStatics.contains(field)) {
3459 return irBuilder.buildStaticFieldLazyGet(field, src);
3460 } else {
3461 return irBuilder.buildStaticFieldGet(field, src);
3462 }
3463 }
3464
3465 /// Build code to handle foreign code, that is, native JavaScript code, or
3466 /// builtin values and operations of the backend.
3467 ir.Primitive handleForeignCode(ast.Send node,
3468 MethodElement function,
3469 ast.NodeList argumentList,
3470 CallStructure callStructure) {
3471
3472 void validateArgumentCount({int minimum, int exactly}) {
3473 assert((minimum == null) != (exactly == null));
3474 int count = 0;
3475 int maximum;
3476 if (exactly != null) {
3477 minimum = exactly;
3478 maximum = exactly;
3479 }
3480 for (ast.Node argument in argumentList) {
3481 count++;
3482 if (maximum != null && count > maximum) {
3483 internalError(argument, 'Additional argument.');
3484 }
3485 }
3486 if (count < minimum) {
3487 internalError(node, 'Expected at least $minimum arguments.');
3488 }
3489 }
3490
3491 /// Call a helper method from the isolate library. The isolate library uses
3492 /// its own isolate structure, that encapsulates dart2js's isolate.
3493 ir.Primitive buildIsolateHelperInvocation(Element element,
3494 CallStructure callStructure) {
3495 if (element == null) {
3496 reporter.internalError(node,
3497 'Isolate library and compiler mismatch.');
3498 }
3499 List<ir.Primitive> arguments = <ir.Primitive>[];
3500 callStructure = translateStaticArguments(argumentList, element,
3501 callStructure, arguments);
3502 return irBuilder.buildStaticFunctionInvocation(
3503 element,
3504 callStructure,
3505 arguments,
3506 sourceInformation:
3507 sourceInformationBuilder.buildCall(node, node.selector));
3508 }
3509
3510 /// Lookup the value of the enum described by [node].
3511 getEnumValue(ast.Node node, EnumClassElement enumClass, List values) {
3512 Element element = elements[node];
3513 if (element is! FieldElement || element.enclosingClass != enumClass) {
3514 internalError(node, 'expected a JsBuiltin enum value');
3515 }
3516
3517 int index = enumClass.enumValues.indexOf(element);
3518 return values[index];
3519 }
3520
3521 /// Returns the String the node evaluates to, or throws an error if the
3522 /// result is not a string constant.
3523 String expectStringConstant(ast.Node node) {
3524 ir.Primitive nameValue = visit(node);
3525 if (nameValue is ir.Constant && nameValue.value.isString) {
3526 StringConstantValue constantValue = nameValue.value;
3527 return constantValue.primitiveValue.slowToString();
3528 } else {
3529 return internalError(node, 'expected a literal string');
3530 }
3531 }
3532
3533 Link<ast.Node> argumentNodes = argumentList.nodes;
3534 NativeBehavior behavior =
3535 compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
3536 switch (function.name) {
3537 case 'JS':
3538 validateArgumentCount(minimum: 2);
3539 // The first two arguments are the type and the foreign code template,
3540 // which already have been analyzed by the resolver and can be retrieved
3541 // using [NativeBehavior]. We can ignore these arguments in the backend.
3542 List<ir.Primitive> arguments =
3543 argumentNodes.skip(2).mapToList(visit, growable: false);
3544 if (behavior.codeTemplate.positionalArgumentCount != arguments.length) {
3545 reporter.reportErrorMessage(
3546 node, MessageKind.GENERIC,
3547 {'text':
3548 'Mismatch between number of placeholders'
3549 ' and number of arguments.'});
3550 return irBuilder.buildNullConstant();
3551 }
3552
3553 if (HasCapturedPlaceholders.check(behavior.codeTemplate.ast)) {
3554 reporter.reportErrorMessage(node, MessageKind.JS_PLACEHOLDER_CAPTURE);
3555 return irBuilder.buildNullConstant();
3556 }
3557
3558 return irBuilder.buildForeignCode(behavior.codeTemplate, arguments,
3559 behavior);
3560
3561 case 'DART_CLOSURE_TO_JS':
3562 // TODO(ahe): This should probably take care to wrap the closure in
3563 // another closure that saves the current isolate.
3564 case 'RAW_DART_FUNCTION_REF':
3565 validateArgumentCount(exactly: 1);
3566
3567 ast.Node argument = node.arguments.single;
3568 FunctionElement closure = elements[argument].implementation;
3569 if (!Elements.isStaticOrTopLevelFunction(closure)) {
3570 internalError(argument,
3571 'only static or toplevel function supported');
3572 }
3573 if (closure.functionSignature.hasOptionalParameters) {
3574 internalError(argument,
3575 'closures with optional parameters not supported');
3576 }
3577 return irBuilder.buildForeignCode(
3578 js.js.expressionTemplateYielding(
3579 backend.emitter.staticFunctionAccess(closure)),
3580 <ir.Primitive>[],
3581 NativeBehavior.PURE,
3582 dependency: closure);
3583
3584 case 'JS_BUILTIN':
3585 // The first argument is a description of the type and effect of the
3586 // builtin, which has already been analyzed in the frontend. The second
3587 // argument must be a [JsBuiltin] value. All other arguments are
3588 // values used by the JavaScript template that is associated with the
3589 // builtin.
3590 validateArgumentCount(minimum: 2);
3591
3592 ast.Node builtin = argumentNodes.tail.head;
3593 JsBuiltin value = getEnumValue(builtin, helpers.jsBuiltinEnum,
3594 JsBuiltin.values);
3595 js.Template template = backend.emitter.builtinTemplateFor(value);
3596 List<ir.Primitive> arguments =
3597 argumentNodes.skip(2).mapToList(visit, growable: false);
3598 return irBuilder.buildForeignCode(template, arguments, behavior);
3599
3600 case 'JS_EMBEDDED_GLOBAL':
3601 validateArgumentCount(exactly: 2);
3602
3603 String name = expectStringConstant(argumentNodes.tail.head);
3604 js.Expression access =
3605 backend.emitter.generateEmbeddedGlobalAccess(name);
3606 js.Template template = js.js.expressionTemplateYielding(access);
3607 return irBuilder.buildForeignCode(template, <ir.Primitive>[], behavior);
3608
3609 case 'JS_INTERCEPTOR_CONSTANT':
3610 validateArgumentCount(exactly: 1);
3611
3612 ast.Node argument = argumentNodes.head;
3613 ir.Primitive argumentValue = visit(argument);
3614 if (argumentValue is ir.Constant && argumentValue.value.isType) {
3615 TypeConstantValue constant = argumentValue.value;
3616 ConstantValue interceptorValue =
3617 new InterceptorConstantValue(constant.representedType);
3618 return irBuilder.buildConstant(interceptorValue);
3619 }
3620 return internalError(argument, 'expected Type as argument');
3621
3622 case 'JS_EFFECT':
3623 return irBuilder.buildNullConstant();
3624
3625 case 'JS_GET_NAME':
3626 validateArgumentCount(exactly: 1);
3627
3628 ast.Node argument = argumentNodes.head;
3629 JsGetName id = getEnumValue(argument, helpers.jsGetNameEnum,
3630 JsGetName.values);
3631 js.Name name = backend.namer.getNameForJsGetName(argument, id);
3632 ConstantValue nameConstant =
3633 new SyntheticConstantValue(SyntheticConstantKind.NAME,
3634 js.js.quoteName(name));
3635
3636 return irBuilder.buildConstant(nameConstant);
3637
3638 case 'JS_GET_FLAG':
3639 validateArgumentCount(exactly: 1);
3640
3641 String name = expectStringConstant(argumentNodes.first);
3642 bool value = false;
3643 switch (name) {
3644 case 'MUST_RETAIN_METADATA':
3645 value = backend.mustRetainMetadata;
3646 break;
3647 case 'USE_CONTENT_SECURITY_POLICY':
3648 value = compiler.useContentSecurityPolicy;
3649 break;
3650 default:
3651 internalError(node, 'Unknown internal flag "$name".');
3652 }
3653 return irBuilder.buildBooleanConstant(value);
3654
3655 case 'JS_STRING_CONCAT':
3656 validateArgumentCount(exactly: 2);
3657 List<ir.Primitive> arguments = argumentNodes.mapToList(visit);
3658 return irBuilder.buildStringConcatenation(arguments);
3659
3660 case 'JS_CURRENT_ISOLATE_CONTEXT':
3661 validateArgumentCount(exactly: 0);
3662
3663 if (!compiler.hasIsolateSupport) {
3664 // If the isolate library is not used, we just generate code
3665 // to fetch the current isolate.
3666 continue getStaticState;
3667 }
3668 return buildIsolateHelperInvocation(backend.helpers.currentIsolate,
3669 CallStructure.NO_ARGS);
3670
3671 getStaticState: case 'JS_GET_STATIC_STATE':
3672 validateArgumentCount(exactly: 0);
3673
3674 return irBuilder.buildForeignCode(
3675 js.js.parseForeignJS(backend.namer.staticStateHolder),
3676 const <ir.Primitive>[],
3677 NativeBehavior.PURE);
3678
3679 case 'JS_SET_STATIC_STATE':
3680 validateArgumentCount(exactly: 1);
3681
3682 ir.Primitive value = visit(argumentNodes.single);
3683 String isolateName = backend.namer.staticStateHolder;
3684 return irBuilder.buildForeignCode(
3685 js.js.parseForeignJS("$isolateName = #"),
3686 <ir.Primitive>[value],
3687 NativeBehavior.PURE);
3688
3689 case 'JS_CALL_IN_ISOLATE':
3690 validateArgumentCount(exactly: 2);
3691
3692 if (!compiler.hasIsolateSupport) {
3693 ir.Primitive closure = visit(argumentNodes.tail.head);
3694 return irBuilder.buildCallInvocation(closure, CallStructure.NO_ARGS,
3695 const <ir.Primitive>[]);
3696 }
3697 return buildIsolateHelperInvocation(backend.helpers.callInIsolate,
3698 CallStructure.TWO_ARGS);
3699
3700 default:
3701 return giveup(node, 'unplemented native construct: ${function.name}');
3702 }
3703 }
3704
3705 @override
3706 ir.Primitive handleStaticFunctionInvoke(ast.Send node,
3707 MethodElement function,
3708 ast.NodeList argumentsNode,
3709 CallStructure callStructure,
3710 _) {
3711 if (compiler.backend.isForeign(function)) {
3712 return handleForeignCode(node, function, argumentsNode, callStructure);
3713 } else {
3714 List<ir.Primitive> arguments = <ir.Primitive>[];
3715 callStructure = translateStaticArguments(argumentsNode, function,
3716 callStructure, arguments);
3717 return irBuilder.buildStaticFunctionInvocation(function,
3718 callStructure,
3719 arguments,
3720 sourceInformation:
3721 sourceInformationBuilder.buildCall(node, node.selector));
3722 }
3723 }
3724 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698