Chromium Code Reviews| 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 |