| 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 20 matching lines...) Expand all Loading... |
| 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 Set<ClassElement> generatedClasses; |
| 40 StringBuffer mainBuffer; | 40 StringBuffer mainBuffer; |
| 41 String isolatePrototype; |
| 41 | 42 |
| 42 CodeEmitterTask(Compiler compiler) | 43 CodeEmitterTask(Compiler compiler) |
| 43 : namer = compiler.namer, | 44 : namer = compiler.namer, |
| 44 nativeEmitter = new NativeEmitter(compiler), | 45 nativeEmitter = new NativeEmitter(compiler), |
| 45 generatedClasses = new Set<ClassElement>(), | 46 generatedClasses = new Set<ClassElement>(), |
| 46 mainBuffer = new StringBuffer(), | 47 mainBuffer = new StringBuffer(), |
| 47 super(compiler); | 48 super(compiler); |
| 48 | 49 |
| 49 String get name() => 'CodeEmitter'; | 50 String get name() => 'CodeEmitter'; |
| 50 | 51 |
| 51 String get inheritsName() => '${namer.ISOLATE}.\$inherits'; | 52 String get inheritsName() => '${namer.ISOLATE}.\$inherits'; |
| 52 | 53 |
| 53 String get objectClassName() { | |
| 54 ClassElement objectClass = | |
| 55 compiler.coreLibrary.find(const SourceString('Object')); | |
| 56 return namer.isolatePropertyAccess(objectClass); | |
| 57 } | |
| 58 | |
| 59 void addInheritFunctionIfNecessary() { | 54 void addInheritFunctionIfNecessary() { |
| 60 if (addedInheritFunction) return; | 55 if (addedInheritFunction) return; |
| 61 addedInheritFunction = true; | 56 addedInheritFunction = true; |
| 62 mainBuffer.add('$inheritsName = '); | 57 mainBuffer.add('$inheritsName = '); |
| 63 mainBuffer.add(INHERIT_FUNCTION); | 58 mainBuffer.add(INHERIT_FUNCTION); |
| 64 mainBuffer.add(';\n'); | 59 mainBuffer.add(';\n'); |
| 65 } | 60 } |
| 66 | 61 |
| 67 void addParameterStub(FunctionElement member, | 62 void addParameterStub(FunctionElement member, |
| 68 String attachTo(String invocationName), | 63 String attachTo(String invocationName), |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 249 | 244 |
| 250 classElement.forEachInstanceField(generateFieldInit, | 245 classElement.forEachInstanceField(generateFieldInit, |
| 251 includeBackendMembers: true, | 246 includeBackendMembers: true, |
| 252 includeSuperMembers: true); | 247 includeSuperMembers: true); |
| 253 } | 248 } |
| 254 | 249 |
| 255 void emitInherits(ClassElement cls, StringBuffer buffer) { | 250 void emitInherits(ClassElement cls, StringBuffer buffer) { |
| 256 ClassElement superclass = cls.superclass; | 251 ClassElement superclass = cls.superclass; |
| 257 if (superclass !== null) { | 252 if (superclass !== null) { |
| 258 addInheritFunctionIfNecessary(); | 253 addInheritFunctionIfNecessary(); |
| 259 String className = namer.isolatePropertyAccess(cls); | 254 String className = namer.getName(cls); |
| 260 String superName = namer.isolatePropertyAccess(superclass); | 255 String superName = namer.getName(superclass); |
| 261 buffer.add('${inheritsName}($className, $superName);\n'); | 256 buffer.add('${inheritsName}($isolatePrototype.$className, '); |
| 257 buffer.add('$isolatePrototype.$superName);\n'); |
| 262 } | 258 } |
| 263 } | 259 } |
| 264 | 260 |
| 265 void ensureGenerated(ClassElement classElement, StringBuffer buffer) { | 261 void ensureGenerated(ClassElement classElement, StringBuffer buffer) { |
| 266 if (classElement == null) return; | 262 if (classElement == null) return; |
| 267 if (generatedClasses.contains(classElement)) return; | 263 if (generatedClasses.contains(classElement)) return; |
| 268 generatedClasses.add(classElement); | 264 generatedClasses.add(classElement); |
| 269 generateClass(classElement, buffer); | 265 generateClass(classElement, buffer); |
| 270 } | 266 } |
| 271 | 267 |
| 272 void generateClass(ClassElement classElement, StringBuffer buffer) { | 268 void generateClass(ClassElement classElement, StringBuffer buffer) { |
| 273 ensureGenerated(classElement.superclass, buffer); | 269 ensureGenerated(classElement.superclass, buffer); |
| 274 | 270 |
| 275 if (classElement.isNative()) { | 271 if (classElement.isNative()) { |
| 276 nativeEmitter.generateNativeClass(classElement); | 272 nativeEmitter.generateNativeClass(classElement); |
| 277 return; | 273 return; |
| 278 } else { | 274 } else { |
| 279 // TODO(ngeoffray): Instead of switching between buffer, we | 275 // TODO(ngeoffray): Instead of switching between buffer, we |
| 280 // should create code sections, and decide where to emit them at | 276 // should create code sections, and decide where to emit them at |
| 281 // the end. | 277 // the end. |
| 282 buffer = mainBuffer; | 278 buffer = mainBuffer; |
| 283 } | 279 } |
| 284 | 280 |
| 285 String className = namer.isolatePropertyAccess(classElement); | 281 String className = '${isolatePrototype}.${namer.getName(classElement)}'; |
| 286 String constructorName = namer.safeName(classElement.name.slowToString()); | 282 String constructorName = namer.safeName(classElement.name.slowToString()); |
| 287 buffer.add('$className = function $constructorName('); | 283 buffer.add('$className = function $constructorName('); |
| 288 StringBuffer bodyBuffer = new StringBuffer(); | 284 StringBuffer bodyBuffer = new StringBuffer(); |
| 289 // If the class is never instantiated we still need to set it up for | 285 // If the class is never instantiated we still need to set it up for |
| 290 // inheritance purposes, but we can leave its JavaScript constructor empty. | 286 // inheritance purposes, but we can leave its JavaScript constructor empty. |
| 291 if (compiler.universe.instantiatedClasses.contains(classElement)) { | 287 if (compiler.universe.instantiatedClasses.contains(classElement)) { |
| 292 generateFieldInits(classElement, buffer, bodyBuffer); | 288 generateFieldInits(classElement, buffer, bodyBuffer); |
| 293 } | 289 } |
| 294 buffer.add(') {\n'); | 290 buffer.add(') {\n'); |
| 295 buffer.add(bodyBuffer); | 291 buffer.add(bodyBuffer); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 for (ClassElement element in compiler.universe.instantiatedClasses) { | 347 for (ClassElement element in compiler.universe.instantiatedClasses) { |
| 352 ensureGenerated(element, buffer); | 348 ensureGenerated(element, buffer); |
| 353 } | 349 } |
| 354 } | 350 } |
| 355 | 351 |
| 356 void emitStaticFunctionsWithNamer(StringBuffer buffer, | 352 void emitStaticFunctionsWithNamer(StringBuffer buffer, |
| 357 Map<Element, String> generatedCode, | 353 Map<Element, String> generatedCode, |
| 358 String functionNamer(Element element)) { | 354 String functionNamer(Element element)) { |
| 359 generatedCode.forEach((Element element, String codeBlock) { | 355 generatedCode.forEach((Element element, String codeBlock) { |
| 360 if (!element.isInstanceMember()) { | 356 if (!element.isInstanceMember()) { |
| 361 buffer.add('${functionNamer(element)} = '); | 357 buffer.add(isolatePrototype); |
| 358 buffer.add('.${functionNamer(element)} = '); |
| 362 buffer.add(codeBlock); | 359 buffer.add(codeBlock); |
| 363 buffer.add(';\n\n'); | 360 buffer.add(';\n\n'); |
| 364 } | 361 } |
| 365 }); | 362 }); |
| 366 } | 363 } |
| 367 | 364 |
| 368 void emitStaticFunctions(StringBuffer buffer) { | 365 void emitStaticFunctions(StringBuffer buffer) { |
| 369 emitStaticFunctionsWithNamer(buffer, | 366 emitStaticFunctionsWithNamer(buffer, |
| 370 compiler.universe.generatedCode, | 367 compiler.universe.generatedCode, |
| 371 namer.isolatePropertyAccess); | 368 namer.getName); |
| 372 emitStaticFunctionsWithNamer(buffer, | 369 emitStaticFunctionsWithNamer(buffer, |
| 373 compiler.universe.generatedBailoutCode, | 370 compiler.universe.generatedBailoutCode, |
| 374 namer.isolateBailoutPropertyAccess); | 371 namer.getBailoutName); |
| 375 } | 372 } |
| 376 | 373 |
| 377 void emitStaticFunctionGetters(StringBuffer buffer) { | 374 void emitStaticFunctionGetters(StringBuffer buffer) { |
| 378 Set<FunctionElement> functionsNeedingGetter = | 375 Set<FunctionElement> functionsNeedingGetter = |
| 379 compiler.universe.staticFunctionsNeedingGetter; | 376 compiler.universe.staticFunctionsNeedingGetter; |
| 380 for (FunctionElement element in functionsNeedingGetter) { | 377 for (FunctionElement element in functionsNeedingGetter) { |
| 381 // The static function does not have the correct name. Since | 378 // The static function does not have the correct name. Since |
| 382 // [addParameterStubs] use the name to create its stubs we simply | 379 // [addParameterStubs] use the name to create its stubs we simply |
| 383 // create a fake element with the correct name. | 380 // create a fake element with the correct name. |
| 384 // Note: the callElement will not have any enclosingElement. | 381 // Note: the callElement will not have any enclosingElement. |
| 385 FunctionElement callElement = | 382 FunctionElement callElement = |
| 386 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, element); | 383 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, element); |
| 387 String staticName = namer.isolatePropertyAccess(element); | 384 String staticName = namer.getName(element); |
| 388 int parameterCount = element.parameterCount(compiler); | 385 int parameterCount = element.parameterCount(compiler); |
| 389 String invocationName = | 386 String invocationName = |
| 390 namer.instanceMethodName(element.getLibrary(), callElement.name, | 387 namer.instanceMethodName(element.getLibrary(), callElement.name, |
| 391 parameterCount); | 388 parameterCount); |
| 392 buffer.add("$staticName.$invocationName = $staticName;\n"); | 389 buffer.add(isolatePrototype); |
| 393 addParameterStubs(callElement, (name) => '$staticName.$name', buffer); | 390 buffer.add(".$staticName.$invocationName = "); |
| 391 buffer.add(isolatePrototype); |
| 392 buffer.add(".$staticName;\n"); |
| 393 addParameterStubs(callElement, |
| 394 (name) => '$isolatePrototype.$staticName.$name', |
| 395 buffer); |
| 394 } | 396 } |
| 395 } | 397 } |
| 396 | 398 |
| 397 void emitDynamicFunctionGetter(StringBuffer buffer, | 399 void emitDynamicFunctionGetter(StringBuffer buffer, |
| 398 String attachTo(String invocationName), | 400 String attachTo(String invocationName), |
| 399 FunctionElement member) { | 401 FunctionElement member) { |
| 400 // For every method that has the same name as a property-get we create a | 402 // For every method that has the same name as a property-get we create a |
| 401 // getter that returns a bound closure. Say we have a class 'A' with method | 403 // getter that returns a bound closure. Say we have a class 'A' with method |
| 402 // 'foo' and somewhere in the code there is a dynamic property get of | 404 // 'foo' and somewhere in the code there is a dynamic property get of |
| 403 // 'foo'. Then we generate the following code (in pseudo Dart): | 405 // 'foo'. Then we generate the following code (in pseudo Dart): |
| 404 // | 406 // |
| 405 // class A { | 407 // class A { |
| 406 // foo(x, y, z) { ... } // Original function. | 408 // foo(x, y, z) { ... } // Original function. |
| 407 // get foo() { return new BoundClosure499(this); } | 409 // get foo() { return new BoundClosure499(this); } |
| 408 // } | 410 // } |
| 409 // class BoundClosure499 extends Closure { | 411 // class BoundClosure499 extends Closure { |
| 410 // var self; | 412 // var self; |
| 411 // BoundClosure499(this.self); | 413 // BoundClosure499(this.self); |
| 412 // $call3(x, y, z) { return self.foo(x, y, z); } | 414 // $call3(x, y, z) { return self.foo(x, y, z); } |
| 413 // } | 415 // } |
| 414 | 416 |
| 415 // TODO(floitsch): share the closure classes with other classes | 417 // TODO(floitsch): share the closure classes with other classes |
| 416 // if they share methods with the same signature. | 418 // if they share methods with the same signature. |
| 417 | 419 |
| 418 // The closure class. | 420 // The closure class. |
| 419 SourceString name = const SourceString("BoundClosure"); | 421 SourceString name = const SourceString("BoundClosure"); |
| 420 ClassElement closureClassElement = | 422 ClassElement closureClassElement = |
| 421 new ClosureClassElement(compiler, member.getCompilationUnit()); | 423 new ClosureClassElement(compiler, member.getCompilationUnit()); |
| 422 String isolateAccess = namer.isolatePropertyAccess(closureClassElement); | 424 String mangledName = namer.getName(closureClassElement); |
| 423 ensureGenerated(closureClassElement.superclass, buffer); | 425 ensureGenerated(closureClassElement.superclass, buffer); |
| 424 | 426 |
| 425 // Define the constructor with a name so that Object.toString can | 427 // Define the constructor with a name so that Object.toString can |
| 426 // find the class name of the closure class. | 428 // find the class name of the closure class. |
| 427 buffer.add("$isolateAccess = function $name(self) "); | 429 buffer.add(isolatePrototype); |
| 430 buffer.add(".$mangledName = function $name(self) "); |
| 428 buffer.add("{ this.self = self; };\n"); | 431 buffer.add("{ this.self = self; };\n"); |
| 429 emitInherits(closureClassElement, buffer); | 432 emitInherits(closureClassElement, buffer); |
| 430 | 433 |
| 431 String prototype = "$isolateAccess.prototype"; | 434 String prototype = "$isolatePrototype.$mangledName.prototype"; |
| 432 | 435 |
| 433 // Now add the methods on the closure class. The instance method does not | 436 // Now add the methods on the closure class. The instance method does not |
| 434 // have the correct name. Since [addParameterStubs] use the name to create | 437 // have the correct name. Since [addParameterStubs] use the name to create |
| 435 // its stubs we simply create a fake element with the correct name. | 438 // its stubs we simply create a fake element with the correct name. |
| 436 // Note: the callElement will not have any enclosingElement. | 439 // Note: the callElement will not have any enclosingElement. |
| 437 FunctionElement callElement = | 440 FunctionElement callElement = |
| 438 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); | 441 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); |
| 439 | 442 |
| 440 int parameterCount = member.parameterCount(compiler); | 443 int parameterCount = member.parameterCount(compiler); |
| 441 String invocationName = | 444 String invocationName = |
| 442 namer.instanceMethodName(member.getLibrary(), | 445 namer.instanceMethodName(member.getLibrary(), |
| 443 callElement.name, parameterCount); | 446 callElement.name, parameterCount); |
| 444 String targetName = namer.instanceMethodName(member.getLibrary(), | 447 String targetName = namer.instanceMethodName(member.getLibrary(), |
| 445 member.name, parameterCount); | 448 member.name, parameterCount); |
| 446 List<String> arguments = new List<String>(parameterCount); | 449 List<String> arguments = new List<String>(parameterCount); |
| 447 for (int i = 0; i < parameterCount; i++) { | 450 for (int i = 0; i < parameterCount; i++) { |
| 448 arguments[i] = "arg$i"; | 451 arguments[i] = "arg$i"; |
| 449 } | 452 } |
| 450 String joinedArgs = Strings.join(arguments, ", "); | 453 String joinedArgs = Strings.join(arguments, ", "); |
| 451 buffer.add("$prototype.$invocationName = function($joinedArgs) {\n"); | 454 buffer.add("$prototype.$invocationName = function($joinedArgs) {\n"); |
| 452 buffer.add(" return this.self.$targetName($joinedArgs);\n"); | 455 buffer.add(" return this.self.$targetName($joinedArgs);\n"); |
| 453 buffer.add("};\n"); | 456 buffer.add("};\n"); |
| 454 addParameterStubs(callElement, | 457 addParameterStubs(callElement, |
| 455 (invocationName) => '$prototype.$invocationName', | 458 (stubName) => '$prototype.$stubName', |
| 456 buffer); | 459 buffer); |
| 457 | 460 |
| 458 // And finally the getter. | 461 // And finally the getter. |
| 459 String getterName = namer.getterName(member.getLibrary(), member.name); | 462 String getterName = namer.getterName(member.getLibrary(), member.name); |
| 460 String closureClass = namer.isolateAccess(closureClassElement); | 463 String closureClass = namer.isolateAccess(closureClassElement); |
| 461 buffer.add("${attachTo(getterName)} = function() {\n"); | 464 buffer.add("${attachTo(getterName)} = function() {\n"); |
| 462 buffer.add(" return new $closureClass(this);\n"); | 465 buffer.add(" return new $closureClass(this);\n"); |
| 463 buffer.add("};\n"); | 466 buffer.add("};\n"); |
| 464 } | 467 } |
| 465 | 468 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 compiler.withCurrentElement(element, () { | 512 compiler.withCurrentElement(element, () { |
| 510 handler.writeJsCodeForVariable(buffer, element); | 513 handler.writeJsCodeForVariable(buffer, element); |
| 511 }); | 514 }); |
| 512 buffer.add(';\n'); | 515 buffer.add(';\n'); |
| 513 } | 516 } |
| 514 } | 517 } |
| 515 | 518 |
| 516 void emitCompileTimeConstants(StringBuffer buffer) { | 519 void emitCompileTimeConstants(StringBuffer buffer) { |
| 517 ConstantHandler handler = compiler.constantHandler; | 520 ConstantHandler handler = compiler.constantHandler; |
| 518 List<Constant> constants = handler.getConstantsForEmission(); | 521 List<Constant> constants = handler.getConstantsForEmission(); |
| 519 String prototype = "${namer.ISOLATE}.prototype"; | |
| 520 bool addedMakeConstantList = false; | 522 bool addedMakeConstantList = false; |
| 521 for (Constant constant in constants) { | 523 for (Constant constant in constants) { |
| 522 String name = handler.getNameForConstant(constant); | 524 String name = handler.getNameForConstant(constant); |
| 523 // The name is null when the constant is already a JS constant. | 525 // The name is null when the constant is already a JS constant. |
| 524 // TODO(floitsch): every constant should be registered, so that we can | 526 // TODO(floitsch): every constant should be registered, so that we can |
| 525 // share the ones that take up too much space (like some strings). | 527 // share the ones that take up too much space (like some strings). |
| 526 if (name === null) continue; | 528 if (name === null) continue; |
| 527 if (!addedMakeConstantList && constant.isList()) { | 529 if (!addedMakeConstantList && constant.isList()) { |
| 528 addedMakeConstantList = true; | 530 addedMakeConstantList = true; |
| 529 emitMakeConstantList(prototype, buffer); | 531 emitMakeConstantList(buffer); |
| 530 } | 532 } |
| 531 buffer.add('$prototype.$name = '); | 533 buffer.add('$isolatePrototype.$name = '); |
| 532 handler.writeJsCode(buffer, constant); | 534 handler.writeJsCode(buffer, constant); |
| 533 buffer.add(';\n'); | 535 buffer.add(';\n'); |
| 534 } | 536 } |
| 535 } | 537 } |
| 536 | 538 |
| 537 void emitMakeConstantList(String prototype, StringBuffer buffer) { | 539 void emitMakeConstantList(StringBuffer buffer) { |
| 538 buffer.add(prototype); | 540 buffer.add(isolatePrototype); |
| 539 buffer.add(@'''.makeConstantList = function(list) { | 541 buffer.add(@'''.makeConstantList = function(list) { |
| 540 list.immutable$list = true; | 542 list.immutable$list = true; |
| 541 list.fixed$length = true; | 543 list.fixed$length = true; |
| 542 return list; | 544 return list; |
| 543 }; | 545 }; |
| 544 '''); | 546 '''); |
| 545 } | 547 } |
| 546 | 548 |
| 547 void emitStaticFinalFieldInitializations(StringBuffer buffer) { | 549 void emitStaticFinalFieldInitializations(StringBuffer buffer) { |
| 548 ConstantHandler handler = compiler.constantHandler; | 550 ConstantHandler handler = compiler.constantHandler; |
| 549 List<VariableElement> staticFinalFields = | 551 List<VariableElement> staticFinalFields = |
| 550 handler.getStaticFinalFieldsForEmission(); | 552 handler.getStaticFinalFieldsForEmission(); |
| 551 for (VariableElement element in staticFinalFields) { | 553 for (VariableElement element in staticFinalFields) { |
| 552 buffer.add('${namer.isolatePropertyAccess(element)} = '); | 554 buffer.add(isolatePrototype); |
| 555 buffer.add('.${namer.getName(element)} = '); |
| 553 compiler.withCurrentElement(element, () { | 556 compiler.withCurrentElement(element, () { |
| 554 handler.writeJsCodeForVariable(buffer, element); | 557 handler.writeJsCodeForVariable(buffer, element); |
| 555 }); | 558 }); |
| 556 buffer.add(';\n'); | 559 buffer.add(';\n'); |
| 557 } | 560 } |
| 558 } | 561 } |
| 559 | 562 |
| 560 void emitExtraAccessors(Element member, | 563 void emitExtraAccessors(Element member, |
| 561 String attachTo(String name), | 564 String attachTo(String name), |
| 562 StringBuffer buffer) { | 565 StringBuffer buffer) { |
| 563 if (member.kind == ElementKind.GETTER || member.kind == ElementKind.FIELD) { | 566 if (member.kind == ElementKind.GETTER || member.kind == ElementKind.FIELD) { |
| 564 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; | 567 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; |
| 565 if (selectors !== null && !selectors.isEmpty()) { | 568 if (selectors !== null && !selectors.isEmpty()) { |
| 566 compiler.emitter.emitCallStubForGetter( | 569 compiler.emitter.emitCallStubForGetter( |
| 567 buffer, attachTo, member, selectors); | 570 buffer, attachTo, member, selectors); |
| 568 } | 571 } |
| 569 } else if (member.kind == ElementKind.FUNCTION) { | 572 } else if (member.kind == ElementKind.FUNCTION) { |
| 570 if (compiler.universe.invokedGetters.contains(member.name)) { | 573 if (compiler.universe.invokedGetters.contains(member.name)) { |
| 571 compiler.emitter.emitDynamicFunctionGetter( | 574 compiler.emitter.emitDynamicFunctionGetter(buffer, attachTo, member); |
| 572 buffer, attachTo, member); | |
| 573 } | 575 } |
| 574 } | 576 } |
| 575 } | 577 } |
| 576 | 578 |
| 577 void emitNoSuchMethodCalls(StringBuffer buffer) { | 579 void emitNoSuchMethodCalls(StringBuffer buffer) { |
| 578 // Do not generate no such method calls if there is no class. | 580 // Do not generate no such method calls if there is no class. |
| 579 if (compiler.universe.instantiatedClasses.isEmpty()) return; | 581 if (compiler.universe.instantiatedClasses.isEmpty()) return; |
| 580 | 582 |
| 581 ClassElement objectClass = | 583 ClassElement objectClass = |
| 582 compiler.coreLibrary.find(const SourceString('Object')); | 584 compiler.coreLibrary.find(const SourceString('Object')); |
| 583 String className = namer.isolatePropertyAccess(objectClass); | 585 String className = namer.getName(objectClass); |
| 584 String prototype = '$className.prototype'; | 586 String prototype = '$isolatePrototype.$className.prototype'; |
| 587 String runtimeObjectPrototype = |
| 588 '${namer.isolateAccess(objectClass)}.prototype'; |
| 585 String noSuchMethodName = | 589 String noSuchMethodName = |
| 586 namer.instanceMethodName(null, Compiler.NO_SUCH_METHOD, 2); | 590 namer.instanceMethodName(null, Compiler.NO_SUCH_METHOD, 2); |
| 587 Collection<LibraryElement> libraries = | 591 Collection<LibraryElement> libraries = |
| 588 compiler.universe.libraries.getValues(); | 592 compiler.universe.libraries.getValues(); |
| 589 | 593 |
| 590 void generateMethod(String methodName, String jsName, Selector selector) { | 594 void generateMethod(String methodName, String jsName, Selector selector) { |
| 591 buffer.add('$prototype.$jsName = function'); | 595 buffer.add('$prototype.$jsName = function'); |
| 592 StringBuffer args = new StringBuffer(); | 596 StringBuffer args = new StringBuffer(); |
| 593 for (int i = 0; i < selector.argumentCount; i++) { | 597 for (int i = 0; i < selector.argumentCount; i++) { |
| 594 if (i != 0) args.add(', '); | 598 if (i != 0) args.add(', '); |
| 595 args.add('arg$i'); | 599 args.add('arg$i'); |
| 596 } | 600 } |
| 597 // We need to check if the object has a noSuchMethod. If not, it | 601 // We need to check if the object has a noSuchMethod. If not, it |
| 598 // means the object is a native object, and we can just call our | 602 // means the object is a native object, and we can just call our |
| 599 // generic noSuchMethod. Note that when calling this method, the | 603 // generic noSuchMethod. Note that when calling this method, the |
| 600 // 'this' object is not a Dart object. | 604 // 'this' object is not a Dart object. |
| 601 buffer.add(' ($args) {\n'); | 605 buffer.add(' ($args) {\n'); |
| 602 buffer.add(' return this.$noSuchMethodName\n'); | 606 buffer.add(' return this.$noSuchMethodName\n'); |
| 603 buffer.add(" ? this.$noSuchMethodName('$methodName', [$args])\n"); | 607 buffer.add(" ? this.$noSuchMethodName('$methodName', [$args])\n"); |
| 604 buffer.add(" : $objectClassName.prototype.$noSuchMethodName.call("); | 608 buffer.add(" : $runtimeObjectPrototype.$noSuchMethodName.call("); |
| 605 buffer.add("this, '$methodName', [$args])\n"); | 609 buffer.add("this, '$methodName', [$args])\n"); |
| 606 buffer.add('}\n'); | 610 buffer.add('}\n'); |
| 607 } | 611 } |
| 608 | 612 |
| 609 compiler.universe.invokedNames.forEach((SourceString methodName, | 613 compiler.universe.invokedNames.forEach((SourceString methodName, |
| 610 Set<Selector> selectors) { | 614 Set<Selector> selectors) { |
| 611 if (objectClass.lookupLocalMember(methodName) === null | 615 if (objectClass.lookupLocalMember(methodName) === null |
| 612 && methodName != Namer.OPERATOR_EQUALS) { | 616 && methodName != Namer.OPERATOR_EQUALS) { |
| 613 for (Selector selector in selectors) { | 617 for (Selector selector in selectors) { |
| 614 if (methodName.isPrivate()) { | 618 if (methodName.isPrivate()) { |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 711 ${mainCall}; | 715 ${mainCall}; |
| 712 } | 716 } |
| 713 """); | 717 """); |
| 714 } | 718 } |
| 715 | 719 |
| 716 String assembleProgram() { | 720 String assembleProgram() { |
| 717 measure(() { | 721 measure(() { |
| 718 mainBuffer.add('function ${namer.ISOLATE}() {'); | 722 mainBuffer.add('function ${namer.ISOLATE}() {'); |
| 719 emitStaticNonFinalFieldInitializations(mainBuffer); | 723 emitStaticNonFinalFieldInitializations(mainBuffer); |
| 720 mainBuffer.add('}\n\n'); | 724 mainBuffer.add('}\n\n'); |
| 725 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. |
| 726 isolatePrototype = namer.CURRENT_ISOLATE; |
| 727 mainBuffer.add('var $isolatePrototype = ${namer.ISOLATE}.prototype;\n'); |
| 721 emitClasses(mainBuffer); | 728 emitClasses(mainBuffer); |
| 722 emitStaticFunctions(mainBuffer); | 729 emitStaticFunctions(mainBuffer); |
| 723 emitStaticFunctionGetters(mainBuffer); | 730 emitStaticFunctionGetters(mainBuffer); |
| 724 emitCompileTimeConstants(mainBuffer); | 731 emitCompileTimeConstants(mainBuffer); |
| 725 emitStaticFinalFieldInitializations(mainBuffer); | 732 emitStaticFinalFieldInitializations(mainBuffer); |
| 726 nativeEmitter.emitDynamicDispatchMetadata(); | 733 |
| 734 isolatePrototype = '${namer.ISOLATE}.prototype;\n'; |
| 727 mainBuffer.add( | 735 mainBuffer.add( |
| 728 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); | 736 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); |
| 737 nativeEmitter.emitDynamicDispatchMetadata(); |
| 729 nativeEmitter.assembleCode(mainBuffer); | 738 nativeEmitter.assembleCode(mainBuffer); |
| 730 emitMain(mainBuffer); | 739 emitMain(mainBuffer); |
| 731 compiler.assembledCode = mainBuffer.toString(); | 740 compiler.assembledCode = mainBuffer.toString(); |
| 732 }); | 741 }); |
| 733 return compiler.assembledCode; | 742 return compiler.assembledCode; |
| 734 } | 743 } |
| 735 } | 744 } |
| OLD | NEW |