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 part of dart2js.js_emitter; | 5 part of dart2js.js_emitter; |
6 | 6 |
7 class InterceptorStubGenerator { | 7 class InterceptorStubGenerator { |
8 final Compiler compiler; | 8 final Compiler compiler; |
9 final Namer namer; | 9 final Namer namer; |
10 final JavaScriptBackend backend; | 10 final JavaScriptBackend backend; |
(...skipping 12 matching lines...) Expand all Loading... |
23 /** | 23 /** |
24 * Build a JavaScrit AST node for doing a type check on | 24 * Build a JavaScrit AST node for doing a type check on |
25 * [cls]. [cls] must be a non-native interceptor class. | 25 * [cls]. [cls] must be a non-native interceptor class. |
26 */ | 26 */ |
27 jsAst.Statement buildInterceptorCheck(ClassElement cls) { | 27 jsAst.Statement buildInterceptorCheck(ClassElement cls) { |
28 jsAst.Expression condition; | 28 jsAst.Expression condition; |
29 assert(backend.isInterceptorClass(cls)); | 29 assert(backend.isInterceptorClass(cls)); |
30 if (cls == helpers.jsBoolClass) { | 30 if (cls == helpers.jsBoolClass) { |
31 condition = js('(typeof receiver) == "boolean"'); | 31 condition = js('(typeof receiver) == "boolean"'); |
32 } else if (cls == helpers.jsIntClass || | 32 } else if (cls == helpers.jsIntClass || |
33 cls == helpers.jsDoubleClass || | 33 cls == helpers.jsDoubleClass || |
34 cls == helpers.jsNumberClass) { | 34 cls == helpers.jsNumberClass) { |
35 throw 'internal error'; | 35 throw 'internal error'; |
36 } else if (cls == helpers.jsArrayClass || | 36 } else if (cls == helpers.jsArrayClass || |
37 cls == helpers.jsMutableArrayClass || | 37 cls == helpers.jsMutableArrayClass || |
38 cls == helpers.jsFixedArrayClass || | 38 cls == helpers.jsFixedArrayClass || |
39 cls == helpers.jsExtendableArrayClass) { | 39 cls == helpers.jsExtendableArrayClass) { |
40 condition = js('receiver.constructor == Array'); | 40 condition = js('receiver.constructor == Array'); |
41 } else if (cls == helpers.jsStringClass) { | 41 } else if (cls == helpers.jsStringClass) { |
42 condition = js('(typeof receiver) == "string"'); | 42 condition = js('(typeof receiver) == "string"'); |
43 } else if (cls == helpers.jsNullClass) { | 43 } else if (cls == helpers.jsNullClass) { |
44 condition = js('receiver == null'); | 44 condition = js('receiver == null'); |
45 } else { | 45 } else { |
46 throw 'internal error'; | 46 throw 'internal error'; |
47 } | 47 } |
48 return js.statement('if (#) return #', [condition, interceptorFor(cls)]); | 48 return js.statement('if (#) return #', [condition, interceptorFor(cls)]); |
49 } | 49 } |
50 | 50 |
51 bool hasArray = false; | 51 bool hasArray = false; |
52 bool hasBool = false; | 52 bool hasBool = false; |
53 bool hasDouble = false; | 53 bool hasDouble = false; |
54 bool hasInt = false; | 54 bool hasInt = false; |
55 bool hasNull = false; | 55 bool hasNull = false; |
56 bool hasNumber = false; | 56 bool hasNumber = false; |
57 bool hasString = false; | 57 bool hasString = false; |
58 bool hasNative = false; | 58 bool hasNative = false; |
59 bool anyNativeClasses = compiler.enqueuer.codegen.nativeEnqueuer | 59 bool anyNativeClasses = |
60 .hasInstantiatedNativeClasses(); | 60 compiler.enqueuer.codegen.nativeEnqueuer.hasInstantiatedNativeClasses(); |
61 | 61 |
62 for (ClassElement cls in classes) { | 62 for (ClassElement cls in classes) { |
63 if (cls == helpers.jsArrayClass || | 63 if (cls == helpers.jsArrayClass || |
64 cls == helpers.jsMutableArrayClass || | 64 cls == helpers.jsMutableArrayClass || |
65 cls == helpers.jsFixedArrayClass || | 65 cls == helpers.jsFixedArrayClass || |
66 cls == helpers.jsExtendableArrayClass) hasArray = true; | 66 cls == helpers.jsExtendableArrayClass) |
67 else if (cls == helpers.jsBoolClass) hasBool = true; | 67 hasArray = true; |
68 else if (cls == helpers.jsDoubleClass) hasDouble = true; | 68 else if (cls == helpers.jsBoolClass) |
69 else if (cls == helpers.jsIntClass) hasInt = true; | 69 hasBool = true; |
70 else if (cls == helpers.jsNullClass) hasNull = true; | 70 else if (cls == helpers.jsDoubleClass) |
71 else if (cls == helpers.jsNumberClass) hasNumber = true; | 71 hasDouble = true; |
72 else if (cls == helpers.jsStringClass) hasString = true; | 72 else if (cls == helpers.jsIntClass) |
| 73 hasInt = true; |
| 74 else if (cls == helpers.jsNullClass) |
| 75 hasNull = true; |
| 76 else if (cls == helpers.jsNumberClass) |
| 77 hasNumber = true; |
| 78 else if (cls == helpers.jsStringClass) |
| 79 hasString = true; |
73 else { | 80 else { |
74 // The set of classes includes classes mixed-in to interceptor classes | 81 // The set of classes includes classes mixed-in to interceptor classes |
75 // and user extensions of native classes. | 82 // and user extensions of native classes. |
76 // | 83 // |
77 // The set of classes also includes the 'primitive' interceptor | 84 // The set of classes also includes the 'primitive' interceptor |
78 // PlainJavaScriptObject even when it has not been resolved, since it is | 85 // PlainJavaScriptObject even when it has not been resolved, since it is |
79 // only resolved through the reference in getNativeInterceptor when | 86 // only resolved through the reference in getNativeInterceptor when |
80 // getNativeInterceptor is marked as used. Guard against probing | 87 // getNativeInterceptor is marked as used. Guard against probing |
81 // unresolved PlainJavaScriptObject by testing for anyNativeClasses. | 88 // unresolved PlainJavaScriptObject by testing for anyNativeClasses. |
82 | 89 |
(...skipping 18 matching lines...) Expand all Loading... |
101 jsAst.Statement whenNumber; | 108 jsAst.Statement whenNumber; |
102 | 109 |
103 /// Note: there are two number classes in play: Dart's [num], | 110 /// Note: there are two number classes in play: Dart's [num], |
104 /// and JavaScript's Number (typeof receiver == 'number'). This | 111 /// and JavaScript's Number (typeof receiver == 'number'). This |
105 /// is the fallback used when we have determined that receiver | 112 /// is the fallback used when we have determined that receiver |
106 /// is a JavaScript Number. | 113 /// is a JavaScript Number. |
107 jsAst.Expression interceptorForNumber = interceptorFor( | 114 jsAst.Expression interceptorForNumber = interceptorFor( |
108 hasDouble ? helpers.jsDoubleClass : helpers.jsNumberClass); | 115 hasDouble ? helpers.jsDoubleClass : helpers.jsNumberClass); |
109 | 116 |
110 if (hasInt) { | 117 if (hasInt) { |
111 whenNumber = js.statement('''{ | 118 whenNumber = js.statement( |
| 119 '''{ |
112 if (Math.floor(receiver) == receiver) return #; | 120 if (Math.floor(receiver) == receiver) return #; |
113 return #; | 121 return #; |
114 }''', [interceptorFor(helpers.jsIntClass), interceptorForNumber]); | 122 }''', |
| 123 [interceptorFor(helpers.jsIntClass), interceptorForNumber]); |
115 } else { | 124 } else { |
116 whenNumber = js.statement('return #', interceptorForNumber); | 125 whenNumber = js.statement('return #', interceptorForNumber); |
117 } | 126 } |
118 statements.add( | 127 statements |
119 js.statement('if (typeof receiver == "number") #;', whenNumber)); | 128 .add(js.statement('if (typeof receiver == "number") #;', whenNumber)); |
120 } | 129 } |
121 | 130 |
122 if (hasString) { | 131 if (hasString) { |
123 statements.add(buildInterceptorCheck(helpers.jsStringClass)); | 132 statements.add(buildInterceptorCheck(helpers.jsStringClass)); |
124 } | 133 } |
125 if (hasNull) { | 134 if (hasNull) { |
126 statements.add(buildInterceptorCheck(helpers.jsNullClass)); | 135 statements.add(buildInterceptorCheck(helpers.jsNullClass)); |
127 } else { | 136 } else { |
128 // Returning "undefined" or "null" here will provoke a JavaScript | 137 // Returning "undefined" or "null" here will provoke a JavaScript |
129 // TypeError which is later identified as a null-error by | 138 // TypeError which is later identified as a null-error by |
130 // [unwrapException] in js_helper.dart. | 139 // [unwrapException] in js_helper.dart. |
131 statements.add( | 140 statements.add(js.statement('if (receiver == null) return receiver')); |
132 js.statement('if (receiver == null) return receiver')); | |
133 } | 141 } |
134 if (hasBool) { | 142 if (hasBool) { |
135 statements.add(buildInterceptorCheck(helpers.jsBoolClass)); | 143 statements.add(buildInterceptorCheck(helpers.jsBoolClass)); |
136 } | 144 } |
137 // TODO(ahe): It might be faster to check for Array before | 145 // TODO(ahe): It might be faster to check for Array before |
138 // function and bool. | 146 // function and bool. |
139 if (hasArray) { | 147 if (hasArray) { |
140 statements.add(buildInterceptorCheck(helpers.jsArrayClass)); | 148 statements.add(buildInterceptorCheck(helpers.jsArrayClass)); |
141 } | 149 } |
142 | 150 |
143 if (hasNative) { | 151 if (hasNative) { |
144 statements.add(js.statement(r'''{ | 152 statements.add(js.statement( |
| 153 r'''{ |
145 if (typeof receiver != "object") { | 154 if (typeof receiver != "object") { |
146 if (typeof receiver == "function" ) return #; | 155 if (typeof receiver == "function" ) return #; |
147 return receiver; | 156 return receiver; |
148 } | 157 } |
149 if (receiver instanceof #) return receiver; | 158 if (receiver instanceof #) return receiver; |
150 return #(receiver); | 159 return #(receiver); |
151 }''', [ | 160 }''', |
152 interceptorFor(helpers.jsJavaScriptFunctionClass), | 161 [ |
153 backend.emitter.constructorAccess(compiler.coreClasses.objectClass), | 162 interceptorFor(helpers.jsJavaScriptFunctionClass), |
154 backend.emitter | 163 backend.emitter.constructorAccess(compiler.coreClasses.objectClass), |
155 .staticFunctionAccess(helpers.getNativeInterceptorMethod)])); | 164 backend.emitter |
156 | 165 .staticFunctionAccess(helpers.getNativeInterceptorMethod) |
| 166 ])); |
157 } else { | 167 } else { |
158 ClassElement jsUnknown = helpers.jsUnknownJavaScriptObjectClass; | 168 ClassElement jsUnknown = helpers.jsUnknownJavaScriptObjectClass; |
159 if (compiler.codegenWorld | 169 if (compiler.codegenWorld.directlyInstantiatedClasses |
160 .directlyInstantiatedClasses.contains(jsUnknown)) { | 170 .contains(jsUnknown)) { |
161 statements.add( | 171 statements.add(js.statement('if (!(receiver instanceof #)) return #;', [ |
162 js.statement('if (!(receiver instanceof #)) return #;', | 172 backend.emitter.constructorAccess(compiler.coreClasses.objectClass), |
163 [backend.emitter.constructorAccess( | 173 interceptorFor(jsUnknown) |
164 compiler.coreClasses.objectClass), | 174 ])); |
165 interceptorFor(jsUnknown)])); | |
166 } | 175 } |
167 | 176 |
168 statements.add(js.statement('return receiver')); | 177 statements.add(js.statement('return receiver')); |
169 } | 178 } |
170 | 179 |
171 return js('''function(receiver) { #; }''', new jsAst.Block(statements)); | 180 return js('''function(receiver) { #; }''', new jsAst.Block(statements)); |
172 } | 181 } |
173 | 182 |
174 // Returns a statement that takes care of performance critical | 183 // Returns a statement that takes care of performance critical |
175 // common case for a one-shot interceptor, or null if there is no | 184 // common case for a one-shot interceptor, or null if there is no |
176 // fast path. | 185 // fast path. |
177 jsAst.Statement _fastPathForOneShotInterceptor(Selector selector, | 186 jsAst.Statement _fastPathForOneShotInterceptor( |
178 Set<ClassElement> classes) { | 187 Selector selector, Set<ClassElement> classes) { |
179 | |
180 if (selector.isOperator) { | 188 if (selector.isOperator) { |
181 String name = selector.name; | 189 String name = selector.name; |
182 if (name == '==') { | 190 if (name == '==') { |
183 return js.statement('''{ | 191 return js.statement('''{ |
184 if (receiver == null) return a0 == null; | 192 if (receiver == null) return a0 == null; |
185 if (typeof receiver != "object") | 193 if (typeof receiver != "object") |
186 return a0 != null && receiver === a0; | 194 return a0 != null && receiver === a0; |
187 }'''); | 195 }'''); |
188 } | 196 } |
189 if (!classes.contains(helpers.jsIntClass) | 197 if (!classes.contains(helpers.jsIntClass) && |
190 && !classes.contains(helpers.jsNumberClass) | 198 !classes.contains(helpers.jsNumberClass) && |
191 && !classes.contains(helpers.jsDoubleClass)) { | 199 !classes.contains(helpers.jsDoubleClass)) { |
192 return null; | 200 return null; |
193 } | 201 } |
194 if (selector.argumentCount == 1) { | 202 if (selector.argumentCount == 1) { |
195 // The following operators do not map to a JavaScript operator. | 203 // The following operators do not map to a JavaScript operator. |
196 if (name == '~/' || name == '<<' || name == '%' || name == '>>') { | 204 if (name == '~/' || name == '<<' || name == '%' || name == '>>') { |
197 return null; | 205 return null; |
198 } | 206 } |
199 jsAst.Expression result = js('receiver $name a0'); | 207 jsAst.Expression result = js('receiver $name a0'); |
200 if (name == '&' || name == '|' || name == '^') { | 208 if (name == '&' || name == '|' || name == '^') { |
201 result = js('# >>> 0', result); | 209 result = js('# >>> 0', result); |
202 } | 210 } |
203 return js.statement( | 211 return js.statement( |
204 'if (typeof receiver == "number" && typeof a0 == "number")' | 212 'if (typeof receiver == "number" && typeof a0 == "number")' |
205 ' return #;', | 213 ' return #;', |
206 result); | 214 result); |
207 } else if (name == 'unary-') { | 215 } else if (name == 'unary-') { |
208 return js.statement( | 216 return js |
209 'if (typeof receiver == "number") return -receiver'); | 217 .statement('if (typeof receiver == "number") return -receiver'); |
210 } else { | 218 } else { |
211 assert(name == '~'); | 219 assert(name == '~'); |
212 return js.statement(''' | 220 return js.statement(''' |
213 if (typeof receiver == "number" && Math.floor(receiver) == receiver) | 221 if (typeof receiver == "number" && Math.floor(receiver) == receiver) |
214 return (~receiver) >>> 0; | 222 return (~receiver) >>> 0; |
215 '''); | 223 '''); |
216 } | 224 } |
217 } else if (selector.isIndex || selector.isIndexSet) { | 225 } else if (selector.isIndex || selector.isIndexSet) { |
218 // For an index operation, this code generates: | 226 // For an index operation, this code generates: |
219 // | 227 // |
(...skipping 11 matching lines...) Expand all Loading... |
231 // if (typeof a0 === "number") { | 239 // if (typeof a0 === "number") { |
232 // if (receiver.constructor == Array && !receiver.immutable$list) { | 240 // if (receiver.constructor == Array && !receiver.immutable$list) { |
233 // if (a0 >>> 0 === a0 && a0 < receiver.length) { | 241 // if (a0 >>> 0 === a0 && a0 < receiver.length) { |
234 // return receiver[a0] = a1; | 242 // return receiver[a0] = a1; |
235 // } | 243 // } |
236 // } | 244 // } |
237 // } | 245 // } |
238 bool containsArray = classes.contains(helpers.jsArrayClass); | 246 bool containsArray = classes.contains(helpers.jsArrayClass); |
239 bool containsString = classes.contains(helpers.jsStringClass); | 247 bool containsString = classes.contains(helpers.jsStringClass); |
240 bool containsJsIndexable = | 248 bool containsJsIndexable = |
241 helpers.jsIndexingBehaviorInterface.isResolved && classes.any((cls) { | 249 helpers.jsIndexingBehaviorInterface.isResolved && |
242 return compiler.world.isSubtypeOf(cls, | 250 classes.any((cls) { |
243 helpers.jsIndexingBehaviorInterface); | 251 return compiler.world |
244 }); | 252 .isSubtypeOf(cls, helpers.jsIndexingBehaviorInterface); |
| 253 }); |
245 // The index set operator requires a check on its set value in | 254 // The index set operator requires a check on its set value in |
246 // checked mode, so we don't optimize the interceptor if the | 255 // checked mode, so we don't optimize the interceptor if the |
247 // compiler has type assertions enabled. | 256 // compiler has type assertions enabled. |
248 if (selector.isIndexSet | 257 if (selector.isIndexSet && |
249 && (compiler.options.enableTypeAssertions || !containsArray)) { | 258 (compiler.options.enableTypeAssertions || !containsArray)) { |
250 return null; | 259 return null; |
251 } | 260 } |
252 if (!containsArray && !containsString) { | 261 if (!containsArray && !containsString) { |
253 return null; | 262 return null; |
254 } | 263 } |
255 jsAst.Expression arrayCheck = js('receiver.constructor == Array'); | 264 jsAst.Expression arrayCheck = js('receiver.constructor == Array'); |
256 jsAst.Expression indexableCheck = | 265 jsAst.Expression indexableCheck = |
257 backend.generateIsJsIndexableCall(js('receiver'), js('receiver')); | 266 backend.generateIsJsIndexableCall(js('receiver'), js('receiver')); |
258 | 267 |
259 jsAst.Expression orExp(left, right) { | 268 jsAst.Expression orExp(left, right) { |
260 return left == null ? right : js('# || #', [left, right]); | 269 return left == null ? right : js('# || #', [left, right]); |
261 } | 270 } |
262 | 271 |
263 if (selector.isIndex) { | 272 if (selector.isIndex) { |
264 jsAst.Expression typeCheck; | 273 jsAst.Expression typeCheck; |
265 if (containsArray) { | 274 if (containsArray) { |
266 typeCheck = arrayCheck; | 275 typeCheck = arrayCheck; |
267 } | 276 } |
268 | 277 |
269 if (containsString) { | 278 if (containsString) { |
270 typeCheck = orExp(typeCheck, js('typeof receiver == "string"')); | 279 typeCheck = orExp(typeCheck, js('typeof receiver == "string"')); |
271 } | 280 } |
272 | 281 |
273 if (containsJsIndexable) { | 282 if (containsJsIndexable) { |
274 typeCheck = orExp(typeCheck, indexableCheck); | 283 typeCheck = orExp(typeCheck, indexableCheck); |
275 } | 284 } |
276 | 285 |
277 return js.statement(''' | 286 return js.statement( |
| 287 ''' |
278 if (typeof a0 === "number") | 288 if (typeof a0 === "number") |
279 if (#) | 289 if (#) |
280 if ((a0 >>> 0) === a0 && a0 < receiver.length) | 290 if ((a0 >>> 0) === a0 && a0 < receiver.length) |
281 return receiver[a0]; | 291 return receiver[a0]; |
282 ''', typeCheck); | 292 ''', |
| 293 typeCheck); |
283 } else { | 294 } else { |
284 jsAst.Expression typeCheck; | 295 jsAst.Expression typeCheck; |
285 if (containsArray) { | 296 if (containsArray) { |
286 typeCheck = arrayCheck; | 297 typeCheck = arrayCheck; |
287 } | 298 } |
288 | 299 |
289 if (containsJsIndexable) { | 300 if (containsJsIndexable) { |
290 typeCheck = orExp(typeCheck, indexableCheck); | 301 typeCheck = orExp(typeCheck, indexableCheck); |
291 } | 302 } |
292 | 303 |
293 return js.statement(r''' | 304 return js.statement( |
| 305 r''' |
294 if (typeof a0 === "number") | 306 if (typeof a0 === "number") |
295 if (# && !receiver.immutable$list && | 307 if (# && !receiver.immutable$list && |
296 (a0 >>> 0) === a0 && a0 < receiver.length) | 308 (a0 >>> 0) === a0 && a0 < receiver.length) |
297 return receiver[a0] = a1; | 309 return receiver[a0] = a1; |
298 ''', typeCheck); | 310 ''', |
| 311 typeCheck); |
299 } | 312 } |
300 } | 313 } |
301 return null; | 314 return null; |
302 } | 315 } |
303 | 316 |
304 jsAst.Expression generateOneShotInterceptor(jsAst.Name name) { | 317 jsAst.Expression generateOneShotInterceptor(jsAst.Name name) { |
305 Selector selector = backend.oneShotInterceptors[name]; | 318 Selector selector = backend.oneShotInterceptors[name]; |
306 Set<ClassElement> classes = | 319 Set<ClassElement> classes = backend.getInterceptedClassesOn(selector.name); |
307 backend.getInterceptedClassesOn(selector.name); | |
308 jsAst.Name getInterceptorName = namer.nameForGetInterceptor(classes); | 320 jsAst.Name getInterceptorName = namer.nameForGetInterceptor(classes); |
309 | 321 |
310 List<String> parameterNames = <String>[]; | 322 List<String> parameterNames = <String>[]; |
311 parameterNames.add('receiver'); | 323 parameterNames.add('receiver'); |
312 | 324 |
313 if (selector.isSetter) { | 325 if (selector.isSetter) { |
314 parameterNames.add('value'); | 326 parameterNames.add('value'); |
315 } else { | 327 } else { |
316 for (int i = 0; i < selector.argumentCount; i++) { | 328 for (int i = 0; i < selector.argumentCount; i++) { |
317 parameterNames.add('a$i'); | 329 parameterNames.add('a$i'); |
318 } | 330 } |
319 } | 331 } |
320 | 332 |
321 jsAst.Name invocationName = backend.namer.invocationName(selector); | 333 jsAst.Name invocationName = backend.namer.invocationName(selector); |
322 String globalObject = namer.globalObjectFor(helpers.interceptorsLibrary); | 334 String globalObject = namer.globalObjectFor(helpers.interceptorsLibrary); |
323 | 335 |
324 jsAst.Statement optimizedPath = | 336 jsAst.Statement optimizedPath = |
325 _fastPathForOneShotInterceptor(selector, classes); | 337 _fastPathForOneShotInterceptor(selector, classes); |
326 if (optimizedPath == null) optimizedPath = js.statement(';'); | 338 if (optimizedPath == null) optimizedPath = js.statement(';'); |
327 | 339 |
328 return js( | 340 return js('function(#) { #; return #.#(receiver).#(#) }', [ |
329 'function(#) { #; return #.#(receiver).#(#) }', | 341 parameterNames, |
330 [parameterNames, | 342 optimizedPath, |
331 optimizedPath, | 343 globalObject, |
332 globalObject, getInterceptorName, invocationName, parameterNames]); | 344 getInterceptorName, |
| 345 invocationName, |
| 346 parameterNames |
| 347 ]); |
333 } | 348 } |
334 | 349 |
335 jsAst.ArrayInitializer generateTypeToInterceptorMap() { | 350 jsAst.ArrayInitializer generateTypeToInterceptorMap() { |
336 // TODO(sra): Perhaps inject a constant instead? | 351 // TODO(sra): Perhaps inject a constant instead? |
337 CustomElementsAnalysis analysis = backend.customElementsAnalysis; | 352 CustomElementsAnalysis analysis = backend.customElementsAnalysis; |
338 if (!analysis.needsTable) return null; | 353 if (!analysis.needsTable) return null; |
339 | 354 |
340 List<jsAst.Expression> elements = <jsAst.Expression>[]; | 355 List<jsAst.Expression> elements = <jsAst.Expression>[]; |
341 JavaScriptConstantCompiler handler = backend.constants; | 356 JavaScriptConstantCompiler handler = backend.constants; |
342 List<ConstantValue> constants = | 357 List<ConstantValue> constants = |
(...skipping 19 matching lines...) Expand all Loading... |
362 // A.bar() {} | 377 // A.bar() {} |
363 // } | 378 // } |
364 // | 379 // |
365 // Which are described by the map | 380 // Which are described by the map |
366 // | 381 // |
367 // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar} | 382 // {"": A.A$, "foo": A.A$foo, "bar": A.A$bar} |
368 // | 383 // |
369 // We expect most of the time the map will be a singleton. | 384 // We expect most of the time the map will be a singleton. |
370 var properties = []; | 385 var properties = []; |
371 for (Element member in analysis.constructors(classElement)) { | 386 for (Element member in analysis.constructors(classElement)) { |
372 properties.add( | 387 properties.add(new jsAst.Property(js.string(member.name), |
373 new jsAst.Property( | 388 backend.emitter.staticFunctionAccess(member))); |
374 js.string(member.name), | |
375 backend.emitter.staticFunctionAccess(member))); | |
376 } | 389 } |
377 | 390 |
378 var map = new jsAst.ObjectInitializer(properties); | 391 var map = new jsAst.ObjectInitializer(properties); |
379 elements.add(map); | 392 elements.add(map); |
380 } | 393 } |
381 } | 394 } |
382 } | 395 } |
383 | 396 |
384 return new jsAst.ArrayInitializer(elements); | 397 return new jsAst.ArrayInitializer(elements); |
385 } | 398 } |
386 } | 399 } |
OLD | NEW |