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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 String get defineClassFunction() { | 55 String get defineClassFunction() { |
| 56 final String GETTER = "getter"; | |
| 57 final String SETTER = "setter"; | |
| 56 // First the class name, then the super class name, followed by the fields | 58 // First the class name, then the super class name, followed by the fields |
| 57 // (in an array) and the members (inside an Object literal). | 59 // (in an array) and the members (inside an Object literal). |
| 58 // The caller can also pass in the constructor as a function if needed. | 60 // The caller can also pass in the constructor as a function if needed. |
| 59 // | 61 // |
| 60 // Example: | 62 // Example: |
| 61 // defineClass("A", "B", ["x", "y"], { | 63 // defineClass("A", "B", ["x", "y"], { |
| 62 // foo$1: function(y) { | 64 // foo$1: function(y) { |
| 63 // print(this.x + y); | 65 // print(this.x + y); |
| 64 // }, | 66 // }, |
| 65 // bar$2: function(t, v) { | 67 // bar$2: function(t, v) { |
| 66 // this.x = t - v; | 68 // this.x = t - v; |
| 67 // }, | 69 // }, |
| 68 // }); | 70 // }); |
| 69 return """ | 71 return """ |
| 70 function(cls, superclass, fields, prototype) { | 72 function(cls, superclass, fields, fieldBitSet, prototype) { |
|
ngeoffray
2012/05/09 08:50:28
Not sure we need the two following lines. They kin
floitsch
2012/05/09 13:58:36
inlined.
| |
| 73 ${namer.getDynamicFieldGetterNamerFunction(GETTER)} | |
| 74 ${namer.getDynamicFieldSetterNamerFunction(SETTER)} | |
| 71 var constructor; | 75 var constructor; |
| 72 if (typeof fields == 'function') { | 76 if (typeof fields == 'function') { |
| 73 constructor = fields; | 77 constructor = fields; |
| 78 prototype = fieldBitSet; | |
|
ngeoffray
2012/05/09 08:50:28
This is starting to be confusing. Maybe add anothe
floitsch
2012/05/09 13:58:36
removed.
| |
| 74 } else { | 79 } else { |
| 80 if (typeof fieldBitSet !== 'number') { | |
| 81 prototype = fieldBitSet; | |
| 82 fieldBitSet = 0; | |
| 83 } | |
| 75 var str = "(function " + cls + "("; | 84 var str = "(function " + cls + "("; |
| 76 var body = ""; | 85 var body = ""; |
| 77 for (var i = 0; i < fields.length; i++) { | 86 for (var i = 0; i < fields.length; i++) { |
|
kasperl
2012/05/09 07:53:15
Have you thought about encoding the need for a get
floitsch
2012/05/09 13:58:36
Done.
| |
| 78 if (i != 0) str += ", "; | 87 if (i != 0) str += ", "; |
| 79 str += fields[i]; | 88 var field = fields[i]; |
| 89 str += field; | |
| 80 body += "this." + fields[i] + " = " + fields[i] + ";\\n"; | 90 body += "this." + fields[i] + " = " + fields[i] + ";\\n"; |
|
kasperl
2012/05/09 07:53:15
Use field instead of fields[i].
floitsch
2012/05/09 13:58:36
Done.
| |
| 91 if (fieldBitSet & 1) { | |
| 92 var getterString = "return this." + field + ";"; | |
| 93 prototype[$GETTER(field)] = new Function(getterString); | |
| 94 } | |
| 95 fieldBitSet >>>= 1; | |
| 96 if (fieldBitSet & 1) { | |
| 97 var setterString = "this." + field + " = v;"; | |
| 98 prototype[$SETTER(field)] = new Function("v", setterString); | |
| 99 } | |
| 100 fieldBitSet >>>= 1; | |
| 81 } | 101 } |
| 82 str += ") {" + body + "})"; | 102 str += ") {" + body + "})"; |
| 83 constructor = eval(str); | 103 constructor = eval(str); |
|
sra1
2012/05/08 17:59:42
Should this new new Function too?
floitsch
2012/05/09 13:58:36
I would like it to be a "new Function", but then w
| |
| 84 } | 104 } |
| 85 $isolatePropertiesName[cls] = constructor; | 105 $isolatePropertiesName[cls] = constructor; |
| 86 constructor.prototype = prototype; | 106 constructor.prototype = prototype; |
| 87 if (superclass !== "") { | 107 if (superclass !== "") { |
| 88 $pendingClassesName[cls] = superclass; | 108 $pendingClassesName[cls] = superclass; |
| 89 } | 109 } |
| 90 }"""; | 110 }"""; |
| 91 } | 111 } |
| 92 | 112 |
| 93 String get finishClassesFunction() { | 113 String get finishClassesFunction() { |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 void defineInstanceMember(String invocationName, | 339 void defineInstanceMember(String invocationName, |
| 320 String definition)) { | 340 String definition)) { |
| 321 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; | 341 Set<Selector> selectors = compiler.universe.invokedNames[member.name]; |
| 322 if (selectors == null) return; | 342 if (selectors == null) return; |
| 323 for (Selector selector in selectors) { | 343 for (Selector selector in selectors) { |
| 324 if (!selector.applies(member, compiler)) continue; | 344 if (!selector.applies(member, compiler)) continue; |
| 325 addParameterStub(member, selector, defineInstanceMember); | 345 addParameterStub(member, selector, defineInstanceMember); |
| 326 } | 346 } |
| 327 } | 347 } |
| 328 | 348 |
| 349 bool instanceFieldNeedsGetter(Element member) { | |
| 350 assert(member.kind === ElementKind.FIELD); | |
| 351 return compiler.universe.hasGetter(member, compiler); | |
| 352 } | |
| 353 | |
| 354 bool instanceFieldNeedsSetter(Element member) { | |
| 355 assert(member.kind === ElementKind.FIELD); | |
| 356 return (member.modifiers === null || !member.modifiers.isFinal()) && | |
| 357 compiler.universe.hasSetter(member, compiler); | |
|
kasperl
2012/05/09 07:53:15
The indentation seems a bit off here.
floitsch
2012/05/09 13:58:36
Done.
| |
| 358 } | |
| 359 | |
| 360 String compiledFieldName(Element member) { | |
| 361 assert(member.kind === ElementKind.FIELD); | |
| 362 return member.isNative() | |
| 363 ? member.name.slowToString() | |
| 364 : namer.getName(member); | |
| 365 } | |
| 366 | |
| 329 void addInstanceMember(Element member, | 367 void addInstanceMember(Element member, |
| 368 Set<Element> dynamicallyEmittedFieldGettersSetters, | |
| 330 void defineInstanceMember(String invocationName, | 369 void defineInstanceMember(String invocationName, |
| 331 String definition)) { | 370 String definition)) { |
| 332 // TODO(floitsch): we don't need to deal with members of | 371 // TODO(floitsch): we don't need to deal with members of |
| 333 // uninstantiated classes, that have been overwritten by subclasses. | 372 // uninstantiated classes, that have been overwritten by subclasses. |
| 334 | 373 |
| 335 if (member.kind === ElementKind.FUNCTION | 374 if (member.kind === ElementKind.FUNCTION |
| 336 || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY | 375 || member.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY |
| 337 || member.kind === ElementKind.GETTER | 376 || member.kind === ElementKind.GETTER |
| 338 || member.kind === ElementKind.SETTER) { | 377 || member.kind === ElementKind.SETTER) { |
| 339 if (member.modifiers !== null && member.modifiers.isAbstract()) return; | 378 if (member.modifiers !== null && member.modifiers.isAbstract()) return; |
| 340 String codeBlock = compiler.universe.generatedCode[member]; | 379 String codeBlock = compiler.universe.generatedCode[member]; |
| 341 if (codeBlock == null) return; | 380 if (codeBlock == null) return; |
| 342 defineInstanceMember(namer.getName(member), codeBlock); | 381 defineInstanceMember(namer.getName(member), codeBlock); |
| 343 codeBlock = compiler.universe.generatedBailoutCode[member]; | 382 codeBlock = compiler.universe.generatedBailoutCode[member]; |
| 344 if (codeBlock !== null) { | 383 if (codeBlock !== null) { |
| 345 defineInstanceMember(compiler.namer.getBailoutName(member), codeBlock); | 384 defineInstanceMember(compiler.namer.getBailoutName(member), codeBlock); |
| 346 } | 385 } |
| 347 FunctionElement function = member; | 386 FunctionElement function = member; |
| 348 FunctionSignature parameters = function.computeSignature(compiler); | 387 FunctionSignature parameters = function.computeSignature(compiler); |
| 349 if (!parameters.optionalParameters.isEmpty()) { | 388 if (!parameters.optionalParameters.isEmpty()) { |
| 350 addParameterStubs(member, defineInstanceMember); | 389 addParameterStubs(member, defineInstanceMember); |
| 351 } | 390 } |
| 352 } else if (member.kind === ElementKind.FIELD) { | 391 } else if (member.kind === ElementKind.FIELD) { |
| 353 // TODO(ngeoffray): Have another class generate the code for the | 392 // TODO(ngeoffray): Have another class generate the code for the |
| 354 // fields. | 393 // fields. |
|
ngeoffray
2012/05/09 08:50:28
Remove the TODO.
floitsch
2012/05/09 13:58:36
Done.
| |
| 355 if ((member.modifiers === null || !member.modifiers.isFinal()) && | 394 if (instanceFieldNeedsGetter(member) && |
| 356 compiler.universe.hasSetter(member, compiler)) { | 395 !dynamicallyEmittedFieldGettersSetters.contains(member)) { |
| 396 String getterName = namer.getterName(member.getLibrary(), member.name); | |
| 397 String name = compiledFieldName(member); | |
| 398 defineInstanceMember(getterName, "function() { return this.$name; }"); | |
| 399 } | |
| 400 | |
| 401 if (instanceFieldNeedsSetter(member) && | |
| 402 !dynamicallyEmittedFieldGettersSetters.contains(member)) { | |
| 357 String setterName = namer.setterName(member.getLibrary(), member.name); | 403 String setterName = namer.setterName(member.getLibrary(), member.name); |
| 358 String name = member.isNative() | 404 String name = compiledFieldName(member); |
| 359 ? member.name.slowToString() | |
| 360 : namer.getName(member); | |
| 361 defineInstanceMember(setterName, "function(v) { this.$name = v; }"); | 405 defineInstanceMember(setterName, "function(v) { this.$name = v; }"); |
| 362 } | 406 } |
| 363 if (compiler.universe.hasGetter(member, compiler)) { | |
| 364 String getterName = namer.getterName(member.getLibrary(), member.name); | |
| 365 String name = member.isNative() | |
| 366 ? member.name.slowToString() | |
| 367 : namer.getName(member); | |
| 368 defineInstanceMember(getterName, "function() { return this.$name; }"); | |
| 369 } | |
| 370 } else { | 407 } else { |
| 371 compiler.internalError('unexpected kind: "${member.kind}"', | 408 compiler.internalError('unexpected kind: "${member.kind}"', |
| 372 element: member); | 409 element: member); |
| 373 } | 410 } |
| 374 emitExtraAccessors(member, defineInstanceMember); | 411 emitExtraAccessors(member, defineInstanceMember); |
| 375 } | 412 } |
| 376 | 413 |
| 377 List<String> generateFieldList(ClassElement classElement) { | |
| 378 List<String> result = <String>[]; | |
| 379 void addField(ClassElement enclosingClass, Element member) { | |
| 380 result.add(namer.instanceFieldName(member.getLibrary(), member.name)); | |
| 381 } | |
| 382 | |
| 383 classElement.forEachInstanceField(addField, | |
| 384 includeBackendMembers: true, | |
| 385 includeSuperMembers: true); | |
| 386 return result; | |
| 387 } | |
| 388 | |
| 389 void generateClass(ClassElement classElement, StringBuffer buffer) { | 414 void generateClass(ClassElement classElement, StringBuffer buffer) { |
| 390 needsDefineClass = true; | 415 needsDefineClass = true; |
| 391 | 416 |
| 392 if (classElement.isNative()) { | 417 if (classElement.isNative()) { |
| 393 nativeEmitter.generateNativeClass(classElement); | 418 nativeEmitter.generateNativeClass(classElement); |
| 394 return; | 419 return; |
| 395 } else { | 420 } else { |
| 396 // TODO(ngeoffray): Instead of switching between buffer, we | 421 // TODO(ngeoffray): Instead of switching between buffer, we |
| 397 // should create code sections, and decide where to emit them at | 422 // should create code sections, and decide where to emit them at |
| 398 // the end. | 423 // the end. |
| 399 buffer = mainBuffer; | 424 buffer = mainBuffer; |
| 400 } | 425 } |
| 401 | 426 |
| 402 String className = namer.getName(classElement); | 427 String className = namer.getName(classElement); |
| 403 ClassElement superclass = classElement.superclass; | 428 ClassElement superclass = classElement.superclass; |
| 404 String superName = ""; | 429 String superName = ""; |
| 405 if (superclass !== null) { | 430 if (superclass !== null) { |
| 406 superName = namer.getName(superclass); | 431 superName = namer.getName(superclass); |
| 407 } | 432 } |
| 408 String constructorName = namer.safeName(classElement.name.slowToString()); | 433 String constructorName = namer.safeName(classElement.name.slowToString()); |
| 434 | |
| 435 Set<Element> dynamicallyEmittedGettersSetters = new Set<Element>(); | |
| 436 | |
| 409 buffer.add('$defineClassName("$className", "$superName", '); | 437 buffer.add('$defineClassName("$className", "$superName", '); |
| 438 | |
| 410 // If the class is never instantiated we still need to set it up for | 439 // If the class is never instantiated we still need to set it up for |
| 411 // inheritance purposes, but we can simplify its JavaScript constructor. | 440 // inheritance purposes, but we can simplify its JavaScript constructor. |
| 412 if (!compiler.universe.instantiatedClasses.contains(classElement)) { | 441 bool isInstantiated = |
| 413 buffer.add("[]"); | 442 compiler.universe.instantiatedClasses.contains(classElement); |
| 414 } else { | 443 |
| 415 List<String> fields = generateFieldList(classElement); | 444 // We encode 15 field getters and setters in an integer bit field. This way |
| 416 buffer.add('['); | 445 // the integer will fit into a JavaScript Smi. |
| 417 for (int i = 0; i < fields.length; i++) { | 446 // The getters and setters for the marked fields will be generated |
| 418 if (i != 0) buffer.add(", "); | 447 // dynamically. |
| 419 buffer.add('"${fields[i]}"'); | 448 final int MAX_DYNAMICALLY_GENERATED_FIELD_GETTERS_SETTERS = 15; |
| 449 int fieldBits = 0; | |
| 450 int fieldCounter = 0; | |
| 451 buffer.add('['); | |
| 452 | |
| 453 void addField(ClassElement enclosingClass, Element member) { | |
| 454 assert(!member.isNative()); | |
| 455 LibraryElement library = member.getLibrary(); | |
| 456 SourceString name = member.name; | |
| 457 String fieldName = namer.instanceFieldName(library, name); | |
| 458 // See, if we can dynamically create getters and setters. | |
|
kasperl
2012/05/09 07:53:15
Remove , after See.
floitsch
2012/05/09 13:58:36
Done.
| |
| 459 // We can only generate getters and setters for [classElement] since | |
| 460 // the fields of super classes could be overwritten with getters or | |
| 461 // setters. | |
| 462 bool needsDynamicGetter = false; | |
| 463 bool needsDynamicSetter = false; | |
| 464 if (fieldCounter <= MAX_DYNAMICALLY_GENERATED_FIELD_GETTERS_SETTERS && | |
| 465 enclosingClass === classElement) { | |
| 466 needsDynamicGetter = instanceFieldNeedsGetter(member); | |
| 467 needsDynamicSetter = instanceFieldNeedsSetter(member); | |
| 468 // Make sure that the name we would generate dynamically matches the | |
| 469 // name we assign to the getter/setter during compilation time. | |
| 470 if ((needsDynamicGetter && namer.getterName(library, name) != | |
|
kasperl
2012/05/09 07:53:15
Maybe add a helper on namer for this check (takes
floitsch
2012/05/09 13:58:36
code removed.
| |
| 471 namer.dynamicGetterName(fieldName)) | |
| 472 || (needsDynamicSetter && namer.setterName(library, name) != | |
| 473 namer.dynamicSetterName(fieldName))) { | |
| 474 needsDynamicGetter = false; | |
| 475 needsDynamicSetter = false; | |
| 476 } | |
| 420 } | 477 } |
| 421 buffer.add(']'); | 478 |
| 479 if (isInstantiated || needsDynamicGetter || needsDynamicSetter) { | |
| 480 fieldCounter++; | |
| 481 if (fieldCounter != 1) buffer.add(", "); | |
| 482 buffer.add('"$fieldName"'); | |
| 483 if (needsDynamicGetter || needsDynamicSetter) { | |
| 484 dynamicallyEmittedGettersSetters.add(member); | |
| 485 if (needsDynamicGetter) { | |
| 486 fieldBits |= 1 << ((fieldCounter - 1) * 2); | |
| 487 } | |
| 488 if (needsDynamicSetter) { | |
| 489 fieldBits |= 1 << ((fieldCounter - 1) * 2 + 1); | |
| 490 } | |
| 491 } | |
| 492 } | |
| 422 } | 493 } |
| 494 | |
| 495 // If a class is not instantiated then we add the field just so we can | |
| 496 // generate the field getter/setter dynamically. Since this is only | |
| 497 // allowed on fields that are in [classElement] we don't need to visit | |
| 498 // superclasses for non-instantiated classes. | |
| 499 classElement.forEachInstanceField(addField, | |
| 500 includeBackendMembers: true, | |
| 501 includeSuperMembers: isInstantiated); | |
| 502 buffer.add(']'); | |
| 503 if (fieldBits != 0) buffer.add(', $fieldBits'); | |
| 423 buffer.add(', {\n'); | 504 buffer.add(', {\n'); |
| 424 | 505 |
| 425 void defineInstanceMember(String name, String value) { | 506 void defineInstanceMember(String name, String value) { |
| 426 buffer.add(' $name: $value,\n'); | 507 buffer.add(' $name: $value,\n'); |
| 427 } | 508 } |
| 428 | 509 |
| 429 classElement.forEachMember(includeBackendMembers: true, | 510 classElement.forEachMember(includeBackendMembers: true, |
| 430 f: (ClassElement enclosing, Element member) { | 511 f: (ClassElement enclosing, Element member) { |
| 431 if (member.isInstanceMember()) { | 512 if (member.isInstanceMember()) { |
| 432 addInstanceMember(member, defineInstanceMember); | 513 addInstanceMember( |
| 514 member, dynamicallyEmittedGettersSetters, defineInstanceMember); | |
| 433 } | 515 } |
| 434 }); | 516 }); |
| 435 | 517 |
| 436 generateTypeTests(classElement, (Element other) { | 518 generateTypeTests(classElement, (Element other) { |
| 437 if (nativeEmitter.requiresNativeIsCheck(other)) { | 519 if (nativeEmitter.requiresNativeIsCheck(other)) { |
| 438 defineInstanceMember(namer.operatorIs(other), | 520 defineInstanceMember(namer.operatorIs(other), |
| 439 'function() { return true; }'); | 521 'function() { return true; }'); |
| 440 } else { | 522 } else { |
| 441 defineInstanceMember(namer.operatorIs(other), 'true'); | 523 defineInstanceMember(namer.operatorIs(other), 'true'); |
| 442 } | 524 } |
| (...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 903 mainBuffer.add('function init() {\n'); | 985 mainBuffer.add('function init() {\n'); |
| 904 mainBuffer.add(' $isolateProperties = {};\n'); | 986 mainBuffer.add(' $isolateProperties = {};\n'); |
| 905 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); | 987 addDefineClassAndFinishClassFunctionsIfNecessary(mainBuffer); |
| 906 emitFinishIsolateConstructor(mainBuffer); | 988 emitFinishIsolateConstructor(mainBuffer); |
| 907 mainBuffer.add('}\n'); | 989 mainBuffer.add('}\n'); |
| 908 compiler.assembledCode = mainBuffer.toString(); | 990 compiler.assembledCode = mainBuffer.toString(); |
| 909 }); | 991 }); |
| 910 return compiler.assembledCode; | 992 return compiler.assembledCode; |
| 911 } | 993 } |
| 912 } | 994 } |
| OLD | NEW |