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) { | |
|
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 |