| 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 2504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2515 bool isNot = false; | 2515 bool isNot = false; |
| 2516 // TODO(ngeoffray): Duplicating pattern in resolver. We should | 2516 // TODO(ngeoffray): Duplicating pattern in resolver. We should |
| 2517 // add a new kind of node. | 2517 // add a new kind of node. |
| 2518 if (typeAnnotation == null) { | 2518 if (typeAnnotation == null) { |
| 2519 typeAnnotation = argument.asSend().receiver; | 2519 typeAnnotation = argument.asSend().receiver; |
| 2520 isNot = true; | 2520 isNot = true; |
| 2521 } | 2521 } |
| 2522 | 2522 |
| 2523 DartType type = elements.getType(typeAnnotation); | 2523 DartType type = elements.getType(typeAnnotation); |
| 2524 HInstruction typeInfo = null; | 2524 HInstruction typeInfo = null; |
| 2525 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { | 2525 if (RuntimeTypeInformation.hasTypeArguments(type)) { |
| 2526 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), expression); | 2526 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), expression); |
| 2527 typeInfo = pop(); | 2527 typeInfo = pop(); |
| 2528 } | 2528 } |
| 2529 if (type.element.isTypeVariable()) { | 2529 if (type.element.isTypeVariable()) { |
| 2530 // TODO(karlklose): We currently answer true to any is check | 2530 // TODO(karlklose): We currently answer true to any is check |
| 2531 // involving a type variable -- both is T and is !T -- until | 2531 // involving a type variable -- both is T and is !T -- until |
| 2532 // we have a proper implementation of reified generics. | 2532 // we have a proper implementation of reified generics. |
| 2533 stack.add(graph.addConstantBool(true, constantSystem)); | 2533 stack.add(graph.addConstantBool(true, constantSystem)); |
| 2534 } else { | 2534 } else { |
| 2535 HInstruction instruction; | 2535 HInstruction instruction; |
| (...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2985 // The type variable is stored in a parameter of the factory. | 2985 // The type variable is stored in a parameter of the factory. |
| 2986 inputs.add(localsHandler.readLocal(type.element)); | 2986 inputs.add(localsHandler.readLocal(type.element)); |
| 2987 } else if (member.isInstanceMember() | 2987 } else if (member.isInstanceMember() |
| 2988 || member.isGenerativeConstructor()) { | 2988 || member.isGenerativeConstructor()) { |
| 2989 // The type variable is stored in [this]. | 2989 // The type variable is stored in [this]. |
| 2990 if (typeInfo == null) { | 2990 if (typeInfo == null) { |
| 2991 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), | 2991 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), |
| 2992 localsHandler.readThis()); | 2992 localsHandler.readThis()); |
| 2993 typeInfo = pop(); | 2993 typeInfo = pop(); |
| 2994 } | 2994 } |
| 2995 int index = RuntimeTypeInformation.getTypeVariableIndex(type); |
| 2995 HInstruction foreign = new HForeign( | 2996 HInstruction foreign = new HForeign( |
| 2996 new LiteralDartString('#.${type.name.slowToString()}'), | 2997 new LiteralDartString('#[$index]'), |
| 2997 new LiteralDartString('String'), | 2998 new LiteralDartString('String'), |
| 2998 <HInstruction>[typeInfo]); | 2999 <HInstruction>[typeInfo]); |
| 2999 add(foreign); | 3000 add(foreign); |
| 3000 inputs.add(foreign); | 3001 inputs.add(foreign); |
| 3001 } else { | 3002 } else { |
| 3002 // TODO(ngeoffray): Match the VM behavior and throw an | 3003 // TODO(ngeoffray): Match the VM behavior and throw an |
| 3003 // exception at runtime. | 3004 // exception at runtime. |
| 3004 compiler.cancel('Unimplemented unresolved type variable', | 3005 compiler.cancel('Unimplemented unresolved type variable', |
| 3005 node: currentNode); | 3006 node: currentNode); |
| 3006 } | 3007 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3019 */ | 3020 */ |
| 3020 void buildTypeString(DartType type, {isInQuotes: false}) { | 3021 void buildTypeString(DartType type, {isInQuotes: false}) { |
| 3021 if (type is TypeVariableType) { | 3022 if (type is TypeVariableType) { |
| 3022 addTypeVariableReference(type); | 3023 addTypeVariableReference(type); |
| 3023 template.add(isInQuotes ? "' + # +'" : "#"); | 3024 template.add(isInQuotes ? "' + # +'" : "#"); |
| 3024 } else if (type is InterfaceType) { | 3025 } else if (type is InterfaceType) { |
| 3025 bool isFirstVariable = true; | 3026 bool isFirstVariable = true; |
| 3026 InterfaceType interfaceType = type; | 3027 InterfaceType interfaceType = type; |
| 3027 bool hasTypeArguments = !interfaceType.arguments.isEmpty; | 3028 bool hasTypeArguments = !interfaceType.arguments.isEmpty; |
| 3028 if (!isInQuotes) template.add("'"); | 3029 if (!isInQuotes) template.add("'"); |
| 3029 template.add(rti.getName(type.element)); | 3030 template.add(backend.namer.getName(type.element, |
| 3031 allowUnsafeName: true)); |
| 3030 if (hasTypeArguments) { | 3032 if (hasTypeArguments) { |
| 3031 template.add("<"); | 3033 template.add("<"); |
| 3032 for (DartType argument in interfaceType.arguments) { | 3034 for (DartType argument in interfaceType.arguments) { |
| 3033 if (!isFirstVariable) { | 3035 if (!isFirstVariable) { |
| 3034 template.add(", "); | 3036 template.add(", "); |
| 3035 } else { | 3037 } else { |
| 3036 isFirstVariable = false; | 3038 isFirstVariable = false; |
| 3037 } | 3039 } |
| 3038 buildTypeString(argument, isInQuotes: true); | 3040 buildTypeString(argument, isInQuotes: true); |
| 3039 } | 3041 } |
| 3040 template.add(">"); | 3042 template.add(">"); |
| 3041 } | 3043 } |
| 3042 if (!isInQuotes) template.add("'"); | 3044 if (!isInQuotes) template.add("'"); |
| 3043 } else { | 3045 } else { |
| 3044 assert(type is TypedefType); | 3046 assert(type is TypedefType); |
| 3045 if (!isInQuotes) template.add("'"); | 3047 if (!isInQuotes) template.add("'"); |
| 3046 template.add(rti.getName(argument.element)); | 3048 template.add(backend.namer.getName(argument.element, |
| 3049 allowUnsafeName: true)); |
| 3047 if (!isInQuotes) template.add("'"); | 3050 if (!isInQuotes) template.add("'"); |
| 3048 } | 3051 } |
| 3049 } | 3052 } |
| 3050 | 3053 |
| 3051 buildTypeString(argument, isInQuotes: false); | 3054 buildTypeString(argument, isInQuotes: false); |
| 3052 HInstruction result = | 3055 HInstruction result = |
| 3053 new HForeign(new LiteralDartString("$template"), | 3056 new HForeign(new LiteralDartString("$template"), |
| 3054 new LiteralDartString('String'), | 3057 new LiteralDartString('String'), |
| 3055 inputs); | 3058 inputs); |
| 3056 add(result); | 3059 add(result); |
| 3057 return result; | 3060 return result; |
| 3058 } | 3061 } |
| 3059 | 3062 |
| 3060 void handleListConstructor(InterfaceType type, | 3063 void handleListConstructor(InterfaceType type, |
| 3061 Node currentNode, | 3064 Node currentNode, |
| 3062 HInstruction newObject) { | 3065 HInstruction newObject) { |
| 3063 if (!compiler.world.needsRti(type.element)) return; | 3066 if (!compiler.world.needsRti(type.element)) return; |
| 3064 List<HInstruction> inputs = <HInstruction>[]; | 3067 List<HInstruction> inputs = <HInstruction>[]; |
| 3065 type.arguments.forEach((DartType argument) { | 3068 type.arguments.forEach((DartType argument) { |
| 3066 inputs.add(analyzeTypeArgument(argument, currentNode)); | 3069 inputs.add(analyzeTypeArgument(argument, currentNode)); |
| 3067 }); | 3070 }); |
| 3068 callSetRuntimeTypeInfo(type.element, inputs, newObject); | 3071 callSetRuntimeTypeInfo(type.element, inputs, newObject); |
| 3069 } | 3072 } |
| 3070 | 3073 |
| 3071 void callSetRuntimeTypeInfo(ClassElement element, | 3074 void callSetRuntimeTypeInfo(ClassElement element, |
| 3072 List<HInstruction> rtiInputs, | 3075 List<HInstruction> rtiInputs, |
| 3073 HInstruction newObject) { | 3076 HInstruction newObject) { |
| 3074 bool needsRti = compiler.world.needsRti(element) && !rtiInputs.isEmpty; | 3077 if (!compiler.world.needsRti(element) || element.typeVariables.isEmpty) { |
| 3075 bool runtimeTypeIsUsed = compiler.enabledRuntimeType; | 3078 return; |
| 3076 if (!needsRti && !runtimeTypeIsUsed) return; | |
| 3077 | |
| 3078 HInstruction createForeign(String template, | |
| 3079 List<HInstruction> arguments, | |
| 3080 [String type = 'String']) { | |
| 3081 return new HForeign(new LiteralDartString(template), | |
| 3082 new LiteralDartString(type), | |
| 3083 arguments); | |
| 3084 } | 3079 } |
| 3085 | 3080 |
| 3086 // Construct the runtime type information. | 3081 HInstruction typeInfo = new HLiteralList(rtiInputs); |
| 3087 StringBuffer runtimeCode = new StringBuffer(); | 3082 add(typeInfo); |
| 3088 List<HInstruction> runtimeCodeInputs = <HInstruction>[]; | |
| 3089 if (runtimeTypeIsUsed) { | |
| 3090 String runtimeTypeString = | |
| 3091 rti.generateRuntimeTypeString(element, rtiInputs.length); | |
| 3092 HInstruction runtimeType = createForeign(runtimeTypeString, rtiInputs); | |
| 3093 add(runtimeType); | |
| 3094 runtimeCodeInputs.add(runtimeType); | |
| 3095 runtimeCode.add("runtimeType: '#'"); | |
| 3096 } | |
| 3097 if (needsRti) { | |
| 3098 if (runtimeTypeIsUsed) runtimeCode.add(', '); | |
| 3099 String typeVariablesString = | |
| 3100 RuntimeTypeInformation.generateTypeVariableString(element, | |
| 3101 rtiInputs.length); | |
| 3102 HInstruction typeInfo = createForeign(typeVariablesString, rtiInputs); | |
| 3103 add(typeInfo); | |
| 3104 runtimeCodeInputs.add(typeInfo); | |
| 3105 runtimeCode.add('#'); | |
| 3106 } | |
| 3107 HInstruction runtimeInfo = | |
| 3108 createForeign("{$runtimeCode}", runtimeCodeInputs, 'Object'); | |
| 3109 add(runtimeInfo); | |
| 3110 | 3083 |
| 3111 // Set the runtime type information on the object. | 3084 // Set the runtime type information on the object. |
| 3112 Element typeInfoSetterElement = interceptors.getSetRuntimeTypeInfo(); | 3085 Element typeInfoSetterElement = interceptors.getSetRuntimeTypeInfo(); |
| 3113 HInstruction typeInfoSetter = new HStatic(typeInfoSetterElement); | 3086 HInstruction typeInfoSetter = new HStatic(typeInfoSetterElement); |
| 3114 add(typeInfoSetter); | 3087 add(typeInfoSetter); |
| 3115 add(new HInvokeStatic( | 3088 add(new HInvokeStatic( |
| 3116 <HInstruction>[typeInfoSetter, newObject, runtimeInfo])); | 3089 <HInstruction>[typeInfoSetter, newObject, typeInfo])); |
| 3117 } | 3090 } |
| 3118 | 3091 |
| 3119 visitNewSend(Send node, InterfaceType type) { | 3092 visitNewSend(Send node, InterfaceType type) { |
| 3120 bool isListConstructor = false; | 3093 bool isListConstructor = false; |
| 3121 computeType(element) { | 3094 computeType(element) { |
| 3122 Element originalElement = elements[node]; | 3095 Element originalElement = elements[node]; |
| 3123 if (identical(originalElement.getEnclosingClass(), compiler.listClass)) { | 3096 if (identical(originalElement.getEnclosingClass(), compiler.listClass)) { |
| 3124 isListConstructor = true; | 3097 isListConstructor = true; |
| 3125 if (node.arguments.isEmpty) { | 3098 if (node.arguments.isEmpty) { |
| 3126 return HType.EXTENDABLE_ARRAY; | 3099 return HType.EXTENDABLE_ARRAY; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3161 if (constructor.getEnclosingClass().isAbstract(compiler) && | 3134 if (constructor.getEnclosingClass().isAbstract(compiler) && |
| 3162 constructor.isGenerativeConstructor()) { | 3135 constructor.isGenerativeConstructor()) { |
| 3163 generateAbstractClassInstantiationError(node, type.name.slowToString()); | 3136 generateAbstractClassInstantiationError(node, type.name.slowToString()); |
| 3164 return; | 3137 return; |
| 3165 } | 3138 } |
| 3166 if (compiler.world.needsRti(constructor.enclosingElement)) { | 3139 if (compiler.world.needsRti(constructor.enclosingElement)) { |
| 3167 if (!type.arguments.isEmpty) { | 3140 if (!type.arguments.isEmpty) { |
| 3168 type.arguments.forEach((DartType argument) { | 3141 type.arguments.forEach((DartType argument) { |
| 3169 inputs.add(analyzeTypeArgument(argument, node)); | 3142 inputs.add(analyzeTypeArgument(argument, node)); |
| 3170 }); | 3143 }); |
| 3171 } else if (compiler.enabledRuntimeType) { | |
| 3172 Link<DartType> variables = | |
| 3173 constructor.getEnclosingClass().typeVariables; | |
| 3174 if (!variables.isEmpty) { | |
| 3175 // If the class has type variables but no type arguments have been | |
| 3176 // provided, add [:dynamic:] as argument for all type variables. | |
| 3177 DartString stringDynamic = new DartString.literal('dynamic'); | |
| 3178 HInstruction input = graph.addConstantString(stringDynamic, | |
| 3179 node, | |
| 3180 constantSystem); | |
| 3181 variables.forEach((_) => inputs.add(input)); | |
| 3182 } | |
| 3183 } | 3144 } |
| 3184 } | 3145 } |
| 3185 | 3146 |
| 3186 HType elementType = computeType(constructor); | 3147 HType elementType = computeType(constructor); |
| 3187 HInstruction newInstance = new HInvokeStatic(inputs, elementType); | 3148 HInstruction newInstance = new HInvokeStatic(inputs, elementType); |
| 3188 pushWithPosition(newInstance, node); | 3149 pushWithPosition(newInstance, node); |
| 3189 | 3150 |
| 3190 // The List constructor forwards to a Dart static method that does | 3151 // The List constructor forwards to a Dart static method that does |
| 3191 // not know about the type argument. Therefore we special case | 3152 // not know about the type argument. Therefore we special case |
| 3192 // this constructor to have the setRuntimeTypeInfo called where | 3153 // this constructor to have the setRuntimeTypeInfo called where |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3257 Constant constant = constantSystem.createString(dartString, node); | 3218 Constant constant = constantSystem.createString(dartString, node); |
| 3258 return graph.addConstant(constant); | 3219 return graph.addConstant(constant); |
| 3259 } | 3220 } |
| 3260 | 3221 |
| 3261 visitTypeReferenceSend(Send node) { | 3222 visitTypeReferenceSend(Send node) { |
| 3262 Element element = elements[node]; | 3223 Element element = elements[node]; |
| 3263 HInstruction name; | 3224 HInstruction name; |
| 3264 Element helper = | 3225 Element helper = |
| 3265 compiler.findHelper(const SourceString('createRuntimeType')); | 3226 compiler.findHelper(const SourceString('createRuntimeType')); |
| 3266 if (element.isClass()) { | 3227 if (element.isClass()) { |
| 3267 String string = rti.generateRuntimeTypeString(element, 0); | 3228 ClassElement classElement = element; |
| 3229 String string = backend.namer.getName(classElement, |
| 3230 allowUnsafeName: true); |
| 3231 if (!classElement.typeVariables.isEmpty) { |
| 3232 String arguments = |
| 3233 RuntimeTypeInformation.buildRawArguments(classElement); |
| 3234 string = "$string<$arguments>"; |
| 3235 } |
| 3268 name = addConstantString(node.selector, string); | 3236 name = addConstantString(node.selector, string); |
| 3269 } else if (element.isTypedef()) { | 3237 } else if (element.isTypedef()) { |
| 3270 // TODO(karlklose): implement support for type variables in typedefs. | 3238 // TODO(karlklose): implement support for type variables in typedefs. |
| 3271 name = addConstantString(node.selector, rti.getName(element)); | 3239 name = addConstantString(node.selector, backend.namer.getName(element)); |
| 3272 } else if (element.isTypeVariable()) { | 3240 } else if (element.isTypeVariable()) { |
| 3273 // TODO(6248): implement support for type variables. | 3241 // TODO(6248): implement support for type variables. |
| 3274 compiler.unimplemented('first class type for type variable', node: node); | 3242 compiler.unimplemented('first class type for type variable', node: node); |
| 3275 } else { | 3243 } else { |
| 3276 internalError('unexpected element $element', node: node); | 3244 internalError('unexpected element $element', node: node); |
| 3277 } | 3245 } |
| 3278 pushInvokeHelper1(helper, name); | 3246 pushInvokeHelper1(helper, name); |
| 3279 if (node.isCall) { | 3247 if (node.isCall) { |
| 3280 // This send is of the form 'e(...)', where e is resolved to a type | 3248 // This send is of the form 'e(...)', where e is resolved to a type |
| 3281 // reference. We create a regular closure call on the result of the type | 3249 // 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... |
| 4841 new HSubGraphBlockInformation(elseBranch.graph)); | 4809 new HSubGraphBlockInformation(elseBranch.graph)); |
| 4842 | 4810 |
| 4843 HBasicBlock conditionStartBlock = conditionBranch.block; | 4811 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 4844 conditionStartBlock.setBlockFlow(info, joinBlock); | 4812 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 4845 SubGraph conditionGraph = conditionBranch.graph; | 4813 SubGraph conditionGraph = conditionBranch.graph; |
| 4846 HIf branch = conditionGraph.end.last; | 4814 HIf branch = conditionGraph.end.last; |
| 4847 assert(branch is HIf); | 4815 assert(branch is HIf); |
| 4848 branch.blockInformation = conditionStartBlock.blockFlow; | 4816 branch.blockInformation = conditionStartBlock.blockFlow; |
| 4849 } | 4817 } |
| 4850 } | 4818 } |
| OLD | NEW |