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) { | |
ngeoffray
2012/12/06 23:21:45
HForeign createForeign
karlklose
2012/12/07 07:46:35
Done.
| |
2637 return new HForeign(new LiteralDartString(code), | |
2638 new LiteralDartString(type), | |
2639 inputs); | |
2640 } | |
2641 | |
2642 HInstruction getRuntimeTypeInfo(HInstruction target) { | |
2643 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), target); | |
2644 return pop(); | |
2645 } | |
2646 | |
2647 // TODO(karlklose): change construction of the representations to be GVN'able. | |
ngeoffray
2012/12/06 23:21:45
You can also reference the bug number.
karlklose
2012/12/07 07:46:35
Done.
| |
2648 List<HInstruction> buildTypeArgumentRepresentations(DartType type) { | |
2649 HInstruction createForeignArray(String code, inputs) { | |
2650 return createForeign(code, 'JSArray', inputs); | |
ngeoffray
2012/12/06 23:21:45
Should be '=List' but i plan on fixing that.
karlklose
2012/12/07 07:46:35
I changed it to '=List'.
| |
2651 } | |
2652 HInstruction typeInfo; | |
2653 | |
2654 /// Helper to create an instruction that contains the runtime value of | |
2655 /// the type variable [variable]. | |
2656 HInstruction getTypeArgument(TypeVariableType variable) { | |
2657 if (typeInfo == null) { | |
2658 typeInfo = getRuntimeTypeInfo(localsHandler.readThis()); | |
2659 } | |
2660 int intIndex = RuntimeTypeInformation.getTypeVariableIndex(variable); | |
2661 HInstruction index = graph.addConstantInt(intIndex, constantSystem); | |
2662 return createForeignArray('#[#]', <HInstruction>[typeInfo, index]); | |
2663 } | |
2664 | |
2665 // Compute the representation of the type arguments, including access | |
2666 // to the runtime type information for type variables as instructions. | |
2667 HInstruction representations; | |
2668 if (type.element.isTypeVariable()) { | |
2669 return <HInstruction>[getTypeArgument(type)]; | |
2670 } else { | |
2671 assert(type.element.isClass()); | |
2672 List<HInstruction> arguments = <HInstruction>[]; | |
2673 InterfaceType interface = type; | |
2674 for (DartType argument in interface.typeArguments) { | |
2675 List<HInstruction> inputs = <HInstruction>[]; | |
2676 String template = rti.getTypeRepresentation(argument, (variable) { | |
2677 HInstruction runtimeType = getTypeArgument(variable); | |
2678 add(runtimeType); | |
2679 inputs.add(runtimeType); | |
2680 }); | |
2681 HInstruction representation = createForeignArray(template, inputs); | |
2682 add(representation); | |
2683 arguments.add(representation); | |
2684 } | |
2685 return arguments; | |
2686 } | |
2687 } | |
2688 | |
2636 visitOperatorSend(node) { | 2689 visitOperatorSend(node) { |
2637 assert(node.selector is Operator); | 2690 assert(node.selector is Operator); |
2638 if (!methodInterceptionEnabled) { | 2691 if (!methodInterceptionEnabled) { |
2639 visitDynamicSend(node); | 2692 visitDynamicSend(node); |
2640 return; | 2693 return; |
2641 } | 2694 } |
2642 | 2695 |
2643 Operator op = node.selector; | 2696 Operator op = node.selector; |
2644 if (const SourceString("[]") == op.source) { | 2697 if (const SourceString("[]") == op.source) { |
2645 HStatic target = new HStatic(interceptors.getIndexInterceptor()); | 2698 HStatic target = new HStatic(interceptors.getIndexInterceptor()); |
(...skipping 15 matching lines...) Expand all Loading... | |
2661 HInstruction expression = pop(); | 2714 HInstruction expression = pop(); |
2662 Node argument = node.arguments.head; | 2715 Node argument = node.arguments.head; |
2663 TypeAnnotation typeAnnotation = argument.asTypeAnnotation(); | 2716 TypeAnnotation typeAnnotation = argument.asTypeAnnotation(); |
2664 bool isNot = false; | 2717 bool isNot = false; |
2665 // TODO(ngeoffray): Duplicating pattern in resolver. We should | 2718 // TODO(ngeoffray): Duplicating pattern in resolver. We should |
2666 // add a new kind of node. | 2719 // add a new kind of node. |
2667 if (typeAnnotation == null) { | 2720 if (typeAnnotation == null) { |
2668 typeAnnotation = argument.asSend().receiver; | 2721 typeAnnotation = argument.asSend().receiver; |
2669 isNot = true; | 2722 isNot = true; |
2670 } | 2723 } |
2671 | |
2672 DartType type = elements.getType(typeAnnotation); | 2724 DartType type = elements.getType(typeAnnotation); |
2673 if (type.isMalformed) { | 2725 if (type.isMalformed) { |
2674 String reasons = fetchReasonsFromMalformedType(type); | 2726 String reasons = fetchReasonsFromMalformedType(type); |
2675 if (compiler.enableTypeAssertions) { | 2727 if (compiler.enableTypeAssertions) { |
2676 generateMalformedSubtypeError(node, expression, type, reasons); | 2728 generateMalformedSubtypeError(node, expression, type, reasons); |
2677 } else { | 2729 } else { |
2678 generateRuntimeError(node, '$type is malformed: $reasons'); | 2730 generateRuntimeError(node, '$type is malformed: $reasons'); |
2679 } | 2731 } |
2680 return; | 2732 return; |
2681 } | 2733 } |
2682 HInstruction typeInfo = null; | 2734 if (type.element.isTypeVariable()) { |
2683 if (RuntimeTypeInformation.hasTypeArguments(type)) { | 2735 // TODO(karlklose): remove this check when the backend can deal with |
2684 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), expression); | 2736 // checks of the form [:o is T:] where [:T:] is a type variable. |
2685 typeInfo = pop(); | 2737 stack.add(graph.addConstantBool(true, constantSystem)); |
2738 return; | |
2686 } | 2739 } |
2687 if (type.element.isTypeVariable()) { | 2740 |
2688 // TODO(karlklose): We currently answer true to any is check | 2741 HInstruction instruction; |
2689 // involving a type variable -- both is T and is !T -- until | 2742 if (RuntimeTypeInformation.hasTypeArguments(type) || |
2690 // we have a proper implementation of reified generics. | 2743 type.element.isTypeVariable()) { |
ngeoffray
2012/12/06 23:21:45
I don't think this can happen (see line 2734 and 2
karlklose
2012/12/07 07:46:35
You are right, this is a left-over from trying to
| |
2691 stack.add(graph.addConstantBool(true, constantSystem)); | 2744 HInstruction typeInfo = getRuntimeTypeInfo(expression); |
2745 // TODO(karlklose): make isSubtype a HInstruction to enable | |
2746 // optimizations? | |
ngeoffray
2012/12/06 23:21:45
No, I think we need to put compiler flags on the m
karlklose
2012/12/07 07:46:35
I will remove the comment. Let's chat about dartbu
| |
2747 Element helper = compiler.findHelper(const SourceString('isSubtype')); | |
2748 HInstruction isSubtype = new HStatic(helper); | |
2749 add(isSubtype); | |
2750 // Build a list of representations for the type arguments. | |
2751 List<HInstruction> representations = | |
2752 buildTypeArgumentRepresentations(type); | |
2753 // For each type argument, build a call to isSubtype, with the type | |
2754 // argument as first and the representation of the tested type as | |
2755 // second argument. | |
2756 List<HInstruction> checks = <HInstruction>[]; | |
2757 int index = 0; | |
2758 representations.forEach((HInstruction representation) { | |
2759 HInstruction position = graph.addConstantInt(index, constantSystem); | |
2760 // Get the index'th type argument from the runtime type information. | |
2761 HInstruction typeArgument = | |
2762 createForeign('#[#]', 'Object', [typeInfo, position]); | |
2763 add(typeArgument); | |
2764 // Create the call to isSubtype. | |
2765 List<HInstruction> inputs = | |
2766 <HInstruction>[isSubtype, typeArgument, representation]; | |
2767 HInstruction call = new HInvokeStatic(inputs); | |
2768 add(call); | |
2769 checks.add(call); | |
2770 index++; | |
2771 }); | |
2772 instruction = new HIs.withArgumentChecks(type, expression, checks); | |
2692 } else { | 2773 } else { |
2693 HInstruction instruction; | 2774 instruction = new HIs(type, expression); |
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 } | 2775 } |
2776 if (isNot) { | |
2777 add(instruction); | |
2778 instruction = new HNot(instruction); | |
2779 } | |
2780 push(instruction); | |
2705 } else if (const SourceString("as") == op.source) { | 2781 } else if (const SourceString("as") == op.source) { |
2706 visit(node.receiver); | 2782 visit(node.receiver); |
2707 HInstruction expression = pop(); | 2783 HInstruction expression = pop(); |
2708 Node argument = node.arguments.head; | 2784 Node argument = node.arguments.head; |
2709 TypeAnnotation typeAnnotation = argument.asTypeAnnotation(); | 2785 TypeAnnotation typeAnnotation = argument.asTypeAnnotation(); |
2710 DartType type = elements.getType(typeAnnotation); | 2786 DartType type = elements.getType(typeAnnotation); |
2711 HInstruction converted = expression.convertType( | 2787 HInstruction converted = expression.convertType( |
2712 compiler, type, HTypeConversion.CAST_TYPE_CHECK); | 2788 compiler, type, HTypeConversion.CAST_TYPE_CHECK); |
2713 if (converted != expression) add(converted); | 2789 if (converted != expression) add(converted); |
2714 stack.add(converted); | 2790 stack.add(converted); |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3097 */ | 3173 */ |
3098 HInstruction analyzeTypeArgument(DartType argument, Node currentNode) { | 3174 HInstruction analyzeTypeArgument(DartType argument, Node currentNode) { |
3099 assert(invariant(currentNode, | 3175 assert(invariant(currentNode, |
3100 !compiler.enableTypeAssertions || !argument.isMalformed, | 3176 !compiler.enableTypeAssertions || !argument.isMalformed, |
3101 message: '$argument is malformed in checked mode')); | 3177 message: '$argument is malformed in checked mode')); |
3102 if (argument == compiler.types.dynamicType || argument.isMalformed) { | 3178 if (argument == compiler.types.dynamicType || argument.isMalformed) { |
3103 // Represent [dynamic] as [null]. | 3179 // Represent [dynamic] as [null]. |
3104 return graph.addConstantNull(constantSystem); | 3180 return graph.addConstantNull(constantSystem); |
3105 } | 3181 } |
3106 | 3182 |
3107 // These variables are shared between invocations of the helper methods. | 3183 // These variables are shared between invocations of the helper. |
3108 HInstruction typeInfo; | 3184 HInstruction typeInfo; |
3109 StringBuffer template = new StringBuffer(); | |
3110 List<HInstruction> inputs = <HInstruction>[]; | 3185 List<HInstruction> inputs = <HInstruction>[]; |
3111 | 3186 |
3112 /** | 3187 /** |
3113 * Helper to create an instruction that gets the value of a type variable. | 3188 * Helper to create an instruction that gets the value of a type variable. |
3114 */ | 3189 */ |
3115 void addTypeVariableReference(TypeVariableType type) { | 3190 void addTypeVariableReference(TypeVariableType type) { |
3116 Element member = work.element; | 3191 Element member = work.element; |
3117 if (member.enclosingElement.isClosure()) { | 3192 if (member.enclosingElement.isClosure()) { |
3118 ClosureClassElement closureClass = member.enclosingElement; | 3193 ClosureClassElement closureClass = member.enclosingElement; |
3119 member = closureClass.methodElement; | 3194 member = closureClass.methodElement; |
3120 member = member.getOutermostEnclosingMemberOrTopLevel(); | 3195 member = member.getOutermostEnclosingMemberOrTopLevel(); |
3121 } | 3196 } |
3122 if (member.isFactoryConstructor()) { | 3197 if (member.isFactoryConstructor()) { |
3123 // The type variable is stored in a parameter of the factory. | 3198 // The type variable is stored in a parameter of the factory. |
3124 inputs.add(localsHandler.readLocal(type.element)); | 3199 inputs.add(localsHandler.readLocal(type.element)); |
3125 } else if (member.isInstanceMember() | 3200 } else if (member.isInstanceMember() |
3126 || member.isGenerativeConstructor()) { | 3201 || member.isGenerativeConstructor()) { |
3127 // The type variable is stored in [this]. | 3202 // The type variable is stored in [this]. |
3128 if (typeInfo == null) { | 3203 if (typeInfo == null) { |
3129 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), | 3204 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), |
3130 localsHandler.readThis()); | 3205 localsHandler.readThis()); |
3131 typeInfo = pop(); | 3206 typeInfo = pop(); |
3132 } | 3207 } |
3133 int index = RuntimeTypeInformation.getTypeVariableIndex(type); | 3208 int index = RuntimeTypeInformation.getTypeVariableIndex(type); |
3134 HInstruction foreign = new HForeign( | 3209 HInstruction foreign = createForeign('#[$index]', 'String', |
3135 new LiteralDartString('#[$index]'), | 3210 <HInstruction>[typeInfo]); |
3136 new LiteralDartString('String'), | |
3137 <HInstruction>[typeInfo]); | |
3138 add(foreign); | 3211 add(foreign); |
3139 inputs.add(foreign); | 3212 inputs.add(foreign); |
3140 } else { | 3213 } else { |
3141 // TODO(ngeoffray): Match the VM behavior and throw an | 3214 // TODO(ngeoffray): Match the VM behavior and throw an |
3142 // exception at runtime. | 3215 // exception at runtime. |
3143 compiler.cancel('Unimplemented unresolved type variable', | 3216 compiler.cancel('Unimplemented unresolved type variable', |
3144 node: currentNode); | 3217 node: currentNode); |
3145 } | 3218 } |
3146 } | 3219 } |
3147 | 3220 |
3148 /** | 3221 String template = rti.getTypeRepresentation(argument, |
3149 * Helper to build an instruction that builds the string representation for | 3222 addTypeVariableReference); |
3150 * this type, where type variables are substituted by their runtime value. | 3223 HInstruction result = createForeign(template, 'String', 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); | 3224 add(result); |
3196 return result; | 3225 return result; |
3197 } | 3226 } |
3198 | 3227 |
3199 void handleListConstructor(InterfaceType type, | 3228 void handleListConstructor(InterfaceType type, |
3200 Node currentNode, | 3229 Node currentNode, |
3201 HInstruction newObject) { | 3230 HInstruction newObject) { |
3202 if (!compiler.world.needsRti(type.element)) return; | 3231 if (!compiler.world.needsRti(type.element)) return; |
3203 List<HInstruction> inputs = <HInstruction>[]; | 3232 List<HInstruction> inputs = <HInstruction>[]; |
3204 if (!type.isRaw) { | 3233 if (!type.isRaw) { |
(...skipping 1756 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4961 new HSubGraphBlockInformation(elseBranch.graph)); | 4990 new HSubGraphBlockInformation(elseBranch.graph)); |
4962 | 4991 |
4963 HBasicBlock conditionStartBlock = conditionBranch.block; | 4992 HBasicBlock conditionStartBlock = conditionBranch.block; |
4964 conditionStartBlock.setBlockFlow(info, joinBlock); | 4993 conditionStartBlock.setBlockFlow(info, joinBlock); |
4965 SubGraph conditionGraph = conditionBranch.graph; | 4994 SubGraph conditionGraph = conditionBranch.graph; |
4966 HIf branch = conditionGraph.end.last; | 4995 HIf branch = conditionGraph.end.last; |
4967 assert(branch is HIf); | 4996 assert(branch is HIf); |
4968 branch.blockInformation = conditionStartBlock.blockFlow; | 4997 branch.blockInformation = conditionStartBlock.blockFlow; |
4969 } | 4998 } |
4970 } | 4999 } |
OLD | NEW |