| 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 class Interceptors { | 7 class Interceptors { |
| 8 Compiler compiler; | 8 Compiler compiler; |
| 9 Interceptors(Compiler this.compiler); | 9 Interceptors(Compiler this.compiler); |
| 10 | 10 |
| (...skipping 2477 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2488 bool isNot = false; | 2488 bool isNot = false; |
| 2489 // TODO(ngeoffray): Duplicating pattern in resolver. We should | 2489 // TODO(ngeoffray): Duplicating pattern in resolver. We should |
| 2490 // add a new kind of node. | 2490 // add a new kind of node. |
| 2491 if (typeAnnotation == null) { | 2491 if (typeAnnotation == null) { |
| 2492 typeAnnotation = argument.asSend().receiver; | 2492 typeAnnotation = argument.asSend().receiver; |
| 2493 isNot = true; | 2493 isNot = true; |
| 2494 } | 2494 } |
| 2495 | 2495 |
| 2496 DartType type = elements.getType(typeAnnotation); | 2496 DartType type = elements.getType(typeAnnotation); |
| 2497 HInstruction typeInfo = null; | 2497 HInstruction typeInfo = null; |
| 2498 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { | 2498 if (RuntimeTypeInformation.hasTypeArguments(type)) { |
| 2499 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), expression); | 2499 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), expression); |
| 2500 typeInfo = pop(); | 2500 typeInfo = pop(); |
| 2501 } | 2501 } |
| 2502 if (type.element.isTypeVariable()) { | 2502 if (type.element.isTypeVariable()) { |
| 2503 // TODO(karlklose): We currently answer true to any is check | 2503 // TODO(karlklose): We currently answer true to any is check |
| 2504 // involving a type variable -- both is T and is !T -- until | 2504 // involving a type variable -- both is T and is !T -- until |
| 2505 // we have a proper implementation of reified generics. | 2505 // we have a proper implementation of reified generics. |
| 2506 stack.add(graph.addConstantBool(true, constantSystem)); | 2506 stack.add(graph.addConstantBool(true, constantSystem)); |
| 2507 } else { | 2507 } else { |
| 2508 HInstruction instruction; | 2508 HInstruction instruction; |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2954 // The type variable is stored in a parameter of the factory. | 2954 // The type variable is stored in a parameter of the factory. |
| 2955 inputs.add(localsHandler.readLocal(type.element)); | 2955 inputs.add(localsHandler.readLocal(type.element)); |
| 2956 } else if (member.isInstanceMember() | 2956 } else if (member.isInstanceMember() |
| 2957 || member.isGenerativeConstructor()) { | 2957 || member.isGenerativeConstructor()) { |
| 2958 // The type variable is stored in [this]. | 2958 // The type variable is stored in [this]. |
| 2959 if (typeInfo == null) { | 2959 if (typeInfo == null) { |
| 2960 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), | 2960 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), |
| 2961 localsHandler.readThis()); | 2961 localsHandler.readThis()); |
| 2962 typeInfo = pop(); | 2962 typeInfo = pop(); |
| 2963 } | 2963 } |
| 2964 int index = RuntimeTypeInformation.getTypeVariableIndex(type); |
| 2964 HInstruction foreign = new HForeign( | 2965 HInstruction foreign = new HForeign( |
| 2965 new LiteralDartString('#.${type.name.slowToString()}'), | 2966 new LiteralDartString('#[$index]'), |
| 2966 new LiteralDartString('String'), | 2967 new LiteralDartString('String'), |
| 2967 <HInstruction>[typeInfo]); | 2968 <HInstruction>[typeInfo]); |
| 2968 add(foreign); | 2969 add(foreign); |
| 2969 inputs.add(foreign); | 2970 inputs.add(foreign); |
| 2970 } else { | 2971 } else { |
| 2971 // TODO(ngeoffray): Match the VM behavior and throw an | 2972 // TODO(ngeoffray): Match the VM behavior and throw an |
| 2972 // exception at runtime. | 2973 // exception at runtime. |
| 2973 compiler.cancel('Unimplemented unresolved type variable', | 2974 compiler.cancel('Unimplemented unresolved type variable', |
| 2974 node: currentNode); | 2975 node: currentNode); |
| 2975 } | 2976 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2988 */ | 2989 */ |
| 2989 void buildTypeString(DartType type, {isInQuotes: false}) { | 2990 void buildTypeString(DartType type, {isInQuotes: false}) { |
| 2990 if (type is TypeVariableType) { | 2991 if (type is TypeVariableType) { |
| 2991 addTypeVariableReference(type); | 2992 addTypeVariableReference(type); |
| 2992 template.add(isInQuotes ? "' + # +'" : "#"); | 2993 template.add(isInQuotes ? "' + # +'" : "#"); |
| 2993 } else if (type is InterfaceType) { | 2994 } else if (type is InterfaceType) { |
| 2994 bool isFirstVariable = true; | 2995 bool isFirstVariable = true; |
| 2995 InterfaceType interfaceType = type; | 2996 InterfaceType interfaceType = type; |
| 2996 bool hasTypeArguments = !interfaceType.arguments.isEmpty; | 2997 bool hasTypeArguments = !interfaceType.arguments.isEmpty; |
| 2997 if (!isInQuotes) template.add("'"); | 2998 if (!isInQuotes) template.add("'"); |
| 2998 template.add(rti.getName(type.element)); | 2999 template.add(backend.namer.getName(type.element, |
| 3000 allowUnsafeName: true)); |
| 2999 if (hasTypeArguments) { | 3001 if (hasTypeArguments) { |
| 3000 template.add("<"); | 3002 template.add("<"); |
| 3001 for (DartType argument in interfaceType.arguments) { | 3003 for (DartType argument in interfaceType.arguments) { |
| 3002 if (!isFirstVariable) { | 3004 if (!isFirstVariable) { |
| 3003 template.add(", "); | 3005 template.add(", "); |
| 3004 } else { | 3006 } else { |
| 3005 isFirstVariable = false; | 3007 isFirstVariable = false; |
| 3006 } | 3008 } |
| 3007 buildTypeString(argument, isInQuotes: true); | 3009 buildTypeString(argument, isInQuotes: true); |
| 3008 } | 3010 } |
| 3009 template.add(">"); | 3011 template.add(">"); |
| 3010 } | 3012 } |
| 3011 if (!isInQuotes) template.add("'"); | 3013 if (!isInQuotes) template.add("'"); |
| 3012 } else { | 3014 } else { |
| 3013 assert(type is TypedefType); | 3015 assert(type is TypedefType); |
| 3014 if (!isInQuotes) template.add("'"); | 3016 if (!isInQuotes) template.add("'"); |
| 3015 template.add(rti.getName(argument.element)); | 3017 template.add(backend.namer.getName(argument.element, |
| 3018 allowUnsafeName: true)); |
| 3016 if (!isInQuotes) template.add("'"); | 3019 if (!isInQuotes) template.add("'"); |
| 3017 } | 3020 } |
| 3018 } | 3021 } |
| 3019 | 3022 |
| 3020 buildTypeString(argument, isInQuotes: false); | 3023 buildTypeString(argument, isInQuotes: false); |
| 3021 HInstruction result = | 3024 HInstruction result = |
| 3022 new HForeign(new LiteralDartString("$template"), | 3025 new HForeign(new LiteralDartString("$template"), |
| 3023 new LiteralDartString('String'), | 3026 new LiteralDartString('String'), |
| 3024 inputs); | 3027 inputs); |
| 3025 add(result); | 3028 add(result); |
| 3026 return result; | 3029 return result; |
| 3027 } | 3030 } |
| 3028 | 3031 |
| 3029 void handleListConstructor(InterfaceType type, | 3032 void handleListConstructor(InterfaceType type, |
| 3030 Node currentNode, | 3033 Node currentNode, |
| 3031 HInstruction newObject) { | 3034 HInstruction newObject) { |
| 3032 if (!compiler.world.needsRti(type.element)) return; | 3035 if (!compiler.world.needsRti(type.element)) return; |
| 3033 List<HInstruction> inputs = <HInstruction>[]; | 3036 List<HInstruction> inputs = <HInstruction>[]; |
| 3034 type.arguments.forEach((DartType argument) { | 3037 type.arguments.forEach((DartType argument) { |
| 3035 inputs.add(analyzeTypeArgument(argument, currentNode)); | 3038 inputs.add(analyzeTypeArgument(argument, currentNode)); |
| 3036 }); | 3039 }); |
| 3037 callSetRuntimeTypeInfo(type.element, inputs, newObject); | 3040 callSetRuntimeTypeInfo(type.element, inputs, newObject); |
| 3038 } | 3041 } |
| 3039 | 3042 |
| 3040 void callSetRuntimeTypeInfo(ClassElement element, | 3043 void callSetRuntimeTypeInfo(ClassElement element, |
| 3041 List<HInstruction> rtiInputs, | 3044 List<HInstruction> rtiInputs, |
| 3042 HInstruction newObject) { | 3045 HInstruction newObject) { |
| 3043 bool needsRti = compiler.world.needsRti(element) && !rtiInputs.isEmpty; | 3046 if (!compiler.world.needsRti(element) || element.typeVariables.isEmpty) { |
| 3044 bool runtimeTypeIsUsed = compiler.enabledRuntimeType; | 3047 return; |
| 3045 if (!needsRti && !runtimeTypeIsUsed) return; | |
| 3046 | |
| 3047 HInstruction createForeign(String template, | |
| 3048 List<HInstruction> arguments, | |
| 3049 [String type = 'String']) { | |
| 3050 return new HForeign(new LiteralDartString(template), | |
| 3051 new LiteralDartString(type), | |
| 3052 arguments); | |
| 3053 } | 3048 } |
| 3054 | 3049 |
| 3055 // Construct the runtime type information. | 3050 HInstruction typeInfo = new HLiteralList(rtiInputs); |
| 3056 StringBuffer runtimeCode = new StringBuffer(); | 3051 add(typeInfo); |
| 3057 List<HInstruction> runtimeCodeInputs = <HInstruction>[]; | |
| 3058 if (runtimeTypeIsUsed) { | |
| 3059 String runtimeTypeString = | |
| 3060 rti.generateRuntimeTypeString(element, rtiInputs.length); | |
| 3061 HInstruction runtimeType = createForeign(runtimeTypeString, rtiInputs); | |
| 3062 add(runtimeType); | |
| 3063 runtimeCodeInputs.add(runtimeType); | |
| 3064 runtimeCode.add("runtimeType: '#'"); | |
| 3065 } | |
| 3066 if (needsRti) { | |
| 3067 if (runtimeTypeIsUsed) runtimeCode.add(', '); | |
| 3068 String typeVariablesString = | |
| 3069 RuntimeTypeInformation.generateTypeVariableString(element, | |
| 3070 rtiInputs.length); | |
| 3071 HInstruction typeInfo = createForeign(typeVariablesString, rtiInputs); | |
| 3072 add(typeInfo); | |
| 3073 runtimeCodeInputs.add(typeInfo); | |
| 3074 runtimeCode.add('#'); | |
| 3075 } | |
| 3076 HInstruction runtimeInfo = | |
| 3077 createForeign("{$runtimeCode}", runtimeCodeInputs, 'Object'); | |
| 3078 add(runtimeInfo); | |
| 3079 | 3052 |
| 3080 // Set the runtime type information on the object. | 3053 // Set the runtime type information on the object. |
| 3081 Element typeInfoSetterElement = interceptors.getSetRuntimeTypeInfo(); | 3054 Element typeInfoSetterElement = interceptors.getSetRuntimeTypeInfo(); |
| 3082 HInstruction typeInfoSetter = new HStatic(typeInfoSetterElement); | 3055 HInstruction typeInfoSetter = new HStatic(typeInfoSetterElement); |
| 3083 add(typeInfoSetter); | 3056 add(typeInfoSetter); |
| 3084 add(new HInvokeStatic( | 3057 add(new HInvokeStatic( |
| 3085 <HInstruction>[typeInfoSetter, newObject, runtimeInfo])); | 3058 <HInstruction>[typeInfoSetter, newObject, typeInfo])); |
| 3086 } | 3059 } |
| 3087 | 3060 |
| 3088 visitNewSend(Send node, InterfaceType type) { | 3061 visitNewSend(Send node, InterfaceType type) { |
| 3089 bool isListConstructor = false; | 3062 bool isListConstructor = false; |
| 3090 computeType(element) { | 3063 computeType(element) { |
| 3091 Element originalElement = elements[node]; | 3064 Element originalElement = elements[node]; |
| 3092 if (identical(originalElement.getEnclosingClass(), compiler.listClass)) { | 3065 if (identical(originalElement.getEnclosingClass(), compiler.listClass)) { |
| 3093 isListConstructor = true; | 3066 isListConstructor = true; |
| 3094 if (node.arguments.isEmpty) { | 3067 if (node.arguments.isEmpty) { |
| 3095 return HType.EXTENDABLE_ARRAY; | 3068 return HType.EXTENDABLE_ARRAY; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3130 if (type.element.modifiers.isAbstract() && | 3103 if (type.element.modifiers.isAbstract() && |
| 3131 constructor.isGenerativeConstructor()) { | 3104 constructor.isGenerativeConstructor()) { |
| 3132 generateAbstractClassInstantiationError(node, type.name.slowToString()); | 3105 generateAbstractClassInstantiationError(node, type.name.slowToString()); |
| 3133 return; | 3106 return; |
| 3134 } | 3107 } |
| 3135 if (compiler.world.needsRti(constructor.enclosingElement)) { | 3108 if (compiler.world.needsRti(constructor.enclosingElement)) { |
| 3136 if (!type.arguments.isEmpty) { | 3109 if (!type.arguments.isEmpty) { |
| 3137 type.arguments.forEach((DartType argument) { | 3110 type.arguments.forEach((DartType argument) { |
| 3138 inputs.add(analyzeTypeArgument(argument, node)); | 3111 inputs.add(analyzeTypeArgument(argument, node)); |
| 3139 }); | 3112 }); |
| 3140 } else if (compiler.enabledRuntimeType) { | |
| 3141 Link<DartType> variables = | |
| 3142 constructor.getEnclosingClass().typeVariables; | |
| 3143 if (!variables.isEmpty) { | |
| 3144 // If the class has type variables but no type arguments have been | |
| 3145 // provided, add [:dynamic:] as argument for all type variables. | |
| 3146 DartString stringDynamic = new DartString.literal('dynamic'); | |
| 3147 HInstruction input = graph.addConstantString(stringDynamic, | |
| 3148 node, | |
| 3149 constantSystem); | |
| 3150 variables.forEach((_) => inputs.add(input)); | |
| 3151 } | |
| 3152 } | 3113 } |
| 3153 } | 3114 } |
| 3154 | 3115 |
| 3155 HType elementType = computeType(constructor); | 3116 HType elementType = computeType(constructor); |
| 3156 HInstruction newInstance = new HInvokeStatic(inputs, elementType); | 3117 HInstruction newInstance = new HInvokeStatic(inputs, elementType); |
| 3157 pushWithPosition(newInstance, node); | 3118 pushWithPosition(newInstance, node); |
| 3158 | 3119 |
| 3159 // The List constructor forwards to a Dart static method that does | 3120 // The List constructor forwards to a Dart static method that does |
| 3160 // not know about the type argument. Therefore we special case | 3121 // not know about the type argument. Therefore we special case |
| 3161 // this constructor to have the setRuntimeTypeInfo called where | 3122 // this constructor to have the setRuntimeTypeInfo called where |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3226 Constant constant = constantSystem.createString(dartString, node); | 3187 Constant constant = constantSystem.createString(dartString, node); |
| 3227 return graph.addConstant(constant); | 3188 return graph.addConstant(constant); |
| 3228 } | 3189 } |
| 3229 | 3190 |
| 3230 visitTypeReferenceSend(Send node) { | 3191 visitTypeReferenceSend(Send node) { |
| 3231 Element element = elements[node]; | 3192 Element element = elements[node]; |
| 3232 HInstruction name; | 3193 HInstruction name; |
| 3233 Element helper = | 3194 Element helper = |
| 3234 compiler.findHelper(RuntimeTypeInformation.CACHE_HELPER_NAME); | 3195 compiler.findHelper(RuntimeTypeInformation.CACHE_HELPER_NAME); |
| 3235 if (element.isClass()) { | 3196 if (element.isClass()) { |
| 3236 String string = rti.generateRuntimeTypeString(element, 0); | 3197 ClassElement classElement = element; |
| 3198 String string = backend.namer.getName(classElement, |
| 3199 allowUnsafeName: true); |
| 3200 if (!classElement.typeVariables.isEmpty) { |
| 3201 String arguments = |
| 3202 RuntimeTypeInformation.buildRawArguments(classElement); |
| 3203 string = "$string<$arguments>"; |
| 3204 } |
| 3237 name = addConstantString(node.selector, string); | 3205 name = addConstantString(node.selector, string); |
| 3238 } else if (element.isTypedef()) { | 3206 } else if (element.isTypedef()) { |
| 3239 // TODO(karlklose): implement support for type variables in typedefs. | 3207 // TODO(karlklose): implement support for type variables in typedefs. |
| 3240 name = addConstantString(node.selector, rti.getName(element)); | 3208 name = addConstantString(node.selector, backend.namer.getName(element)); |
| 3241 } else if (element.isTypeVariable()) { | 3209 } else if (element.isTypeVariable()) { |
| 3242 // TODO(6248): implement support for type variables. | 3210 // TODO(6248): implement support for type variables. |
| 3243 compiler.unimplemented('first class type for type variable', node: node); | 3211 compiler.unimplemented('first class type for type variable', node: node); |
| 3244 } else { | 3212 } else { |
| 3245 internalError('unexpected element $element', node: node); | 3213 internalError('unexpected element $element', node: node); |
| 3246 } | 3214 } |
| 3247 pushInvokeHelper1(helper, name); | 3215 pushInvokeHelper1(helper, name); |
| 3248 if (node.isCall) { | 3216 if (node.isCall) { |
| 3249 // This send is of the form 'e(...)', where e is resolved to a type | 3217 // This send is of the form 'e(...)', where e is resolved to a type |
| 3250 // reference. We create a regular closure call on the result of the type | 3218 // reference. We create a regular closure call on the result of the type |
| (...skipping 1559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4810 new HSubGraphBlockInformation(elseBranch.graph)); | 4778 new HSubGraphBlockInformation(elseBranch.graph)); |
| 4811 | 4779 |
| 4812 HBasicBlock conditionStartBlock = conditionBranch.block; | 4780 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 4813 conditionStartBlock.setBlockFlow(info, joinBlock); | 4781 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 4814 SubGraph conditionGraph = conditionBranch.graph; | 4782 SubGraph conditionGraph = conditionBranch.graph; |
| 4815 HIf branch = conditionGraph.end.last; | 4783 HIf branch = conditionGraph.end.last; |
| 4816 assert(branch is HIf); | 4784 assert(branch is HIf); |
| 4817 branch.blockInformation = conditionStartBlock.blockFlow; | 4785 branch.blockInformation = conditionStartBlock.blockFlow; |
| 4818 } | 4786 } |
| 4819 } | 4787 } |
| OLD | NEW |