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 /** | 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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 43 : namer = compiler.namer, | 43 : namer = compiler.namer, |
| 44 nativeEmitter = new NativeEmitter(compiler), | 44 nativeEmitter = new NativeEmitter(compiler), |
| 45 generatedClasses = new Set<ClassElement>(), | 45 generatedClasses = new Set<ClassElement>(), |
| 46 mainBuffer = new StringBuffer(), | 46 mainBuffer = new StringBuffer(), |
| 47 super(compiler); | 47 super(compiler); |
| 48 | 48 |
| 49 String get name() => 'CodeEmitter'; | 49 String get name() => 'CodeEmitter'; |
| 50 | 50 |
| 51 String get inheritsName() => '${namer.ISOLATE}.\$inherits'; | 51 String get inheritsName() => '${namer.ISOLATE}.\$inherits'; |
| 52 | 52 |
| 53 String get objectClassName() { | |
| 54 ClassElement objectClass = | |
| 55 compiler.coreLibrary.find(const SourceString('Object')); | |
| 56 return namer.isolatePropertyAccess(objectClass); | |
| 57 } | |
| 58 | |
| 59 void addInheritFunctionIfNecessary() { | 53 void addInheritFunctionIfNecessary() { |
| 60 if (addedInheritFunction) return; | 54 if (addedInheritFunction) return; |
| 61 addedInheritFunction = true; | 55 addedInheritFunction = true; |
| 62 mainBuffer.add('$inheritsName = '); | 56 mainBuffer.add('$inheritsName = '); |
| 63 mainBuffer.add(INHERIT_FUNCTION); | 57 mainBuffer.add(INHERIT_FUNCTION); |
| 64 mainBuffer.add(';\n'); | 58 mainBuffer.add(';\n'); |
| 65 } | 59 } |
| 66 | 60 |
| 67 void addParameterStub(FunctionElement member, | 61 void addParameterStub(FunctionElement member, |
| 68 String attachTo(String invocationName), | 62 String attachTo(String invocationName), |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 178 FunctionParameters parameters = member.computeParameters(compiler); | 172 FunctionParameters parameters = member.computeParameters(compiler); |
| 179 for (Selector selector in selectors) { | 173 for (Selector selector in selectors) { |
| 180 if (!selector.applies(parameters)) continue; | 174 if (!selector.applies(parameters)) continue; |
| 181 addParameterStub(member, attachTo, buffer, selector, isNative); | 175 addParameterStub(member, attachTo, buffer, selector, isNative); |
| 182 } | 176 } |
| 183 } | 177 } |
| 184 | 178 |
| 185 void addInstanceMember(Element member, | 179 void addInstanceMember(Element member, |
| 186 String attachTo(String name), | 180 String attachTo(String name), |
| 187 StringBuffer buffer, | 181 StringBuffer buffer, |
| 182 String isolatePrototype, | |
| 188 [bool isNative = false]) { | 183 [bool isNative = false]) { |
| 189 // TODO(floitsch): we don't need to deal with members of | 184 // TODO(floitsch): we don't need to deal with members of |
| 190 // uninstantiated classes, that have been overwritten by subclasses. | 185 // uninstantiated classes, that have been overwritten by subclasses. |
| 191 | 186 |
| 192 if (member.kind === ElementKind.FUNCTION | 187 if (member.kind === ElementKind.FUNCTION |
| 193 || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY | 188 || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY |
| 194 || member.kind === ElementKind.GETTER | 189 || member.kind === ElementKind.GETTER |
| 195 || member.kind === ElementKind.SETTER) { | 190 || member.kind === ElementKind.SETTER) { |
| 196 if (member.modifiers !== null && member.modifiers.isAbstract()) return; | 191 if (member.modifiers !== null && member.modifiers.isAbstract()) return; |
| 197 String codeBlock = compiler.universe.generatedCode[member]; | 192 String codeBlock = compiler.universe.generatedCode[member]; |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 222 String getterName = namer.getterName(member.getLibrary(), member.name); | 217 String getterName = namer.getterName(member.getLibrary(), member.name); |
| 223 String name = | 218 String name = |
| 224 isNative ? member.name.slowToString() : namer.getName(member); | 219 isNative ? member.name.slowToString() : namer.getName(member); |
| 225 buffer.add('${attachTo(getterName)} = function(){\n'); | 220 buffer.add('${attachTo(getterName)} = function(){\n'); |
| 226 buffer.add(' return this.$name;\n};\n'); | 221 buffer.add(' return this.$name;\n};\n'); |
| 227 } | 222 } |
| 228 } else { | 223 } else { |
| 229 compiler.internalError('unexpected kind: "${member.kind}"', | 224 compiler.internalError('unexpected kind: "${member.kind}"', |
| 230 element: member); | 225 element: member); |
| 231 } | 226 } |
| 232 emitExtraAccessors(member, attachTo, buffer); | 227 emitExtraAccessors(member, attachTo, buffer, isolatePrototype); |
| 233 } | 228 } |
| 234 | 229 |
| 235 bool generateFieldInits(ClassElement classElement, | 230 bool generateFieldInits(ClassElement classElement, |
| 236 StringBuffer argumentsBuffer, | 231 StringBuffer argumentsBuffer, |
| 237 StringBuffer bodyBuffer) { | 232 StringBuffer bodyBuffer) { |
| 238 bool isFirst = true; | 233 bool isFirst = true; |
| 239 void generateFieldInit(ClassElement enclosingClass, Element member) { | 234 void generateFieldInit(ClassElement enclosingClass, Element member) { |
| 240 // TODO(floitsch): make sure there are no name clashes. | 235 // TODO(floitsch): make sure there are no name clashes. |
| 241 String className = namer.getName(enclosingClass); | 236 String className = namer.getName(enclosingClass); |
| 242 if (!isFirst) argumentsBuffer.add(', '); | 237 if (!isFirst) argumentsBuffer.add(', '); |
| 243 isFirst = false; | 238 isFirst = false; |
| 244 String memberName = namer.instanceFieldName(member.getLibrary(), | 239 String memberName = namer.instanceFieldName(member.getLibrary(), |
| 245 member.name); | 240 member.name); |
| 246 argumentsBuffer.add('${className}_$memberName'); | 241 argumentsBuffer.add('${className}_$memberName'); |
| 247 bodyBuffer.add(' this.$memberName = ${className}_$memberName;\n'); | 242 bodyBuffer.add(' this.$memberName = ${className}_$memberName;\n'); |
| 248 } | 243 } |
| 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, |
| 251 StringBuffer buffer, | |
| 252 String isolatePrototype) { | |
| 256 ClassElement superclass = cls.superclass; | 253 ClassElement superclass = cls.superclass; |
| 257 if (superclass !== null) { | 254 if (superclass !== null) { |
| 258 addInheritFunctionIfNecessary(); | 255 addInheritFunctionIfNecessary(); |
| 259 String className = namer.isolatePropertyAccess(cls); | 256 String className = namer.getName(cls); |
| 260 String superName = namer.isolatePropertyAccess(superclass); | 257 String superName = namer.getName(superclass); |
| 261 buffer.add('${inheritsName}($className, $superName);\n'); | 258 buffer.add('${inheritsName}($isolatePrototype.$className, '); |
| 259 buffer.add('$isolatePrototype.$superName);\n'); | |
| 262 } | 260 } |
| 263 } | 261 } |
| 264 | 262 |
| 265 void ensureGenerated(ClassElement classElement, StringBuffer buffer) { | 263 void ensureGenerated(ClassElement classElement, |
| 264 StringBuffer buffer, | |
| 265 String isolatePrototype) { | |
| 266 if (classElement == null) return; | 266 if (classElement == null) return; |
| 267 if (generatedClasses.contains(classElement)) return; | 267 if (generatedClasses.contains(classElement)) return; |
| 268 generatedClasses.add(classElement); | 268 generatedClasses.add(classElement); |
| 269 generateClass(classElement, buffer); | 269 generateClass(classElement, buffer, isolatePrototype); |
| 270 } | 270 } |
| 271 | 271 |
| 272 void generateClass(ClassElement classElement, StringBuffer buffer) { | 272 void generateClass(ClassElement classElement, |
| 273 ensureGenerated(classElement.superclass, buffer); | 273 StringBuffer buffer, |
| 274 String isolatePrototype) { | |
| 275 ensureGenerated(classElement.superclass, buffer, isolatePrototype); | |
| 274 | 276 |
| 275 if (classElement.isNative()) { | 277 if (classElement.isNative()) { |
| 276 nativeEmitter.generateNativeClass(classElement); | 278 nativeEmitter.generateNativeClass(classElement); |
| 277 return; | 279 return; |
| 278 } else { | 280 } else { |
| 279 // TODO(ngeoffray): Instead of switching between buffer, we | 281 // TODO(ngeoffray): Instead of switching between buffer, we |
| 280 // should create code sections, and decide where to emit them at | 282 // should create code sections, and decide where to emit them at |
| 281 // the end. | 283 // the end. |
| 282 buffer = mainBuffer; | 284 buffer = mainBuffer; |
| 283 } | 285 } |
| 284 | 286 |
| 285 String className = namer.isolatePropertyAccess(classElement); | 287 String className = '${isolatePrototype}.${namer.getName(classElement)}'; |
| 286 String constructorName = namer.safeName(classElement.name.slowToString()); | 288 String constructorName = namer.safeName(classElement.name.slowToString()); |
| 287 buffer.add('$className = function $constructorName('); | 289 buffer.add('$className = function $constructorName('); |
| 288 StringBuffer bodyBuffer = new StringBuffer(); | 290 StringBuffer bodyBuffer = new StringBuffer(); |
| 289 // If the class is never instantiated we still need to set it up for | 291 // 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. | 292 // inheritance purposes, but we can leave its JavaScript constructor empty. |
| 291 if (compiler.universe.instantiatedClasses.contains(classElement)) { | 293 if (compiler.universe.instantiatedClasses.contains(classElement)) { |
| 292 generateFieldInits(classElement, buffer, bodyBuffer); | 294 generateFieldInits(classElement, buffer, bodyBuffer); |
| 293 } | 295 } |
| 294 buffer.add(') {\n'); | 296 buffer.add(') {\n'); |
| 295 buffer.add(bodyBuffer); | 297 buffer.add(bodyBuffer); |
| 296 buffer.add('};\n'); | 298 buffer.add('};\n'); |
| 297 | 299 |
| 298 emitInherits(classElement, buffer); | 300 emitInherits(classElement, buffer, isolatePrototype); |
| 299 | 301 |
| 300 String attachTo(String name) => '$className.prototype.$name'; | 302 String attachTo(String name) => '$className.prototype.$name'; |
| 301 | 303 |
| 302 classElement.forEachMember(includeBackendMembers: true, | 304 classElement.forEachMember(includeBackendMembers: true, |
| 303 f: (ClassElement enclosing, Element member) { | 305 f: (ClassElement enclosing, Element member) { |
| 304 if (member.isInstanceMember()) { | 306 if (member.isInstanceMember()) { |
| 305 addInstanceMember(member, attachTo, buffer); | 307 addInstanceMember(member, attachTo, buffer, isolatePrototype); |
| 306 } | 308 } |
| 307 }); | 309 }); |
| 308 | 310 |
| 309 generateTypeTests(classElement, (Element other) { | 311 generateTypeTests(classElement, (Element other) { |
| 310 buffer.add('${attachTo(namer.operatorIs(other))} = '); | 312 buffer.add('${attachTo(namer.operatorIs(other))} = '); |
| 311 if (nativeEmitter.requiresNativeIsCheck(other)) { | 313 if (nativeEmitter.requiresNativeIsCheck(other)) { |
| 312 buffer.add('function() { return true; }'); | 314 buffer.add('function() { return true; }'); |
| 313 } else { | 315 } else { |
| 314 buffer.add('true'); | 316 buffer.add('true'); |
| 315 } | 317 } |
| 316 buffer.add(';\n'); | 318 buffer.add(';\n'); |
| 317 }); | 319 }); |
| 318 | 320 |
| 319 if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) { | 321 if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) { |
| 320 // Emit the noSuchMethods on the Object prototype now, so that | 322 // Emit the noSuchMethods on the Object prototype now, so that |
| 321 // the code in the dynamicMethod can find them. Note that the | 323 // the code in the dynamicMethod can find them. Note that the |
| 322 // code in dynamicMethod is invoked before analyzing the full JS | 324 // code in dynamicMethod is invoked before analyzing the full JS |
| 323 // script. | 325 // script. |
| 324 emitNoSuchMethodCalls(buffer); | 326 emitNoSuchMethodCalls(buffer, isolatePrototype); |
| 325 } | 327 } |
| 326 } | 328 } |
| 327 | 329 |
| 328 void generateTypeTests(ClassElement cls, | 330 void generateTypeTests(ClassElement cls, |
| 329 void generateTypeTest(ClassElement element)) { | 331 void generateTypeTest(ClassElement element)) { |
| 330 if (compiler.universe.isChecks.contains(cls)) { | 332 if (compiler.universe.isChecks.contains(cls)) { |
| 331 generateTypeTest(cls); | 333 generateTypeTest(cls); |
| 332 } | 334 } |
| 333 generateInterfacesIsTests(cls, generateTypeTest, new Set<Element>()); | 335 generateInterfacesIsTests(cls, generateTypeTest, new Set<Element>()); |
| 334 } | 336 } |
| 335 | 337 |
| 336 void generateInterfacesIsTests(ClassElement cls, | 338 void generateInterfacesIsTests(ClassElement cls, |
| 337 void generateTypeTest(ClassElement element), | 339 void generateTypeTest(ClassElement element), |
| 338 Set<Element> alreadyGenerated) { | 340 Set<Element> alreadyGenerated) { |
| 339 for (Type interfaceType in cls.interfaces) { | 341 for (Type interfaceType in cls.interfaces) { |
| 340 Element element = interfaceType.element; | 342 Element element = interfaceType.element; |
| 341 if (!alreadyGenerated.contains(element) && | 343 if (!alreadyGenerated.contains(element) && |
| 342 compiler.universe.isChecks.contains(element)) { | 344 compiler.universe.isChecks.contains(element)) { |
| 343 alreadyGenerated.add(element); | 345 alreadyGenerated.add(element); |
| 344 generateTypeTest(element); | 346 generateTypeTest(element); |
| 345 } | 347 } |
| 346 generateInterfacesIsTests(element, generateTypeTest, alreadyGenerated); | 348 generateInterfacesIsTests(element, generateTypeTest, alreadyGenerated); |
| 347 } | 349 } |
| 348 } | 350 } |
| 349 | 351 |
| 350 void emitClasses(StringBuffer buffer) { | 352 void emitClasses(StringBuffer buffer, String isolatePrototype) { |
| 351 for (ClassElement element in compiler.universe.instantiatedClasses) { | 353 for (ClassElement element in compiler.universe.instantiatedClasses) { |
| 352 ensureGenerated(element, buffer); | 354 ensureGenerated(element, buffer, isolatePrototype); |
| 353 } | 355 } |
| 354 } | 356 } |
| 355 | 357 |
| 356 void emitStaticFunctionsWithNamer(StringBuffer buffer, | 358 void emitStaticFunctionsWithNamer(StringBuffer buffer, |
| 359 String isolatePrototype, | |
| 357 Map<Element, String> generatedCode, | 360 Map<Element, String> generatedCode, |
| 358 String functionNamer(Element element)) { | 361 String functionNamer(Element element)) { |
| 359 generatedCode.forEach((Element element, String codeBlock) { | 362 generatedCode.forEach((Element element, String codeBlock) { |
| 360 if (!element.isInstanceMember()) { | 363 if (!element.isInstanceMember()) { |
| 361 buffer.add('${functionNamer(element)} = '); | 364 buffer.add(isolatePrototype); |
| 365 buffer.add('.${functionNamer(element)} = '); | |
| 362 buffer.add(codeBlock); | 366 buffer.add(codeBlock); |
| 363 buffer.add(';\n\n'); | 367 buffer.add(';\n\n'); |
| 364 } | 368 } |
| 365 }); | 369 }); |
| 366 } | 370 } |
| 367 | 371 |
| 368 void emitStaticFunctions(StringBuffer buffer) { | 372 void emitStaticFunctions(StringBuffer buffer, String isolatePrototype) { |
| 369 emitStaticFunctionsWithNamer(buffer, | 373 emitStaticFunctionsWithNamer(buffer, |
| 374 isolatePrototype, | |
| 370 compiler.universe.generatedCode, | 375 compiler.universe.generatedCode, |
| 371 namer.isolatePropertyAccess); | 376 namer.getName); |
| 372 emitStaticFunctionsWithNamer(buffer, | 377 emitStaticFunctionsWithNamer(buffer, |
| 378 isolatePrototype, | |
| 373 compiler.universe.generatedBailoutCode, | 379 compiler.universe.generatedBailoutCode, |
| 374 namer.isolateBailoutPropertyAccess); | 380 namer.getBailoutName); |
| 375 } | 381 } |
| 376 | 382 |
| 377 void emitStaticFunctionGetters(StringBuffer buffer) { | 383 void emitStaticFunctionGetters(StringBuffer buffer, String isolatePrototype) { |
| 378 Set<FunctionElement> functionsNeedingGetter = | 384 Set<FunctionElement> functionsNeedingGetter = |
| 379 compiler.universe.staticFunctionsNeedingGetter; | 385 compiler.universe.staticFunctionsNeedingGetter; |
| 380 for (FunctionElement element in functionsNeedingGetter) { | 386 for (FunctionElement element in functionsNeedingGetter) { |
| 381 // The static function does not have the correct name. Since | 387 // The static function does not have the correct name. Since |
| 382 // [addParameterStubs] use the name to create its stubs we simply | 388 // [addParameterStubs] use the name to create its stubs we simply |
| 383 // create a fake element with the correct name. | 389 // create a fake element with the correct name. |
| 384 // Note: the callElement will not have any enclosingElement. | 390 // Note: the callElement will not have any enclosingElement. |
| 385 FunctionElement callElement = | 391 FunctionElement callElement = |
| 386 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, element); | 392 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, element); |
| 387 String staticName = namer.isolatePropertyAccess(element); | 393 String staticName = namer.getName(element); |
| 388 int parameterCount = element.parameterCount(compiler); | 394 int parameterCount = element.parameterCount(compiler); |
| 389 String invocationName = | 395 String invocationName = |
| 390 namer.instanceMethodName(element.getLibrary(), callElement.name, | 396 namer.instanceMethodName(element.getLibrary(), callElement.name, |
| 391 parameterCount); | 397 parameterCount); |
| 392 buffer.add("$staticName.$invocationName = $staticName;\n"); | 398 buffer.add(isolatePrototype); |
| 393 addParameterStubs(callElement, (name) => '$staticName.$name', buffer); | 399 buffer.add(".$staticName.$invocationName = "); |
| 400 buffer.add(isolatePrototype); | |
| 401 buffer.add(".$staticName;\n"); | |
| 402 addParameterStubs(callElement, | |
| 403 (name) => '$isolatePrototype.$staticName.$name', | |
| 404 buffer); | |
| 394 } | 405 } |
| 395 } | 406 } |
| 396 | 407 |
| 397 void emitDynamicFunctionGetter(StringBuffer buffer, | 408 void emitDynamicFunctionGetter(StringBuffer buffer, |
| 409 String isolatePrototype, | |
| 398 String attachTo(String invocationName), | 410 String attachTo(String invocationName), |
| 399 FunctionElement member) { | 411 FunctionElement member) { |
| 400 // For every method that has the same name as a property-get we create a | 412 // 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 | 413 // 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 | 414 // 'foo' and somewhere in the code there is a dynamic property get of |
| 403 // 'foo'. Then we generate the following code (in pseudo Dart): | 415 // 'foo'. Then we generate the following code (in pseudo Dart): |
| 404 // | 416 // |
| 405 // class A { | 417 // class A { |
| 406 // foo(x, y, z) { ... } // Original function. | 418 // foo(x, y, z) { ... } // Original function. |
| 407 // get foo() { return new BoundClosure499(this); } | 419 // get foo() { return new BoundClosure499(this); } |
| 408 // } | 420 // } |
| 409 // class BoundClosure499 extends Closure { | 421 // class BoundClosure499 extends Closure { |
| 410 // var self; | 422 // var self; |
| 411 // BoundClosure499(this.self); | 423 // BoundClosure499(this.self); |
| 412 // $call3(x, y, z) { return self.foo(x, y, z); } | 424 // $call3(x, y, z) { return self.foo(x, y, z); } |
| 413 // } | 425 // } |
| 414 | 426 |
| 415 // TODO(floitsch): share the closure classes with other classes | 427 // TODO(floitsch): share the closure classes with other classes |
| 416 // if they share methods with the same signature. | 428 // if they share methods with the same signature. |
| 417 | 429 |
| 418 // The closure class. | 430 // The closure class. |
| 419 SourceString name = const SourceString("BoundClosure"); | 431 SourceString name = const SourceString("BoundClosure"); |
| 420 ClassElement closureClassElement = | 432 ClassElement closureClassElement = |
| 421 new ClosureClassElement(compiler, member.getCompilationUnit()); | 433 new ClosureClassElement(compiler, member.getCompilationUnit()); |
| 422 String isolateAccess = namer.isolatePropertyAccess(closureClassElement); | 434 String mangledName = namer.getName(closureClassElement); |
| 423 ensureGenerated(closureClassElement.superclass, buffer); | 435 ensureGenerated(closureClassElement.superclass, buffer, isolatePrototype); |
| 424 | 436 |
| 425 // Define the constructor with a name so that Object.toString can | 437 // Define the constructor with a name so that Object.toString can |
| 426 // find the class name of the closure class. | 438 // find the class name of the closure class. |
| 427 buffer.add("$isolateAccess = function $name(self) "); | 439 buffer.add(isolatePrototype); |
|
Lasse Reichstein Nielsen
2012/04/12 09:45:32
We should add an "<<" operator to StringBuffer :)
floitsch
2012/04/12 11:26:56
hehe.
| |
| 440 buffer.add(".$mangledName = function $name(self) "); | |
| 428 buffer.add("{ this.self = self; };\n"); | 441 buffer.add("{ this.self = self; };\n"); |
| 429 emitInherits(closureClassElement, buffer); | 442 emitInherits(closureClassElement, buffer, isolatePrototype); |
| 430 | 443 |
| 431 String prototype = "$isolateAccess.prototype"; | 444 String prototype = "$isolatePrototype.$mangledName.prototype"; |
| 432 | 445 |
| 433 // Now add the methods on the closure class. The instance method does not | 446 // 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 | 447 // have the correct name. Since [addParameterStubs] use the name to create |
| 435 // its stubs we simply create a fake element with the correct name. | 448 // its stubs we simply create a fake element with the correct name. |
| 436 // Note: the callElement will not have any enclosingElement. | 449 // Note: the callElement will not have any enclosingElement. |
| 437 FunctionElement callElement = | 450 FunctionElement callElement = |
| 438 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); | 451 new ClosureInvocationElement(Namer.CLOSURE_INVOCATION_NAME, member); |
| 439 | 452 |
| 440 int parameterCount = member.parameterCount(compiler); | 453 int parameterCount = member.parameterCount(compiler); |
| 441 String invocationName = | 454 String invocationName = |
| 442 namer.instanceMethodName(member.getLibrary(), | 455 namer.instanceMethodName(member.getLibrary(), |
| 443 callElement.name, parameterCount); | 456 callElement.name, parameterCount); |
| 444 String targetName = namer.instanceMethodName(member.getLibrary(), | 457 String targetName = namer.instanceMethodName(member.getLibrary(), |
| 445 member.name, parameterCount); | 458 member.name, parameterCount); |
| 446 List<String> arguments = new List<String>(parameterCount); | 459 List<String> arguments = new List<String>(parameterCount); |
| 447 for (int i = 0; i < parameterCount; i++) { | 460 for (int i = 0; i < parameterCount; i++) { |
| 448 arguments[i] = "arg$i"; | 461 arguments[i] = "arg$i"; |
| 449 } | 462 } |
| 450 String joinedArgs = Strings.join(arguments, ", "); | 463 String joinedArgs = Strings.join(arguments, ", "); |
| 451 buffer.add("$prototype.$invocationName = function($joinedArgs) {\n"); | 464 buffer.add("$prototype.$invocationName = function($joinedArgs) {\n"); |
| 452 buffer.add(" return this.self.$targetName($joinedArgs);\n"); | 465 buffer.add(" return this.self.$targetName($joinedArgs);\n"); |
| 453 buffer.add("};\n"); | 466 buffer.add("};\n"); |
| 454 addParameterStubs(callElement, | 467 addParameterStubs(callElement, |
| 455 (invocationName) => '$prototype.$invocationName', | 468 (stubName) => '$prototype.$stubName', |
| 456 buffer); | 469 buffer); |
| 457 | 470 |
| 458 // And finally the getter. | 471 // And finally the getter. |
| 459 String getterName = namer.getterName(member.getLibrary(), member.name); | 472 String getterName = namer.getterName(member.getLibrary(), member.name); |
| 460 String closureClass = namer.isolateAccess(closureClassElement); | 473 String closureClass = namer.isolateAccess(closureClassElement); |
| 461 buffer.add("${attachTo(getterName)} = function() {\n"); | 474 buffer.add("${attachTo(getterName)} = function() {\n"); |
| 462 buffer.add(" return new $closureClass(this);\n"); | 475 buffer.add(" return new $closureClass(this);\n"); |
| 463 buffer.add("};\n"); | 476 buffer.add("};\n"); |
| 464 } | 477 } |
| 465 | 478 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 506 if (!staticNonFinalFields.isEmpty()) buffer.add('\n'); | 519 if (!staticNonFinalFields.isEmpty()) buffer.add('\n'); |
| 507 for (Element element in staticNonFinalFields) { | 520 for (Element element in staticNonFinalFields) { |
| 508 buffer.add(' this.${namer.getName(element)} = '); | 521 buffer.add(' this.${namer.getName(element)} = '); |
| 509 compiler.withCurrentElement(element, () { | 522 compiler.withCurrentElement(element, () { |
| 510 handler.writeJsCodeForVariable(buffer, element); | 523 handler.writeJsCodeForVariable(buffer, element); |
| 511 }); | 524 }); |
| 512 buffer.add(';\n'); | 525 buffer.add(';\n'); |
| 513 } | 526 } |
| 514 } | 527 } |
| 515 | 528 |
| 516 void emitCompileTimeConstants(StringBuffer buffer) { | 529 void emitCompileTimeConstants(StringBuffer buffer, String isolatePrototype) { |
| 517 ConstantHandler handler = compiler.constantHandler; | 530 ConstantHandler handler = compiler.constantHandler; |
| 518 List<Constant> constants = handler.getConstantsForEmission(); | 531 List<Constant> constants = handler.getConstantsForEmission(); |
| 519 String prototype = "${namer.ISOLATE}.prototype"; | |
| 520 bool addedMakeConstantList = false; | 532 bool addedMakeConstantList = false; |
| 521 for (Constant constant in constants) { | 533 for (Constant constant in constants) { |
| 522 if (!addedMakeConstantList && constant.isList()) { | 534 if (!addedMakeConstantList && constant.isList()) { |
| 523 addedMakeConstantList = true; | 535 addedMakeConstantList = true; |
| 524 emitMakeConstantList(prototype, buffer); | 536 emitMakeConstantList(buffer, isolatePrototype); |
| 525 } | 537 } |
| 526 String name = handler.getNameForConstant(constant); | 538 String name = handler.getNameForConstant(constant); |
| 527 buffer.add('$prototype.$name = '); | 539 buffer.add('$isolatePrototype.$name = '); |
| 528 handler.writeJsCode(buffer, constant); | 540 handler.writeJsCode(buffer, constant); |
| 529 buffer.add(';\n'); | 541 buffer.add(';\n'); |
| 530 } | 542 } |
| 531 } | 543 } |
| 532 | 544 |
| 533 void emitMakeConstantList(String prototype, StringBuffer buffer) { | 545 void emitMakeConstantList(StringBuffer buffer, String isolatePrototype) { |
| 534 buffer.add(prototype); | 546 buffer.add(isolatePrototype); |
| 535 buffer.add(@'''.makeConstantList = function(list) { | 547 buffer.add(@'''.makeConstantList = function(list) { |
| 536 list.immutable$list = true; | 548 list.immutable$list = true; |
| 537 list.fixed$length = true; | 549 list.fixed$length = true; |
| 538 return list; | 550 return list; |
| 539 }; | 551 }; |
| 540 '''); | 552 '''); |
| 541 } | 553 } |
| 542 | 554 |
| 543 void emitStaticFinalFieldInitializations(StringBuffer buffer) { | 555 void emitStaticFinalFieldInitializations(StringBuffer buffer, |
| 556 String isolatePrototype) { | |
| 544 ConstantHandler handler = compiler.constantHandler; | 557 ConstantHandler handler = compiler.constantHandler; |
| 545 List<VariableElement> staticFinalFields = | 558 List<VariableElement> staticFinalFields = |
| 546 handler.getStaticFinalFieldsForEmission(); | 559 handler.getStaticFinalFieldsForEmission(); |
| 547 for (VariableElement element in staticFinalFields) { | 560 for (VariableElement element in staticFinalFields) { |
| 548 buffer.add('${namer.isolatePropertyAccess(element)} = '); | 561 buffer.add(isolatePrototype); |
| 562 buffer.add('.${namer.getName(element)} = '); | |
| 549 compiler.withCurrentElement(element, () { | 563 compiler.withCurrentElement(element, () { |
| 550 handler.writeJsCodeForVariable(buffer, element); | 564 handler.writeJsCodeForVariable(buffer, element); |
| 551 }); | 565 }); |
| 552 buffer.add(';\n'); | 566 buffer.add(';\n'); |
| 553 } | 567 } |
| 554 } | 568 } |
| 555 | 569 |
| 556 void emitExtraAccessors(Element member, | 570 void emitExtraAccessors(Element member, |
| 557 String attachTo(String name), | 571 String attachTo(String name), |
| 558 StringBuffer buffer) { | 572 StringBuffer buffer, |
| 573 String isolatePrototype) { | |
| 559 if (member.kind == ElementKind.GETTER || member.kind == ElementKind.FIELD) { | 574 if (member.kind == ElementKind.GETTER || member.kind == ElementKind.FIELD) { |
| 560 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; | 575 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; |
| 561 if (selectors !== null && !selectors.isEmpty()) { | 576 if (selectors !== null && !selectors.isEmpty()) { |
| 562 compiler.emitter.emitCallStubForGetter( | 577 compiler.emitter.emitCallStubForGetter( |
| 563 buffer, attachTo, member, selectors); | 578 buffer, attachTo, member, selectors); |
| 564 } | 579 } |
| 565 } else if (member.kind == ElementKind.FUNCTION) { | 580 } else if (member.kind == ElementKind.FUNCTION) { |
| 566 if (compiler.universe.invokedGetters.contains(member.name)) { | 581 if (compiler.universe.invokedGetters.contains(member.name)) { |
| 567 compiler.emitter.emitDynamicFunctionGetter( | 582 compiler.emitter.emitDynamicFunctionGetter( |
| 568 buffer, attachTo, member); | 583 buffer, isolatePrototype, attachTo, member); |
| 569 } | 584 } |
| 570 } | 585 } |
| 571 } | 586 } |
| 572 | 587 |
| 573 void emitNoSuchMethodCalls(StringBuffer buffer) { | 588 void emitNoSuchMethodCalls(StringBuffer buffer, String isolatePrototype) { |
|
Lasse Reichstein Nielsen
2012/04/12 09:45:32
Instead of passing isolatePrototype everywhere, co
floitsch
2012/04/12 11:26:56
Done.
| |
| 574 // Do not generate no such method calls if there is no class. | 589 // Do not generate no such method calls if there is no class. |
| 575 if (compiler.universe.instantiatedClasses.isEmpty()) return; | 590 if (compiler.universe.instantiatedClasses.isEmpty()) return; |
| 576 | 591 |
| 577 ClassElement objectClass = | 592 ClassElement objectClass = |
| 578 compiler.coreLibrary.find(const SourceString('Object')); | 593 compiler.coreLibrary.find(const SourceString('Object')); |
| 579 String className = namer.isolatePropertyAccess(objectClass); | 594 String className = namer.getName(objectClass); |
| 580 String prototype = '$className.prototype'; | 595 String prototype = '$isolatePrototype.$className.prototype'; |
| 596 String runtimeObjectPrototype = | |
| 597 '${namer.isolateAccess(objectClass)}.prototype'; | |
| 581 String noSuchMethodName = | 598 String noSuchMethodName = |
| 582 namer.instanceMethodName(null, Compiler.NO_SUCH_METHOD, 2); | 599 namer.instanceMethodName(null, Compiler.NO_SUCH_METHOD, 2); |
| 583 Collection<LibraryElement> libraries = | 600 Collection<LibraryElement> libraries = |
| 584 compiler.universe.libraries.getValues(); | 601 compiler.universe.libraries.getValues(); |
| 585 | 602 |
| 586 void generateMethod(String methodName, String jsName, Selector selector) { | 603 void generateMethod(String methodName, String jsName, Selector selector) { |
| 587 buffer.add('$prototype.$jsName = function'); | 604 buffer.add('$prototype.$jsName = function'); |
| 588 StringBuffer args = new StringBuffer(); | 605 StringBuffer args = new StringBuffer(); |
| 589 for (int i = 0; i < selector.argumentCount; i++) { | 606 for (int i = 0; i < selector.argumentCount; i++) { |
| 590 if (i != 0) args.add(', '); | 607 if (i != 0) args.add(', '); |
| 591 args.add('arg$i'); | 608 args.add('arg$i'); |
| 592 } | 609 } |
| 593 // We need to check if the object has a noSuchMethod. If not, it | 610 // We need to check if the object has a noSuchMethod. If not, it |
| 594 // means the object is a native object, and we can just call our | 611 // means the object is a native object, and we can just call our |
| 595 // generic noSuchMethod. Note that when calling this method, the | 612 // generic noSuchMethod. Note that when calling this method, the |
| 596 // 'this' object is not a Dart object. | 613 // 'this' object is not a Dart object. |
| 597 buffer.add(' ($args) {\n'); | 614 buffer.add(' ($args) {\n'); |
| 598 buffer.add(' return this.$noSuchMethodName\n'); | 615 buffer.add(' return this.$noSuchMethodName\n'); |
| 599 buffer.add(" ? this.$noSuchMethodName('$methodName', [$args])\n"); | 616 buffer.add(" ? this.$noSuchMethodName('$methodName', [$args])\n"); |
| 600 buffer.add(" : $objectClassName.prototype.$noSuchMethodName.call("); | 617 buffer.add(" : $runtimeObjectPrototype.$noSuchMethodName.call("); |
| 601 buffer.add("this, '$methodName', [$args])\n"); | 618 buffer.add("this, '$methodName', [$args])\n"); |
| 602 buffer.add('}\n'); | 619 buffer.add('}\n'); |
| 603 } | 620 } |
| 604 | 621 |
| 605 compiler.universe.invokedNames.forEach((SourceString methodName, | 622 compiler.universe.invokedNames.forEach((SourceString methodName, |
| 606 Set<Selector> selectors) { | 623 Set<Selector> selectors) { |
| 607 if (objectClass.lookupLocalMember(methodName) === null | 624 if (objectClass.lookupLocalMember(methodName) === null |
| 608 && methodName != Namer.OPERATOR_EQUALS) { | 625 && methodName != Namer.OPERATOR_EQUALS) { |
| 609 for (Selector selector in selectors) { | 626 for (Selector selector in selectors) { |
| 610 if (methodName.isPrivate()) { | 627 if (methodName.isPrivate()) { |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 706 } else { | 723 } else { |
| 707 ${mainCall}; | 724 ${mainCall}; |
| 708 } | 725 } |
| 709 """); | 726 """); |
| 710 } | 727 } |
| 711 | 728 |
| 712 String assembleProgram() { | 729 String assembleProgram() { |
| 713 measure(() { | 730 measure(() { |
| 714 mainBuffer.add('function ${namer.ISOLATE}() {'); | 731 mainBuffer.add('function ${namer.ISOLATE}() {'); |
| 715 emitStaticNonFinalFieldInitializations(mainBuffer); | 732 emitStaticNonFinalFieldInitializations(mainBuffer); |
| 716 mainBuffer.add('}\n\n'); | 733 mainBuffer.add('};\n\n'); |
| 717 emitClasses(mainBuffer); | 734 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. |
| 718 emitStaticFunctions(mainBuffer); | 735 String isolatePrototype = namer.CURRENT_ISOLATE; |
| 719 emitStaticFunctionGetters(mainBuffer); | 736 mainBuffer.add('var $isolatePrototype = ${namer.ISOLATE}.prototype;\n'); |
| 720 emitCompileTimeConstants(mainBuffer); | 737 emitClasses(mainBuffer, isolatePrototype); |
| 721 emitStaticFinalFieldInitializations(mainBuffer); | 738 emitStaticFunctions(mainBuffer, isolatePrototype); |
| 722 nativeEmitter.emitDynamicDispatchMetadata(); | 739 emitStaticFunctionGetters(mainBuffer, isolatePrototype); |
| 740 emitCompileTimeConstants(mainBuffer, isolatePrototype); | |
| 741 emitStaticFinalFieldInitializations(mainBuffer, isolatePrototype); | |
| 742 | |
| 723 mainBuffer.add( | 743 mainBuffer.add( |
| 724 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); | 744 'var ${namer.CURRENT_ISOLATE} = new ${namer.ISOLATE}();\n'); |
| 745 nativeEmitter.emitDynamicDispatchMetadata(); | |
| 725 nativeEmitter.assembleCode(mainBuffer); | 746 nativeEmitter.assembleCode(mainBuffer); |
| 726 emitMain(mainBuffer); | 747 emitMain(mainBuffer); |
| 727 compiler.assembledCode = mainBuffer.toString(); | 748 compiler.assembledCode = mainBuffer.toString(); |
| 728 }); | 749 }); |
| 729 return compiler.assembledCode; | 750 return compiler.assembledCode; |
| 730 } | 751 } |
| 731 } | 752 } |
| OLD | NEW |