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