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