| 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 /** | 5 /** |
| 6 * A function element that represents a closure call. The signature is copied | 6 * A function element that represents a closure call. The signature is copied |
| 7 * from the given element. | 7 * from the given element. |
| 8 */ | 8 */ |
| 9 class ClosureInvocationElement extends FunctionElement { | 9 class ClosureInvocationElement extends FunctionElement { |
| 10 ClosureInvocationElement(SourceString name, | 10 ClosureInvocationElement(SourceString name, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 function tmp() {}; | 29 function tmp() {}; |
| 30 tmp.prototype = parent.prototype; | 30 tmp.prototype = parent.prototype; |
| 31 child.prototype = new tmp(); | 31 child.prototype = new tmp(); |
| 32 child.prototype.constructor = child; | 32 child.prototype.constructor = child; |
| 33 } | 33 } |
| 34 }'''; | 34 }'''; |
| 35 | 35 |
| 36 bool addedInheritFunction = false; | 36 bool addedInheritFunction = false; |
| 37 final Namer namer; | 37 final Namer namer; |
| 38 final NativeEmitter nativeEmitter; | 38 final NativeEmitter nativeEmitter; |
| 39 Set<ClassElement> generatedClasses; |
| 39 | 40 |
| 40 CodeEmitterTask(Compiler compiler) | 41 CodeEmitterTask(Compiler compiler) |
| 41 : namer = compiler.namer, | 42 : namer = compiler.namer, |
| 42 nativeEmitter = new NativeEmitter(compiler), | 43 nativeEmitter = new NativeEmitter(compiler), |
| 44 generatedClasses = new Set<ClassElement>(), |
| 43 super(compiler); | 45 super(compiler); |
| 44 | 46 |
| 45 String get name() => 'CodeEmitter'; | 47 String get name() => 'CodeEmitter'; |
| 46 | 48 |
| 47 String get inheritsName() => '${namer.ISOLATE}.\$inherits'; | 49 String get inheritsName() => '${namer.ISOLATE}.\$inherits'; |
| 48 | 50 |
| 49 String get objectClassName() { | 51 String get objectClassName() { |
| 50 ClassElement objectClass = | 52 ClassElement objectClass = |
| 51 compiler.coreLibrary.find(const SourceString('Object')); | 53 compiler.coreLibrary.find(const SourceString('Object')); |
| 52 return namer.isolatePropertyAccess(objectClass); | 54 return namer.isolatePropertyAccess(objectClass); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 generateFieldInit(element); | 249 generateFieldInit(element); |
| 248 } | 250 } |
| 249 for (Element element in classElement.backendMembers) { | 251 for (Element element in classElement.backendMembers) { |
| 250 generateFieldInit(element); | 252 generateFieldInit(element); |
| 251 } | 253 } |
| 252 | 254 |
| 253 classElement = classElement.superclass; | 255 classElement = classElement.superclass; |
| 254 } while(classElement !== null); | 256 } while(classElement !== null); |
| 255 } | 257 } |
| 256 | 258 |
| 257 void generateClass(ClassElement classElement, | 259 void emitInherits(ClassElement cls, StringBuffer buffer) { |
| 258 StringBuffer buffer, | 260 ClassElement superclass = cls.superclass; |
| 259 Set<ClassElement> seenClasses) { | |
| 260 if (seenClasses.contains(classElement)) return; | |
| 261 seenClasses.add(classElement); | |
| 262 ClassElement superclass = classElement.superclass; | |
| 263 if (superclass !== null) { | 261 if (superclass !== null) { |
| 264 generateClass(classElement.superclass, buffer, seenClasses); | 262 addInheritFunctionIfNecessary(buffer); |
| 263 String className = namer.isolatePropertyAccess(cls); |
| 264 String superName = namer.isolatePropertyAccess(superclass); |
| 265 buffer.add('${inheritsName}($className, $superName);\n'); |
| 265 } | 266 } |
| 267 } |
| 268 |
| 269 void ensureGenerated(ClassElement classElement, StringBuffer buffer) { |
| 270 if (classElement == null) return; |
| 271 if (generatedClasses.contains(classElement)) return; |
| 272 generatedClasses.add(classElement); |
| 273 generateClass(classElement, buffer); |
| 274 } |
| 275 |
| 276 void generateClass(ClassElement classElement, StringBuffer buffer) { |
| 277 ensureGenerated(classElement.superclass, buffer); |
| 266 | 278 |
| 267 if (classElement.isNative()) { | 279 if (classElement.isNative()) { |
| 268 nativeEmitter.generateNativeClass(classElement, buffer); | 280 nativeEmitter.generateNativeClass(classElement, buffer); |
| 269 return; | 281 return; |
| 270 } | 282 } |
| 271 | 283 |
| 272 String className = namer.isolatePropertyAccess(classElement); | 284 String className = namer.isolatePropertyAccess(classElement); |
| 273 buffer.add('$className = function ${classElement.name.slowToString()}('); | 285 buffer.add('$className = function ${classElement.name.slowToString()}('); |
| 274 StringBuffer bodyBuffer = new StringBuffer(); | 286 StringBuffer bodyBuffer = new StringBuffer(); |
| 275 // If the class is never instantiated we still need to set it up for | 287 // If the class is never instantiated we still need to set it up for |
| 276 // inheritance purposes, but we can leave its JavaScript constructor empty. | 288 // inheritance purposes, but we can leave its JavaScript constructor empty. |
| 277 if (compiler.universe.instantiatedClasses.contains(classElement)) { | 289 if (compiler.universe.instantiatedClasses.contains(classElement)) { |
| 278 generateFieldInits(classElement, buffer, bodyBuffer); | 290 generateFieldInits(classElement, buffer, bodyBuffer); |
| 279 } | 291 } |
| 280 buffer.add(') {\n'); | 292 buffer.add(') {\n'); |
| 281 buffer.add(bodyBuffer); | 293 buffer.add(bodyBuffer); |
| 282 buffer.add('};\n'); | 294 buffer.add('};\n'); |
| 283 if (superclass !== null) { | 295 |
| 284 addInheritFunctionIfNecessary(buffer); | 296 emitInherits(classElement, buffer); |
| 285 String superName = namer.isolatePropertyAccess(superclass); | |
| 286 buffer.add('${inheritsName}($className, $superName);\n'); | |
| 287 } | |
| 288 | 297 |
| 289 String attachTo(String name) => '$className.prototype.$name'; | 298 String attachTo(String name) => '$className.prototype.$name'; |
| 290 for (Element member in classElement.members) { | 299 for (Element member in classElement.members) { |
| 291 if (member.isInstanceMember()) { | 300 if (member.isInstanceMember()) { |
| 292 addInstanceMember(member, attachTo, buffer); | 301 addInstanceMember(member, attachTo, buffer); |
| 293 } | 302 } |
| 294 } | 303 } |
| 295 for (Element member in classElement.backendMembers) { | 304 for (Element member in classElement.backendMembers) { |
| 296 if (member.isInstanceMember()) { | 305 if (member.isInstanceMember()) { |
| 297 addInstanceMember(member, attachTo, buffer); | 306 addInstanceMember(member, attachTo, buffer); |
| 298 } | 307 } |
| 299 } | 308 } |
| 300 generateTypeTests(classElement, (Element other) { | 309 generateTypeTests(classElement, (Element other) { |
| 301 buffer.add('${attachTo(namer.operatorIs(other))} = true;\n'); | 310 buffer.add('${attachTo(namer.operatorIs(other))} = true;\n'); |
| 302 }); | 311 }); |
| 303 | 312 |
| 304 if (superclass === null && compiler.enabledNoSuchMethod) { | 313 if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) { |
| 305 // Emit the noSuchMethods on the Object prototype now, so that | 314 // Emit the noSuchMethods on the Object prototype now, so that |
| 306 // the code in the dynamicMethod can find them. Note that the | 315 // the code in the dynamicMethod can find them. Note that the |
| 307 // code in dynamicMethod is invoked before analyzing the full JS | 316 // code in dynamicMethod is invoked before analyzing the full JS |
| 308 // script. | 317 // script. |
| 309 emitNoSuchMethodCalls(buffer); | 318 emitNoSuchMethodCalls(buffer); |
| 310 } | 319 } |
| 311 } | 320 } |
| 312 | 321 |
| 313 void generateTypeTests(ClassElement cls, | 322 void generateTypeTests(ClassElement cls, |
| 314 void generateTypeTest(ClassElement element)) { | 323 void generateTypeTest(ClassElement element)) { |
| 315 if (compiler.universe.isChecks.contains(cls)) { | 324 if (compiler.universe.isChecks.contains(cls)) { |
| 316 generateTypeTest(cls); | 325 generateTypeTest(cls); |
| 317 } | 326 } |
| 318 generateInterfacesIsTests(cls, generateTypeTest); | 327 generateInterfacesIsTests(cls, generateTypeTest); |
| 319 } | 328 } |
| 320 | 329 |
| 321 void generateInterfacesIsTests(ClassElement cls, | 330 void generateInterfacesIsTests(ClassElement cls, |
| 322 void generateTypeTest(ClassElement element)) { | 331 void generateTypeTest(ClassElement element)) { |
| 323 for (Type interfaceType in cls.interfaces) { | 332 for (Type interfaceType in cls.interfaces) { |
| 324 Element element = interfaceType.element; | 333 Element element = interfaceType.element; |
| 325 if (compiler.universe.isChecks.contains(element)) { | 334 if (compiler.universe.isChecks.contains(element)) { |
| 326 generateTypeTest(element); | 335 generateTypeTest(element); |
| 327 } | 336 } |
| 328 generateInterfacesIsTests(element, generateTypeTest); | 337 generateInterfacesIsTests(element, generateTypeTest); |
| 329 } | 338 } |
| 330 } | 339 } |
| 331 | 340 |
| 332 void emitClasses(StringBuffer buffer) { | 341 void emitClasses(StringBuffer buffer) { |
| 333 Set seenClasses = new Set<ClassElement>(); | |
| 334 for (ClassElement element in compiler.universe.instantiatedClasses) { | 342 for (ClassElement element in compiler.universe.instantiatedClasses) { |
| 335 generateClass(element, buffer, seenClasses); | 343 ensureGenerated(element, buffer); |
| 336 } | 344 } |
| 337 } | 345 } |
| 338 | 346 |
| 339 void emitStaticFunctionsWithNamer(StringBuffer buffer, | 347 void emitStaticFunctionsWithNamer(StringBuffer buffer, |
| 340 Map<Element, String> generatedCode, | 348 Map<Element, String> generatedCode, |
| 341 String functionNamer(Element element)) { | 349 String functionNamer(Element element)) { |
| 342 generatedCode.forEach((Element element, String codeBlock) { | 350 generatedCode.forEach((Element element, String codeBlock) { |
| 343 if (!element.isInstanceMember()) { | 351 if (!element.isInstanceMember()) { |
| 344 buffer.add('${functionNamer(element)} = '); | 352 buffer.add('${functionNamer(element)} = '); |
| 345 buffer.add(codeBlock); | 353 buffer.add(codeBlock); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 FunctionElement member) { | 389 FunctionElement member) { |
| 382 // For every method that has the same name as a property-get we create a | 390 // For every method that has the same name as a property-get we create a |
| 383 // getter that returns a bound closure. Say we have a class 'A' with method | 391 // getter that returns a bound closure. Say we have a class 'A' with method |
| 384 // 'foo' and somewhere in the code there is a dynamic property get of | 392 // 'foo' and somewhere in the code there is a dynamic property get of |
| 385 // 'foo'. Then we generate the following code (in pseudo Dart): | 393 // 'foo'. Then we generate the following code (in pseudo Dart): |
| 386 // | 394 // |
| 387 // class A { | 395 // class A { |
| 388 // foo(x, y, z) { ... } // Original function. | 396 // foo(x, y, z) { ... } // Original function. |
| 389 // get foo() { return new BoundClosure499(this); } | 397 // get foo() { return new BoundClosure499(this); } |
| 390 // } | 398 // } |
| 391 // class BoundClosure499 { | 399 // class BoundClosure499 extends Closure { |
| 392 // var self; | 400 // var self; |
| 393 // BoundClosure499(this.self); | 401 // BoundClosure499(this.self); |
| 394 // $call3(x, y, z) { return self.foo(x, y, z); } | 402 // $call3(x, y, z) { return self.foo(x, y, z); } |
| 395 // } | 403 // } |
| 396 | 404 |
| 397 // TODO(floitsch): share the closure classes with other classes | 405 // TODO(floitsch): share the closure classes with other classes |
| 398 // if they share methods with the same signature. | 406 // if they share methods with the same signature. |
| 399 | 407 |
| 400 // The closure class. | 408 // The closure class. |
| 401 SourceString name = const SourceString("BoundClosure"); | 409 SourceString name = const SourceString("BoundClosure"); |
| 402 CompilationUnitElement compilationUnit = member.getCompilationUnit(); | 410 ClassElement closureClassElement = |
| 403 ClassElement closureClassElement = new ClassElement(name, compilationUnit); | 411 new ClosureClassElement(compiler, member.getCompilationUnit()); |
| 404 String isolateAccess = namer.isolatePropertyAccess(closureClassElement); | 412 String isolateAccess = namer.isolatePropertyAccess(closureClassElement); |
| 413 ensureGenerated(closureClassElement.superclass, buffer); |
| 405 | 414 |
| 406 // Define the constructor with a name so that Object.toString can | 415 // Define the constructor with a name so that Object.toString can |
| 407 // find the class name of the closure class. | 416 // find the class name of the closure class. |
| 408 buffer.add("$isolateAccess = function $name(self) "); | 417 buffer.add("$isolateAccess = function $name(self) "); |
| 409 buffer.add("{ this.self = self; };\n"); | 418 buffer.add("{ this.self = self; };\n"); |
| 410 | 419 emitInherits(closureClassElement, buffer); |
| 411 // Make the closure class extend Object. | |
| 412 addInheritFunctionIfNecessary(buffer); | |
| 413 ClassElement objectClass = | |
| 414 compiler.coreLibrary.find(const SourceString('Object')); | |
| 415 String superName = namer.isolatePropertyAccess(objectClass); | |
| 416 buffer.add('${inheritsName}($isolateAccess, $superName);\n'); | |
| 417 | 420 |
| 418 String prototype = "$isolateAccess.prototype"; | 421 String prototype = "$isolateAccess.prototype"; |
| 419 | 422 |
| 420 // Now add the methods on the closure class. The instance method does not | 423 // Now add the methods on the closure class. The instance method does not |
| 421 // have the correct name. Since [addParameterStubs] use the name to create | 424 // have the correct name. Since [addParameterStubs] use the name to create |
| 422 // its stubs we simply create a fake element with the correct name. | 425 // its stubs we simply create a fake element with the correct name. |
| 423 // Note: the callElement will not have any enclosingElement. | 426 // Note: the callElement will not have any enclosingElement. |
| 424 FunctionElement callElement = | 427 FunctionElement callElement = |
| 425 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); | 428 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); |
| 426 | 429 |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 emitStaticFinalFieldInitializations(buffer); | 617 emitStaticFinalFieldInitializations(buffer); |
| 615 nativeEmitter.emitDynamicDispatchMetadata(buffer); | 618 nativeEmitter.emitDynamicDispatchMetadata(buffer); |
| 616 buffer.add('var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); | 619 buffer.add('var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); |
| 617 Element main = compiler.mainApp.find(Compiler.MAIN); | 620 Element main = compiler.mainApp.find(Compiler.MAIN); |
| 618 buffer.add('${namer.isolateAccess(main)}();\n'); | 621 buffer.add('${namer.isolateAccess(main)}();\n'); |
| 619 compiler.assembledCode = buffer.toString(); | 622 compiler.assembledCode = buffer.toString(); |
| 620 }); | 623 }); |
| 621 return compiler.assembledCode; | 624 return compiler.assembledCode; |
| 622 } | 625 } |
| 623 } | 626 } |
| OLD | NEW |