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 part of ssa; | 5 part of ssa; |
6 | 6 |
7 /** | 7 /** |
8 * A special element for the extra parameter taken by intercepted | 8 * A special element for the extra parameter taken by intercepted |
9 * methods. We need to override [Element.computeType] because our | 9 * methods. We need to override [Element.computeType] because our |
10 * optimizers may look at its declared type. | 10 * optimizers may look at its declared type. |
(...skipping 2615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2626 | 2626 |
2627 void pushInvokeHelper4(Element helper, HInstruction a0, HInstruction a1, | 2627 void pushInvokeHelper4(Element helper, HInstruction a0, HInstruction a1, |
2628 HInstruction a2, HInstruction a3) { | 2628 HInstruction a2, HInstruction a3) { |
2629 HInstruction reference = new HStatic(helper); | 2629 HInstruction reference = new HStatic(helper); |
2630 add(reference); | 2630 add(reference); |
2631 List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2, a3]; | 2631 List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2, a3]; |
2632 HInstruction result = new HInvokeStatic(inputs); | 2632 HInstruction result = new HInvokeStatic(inputs); |
2633 push(result); | 2633 push(result); |
2634 } | 2634 } |
2635 | 2635 |
2636 createForeign(String code, String type, List<HInstruction> inputs) { | |
2637 return new HForeign(new LiteralDartString(code), | |
2638 new LiteralDartString(type), | |
2639 inputs); | |
2640 } | |
2641 | |
2642 List<HInstruction> buildRepresentations(DartType type) { | |
kasperl
2012/12/06 09:51:04
Maybe give this function a more telling name? Also
karlklose
2012/12/06 13:30:03
Renamed and added a comment for making the constru
| |
2643 HInstruction createForeignArray(String code, inputs) { | |
2644 return createForeign(code, 'JSArray', inputs); | |
2645 } | |
2646 HInstruction typeInfo; | |
2647 | |
2648 /// Helper to create an instruction that contains the runtime value of | |
2649 /// the type variable [variable]. | |
2650 HInstruction getTypeArgument(TypeVariableType variable) { | |
2651 if (typeInfo == null) { | |
2652 HInstruction context = localsHandler.readThis(); | |
2653 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), context); | |
2654 typeInfo = pop(); | |
2655 } | |
2656 int intIndex = RuntimeTypeInformation.getTypeVariableIndex(variable); | |
2657 HInstruction index = graph.addConstantInt(intIndex, constantSystem); | |
2658 return createForeignArray('#[#]', <HInstruction>[typeInfo, index]); | |
2659 } | |
2660 | |
2661 // Compute the representation of the type arguments, including access | |
2662 // to the runtime type information for type variables as instructions. | |
2663 HInstruction representations; | |
2664 if (type.element.isTypeVariable()) { | |
2665 return <HInstruction>[getTypeArgument(type)]; | |
2666 } else { | |
2667 assert(type.element.isClass()); | |
2668 List<HInstruction> arguments = <HInstruction>[]; | |
2669 InterfaceType interface = type; | |
2670 for (DartType argument in interface.typeArguments) { | |
2671 List<HInstruction> inputs = <HInstruction>[]; | |
2672 String template = rti.getTypeRepresentation(argument, (variable) { | |
2673 HInstruction runtimeType = getTypeArgument(variable); | |
2674 add(runtimeType); | |
2675 inputs.add(runtimeType); | |
2676 }); | |
2677 HInstruction representation = createForeignArray(template, inputs); | |
2678 add(representation); | |
2679 arguments.add(representation); | |
2680 } | |
2681 return arguments; | |
2682 } | |
2683 } | |
2684 | |
2636 visitOperatorSend(node) { | 2685 visitOperatorSend(node) { |
2637 assert(node.selector is Operator); | 2686 assert(node.selector is Operator); |
2638 if (!methodInterceptionEnabled) { | 2687 if (!methodInterceptionEnabled) { |
2639 visitDynamicSend(node); | 2688 visitDynamicSend(node); |
2640 return; | 2689 return; |
2641 } | 2690 } |
2642 | 2691 |
2643 Operator op = node.selector; | 2692 Operator op = node.selector; |
2644 if (const SourceString("[]") == op.source) { | 2693 if (const SourceString("[]") == op.source) { |
2645 HStatic target = new HStatic(interceptors.getIndexInterceptor()); | 2694 HStatic target = new HStatic(interceptors.getIndexInterceptor()); |
(...skipping 15 matching lines...) Expand all Loading... | |
2661 HInstruction expression = pop(); | 2710 HInstruction expression = pop(); |
2662 Node argument = node.arguments.head; | 2711 Node argument = node.arguments.head; |
2663 TypeAnnotation typeAnnotation = argument.asTypeAnnotation(); | 2712 TypeAnnotation typeAnnotation = argument.asTypeAnnotation(); |
2664 bool isNot = false; | 2713 bool isNot = false; |
2665 // TODO(ngeoffray): Duplicating pattern in resolver. We should | 2714 // TODO(ngeoffray): Duplicating pattern in resolver. We should |
2666 // add a new kind of node. | 2715 // add a new kind of node. |
2667 if (typeAnnotation == null) { | 2716 if (typeAnnotation == null) { |
2668 typeAnnotation = argument.asSend().receiver; | 2717 typeAnnotation = argument.asSend().receiver; |
2669 isNot = true; | 2718 isNot = true; |
2670 } | 2719 } |
2671 | |
2672 DartType type = elements.getType(typeAnnotation); | 2720 DartType type = elements.getType(typeAnnotation); |
2673 if (type.isMalformed) { | 2721 if (type.isMalformed) { |
2674 String reasons = fetchReasonsFromMalformedType(type); | 2722 String reasons = fetchReasonsFromMalformedType(type); |
2675 if (compiler.enableTypeAssertions) { | 2723 if (compiler.enableTypeAssertions) { |
2676 generateMalformedSubtypeError(node, expression, type, reasons); | 2724 generateMalformedSubtypeError(node, expression, type, reasons); |
2677 } else { | 2725 } else { |
2678 generateRuntimeError(node, '$type is malformed: $reasons'); | 2726 generateRuntimeError(node, '$type is malformed: $reasons'); |
2679 } | 2727 } |
2680 return; | 2728 return; |
2681 } | 2729 } |
2682 HInstruction typeInfo = null; | 2730 if (type.element.isTypeVariable()) { |
2683 if (RuntimeTypeInformation.hasTypeArguments(type)) { | 2731 // TODO(karlklose): remove this check when the backend can deal with it. |
kasperl
2012/12/06 09:51:04
Expand the comment to explain what you're waiting
karlklose
2012/12/06 13:30:03
Done.
| |
2732 stack.add(graph.addConstantBool(true, constantSystem)); | |
2733 return; | |
2734 } | |
2735 | |
2736 HInstruction instruction; | |
2737 if (RuntimeTypeInformation.hasTypeArguments(type) || | |
2738 type.element.isTypeVariable()) { | |
2684 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), expression); | 2739 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), expression); |
kasperl
2012/12/06 09:51:04
Could this code be put in a separate helper functi
karlklose
2012/12/06 13:30:03
Done.
| |
2685 typeInfo = pop(); | 2740 HInstruction typeInfo = pop(); |
2741 Element helper = compiler.findHelper(const SourceString('isSubtype')); | |
kasperl
2012/12/06 09:51:04
Would it make sense to have a separate HIsSubtype
karlklose
2012/12/06 13:30:03
I am not sure how much work it is to do it, but I
| |
2742 HInstruction isSubtype = new HStatic(helper); | |
2743 add(isSubtype); | |
2744 List<HInstruction> representations = buildRepresentations(type); | |
2745 List<HInstruction> checks = <HInstruction>[]; | |
2746 int index = 0; | |
2747 representations.forEach((HInstruction representation) { | |
kasperl
2012/12/06 09:51:04
Add a comment that explains the code you're buildi
karlklose
2012/12/06 13:30:03
Done.
| |
2748 HInstruction position = graph.addConstantInt(index, constantSystem); | |
2749 HInstruction typeArgument = | |
kasperl
2012/12/06 09:51:04
I wonder if we should be creating something that w
karlklose
2012/12/06 13:30:03
As said above, I'll look into better code generati
| |
2750 createForeign('#[#]', 'Object', [typeInfo, position]); | |
2751 add(typeArgument); | |
2752 List<HInstruction> inputs = | |
2753 <HInstruction>[isSubtype, typeArgument, representation]; | |
2754 HInstruction call = new HInvokeStatic(inputs); | |
2755 add(call); | |
2756 checks.add(call); | |
2757 index++; | |
2758 }); | |
2759 instruction = new HIs.withArgumentChecks(type, expression, checks); | |
2760 } else { | |
2761 instruction = new HIs(type, expression); | |
2686 } | 2762 } |
2687 if (type.element.isTypeVariable()) { | 2763 if (isNot) { |
2688 // TODO(karlklose): We currently answer true to any is check | 2764 add(instruction); |
2689 // involving a type variable -- both is T and is !T -- until | 2765 instruction = new HNot(instruction); |
2690 // we have a proper implementation of reified generics. | |
2691 stack.add(graph.addConstantBool(true, constantSystem)); | |
2692 } else { | |
2693 HInstruction instruction; | |
2694 if (typeInfo != null) { | |
2695 instruction = new HIs.withTypeInfoCall(type, expression, typeInfo); | |
2696 } else { | |
2697 instruction = new HIs(type, expression); | |
2698 } | |
2699 if (isNot) { | |
2700 add(instruction); | |
2701 instruction = new HNot(instruction); | |
2702 } | |
2703 push(instruction); | |
2704 } | 2766 } |
2767 push(instruction); | |
2705 } else if (const SourceString("as") == op.source) { | 2768 } else if (const SourceString("as") == op.source) { |
2706 visit(node.receiver); | 2769 visit(node.receiver); |
2707 HInstruction expression = pop(); | 2770 HInstruction expression = pop(); |
2708 Node argument = node.arguments.head; | 2771 Node argument = node.arguments.head; |
2709 TypeAnnotation typeAnnotation = argument.asTypeAnnotation(); | 2772 TypeAnnotation typeAnnotation = argument.asTypeAnnotation(); |
2710 DartType type = elements.getType(typeAnnotation); | 2773 DartType type = elements.getType(typeAnnotation); |
2711 HInstruction converted = expression.convertType( | 2774 HInstruction converted = expression.convertType( |
2712 compiler, type, HTypeConversion.CAST_TYPE_CHECK); | 2775 compiler, type, HTypeConversion.CAST_TYPE_CHECK); |
2713 if (converted != expression) add(converted); | 2776 if (converted != expression) add(converted); |
2714 stack.add(converted); | 2777 stack.add(converted); |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3097 */ | 3160 */ |
3098 HInstruction analyzeTypeArgument(DartType argument, Node currentNode) { | 3161 HInstruction analyzeTypeArgument(DartType argument, Node currentNode) { |
3099 assert(invariant(currentNode, | 3162 assert(invariant(currentNode, |
3100 !compiler.enableTypeAssertions || !argument.isMalformed, | 3163 !compiler.enableTypeAssertions || !argument.isMalformed, |
3101 message: '$argument is malformed in checked mode')); | 3164 message: '$argument is malformed in checked mode')); |
3102 if (argument == compiler.types.dynamicType || argument.isMalformed) { | 3165 if (argument == compiler.types.dynamicType || argument.isMalformed) { |
3103 // Represent [dynamic] as [null]. | 3166 // Represent [dynamic] as [null]. |
3104 return graph.addConstantNull(constantSystem); | 3167 return graph.addConstantNull(constantSystem); |
3105 } | 3168 } |
3106 | 3169 |
3107 // These variables are shared between invocations of the helper methods. | 3170 createForeignString(template, inputs) { |
kasperl
2012/12/06 09:51:04
Use createForeign?
karlklose
2012/12/06 13:30:03
Done.
| |
3171 return new HForeign(new LiteralDartString(template), | |
3172 new LiteralDartString('String'), | |
3173 inputs); | |
3174 } | |
3175 | |
3176 // These variables are shared between invocations of the helper. | |
3108 HInstruction typeInfo; | 3177 HInstruction typeInfo; |
3109 StringBuffer template = new StringBuffer(); | |
3110 List<HInstruction> inputs = <HInstruction>[]; | 3178 List<HInstruction> inputs = <HInstruction>[]; |
3111 | 3179 |
3112 /** | 3180 /** |
3113 * Helper to create an instruction that gets the value of a type variable. | 3181 * Helper to create an instruction that gets the value of a type variable. |
3114 */ | 3182 */ |
3115 void addTypeVariableReference(TypeVariableType type) { | 3183 void addTypeVariableReference(TypeVariableType type) { |
3116 Element member = work.element; | 3184 Element member = work.element; |
3117 if (member.enclosingElement.isClosure()) { | 3185 if (member.enclosingElement.isClosure()) { |
3118 ClosureClassElement closureClass = member.enclosingElement; | 3186 ClosureClassElement closureClass = member.enclosingElement; |
3119 member = closureClass.methodElement; | 3187 member = closureClass.methodElement; |
3120 member = member.getOutermostEnclosingMemberOrTopLevel(); | 3188 member = member.getOutermostEnclosingMemberOrTopLevel(); |
3121 } | 3189 } |
3122 if (member.isFactoryConstructor()) { | 3190 if (member.isFactoryConstructor()) { |
3123 // The type variable is stored in a parameter of the factory. | 3191 // The type variable is stored in a parameter of the factory. |
3124 inputs.add(localsHandler.readLocal(type.element)); | 3192 inputs.add(localsHandler.readLocal(type.element)); |
3125 } else if (member.isInstanceMember() | 3193 } else if (member.isInstanceMember() |
3126 || member.isGenerativeConstructor()) { | 3194 || member.isGenerativeConstructor()) { |
3127 // The type variable is stored in [this]. | 3195 // The type variable is stored in [this]. |
3128 if (typeInfo == null) { | 3196 if (typeInfo == null) { |
3129 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), | 3197 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), |
3130 localsHandler.readThis()); | 3198 localsHandler.readThis()); |
3131 typeInfo = pop(); | 3199 typeInfo = pop(); |
3132 } | 3200 } |
3133 int index = RuntimeTypeInformation.getTypeVariableIndex(type); | 3201 int index = RuntimeTypeInformation.getTypeVariableIndex(type); |
3134 HInstruction foreign = new HForeign( | 3202 HInstruction foreign = createForeignString('#[$index]', |
3135 new LiteralDartString('#[$index]'), | 3203 <HInstruction>[typeInfo]); |
3136 new LiteralDartString('String'), | |
3137 <HInstruction>[typeInfo]); | |
3138 add(foreign); | 3204 add(foreign); |
3139 inputs.add(foreign); | 3205 inputs.add(foreign); |
3140 } else { | 3206 } else { |
3141 // TODO(ngeoffray): Match the VM behavior and throw an | 3207 // TODO(ngeoffray): Match the VM behavior and throw an |
3142 // exception at runtime. | 3208 // exception at runtime. |
3143 compiler.cancel('Unimplemented unresolved type variable', | 3209 compiler.cancel('Unimplemented unresolved type variable', |
3144 node: currentNode); | 3210 node: currentNode); |
3145 } | 3211 } |
3146 } | 3212 } |
3147 | 3213 |
3148 /** | 3214 String template = rti.getTypeRepresentation(argument, |
3149 * Helper to build an instruction that builds the string representation for | 3215 addTypeVariableReference); |
3150 * this type, where type variables are substituted by their runtime value. | 3216 HInstruction result = createForeignString(template, inputs); |
3151 * | |
3152 * Examples: | |
3153 * Type Template Inputs | |
3154 * int 'int' [] | |
3155 * C<int, int> 'C<int, int>' [] | |
3156 * Var # [getRuntimeType(this).Var] | |
3157 * C<int, D<Var>> 'C<int, D<' + # + '>>' [getRuntimeType(this).Var] | |
3158 */ | |
3159 void buildTypeString(DartType type, {isInQuotes: false}) { | |
3160 if (type is TypeVariableType) { | |
3161 addTypeVariableReference(type); | |
3162 template.add(isInQuotes ? "' + # +'" : "#"); | |
3163 } else if (type is InterfaceType) { | |
3164 bool isFirstVariable = true; | |
3165 InterfaceType interfaceType = type; | |
3166 bool hasTypeArguments = !interfaceType.isRaw; | |
3167 if (!isInQuotes) template.add("'"); | |
3168 template.add(backend.namer.getName(type.element)); | |
3169 if (hasTypeArguments) { | |
3170 template.add("<"); | |
3171 for (DartType argument in interfaceType.typeArguments) { | |
3172 if (!isFirstVariable) { | |
3173 template.add(", "); | |
3174 } else { | |
3175 isFirstVariable = false; | |
3176 } | |
3177 buildTypeString(argument, isInQuotes: true); | |
3178 } | |
3179 template.add(">"); | |
3180 } | |
3181 if (!isInQuotes) template.add("'"); | |
3182 } else { | |
3183 assert(type is TypedefType); | |
3184 if (!isInQuotes) template.add("'"); | |
3185 template.add(backend.namer.getName(argument.element)); | |
3186 if (!isInQuotes) template.add("'"); | |
3187 } | |
3188 } | |
3189 | |
3190 buildTypeString(argument, isInQuotes: false); | |
3191 HInstruction result = | |
3192 new HForeign(new LiteralDartString("$template"), | |
3193 new LiteralDartString('String'), | |
3194 inputs); | |
3195 add(result); | 3217 add(result); |
3196 return result; | 3218 return result; |
3197 } | 3219 } |
3198 | 3220 |
3199 void handleListConstructor(InterfaceType type, | 3221 void handleListConstructor(InterfaceType type, |
3200 Node currentNode, | 3222 Node currentNode, |
3201 HInstruction newObject) { | 3223 HInstruction newObject) { |
3202 if (!compiler.world.needsRti(type.element)) return; | 3224 if (!compiler.world.needsRti(type.element)) return; |
3203 List<HInstruction> inputs = <HInstruction>[]; | 3225 List<HInstruction> inputs = <HInstruction>[]; |
3204 if (!type.isRaw) { | 3226 if (!type.isRaw) { |
(...skipping 1756 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4961 new HSubGraphBlockInformation(elseBranch.graph)); | 4983 new HSubGraphBlockInformation(elseBranch.graph)); |
4962 | 4984 |
4963 HBasicBlock conditionStartBlock = conditionBranch.block; | 4985 HBasicBlock conditionStartBlock = conditionBranch.block; |
4964 conditionStartBlock.setBlockFlow(info, joinBlock); | 4986 conditionStartBlock.setBlockFlow(info, joinBlock); |
4965 SubGraph conditionGraph = conditionBranch.graph; | 4987 SubGraph conditionGraph = conditionBranch.graph; |
4966 HIf branch = conditionGraph.end.last; | 4988 HIf branch = conditionGraph.end.last; |
4967 assert(branch is HIf); | 4989 assert(branch is HIf); |
4968 branch.blockInformation = conditionStartBlock.blockFlow; | 4990 branch.blockInformation = conditionStartBlock.blockFlow; |
4969 } | 4991 } |
4970 } | 4992 } |
OLD | NEW |