Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(88)

Side by Side Diff: lib/compiler/implementation/emitter.dart

Issue 10310060: Generate getters and setters dynamically. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Simplify by using a bool. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | lib/compiler/implementation/namer.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | lib/compiler/implementation/namer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698