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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 45 => '${namer.ISOLATE}.\$defineClass'; | 45 => '${namer.ISOLATE}.\$defineClass'; |
| 46 String get finishClassesName() | 46 String get finishClassesName() |
| 47 => '${namer.ISOLATE}.\$finishClasses'; | 47 => '${namer.ISOLATE}.\$finishClasses'; |
| 48 String get finishIsolateConstructorName() | 48 String get finishIsolateConstructorName() |
| 49 => '${namer.ISOLATE}.\$finishIsolateConstructor'; | 49 => '${namer.ISOLATE}.\$finishIsolateConstructor'; |
| 50 String get pendingClassesName() | 50 String get pendingClassesName() |
| 51 => '${namer.ISOLATE}.\$pendingClasses'; | 51 => '${namer.ISOLATE}.\$pendingClasses'; |
| 52 String get isolatePropertiesName() | 52 String get isolatePropertiesName() |
| 53 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; | 53 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; |
| 54 | 54 |
| 55 final String GETTER_SUFFIX = "?"; | |
| 56 final String SETTER_SUFFIX = "!"; | |
| 57 final String GETTER_SETTER_SUFFIX = "="; | |
| 58 | |
| 55 String get defineClassFunction() { | 59 String get defineClassFunction() { |
| 56 // First the class name, then the super class name, followed by the fields | 60 // First the class name, then the super class name, followed by the fields |
| 57 // (in an array) and the members (inside an Object literal). | 61 // (in an array) and the members (inside an Object literal). |
| 58 // The caller can also pass in the constructor as a function if needed. | 62 // The caller can also pass in the constructor as a function if needed. |
| 59 // | 63 // |
| 60 // Example: | 64 // Example: |
| 61 // defineClass("A", "B", ["x", "y"], { | 65 // defineClass("A", "B", ["x", "y"], { |
| 62 // foo$1: function(y) { | 66 // foo$1: function(y) { |
| 63 // print(this.x + y); | 67 // print(this.x + y); |
| 64 // }, | 68 // }, |
| 65 // bar$2: function(t, v) { | 69 // bar$2: function(t, v) { |
| 66 // this.x = t - v; | 70 // this.x = t - v; |
| 67 // }, | 71 // }, |
| 68 // }); | 72 // }); |
| 69 return """ | 73 return """ |
| 70 function(cls, superclass, fields, prototype) { | 74 function(cls, superclass, fields, prototype) { |
| 71 var constructor; | 75 var constructor; |
| 72 if (typeof fields == 'function') { | 76 if (typeof fields == 'function') { |
| 73 constructor = fields; | 77 constructor = fields; |
| 74 } else { | 78 } else { |
| 75 var str = "(function " + cls + "("; | 79 var str = "(function " + cls + "("; |
| 76 var body = ""; | 80 var body = ""; |
| 77 for (var i = 0; i < fields.length; i++) { | 81 for (var i = 0; i < fields.length; i++) { |
| 78 if (i != 0) str += ", "; | 82 if (i != 0) str += ", "; |
| 79 str += fields[i]; | 83 var field = fields[i]; |
| 80 body += "this." + fields[i] + " = " + fields[i] + ";\\n"; | 84 var len = field.length; |
| 85 var lastChar = field[len - 1]; | |
| 86 var needsGetter = false; | |
| 87 var needsSetter = false; | |
| 88 switch (lastChar) { | |
| 89 case '$GETTER_SUFFIX': needsGetter = true; break; | |
|
kasperl
2012/05/09 14:07:49
Indent cases.
floitsch
2012/05/09 14:11:19
Done.
| |
| 90 case '$GETTER_SETTER_SUFFIX': needsGetter = true; // fallthrough. | |
|
kasperl
2012/05/09 14:07:49
fallthrough -> Fall-through
floitsch
2012/05/09 14:11:19
Done.
| |
| 91 case '$SETTER_SUFFIX': needsSetter = true; | |
| 92 } | |
| 93 if (needsGetter || needsSetter) field = field.substring(0, len - 1); | |
| 94 str += field; | |
| 95 body += "this." + field + " = " + field + ";\\n"; | |
| 96 if (needsGetter) { | |
| 97 var getterString = "return this." + field + ";"; | |
| 98 prototype["get\$" + field] = new Function(getterString); | |
| 99 } | |
| 100 if (needsSetter) { | |
| 101 var setterString = "this." + field + " = v;"; | |
| 102 prototype["set\$" + field] = new Function("v", setterString); | |
| 103 } | |
| 81 } | 104 } |
| 82 str += ") {" + body + "})"; | 105 str += ") {" + body + "})"; |
| 83 constructor = eval(str); | 106 constructor = eval(str); |
| 84 } | 107 } |
| 85 $isolatePropertiesName[cls] = constructor; | 108 $isolatePropertiesName[cls] = constructor; |
| 86 constructor.prototype = prototype; | 109 constructor.prototype = prototype; |
| 87 if (superclass !== "") { | 110 if (superclass !== "") { |
| 88 $pendingClassesName[cls] = superclass; | 111 $pendingClassesName[cls] = superclass; |
| 89 } | 112 } |
| 90 }"""; | 113 }"""; |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 void defineInstanceMember(String invocationName, | 342 void defineInstanceMember(String invocationName, |
| 320 String definition)) { | 343 String definition)) { |
| 321 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; | 344 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; |
| 322 if (selectors == null) return; | 345 if (selectors == null) return; |
| 323 for (Selector selector in selectors) { | 346 for (Selector selector in selectors) { |
| 324 if (!selector.applies(member, compiler)) continue; | 347 if (!selector.applies(member, compiler)) continue; |
| 325 addParameterStub(member, selector, defineInstanceMember); | 348 addParameterStub(member, selector, defineInstanceMember); |
| 326 } | 349 } |
| 327 } | 350 } |
| 328 | 351 |
| 352 bool instanceFieldNeedsGetter(Element member) { | |
| 353 assert(member.kind === ElementKind.FIELD); | |
| 354 return compiler.universe.hasGetter(member, compiler); | |
| 355 } | |
| 356 | |
| 357 bool instanceFieldNeedsSetter(Element member) { | |
| 358 assert(member.kind === ElementKind.FIELD); | |
| 359 return (member.modifiers === null || !member.modifiers.isFinal()) | |
| 360 && compiler.universe.hasSetter(member, compiler); | |
| 361 } | |
| 362 | |
| 363 String compiledFieldName(Element member) { | |
| 364 assert(member.kind === ElementKind.FIELD); | |
| 365 return member.isNative() | |
| 366 ? member.name.slowToString() | |
| 367 : namer.getName(member); | |
| 368 } | |
| 369 | |
| 329 void addInstanceMember(Element member, | 370 void addInstanceMember(Element member, |
| 371 bool needGettersAndSetters, | |
| 330 void defineInstanceMember(String invocationName, | 372 void defineInstanceMember(String invocationName, |
| 331 String definition)) { | 373 String definition)) { |
| 332 // TODO(floitsch): we don't need to deal with members of | 374 // TODO(floitsch): we don't need to deal with members of |
| 333 // uninstantiated classes, that have been overwritten by subclasses. | 375 // uninstantiated classes, that have been overwritten by subclasses. |
| 334 | 376 |
| 335 if (member.kind === ElementKind.FUNCTION | 377 if (member.kind === ElementKind.FUNCTION |
| 336 || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY | 378 || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY |
| 337 || member.kind === ElementKind.GETTER | 379 || member.kind === ElementKind.GETTER |
| 338 || member.kind === ElementKind.SETTER) { | 380 || member.kind === ElementKind.SETTER) { |
| 339 if (member.modifiers !== null && member.modifiers.isAbstract()) return; | 381 if (member.modifiers !== null && member.modifiers.isAbstract()) return; |
| 340 String codeBlock = compiler.universe.generatedCode[member]; | 382 String codeBlock = compiler.universe.generatedCode[member]; |
| 341 if (codeBlock == null) return; | 383 if (codeBlock == null) return; |
| 342 defineInstanceMember(namer.getName(member), codeBlock); | 384 defineInstanceMember(namer.getName(member), codeBlock); |
| 343 codeBlock = compiler.universe.generatedBailoutCode[member]; | 385 codeBlock = compiler.universe.generatedBailoutCode[member]; |
| 344 if (codeBlock !== null) { | 386 if (codeBlock !== null) { |
| 345 defineInstanceMember(compiler.namer.getBailoutName(member), codeBlock); | 387 defineInstanceMember(compiler.namer.getBailoutName(member), codeBlock); |
| 346 } | 388 } |
| 347 FunctionElement function = member; | 389 FunctionElement function = member; |
| 348 FunctionSignature parameters = function.computeSignature(compiler); | 390 FunctionSignature parameters = function.computeSignature(compiler); |
| 349 if (!parameters.optionalParameters.isEmpty()) { | 391 if (!parameters.optionalParameters.isEmpty()) { |
| 350 addParameterStubs(member, defineInstanceMember); | 392 addParameterStubs(member, defineInstanceMember); |
| 351 } | 393 } |
| 352 } else if (member.kind === ElementKind.FIELD) { | 394 } else if (member.kind === ElementKind.FIELD) { |
| 353 // TODO(ngeoffray): Have another class generate the code for the | 395 // Getters and setters for non native members are generated dynamically. |
|
kasperl
2012/05/09 14:07:49
non-native
floitsch
2012/05/09 14:11:19
forgot to upload latest cosmetic changes patchset.
| |
| 354 // fields. | 396 if (needGettersAndSetters) { |
| 355 if ((member.modifiers === null || !member.modifiers.isFinal()) && | 397 if (instanceFieldNeedsGetter(member)) { |
| 356 compiler.universe.hasSetter(member, compiler)) { | 398 String getter = namer.getterName(member.getLibrary(), member.name); |
| 357 String setterName = namer.setterName(member.getLibrary(), member.name); | 399 String name = compiledFieldName(member); |
| 358 String name = member.isNative() | 400 defineInstanceMember(getter, "function() { return this.$name; }"); |
| 359 ? member.name.slowToString() | 401 } |
| 360 : namer.getName(member); | 402 |
| 361 defineInstanceMember(setterName, "function(v) { this.$name = v; }"); | 403 if (instanceFieldNeedsSetter(member)) { |
| 362 } | 404 String setter = namer.setterName(member.getLibrary(), member.name); |
| 363 if (compiler.universe.hasGetter(member, compiler)) { | 405 String name = compiledFieldName(member); |
| 364 String getterName = namer.getterName(member.getLibrary(), member.name); | 406 defineInstanceMember(setter, "function(v) { this.$name = v; }"); |
| 365 String name = member.isNative() | 407 } |
| 366 ? member.name.slowToString() | |
| 367 : namer.getName(member); | |
| 368 defineInstanceMember(getterName, "function() { return this.$name; }"); | |
| 369 } | 408 } |
| 370 } else { | 409 } else { |
| 371 compiler.internalError('unexpected kind: "${member.kind}"', | 410 compiler.internalError('unexpected kind: "${member.kind}"', |
| 372 element: member); | 411 element: member); |
| 373 } | 412 } |
| 374 emitExtraAccessors(member, defineInstanceMember); | 413 emitExtraAccessors(member, defineInstanceMember); |
| 375 } | 414 } |
| 376 | 415 |
| 377 List<String> generateFieldList(ClassElement classElement) { | 416 Set<Element> emitClassFields(ClassElement classElement, StringBuffer buffer) { |
| 378 List<String> result = <String>[]; | 417 // If the class is never instantiated we still need to set it up for |
| 418 // inheritance purposes, but we can simplify its JavaScript constructor. | |
| 419 bool isInstantiated = | |
| 420 compiler.universe.instantiatedClasses.contains(classElement); | |
| 421 | |
| 422 bool isFirstField = true; | |
| 379 void addField(ClassElement enclosingClass, Element member) { | 423 void addField(ClassElement enclosingClass, Element member) { |
| 380 result.add(namer.instanceFieldName(member.getLibrary(), member.name)); | 424 assert(!member.isNative()); |
| 425 LibraryElement library = member.getLibrary(); | |
| 426 SourceString name = member.name; | |
| 427 String fieldName = namer.instanceFieldName(library, name); | |
| 428 // See if we can dynamically create getters and setters. | |
| 429 // We can only generate getters and setters for [classElement] since | |
| 430 // the fields of super classes could be overwritten with getters or | |
| 431 // setters. | |
| 432 bool needsDynamicGetter = false; | |
| 433 bool needsDynamicSetter = false; | |
| 434 if (enclosingClass === classElement) { | |
| 435 needsDynamicGetter = instanceFieldNeedsGetter(member); | |
| 436 needsDynamicSetter = instanceFieldNeedsSetter(member); | |
| 437 } | |
| 438 | |
| 439 if (isInstantiated || needsDynamicGetter || needsDynamicSetter) { | |
| 440 if (isFirstField) { | |
| 441 isFirstField = false; | |
| 442 } else { | |
| 443 buffer.add(", "); | |
| 444 } | |
| 445 // Getters and setters with suffixes will be generated dynamically. | |
| 446 buffer.add('"$fieldName'); | |
| 447 if (needsDynamicGetter || needsDynamicSetter) { | |
| 448 if (needsDynamicGetter && needsDynamicSetter) { | |
| 449 buffer.add(GETTER_SETTER_SUFFIX); | |
| 450 } else if (needsDynamicGetter) { | |
| 451 buffer.add(GETTER_SUFFIX); | |
| 452 } else { | |
| 453 buffer.add(SETTER_SUFFIX); | |
| 454 } | |
| 455 } | |
| 456 buffer.add('"'); | |
| 457 } | |
| 381 } | 458 } |
| 382 | 459 |
| 460 // If a class is not instantiated then we add the field just so we can | |
| 461 // generate the field getter/setter dynamically. Since this is only | |
| 462 // allowed on fields that are in [classElement] we don't need to visit | |
| 463 // superclasses for non-instantiated classes. | |
| 383 classElement.forEachInstanceField(addField, | 464 classElement.forEachInstanceField(addField, |
| 384 includeBackendMembers: true, | 465 includeBackendMembers: true, |
| 385 includeSuperMembers: true); | 466 includeSuperMembers: isInstantiated); |
| 386 return result; | |
| 387 } | 467 } |
| 388 | 468 |
| 389 void generateClass(ClassElement classElement, StringBuffer buffer) { | 469 void emitInstanceMembers(ClassElement classElement, StringBuffer buffer) { |
| 390 needsDefineClass = true; | |
| 391 | |
| 392 if (classElement.isNative()) { | |
| 393 nativeEmitter.generateNativeClass(classElement); | |
| 394 return; | |
| 395 } else { | |
| 396 // TODO(ngeoffray): Instead of switching between buffer, we | |
| 397 // should create code sections, and decide where to emit them at | |
| 398 // the end. | |
| 399 buffer = mainBuffer; | |
| 400 } | |
| 401 | |
| 402 String className = namer.getName(classElement); | |
| 403 ClassElement superclass = classElement.superclass; | |
| 404 String superName = ""; | |
| 405 if (superclass !== null) { | |
| 406 superName = namer.getName(superclass); | |
| 407 } | |
| 408 String constructorName = namer.safeName(classElement.name.slowToString()); | |
| 409 buffer.add('$defineClassName("$className", "$superName", '); | |
| 410 // If the class is never instantiated we still need to set it up for | |
| 411 // inheritance purposes, but we can simplify its JavaScript constructor. | |
| 412 if (!compiler.universe.instantiatedClasses.contains(classElement)) { | |
| 413 buffer.add("[]"); | |
| 414 } else { | |
| 415 List<String> fields = generateFieldList(classElement); | |
| 416 buffer.add('['); | |
| 417 for (int i = 0; i < fields.length; i++) { | |
| 418 if (i != 0) buffer.add(", "); | |
| 419 buffer.add('"${fields[i]}"'); | |
| 420 } | |
| 421 buffer.add(']'); | |
| 422 } | |
| 423 buffer.add(', {\n'); | |
| 424 | |
| 425 void defineInstanceMember(String name, String value) { | 470 void defineInstanceMember(String name, String value) { |
| 426 buffer.add(' $name: $value,\n'); | 471 buffer.add(' $name: $value,\n'); |
| 427 } | 472 } |
| 428 | 473 |
| 429 classElement.forEachMember(includeBackendMembers: true, | 474 classElement.forEachMember(includeBackendMembers: true, |
| 430 f: (ClassElement enclosing, Element member) { | 475 f: (ClassElement enclosing, Element member) { |
| 431 if (member.isInstanceMember()) { | 476 if (member.isInstanceMember()) { |
| 432 addInstanceMember(member, defineInstanceMember); | 477 // All getters and setters for non-native classes are generated |
| 478 // dynamically. | |
| 479 bool needGettersAndSetters = false; | |
| 480 addInstanceMember(member, needGettersAndSetters, defineInstanceMember); | |
| 433 } | 481 } |
| 434 }); | 482 }); |
| 435 | 483 |
| 436 generateTypeTests(classElement, (Element other) { | 484 generateTypeTests(classElement, (Element other) { |
| 437 if (nativeEmitter.requiresNativeIsCheck(other)) { | 485 if (nativeEmitter.requiresNativeIsCheck(other)) { |
| 438 defineInstanceMember(namer.operatorIs(other), | 486 defineInstanceMember(namer.operatorIs(other), |
| 439 'function() { return true; }'); | 487 'function() { return true; }'); |
| 440 } else { | 488 } else { |
| 441 defineInstanceMember(namer.operatorIs(other), 'true'); | 489 defineInstanceMember(namer.operatorIs(other), 'true'); |
| 442 } | 490 } |
| 443 }); | 491 }); |
| 444 | 492 |
| 445 if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) { | 493 if (classElement === compiler.objectClass && compiler.enabledNoSuchMethod) { |
| 446 // Emit the noSuchMethods on the Object prototype now, so that | 494 // Emit the noSuchMethods on the Object prototype now, so that |
| 447 // the code in the dynamicMethod can find them. Note that the | 495 // the code in the dynamicMethod can find them. Note that the |
| 448 // code in dynamicMethod is invoked before analyzing the full JS | 496 // code in dynamicMethod is invoked before analyzing the full JS |
| 449 // script. | 497 // script. |
| 450 emitNoSuchMethodCalls(defineInstanceMember); | 498 emitNoSuchMethodCalls(defineInstanceMember); |
| 451 } | 499 } |
| 500 } | |
| 501 | |
| 502 void generateClass(ClassElement classElement, StringBuffer buffer) { | |
| 503 needsDefineClass = true; | |
| 504 | |
| 505 if (classElement.isNative()) { | |
| 506 nativeEmitter.generateNativeClass(classElement); | |
| 507 return; | |
| 508 } else { | |
| 509 // TODO(ngeoffray): Instead of switching between buffer, we | |
| 510 // should create code sections, and decide where to emit them at | |
| 511 // the end. | |
| 512 buffer = mainBuffer; | |
| 513 } | |
| 514 | |
| 515 String className = namer.getName(classElement); | |
| 516 ClassElement superclass = classElement.superclass; | |
| 517 String superName = ""; | |
| 518 if (superclass !== null) { | |
| 519 superName = namer.getName(superclass); | |
| 520 } | |
| 521 String constructorName = namer.safeName(classElement.name.slowToString()); | |
| 522 | |
| 523 buffer.add('$defineClassName("$className", "$superName", ['); | |
| 524 emitClassFields(classElement, buffer); | |
| 525 buffer.add('], {\n'); | |
| 526 emitInstanceMembers(classElement, buffer); | |
| 452 buffer.add('});\n\n'); | 527 buffer.add('});\n\n'); |
| 453 } | 528 } |
| 454 | 529 |
| 455 void generateTypeTests(ClassElement cls, | 530 void generateTypeTests(ClassElement cls, |
| 456 void generateTypeTest(ClassElement element)) { | 531 void generateTypeTest(ClassElement element)) { |
| 457 if (compiler.universe.isChecks.contains(cls)) { | 532 if (compiler.universe.isChecks.contains(cls)) { |
| 458 generateTypeTest(cls); | 533 generateTypeTest(cls); |
| 459 } | 534 } |
| 460 generateInterfacesIsTests(cls, generateTypeTest, new Set<Element>()); | 535 generateInterfacesIsTests(cls, generateTypeTest, new Set<Element>()); |
| 461 } | 536 } |
| (...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 906 mainBuffer.add('function init() {\n'); | 981 mainBuffer.add('function init() {\n'); |
| 907 mainBuffer.add(' $isolateProperties = {};\n'); | 982 mainBuffer.add(' $isolateProperties = {};\n'); |
| 908 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); | 983 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); |
| 909 emitFinishIsolateConstructor(mainBuffer); | 984 emitFinishIsolateConstructor(mainBuffer); |
| 910 mainBuffer.add('}\n'); | 985 mainBuffer.add('}\n'); |
| 911 compiler.assembledCode = mainBuffer.toString(); | 986 compiler.assembledCode = mainBuffer.toString(); |
| 912 }); | 987 }); |
| 913 return compiler.assembledCode; | 988 return compiler.assembledCode; |
| 914 } | 989 } |
| 915 } | 990 } |
| OLD | NEW |