| 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 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 // The sets could be much smaller if we could make assumptions about the | 314 // The sets could be much smaller if we could make assumptions about the |
| 315 // cls tags of other classes (which are constructor names or part of the | 315 // cls tags of other classes (which are constructor names or part of the |
| 316 // result of Object.protocls.toString). For example, if objects that are | 316 // result of Object.protocls.toString). For example, if objects that are |
| 317 // Dart objects could be easily excluded, then we might be able to simplify | 317 // Dart objects could be easily excluded, then we might be able to simplify |
| 318 // the test, replacing dozens of HTMLxxxElement classes with the regexp | 318 // the test, replacing dozens of HTMLxxxElement classes with the regexp |
| 319 // /HTML.*Element/. | 319 // /HTML.*Element/. |
| 320 | 320 |
| 321 // Temporary variables for common substrings. | 321 // Temporary variables for common substrings. |
| 322 List<String> varNames = <String>[]; | 322 List<String> varNames = <String>[]; |
| 323 // var -> expression | 323 // var -> expression |
| 324 Map<String, String> varDefns = <String, String>{}; | 324 Map<String, js.Expression> varDefns = <String, js.Expression>{}; |
| 325 // tag -> expression (a string or a variable) | 325 // tag -> expression (a string or a variable) |
| 326 Map<ClassElement, String> tagDefns = new Map<ClassElement, String>(); | 326 Map<ClassElement, js.Expression> tagDefns = |
| 327 new Map<ClassElement, js.Expression>(); |
| 327 | 328 |
| 328 String makeExpression(ClassElement classElement) { | 329 String makeExpression(ClassElement classElement) { |
| 329 // Expression fragments for this set of cls keys. | 330 // Expression fragments for this set of cls keys. |
| 330 List<String> expressions = <String>[]; | 331 List<js.Expression> expressions = <js.Expression>[]; |
| 331 // TODO: Remove if cls is abstract. | 332 // TODO: Remove if cls is abstract. |
| 332 List<String> subtags = [toNativeName(classElement)]; | 333 List<String> subtags = [toNativeName(classElement)]; |
| 333 void walk(ClassElement cls) { | 334 void walk(ClassElement cls) { |
| 334 for (final ClassElement subclass in getDirectSubclasses(cls)) { | 335 for (final ClassElement subclass in getDirectSubclasses(cls)) { |
| 335 ClassElement tag = subclass; | 336 ClassElement tag = subclass; |
| 336 String existing = tagDefns[tag]; | 337 String existing = tagDefns[tag]; |
| 337 if (existing == null) { | 338 if (existing == null) { |
| 338 subtags.add(toNativeName(tag)); | 339 subtags.add(toNativeName(tag)); |
| 339 walk(subclass); | 340 walk(subclass); |
| 340 } else { | 341 } else { |
| 341 if (varDefns.containsKey(existing)) { | 342 if (varDefns.containsKey(existing)) { |
| 342 expressions.add(existing); | 343 expressions.add(existing); |
| 343 } else { | 344 } else { |
| 344 String varName = 'v${varNames.length}/*${tag}*/'; | 345 String varName = 'v${varNames.length}_${tag.name.slowToString()}'; |
| 345 varNames.add(varName); | 346 varNames.add(varName); |
| 346 varDefns[varName] = existing; | 347 varDefns[varName] = existing; |
| 347 tagDefns[tag] = varName; | 348 tagDefns[tag] = new js.VariableUse(varName); |
| 348 expressions.add(varName); | 349 expressions.add(new js.VariableUse(varName)); |
| 349 } | 350 } |
| 350 } | 351 } |
| 351 } | 352 } |
| 352 } | 353 } |
| 353 walk(classElement); | 354 walk(classElement); |
| 354 String constantPart = "'${Strings.join(subtags, '|')}'"; | 355 if (!subtags.isEmpty) { |
| 355 if (constantPart != "''") expressions.add(constantPart); | 356 expressions.add( |
| 356 String expression; | 357 new js.LiteralString("'${Strings.join(subtags, '|')}'")); |
| 358 } |
| 359 js.Expression expression; |
| 357 if (expressions.length == 1) { | 360 if (expressions.length == 1) { |
| 358 expression = expressions[0]; | 361 expression = expressions[0]; |
| 359 } else { | 362 } else { |
| 360 expression = "[${Strings.join(expressions, ',')}].join('|')"; | 363 js.Expression array = new js.ArrayInitializer.from(expressions); |
| 364 expression = new js.Call( |
| 365 new js.PropertyAccess.field(array, 'join'), |
| 366 [new js.LiteralString("'|'")]); |
| 361 } | 367 } |
| 362 return expression; | 368 return expression; |
| 363 } | 369 } |
| 364 | 370 |
| 365 for (final ClassElement classElement in dispatchClasses) { | 371 for (final ClassElement classElement in dispatchClasses) { |
| 366 tagDefns[classElement] = makeExpression(classElement); | 372 tagDefns[classElement] = makeExpression(classElement); |
| 367 } | 373 } |
| 368 | 374 |
| 369 // Write out a thunk that builds the metadata. | 375 // Write out a thunk that builds the metadata. |
| 370 if (!tagDefns.isEmpty) { | 376 if (!tagDefns.isEmpty) { |
| 371 nativeBuffer.add('(function(){\n'); | 377 List<js.Statement> statements = <js.Statement>[]; |
| 372 | 378 |
| 379 List<js.Expression> initializations = <js.Expression>[]; |
| 373 for (final String varName in varNames) { | 380 for (final String varName in varNames) { |
| 374 nativeBuffer.add(' var ${varName} = ${varDefns[varName]};\n'); | 381 initializations.add( |
| 382 new js.VariableInitialization( |
| 383 new js.VariableDeclaration(varName), |
| 384 varDefns[varName])); |
| 385 } |
| 386 if (!initializations.isEmpty) { |
| 387 statements.add( |
| 388 new js.ExpressionStatement( |
| 389 new js.VariableDeclarationList(initializations))); |
| 375 } | 390 } |
| 376 | 391 |
| 377 nativeBuffer.add(' var table = [\n'); | 392 // [table] is a list of lists, each inner list of the form: |
| 393 // [dynamic-dispatch-tag, tags-of-classes-implementing-dispatch-tag] |
| 394 // E.g. |
| 395 // [['Node', 'Text|HTMLElement|HTMLDivElement|...'], ...] |
| 396 js.Expression table = |
| 397 new js.ArrayInitializer.from( |
| 398 dispatchClasses.map((cls) => |
| 399 new js.ArrayInitializer.from([ |
| 400 new js.LiteralString("'${toNativeName(cls)}'"), |
| 401 tagDefns[cls]]))); |
| 402 |
| 403 // $.dynamicSetMetadata(table); |
| 404 statements.add( |
| 405 new js.ExpressionStatement( |
| 406 new js.Call( |
| 407 new js.VariableUse(dynamicSetMetadataName), |
| 408 [table]))); |
| 409 |
| 410 // (function(){statements})(); |
| 378 nativeBuffer.add( | 411 nativeBuffer.add( |
| 379 ' // [dynamic-dispatch-tag, ' | 412 js.prettyPrint( |
| 380 'tags of classes implementing dynamic-dispatch-tag]'); | 413 new js.ExpressionStatement( |
| 381 bool needsComma = false; | 414 new js.Call(new js.Fun([], new js.Block(statements)), [])), |
| 382 List<String> entries = <String>[]; | 415 compiler)); |
| 383 for (final ClassElement cls in dispatchClasses) { | |
| 384 String clsName = toNativeName(cls); | |
| 385 entries.add("\n ['$clsName', ${tagDefns[cls]}]"); | |
| 386 } | |
| 387 nativeBuffer.add(Strings.join(entries, ',')); | |
| 388 nativeBuffer.add('];\n'); | |
| 389 nativeBuffer.add('$dynamicSetMetadataName(table);\n'); | |
| 390 | |
| 391 nativeBuffer.add('})();\n'); | |
| 392 } | 416 } |
| 393 } | 417 } |
| 394 | 418 |
| 395 bool isSupertypeOfNativeClass(Element element) { | 419 bool isSupertypeOfNativeClass(Element element) { |
| 396 if (element.isTypeVariable()) { | 420 if (element.isTypeVariable()) { |
| 397 compiler.cancel("Is check for type variable", element: element); | 421 compiler.cancel("Is check for type variable", element: element); |
| 398 return false; | 422 return false; |
| 399 } | 423 } |
| 400 if (element.computeType(compiler).unalias(compiler) is FunctionType) { | 424 if (element.computeType(compiler).unalias(compiler) is FunctionType) { |
| 401 // The element type is a function type either directly or through | 425 // The element type is a function type either directly or through |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 475 if (!first) targetBuffer.add(",\n"); | 499 if (!first) targetBuffer.add(",\n"); |
| 476 targetBuffer.add(" $name: $function"); | 500 targetBuffer.add(" $name: $function"); |
| 477 first = false; | 501 first = false; |
| 478 }); | 502 }); |
| 479 targetBuffer.add("\n});\n\n"); | 503 targetBuffer.add("\n});\n\n"); |
| 480 } | 504 } |
| 481 targetBuffer.add(nativeBuffer); | 505 targetBuffer.add(nativeBuffer); |
| 482 targetBuffer.add('\n'); | 506 targetBuffer.add('\n'); |
| 483 } | 507 } |
| 484 } | 508 } |
| OLD | NEW |