OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library dart2js.js_emitter.runtime_type_generator; | 5 library dart2js.js_emitter.runtime_type_generator; |
6 | 6 |
7 import '../closure.dart' | 7 import '../closure.dart' |
8 show ClosureRepresentationInfo, ClosureFieldElement, ClosureConversionTask; | 8 show ClosureRepresentationInfo, ClosureFieldElement, ClosureConversionTask; |
9 import '../common.dart'; | 9 import '../common.dart'; |
10 import '../common/names.dart' show Identifiers; | 10 import '../common/names.dart' show Identifiers; |
11 import '../common_elements.dart' show CommonElements, ElementEnvironment; | 11 import '../common_elements.dart' show CommonElements, ElementEnvironment; |
12 import '../elements/elements.dart' | 12 import '../elements/elements.dart' |
13 show ClassElement, MethodElement, MixinApplicationElement; | 13 show ClassElement, MethodElement, MixinApplicationElement; |
14 import '../elements/entities.dart'; | 14 import '../elements/entities.dart'; |
15 import '../elements/types.dart'; | 15 import '../elements/types.dart'; |
16 import '../js/js.dart' as jsAst; | 16 import '../js/js.dart' as jsAst; |
17 import '../js/js.dart' show js; | 17 import '../js/js.dart' show js; |
18 import '../js_backend/js_interop_analysis.dart'; | 18 import '../js_backend/js_interop_analysis.dart'; |
19 import '../js_backend/native_data.dart'; | 19 import '../js_backend/native_data.dart'; |
20 import '../js_backend/namer.dart' show Namer; | 20 import '../js_backend/namer.dart' show Namer; |
21 import '../js_backend/runtime_types.dart' | 21 import '../js_backend/runtime_types.dart' |
22 show | 22 show |
23 RuntimeTypesChecks, | 23 RuntimeTypesChecks, |
24 RuntimeTypesNeed, | 24 RuntimeTypesNeed, |
25 RuntimeTypesEncoder, | 25 RuntimeTypesEncoder, |
26 RuntimeTypesSubstitutions, | 26 RuntimeTypesSubstitutions, |
27 Substitution, | 27 Substitution, |
28 TypeCheck, | 28 TypeCheck, |
29 TypeChecks; | 29 TypeChecks; |
| 30 import '../js_emitter/sorter.dart'; |
30 import '../util/util.dart' show Setlet; | 31 import '../util/util.dart' show Setlet; |
31 import '../world.dart'; | 32 import '../world.dart'; |
32 | 33 |
33 import 'code_emitter_task.dart' show CodeEmitterTask; | 34 import 'code_emitter_task.dart' show CodeEmitterTask; |
34 import 'type_test_registry.dart' show TypeTestRegistry; | 35 import 'type_test_registry.dart' show TypeTestRegistry; |
35 | 36 |
36 // Function signatures used in the generation of runtime type information. | 37 // Function signatures used in the generation of runtime type information. |
37 typedef void FunctionTypeSignatureEmitter( | 38 typedef void FunctionTypeSignatureEmitter( |
38 FunctionEntity method, FunctionType methodType); | 39 FunctionEntity method, FunctionType methodType); |
39 | 40 |
40 typedef void SubstitutionEmitter(ClassEntity element, {bool emitNull}); | 41 typedef void SubstitutionEmitter(ClassEntity element, {bool emitNull}); |
41 | 42 |
| 43 class TypeTest { |
| 44 final jsAst.Name name; |
| 45 final jsAst.Node expression; |
| 46 |
| 47 TypeTest(this.name, this.expression); |
| 48 } |
| 49 |
| 50 class TypeTests { |
| 51 TypeTest isTest; |
| 52 TypeTest substitution; |
| 53 TypeTest signature; |
| 54 } |
| 55 |
42 class TypeTestProperties { | 56 class TypeTestProperties { |
43 /// The index of the function type into the metadata. | 57 /// The index of the function type into the metadata. |
44 /// | 58 /// |
45 /// If the class doesn't have a function type this field is `null`. | 59 /// If the class doesn't have a function type this field is `null`. |
46 /// | 60 /// |
47 /// If the is tests were generated with `storeFunctionTypeInMetadata` set to | 61 /// If the is tests were generated with `storeFunctionTypeInMetadata` set to |
48 /// `false`, this field is `null`, and the [properties] contain a property | 62 /// `false`, this field is `null`, and the [properties] contain a property |
49 /// that encodes the function type. | 63 /// that encodes the function type. |
50 jsAst.Expression functionTypeIndex; | 64 jsAst.Expression functionTypeIndex; |
51 | 65 |
52 /// The properties that must be installed on the prototype of the | 66 /// The properties that must be installed on the prototype of the |
53 /// JS constructor of the [ClassEntity] for which the is checks were | 67 /// JS constructor of the [ClassEntity] for which the is checks were |
54 /// generated. | 68 /// generated. |
55 final Map<jsAst.Name, jsAst.Node> properties = <jsAst.Name, jsAst.Node>{}; | 69 final Map<ClassEntity, TypeTests> _properties = <ClassEntity, TypeTests>{}; |
| 70 |
| 71 void addIsTest(ClassEntity cls, jsAst.Name name, jsAst.Node expression) { |
| 72 TypeTests typeTests = _properties.putIfAbsent(cls, () => new TypeTests()); |
| 73 typeTests.isTest = new TypeTest(name, expression); |
| 74 } |
| 75 |
| 76 void addSubstitution( |
| 77 ClassEntity cls, jsAst.Name name, jsAst.Node expression) { |
| 78 TypeTests typeTests = _properties.putIfAbsent(cls, () => new TypeTests()); |
| 79 typeTests.substitution = new TypeTest(name, expression); |
| 80 } |
| 81 |
| 82 void addSignature(ClassEntity cls, jsAst.Name name, jsAst.Node expression) { |
| 83 TypeTests typeTests = _properties.putIfAbsent(cls, () => new TypeTests()); |
| 84 typeTests.signature = new TypeTest(name, expression); |
| 85 } |
| 86 |
| 87 void forEachProperty( |
| 88 Sorter sorter, void f(jsAst.Name name, jsAst.Node expression)) { |
| 89 void handleTypeTest(TypeTest typeTest) { |
| 90 if (typeTest == null) return; |
| 91 f(typeTest.name, typeTest.expression); |
| 92 } |
| 93 |
| 94 for (ClassEntity cls in sorter.sortClasses(_properties.keys)) { |
| 95 TypeTests typeTests = _properties[cls]; |
| 96 handleTypeTest(typeTests.isTest); |
| 97 handleTypeTest(typeTests.substitution); |
| 98 handleTypeTest(typeTests.signature); |
| 99 } |
| 100 } |
56 } | 101 } |
57 | 102 |
58 class RuntimeTypeGenerator { | 103 class RuntimeTypeGenerator { |
59 final ElementEnvironment _elementEnvironment; | 104 final ElementEnvironment _elementEnvironment; |
60 final CommonElements _commonElements; | 105 final CommonElements _commonElements; |
61 final DartTypes _types; | 106 final DartTypes _types; |
62 final ClosedWorld _closedWorld; | 107 final ClosedWorld _closedWorld; |
63 final ClosureConversionTask _closureDataLookup; | 108 final ClosureConversionTask _closureDataLookup; |
64 final CodeEmitterTask emitterTask; | 109 final CodeEmitterTask emitterTask; |
65 final Namer _namer; | 110 final Namer _namer; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 failedAt(classElement)); | 158 failedAt(classElement)); |
114 | 159 |
115 /// Generates an is-test if the test is not inherited from a superclass | 160 /// Generates an is-test if the test is not inherited from a superclass |
116 /// This assumes that for every class an is-tests is generated | 161 /// This assumes that for every class an is-tests is generated |
117 /// dynamically at runtime. We also always generate tests against | 162 /// dynamically at runtime. We also always generate tests against |
118 /// native classes. | 163 /// native classes. |
119 /// TODO(herhut): Generate tests for native classes dynamically, as well. | 164 /// TODO(herhut): Generate tests for native classes dynamically, as well. |
120 void generateIsTest(ClassEntity other) { | 165 void generateIsTest(ClassEntity other) { |
121 if (_nativeData.isNativeClass(classElement) || | 166 if (_nativeData.isNativeClass(classElement) || |
122 !_closedWorld.isSubclassOf(classElement, other)) { | 167 !_closedWorld.isSubclassOf(classElement, other)) { |
123 result.properties[_namer.operatorIs(other)] = js('1'); | 168 result.addIsTest(other, _namer.operatorIs(other), js('1')); |
124 } | 169 } |
125 } | 170 } |
126 | 171 |
127 void generateFunctionTypeSignature( | 172 void generateFunctionTypeSignature( |
128 FunctionEntity method, FunctionType type) { | 173 FunctionEntity method, FunctionType type) { |
129 assert(!(method is MethodElement && !method.isImplementation)); | 174 assert(!(method is MethodElement && !method.isImplementation)); |
130 jsAst.Expression thisAccess = new jsAst.This(); | 175 jsAst.Expression thisAccess = new jsAst.This(); |
131 if (!method.isAbstract) { | 176 if (!method.isAbstract) { |
132 ClosureRepresentationInfo closureData = | 177 ClosureRepresentationInfo closureData = |
133 _closureDataLookup.getClosureRepresentationInfo(method); | 178 _closureDataLookup.getClosureRepresentationInfo(method); |
134 if (closureData != null) { | 179 if (closureData != null) { |
135 ClosureFieldElement thisLocal = closureData.thisFieldEntity; | 180 ClosureFieldElement thisLocal = closureData.thisFieldEntity; |
136 if (thisLocal != null) { | 181 if (thisLocal != null) { |
137 jsAst.Name thisName = _namer.instanceFieldPropertyName(thisLocal); | 182 jsAst.Name thisName = _namer.instanceFieldPropertyName(thisLocal); |
138 thisAccess = js('this.#', thisName); | 183 thisAccess = js('this.#', thisName); |
139 } | 184 } |
140 } | 185 } |
141 } | 186 } |
142 | 187 |
143 if (storeFunctionTypeInMetadata && !type.containsTypeVariables) { | 188 if (storeFunctionTypeInMetadata && !type.containsTypeVariables) { |
144 result.functionTypeIndex = | 189 result.functionTypeIndex = |
145 emitterTask.metadataCollector.reifyType(type); | 190 emitterTask.metadataCollector.reifyType(type); |
146 } else { | 191 } else { |
147 jsAst.Expression encoding = _rtiEncoder.getSignatureEncoding( | 192 jsAst.Expression encoding = _rtiEncoder.getSignatureEncoding( |
148 emitterTask.emitter, type, thisAccess); | 193 emitterTask.emitter, type, thisAccess); |
149 jsAst.Name operatorSignature = _namer.asName(_namer.operatorSignature); | 194 jsAst.Name operatorSignature = _namer.asName(_namer.operatorSignature); |
150 result.properties[operatorSignature] = encoding; | 195 result.addSignature(classElement, operatorSignature, encoding); |
151 } | 196 } |
152 } | 197 } |
153 | 198 |
154 void generateSubstitution(ClassEntity cls, {bool emitNull: false}) { | 199 void generateSubstitution(ClassEntity cls, {bool emitNull: false}) { |
155 if (!_elementEnvironment.isGenericClass(cls)) return; | 200 if (!_elementEnvironment.isGenericClass(cls)) return; |
156 jsAst.Expression expression; | 201 jsAst.Expression expression; |
157 bool needsNativeCheck = | 202 bool needsNativeCheck = |
158 emitterTask.nativeEmitter.requiresNativeIsCheck(cls); | 203 emitterTask.nativeEmitter.requiresNativeIsCheck(cls); |
159 Substitution substitution = | 204 Substitution substitution = |
160 _rtiSubstitutions.getSubstitution(classElement, cls); | 205 _rtiSubstitutions.getSubstitution(classElement, cls); |
161 if (substitution != null) { | 206 if (substitution != null) { |
162 expression = | 207 expression = |
163 _rtiEncoder.getSubstitutionCode(emitterTask.emitter, substitution); | 208 _rtiEncoder.getSubstitutionCode(emitterTask.emitter, substitution); |
164 } | 209 } |
165 if (expression == null && (emitNull || needsNativeCheck)) { | 210 if (expression == null && (emitNull || needsNativeCheck)) { |
166 expression = new jsAst.LiteralNull(); | 211 expression = new jsAst.LiteralNull(); |
167 } | 212 } |
168 if (expression != null) { | 213 if (expression != null) { |
169 result.properties[_namer.substitutionName(cls)] = expression; | 214 result.addSubstitution(cls, _namer.substitutionName(cls), expression); |
170 } | 215 } |
171 } | 216 } |
172 | 217 |
173 void generateTypeCheck(TypeCheck check) { | 218 void generateTypeCheck(TypeCheck check) { |
174 ClassEntity checkedClass = check.cls; | 219 ClassEntity checkedClass = check.cls; |
175 generateIsTest(checkedClass); | 220 generateIsTest(checkedClass); |
176 Substitution substitution = check.substitution; | 221 Substitution substitution = check.substitution; |
177 if (substitution != null) { | 222 if (substitution != null) { |
178 jsAst.Expression body = | 223 jsAst.Expression body = |
179 _rtiEncoder.getSubstitutionCode(emitterTask.emitter, substitution); | 224 _rtiEncoder.getSubstitutionCode(emitterTask.emitter, substitution); |
180 result.properties[_namer.substitutionName(checkedClass)] = body; | 225 result.addSubstitution( |
| 226 checkedClass, _namer.substitutionName(checkedClass), body); |
181 } | 227 } |
182 } | 228 } |
183 | 229 |
184 _generateIsTestsOn( | 230 _generateIsTestsOn( |
185 classElement, | 231 classElement, |
186 generateIsTest, | 232 generateIsTest, |
187 generateFunctionTypeSignature, | 233 generateFunctionTypeSignature, |
188 (ClassEntity e, {bool emitNull: false}) => | 234 (ClassEntity e, {bool emitNull: false}) => |
189 generateSubstitution(e, emitNull: emitNull), | 235 generateSubstitution(e, emitNull: emitNull), |
190 generateTypeCheck); | 236 generateTypeCheck); |
191 | 237 |
192 if (classElement == _commonElements.jsJavaScriptFunctionClass) { | 238 if (classElement == _commonElements.jsJavaScriptFunctionClass) { |
193 var type = _jsInteropAnalysis.buildJsFunctionType(); | 239 var type = _jsInteropAnalysis.buildJsFunctionType(); |
194 if (type != null) { | 240 if (type != null) { |
195 jsAst.Expression thisAccess = new jsAst.This(); | 241 jsAst.Expression thisAccess = new jsAst.This(); |
196 jsAst.Expression encoding = _rtiEncoder.getSignatureEncoding( | 242 jsAst.Expression encoding = _rtiEncoder.getSignatureEncoding( |
197 emitterTask.emitter, type, thisAccess); | 243 emitterTask.emitter, type, thisAccess); |
198 jsAst.Name operatorSignature = _namer.asName(_namer.operatorSignature); | 244 jsAst.Name operatorSignature = _namer.asName(_namer.operatorSignature); |
199 result.properties[operatorSignature] = encoding; | 245 result.addSignature(classElement, operatorSignature, encoding); |
200 } | 246 } |
201 } | 247 } |
202 return result; | 248 return result; |
203 } | 249 } |
204 | 250 |
205 /** | 251 /** |
206 * Generate "is tests" for [cls] itself, and the "is tests" for the | 252 * Generate "is tests" for [cls] itself, and the "is tests" for the |
207 * classes it implements and type argument substitution functions for these | 253 * classes it implements and type argument substitution functions for these |
208 * tests. We don't need to add the "is tests" of the super class because | 254 * tests. We don't need to add the "is tests" of the super class because |
209 * they will be inherited at runtime, but we may need to generate the | 255 * they will be inherited at runtime, but we may need to generate the |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
343 | 389 |
344 // We need to also emit "is checks" for the superclass and its supertypes. | 390 // We need to also emit "is checks" for the superclass and its supertypes. |
345 ClassEntity superclass = _elementEnvironment.getSuperClass(cls); | 391 ClassEntity superclass = _elementEnvironment.getSuperClass(cls); |
346 if (superclass != null) { | 392 if (superclass != null) { |
347 tryEmitTest(superclass); | 393 tryEmitTest(superclass); |
348 _generateInterfacesIsTests( | 394 _generateInterfacesIsTests( |
349 superclass, generateIsTest, generateSubstitution, alreadyGenerated); | 395 superclass, generateIsTest, generateSubstitution, alreadyGenerated); |
350 } | 396 } |
351 } | 397 } |
352 } | 398 } |
OLD | NEW |