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 js_backend; | 5 part of js_backend; |
6 | 6 |
7 class NativeEmitter { | 7 class NativeEmitter { |
8 | 8 |
9 CodeEmitterTask emitter; | 9 CodeEmitterTask emitter; |
10 CodeBuffer nativeBuffer; | 10 CodeBuffer nativeBuffer; |
(...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 if (classesWithDynamicDispatch.isEmpty) return; | 278 if (classesWithDynamicDispatch.isEmpty) return; |
279 int length = classesWithDynamicDispatch.length; | 279 int length = classesWithDynamicDispatch.length; |
280 nativeBuffer.add('// $length dynamic classes.\n'); | 280 nativeBuffer.add('// $length dynamic classes.\n'); |
281 | 281 |
282 // Build a pre-order traversal over all the classes and their subclasses. | 282 // Build a pre-order traversal over all the classes and their subclasses. |
283 Set<ClassElement> seen = new Set<ClassElement>(); | 283 Set<ClassElement> seen = new Set<ClassElement>(); |
284 List<ClassElement> classes = <ClassElement>[]; | 284 List<ClassElement> classes = <ClassElement>[]; |
285 void visit(ClassElement cls) { | 285 void visit(ClassElement cls) { |
286 if (seen.contains(cls)) return; | 286 if (seen.contains(cls)) return; |
287 seen.add(cls); | 287 seen.add(cls); |
288 for (final ClassElement subclass in getDirectSubclasses(cls)) { | 288 getDirectSubclasses(cls).forEach(visit); |
289 visit(subclass); | |
290 } | |
291 classes.add(cls); | 289 classes.add(cls); |
292 } | 290 } |
293 for (final ClassElement classElement in classesWithDynamicDispatch) { | 291 classesWithDynamicDispatch.forEach(visit); |
294 visit(classElement); | |
295 } | |
296 | 292 |
297 Collection<ClassElement> dispatchClasses = classes.filter( | 293 Collection<ClassElement> preorderDispatchClasses = classes.filter( |
298 (cls) => !getDirectSubclasses(cls).isEmpty && | 294 (cls) => !getDirectSubclasses(cls).isEmpty && |
299 classesWithDynamicDispatch.contains(cls)); | 295 classesWithDynamicDispatch.contains(cls)); |
300 | 296 |
301 nativeBuffer.add('// ${classes.length} classes\n'); | 297 nativeBuffer.add('// ${classes.length} classes\n'); |
302 Collection<ClassElement> classesThatHaveSubclasses = classes.filter( | 298 Collection<ClassElement> classesThatHaveSubclasses = classes.filter( |
303 (ClassElement t) => !getDirectSubclasses(t).isEmpty); | 299 (ClassElement t) => !getDirectSubclasses(t).isEmpty); |
304 nativeBuffer.add('// ${classesThatHaveSubclasses.length} !leaf\n'); | 300 nativeBuffer.add('// ${classesThatHaveSubclasses.length} !leaf\n'); |
305 | 301 |
306 // Generate code that builds the map from cls tags used in dynamic dispatch | 302 // Generate code that builds the map from cls tags used in dynamic dispatch |
307 // to the set of cls tags of classes that extend (TODO: or implement) those | 303 // to the set of cls tags of classes that extend (TODO: or implement) those |
308 // classes. The set is represented as a string of tags joined with '|'. | 304 // classes. The set is represented as a string of tags joined with '|'. |
309 // This is easily split into an array of tags, or converted into a regexp. | 305 // This is easily split into an array of tags, or converted into a regexp. |
310 // | 306 // |
311 // To reduce the size of the sets, subsets are CSE-ed out into variables. | 307 // To reduce the size of the sets, subsets are CSE-ed out into variables. |
312 // The sets could be much smaller if we could make assumptions about the | 308 // The sets could be much smaller if we could make assumptions about the |
313 // cls tags of other classes (which are constructor names or part of the | 309 // cls tags of other classes (which are constructor names or part of the |
314 // result of Object.protocls.toString). For example, if objects that are | 310 // result of Object.protocls.toString). For example, if objects that are |
315 // Dart objects could be easily excluded, then we might be able to simplify | 311 // Dart objects could be easily excluded, then we might be able to simplify |
316 // the test, replacing dozens of HTMLxxxElement classes with the regexp | 312 // the test, replacing dozens of HTMLxxxElement classes with the regexp |
317 // /HTML.*Element/. | 313 // /HTML.*Element/. |
318 | 314 |
319 // Temporary variables for common substrings. | 315 // Temporary variables for common substrings. |
320 List<String> varNames = <String>[]; | 316 List<String> varNames = <String>[]; |
321 // var -> expression | 317 // Values of temporary variables. |
322 Map<dynamic, js.Expression> varDefns = new Map<dynamic, js.Expression>(); | 318 Map<String, js.Expression> varDefns = new Map<String, js.Expression>(); |
323 // tag -> expression (a string or a variable) | 319 |
| 320 // Expression to compute tags string for a class. The expression will |
| 321 // initially be a string or expression building a string, but may be |
| 322 // replaced with a variable reference to the common substring. |
324 Map<ClassElement, js.Expression> tagDefns = | 323 Map<ClassElement, js.Expression> tagDefns = |
325 new Map<ClassElement, js.Expression>(); | 324 new Map<ClassElement, js.Expression>(); |
326 | 325 |
327 js.Expression makeExpression(ClassElement classElement) { | 326 js.Expression makeExpression(ClassElement classElement) { |
328 // Expression fragments for this set of cls keys. | 327 // Expression fragments for this set of cls keys. |
329 List<js.Expression> expressions = <js.Expression>[]; | 328 List<js.Expression> expressions = <js.Expression>[]; |
330 // TODO: Remove if cls is abstract. | 329 // TODO: Remove if cls is abstract. |
331 List<String> subtags = [toNativeName(classElement)]; | 330 List<String> subtags = [toNativeName(classElement)]; |
332 void walk(ClassElement cls) { | 331 void walk(ClassElement cls) { |
333 for (final ClassElement subclass in getDirectSubclasses(cls)) { | 332 for (final ClassElement subclass in getDirectSubclasses(cls)) { |
334 ClassElement tag = subclass; | 333 ClassElement tag = subclass; |
335 var existing = tagDefns[tag]; | 334 js.Expression existing = tagDefns[tag]; |
336 if (existing == null) { | 335 if (existing == null) { |
| 336 // [subclass] is still within the subtree between dispatch classes. |
337 subtags.add(toNativeName(tag)); | 337 subtags.add(toNativeName(tag)); |
338 walk(subclass); | 338 walk(subclass); |
339 } else { | 339 } else { |
340 if (varDefns.containsKey(existing)) { | 340 // [subclass] is one of the preorderDispatchClasses, so CSE this |
341 expressions.add(existing); | 341 // reference with the previous reference. |
| 342 if (existing is js.VariableUse && |
| 343 varDefns.containsKey(existing.name)) { |
| 344 // We end up here if the subclasses have a DAG structure. We |
| 345 // don't have DAGs yet, but if the dispatch is used for mixins |
| 346 // that will be a possibility. |
| 347 // Re-use the previously created temporary variable. |
| 348 expressions.add(new js.VariableUse(existing.name)); |
342 } else { | 349 } else { |
343 String varName = 'v${varNames.length}_${tag.name.slowToString()}'; | 350 String varName = 'v${varNames.length}_${tag.name.slowToString()}'; |
344 varNames.add(varName); | 351 varNames.add(varName); |
345 varDefns[varName] = existing; | 352 varDefns[varName] = existing; |
346 tagDefns[tag] = new js.VariableUse(varName); | 353 tagDefns[tag] = new js.VariableUse(varName); |
347 expressions.add(new js.VariableUse(varName)); | 354 expressions.add(new js.VariableUse(varName)); |
348 } | 355 } |
349 } | 356 } |
350 } | 357 } |
351 } | 358 } |
352 walk(classElement); | 359 walk(classElement); |
| 360 |
353 if (!subtags.isEmpty) { | 361 if (!subtags.isEmpty) { |
354 expressions.add( | 362 expressions.add( |
355 new js.LiteralString("'${Strings.join(subtags, '|')}'")); | 363 new js.LiteralString("'${Strings.join(subtags, '|')}'")); |
356 } | 364 } |
357 js.Expression expression; | 365 js.Expression expression; |
358 if (expressions.length == 1) { | 366 if (expressions.length == 1) { |
359 expression = expressions[0]; | 367 expression = expressions[0]; |
360 } else { | 368 } else { |
361 js.Expression array = new js.ArrayInitializer.from(expressions); | 369 js.Expression array = new js.ArrayInitializer.from(expressions); |
362 expression = new js.Call( | 370 expression = new js.Call( |
363 new js.PropertyAccess.field(array, 'join'), | 371 new js.PropertyAccess.field(array, 'join'), |
364 [new js.LiteralString("'|'")]); | 372 [new js.LiteralString("'|'")]); |
365 } | 373 } |
366 return expression; | 374 return expression; |
367 } | 375 } |
368 | 376 |
369 for (final ClassElement classElement in dispatchClasses) { | 377 for (final ClassElement classElement in preorderDispatchClasses) { |
370 tagDefns[classElement] = makeExpression(classElement); | 378 tagDefns[classElement] = makeExpression(classElement); |
371 } | 379 } |
372 | 380 |
373 // Write out a thunk that builds the metadata. | 381 // Write out a thunk that builds the metadata. |
374 if (!tagDefns.isEmpty) { | 382 if (!tagDefns.isEmpty) { |
375 List<js.Statement> statements = <js.Statement>[]; | 383 List<js.Statement> statements = <js.Statement>[]; |
376 | 384 |
377 List<js.VariableInitialization> initializations = | 385 List<js.VariableInitialization> initializations = |
378 <js.VariableInitialization>[]; | 386 <js.VariableInitialization>[]; |
379 for (final String varName in varNames) { | 387 for (final String varName in varNames) { |
380 initializations.add( | 388 initializations.add( |
381 new js.VariableInitialization( | 389 new js.VariableInitialization( |
382 new js.VariableDeclaration(varName), | 390 new js.VariableDeclaration(varName), |
383 varDefns[varName])); | 391 varDefns[varName])); |
384 } | 392 } |
385 if (!initializations.isEmpty) { | 393 if (!initializations.isEmpty) { |
386 statements.add( | 394 statements.add( |
387 new js.ExpressionStatement( | 395 new js.ExpressionStatement( |
388 new js.VariableDeclarationList(initializations))); | 396 new js.VariableDeclarationList(initializations))); |
389 } | 397 } |
390 | 398 |
391 // [table] is a list of lists, each inner list of the form: | 399 // [table] is a list of lists, each inner list of the form: |
392 // [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag] | 400 // [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag] |
393 // E.g. | 401 // E.g. |
394 // [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...] | 402 // [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...] |
395 js.Expression table = | 403 js.Expression table = |
396 new js.ArrayInitializer.from( | 404 new js.ArrayInitializer.from( |
397 dispatchClasses.map((cls) => | 405 preorderDispatchClasses.map((cls) => |
398 new js.ArrayInitializer.from([ | 406 new js.ArrayInitializer.from([ |
399 new js.LiteralString("'${toNativeName(cls)}'"), | 407 new js.LiteralString("'${toNativeName(cls)}'"), |
400 tagDefns[cls]]))); | 408 tagDefns[cls]]))); |
401 | 409 |
402 // $.dynamicSetMetadata(table); | 410 // $.dynamicSetMetadata(table); |
403 statements.add( | 411 statements.add( |
404 new js.ExpressionStatement( | 412 new js.ExpressionStatement( |
405 new js.Call( | 413 new js.Call( |
406 new js.VariableUse(dynamicSetMetadataName), | 414 new js.VariableUse(dynamicSetMetadataName), |
407 [table]))); | 415 [table]))); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 if (!first) targetBuffer.add(",\n"); | 506 if (!first) targetBuffer.add(",\n"); |
499 targetBuffer.add(" $name: $function"); | 507 targetBuffer.add(" $name: $function"); |
500 first = false; | 508 first = false; |
501 }); | 509 }); |
502 targetBuffer.add("\n});\n\n"); | 510 targetBuffer.add("\n});\n\n"); |
503 } | 511 } |
504 targetBuffer.add(nativeBuffer); | 512 targetBuffer.add(nativeBuffer); |
505 targetBuffer.add('\n'); | 513 targetBuffer.add('\n'); |
506 } | 514 } |
507 } | 515 } |
OLD | NEW |