OLD | NEW |
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'; |
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 /// Registry used to enqueue work during codegen, may be null to avoid | 370 /// Registry used to enqueue work during codegen, may be null to avoid |
371 /// enqueing any work. | 371 /// enqueing any work. |
372 // TODO(sigmund,johnniwinther): get rid of registry entirely. We should be | 372 // TODO(sigmund,johnniwinther): get rid of registry entirely. We should be |
373 // able to return the impact as a result after building and avoid enqueing | 373 // able to return the impact as a result after building and avoid enqueing |
374 // things here. Later the codegen task can decide whether to enqueue | 374 // things here. Later the codegen task can decide whether to enqueue |
375 // something. In the past this didn't matter as much because the SSA graph was | 375 // something. In the past this didn't matter as much because the SSA graph was |
376 // used only for codegen, but currently we want to experiment using it for | 376 // used only for codegen, but currently we want to experiment using it for |
377 // code-analysis too. | 377 // code-analysis too. |
378 final CodegenRegistry registry; | 378 final CodegenRegistry registry; |
379 final Compiler compiler; | 379 final Compiler compiler; |
| 380 final GlobalTypeInferenceResults inferenceResults; |
380 final JavaScriptBackend backend; | 381 final JavaScriptBackend backend; |
381 final ConstantSystem constantSystem; | 382 final ConstantSystem constantSystem; |
382 final RuntimeTypes rti; | 383 final RuntimeTypes rti; |
383 | 384 |
384 SourceInformationBuilder sourceInformationBuilder; | 385 SourceInformationBuilder sourceInformationBuilder; |
385 | 386 |
386 bool inLazyInitializerExpression = false; | 387 bool inLazyInitializerExpression = false; |
387 | 388 |
388 // TODO(sigmund): make all comments /// instead of /* */ | 389 // TODO(sigmund): make all comments /// instead of /* */ |
389 /* This field is used by the native handler. */ | 390 /* This field is used by the native handler. */ |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
424 this.target, | 425 this.target, |
425 this.resolvedAst, | 426 this.resolvedAst, |
426 this.registry, | 427 this.registry, |
427 JavaScriptBackend backend, | 428 JavaScriptBackend backend, |
428 this.nativeEmitter, | 429 this.nativeEmitter, |
429 SourceInformationStrategy sourceInformationFactory) | 430 SourceInformationStrategy sourceInformationFactory) |
430 : this.compiler = backend.compiler, | 431 : this.compiler = backend.compiler, |
431 this.infoReporter = backend.compiler.dumpInfoTask, | 432 this.infoReporter = backend.compiler.dumpInfoTask, |
432 this.backend = backend, | 433 this.backend = backend, |
433 this.constantSystem = backend.constantSystem, | 434 this.constantSystem = backend.constantSystem, |
434 this.rti = backend.rti { | 435 this.rti = backend.rti, |
| 436 this.inferenceResults = backend.compiler.globalInference.results { |
435 assert(target.isImplementation); | 437 assert(target.isImplementation); |
436 graph.element = target; | 438 graph.element = target; |
437 sourceElementStack.add(target); | 439 sourceElementStack.add(target); |
438 sourceInformationBuilder = | 440 sourceInformationBuilder = |
439 sourceInformationFactory.createBuilderForContext(resolvedAst); | 441 sourceInformationFactory.createBuilderForContext(resolvedAst); |
440 graph.sourceInformation = | 442 graph.sourceInformation = |
441 sourceInformationBuilder.buildVariableDeclaration(); | 443 sourceInformationBuilder.buildVariableDeclaration(); |
442 localsHandler = new LocalsHandler(this, target, null, compiler); | 444 localsHandler = new LocalsHandler(this, target, null, compiler); |
443 } | 445 } |
444 | 446 |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 // Generative constructors of native classes should not be called directly | 669 // Generative constructors of native classes should not be called directly |
668 // and have an extra argument that causes problems with inlining. | 670 // and have an extra argument that causes problems with inlining. |
669 if (element.isGenerativeConstructor && | 671 if (element.isGenerativeConstructor && |
670 backend.isNativeOrExtendsNative(element.enclosingClass)) { | 672 backend.isNativeOrExtendsNative(element.enclosingClass)) { |
671 return false; | 673 return false; |
672 } | 674 } |
673 | 675 |
674 // A generative constructor body is not seen by global analysis, | 676 // A generative constructor body is not seen by global analysis, |
675 // so we should not query for its type. | 677 // so we should not query for its type. |
676 if (!element.isGenerativeConstructorBody) { | 678 if (!element.isGenerativeConstructorBody) { |
677 if (compiler.globalInference.throwsAlways(element)) { | 679 if (inferenceResults.throwsAlways(element)) { |
678 isReachable = false; | 680 isReachable = false; |
679 return false; | 681 return false; |
680 } | 682 } |
681 } | 683 } |
682 | 684 |
683 return true; | 685 return true; |
684 } | 686 } |
685 | 687 |
686 bool doesNotContainCode() { | 688 bool doesNotContainCode() { |
687 // A function with size 1 does not contain any code. | 689 // A function with size 1 does not contain any code. |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
804 | 806 |
805 bool get allInlinedFunctionsCalledOnce { | 807 bool get allInlinedFunctionsCalledOnce { |
806 return inliningStack.isEmpty || inliningStack.last.allFunctionsCalledOnce; | 808 return inliningStack.isEmpty || inliningStack.last.allFunctionsCalledOnce; |
807 } | 809 } |
808 | 810 |
809 bool isFunctionCalledOnce(Element element) { | 811 bool isFunctionCalledOnce(Element element) { |
810 if (element is ConstructorBodyElement) { | 812 if (element is ConstructorBodyElement) { |
811 // ConstructorBodyElements are not in the type inference graph. | 813 // ConstructorBodyElements are not in the type inference graph. |
812 return false; | 814 return false; |
813 } | 815 } |
814 return compiler.globalInference.isCalledOnce(element); | 816 return inferenceResults.isCalledOnce(element); |
815 } | 817 } |
816 | 818 |
817 bool isCalledOnce(Element element) { | 819 bool isCalledOnce(Element element) { |
818 return allInlinedFunctionsCalledOnce && isFunctionCalledOnce(element); | 820 return allInlinedFunctionsCalledOnce && isFunctionCalledOnce(element); |
819 } | 821 } |
820 | 822 |
821 inlinedFrom(ResolvedAst resolvedAst, f()) { | 823 inlinedFrom(ResolvedAst resolvedAst, f()) { |
822 Element element = resolvedAst.element; | 824 Element element = resolvedAst.element; |
823 assert(element is FunctionElement || element is VariableElement); | 825 assert(element is FunctionElement || element is VariableElement); |
824 return reporter.withCurrentElement(element.implementation, () { | 826 return reporter.withCurrentElement(element.implementation, () { |
(...skipping 1728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2553 if (operand is HConstant) { | 2555 if (operand is HConstant) { |
2554 UnaryOperation operation = constantSystem.lookupUnary(operator); | 2556 UnaryOperation operation = constantSystem.lookupUnary(operator); |
2555 HConstant constant = operand; | 2557 HConstant constant = operand; |
2556 ConstantValue folded = operation.fold(constant.constant); | 2558 ConstantValue folded = operation.fold(constant.constant); |
2557 if (folded != null) { | 2559 if (folded != null) { |
2558 stack.add(graph.addConstant(folded, compiler)); | 2560 stack.add(graph.addConstant(folded, compiler)); |
2559 return; | 2561 return; |
2560 } | 2562 } |
2561 } | 2563 } |
2562 | 2564 |
2563 pushInvokeDynamic( | 2565 pushInvokeDynamic(node, elements.getSelector(node), |
2564 node, elements.getSelector(node), elements.getTypeMask(node), [operand], | 2566 inferenceResults.typeOfSend(node, elements), [operand], |
2565 sourceInformation: sourceInformationBuilder.buildGeneric(node)); | 2567 sourceInformation: sourceInformationBuilder.buildGeneric(node)); |
2566 } | 2568 } |
2567 | 2569 |
2568 @override | 2570 @override |
2569 void visitBinary(ast.Send node, ast.Node left, BinaryOperator operator, | 2571 void visitBinary(ast.Send node, ast.Node left, BinaryOperator operator, |
2570 ast.Node right, _) { | 2572 ast.Node right, _) { |
2571 handleBinary(node, left, right); | 2573 handleBinary(node, left, right); |
2572 } | 2574 } |
2573 | 2575 |
2574 @override | 2576 @override |
2575 void visitIndex(ast.Send node, ast.Node receiver, ast.Node index, _) { | 2577 void visitIndex(ast.Send node, ast.Node receiver, ast.Node index, _) { |
2576 generateDynamicSend(node); | 2578 generateDynamicSend(node); |
2577 } | 2579 } |
2578 | 2580 |
2579 @override | 2581 @override |
2580 void visitEquals(ast.Send node, ast.Node left, ast.Node right, _) { | 2582 void visitEquals(ast.Send node, ast.Node left, ast.Node right, _) { |
2581 handleBinary(node, left, right); | 2583 handleBinary(node, left, right); |
2582 } | 2584 } |
2583 | 2585 |
2584 @override | 2586 @override |
2585 void visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) { | 2587 void visitNotEquals(ast.Send node, ast.Node left, ast.Node right, _) { |
2586 handleBinary(node, left, right); | 2588 handleBinary(node, left, right); |
2587 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); | 2589 pushWithPosition(new HNot(popBoolified(), backend.boolType), node.selector); |
2588 } | 2590 } |
2589 | 2591 |
2590 void handleBinary(ast.Send node, ast.Node left, ast.Node right) { | 2592 void handleBinary(ast.Send node, ast.Node left, ast.Node right) { |
2591 visitBinarySend(visitAndPop(left), visitAndPop(right), | 2593 visitBinarySend( |
2592 elements.getSelector(node), elements.getTypeMask(node), node, | 2594 visitAndPop(left), |
| 2595 visitAndPop(right), |
| 2596 elements.getSelector(node), |
| 2597 inferenceResults.typeOfSend(node, elements), |
| 2598 node, |
2593 sourceInformation: | 2599 sourceInformation: |
2594 sourceInformationBuilder.buildGeneric(node.selector)); | 2600 sourceInformationBuilder.buildGeneric(node.selector)); |
2595 } | 2601 } |
2596 | 2602 |
2597 /// TODO(johnniwinther): Merge [visitBinarySend] with [handleBinary] and | 2603 /// TODO(johnniwinther): Merge [visitBinarySend] with [handleBinary] and |
2598 /// remove use of [location] for source information. | 2604 /// remove use of [location] for source information. |
2599 void visitBinarySend(HInstruction left, HInstruction right, Selector selector, | 2605 void visitBinarySend(HInstruction left, HInstruction right, Selector selector, |
2600 TypeMask mask, ast.Send send, | 2606 TypeMask mask, ast.Send send, |
2601 {SourceInformation sourceInformation}) { | 2607 {SourceInformation sourceInformation}) { |
2602 pushInvokeDynamic(send, selector, mask, [left, right], | 2608 pushInvokeDynamic(send, selector, mask, [left, right], |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2742 generateDeferredLoaderGet(node, getter, sourceInformation); | 2748 generateDeferredLoaderGet(node, getter, sourceInformation); |
2743 } else { | 2749 } else { |
2744 pushInvokeStatic(node, getter, <HInstruction>[], | 2750 pushInvokeStatic(node, getter, <HInstruction>[], |
2745 sourceInformation: sourceInformation); | 2751 sourceInformation: sourceInformation); |
2746 } | 2752 } |
2747 } | 2753 } |
2748 | 2754 |
2749 /// Generate a dynamic getter invocation. | 2755 /// Generate a dynamic getter invocation. |
2750 void generateDynamicGet(ast.Send node) { | 2756 void generateDynamicGet(ast.Send node) { |
2751 HInstruction receiver = generateInstanceSendReceiver(node); | 2757 HInstruction receiver = generateInstanceSendReceiver(node); |
2752 generateInstanceGetterWithCompiledReceiver( | 2758 generateInstanceGetterWithCompiledReceiver(node, elements.getSelector(node), |
2753 node, elements.getSelector(node), elements.getTypeMask(node), receiver); | 2759 inferenceResults.typeOfSend(node, elements), receiver); |
2754 } | 2760 } |
2755 | 2761 |
2756 /// Generate a closurization of the static or top level [function]. | 2762 /// Generate a closurization of the static or top level [function]. |
2757 void generateStaticFunctionGet(ast.Send node, MethodElement function) { | 2763 void generateStaticFunctionGet(ast.Send node, MethodElement function) { |
2758 // TODO(5346): Try to avoid the need for calling [declaration] before | 2764 // TODO(5346): Try to avoid the need for calling [declaration] before |
2759 // creating an [HStatic]. | 2765 // creating an [HStatic]. |
2760 SourceInformation sourceInformation = | 2766 SourceInformation sourceInformation = |
2761 sourceInformationBuilder.buildGet(node); | 2767 sourceInformationBuilder.buildGet(node); |
2762 push(new HStatic(function.declaration, backend.nonNullType) | 2768 push(new HStatic(function.declaration, backend.nonNullType) |
2763 ..sourceInformation = sourceInformation); | 2769 ..sourceInformation = sourceInformation); |
(...skipping 28 matching lines...) Expand all Loading... |
2792 brancher.handleConditional( | 2798 brancher.handleConditional( |
2793 () { | 2799 () { |
2794 expression = visitAndPop(receiver); | 2800 expression = visitAndPop(receiver); |
2795 pushCheckNull(expression); | 2801 pushCheckNull(expression); |
2796 }, | 2802 }, |
2797 () => stack.add(expression), | 2803 () => stack.add(expression), |
2798 () { | 2804 () { |
2799 generateInstanceGetterWithCompiledReceiver( | 2805 generateInstanceGetterWithCompiledReceiver( |
2800 node, | 2806 node, |
2801 elements.getSelector(node), | 2807 elements.getSelector(node), |
2802 elements.getTypeMask(node), | 2808 inferenceResults.typeOfSend(node, elements), |
2803 expression); | 2809 expression); |
2804 }); | 2810 }); |
2805 } | 2811 } |
2806 | 2812 |
2807 @override | 2813 @override |
2808 pushCheckNull(HInstruction expression) { | 2814 pushCheckNull(HInstruction expression) { |
2809 push(new HIdentity( | 2815 push(new HIdentity( |
2810 expression, graph.addConstantNull(compiler), null, backend.boolType)); | 2816 expression, graph.addConstantNull(compiler), null, backend.boolType)); |
2811 } | 2817 } |
2812 | 2818 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2863 void generateInstanceSetterWithCompiledReceiver( | 2869 void generateInstanceSetterWithCompiledReceiver( |
2864 ast.Send send, HInstruction receiver, HInstruction value, | 2870 ast.Send send, HInstruction receiver, HInstruction value, |
2865 {Selector selector, TypeMask mask, ast.Node location}) { | 2871 {Selector selector, TypeMask mask, ast.Node location}) { |
2866 assert(invariant(send == null ? location : send, | 2872 assert(invariant(send == null ? location : send, |
2867 send == null || Elements.isInstanceSend(send, elements), | 2873 send == null || Elements.isInstanceSend(send, elements), |
2868 message: "Unexpected instance setter" | 2874 message: "Unexpected instance setter" |
2869 "${send != null ? " element: ${elements[send]}" : ""}")); | 2875 "${send != null ? " element: ${elements[send]}" : ""}")); |
2870 if (selector == null) { | 2876 if (selector == null) { |
2871 assert(send != null); | 2877 assert(send != null); |
2872 selector = elements.getSelector(send); | 2878 selector = elements.getSelector(send); |
2873 if (mask == null) { | 2879 mask ??= inferenceResults.typeOfSend(send, elements); |
2874 mask = elements.getTypeMask(send); | |
2875 } | |
2876 } | 2880 } |
2877 if (location == null) { | 2881 if (location == null) { |
2878 assert(send != null); | 2882 assert(send != null); |
2879 location = send; | 2883 location = send; |
2880 } | 2884 } |
2881 assert(selector.isSetter); | 2885 assert(selector.isSetter); |
2882 pushInvokeDynamic(location, selector, mask, [receiver, value], | 2886 pushInvokeDynamic(location, selector, mask, [receiver, value], |
2883 sourceInformation: sourceInformationBuilder.buildAssignment(location)); | 2887 sourceInformation: sourceInformationBuilder.buildAssignment(location)); |
2884 pop(); | 2888 pop(); |
2885 stack.add(value); | 2889 stack.add(value); |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3137 } | 3141 } |
3138 | 3142 |
3139 /// Generate a dynamic method, getter or setter invocation. | 3143 /// Generate a dynamic method, getter or setter invocation. |
3140 void generateDynamicSend(ast.Send node) { | 3144 void generateDynamicSend(ast.Send node) { |
3141 HInstruction receiver = generateInstanceSendReceiver(node); | 3145 HInstruction receiver = generateInstanceSendReceiver(node); |
3142 _generateDynamicSend(node, receiver); | 3146 _generateDynamicSend(node, receiver); |
3143 } | 3147 } |
3144 | 3148 |
3145 void _generateDynamicSend(ast.Send node, HInstruction receiver) { | 3149 void _generateDynamicSend(ast.Send node, HInstruction receiver) { |
3146 Selector selector = elements.getSelector(node); | 3150 Selector selector = elements.getSelector(node); |
3147 TypeMask mask = elements.getTypeMask(node); | 3151 TypeMask mask = inferenceResults.typeOfSend(node, elements); |
3148 SourceInformation sourceInformation = | 3152 SourceInformation sourceInformation = |
3149 sourceInformationBuilder.buildCall(node, node.selector); | 3153 sourceInformationBuilder.buildCall(node, node.selector); |
3150 | 3154 |
3151 List<HInstruction> inputs = <HInstruction>[]; | 3155 List<HInstruction> inputs = <HInstruction>[]; |
3152 inputs.add(receiver); | 3156 inputs.add(receiver); |
3153 addDynamicSendArgumentsToList(node, inputs); | 3157 addDynamicSendArgumentsToList(node, inputs); |
3154 | 3158 |
3155 pushInvokeDynamic(node, selector, mask, inputs, | 3159 pushInvokeDynamic(node, selector, mask, inputs, |
3156 sourceInformation: sourceInformation); | 3160 sourceInformation: sourceInformation); |
3157 if (selector.isSetter || selector.isIndexSet) { | 3161 if (selector.isSetter || selector.isIndexSet) { |
(...skipping 866 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4024 Elements.isFixedListConstructorCall(elements[send], send, compiler); | 4028 Elements.isFixedListConstructorCall(elements[send], send, compiler); |
4025 bool isGrowableListConstructorCall = | 4029 bool isGrowableListConstructorCall = |
4026 Elements.isGrowableListConstructorCall(elements[send], send, compiler); | 4030 Elements.isGrowableListConstructorCall(elements[send], send, compiler); |
4027 | 4031 |
4028 TypeMask computeType(element) { | 4032 TypeMask computeType(element) { |
4029 Element originalElement = elements[send]; | 4033 Element originalElement = elements[send]; |
4030 if (isFixedListConstructorCall || | 4034 if (isFixedListConstructorCall || |
4031 Elements.isFilledListConstructorCall( | 4035 Elements.isFilledListConstructorCall( |
4032 originalElement, send, compiler)) { | 4036 originalElement, send, compiler)) { |
4033 isFixedList = true; | 4037 isFixedList = true; |
4034 TypeMask inferred = | 4038 TypeMask inferred = _inferredTypeOfNewList(send); |
4035 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); | |
4036 return inferred.containsAll(compiler.world) | 4039 return inferred.containsAll(compiler.world) |
4037 ? backend.fixedArrayType | 4040 ? backend.fixedArrayType |
4038 : inferred; | 4041 : inferred; |
4039 } else if (isGrowableListConstructorCall) { | 4042 } else if (isGrowableListConstructorCall) { |
4040 TypeMask inferred = | 4043 TypeMask inferred = _inferredTypeOfNewList(send); |
4041 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); | |
4042 return inferred.containsAll(compiler.world) | 4044 return inferred.containsAll(compiler.world) |
4043 ? backend.extendableArrayType | 4045 ? backend.extendableArrayType |
4044 : inferred; | 4046 : inferred; |
4045 } else if (Elements.isConstructorOfTypedArraySubclass( | 4047 } else if (Elements.isConstructorOfTypedArraySubclass( |
4046 originalElement, compiler)) { | 4048 originalElement, compiler)) { |
4047 isFixedList = true; | 4049 isFixedList = true; |
4048 TypeMask inferred = | 4050 TypeMask inferred = _inferredTypeOfNewList(send); |
4049 TypeMaskFactory.inferredForNode(sourceElement, send, compiler); | |
4050 ClassElement cls = element.enclosingClass; | 4051 ClassElement cls = element.enclosingClass; |
4051 assert(backend.isNative(cls.thisType.element)); | 4052 assert(backend.isNative(cls.thisType.element)); |
4052 return inferred.containsAll(compiler.world) | 4053 return inferred.containsAll(compiler.world) |
4053 ? new TypeMask.nonNullExact(cls.thisType.element, compiler.world) | 4054 ? new TypeMask.nonNullExact(cls.thisType.element, compiler.world) |
4054 : inferred; | 4055 : inferred; |
4055 } else if (element.isGenerativeConstructor) { | 4056 } else if (element.isGenerativeConstructor) { |
4056 ClassElement cls = element.enclosingClass; | 4057 ClassElement cls = element.enclosingClass; |
4057 if (cls.isAbstract) { | 4058 if (cls.isAbstract) { |
4058 // An error will be thrown. | 4059 // An error will be thrown. |
4059 return new TypeMask.nonNullEmpty(); | 4060 return new TypeMask.nonNullEmpty(); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4171 var constant = inputs[0]; | 4172 var constant = inputs[0]; |
4172 int value = constant.constant.primitiveValue; | 4173 int value = constant.constant.primitiveValue; |
4173 if (0 <= value && value < 0x100000000) canThrow = false; | 4174 if (0 <= value && value < 0x100000000) canThrow = false; |
4174 } | 4175 } |
4175 HForeignCode foreign = new HForeignCode(code, elementType, inputs, | 4176 HForeignCode foreign = new HForeignCode(code, elementType, inputs, |
4176 nativeBehavior: behavior, | 4177 nativeBehavior: behavior, |
4177 throwBehavior: canThrow | 4178 throwBehavior: canThrow |
4178 ? native.NativeThrowBehavior.MAY | 4179 ? native.NativeThrowBehavior.MAY |
4179 : native.NativeThrowBehavior.NEVER); | 4180 : native.NativeThrowBehavior.NEVER); |
4180 push(foreign); | 4181 push(foreign); |
4181 if (compiler.globalInference.isFixedArrayCheckedForGrowable(send)) { | 4182 if (inferenceResults.isFixedArrayCheckedForGrowable(send)) { |
4182 js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array'); | 4183 js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array'); |
4183 // We set the instruction as [canThrow] to avoid it being dead code. | 4184 // We set the instruction as [canThrow] to avoid it being dead code. |
4184 // We need a finer grained side effect. | 4185 // We need a finer grained side effect. |
4185 add(new HForeignCode(code, backend.nullType, [stack.last], | 4186 add(new HForeignCode(code, backend.nullType, [stack.last], |
4186 throwBehavior: native.NativeThrowBehavior.MAY)); | 4187 throwBehavior: native.NativeThrowBehavior.MAY)); |
4187 } | 4188 } |
4188 } else if (isGrowableListConstructorCall) { | 4189 } else if (isGrowableListConstructorCall) { |
4189 push(buildLiteralList(<HInstruction>[])); | 4190 push(buildLiteralList(<HInstruction>[])); |
4190 stack.last.instructionType = elementType; | 4191 stack.last.instructionType = elementType; |
4191 } else { | 4192 } else { |
(...skipping 724 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4916 rhs = graph.addConstantInt(1, compiler); | 4917 rhs = graph.addConstantInt(1, compiler); |
4917 } else { | 4918 } else { |
4918 visit(arguments.head); | 4919 visit(arguments.head); |
4919 assert(arguments.tail.isEmpty); | 4920 assert(arguments.tail.isEmpty); |
4920 rhs = pop(); | 4921 rhs = pop(); |
4921 } | 4922 } |
4922 visitBinarySend( | 4923 visitBinarySend( |
4923 receiver, | 4924 receiver, |
4924 rhs, | 4925 rhs, |
4925 elements.getOperatorSelectorInComplexSendSet(node), | 4926 elements.getOperatorSelectorInComplexSendSet(node), |
4926 elements.getOperatorTypeMaskInComplexSendSet(node), | 4927 inferenceResults.typeOfOperator(node, elements), |
4927 node, | 4928 node, |
4928 sourceInformation: | 4929 sourceInformation: |
4929 sourceInformationBuilder.buildGeneric(node.assignmentOperator)); | 4930 sourceInformationBuilder.buildGeneric(node.assignmentOperator)); |
4930 } | 4931 } |
4931 | 4932 |
4932 void handleSuperSendSet(ast.SendSet node) { | 4933 void handleSuperSendSet(ast.SendSet node) { |
4933 Element element = elements[node]; | 4934 Element element = elements[node]; |
4934 List<HInstruction> setterInputs = <HInstruction>[]; | 4935 List<HInstruction> setterInputs = <HInstruction>[]; |
4935 void generateSuperSendSet() { | 4936 void generateSuperSendSet() { |
4936 Selector setterSelector = elements.getSelector(node); | 4937 Selector setterSelector = elements.getSelector(node); |
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5280 HInstruction receiver = pop(); | 5281 HInstruction receiver = pop(); |
5281 Link<ast.Node> arguments = node.arguments; | 5282 Link<ast.Node> arguments = node.arguments; |
5282 HInstruction index; | 5283 HInstruction index; |
5283 if (node.isIndex) { | 5284 if (node.isIndex) { |
5284 visit(arguments.head); | 5285 visit(arguments.head); |
5285 arguments = arguments.tail; | 5286 arguments = arguments.tail; |
5286 index = pop(); | 5287 index = pop(); |
5287 } | 5288 } |
5288 | 5289 |
5289 pushInvokeDynamic(node, elements.getGetterSelectorInComplexSendSet(node), | 5290 pushInvokeDynamic(node, elements.getGetterSelectorInComplexSendSet(node), |
5290 elements.getGetterTypeMaskInComplexSendSet(node), [receiver, index]); | 5291 inferenceResults.typeOfGetter(node, elements), [receiver, index]); |
5291 HInstruction getterInstruction = pop(); | 5292 HInstruction getterInstruction = pop(); |
5292 if (node.isIfNullAssignment) { | 5293 if (node.isIfNullAssignment) { |
5293 // Compile x[i] ??= e as: | 5294 // Compile x[i] ??= e as: |
5294 // t1 = x[i] | 5295 // t1 = x[i] |
5295 // if (t1 == null) | 5296 // if (t1 == null) |
5296 // t1 = x[i] = e; | 5297 // t1 = x[i] = e; |
5297 // result = t1 | 5298 // result = t1 |
5298 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); | 5299 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5299 brancher.handleIfNull(() => stack.add(getterInstruction), () { | 5300 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
5300 visit(arguments.head); | 5301 visit(arguments.head); |
5301 HInstruction value = pop(); | 5302 HInstruction value = pop(); |
5302 pushInvokeDynamic(node, elements.getSelector(node), | 5303 pushInvokeDynamic( |
5303 elements.getTypeMask(node), [receiver, index, value]); | 5304 node, |
| 5305 elements.getSelector(node), |
| 5306 inferenceResults.typeOfSend(node, elements), |
| 5307 [receiver, index, value]); |
5304 pop(); | 5308 pop(); |
5305 stack.add(value); | 5309 stack.add(value); |
5306 }); | 5310 }); |
5307 } else { | 5311 } else { |
5308 handleComplexOperatorSend(node, getterInstruction, arguments); | 5312 handleComplexOperatorSend(node, getterInstruction, arguments); |
5309 HInstruction value = pop(); | 5313 HInstruction value = pop(); |
5310 pushInvokeDynamic(node, elements.getSelector(node), | 5314 pushInvokeDynamic( |
5311 elements.getTypeMask(node), [receiver, index, value]); | 5315 node, |
| 5316 elements.getSelector(node), |
| 5317 inferenceResults.typeOfSend(node, elements), |
| 5318 [receiver, index, value]); |
5312 pop(); | 5319 pop(); |
5313 if (node.isPostfix) { | 5320 if (node.isPostfix) { |
5314 stack.add(getterInstruction); | 5321 stack.add(getterInstruction); |
5315 } else { | 5322 } else { |
5316 stack.add(value); | 5323 stack.add(value); |
5317 } | 5324 } |
5318 } | 5325 } |
5319 } | 5326 } |
5320 } | 5327 } |
5321 | 5328 |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5505 } | 5512 } |
5506 return; | 5513 return; |
5507 } | 5514 } |
5508 | 5515 |
5509 if (Elements.isInstanceSend(node, elements)) { | 5516 if (Elements.isInstanceSend(node, elements)) { |
5510 void generateAssignment(HInstruction receiver) { | 5517 void generateAssignment(HInstruction receiver) { |
5511 // desugars `e.x op= e2` to `e.x = e.x op e2` | 5518 // desugars `e.x op= e2` to `e.x = e.x op e2` |
5512 generateInstanceGetterWithCompiledReceiver( | 5519 generateInstanceGetterWithCompiledReceiver( |
5513 node, | 5520 node, |
5514 elements.getGetterSelectorInComplexSendSet(node), | 5521 elements.getGetterSelectorInComplexSendSet(node), |
5515 elements.getGetterTypeMaskInComplexSendSet(node), | 5522 inferenceResults.typeOfGetter(node, elements), |
5516 receiver); | 5523 receiver); |
5517 HInstruction getterInstruction = pop(); | 5524 HInstruction getterInstruction = pop(); |
5518 if (node.isIfNullAssignment) { | 5525 if (node.isIfNullAssignment) { |
5519 SsaBranchBuilder brancher = | 5526 SsaBranchBuilder brancher = |
5520 new SsaBranchBuilder(this, compiler, node); | 5527 new SsaBranchBuilder(this, compiler, node); |
5521 brancher.handleIfNull(() => stack.add(getterInstruction), () { | 5528 brancher.handleIfNull(() => stack.add(getterInstruction), () { |
5522 visit(node.arguments.head); | 5529 visit(node.arguments.head); |
5523 generateInstanceSetterWithCompiledReceiver(node, receiver, pop()); | 5530 generateInstanceSetterWithCompiledReceiver(node, receiver, pop()); |
5524 }); | 5531 }); |
5525 } else { | 5532 } else { |
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5960 !link.isEmpty; | 5967 !link.isEmpty; |
5961 link = link.tail) { | 5968 link = link.tail) { |
5962 visit(link.head); | 5969 visit(link.head); |
5963 inputs.add(pop()); | 5970 inputs.add(pop()); |
5964 } | 5971 } |
5965 instruction = buildLiteralList(inputs); | 5972 instruction = buildLiteralList(inputs); |
5966 add(instruction); | 5973 add(instruction); |
5967 instruction = setRtiIfNeeded(instruction, node); | 5974 instruction = setRtiIfNeeded(instruction, node); |
5968 } | 5975 } |
5969 | 5976 |
5970 TypeMask type = | 5977 TypeMask type = _inferredTypeOfNewList(node); |
5971 TypeMaskFactory.inferredForNode(sourceElement, node, compiler); | |
5972 if (!type.containsAll(compiler.world)) instruction.instructionType = type; | 5978 if (!type.containsAll(compiler.world)) instruction.instructionType = type; |
5973 stack.add(instruction); | 5979 stack.add(instruction); |
5974 } | 5980 } |
5975 | 5981 |
| 5982 _inferredTypeOfNewList(ast.Node node) => |
| 5983 inferenceResults.typeOfNewList(sourceElement, node) ?? |
| 5984 compiler.commonMasks.dynamicType; |
| 5985 |
5976 visitConditional(ast.Conditional node) { | 5986 visitConditional(ast.Conditional node) { |
5977 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); | 5987 SsaBranchBuilder brancher = new SsaBranchBuilder(this, compiler, node); |
5978 brancher.handleConditional(() => visit(node.condition), | 5988 brancher.handleConditional(() => visit(node.condition), |
5979 () => visit(node.thenExpression), () => visit(node.elseExpression)); | 5989 () => visit(node.thenExpression), () => visit(node.elseExpression)); |
5980 } | 5990 } |
5981 | 5991 |
5982 visitStringInterpolation(ast.StringInterpolation node) { | 5992 visitStringInterpolation(ast.StringInterpolation node) { |
5983 StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); | 5993 StringBuilderVisitor stringBuilder = new StringBuilderVisitor(this, node); |
5984 stringBuilder.visit(node); | 5994 stringBuilder.visit(node); |
5985 stack.add(stringBuilder.result); | 5995 stack.add(stringBuilder.result); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6059 visit(node.expression); | 6069 visit(node.expression); |
6060 HInstruction expression = pop(); | 6070 HInstruction expression = pop(); |
6061 pushInvokeStatic(node, helpers.streamIteratorConstructor, | 6071 pushInvokeStatic(node, helpers.streamIteratorConstructor, |
6062 [expression, graph.addConstantNull(compiler)]); | 6072 [expression, graph.addConstantNull(compiler)]); |
6063 streamIterator = pop(); | 6073 streamIterator = pop(); |
6064 | 6074 |
6065 void buildInitializer() {} | 6075 void buildInitializer() {} |
6066 | 6076 |
6067 HInstruction buildCondition() { | 6077 HInstruction buildCondition() { |
6068 Selector selector = Selectors.moveNext; | 6078 Selector selector = Selectors.moveNext; |
6069 TypeMask mask = elements.getMoveNextTypeMask(node); | 6079 TypeMask mask = inferenceResults.typeOfIteratorMoveNext(node, elements); |
6070 pushInvokeDynamic(node, selector, mask, [streamIterator]); | 6080 pushInvokeDynamic(node, selector, mask, [streamIterator]); |
6071 HInstruction future = pop(); | 6081 HInstruction future = pop(); |
6072 push(new HAwait(future, | 6082 push(new HAwait(future, |
6073 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); | 6083 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); |
6074 return popBoolified(); | 6084 return popBoolified(); |
6075 } | 6085 } |
6076 | 6086 |
6077 void buildBody() { | 6087 void buildBody() { |
6078 Selector call = Selectors.current; | 6088 Selector call = Selectors.current; |
6079 TypeMask callMask = elements.getCurrentTypeMask(node); | 6089 TypeMask callMask = |
| 6090 inferenceResults.typeOfIteratorCurrent(node, elements); |
6080 pushInvokeDynamic(node, call, callMask, [streamIterator]); | 6091 pushInvokeDynamic(node, call, callMask, [streamIterator]); |
6081 | 6092 |
6082 ast.Node identifier = node.declaredIdentifier; | 6093 ast.Node identifier = node.declaredIdentifier; |
6083 Element variable = elements.getForInVariable(node); | 6094 Element variable = elements.getForInVariable(node); |
6084 Selector selector = elements.getSelector(identifier); | 6095 Selector selector = elements.getSelector(identifier); |
6085 TypeMask mask = elements.getTypeMask(identifier); | |
6086 | |
6087 HInstruction value = pop(); | 6096 HInstruction value = pop(); |
6088 if (identifier.asSend() != null && | 6097 if (identifier.asSend() != null && |
6089 Elements.isInstanceSend(identifier, elements)) { | 6098 Elements.isInstanceSend(identifier, elements)) { |
| 6099 TypeMask mask = inferenceResults.typeOfSend(identifier, elements); |
6090 HInstruction receiver = generateInstanceSendReceiver(identifier); | 6100 HInstruction receiver = generateInstanceSendReceiver(identifier); |
6091 assert(receiver != null); | 6101 assert(receiver != null); |
6092 generateInstanceSetterWithCompiledReceiver(null, receiver, value, | 6102 generateInstanceSetterWithCompiledReceiver(null, receiver, value, |
6093 selector: selector, mask: mask, location: identifier); | 6103 selector: selector, mask: mask, location: identifier); |
6094 } else { | 6104 } else { |
6095 generateNonInstanceSetter(null, variable, value, location: identifier); | 6105 generateNonInstanceSetter(null, variable, value, location: identifier); |
6096 } | 6106 } |
6097 pop(); // Pop the value pushed by the setter call. | 6107 pop(); // Pop the value pushed by the setter call. |
6098 | 6108 |
6099 visit(node.body); | 6109 visit(node.body); |
6100 } | 6110 } |
6101 | 6111 |
6102 void buildUpdate() {} | 6112 void buildUpdate() {} |
6103 ; | |
6104 | 6113 |
6105 buildProtectedByFinally(() { | 6114 buildProtectedByFinally(() { |
6106 handleLoop( | 6115 handleLoop( |
6107 node, buildInitializer, buildCondition, buildUpdate, buildBody); | 6116 node, buildInitializer, buildCondition, buildUpdate, buildBody); |
6108 }, () { | 6117 }, () { |
6109 pushInvokeDynamic(node, Selectors.cancel, null, [streamIterator]); | 6118 pushInvokeDynamic(node, Selectors.cancel, null, [streamIterator]); |
6110 push(new HAwait(pop(), | 6119 push(new HAwait(pop(), |
6111 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); | 6120 new TypeMask.subclass(coreClasses.objectClass, compiler.world))); |
6112 pop(); | 6121 pop(); |
6113 }); | 6122 }); |
6114 } | 6123 } |
6115 | 6124 |
6116 visitSyncForIn(ast.SyncForIn node) { | 6125 visitSyncForIn(ast.SyncForIn node) { |
6117 // The 'get iterator' selector for this node has the inferred receiver type. | 6126 // The 'get iterator' selector for this node has the inferred receiver type. |
6118 // If the receiver supports JavaScript indexing we generate an indexing loop | 6127 // If the receiver supports JavaScript indexing we generate an indexing loop |
6119 // instead of allocating an iterator object. | 6128 // instead of allocating an iterator object. |
6120 | 6129 |
6121 // This scheme recognizes for-in on direct lists. It does not recognize all | 6130 // This scheme recognizes for-in on direct lists. It does not recognize all |
6122 // uses of ArrayIterator. They still occur when the receiver is an Iterable | 6131 // uses of ArrayIterator. They still occur when the receiver is an Iterable |
6123 // with a `get iterator` method that delegate to another Iterable and the | 6132 // with a `get iterator` method that delegate to another Iterable and the |
6124 // method is inlined. We would require full scalar replacement in that | 6133 // method is inlined. We would require full scalar replacement in that |
6125 // case. | 6134 // case. |
6126 | 6135 |
6127 TypeMask mask = elements.getIteratorTypeMask(node); | 6136 TypeMask mask = inferenceResults.typeOfIterator(node, elements); |
6128 | 6137 |
6129 ClassWorld classWorld = compiler.world; | 6138 ClassWorld classWorld = compiler.world; |
6130 if (mask != null && | 6139 if (mask != null && |
6131 mask.satisfies(helpers.jsIndexableClass, classWorld) && | 6140 mask.satisfies(helpers.jsIndexableClass, classWorld) && |
6132 // String is indexable but not iterable. | 6141 // String is indexable but not iterable. |
6133 !mask.satisfies(helpers.jsStringClass, classWorld)) { | 6142 !mask.satisfies(helpers.jsStringClass, classWorld)) { |
6134 return buildSyncForInIndexable(node, mask); | 6143 return buildSyncForInIndexable(node, mask); |
6135 } | 6144 } |
6136 buildSyncForInIterator(node); | 6145 buildSyncForInIterator(node); |
6137 } | 6146 } |
6138 | 6147 |
6139 buildSyncForInIterator(ast.SyncForIn node) { | 6148 buildSyncForInIterator(ast.SyncForIn node) { |
6140 // Generate a structure equivalent to: | 6149 // Generate a structure equivalent to: |
6141 // Iterator<E> $iter = <iterable>.iterator; | 6150 // Iterator<E> $iter = <iterable>.iterator; |
6142 // while ($iter.moveNext()) { | 6151 // while ($iter.moveNext()) { |
6143 // <declaredIdentifier> = $iter.current; | 6152 // <declaredIdentifier> = $iter.current; |
6144 // <body> | 6153 // <body> |
6145 // } | 6154 // } |
6146 | 6155 |
6147 // The iterator is shared between initializer, condition and body. | 6156 // The iterator is shared between initializer, condition and body. |
6148 HInstruction iterator; | 6157 HInstruction iterator; |
6149 | 6158 |
6150 void buildInitializer() { | 6159 void buildInitializer() { |
6151 Selector selector = Selectors.iterator; | 6160 Selector selector = Selectors.iterator; |
6152 TypeMask mask = elements.getIteratorTypeMask(node); | 6161 TypeMask mask = inferenceResults.typeOfIterator(node, elements); |
6153 visit(node.expression); | 6162 visit(node.expression); |
6154 HInstruction receiver = pop(); | 6163 HInstruction receiver = pop(); |
6155 pushInvokeDynamic(node, selector, mask, [receiver]); | 6164 pushInvokeDynamic(node, selector, mask, [receiver]); |
6156 iterator = pop(); | 6165 iterator = pop(); |
6157 } | 6166 } |
6158 | 6167 |
6159 HInstruction buildCondition() { | 6168 HInstruction buildCondition() { |
6160 Selector selector = Selectors.moveNext; | 6169 Selector selector = Selectors.moveNext; |
6161 TypeMask mask = elements.getMoveNextTypeMask(node); | 6170 TypeMask mask = inferenceResults.typeOfIteratorMoveNext(node, elements); |
6162 pushInvokeDynamic(node, selector, mask, [iterator]); | 6171 pushInvokeDynamic(node, selector, mask, [iterator]); |
6163 return popBoolified(); | 6172 return popBoolified(); |
6164 } | 6173 } |
6165 | 6174 |
6166 void buildBody() { | 6175 void buildBody() { |
6167 Selector call = Selectors.current; | 6176 Selector call = Selectors.current; |
6168 TypeMask mask = elements.getCurrentTypeMask(node); | 6177 TypeMask mask = inferenceResults.typeOfIteratorCurrent(node, elements); |
6169 pushInvokeDynamic(node, call, mask, [iterator]); | 6178 pushInvokeDynamic(node, call, mask, [iterator]); |
6170 buildAssignLoopVariable(node, pop()); | 6179 buildAssignLoopVariable(node, pop()); |
6171 visit(node.body); | 6180 visit(node.body); |
6172 } | 6181 } |
6173 | 6182 |
6174 handleLoop(node, buildInitializer, buildCondition, () {}, buildBody); | 6183 handleLoop(node, buildInitializer, buildCondition, () {}, buildBody); |
6175 } | 6184 } |
6176 | 6185 |
6177 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { | 6186 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { |
6178 ast.Node identifier = node.declaredIdentifier; | 6187 ast.Node identifier = node.declaredIdentifier; |
6179 Element variable = elements.getForInVariable(node); | 6188 Element variable = elements.getForInVariable(node); |
6180 Selector selector = elements.getSelector(identifier); | 6189 Selector selector = elements.getSelector(identifier); |
6181 TypeMask mask = elements.getTypeMask(identifier); | |
6182 | 6190 |
6183 if (identifier.asSend() != null && | 6191 if (identifier.asSend() != null && |
6184 Elements.isInstanceSend(identifier, elements)) { | 6192 Elements.isInstanceSend(identifier, elements)) { |
| 6193 TypeMask mask = inferenceResults.typeOfSend(identifier, elements); |
6185 HInstruction receiver = generateInstanceSendReceiver(identifier); | 6194 HInstruction receiver = generateInstanceSendReceiver(identifier); |
6186 assert(receiver != null); | 6195 assert(receiver != null); |
6187 generateInstanceSetterWithCompiledReceiver(null, receiver, value, | 6196 generateInstanceSetterWithCompiledReceiver(null, receiver, value, |
6188 selector: selector, mask: mask, location: identifier); | 6197 selector: selector, mask: mask, location: identifier); |
6189 } else { | 6198 } else { |
6190 generateNonInstanceSetter(null, variable, value, location: identifier); | 6199 generateNonInstanceSetter(null, variable, value, location: identifier); |
6191 } | 6200 } |
6192 pop(); // Discard the value pushed by the setter call. | 6201 pop(); // Discard the value pushed by the setter call. |
6193 } | 6202 } |
6194 | 6203 |
(...skipping 1350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7545 const _LoopTypeVisitor(); | 7554 const _LoopTypeVisitor(); |
7546 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; | 7555 int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; |
7547 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; | 7556 int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; |
7548 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; | 7557 int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; |
7549 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; | 7558 int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; |
7550 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 7559 int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
7551 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; | 7560 int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
7552 int visitSwitchStatement(ast.SwitchStatement node) => | 7561 int visitSwitchStatement(ast.SwitchStatement node) => |
7553 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; | 7562 HLoopBlockInformation.SWITCH_CONTINUE_LOOP; |
7554 } | 7563 } |
OLD | NEW |