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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 14018036: Remove holders for runtime type information. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 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
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 part of js_backend; 5 part of js_backend;
6 6
7 /** 7 /**
8 * A function element that represents a closure call. The signature is copied 8 * A function element that represents a closure call. The signature is copied
9 * from the given element. 9 * from the given element.
10 */ 10 */
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 // Example: 283 // Example:
284 // defineClass("A", ["x", "y"], { 284 // defineClass("A", ["x", "y"], {
285 // foo$1: function(y) { 285 // foo$1: function(y) {
286 // print(this.x + y); 286 // print(this.x + y);
287 // }, 287 // },
288 // bar$2: function(t, v) { 288 // bar$2: function(t, v) {
289 // this.x = t - v; 289 // this.x = t - v;
290 // }, 290 // },
291 // }); 291 // });
292 292
293 // function(cls, fields, prototype) { 293 var defineClass = js.fun(['name', 'cls', 'fields', 'prototype'], [
294 var defineClass = js.fun(['cls', 'fields', 'prototype'], [
295 js('var constructor'), 294 js('var constructor'),
296 295
297 // if (typeof fields == "function") {
298 js.if_(js('typeof fields == "function"'), [ 296 js.if_(js('typeof fields == "function"'), [
299 js('constructor = fields') 297 js('constructor = fields')
300 ], /* else */ [ 298 ], /* else */ [
301 js('var str = "function " + cls + "("'), 299 js('var str = "function " + cls + "("'),
302 js('var body = ""'), 300 js('var body = ""'),
303 301
304 // for (var i = 0; i < fields.length; i++) {
305 js.for_('var i = 0', 'i < fields.length', 'i++', [ 302 js.for_('var i = 0', 'i < fields.length', 'i++', [
306 // if (i != 0) str += ", ";
307 js.if_('i != 0', js('str += ", "')), 303 js.if_('i != 0', js('str += ", "')),
308 304
309 js('var field = fields[i]'), 305 js('var field = fields[i]'),
310 js('field = generateAccessor(field, prototype)'), 306 js('field = generateAccessor(field, prototype)'),
311 js('str += field'), 307 js('str += field'),
312 js('body += ("this." + field + " = " + field + ";\\n")') 308 js('body += ("this." + field + " = " + field + ";\\n")')
313 ]), 309 ]),
314 310
315 js('str += (") {" + body + "}\\nreturn " + cls)'), 311 js('str += (") {" + body + "}\\nreturn " + cls)'),
316 312
317 js('constructor = new Function(str)()') 313 js('constructor = new Function(str)()')
318 ]), 314 ]),
319 315
320 js('constructor.prototype = prototype'), 316 js('constructor.prototype = prototype'),
321 js('constructor.builtin\$cls = cls'), 317 js(r'constructor.builtin$cls = name'),
322 318
323 // return constructor;
324 js.return_('constructor') 319 js.return_('constructor')
325 ]); 320 ]);
326 // Declare a function called "generateAccessor". This is used in 321 // Declare a function called "generateAccessor". This is used in
327 // defineClassFunction (it's a local declaration in init()). 322 // defineClassFunction (it's a local declaration in init()).
328 return [ 323 return [
329 generateAccessorFunction, 324 generateAccessorFunction,
330 js('$generateAccessorHolder = generateAccessor'), 325 js('$generateAccessorHolder = generateAccessor'),
331 new jsAst.FunctionDeclaration( 326 new jsAst.FunctionDeclaration(
332 new jsAst.VariableDeclaration('defineClass'), defineClass) ]; 327 new jsAst.VariableDeclaration('defineClass'), defineClass) ];
333 } 328 }
334 329
335 /** Needs defineClass to be defined. */ 330 /** Needs defineClass to be defined. */
336 List buildProtoSupportCheck() { 331 List buildProtoSupportCheck() {
337 // On Firefox and Webkit browsers we can manipulate the __proto__ 332 // On Firefox and Webkit browsers we can manipulate the __proto__
338 // directly. Opera claims to have __proto__ support, but it is buggy. 333 // directly. Opera claims to have __proto__ support, but it is buggy.
339 // So we have to do more checks. 334 // So we have to do more checks.
340 // Opera bug was filed as DSK-370158, and fixed as CORE-47615 335 // Opera bug was filed as DSK-370158, and fixed as CORE-47615
341 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes). 336 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes).
342 // If the browser does not support __proto__ we need to instantiate an 337 // If the browser does not support __proto__ we need to instantiate an
343 // object with the correct (internal) prototype set up correctly, and then 338 // object with the correct (internal) prototype set up correctly, and then
344 // copy the members. 339 // copy the members.
345 // TODO(8541): Remove this work around. 340 // TODO(8541): Remove this work around.
346 341
347 return [ 342 return [
348 js('var $supportsProtoName = false'), 343 js('var $supportsProtoName = false'),
349 js('var tmp = defineClass("c", ["f?"], {}).prototype'), 344 js('var tmp = defineClass("c", "c", ["f?"], {}).prototype'),
350 345
351 js.if_(js('tmp.__proto__'), [ 346 js.if_(js('tmp.__proto__'), [
352 js('tmp.__proto__ = {}'), 347 js('tmp.__proto__ = {}'),
353 js.if_(js(r'typeof tmp.get$f != "undefined"'), 348 js.if_(js(r'typeof tmp.get$f != "undefined"'),
354 js('$supportsProtoName = true')) 349 js('$supportsProtoName = true'))
355 350
356 ]) 351 ])
357 ]; 352 ];
358 } 353 }
359 354
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
587 // constructor. 582 // constructor.
588 // For engines where we have access to the '__proto__' we can manipulate 583 // For engines where we have access to the '__proto__' we can manipulate
589 // the object literal directly. For other engines we have to create a new 584 // the object literal directly. For other engines we have to create a new
590 // object and copy over the members. 585 // object and copy over the members.
591 586
592 List<jsAst.Node> statements = [ 587 List<jsAst.Node> statements = [
593 js('var pendingClasses = {}'), 588 js('var pendingClasses = {}'),
594 589
595 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), 590 js('var hasOwnProperty = Object.prototype.hasOwnProperty'),
596 591
597 // for (var cls in collectedClasses)
598 js.forIn('cls', 'collectedClasses', [ 592 js.forIn('cls', 'collectedClasses', [
599 // if (hasOwnProperty.call(collectedClasses, cls))
600 js.if_('hasOwnProperty.call(collectedClasses, cls)', [ 593 js.if_('hasOwnProperty.call(collectedClasses, cls)', [
601 js('var desc = collectedClasses[cls]'), 594 js('var desc = collectedClasses[cls]'),
602 595
603 /* The 'fields' are either a constructor function or a 596 /* The 'fields' are either a constructor function or a
604 * string encoding fields, constructor and superclass. Get 597 * string encoding fields, constructor and superclass. Get
605 * the superclass and the fields in the format 598 * the superclass and the fields in the format
606 * Super;field1,field2 from the null-string property on the 599 * name/Super;field1,field2 from the null-string property on the
607 * descriptor. 600 * descriptor.
608 */ 601 */
609 // var fields = desc[""], supr; 602 js('var classData = desc[""], supr, name, fields'),
610 js('var fields = desc[""], supr'), 603 js('var split = classData.split("/")'),
604 js.if_('split.length == 2', [
605 js('name = split[0]'),
606 js('fields = split[1]')
607 ], /* else */ [
608 js('name = cls'),
609 js('fields = classData')
610 ]),
611 611
612 js.if_('typeof fields == "string"', [ 612 js.if_('typeof fields == "string"', [
613 js('var s = fields.split(";")'), 613 js('var s = fields.split(";")'),
614 js('supr = s[0]'), 614 js('supr = s[0]'),
615 js('fields = s[1] == "" ? [] : s[1].split(",")'), 615 js('fields = s[1] == "" ? [] : s[1].split(",")'),
616 ], /* else */ [ 616 ], /* else */ [
617 js('supr = desc.super') 617 js('supr = desc.super')
618 ]), 618 ]),
619 619
620 js('isolateProperties[cls] = defineClass(cls, fields, desc)'), 620 js('isolateProperties[cls] = defineClass(name, cls, fields, desc)'),
621 621
622 // if (supr) pendingClasses[cls] = supr;
623 js.if_('supr', js('pendingClasses[cls] = supr')) 622 js.if_('supr', js('pendingClasses[cls] = supr'))
624 ]) 623 ])
625 ]), 624 ]),
626 625
627 js('var finishedClasses = {}'), 626 js('var finishedClasses = {}'),
628 627
629 // function finishClass(cls) { ... } 628 // function finishClass(cls) { ... }
630 buildFinishClass(), 629 buildFinishClass(),
631 ]; 630 ];
632 631
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after
1172 classElement.implementation.forEachMember( 1171 classElement.implementation.forEachMember(
1173 visitMember, 1172 visitMember,
1174 includeBackendMembers: true, 1173 includeBackendMembers: true,
1175 includeSuperMembers: false); 1174 includeSuperMembers: false);
1176 1175
1177 void generateIsTest(Element other) { 1176 void generateIsTest(Element other) {
1178 if (other == compiler.objectClass && other != classElement) { 1177 if (other == compiler.objectClass && other != classElement) {
1179 // Avoid emitting [:$isObject:] on all classes but [Object]. 1178 // Avoid emitting [:$isObject:] on all classes but [Object].
1180 return; 1179 return;
1181 } 1180 }
1181 other = backend.getImplementationClass(other);
1182 builder.addProperty(namer.operatorIs(other), js('true')); 1182 builder.addProperty(namer.operatorIs(other), js('true'));
1183 } 1183 }
1184 1184
1185 void generateSubstitution(Element other, {bool emitNull: false}) { 1185 void generateSubstitution(Element other, {bool emitNull: false}) {
1186 RuntimeTypes rti = backend.rti; 1186 RuntimeTypes rti = backend.rti;
1187 // TODO(karlklose): support typedefs with variables. 1187 // TODO(karlklose): support typedefs with variables.
1188 jsAst.Expression expression; 1188 jsAst.Expression expression;
1189 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); 1189 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other);
1190 if (other.kind == ElementKind.CLASS) { 1190 if (other.kind == ElementKind.CLASS) {
1191 String substitution = rti.getSupertypeSubstitution(classElement, other, 1191 String substitution = rti.getSupertypeSubstitution(classElement, other,
(...skipping 18 matching lines...) Expand all
1210 // them. Note that this helper is invoked before analyzing the 1210 // them. Note that this helper is invoked before analyzing the
1211 // full JS script. 1211 // full JS script.
1212 if (!nativeEmitter.handleNoSuchMethod) { 1212 if (!nativeEmitter.handleNoSuchMethod) {
1213 emitNoSuchMethodHandlers(builder.addProperty); 1213 emitNoSuchMethodHandlers(builder.addProperty);
1214 } 1214 }
1215 } 1215 }
1216 } 1216 }
1217 1217
1218 void emitRuntimeTypeSupport(CodeBuffer buffer) { 1218 void emitRuntimeTypeSupport(CodeBuffer buffer) {
1219 RuntimeTypes rti = backend.rti; 1219 RuntimeTypes rti = backend.rti;
1220 TypeChecks typeChecks = rti.getRequiredChecks(); 1220 TypeChecks typeChecks = rti.requiredChecks;
1221 1221
1222 /// Classes that are not instantiated and native classes need a holder 1222 // Add checks to the constructors of instantiated classes.
1223 /// object for their checks, because there will be no class defined for
1224 /// them.
1225
1226 // TODO(9556): Get rid of holders.
1227 //
1228 // - For primitive classes, use the interceptors (e.g JSInt).
1229 //
1230 // - For uninstantiated classes, define the class anyway. It will not need
1231 // fields or a constructor, or any methods, so the class definition will
1232 // be smaller than a holder.
1233
1234 bool needsHolder(ClassElement cls) {
1235 return !neededClasses.contains(cls) ||
1236 rti.isJsNative(cls);
1237 }
1238
1239 /**
1240 * Generates a holder object if it is needed. A holder is a JavaScript
1241 * object literal with a field [builtin$cls] that contains the name of the
1242 * class as a string (just like object constructors do). The is-checks for
1243 * the class are are added to the holder object later.
1244 */
1245 void maybeGenerateHolder(ClassElement cls) {
1246 if (!needsHolder(cls)) return;
1247 String holder = namer.isolateAccess(cls);
1248 String name = namer.getRuntimeTypeName(cls);
1249 buffer.write('$holder$_=$_{builtin\$cls:$_"$name"');
1250 buffer.write('}$N');
1251 }
1252
1253 // Create representation objects for classes that we do not have a class
1254 // definition for (because they are uninstantiated or native).
1255 for (ClassElement cls in rti.allArguments) {
1256 maybeGenerateHolder(cls);
1257 }
1258
1259 // Add checks to the constructors of instantiated classes or to the created
1260 // holder object.
1261 for (ClassElement cls in typeChecks) { 1223 for (ClassElement cls in typeChecks) {
1262 String holder = namer.isolateAccess(cls); 1224 String holder = namer.isolateAccess(backend.getImplementationClass(cls));
1263 for (ClassElement check in typeChecks[cls]) { 1225 for (ClassElement check in typeChecks[cls]) {
1264 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N'); 1226 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N');
1265 String body = rti.getSupertypeSubstitution(cls, check); 1227 String body = rti.getSupertypeSubstitution(cls, check);
1266 if (body != null) { 1228 if (body != null) {
1267 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N') ; 1229 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N') ;
1268 } 1230 }
1269 }; 1231 };
1270 } 1232 }
1271 } 1233 }
1272 1234
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
1427 /* Do nothing. */ 1389 /* Do nothing. */
1428 } 1390 }
1429 1391
1430 /// Returns `true` if fields added. 1392 /// Returns `true` if fields added.
1431 bool emitClassFields(ClassElement classElement, 1393 bool emitClassFields(ClassElement classElement,
1432 ClassBuilder builder, 1394 ClassBuilder builder,
1433 { String superClass, 1395 { String superClass,
1434 bool classIsNative: false }) { 1396 bool classIsNative: false }) {
1435 String separator = ''; 1397 String separator = '';
1436 StringBuffer buffer = new StringBuffer(); 1398 StringBuffer buffer = new StringBuffer();
1399 String nativeName = namer.getNativeName(classElement);
1400 if (nativeName != null) {
1401 buffer.write('$nativeName/');
1402 }
1437 if (superClass != null) { 1403 if (superClass != null) {
1438 buffer.write('$superClass;'); 1404 buffer.write('$superClass;');
1439 } 1405 }
1440 int bufferClassLength = buffer.length; 1406 int bufferClassLength = buffer.length;
1441 1407
1442 visitClassFields(classElement, (Element member, 1408 visitClassFields(classElement, (Element member,
1443 String name, 1409 String name,
1444 String accessorName, 1410 String accessorName,
1445 bool needsGetter, 1411 bool needsGetter,
1446 bool needsSetter, 1412 bool needsSetter,
(...skipping 1135 matching lines...) Expand 10 before | Expand all | Expand 10 after
2582 } 2548 }
2583 2549
2584 /** 2550 /**
2585 * Compute all the classes that must be emitted. 2551 * Compute all the classes that must be emitted.
2586 */ 2552 */
2587 void computeNeededClasses() { 2553 void computeNeededClasses() {
2588 instantiatedClasses = 2554 instantiatedClasses =
2589 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter()) 2555 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter())
2590 .toSet(); 2556 .toSet();
2591 2557
2558 RuntimeTypes rti = backend.rti;
2559
2592 // The set of classes that must be emitted are based on instantiated 2560 // The set of classes that must be emitted are based on instantiated
2593 // classes. 2561 // classes.
2594 neededClasses.addAll(instantiatedClasses); 2562 neededClasses.addAll(instantiatedClasses);
2563 rti.allArguments.forEach((ClassElement c) {
ngeoffray 2013/04/29 14:14:22 Please add a comment on why you're iterating over
karlklose 2013/04/30 09:29:41 Done.
2564 if (!rti.isJsNative(c)) {
2565 neededClasses.add(c);
2566 }
2567 });
2595 2568
2596 // Then add all superclasses of these classes. 2569 // Then add all superclasses of these classes.
2597 for (ClassElement element in neededClasses.toList() /* copy */) { 2570 for (ClassElement element in neededClasses.toList() /* copy */) {
2598 for (ClassElement superclass = element.superclass; 2571 for (ClassElement superclass = element.superclass;
2599 superclass != null; 2572 superclass != null;
2600 superclass = superclass.superclass) { 2573 superclass = superclass.superclass) {
2601 if (neededClasses.contains(superclass)) break; 2574 if (neededClasses.contains(superclass)) break;
2602 neededClasses.add(superclass); 2575 neededClasses.add(superclass);
2603 } 2576 }
2604 } 2577 }
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
2846 ..addAll(buildLazyInitializerFunctionIfNecessary()) 2819 ..addAll(buildLazyInitializerFunctionIfNecessary())
2847 ..addAll(buildFinishIsolateConstructor()) 2820 ..addAll(buildFinishIsolateConstructor())
2848 ); 2821 );
2849 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( 2822 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration(
2850 new jsAst.VariableDeclaration('init'), fun); 2823 new jsAst.VariableDeclaration('init'), fun);
2851 buffer.write(jsAst.prettyPrint(decl, compiler).getText()); 2824 buffer.write(jsAst.prettyPrint(decl, compiler).getText());
2852 } 2825 }
2853 2826
2854 String assembleProgram() { 2827 String assembleProgram() {
2855 measure(() { 2828 measure(() {
2856 computeNeededClasses();
2857
2858 // Compute the required type checks to know which classes need a 2829 // Compute the required type checks to know which classes need a
2859 // 'is$' method. 2830 // 'is$' method.
2860 computeRequiredTypeChecks(); 2831 computeRequiredTypeChecks();
2861 2832
2833 computeNeededClasses();
2834
2862 mainBuffer.add(GENERATED_BY); 2835 mainBuffer.add(GENERATED_BY);
2863 addComment(HOOKS_API_USAGE, mainBuffer); 2836 addComment(HOOKS_API_USAGE, mainBuffer);
2864 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); 2837 mainBuffer.add('function ${namer.isolateName}()$_{}\n');
2865 mainBuffer.add('init()$N$n'); 2838 mainBuffer.add('init()$N$n');
2866 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. 2839 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary.
2867 isolateProperties = namer.CURRENT_ISOLATE; 2840 isolateProperties = namer.CURRENT_ISOLATE;
2868 mainBuffer.add( 2841 mainBuffer.add(
2869 'var $isolateProperties$_=$_$isolatePropertiesName$N'); 2842 'var $isolateProperties$_=$_$isolatePropertiesName$N');
2870 2843
2871 if (!regularClasses.isEmpty || 2844 if (!regularClasses.isEmpty ||
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
3038 """; 3011 """;
3039 const String HOOKS_API_USAGE = """ 3012 const String HOOKS_API_USAGE = """
3040 // The code supports the following hooks: 3013 // The code supports the following hooks:
3041 // dartPrint(message) - if this function is defined it is called 3014 // dartPrint(message) - if this function is defined it is called
3042 // instead of the Dart [print] method. 3015 // instead of the Dart [print] method.
3043 // dartMainRunner(main) - if this function is defined, the Dart [main] 3016 // dartMainRunner(main) - if this function is defined, the Dart [main]
3044 // method will not be invoked directly. 3017 // method will not be invoked directly.
3045 // Instead, a closure that will invoke [main] is 3018 // Instead, a closure that will invoke [main] is
3046 // passed to [dartMainRunner]. 3019 // passed to [dartMainRunner].
3047 """; 3020 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698