Chromium Code Reviews| 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 /** | 7 /** |
| 8 * A function element that represents a closure call. The signature is copied | 8 * A function element that represents a closure call. The signature is copied |
| 9 * from the given element. | 9 * from the given element. |
| 10 */ | 10 */ |
| (...skipping 1094 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1105 new js.VariableUse('receiver') | 1105 new js.VariableUse('receiver') |
| 1106 .dot(name) | 1106 .dot(name) |
| 1107 .callWith(arguments))])); | 1107 .callWith(arguments))])); |
| 1108 | 1108 |
| 1109 CodeBuffer code = new CodeBuffer(); | 1109 CodeBuffer code = new CodeBuffer(); |
| 1110 code.add(js.prettyPrint(function, compiler)); | 1110 code.add(js.prettyPrint(function, compiler)); |
| 1111 defineInstanceMember(name, code); | 1111 defineInstanceMember(name, code); |
| 1112 } | 1112 } |
| 1113 } | 1113 } |
| 1114 | 1114 |
| 1115 Iterable<Element> getTypedefChecksOn(DartType type) { | |
| 1116 return checkedTypedefs.filter((TypedefElement typedef) { | |
| 1117 FunctionType typedefType = | |
| 1118 typedef.computeType(compiler).unalias(compiler); | |
| 1119 return compiler.types.isSubtype(type, typedefType); | |
| 1120 }); | |
| 1121 } | |
| 1122 | |
| 1115 /** | 1123 /** |
| 1116 * Generate "is tests" for [cls]: itself, and the "is tests" for the | 1124 * Generate "is tests" for [cls]: itself, and the "is tests" for the |
| 1117 * classes it implements. We don't need to add the "is tests" of the | 1125 * classes it implements. We don't need to add the "is tests" of the |
| 1118 * super class because they will be inherited at runtime. | 1126 * super class because they will be inherited at runtime. |
| 1119 */ | 1127 */ |
| 1120 void generateIsTestsOn(ClassElement cls, | 1128 void generateIsTestsOn(ClassElement cls, |
| 1121 void emitIsTest(Element element)) { | 1129 void emitIsTest(Element element)) { |
| 1122 if (checkedClasses.contains(cls)) { | 1130 if (checkedClasses.contains(cls)) { |
| 1123 emitIsTest(cls); | 1131 emitIsTest(cls); |
| 1124 } | 1132 } |
| 1125 | 1133 |
| 1126 Set<Element> generated = new Set<Element>(); | 1134 Set<Element> generated = new Set<Element>(); |
| 1127 // A class that defines a [:call:] method implicitly implements | 1135 // A class that defines a [:call:] method implicitly implements |
| 1128 // [Function] and needs checks for all typedefs that are used in is-checks. | 1136 // [Function] and needs checks for all typedefs that are used in is-checks. |
| 1129 if (checkedClasses.contains(compiler.functionClass) || | 1137 if (checkedClasses.contains(compiler.functionClass) || |
| 1130 !checkedTypedefs.isEmpty) { | 1138 !checkedTypedefs.isEmpty) { |
| 1131 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); | 1139 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); |
| 1132 if (call == null) { | 1140 if (call == null) { |
| 1133 // If [cls] is a closure, it has a synthetic call operator method. | 1141 // If [cls] is a closure, it has a synthetic call operator method. |
| 1134 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); | 1142 call = cls.lookupBackendMember(Compiler.CALL_OPERATOR_NAME); |
| 1135 } | 1143 } |
| 1136 if (call != null) { | 1144 if (call != null) { |
| 1137 generateInterfacesIsTests(compiler.functionClass, | 1145 generateInterfacesIsTests(compiler.functionClass, |
| 1138 emitIsTest, | 1146 emitIsTest, |
| 1139 generated); | 1147 generated); |
| 1140 FunctionType callType = call.computeType(compiler); | 1148 getTypedefChecksOn(call.computeType(compiler)).forEach(emitIsTest); |
| 1141 for (TypedefElement typedef in checkedTypedefs) { | |
| 1142 FunctionType typedefType = | |
| 1143 typedef.computeType(compiler).unalias(compiler); | |
| 1144 if (compiler.types.isSubtype(callType, typedefType)) { | |
| 1145 emitIsTest(typedef); | |
| 1146 } | |
| 1147 } | |
| 1148 } | 1149 } |
| 1149 } | 1150 } |
| 1150 for (DartType interfaceType in cls.interfaces) { | 1151 for (DartType interfaceType in cls.interfaces) { |
| 1151 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); | 1152 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); |
| 1152 } | 1153 } |
| 1153 } | 1154 } |
| 1154 | 1155 |
| 1155 /** | 1156 /** |
| 1156 * Generate "is tests" where [cls] is being implemented. | 1157 * Generate "is tests" where [cls] is being implemented. |
| 1157 */ | 1158 */ |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1334 String invocationName = namer.instanceMethodName(callElement); | 1335 String invocationName = namer.instanceMethodName(callElement); |
| 1335 String fieldAccess = '$isolateProperties.$staticName'; | 1336 String fieldAccess = '$isolateProperties.$staticName'; |
| 1336 buffer.add("$fieldAccess.$invocationName$_=$_$fieldAccess$N"); | 1337 buffer.add("$fieldAccess.$invocationName$_=$_$fieldAccess$N"); |
| 1337 addParameterStubs(callElement, (String name, CodeBuffer value) { | 1338 addParameterStubs(callElement, (String name, CodeBuffer value) { |
| 1338 buffer.add('$fieldAccess.$name$_=$_$value$N'); | 1339 buffer.add('$fieldAccess.$name$_=$_$value$N'); |
| 1339 }); | 1340 }); |
| 1340 // If a static function is used as a closure we need to add its name | 1341 // If a static function is used as a closure we need to add its name |
| 1341 // in case it is used in spawnFunction. | 1342 // in case it is used in spawnFunction. |
| 1342 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 1343 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
| 1343 buffer.add('$fieldAccess.$fieldName$_=$_"$staticName"$N'); | 1344 buffer.add('$fieldAccess.$fieldName$_=$_"$staticName"$N'); |
| 1345 getTypedefChecksOn(element.computeType(compiler)).forEach( | |
| 1346 (Element typedef) { | |
| 1347 String operator = namer.operatorIs(typedef); | |
| 1348 buffer.add('$fieldAccess.$operator$_=${_}true$N'); | |
| 1349 } | |
| 1350 ); | |
| 1344 } | 1351 } |
| 1345 } | 1352 } |
| 1346 | 1353 |
| 1347 void emitBoundClosureClassHeader(String mangledName, | 1354 void emitBoundClosureClassHeader(String mangledName, |
| 1348 String superName, | 1355 String superName, |
| 1349 List<String> fieldNames, | 1356 List<String> fieldNames, |
| 1350 CodeBuffer buffer) { | 1357 CodeBuffer buffer) { |
| 1351 buffer.add('$classesCollector.$mangledName$_=$_' | 1358 buffer.add('$classesCollector.$mangledName$_=$_' |
| 1352 '{"":"$superName;${Strings.join(fieldNames,',')}",'); | 1359 '{"":"$superName;${Strings.join(fieldNames,',')}",'); |
| 1353 } | 1360 } |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1395 extraArg = 'receiver'; | 1402 extraArg = 'receiver'; |
| 1396 } else { | 1403 } else { |
| 1397 cache = boundClosureCache; | 1404 cache = boundClosureCache; |
| 1398 } | 1405 } |
| 1399 List<String> fieldNames = compiler.enableMinification | 1406 List<String> fieldNames = compiler.enableMinification |
| 1400 ? inInterceptor ? const ['a', 'b', 'c'] | 1407 ? inInterceptor ? const ['a', 'b', 'c'] |
| 1401 : const ['a', 'b'] | 1408 : const ['a', 'b'] |
| 1402 : inInterceptor ? const ['self', 'target', 'receiver'] | 1409 : inInterceptor ? const ['self', 'target', 'receiver'] |
| 1403 : const ['self', 'target']; | 1410 : const ['self', 'target']; |
| 1404 | 1411 |
| 1405 String closureClass = hasOptionalParameters ? null : cache[parameterCount]; | 1412 Iterable<Element> typedefChecks = |
| 1413 getTypedefChecksOn(member.computeType(compiler)); | |
| 1414 bool hasTypedefChecks = typedefChecks.iterator().hasNext; | |
|
floitsch
2012/12/19 13:37:23
For your information: this will become:
!typedefCh
ngeoffray
2012/12/19 13:47:27
I was actually looking for it :-)
| |
| 1415 | |
| 1416 bool canBeShared = !hasOptionalParameters && !hasTypedefChecks; | |
| 1417 | |
| 1418 String closureClass = canBeShared ? cache[parameterCount] : null; | |
| 1406 if (closureClass == null) { | 1419 if (closureClass == null) { |
| 1407 // Either the class was not cached yet, or there are optional parameters. | 1420 // Either the class was not cached yet, or there are optional parameters. |
| 1408 // Create a new closure class. | 1421 // Create a new closure class. |
| 1409 SourceString name = const SourceString("BoundClosure"); | 1422 SourceString name = const SourceString("BoundClosure"); |
| 1410 ClassElement closureClassElement = new ClosureClassElement( | 1423 ClassElement closureClassElement = new ClosureClassElement( |
| 1411 name, compiler, member, member.getCompilationUnit()); | 1424 name, compiler, member, member.getCompilationUnit()); |
| 1412 String mangledName = namer.getName(closureClassElement); | 1425 String mangledName = namer.getName(closureClassElement); |
| 1413 String superName = namer.getName(closureClassElement.superclass); | 1426 String superName = namer.getName(closureClassElement.superclass); |
| 1414 needsClosureClass = true; | 1427 needsClosureClass = true; |
| 1415 | 1428 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1447 new js.This().dot(fieldNames[0]), | 1460 new js.This().dot(fieldNames[0]), |
| 1448 new js.This().dot(fieldNames[1])) | 1461 new js.This().dot(fieldNames[1])) |
| 1449 .callWith(arguments))])); | 1462 .callWith(arguments))])); |
| 1450 | 1463 |
| 1451 boundClosureBuffer.add( | 1464 boundClosureBuffer.add( |
| 1452 '$_$invocationName:$_${js.prettyPrint(fun,compiler)}'); | 1465 '$_$invocationName:$_${js.prettyPrint(fun,compiler)}'); |
| 1453 | 1466 |
| 1454 addParameterStubs(callElement, (String stubName, CodeBuffer memberValue) { | 1467 addParameterStubs(callElement, (String stubName, CodeBuffer memberValue) { |
| 1455 boundClosureBuffer.add(',\n$_$stubName:$_$memberValue'); | 1468 boundClosureBuffer.add(',\n$_$stubName:$_$memberValue'); |
| 1456 }); | 1469 }); |
| 1470 | |
| 1471 typedefChecks.forEach((Element typedef) { | |
| 1472 String operator = namer.operatorIs(typedef); | |
| 1473 boundClosureBuffer.add(',\n$_$operator$_:${_}true'); | |
| 1474 }); | |
| 1475 | |
| 1457 boundClosureBuffer.add("$n}$N"); | 1476 boundClosureBuffer.add("$n}$N"); |
| 1458 | 1477 |
| 1459 closureClass = namer.isolateAccess(closureClassElement); | 1478 closureClass = namer.isolateAccess(closureClassElement); |
| 1460 | 1479 |
| 1461 // Cache it. | 1480 // Cache it. |
| 1462 if (!hasOptionalParameters) { | 1481 if (canBeShared) { |
| 1463 cache[parameterCount] = closureClass; | 1482 cache[parameterCount] = closureClass; |
| 1464 } | 1483 } |
| 1465 } | 1484 } |
| 1466 | 1485 |
| 1467 // And finally the getter. | 1486 // And finally the getter. |
| 1468 String getterName = namer.getterName(member.getLibrary(), member.name); | 1487 String getterName = namer.getterName(member.getLibrary(), member.name); |
| 1469 String targetName = namer.instanceMethodName(member); | 1488 String targetName = namer.instanceMethodName(member); |
| 1470 | 1489 |
| 1471 List<js.Parameter> parameters = <js.Parameter>[]; | 1490 List<js.Parameter> parameters = <js.Parameter>[]; |
| 1472 List<js.Expression> arguments = <js.Expression>[]; | 1491 List<js.Expression> arguments = <js.Expression>[]; |
| (...skipping 611 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2084 """; | 2103 """; |
| 2085 const String HOOKS_API_USAGE = """ | 2104 const String HOOKS_API_USAGE = """ |
| 2086 // The code supports the following hooks: | 2105 // The code supports the following hooks: |
| 2087 // dartPrint(message) - if this function is defined it is called | 2106 // dartPrint(message) - if this function is defined it is called |
| 2088 // instead of the Dart [print] method. | 2107 // instead of the Dart [print] method. |
| 2089 // dartMainRunner(main) - if this function is defined, the Dart [main] | 2108 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 2090 // method will not be invoked directly. | 2109 // method will not be invoked directly. |
| 2091 // Instead, a closure that will invoke [main] is | 2110 // Instead, a closure that will invoke [main] is |
| 2092 // passed to [dartMainRunner]. | 2111 // passed to [dartMainRunner]. |
| 2093 """; | 2112 """; |
| OLD | NEW |