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

Side by Side Diff: pkg/compiler/lib/src/ssa/builder.dart

Issue 2814453005: Merge CommonElements and BackendHelpers! (Closed)
Patch Set: merge with head Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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 import 'dart:collection'; 5 import 'dart:collection';
6 6
7 import 'package:js_runtime/shared/embedded_names.dart'; 7 import 'package:js_runtime/shared/embedded_names.dart';
8 8
9 import '../closure.dart'; 9 import '../closure.dart';
10 import '../common.dart'; 10 import '../common.dart';
11 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; 11 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
12 import '../common/names.dart' show Identifiers, Selectors; 12 import '../common/names.dart' show Identifiers, Selectors;
13 import '../common/tasks.dart' show CompilerTask; 13 import '../common/tasks.dart' show CompilerTask;
14 import '../compiler.dart' show Compiler; 14 import '../compiler.dart' show Compiler;
15 import '../constants/constant_system.dart'; 15 import '../constants/constant_system.dart';
16 import '../constants/expressions.dart'; 16 import '../constants/expressions.dart';
17 import '../constants/values.dart'; 17 import '../constants/values.dart';
18 import '../common_elements.dart' show CommonElements; 18 import '../common_elements.dart' show CommonElements;
19 import '../elements/resolution_types.dart'; 19 import '../elements/resolution_types.dart';
20 import '../diagnostics/messages.dart' show Message, MessageTemplate; 20 import '../diagnostics/messages.dart' show Message, MessageTemplate;
21 import '../dump_info.dart' show InfoReporter; 21 import '../dump_info.dart' show InfoReporter;
22 import '../elements/elements.dart'; 22 import '../elements/elements.dart';
23 import '../elements/entities.dart'; 23 import '../elements/entities.dart';
24 import '../elements/modelx.dart' show ConstructorBodyElementX; 24 import '../elements/modelx.dart' show ConstructorBodyElementX;
25 import '../io/source_information.dart'; 25 import '../io/source_information.dart';
26 import '../js/js.dart' as js; 26 import '../js/js.dart' as js;
27 import '../js_backend/backend_helpers.dart' show BackendHelpers; 27 import '../js_backend/backend.dart' show JavaScriptBackend;
28 import '../js_backend/js_backend.dart'; 28 import '../js_backend/js_backend.dart';
29 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; 29 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
30 import '../native/native.dart' as native; 30 import '../native/native.dart' as native;
31 import '../resolution/operators.dart'; 31 import '../resolution/operators.dart';
32 import '../resolution/semantic_visitor.dart'; 32 import '../resolution/semantic_visitor.dart';
33 import '../resolution/tree_elements.dart' show TreeElements; 33 import '../resolution/tree_elements.dart' show TreeElements;
34 import '../tree/tree.dart' as ast; 34 import '../tree/tree.dart' as ast;
35 import '../types/types.dart'; 35 import '../types/types.dart';
36 import '../universe/call_structure.dart' show CallStructure; 36 import '../universe/call_structure.dart' show CallStructure;
37 import '../universe/selector.dart' show Selector; 37 import '../universe/selector.dart' show Selector;
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 sourceElementStack.add(target); 216 sourceElementStack.add(target);
217 sourceInformationBuilder = 217 sourceInformationBuilder =
218 sourceInformationFactory.createBuilderForContext(resolvedAst); 218 sourceInformationFactory.createBuilderForContext(resolvedAst);
219 graph.sourceInformation = 219 graph.sourceInformation =
220 sourceInformationBuilder.buildVariableDeclaration(); 220 sourceInformationBuilder.buildVariableDeclaration();
221 localsHandler = new LocalsHandler(this, target, null, compiler); 221 localsHandler = new LocalsHandler(this, target, null, compiler);
222 loopHandler = new SsaLoopHandler(this); 222 loopHandler = new SsaLoopHandler(this);
223 typeBuilder = new TypeBuilder(this); 223 typeBuilder = new TypeBuilder(this);
224 } 224 }
225 225
226 BackendHelpers get helpers => backend.helpers;
227
228 RuntimeTypesEncoder get rtiEncoder => backend.rtiEncoder; 226 RuntimeTypesEncoder get rtiEncoder => backend.rtiEncoder;
229 227
230 DiagnosticReporter get reporter => compiler.reporter; 228 DiagnosticReporter get reporter => compiler.reporter;
231 229
232 CommonElements get commonElements => closedWorld.commonElements; 230 CommonElements get commonElements => closedWorld.commonElements;
233 231
234 Element get targetElement => target; 232 Element get targetElement => target;
235 233
236 /// Reference to resolved elements in [target]'s AST. 234 /// Reference to resolved elements in [target]'s AST.
237 TreeElements get elements => resolvedAst.elements; 235 TreeElements get elements => resolvedAst.elements;
(...skipping 477 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 }, 713 },
716 visitElse: null, 714 visitElse: null,
717 sourceInformation: sourceInformationBuilder.buildIf(function.body)); 715 sourceInformation: sourceInformationBuilder.buildIf(function.body));
718 } 716 }
719 } 717 }
720 if (const bool.fromEnvironment('unreachable-throw')) { 718 if (const bool.fromEnvironment('unreachable-throw')) {
721 var emptyParameters = 719 var emptyParameters =
722 parameters.values.where((p) => p.instructionType.isEmpty); 720 parameters.values.where((p) => p.instructionType.isEmpty);
723 if (emptyParameters.length > 0) { 721 if (emptyParameters.length > 0) {
724 addComment('${emptyParameters} inferred as [empty]'); 722 addComment('${emptyParameters} inferred as [empty]');
725 pushInvokeStatic(function.body, helpers.assertUnreachableMethod, []); 723 pushInvokeStatic(
724 function.body, commonElements.assertUnreachableMethod, []);
726 pop(); 725 pop();
727 return closeFunction(); 726 return closeFunction();
728 } 727 }
729 } 728 }
730 function.body.accept(this); 729 function.body.accept(this);
731 return closeFunction(); 730 return closeFunction();
732 } 731 }
733 732
734 /// Adds a JavaScript comment to the output. The comment will be omitted in 733 /// Adds a JavaScript comment to the output. The comment will be omitted in
735 /// minified mode. Each line in [text] is preceded with `//` and indented. 734 /// minified mode. Each line in [text] is preceded with `//` and indented.
(...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after
1441 // Otherwise it is a lazy initializer which does not have parameters. 1440 // Otherwise it is a lazy initializer which does not have parameters.
1442 assert(element is VariableElement); 1441 assert(element is VariableElement);
1443 } 1442 }
1444 1443
1445 insertTraceCall(element); 1444 insertTraceCall(element);
1446 insertCoverageCall(element); 1445 insertCoverageCall(element);
1447 } 1446 }
1448 1447
1449 insertTraceCall(Element element) { 1448 insertTraceCall(Element element) {
1450 if (JavaScriptBackend.TRACE_METHOD == 'console') { 1449 if (JavaScriptBackend.TRACE_METHOD == 'console') {
1451 if (element == backend.helpers.traceHelper) return; 1450 if (element == commonElements.traceHelper) return;
1452 n(e) => e == null ? '' : e.name; 1451 n(e) => e == null ? '' : e.name;
1453 String name = "${n(element.library)}:${n(element.enclosingClass)}." 1452 String name = "${n(element.library)}:${n(element.enclosingClass)}."
1454 "${n(element)}"; 1453 "${n(element)}";
1455 HConstant nameConstant = addConstantString(name); 1454 HConstant nameConstant = addConstantString(name);
1456 add(new HInvokeStatic(backend.helpers.traceHelper, 1455 add(new HInvokeStatic(commonElements.traceHelper,
1457 <HInstruction>[nameConstant], commonMasks.dynamicType)); 1456 <HInstruction>[nameConstant], commonMasks.dynamicType));
1458 } 1457 }
1459 } 1458 }
1460 1459
1461 insertCoverageCall(Element element) { 1460 insertCoverageCall(Element element) {
1462 if (JavaScriptBackend.TRACE_METHOD == 'post') { 1461 if (JavaScriptBackend.TRACE_METHOD == 'post') {
1463 if (element == backend.helpers.traceHelper) return; 1462 if (element == commonElements.traceHelper) return;
1464 // TODO(sigmund): create a better uuid for elements. 1463 // TODO(sigmund): create a better uuid for elements.
1465 HConstant idConstant = 1464 HConstant idConstant =
1466 graph.addConstantInt(element.hashCode, closedWorld); 1465 graph.addConstantInt(element.hashCode, closedWorld);
1467 HConstant nameConstant = addConstantString(element.name); 1466 HConstant nameConstant = addConstantString(element.name);
1468 add(new HInvokeStatic(backend.helpers.traceHelper, 1467 add(new HInvokeStatic(commonElements.traceHelper,
1469 <HInstruction>[idConstant, nameConstant], commonMasks.dynamicType)); 1468 <HInstruction>[idConstant, nameConstant], commonMasks.dynamicType));
1470 } 1469 }
1471 } 1470 }
1472 1471
1473 void assertIsSubtype(ast.Node node, ResolutionDartType subtype, 1472 void assertIsSubtype(ast.Node node, ResolutionDartType subtype,
1474 ResolutionDartType supertype, String message) { 1473 ResolutionDartType supertype, String message) {
1475 HInstruction subtypeInstruction = typeBuilder.analyzeTypeArgument( 1474 HInstruction subtypeInstruction = typeBuilder.analyzeTypeArgument(
1476 localsHandler.substInContext(subtype), sourceElement); 1475 localsHandler.substInContext(subtype), sourceElement);
1477 HInstruction supertypeInstruction = typeBuilder.analyzeTypeArgument( 1476 HInstruction supertypeInstruction = typeBuilder.analyzeTypeArgument(
1478 localsHandler.substInContext(supertype), sourceElement); 1477 localsHandler.substInContext(supertype), sourceElement);
1479 HInstruction messageInstruction = graph.addConstantString( 1478 HInstruction messageInstruction = graph.addConstantString(
1480 new ast.DartString.literal(message), closedWorld); 1479 new ast.DartString.literal(message), closedWorld);
1481 MethodElement element = helpers.assertIsSubtype; 1480 MethodElement element = commonElements.assertIsSubtype;
1482 var inputs = <HInstruction>[ 1481 var inputs = <HInstruction>[
1483 subtypeInstruction, 1482 subtypeInstruction,
1484 supertypeInstruction, 1483 supertypeInstruction,
1485 messageInstruction 1484 messageInstruction
1486 ]; 1485 ];
1487 HInstruction assertIsSubtype = 1486 HInstruction assertIsSubtype =
1488 new HInvokeStatic(element, inputs, subtypeInstruction.instructionType); 1487 new HInvokeStatic(element, inputs, subtypeInstruction.instructionType);
1489 registry?.registerTypeVariableBoundsSubtypeCheck(subtype, supertype); 1488 registry?.registerTypeVariableBoundsSubtypeCheck(subtype, supertype);
1490 add(assertIsSubtype); 1489 add(assertIsSubtype);
1491 } 1490 }
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1536 1535
1537 visitAssert(ast.Assert node) { 1536 visitAssert(ast.Assert node) {
1538 if (!compiler.options.enableUserAssertions) return; 1537 if (!compiler.options.enableUserAssertions) return;
1539 1538
1540 if (!node.hasMessage) { 1539 if (!node.hasMessage) {
1541 // Generate: 1540 // Generate:
1542 // 1541 //
1543 // assertHelper(condition); 1542 // assertHelper(condition);
1544 // 1543 //
1545 visit(node.condition); 1544 visit(node.condition);
1546 pushInvokeStatic(node, helpers.assertHelper, [pop()]); 1545 pushInvokeStatic(node, commonElements.assertHelper, [pop()]);
1547 pop(); 1546 pop();
1548 return; 1547 return;
1549 } 1548 }
1550 // Assert has message. Generate: 1549 // Assert has message. Generate:
1551 // 1550 //
1552 // if (assertTest(condition)) assertThrow(message); 1551 // if (assertTest(condition)) assertThrow(message);
1553 // 1552 //
1554 void buildCondition() { 1553 void buildCondition() {
1555 visit(node.condition); 1554 visit(node.condition);
1556 pushInvokeStatic(node, helpers.assertTest, [pop()]); 1555 pushInvokeStatic(node, commonElements.assertTest, [pop()]);
1557 } 1556 }
1558 1557
1559 void fail() { 1558 void fail() {
1560 visit(node.message); 1559 visit(node.message);
1561 pushInvokeStatic(node, helpers.assertThrow, [pop()]); 1560 pushInvokeStatic(node, commonElements.assertThrow, [pop()]);
1562 pop(); 1561 pop();
1563 } 1562 }
1564 1563
1565 handleIf(node: node, visitCondition: buildCondition, visitThen: fail); 1564 handleIf(node: node, visitCondition: buildCondition, visitThen: fail);
1566 } 1565 }
1567 1566
1568 visitBlock(ast.Block node) { 1567 visitBlock(ast.Block node) {
1569 assert(!isAborted()); 1568 assert(!isAborted());
1570 if (!isReachable) return; // This can only happen when inlining. 1569 if (!isReachable) return; // This can only happen when inlining.
1571 for (Link<ast.Node> link = node.statements.nodes; 1570 for (Link<ast.Node> link = node.statements.nodes;
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after
2034 /// Inserts a call to checkDeferredIsLoaded for [prefixElement]. 2033 /// Inserts a call to checkDeferredIsLoaded for [prefixElement].
2035 /// If [prefixElement] is [null] ndo nothing. 2034 /// If [prefixElement] is [null] ndo nothing.
2036 void generateIsDeferredLoadedCheckIfNeeded( 2035 void generateIsDeferredLoadedCheckIfNeeded(
2037 PrefixElement prefixElement, ast.Node location) { 2036 PrefixElement prefixElement, ast.Node location) {
2038 if (prefixElement == null) return; 2037 if (prefixElement == null) return;
2039 String loadId = 2038 String loadId =
2040 compiler.deferredLoadTask.getImportDeferName(location, prefixElement); 2039 compiler.deferredLoadTask.getImportDeferName(location, prefixElement);
2041 HInstruction loadIdConstant = addConstantString(loadId); 2040 HInstruction loadIdConstant = addConstantString(loadId);
2042 String uri = prefixElement.deferredImport.uri.toString(); 2041 String uri = prefixElement.deferredImport.uri.toString();
2043 HInstruction uriConstant = addConstantString(uri); 2042 HInstruction uriConstant = addConstantString(uri);
2044 MethodElement helper = helpers.checkDeferredIsLoaded; 2043 MethodElement helper = commonElements.checkDeferredIsLoaded;
2045 pushInvokeStatic(location, helper, [loadIdConstant, uriConstant]); 2044 pushInvokeStatic(location, helper, [loadIdConstant, uriConstant]);
2046 pop(); 2045 pop();
2047 } 2046 }
2048 2047
2049 /// Inserts a call to checkDeferredIsLoaded if the send has a prefix that 2048 /// Inserts a call to checkDeferredIsLoaded if the send has a prefix that
2050 /// resolves to a deferred library. 2049 /// resolves to a deferred library.
2051 void generateIsDeferredLoadedCheckOfSend(ast.Send node) { 2050 void generateIsDeferredLoadedCheckOfSend(ast.Send node) {
2052 generateIsDeferredLoadedCheckIfNeeded( 2051 generateIsDeferredLoadedCheckIfNeeded(
2053 compiler.deferredLoadTask.deferredPrefixElement(node, elements), node); 2052 compiler.deferredLoadTask.deferredPrefixElement(node, elements), node);
2054 } 2053 }
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after
2400 generateTypeError(node, message); 2399 generateTypeError(node, message);
2401 HInstruction call = pop(); 2400 HInstruction call = pop();
2402 return new HIs.compound(type, expression, call, commonMasks.boolType); 2401 return new HIs.compound(type, expression, call, commonMasks.boolType);
2403 } else if (type.isFunctionType) { 2402 } else if (type.isFunctionType) {
2404 HInstruction representation = 2403 HInstruction representation =
2405 typeBuilder.analyzeTypeArgument(type, sourceElement); 2404 typeBuilder.analyzeTypeArgument(type, sourceElement);
2406 List<HInstruction> inputs = <HInstruction>[ 2405 List<HInstruction> inputs = <HInstruction>[
2407 expression, 2406 expression,
2408 representation, 2407 representation,
2409 ]; 2408 ];
2410 pushInvokeStatic(node, helpers.functionTypeTest, inputs, 2409 pushInvokeStatic(node, commonElements.functionTypeTest, inputs,
2411 typeMask: commonMasks.boolType); 2410 typeMask: commonMasks.boolType);
2412 HInstruction call = pop(); 2411 HInstruction call = pop();
2413 return new HIs.compound(type, expression, call, commonMasks.boolType); 2412 return new HIs.compound(type, expression, call, commonMasks.boolType);
2414 } else if (type.isTypeVariable) { 2413 } else if (type.isTypeVariable) {
2415 HInstruction runtimeType = 2414 HInstruction runtimeType =
2416 typeBuilder.addTypeVariableReference(type, sourceElement); 2415 typeBuilder.addTypeVariableReference(type, sourceElement);
2417 MethodElement helper = helpers.checkSubtypeOfRuntimeType; 2416 MethodElement helper = commonElements.checkSubtypeOfRuntimeType;
2418 List<HInstruction> inputs = <HInstruction>[expression, runtimeType]; 2417 List<HInstruction> inputs = <HInstruction>[expression, runtimeType];
2419 pushInvokeStatic(null, helper, inputs, typeMask: commonMasks.boolType); 2418 pushInvokeStatic(null, helper, inputs, typeMask: commonMasks.boolType);
2420 HInstruction call = pop(); 2419 HInstruction call = pop();
2421 return new HIs.variable(type, expression, call, commonMasks.boolType); 2420 return new HIs.variable(type, expression, call, commonMasks.boolType);
2422 } else if (RuntimeTypesSubstitutions.hasTypeArguments(type)) { 2421 } else if (RuntimeTypesSubstitutions.hasTypeArguments(type)) {
2423 ClassElement element = type.element; 2422 ClassElement element = type.element;
2424 MethodElement helper = helpers.checkSubtype; 2423 MethodElement helper = commonElements.checkSubtype;
2425 HInstruction representations = 2424 HInstruction representations =
2426 typeBuilder.buildTypeArgumentRepresentations(type, sourceElement); 2425 typeBuilder.buildTypeArgumentRepresentations(type, sourceElement);
2427 add(representations); 2426 add(representations);
2428 js.Name operator = backend.namer.operatorIs(element); 2427 js.Name operator = backend.namer.operatorIs(element);
2429 HInstruction isFieldName = addConstantStringFromName(operator); 2428 HInstruction isFieldName = addConstantStringFromName(operator);
2430 HInstruction asFieldName = closedWorld.hasAnyStrictSubtype(element) 2429 HInstruction asFieldName = closedWorld.hasAnyStrictSubtype(element)
2431 ? addConstantStringFromName(backend.namer.substitutionName(element)) 2430 ? addConstantStringFromName(backend.namer.substitutionName(element))
2432 : graph.addConstantNull(closedWorld); 2431 : graph.addConstantNull(closedWorld);
2433 List<HInstruction> inputs = <HInstruction>[ 2432 List<HInstruction> inputs = <HInstruction>[
2434 expression, 2433 expression,
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
2678 // If the isolate library is not used, we just generate code 2677 // If the isolate library is not used, we just generate code
2679 // to fetch the static state. 2678 // to fetch the static state.
2680 String name = backend.namer.staticStateHolder; 2679 String name = backend.namer.staticStateHolder;
2681 push(new HForeignCode( 2680 push(new HForeignCode(
2682 js.js.parseForeignJS(name), commonMasks.dynamicType, <HInstruction>[], 2681 js.js.parseForeignJS(name), commonMasks.dynamicType, <HInstruction>[],
2683 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER)); 2682 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
2684 } else { 2683 } else {
2685 // Call a helper method from the isolate library. The isolate 2684 // Call a helper method from the isolate library. The isolate
2686 // library uses its own isolate structure, that encapsulates 2685 // library uses its own isolate structure, that encapsulates
2687 // Leg's isolate. 2686 // Leg's isolate.
2688 MethodElement element = helpers.currentIsolate; 2687 MethodElement element = commonElements.currentIsolate;
2689 if (element == null) { 2688 if (element == null) {
2690 reporter.internalError(node, 'Isolate library and compiler mismatch.'); 2689 reporter.internalError(node, 'Isolate library and compiler mismatch.');
2691 } 2690 }
2692 pushInvokeStatic(null, element, [], typeMask: commonMasks.dynamicType); 2691 pushInvokeStatic(null, element, [], typeMask: commonMasks.dynamicType);
2693 } 2692 }
2694 } 2693 }
2695 2694
2696 void handleForeignJsGetFlag(ast.Send node) { 2695 void handleForeignJsGetFlag(ast.Send node) {
2697 List<ast.Node> arguments = node.arguments.toList(); 2696 List<ast.Node> arguments = node.arguments.toList();
2698 ast.Node argument; 2697 ast.Node argument;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
2746 default: 2745 default:
2747 for (int i = 1; i < arguments.length; i++) { 2746 for (int i = 1; i < arguments.length; i++) {
2748 reporter.reportErrorMessage(arguments[i], MessageKind.GENERIC, 2747 reporter.reportErrorMessage(arguments[i], MessageKind.GENERIC,
2749 {'text': 'Error: Extra argument to JS_GET_NAME.'}); 2748 {'text': 'Error: Extra argument to JS_GET_NAME.'});
2750 } 2749 }
2751 return; 2750 return;
2752 } 2751 }
2753 Element element = elements[argument]; 2752 Element element = elements[argument];
2754 if (element == null || 2753 if (element == null ||
2755 element is! EnumConstantElement || 2754 element is! EnumConstantElement ||
2756 element.enclosingClass != helpers.jsGetNameEnum) { 2755 element.enclosingClass != commonElements.jsGetNameEnum) {
2757 reporter.reportErrorMessage(argument, MessageKind.GENERIC, 2756 reporter.reportErrorMessage(argument, MessageKind.GENERIC,
2758 {'text': 'Error: Expected a JsGetName enum value.'}); 2757 {'text': 'Error: Expected a JsGetName enum value.'});
2759 } 2758 }
2760 EnumConstantElement enumConstant = element; 2759 EnumConstantElement enumConstant = element;
2761 int index = enumConstant.index; 2760 int index = enumConstant.index;
2762 stack.add(addConstantStringFromName( 2761 stack.add(addConstantStringFromName(
2763 backend.namer.getNameForJsGetName(argument, JsGetName.values[index]))); 2762 backend.namer.getNameForJsGetName(argument, JsGetName.values[index])));
2764 } 2763 }
2765 2764
2766 void handleForeignJsBuiltin(ast.Send node) { 2765 void handleForeignJsBuiltin(ast.Send node) {
2767 List<ast.Node> arguments = node.arguments.toList(); 2766 List<ast.Node> arguments = node.arguments.toList();
2768 ast.Node argument; 2767 ast.Node argument;
2769 if (arguments.length < 2) { 2768 if (arguments.length < 2) {
2770 reporter.reportErrorMessage(node, MessageKind.GENERIC, 2769 reporter.reportErrorMessage(node, MessageKind.GENERIC,
2771 {'text': 'Error: Expected at least two arguments to JS_BUILTIN.'}); 2770 {'text': 'Error: Expected at least two arguments to JS_BUILTIN.'});
2772 } 2771 }
2773 2772
2774 Element builtinElement = elements[arguments[1]]; 2773 Element builtinElement = elements[arguments[1]];
2775 if (builtinElement == null || 2774 if (builtinElement == null ||
2776 (builtinElement is! EnumConstantElement) || 2775 (builtinElement is! EnumConstantElement) ||
2777 builtinElement.enclosingClass != helpers.jsBuiltinEnum) { 2776 builtinElement.enclosingClass != commonElements.jsBuiltinEnum) {
2778 reporter.reportErrorMessage(argument, MessageKind.GENERIC, 2777 reporter.reportErrorMessage(argument, MessageKind.GENERIC,
2779 {'text': 'Error: Expected a JsBuiltin enum value.'}); 2778 {'text': 'Error: Expected a JsBuiltin enum value.'});
2780 } 2779 }
2781 EnumConstantElement enumConstant = builtinElement; 2780 EnumConstantElement enumConstant = builtinElement;
2782 int index = enumConstant.index; 2781 int index = enumConstant.index;
2783 2782
2784 js.Template template = 2783 js.Template template =
2785 backend.emitter.builtinTemplateFor(JsBuiltin.values[index]); 2784 backend.emitter.builtinTemplateFor(JsBuiltin.values[index]);
2786 2785
2787 List<HInstruction> compiledArguments = <HInstruction>[]; 2786 List<HInstruction> compiledArguments = <HInstruction>[];
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
2872 void handleForeignJsCallInIsolate(ast.Send node) { 2871 void handleForeignJsCallInIsolate(ast.Send node) {
2873 Link<ast.Node> link = node.arguments; 2872 Link<ast.Node> link = node.arguments;
2874 if (!backend.backendUsage.isIsolateInUse) { 2873 if (!backend.backendUsage.isIsolateInUse) {
2875 // If the isolate library is not used, we just invoke the 2874 // If the isolate library is not used, we just invoke the
2876 // closure. 2875 // closure.
2877 visit(link.tail.head); 2876 visit(link.tail.head);
2878 push(new HInvokeClosure(new Selector.callClosure(0), 2877 push(new HInvokeClosure(new Selector.callClosure(0),
2879 <HInstruction>[pop()], commonMasks.dynamicType)); 2878 <HInstruction>[pop()], commonMasks.dynamicType));
2880 } else { 2879 } else {
2881 // Call a helper method from the isolate library. 2880 // Call a helper method from the isolate library.
2882 MethodElement element = helpers.callInIsolate; 2881 MethodElement element = commonElements.callInIsolate;
2883 if (element == null) { 2882 if (element == null) {
2884 reporter.internalError(node, 'Isolate library and compiler mismatch.'); 2883 reporter.internalError(node, 'Isolate library and compiler mismatch.');
2885 } 2884 }
2886 List<HInstruction> inputs = <HInstruction>[]; 2885 List<HInstruction> inputs = <HInstruction>[];
2887 addGenericSendArgumentsToList(link, inputs); 2886 addGenericSendArgumentsToList(link, inputs);
2888 pushInvokeStatic(node, element, inputs, 2887 pushInvokeStatic(node, element, inputs,
2889 typeMask: commonMasks.dynamicType); 2888 typeMask: commonMasks.dynamicType);
2890 } 2889 }
2891 } 2890 }
2892 2891
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
2948 if (!node.arguments.isEmpty) { 2947 if (!node.arguments.isEmpty) {
2949 reporter.internalError(node.argumentsNode, 'Too many arguments.'); 2948 reporter.internalError(node.argumentsNode, 'Too many arguments.');
2950 } 2949 }
2951 push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder), 2950 push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder),
2952 commonMasks.dynamicType, <HInstruction>[], 2951 commonMasks.dynamicType, <HInstruction>[],
2953 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER)); 2952 nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
2954 } 2953 }
2955 2954
2956 void handleForeignSend(ast.Send node, FunctionElement element) { 2955 void handleForeignSend(ast.Send node, FunctionElement element) {
2957 String name = element.name; 2956 String name = element.name;
2958 if (name == BackendHelpers.JS) { 2957 if (name == JavaScriptBackend.JS) {
2959 handleForeignJs(node); 2958 handleForeignJs(node);
2960 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') { 2959 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') {
2961 handleForeignJsCurrentIsolateContext(node); 2960 handleForeignJsCurrentIsolateContext(node);
2962 } else if (name == 'JS_CALL_IN_ISOLATE') { 2961 } else if (name == 'JS_CALL_IN_ISOLATE') {
2963 handleForeignJsCallInIsolate(node); 2962 handleForeignJsCallInIsolate(node);
2964 } else if (name == 'DART_CLOSURE_TO_JS') { 2963 } else if (name == 'DART_CLOSURE_TO_JS') {
2965 handleForeignDartClosureToJs(node, 'DART_CLOSURE_TO_JS'); 2964 handleForeignDartClosureToJs(node, 'DART_CLOSURE_TO_JS');
2966 } else if (name == 'RAW_DART_FUNCTION_REF') { 2965 } else if (name == 'RAW_DART_FUNCTION_REF') {
2967 handleForeignRawFunctionRef(node, 'RAW_DART_FUNCTION_REF'); 2966 handleForeignRawFunctionRef(node, 'RAW_DART_FUNCTION_REF');
2968 } else if (name == 'JS_SET_STATIC_STATE') { 2967 } else if (name == 'JS_SET_STATIC_STATE') {
2969 handleForeignJsSetStaticState(node); 2968 handleForeignJsSetStaticState(node);
2970 } else if (name == 'JS_GET_STATIC_STATE') { 2969 } else if (name == 'JS_GET_STATIC_STATE') {
2971 handleForeignJsGetStaticState(node); 2970 handleForeignJsGetStaticState(node);
2972 } else if (name == 'JS_GET_NAME') { 2971 } else if (name == 'JS_GET_NAME') {
2973 handleForeignJsGetName(node); 2972 handleForeignJsGetName(node);
2974 } else if (name == BackendHelpers.JS_EMBEDDED_GLOBAL) { 2973 } else if (name == JavaScriptBackend.JS_EMBEDDED_GLOBAL) {
2975 handleForeignJsEmbeddedGlobal(node); 2974 handleForeignJsEmbeddedGlobal(node);
2976 } else if (name == BackendHelpers.JS_BUILTIN) { 2975 } else if (name == JavaScriptBackend.JS_BUILTIN) {
2977 handleForeignJsBuiltin(node); 2976 handleForeignJsBuiltin(node);
2978 } else if (name == 'JS_GET_FLAG') { 2977 } else if (name == 'JS_GET_FLAG') {
2979 handleForeignJsGetFlag(node); 2978 handleForeignJsGetFlag(node);
2980 } else if (name == 'JS_EFFECT') { 2979 } else if (name == 'JS_EFFECT') {
2981 stack.add(graph.addConstantNull(closedWorld)); 2980 stack.add(graph.addConstantNull(closedWorld));
2982 } else if (name == BackendHelpers.JS_INTERCEPTOR_CONSTANT) { 2981 } else if (name == JavaScriptBackend.JS_INTERCEPTOR_CONSTANT) {
2983 handleJsInterceptorConstant(node); 2982 handleJsInterceptorConstant(node);
2984 } else if (name == 'JS_STRING_CONCAT') { 2983 } else if (name == 'JS_STRING_CONCAT') {
2985 handleJsStringConcat(node); 2984 handleJsStringConcat(node);
2986 } else { 2985 } else {
2987 reporter.internalError(node, "Unknown foreign: ${element}"); 2986 reporter.internalError(node, "Unknown foreign: ${element}");
2988 } 2987 }
2989 } 2988 }
2990 2989
2991 generateDeferredLoaderGet(ast.Send node, FunctionElement deferredLoader, 2990 generateDeferredLoaderGet(ast.Send node, FunctionElement deferredLoader,
2992 SourceInformation sourceInformation) { 2991 SourceInformation sourceInformation) {
2993 // Until now we only handle these as getters. 2992 // Until now we only handle these as getters.
2994 invariant(node, deferredLoader.isDeferredLoaderGetter); 2993 invariant(node, deferredLoader.isDeferredLoaderGetter);
2995 FunctionEntity loadFunction = helpers.loadLibraryWrapper; 2994 FunctionEntity loadFunction = commonElements.loadLibraryWrapper;
2996 PrefixElement prefixElement = deferredLoader.enclosingElement; 2995 PrefixElement prefixElement = deferredLoader.enclosingElement;
2997 String loadId = 2996 String loadId =
2998 compiler.deferredLoadTask.getImportDeferName(node, prefixElement); 2997 compiler.deferredLoadTask.getImportDeferName(node, prefixElement);
2999 var inputs = [ 2998 var inputs = [
3000 graph.addConstantString(new ast.DartString.literal(loadId), closedWorld) 2999 graph.addConstantString(new ast.DartString.literal(loadId), closedWorld)
3001 ]; 3000 ];
3002 push(new HInvokeStatic(loadFunction, inputs, commonMasks.nonNullType, 3001 push(new HInvokeStatic(loadFunction, inputs, commonMasks.nonNullType,
3003 targetCanThrow: false)..sourceInformation = sourceInformation); 3002 targetCanThrow: false)
3003 ..sourceInformation = sourceInformation);
3004 } 3004 }
3005 3005
3006 generateSuperNoSuchMethodSend( 3006 generateSuperNoSuchMethodSend(
3007 ast.Send node, Selector selector, List<HInstruction> arguments) { 3007 ast.Send node, Selector selector, List<HInstruction> arguments) {
3008 String name = selector.name; 3008 String name = selector.name;
3009 3009
3010 ClassElement cls = currentNonClosureClass; 3010 ClassElement cls = currentNonClosureClass;
3011 MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_); 3011 MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_);
3012 if (!Selectors.noSuchMethod_.signatureApplies(element)) { 3012 if (!Selectors.noSuchMethod_.signatureApplies(element)) {
3013 ClassElement objectClass = commonElements.objectClass; 3013 ClassElement objectClass = commonElements.objectClass;
3014 element = objectClass.lookupMember(Identifiers.noSuchMethod_); 3014 element = objectClass.lookupMember(Identifiers.noSuchMethod_);
3015 } 3015 }
3016 if (backend.backendUsage.isInvokeOnUsed && 3016 if (backend.backendUsage.isInvokeOnUsed &&
3017 !element.enclosingClass.isObject) { 3017 !element.enclosingClass.isObject) {
3018 // Register the call as dynamic if [noSuchMethod] on the super 3018 // Register the call as dynamic if [noSuchMethod] on the super
3019 // class is _not_ the default implementation from [Object], in 3019 // class is _not_ the default implementation from [Object], in
3020 // case the [noSuchMethod] implementation calls 3020 // case the [noSuchMethod] implementation calls
3021 // [JSInvocationMirror._invokeOn]. 3021 // [JSInvocationMirror._invokeOn].
3022 // TODO(johnniwinther): Register this more precisely. 3022 // TODO(johnniwinther): Register this more precisely.
3023 registry?.registerDynamicUse(new DynamicUse(selector, null)); 3023 registry?.registerDynamicUse(new DynamicUse(selector, null));
3024 } 3024 }
3025 String publicName = name; 3025 String publicName = name;
3026 if (selector.isSetter) publicName += '='; 3026 if (selector.isSetter) publicName += '=';
3027 3027
3028 ConstantValue nameConstant = 3028 ConstantValue nameConstant =
3029 constantSystem.createString(new ast.DartString.literal(publicName)); 3029 constantSystem.createString(new ast.DartString.literal(publicName));
3030 3030
3031 js.Name internalName = backend.namer.invocationName(selector); 3031 js.Name internalName = backend.namer.invocationName(selector);
3032 3032
3033 MethodElement createInvocationMirror = helpers.createInvocationMirror; 3033 MethodElement createInvocationMirror =
3034 commonElements.createInvocationMirror;
3034 var argumentsInstruction = buildLiteralList(arguments); 3035 var argumentsInstruction = buildLiteralList(arguments);
3035 add(argumentsInstruction); 3036 add(argumentsInstruction);
3036 3037
3037 var argumentNames = new List<HInstruction>(); 3038 var argumentNames = new List<HInstruction>();
3038 for (String argumentName in selector.namedArguments) { 3039 for (String argumentName in selector.namedArguments) {
3039 ConstantValue argumentNameConstant = 3040 ConstantValue argumentNameConstant =
3040 constantSystem.createString(new ast.DartString.literal(argumentName)); 3041 constantSystem.createString(new ast.DartString.literal(argumentName));
3041 argumentNames.add(graph.addConstant(argumentNameConstant, closedWorld)); 3042 argumentNames.add(graph.addConstant(argumentNameConstant, closedWorld));
3042 } 3043 }
3043 var argumentNamesInstruction = buildLiteralList(argumentNames); 3044 var argumentNamesInstruction = buildLiteralList(argumentNames);
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
3252 inputs.add(typeBuilder.analyzeTypeArgument(argument, sourceElement)); 3253 inputs.add(typeBuilder.analyzeTypeArgument(argument, sourceElement));
3253 }); 3254 });
3254 // TODO(15489): Register at codegen. 3255 // TODO(15489): Register at codegen.
3255 registry?.registerInstantiation(type); 3256 registry?.registerInstantiation(type);
3256 return callSetRuntimeTypeInfoWithTypeArguments(type, inputs, newObject); 3257 return callSetRuntimeTypeInfoWithTypeArguments(type, inputs, newObject);
3257 } 3258 }
3258 3259
3259 HInstruction callSetRuntimeTypeInfo( 3260 HInstruction callSetRuntimeTypeInfo(
3260 HInstruction typeInfo, HInstruction newObject) { 3261 HInstruction typeInfo, HInstruction newObject) {
3261 // Set the runtime type information on the object. 3262 // Set the runtime type information on the object.
3262 MethodElement typeInfoSetterElement = helpers.setRuntimeTypeInfo; 3263 MethodElement typeInfoSetterElement = commonElements.setRuntimeTypeInfo;
3263 pushInvokeStatic( 3264 pushInvokeStatic(
3264 null, typeInfoSetterElement, <HInstruction>[newObject, typeInfo], 3265 null, typeInfoSetterElement, <HInstruction>[newObject, typeInfo],
3265 typeMask: commonMasks.dynamicType, 3266 typeMask: commonMasks.dynamicType,
3266 sourceInformation: newObject.sourceInformation); 3267 sourceInformation: newObject.sourceInformation);
3267 3268
3268 // The new object will now be referenced through the 3269 // The new object will now be referenced through the
3269 // `setRuntimeTypeInfo` call. We therefore set the type of that 3270 // `setRuntimeTypeInfo` call. We therefore set the type of that
3270 // instruction to be of the object's type. 3271 // instruction to be of the object's type.
3271 assert(invariant(CURRENT_ELEMENT_SPANNABLE, 3272 assert(invariant(CURRENT_ELEMENT_SPANNABLE,
3272 stack.last is HInvokeStatic || stack.last == newObject, 3273 stack.last is HInvokeStatic || stack.last == newObject,
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
3326 } 3327 }
3327 } 3328 }
3328 3329
3329 CallStructure callStructure = elements.getSelector(send).callStructure; 3330 CallStructure callStructure = elements.getSelector(send).callStructure;
3330 ConstructorElement constructorDeclaration = constructor; 3331 ConstructorElement constructorDeclaration = constructor;
3331 ConstructorElement constructorImplementation = constructor.implementation; 3332 ConstructorElement constructorImplementation = constructor.implementation;
3332 constructor = constructorImplementation.effectiveTarget; 3333 constructor = constructorImplementation.effectiveTarget;
3333 3334
3334 final bool isSymbolConstructor = 3335 final bool isSymbolConstructor =
3335 closedWorld.commonElements.isSymbolConstructor(constructorDeclaration); 3336 closedWorld.commonElements.isSymbolConstructor(constructorDeclaration);
3336 final bool isJSArrayTypedConstructor = 3337 final bool isJSArrayTypedConstructor = constructorDeclaration ==
3337 constructorDeclaration == helpers.jsArrayTypedConstructor; 3338 closedWorld.commonElements.jsArrayTypedConstructor;
3338 3339
3339 if (isSymbolConstructor) { 3340 if (isSymbolConstructor) {
3340 constructor = helpers.symbolValidatedConstructor; 3341 constructor = commonElements.symbolValidatedConstructor;
3341 assert(invariant(send, constructor != null, 3342 assert(invariant(send, constructor != null,
3342 message: 'Constructor Symbol.validated is missing')); 3343 message: 'Constructor Symbol.validated is missing'));
3343 callStructure = helpers.symbolValidatedConstructorSelector.callStructure; 3344 callStructure =
3345 commonElements.symbolValidatedConstructorSelector.callStructure;
3344 assert(invariant(send, callStructure != null, 3346 assert(invariant(send, callStructure != null,
3345 message: 'Constructor Symbol.validated is missing')); 3347 message: 'Constructor Symbol.validated is missing'));
3346 } 3348 }
3347 3349
3348 bool isRedirected = constructorDeclaration.isRedirectingFactory; 3350 bool isRedirected = constructorDeclaration.isRedirectingFactory;
3349 if (!constructorDeclaration.isCyclicRedirection) { 3351 if (!constructorDeclaration.isCyclicRedirection) {
3350 // Insert a check for every deferred redirection on the path to the 3352 // Insert a check for every deferred redirection on the path to the
3351 // final target. 3353 // final target.
3352 ConstructorElement target = constructorDeclaration; 3354 ConstructorElement target = constructorDeclaration;
3353 while (target.isRedirectingFactory) { 3355 while (target.isRedirectingFactory) {
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after
3760 ast.Send node, ResolutionTypeVariableType typeVariable) { 3762 ast.Send node, ResolutionTypeVariableType typeVariable) {
3761 // GENERIC_METHODS: This provides thin support for method type variables 3763 // GENERIC_METHODS: This provides thin support for method type variables
3762 // by treating them as malformed when evaluated as a literal. For full 3764 // by treating them as malformed when evaluated as a literal. For full
3763 // support of generic methods this must be revised. 3765 // support of generic methods this must be revised.
3764 if (typeVariable is MethodTypeVariableType) { 3766 if (typeVariable is MethodTypeVariableType) {
3765 generateTypeError(node, "Method type variables are not reified"); 3767 generateTypeError(node, "Method type variables are not reified");
3766 } else { 3768 } else {
3767 ResolutionDartType type = localsHandler.substInContext(typeVariable); 3769 ResolutionDartType type = localsHandler.substInContext(typeVariable);
3768 HInstruction value = typeBuilder.analyzeTypeArgument(type, sourceElement, 3770 HInstruction value = typeBuilder.analyzeTypeArgument(type, sourceElement,
3769 sourceInformation: sourceInformationBuilder.buildGet(node)); 3771 sourceInformation: sourceInformationBuilder.buildGet(node));
3770 pushInvokeStatic(node, helpers.runtimeTypeToString, [value], 3772 pushInvokeStatic(node, commonElements.runtimeTypeToString, [value],
3771 typeMask: commonMasks.stringType); 3773 typeMask: commonMasks.stringType);
3772 pushInvokeStatic(node, helpers.createRuntimeType, [pop()]); 3774 pushInvokeStatic(node, commonElements.createRuntimeType, [pop()]);
3773 } 3775 }
3774 } 3776 }
3775 3777
3776 /// Generate a call to a type literal. 3778 /// Generate a call to a type literal.
3777 void generateTypeLiteralCall(ast.Send node) { 3779 void generateTypeLiteralCall(ast.Send node) {
3778 // This send is of the form 'e(...)', where e is resolved to a type 3780 // This send is of the form 'e(...)', where e is resolved to a type
3779 // reference. We create a regular closure call on the result of the type 3781 // reference. We create a regular closure call on the result of the type
3780 // reference instead of creating a NoSuchMethodError to avoid pulling it 3782 // reference instead of creating a NoSuchMethodError to avoid pulling it
3781 // in if it is not used (e.g., in a try/catch). 3783 // in if it is not used (e.g., in a try/catch).
3782 HInstruction target = pop(); 3784 HInstruction target = pop();
(...skipping 20 matching lines...) Expand all
3803 internalError(Spannable node, String reason) { 3805 internalError(Spannable node, String reason) {
3804 reporter.internalError(node, reason); 3806 reporter.internalError(node, reason);
3805 } 3807 }
3806 3808
3807 void generateError(ast.Node node, String message, Element helper) { 3809 void generateError(ast.Node node, String message, Element helper) {
3808 HInstruction errorMessage = addConstantString(message); 3810 HInstruction errorMessage = addConstantString(message);
3809 pushInvokeStatic(node, helper, [errorMessage]); 3811 pushInvokeStatic(node, helper, [errorMessage]);
3810 } 3812 }
3811 3813
3812 void generateRuntimeError(ast.Node node, String message) { 3814 void generateRuntimeError(ast.Node node, String message) {
3813 MethodElement helper = helpers.throwRuntimeError; 3815 MethodElement helper = commonElements.throwRuntimeError;
3814 generateError(node, message, helper); 3816 generateError(node, message, helper);
3815 } 3817 }
3816 3818
3817 void generateTypeError(ast.Node node, String message) { 3819 void generateTypeError(ast.Node node, String message) {
3818 MethodElement helper = helpers.throwTypeError; 3820 MethodElement helper = commonElements.throwTypeError;
3819 generateError(node, message, helper); 3821 generateError(node, message, helper);
3820 } 3822 }
3821 3823
3822 void generateAbstractClassInstantiationError(ast.Node node, String message) { 3824 void generateAbstractClassInstantiationError(ast.Node node, String message) {
3823 MethodElement helper = helpers.throwAbstractClassInstantiationError; 3825 MethodElement helper = commonElements.throwAbstractClassInstantiationError;
3824 generateError(node, message, helper); 3826 generateError(node, message, helper);
3825 } 3827 }
3826 3828
3827 void generateThrowNoSuchMethod(ast.Node diagnosticNode, String methodName, 3829 void generateThrowNoSuchMethod(ast.Node diagnosticNode, String methodName,
3828 {Link<ast.Node> argumentNodes, 3830 {Link<ast.Node> argumentNodes,
3829 List<HInstruction> argumentValues, 3831 List<HInstruction> argumentValues,
3830 List<String> existingArguments, 3832 List<String> existingArguments,
3831 SourceInformation sourceInformation}) { 3833 SourceInformation sourceInformation}) {
3832 MethodElement helper = helpers.throwNoSuchMethod; 3834 MethodElement helper = commonElements.throwNoSuchMethod;
3833 ConstantValue receiverConstant = 3835 ConstantValue receiverConstant =
3834 constantSystem.createString(new ast.DartString.empty()); 3836 constantSystem.createString(new ast.DartString.empty());
3835 HInstruction receiver = graph.addConstant(receiverConstant, closedWorld); 3837 HInstruction receiver = graph.addConstant(receiverConstant, closedWorld);
3836 ast.DartString dartString = new ast.DartString.literal(methodName); 3838 ast.DartString dartString = new ast.DartString.literal(methodName);
3837 ConstantValue nameConstant = constantSystem.createString(dartString); 3839 ConstantValue nameConstant = constantSystem.createString(dartString);
3838 HInstruction name = graph.addConstant(nameConstant, closedWorld); 3840 HInstruction name = graph.addConstant(nameConstant, closedWorld);
3839 if (argumentValues == null) { 3841 if (argumentValues == null) {
3840 argumentValues = <HInstruction>[]; 3842 argumentValues = <HInstruction>[];
3841 argumentNodes.forEach((argumentNode) { 3843 argumentNodes.forEach((argumentNode) {
3842 visit(argumentNode); 3844 visit(argumentNode);
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
3937 List<HInstruction> arguments, 3939 List<HInstruction> arguments,
3938 {SourceInformation sourceInformation}) { 3940 {SourceInformation sourceInformation}) {
3939 // We prefer to not inline certain operations on indexables, 3941 // We prefer to not inline certain operations on indexables,
3940 // because the constant folder will handle them better and turn 3942 // because the constant folder will handle them better and turn
3941 // them into simpler instructions that allow further 3943 // them into simpler instructions that allow further
3942 // optimizations. 3944 // optimizations.
3943 bool isOptimizableOperationOnIndexable(Selector selector, Element element) { 3945 bool isOptimizableOperationOnIndexable(Selector selector, Element element) {
3944 bool isLength = selector.isGetter && selector.name == "length"; 3946 bool isLength = selector.isGetter && selector.name == "length";
3945 if (isLength || selector.isIndex) { 3947 if (isLength || selector.isIndex) {
3946 return closedWorld.isSubtypeOf( 3948 return closedWorld.isSubtypeOf(
3947 element.enclosingClass, helpers.jsIndexableClass); 3949 element.enclosingClass, commonElements.jsIndexableClass);
3948 } else if (selector.isIndexSet) { 3950 } else if (selector.isIndexSet) {
3949 return closedWorld.isSubtypeOf( 3951 return closedWorld.isSubtypeOf(
3950 element.enclosingClass, helpers.jsMutableIndexableClass); 3952 element.enclosingClass, commonElements.jsMutableIndexableClass);
3951 } else { 3953 } else {
3952 return false; 3954 return false;
3953 } 3955 }
3954 } 3956 }
3955 3957
3956 bool isOptimizableOperation(Selector selector, Element element) { 3958 bool isOptimizableOperation(Selector selector, Element element) {
3957 ClassElement cls = element.enclosingClass; 3959 ClassElement cls = element.enclosingClass;
3958 if (isOptimizableOperationOnIndexable(selector, element)) return true; 3960 if (isOptimizableOperationOnIndexable(selector, element)) return true;
3959 if (!backend.interceptorData.interceptedClasses.contains(cls)) 3961 if (!backend.interceptorData.interceptedClasses.contains(cls))
3960 return false; 3962 return false;
3961 if (selector.isOperator) return true; 3963 if (selector.isOperator) return true;
3962 if (selector.isSetter) return true; 3964 if (selector.isSetter) return true;
3963 if (selector.isIndex) return true; 3965 if (selector.isIndex) return true;
3964 if (selector.isIndexSet) return true; 3966 if (selector.isIndexSet) return true;
3965 if (element == helpers.jsArrayAdd || 3967 if (element == commonElements.jsArrayAdd ||
3966 element == helpers.jsArrayRemoveLast || 3968 element == commonElements.jsArrayRemoveLast ||
3967 element == helpers.jsStringSplit) { 3969 element == commonElements.jsStringSplit) {
3968 return true; 3970 return true;
3969 } 3971 }
3970 return false; 3972 return false;
3971 } 3973 }
3972 3974
3973 MemberElement element = closedWorld.locateSingleElement(selector, mask); 3975 MemberElement element = closedWorld.locateSingleElement(selector, mask);
3974 if (element != null && 3976 if (element != null &&
3975 !element.isField && 3977 !element.isField &&
3976 !(element.isGetter && selector.isCall) && 3978 !(element.isGetter && selector.isCall) &&
3977 !(element.isFunction && selector.isGetter) && 3979 !(element.isFunction && selector.isGetter) &&
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
4078 if (type is ResolutionInterfaceType && 4080 if (type is ResolutionInterfaceType &&
4079 backend.nativeData.isNativeClass(type.element)) { 4081 backend.nativeData.isNativeClass(type.element)) {
4080 nativeBehavior.typesInstantiated.add(type); 4082 nativeBehavior.typesInstantiated.add(type);
4081 } 4083 }
4082 4084
4083 // It also includes any other JS interop type if we don't trust the 4085 // It also includes any other JS interop type if we don't trust the
4084 // annotation or if is declared too broad. 4086 // annotation or if is declared too broad.
4085 if (!compiler.options.trustJSInteropTypeAnnotations || 4087 if (!compiler.options.trustJSInteropTypeAnnotations ||
4086 type.isObject || 4088 type.isObject ||
4087 type.isDynamic) { 4089 type.isDynamic) {
4088 ClassElement cls = backend.helpers.jsJavaScriptObjectClass; 4090 ClassElement cls = commonElements.jsJavaScriptObjectClass;
4089 nativeBehavior.typesInstantiated.add(cls.thisType); 4091 nativeBehavior.typesInstantiated.add(cls.thisType);
4090 } 4092 }
4091 4093
4092 String code; 4094 String code;
4093 if (element.isGetter) { 4095 if (element.isGetter) {
4094 code = "#"; 4096 code = "#";
4095 } else if (element.isSetter) { 4097 } else if (element.isSetter) {
4096 code = "# = #"; 4098 code = "# = #";
4097 } else { 4099 } else {
4098 var args = new List.filled(arguments.length, '#').join(','); 4100 var args = new List.filled(arguments.length, '#').join(',');
4099 code = element.isConstructor ? "new #($args)" : "#($args)"; 4101 code = element.isConstructor ? "new #($args)" : "#($args)";
4100 } 4102 }
4101 js.Template codeTemplate = js.js.parseForeignJS(code); 4103 js.Template codeTemplate = js.js.parseForeignJS(code);
4102 nativeBehavior.codeTemplate = codeTemplate; 4104 nativeBehavior.codeTemplate = codeTemplate;
4103 4105
4104 return new HForeignCode(codeTemplate, commonMasks.dynamicType, inputs, 4106 return new HForeignCode(codeTemplate, commonMasks.dynamicType, inputs,
4105 nativeBehavior: nativeBehavior)..sourceInformation = sourceInformation; 4107 nativeBehavior: nativeBehavior)
4108 ..sourceInformation = sourceInformation;
4106 } 4109 }
4107 4110
4108 void pushInvokeStatic( 4111 void pushInvokeStatic(
4109 ast.Node location, MethodElement element, List<HInstruction> arguments, 4112 ast.Node location, MethodElement element, List<HInstruction> arguments,
4110 {TypeMask typeMask, 4113 {TypeMask typeMask,
4111 ResolutionInterfaceType instanceType, 4114 ResolutionInterfaceType instanceType,
4112 SourceInformation sourceInformation}) { 4115 SourceInformation sourceInformation}) {
4113 assert(element.isDeclaration); 4116 assert(element.isDeclaration);
4114 // TODO(johnniwinther): Use [sourceInformation] instead of [location]. 4117 // TODO(johnniwinther): Use [sourceInformation] instead of [location].
4115 if (tryInlineMethod(element, null, null, arguments, location, 4118 if (tryInlineMethod(element, null, null, arguments, location,
(...skipping 1207 matching lines...) Expand 10 before | Expand all | Expand 10 after
5323 } 5326 }
5324 return new JumpHandler(this, element); 5327 return new JumpHandler(this, element);
5325 } 5328 }
5326 5329
5327 visitAsyncForIn(ast.AsyncForIn node) { 5330 visitAsyncForIn(ast.AsyncForIn node) {
5328 // The async-for is implemented with a StreamIterator. 5331 // The async-for is implemented with a StreamIterator.
5329 HInstruction streamIterator; 5332 HInstruction streamIterator;
5330 5333
5331 visit(node.expression); 5334 visit(node.expression);
5332 HInstruction expression = pop(); 5335 HInstruction expression = pop();
5333 ConstructorElement constructor = helpers.streamIteratorConstructor; 5336 ConstructorElement constructor = commonElements.streamIteratorConstructor;
5334 pushInvokeStatic( 5337 pushInvokeStatic(
5335 node, constructor, [expression, graph.addConstantNull(closedWorld)]); 5338 node, constructor, [expression, graph.addConstantNull(closedWorld)]);
5336 streamIterator = pop(); 5339 streamIterator = pop();
5337 5340
5338 void buildInitializer() {} 5341 void buildInitializer() {}
5339 5342
5340 HInstruction buildCondition() { 5343 HInstruction buildCondition() {
5341 Selector selector = Selectors.moveNext; 5344 Selector selector = Selectors.moveNext;
5342 TypeMask mask = elementInferenceResults.typeOfIteratorMoveNext(node); 5345 TypeMask mask = elementInferenceResults.typeOfIteratorMoveNext(node);
5343 pushInvokeDynamic(node, selector, mask, [streamIterator]); 5346 pushInvokeDynamic(node, selector, mask, [streamIterator]);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
5391 5394
5392 // This scheme recognizes for-in on direct lists. It does not recognize all 5395 // This scheme recognizes for-in on direct lists. It does not recognize all
5393 // uses of ArrayIterator. They still occur when the receiver is an Iterable 5396 // uses of ArrayIterator. They still occur when the receiver is an Iterable
5394 // with a `get iterator` method that delegates to another Iterable and the 5397 // with a `get iterator` method that delegates to another Iterable and the
5395 // method is inlined. We would require full scalar replacement in that 5398 // method is inlined. We would require full scalar replacement in that
5396 // case. 5399 // case.
5397 5400
5398 TypeMask mask = elementInferenceResults.typeOfIterator(node); 5401 TypeMask mask = elementInferenceResults.typeOfIterator(node);
5399 5402
5400 if (mask != null && 5403 if (mask != null &&
5401 mask.satisfies(helpers.jsIndexableClass, closedWorld) && 5404 mask.satisfies(commonElements.jsIndexableClass, closedWorld) &&
5402 // String is indexable but not iterable. 5405 // String is indexable but not iterable.
5403 !mask.satisfies(helpers.jsStringClass, closedWorld)) { 5406 !mask.satisfies(commonElements.jsStringClass, closedWorld)) {
5404 return buildSyncForInIndexable(node, mask); 5407 return buildSyncForInIndexable(node, mask);
5405 } 5408 }
5406 buildSyncForInIterator(node); 5409 buildSyncForInIterator(node);
5407 } 5410 }
5408 5411
5409 buildSyncForInIterator(ast.SyncForIn node) { 5412 buildSyncForInIterator(ast.SyncForIn node) {
5410 // Generate a structure equivalent to: 5413 // Generate a structure equivalent to:
5411 // Iterator<E> $iter = <iterable>.iterator; 5414 // Iterator<E> $iter = <iterable>.iterator;
5412 // while ($iter.moveNext()) { 5415 // while ($iter.moveNext()) {
5413 // <declaredIdentifier> = $iter.current; 5416 // <declaredIdentifier> = $iter.current;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
5491 5494
5492 void buildConcurrentModificationErrorCheck() { 5495 void buildConcurrentModificationErrorCheck() {
5493 if (originalLength == null) return; 5496 if (originalLength == null) return;
5494 // The static call checkConcurrentModificationError() is expanded in 5497 // The static call checkConcurrentModificationError() is expanded in
5495 // codegen to: 5498 // codegen to:
5496 // 5499 //
5497 // array.length == _end || throwConcurrentModificationError(array) 5500 // array.length == _end || throwConcurrentModificationError(array)
5498 // 5501 //
5499 HInstruction length = buildGetLength(); 5502 HInstruction length = buildGetLength();
5500 push(new HIdentity(length, originalLength, null, boolType)); 5503 push(new HIdentity(length, originalLength, null, boolType));
5501 pushInvokeStatic( 5504 pushInvokeStatic(node, commonElements.checkConcurrentModificationError,
5502 node, helpers.checkConcurrentModificationError, [pop(), array]); 5505 [pop(), array]);
5503 pop(); 5506 pop();
5504 } 5507 }
5505 5508
5506 void buildInitializer() { 5509 void buildInitializer() {
5507 visit(node.expression); 5510 visit(node.expression);
5508 array = pop(); 5511 array = pop();
5509 isFixed = isFixedLength(array.instructionType, closedWorld); 5512 isFixed = isFixedLength(array.instructionType, closedWorld);
5510 localsHandler.updateLocal( 5513 localsHandler.updateLocal(
5511 indexVariable, graph.addConstantInt(0, closedWorld)); 5514 indexVariable, graph.addConstantInt(0, closedWorld));
5512 originalLength = buildGetLength(); 5515 originalLength = buildGetLength();
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
5620 link = link.tail) { 5623 link = link.tail) {
5621 visit(link.head); 5624 visit(link.head);
5622 listInputs.add(pop()); 5625 listInputs.add(pop());
5623 listInputs.add(pop()); 5626 listInputs.add(pop());
5624 } 5627 }
5625 5628
5626 ConstructorElement listConstructor; 5629 ConstructorElement listConstructor;
5627 List<HInstruction> inputs = <HInstruction>[]; 5630 List<HInstruction> inputs = <HInstruction>[];
5628 5631
5629 if (listInputs.isEmpty) { 5632 if (listInputs.isEmpty) {
5630 listConstructor = helpers.mapLiteralConstructorEmpty; 5633 listConstructor = commonElements.mapLiteralConstructorEmpty;
5631 } else { 5634 } else {
5632 listConstructor = helpers.mapLiteralConstructor; 5635 listConstructor = commonElements.mapLiteralConstructor;
5633 HLiteralList keyValuePairs = buildLiteralList(listInputs); 5636 HLiteralList keyValuePairs = buildLiteralList(listInputs);
5634 add(keyValuePairs); 5637 add(keyValuePairs);
5635 inputs.add(keyValuePairs); 5638 inputs.add(keyValuePairs);
5636 } 5639 }
5637 5640
5638 assert(listConstructor.isFactoryConstructor); 5641 assert(listConstructor.isFactoryConstructor);
5639 5642
5640 ConstructorElement constructorElement = listConstructor; 5643 ConstructorElement constructorElement = listConstructor;
5641 listConstructor = constructorElement.effectiveTarget; 5644 listConstructor = constructorElement.effectiveTarget;
5642 5645
5643 ResolutionInterfaceType type = elements.getType(node); 5646 ResolutionInterfaceType type = elements.getType(node);
5644 ResolutionInterfaceType expectedType = 5647 ResolutionInterfaceType expectedType =
5645 constructorElement.computeEffectiveTargetType(type); 5648 constructorElement.computeEffectiveTargetType(type);
5646 expectedType = localsHandler.substInContext(expectedType); 5649 expectedType = localsHandler.substInContext(expectedType);
5647 5650
5648 ClassElement cls = listConstructor.enclosingClass; 5651 ClassElement cls = listConstructor.enclosingClass;
5649 5652
5650 MethodElement createFunction = listConstructor; 5653 MethodElement createFunction = listConstructor;
5651 if (backend.rtiNeed.classNeedsRti(cls)) { 5654 if (backend.rtiNeed.classNeedsRti(cls)) {
5652 List<HInstruction> typeInputs = <HInstruction>[]; 5655 List<HInstruction> typeInputs = <HInstruction>[];
5653 expectedType.typeArguments.forEach((ResolutionDartType argument) { 5656 expectedType.typeArguments.forEach((ResolutionDartType argument) {
5654 typeInputs 5657 typeInputs
5655 .add(typeBuilder.analyzeTypeArgument(argument, sourceElement)); 5658 .add(typeBuilder.analyzeTypeArgument(argument, sourceElement));
5656 }); 5659 });
5657 5660
5658 // We lift this common call pattern into a helper function to save space 5661 // We lift this common call pattern into a helper function to save space
5659 // in the output. 5662 // in the output.
5660 if (typeInputs.every((HInstruction input) => input.isNull())) { 5663 if (typeInputs.every((HInstruction input) => input.isNull())) {
5661 if (listInputs.isEmpty) { 5664 if (listInputs.isEmpty) {
5662 createFunction = helpers.mapLiteralUntypedEmptyMaker; 5665 createFunction = commonElements.mapLiteralUntypedEmptyMaker;
5663 } else { 5666 } else {
5664 createFunction = helpers.mapLiteralUntypedMaker; 5667 createFunction = commonElements.mapLiteralUntypedMaker;
5665 } 5668 }
5666 } else { 5669 } else {
5667 inputs.addAll(typeInputs); 5670 inputs.addAll(typeInputs);
5668 } 5671 }
5669 } 5672 }
5670 5673
5671 // If rti is needed and the map literal has no type parameters, 5674 // If rti is needed and the map literal has no type parameters,
5672 // 'constructor' is a static function that forwards the call to the factory 5675 // 'constructor' is a static function that forwards the call to the factory
5673 // constructor without type parameters. 5676 // constructor without type parameters.
5674 assert(createFunction is ConstructorElement || 5677 assert(createFunction is ConstructorElement ||
5675 createFunction is FunctionElement); 5678 createFunction is FunctionElement);
5676 5679
5677 // The instruction type will always be a subtype of the mapLiteralClass, but 5680 // The instruction type will always be a subtype of the mapLiteralClass, but
5678 // type inference might discover a more specific type, or find nothing (in 5681 // type inference might discover a more specific type, or find nothing (in
5679 // dart2js unit tests). 5682 // dart2js unit tests).
5680 TypeMask mapType = 5683 TypeMask mapType = new TypeMask.nonNullSubtype(
5681 new TypeMask.nonNullSubtype(helpers.mapLiteralClass, closedWorld); 5684 commonElements.mapLiteralClass, closedWorld);
5682 TypeMask returnTypeMask = TypeMaskFactory.inferredReturnTypeForElement( 5685 TypeMask returnTypeMask = TypeMaskFactory.inferredReturnTypeForElement(
5683 createFunction, globalInferenceResults); 5686 createFunction, globalInferenceResults);
5684 TypeMask instructionType = 5687 TypeMask instructionType =
5685 mapType.intersection(returnTypeMask, closedWorld); 5688 mapType.intersection(returnTypeMask, closedWorld);
5686 5689
5687 addInlinedInstantiation(expectedType); 5690 addInlinedInstantiation(expectedType);
5688 pushInvokeStatic(node, createFunction, inputs, 5691 pushInvokeStatic(node, createFunction, inputs,
5689 typeMask: instructionType, instanceType: expectedType); 5692 typeMask: instructionType, instanceType: expectedType);
5690 removeInlinedInstantiation(expectedType); 5693 removeInlinedInstantiation(expectedType);
5691 } 5694 }
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
5978 // An HSwitch has n inputs and n+1 successors, the last being the 5981 // An HSwitch has n inputs and n+1 successors, the last being the
5979 // default case. 5982 // default case.
5980 expressionEnd.addSuccessor(block); 5983 expressionEnd.addSuccessor(block);
5981 hasDefault = true; 5984 hasDefault = true;
5982 } 5985 }
5983 open(block); 5986 open(block);
5984 localsHandler = new LocalsHandler.from(savedLocals); 5987 localsHandler = new LocalsHandler.from(savedLocals);
5985 buildSwitchCase(switchCase); 5988 buildSwitchCase(switchCase);
5986 if (!isAborted()) { 5989 if (!isAborted()) {
5987 if (caseIterator.hasNext && isReachable) { 5990 if (caseIterator.hasNext && isReachable) {
5988 pushInvokeStatic(switchCase, helpers.fallThroughError, []); 5991 pushInvokeStatic(switchCase, commonElements.fallThroughError, []);
5989 HInstruction error = pop(); 5992 HInstruction error = pop();
5990 closeAndGotoExit(new HThrow(error, error.sourceInformation)); 5993 closeAndGotoExit(new HThrow(error, error.sourceInformation));
5991 } else if (!isDefaultCase(switchCase)) { 5994 } else if (!isDefaultCase(switchCase)) {
5992 // If there is no default, we will add one later to avoid 5995 // If there is no default, we will add one later to avoid
5993 // the critical edge. So we generate a break statement to make 5996 // the critical edge. So we generate a break statement to make
5994 // sure the last case does not fall through to the default case. 5997 // sure the last case does not fall through to the default case.
5995 jumpHandler.generateBreak(); 5998 jumpHandler.generateBreak();
5996 } 5999 }
5997 } 6000 }
5998 statements.add( 6001 statements.add(
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
6198 startCatchBlock = graph.addNewBlock(); 6201 startCatchBlock = graph.addNewBlock();
6199 open(startCatchBlock); 6202 open(startCatchBlock);
6200 // Note that the name of this local is irrelevant. 6203 // Note that the name of this local is irrelevant.
6201 SyntheticLocal local = 6204 SyntheticLocal local =
6202 new SyntheticLocal('exception', localsHandler.executableContext); 6205 new SyntheticLocal('exception', localsHandler.executableContext);
6203 exception = new HLocalValue(local, commonMasks.nonNullType); 6206 exception = new HLocalValue(local, commonMasks.nonNullType);
6204 add(exception); 6207 add(exception);
6205 HInstruction oldRethrowableException = rethrowableException; 6208 HInstruction oldRethrowableException = rethrowableException;
6206 rethrowableException = exception; 6209 rethrowableException = exception;
6207 6210
6208 pushInvokeStatic(node, helpers.exceptionUnwrapper, [exception]); 6211 pushInvokeStatic(node, commonElements.exceptionUnwrapper, [exception]);
6209 HInvokeStatic unwrappedException = pop(); 6212 HInvokeStatic unwrappedException = pop();
6210 tryInstruction.exception = exception; 6213 tryInstruction.exception = exception;
6211 Link<ast.Node> link = node.catchBlocks.nodes; 6214 Link<ast.Node> link = node.catchBlocks.nodes;
6212 6215
6213 void pushCondition(ast.CatchBlock catchBlock) { 6216 void pushCondition(ast.CatchBlock catchBlock) {
6214 if (catchBlock.onKeyword != null) { 6217 if (catchBlock.onKeyword != null) {
6215 ResolutionDartType type = elements.getType(catchBlock.type); 6218 ResolutionDartType type = elements.getType(catchBlock.type);
6216 if (type == null) { 6219 if (type == null) {
6217 reporter.internalError(catchBlock.type, 'On with no type.'); 6220 reporter.internalError(catchBlock.type, 'On with no type.');
6218 } 6221 }
(...skipping 24 matching lines...) Expand all
6243 void visitThen() { 6246 void visitThen() {
6244 ast.CatchBlock catchBlock = link.head; 6247 ast.CatchBlock catchBlock = link.head;
6245 link = link.tail; 6248 link = link.tail;
6246 if (catchBlock.exception != null) { 6249 if (catchBlock.exception != null) {
6247 LocalVariableElement exceptionVariable = 6250 LocalVariableElement exceptionVariable =
6248 elements[catchBlock.exception]; 6251 elements[catchBlock.exception];
6249 localsHandler.updateLocal(exceptionVariable, unwrappedException); 6252 localsHandler.updateLocal(exceptionVariable, unwrappedException);
6250 } 6253 }
6251 ast.Node trace = catchBlock.trace; 6254 ast.Node trace = catchBlock.trace;
6252 if (trace != null) { 6255 if (trace != null) {
6253 pushInvokeStatic(trace, helpers.traceFromException, [exception]); 6256 pushInvokeStatic(
6257 trace, commonElements.traceFromException, [exception]);
6254 HInstruction traceInstruction = pop(); 6258 HInstruction traceInstruction = pop();
6255 LocalVariableElement traceVariable = elements[trace]; 6259 LocalVariableElement traceVariable = elements[trace];
6256 localsHandler.updateLocal(traceVariable, traceInstruction); 6260 localsHandler.updateLocal(traceVariable, traceInstruction);
6257 } 6261 }
6258 visit(catchBlock); 6262 visit(catchBlock);
6259 } 6263 }
6260 6264
6261 void visitElse() { 6265 void visitElse() {
6262 if (link.isEmpty) { 6266 if (link.isEmpty) {
6263 closeAndGotoExit(new HThrow(exception, exception.sourceInformation, 6267 closeAndGotoExit(new HThrow(exception, exception.sourceInformation,
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after
6760 this.oldReturnLocal, 6764 this.oldReturnLocal,
6761 this.oldReturnType, 6765 this.oldReturnType,
6762 this.oldResolvedAst, 6766 this.oldResolvedAst,
6763 this.oldStack, 6767 this.oldStack,
6764 this.oldLocalsHandler, 6768 this.oldLocalsHandler,
6765 this.inTryStatement, 6769 this.inTryStatement,
6766 this.allFunctionsCalledOnce, 6770 this.allFunctionsCalledOnce,
6767 this.oldElementInferenceResults) 6771 this.oldElementInferenceResults)
6768 : super(function); 6772 : super(function);
6769 } 6773 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698