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

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: Rebase. 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 282 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 // Example: 293 // Example:
294 // defineClass("A", ["x", "y"], { 294 // defineClass("A", ["x", "y"], {
295 // foo$1: function(y) { 295 // foo$1: function(y) {
296 // print(this.x + y); 296 // print(this.x + y);
297 // }, 297 // },
298 // bar$2: function(t, v) { 298 // bar$2: function(t, v) {
299 // this.x = t - v; 299 // this.x = t - v;
300 // }, 300 // },
301 // }); 301 // });
302 302
303 // function(cls, fields, prototype) { 303 var defineClass = js.fun(['name', 'cls', 'fields', 'prototype'], [
304 var defineClass = js.fun(['cls', 'fields', 'prototype'], [
305 js('var constructor'), 304 js('var constructor'),
306 305
307 // if (typeof fields == "function") {
308 js.if_(js('typeof fields == "function"'), [ 306 js.if_(js('typeof fields == "function"'), [
309 js('constructor = fields') 307 js('constructor = fields')
310 ], /* else */ [ 308 ], /* else */ [
311 js('var str = "function " + cls + "("'), 309 js('var str = "function " + cls + "("'),
312 js('var body = ""'), 310 js('var body = ""'),
313 311
314 // for (var i = 0; i < fields.length; i++) {
315 js.for_('var i = 0', 'i < fields.length', 'i++', [ 312 js.for_('var i = 0', 'i < fields.length', 'i++', [
316 // if (i != 0) str += ", ";
317 js.if_('i != 0', js('str += ", "')), 313 js.if_('i != 0', js('str += ", "')),
318 314
319 js('var field = fields[i]'), 315 js('var field = fields[i]'),
320 js('field = generateAccessor(field, prototype)'), 316 js('field = generateAccessor(field, prototype)'),
321 js('str += field'), 317 js('str += field'),
322 js('body += ("this." + field + " = " + field + ";\\n")') 318 js('body += ("this." + field + " = " + field + ";\\n")')
323 ]), 319 ]),
324 320
325 js('str += (") {" + body + "}\\nreturn " + cls)'), 321 js('str += (") {" + body + "}\\nreturn " + cls)'),
326 322
327 js('constructor = new Function(str)()') 323 js('constructor = new Function(str)()')
328 ]), 324 ]),
329 325
330 js('constructor.prototype = prototype'), 326 js('constructor.prototype = prototype'),
331 js('constructor.builtin\$cls = cls'), 327 js(r'constructor.builtin$cls = name'),
332 328
333 // return constructor;
334 js.return_('constructor') 329 js.return_('constructor')
335 ]); 330 ]);
336 // Declare a function called "generateAccessor". This is used in 331 // Declare a function called "generateAccessor". This is used in
337 // defineClassFunction (it's a local declaration in init()). 332 // defineClassFunction (it's a local declaration in init()).
338 return [ 333 return [
339 generateAccessorFunction, 334 generateAccessorFunction,
340 js('$generateAccessorHolder = generateAccessor'), 335 js('$generateAccessorHolder = generateAccessor'),
341 new jsAst.FunctionDeclaration( 336 new jsAst.FunctionDeclaration(
342 new jsAst.VariableDeclaration('defineClass'), defineClass) ]; 337 new jsAst.VariableDeclaration('defineClass'), defineClass) ];
343 } 338 }
344 339
345 /** Needs defineClass to be defined. */ 340 /** Needs defineClass to be defined. */
346 List buildProtoSupportCheck() { 341 List buildProtoSupportCheck() {
347 // On Firefox and Webkit browsers we can manipulate the __proto__ 342 // On Firefox and Webkit browsers we can manipulate the __proto__
348 // directly. Opera claims to have __proto__ support, but it is buggy. 343 // directly. Opera claims to have __proto__ support, but it is buggy.
349 // So we have to do more checks. 344 // So we have to do more checks.
350 // Opera bug was filed as DSK-370158, and fixed as CORE-47615 345 // Opera bug was filed as DSK-370158, and fixed as CORE-47615
351 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes). 346 // (http://my.opera.com/desktopteam/blog/2012/07/20/more-12-01-fixes).
352 // If the browser does not support __proto__ we need to instantiate an 347 // If the browser does not support __proto__ we need to instantiate an
353 // object with the correct (internal) prototype set up correctly, and then 348 // object with the correct (internal) prototype set up correctly, and then
354 // copy the members. 349 // copy the members.
355 // TODO(8541): Remove this work around. 350 // TODO(8541): Remove this work around.
356 351
357 return [ 352 return [
358 js('var $supportsProtoName = false'), 353 js('var $supportsProtoName = false'),
359 js('var tmp = defineClass("c", ["f?"], {}).prototype'), 354 js('var tmp = defineClass("c", "c", ["f?"], {}).prototype'),
360 355
361 js.if_(js('tmp.__proto__'), [ 356 js.if_(js('tmp.__proto__'), [
362 js('tmp.__proto__ = {}'), 357 js('tmp.__proto__ = {}'),
363 js.if_(js(r'typeof tmp.get$f != "undefined"'), 358 js.if_(js(r'typeof tmp.get$f != "undefined"'),
364 js('$supportsProtoName = true')) 359 js('$supportsProtoName = true'))
365 360
366 ]) 361 ])
367 ]; 362 ];
368 } 363 }
369 364
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 // constructor. 592 // constructor.
598 // For engines where we have access to the '__proto__' we can manipulate 593 // For engines where we have access to the '__proto__' we can manipulate
599 // the object literal directly. For other engines we have to create a new 594 // the object literal directly. For other engines we have to create a new
600 // object and copy over the members. 595 // object and copy over the members.
601 596
602 List<jsAst.Node> statements = [ 597 List<jsAst.Node> statements = [
603 js('var pendingClasses = {}'), 598 js('var pendingClasses = {}'),
604 599
605 js('var hasOwnProperty = Object.prototype.hasOwnProperty'), 600 js('var hasOwnProperty = Object.prototype.hasOwnProperty'),
606 601
607 // for (var cls in collectedClasses)
608 js.forIn('cls', 'collectedClasses', [ 602 js.forIn('cls', 'collectedClasses', [
609 // if (hasOwnProperty.call(collectedClasses, cls))
610 js.if_('hasOwnProperty.call(collectedClasses, cls)', [ 603 js.if_('hasOwnProperty.call(collectedClasses, cls)', [
611 js('var desc = collectedClasses[cls]'), 604 js('var desc = collectedClasses[cls]'),
612 605
613 /* The 'fields' are either a constructor function or a 606 /* The 'fields' are either a constructor function or a
614 * string encoding fields, constructor and superclass. Get 607 * string encoding fields, constructor and superclass. Get
615 * the superclass and the fields in the format 608 * the superclass and the fields in the format
616 * Super;field1,field2 from the null-string property on the 609 * name/Super;field1,field2 from the null-string property on the
617 * descriptor. 610 * descriptor.
sra1 2013/04/29 19:04:12 Commeny should say what name 'name' is. Comment sh
karlklose 2013/04/30 09:29:41 Done.
618 */ 611 */
619 js('var fields = desc[""], supr'), 612 js('var classData = desc[""], supr, name, fields'),
613 js('var split = classData.split("/")'),
614 js.if_('split.length == 2', [
615 js('name = split[0]'),
616 js('fields = split[1]')
617 ], /* else */ [
618 js('name = cls'),
619 js('fields = classData')
620 ]),
620 621
621 js.if_('typeof fields == "string"', [ 622 js.if_('typeof fields == "string"', [
622 js('var s = fields.split(";")'), 623 js('var s = fields.split(";")'),
623 js('fields = s[1] == "" ? [] : s[1].split(",")'), 624 js('fields = s[1] == "" ? [] : s[1].split(",")'),
624 js('supr = s[0]'), 625 js('supr = s[0]'),
625 ], /* else */ [ 626 ], /* else */ [
626 js('supr = desc.super'), 627 js('supr = desc.super'),
627 ]), 628 ]),
628 629
629 optional(needsMixinSupport, js.if_('supr && supr.indexOf("+") > 0', [ 630 optional(needsMixinSupport, js.if_('supr && supr.indexOf("+") > 0', [
630 js('s = supr.split("+")'), 631 js('s = supr.split("+")'),
631 js('supr = s[0]'), 632 js('supr = s[0]'),
632 js('var mixin = collectedClasses[s[1]]'), 633 js('var mixin = collectedClasses[s[1]]'),
633 js.forIn('d', 'mixin', [ 634 js.forIn('d', 'mixin', [
634 js.if_('hasOwnProperty.call(mixin, d)' 635 js.if_('hasOwnProperty.call(mixin, d)'
635 '&& !hasOwnProperty.call(desc, d)', 636 '&& !hasOwnProperty.call(desc, d)',
636 js('desc[d] = mixin[d]')) 637 js('desc[d] = mixin[d]'))
637 ]), 638 ]),
638 ])), 639 ])),
639 640
640 js('isolateProperties[cls] = defineClass(cls, fields, desc)'), 641 js('isolateProperties[cls] = defineClass(name, cls, fields, desc)'),
641 js.if_('supr', js('pendingClasses[cls] = supr')) 642 js.if_('supr', js('pendingClasses[cls] = supr'))
642 ]) 643 ])
643 ]), 644 ]),
644 645
645 js('var finishedClasses = {}'), 646 js('var finishedClasses = {}'),
646 647
647 buildFinishClass(), 648 buildFinishClass(),
648 ]; 649 ];
649 650
650 addTrivialNsmHandlers(statements); 651 addTrivialNsmHandlers(statements);
(...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after
1207 } 1208 }
1208 1209
1209 void emitIsTests(ClassElement classElement, ClassBuilder builder) { 1210 void emitIsTests(ClassElement classElement, ClassBuilder builder) {
1210 assert(invariant(classElement, classElement.isDeclaration)); 1211 assert(invariant(classElement, classElement.isDeclaration));
1211 1212
1212 void generateIsTest(Element other) { 1213 void generateIsTest(Element other) {
1213 if (other == compiler.objectClass && other != classElement) { 1214 if (other == compiler.objectClass && other != classElement) {
1214 // Avoid emitting [:$isObject:] on all classes but [Object]. 1215 // Avoid emitting [:$isObject:] on all classes but [Object].
1215 return; 1216 return;
1216 } 1217 }
1218 other = backend.getImplementationClass(other);
1217 builder.addProperty(namer.operatorIs(other), js('true')); 1219 builder.addProperty(namer.operatorIs(other), js('true'));
1218 } 1220 }
1219 1221
1220 void generateSubstitution(Element other, {bool emitNull: false}) { 1222 void generateSubstitution(Element other, {bool emitNull: false}) {
1221 RuntimeTypes rti = backend.rti; 1223 RuntimeTypes rti = backend.rti;
1222 // TODO(karlklose): support typedefs with variables. 1224 // TODO(karlklose): support typedefs with variables.
1223 jsAst.Expression expression; 1225 jsAst.Expression expression;
1224 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other); 1226 bool needsNativeCheck = nativeEmitter.requiresNativeIsCheck(other);
1225 if (other.kind == ElementKind.CLASS) { 1227 if (other.kind == ElementKind.CLASS) {
1226 String substitution = rti.getSupertypeSubstitution(classElement, other, 1228 String substitution = rti.getSupertypeSubstitution(classElement, other,
1227 alwaysGenerateFunction: true); 1229 alwaysGenerateFunction: true);
1228 if (substitution != null) { 1230 if (substitution != null) {
1229 expression = new jsAst.LiteralExpression(substitution); 1231 expression = new jsAst.LiteralExpression(substitution);
1230 } else if (emitNull || needsNativeCheck) { 1232 } else if (emitNull || needsNativeCheck) {
1231 expression = new jsAst.LiteralNull(); 1233 expression = new jsAst.LiteralNull();
1232 } 1234 }
1233 } 1235 }
1234 if (expression != null) { 1236 if (expression != null) {
1235 builder.addProperty(namer.substitutionName(other), expression); 1237 builder.addProperty(namer.substitutionName(other), expression);
1236 } 1238 }
1237 } 1239 }
1238 1240
1239 generateIsTestsOn(classElement, generateIsTest, generateSubstitution); 1241 generateIsTestsOn(classElement, generateIsTest, generateSubstitution);
1240 } 1242 }
1241 1243
1242 void emitRuntimeTypeSupport(CodeBuffer buffer) { 1244 void emitRuntimeTypeSupport(CodeBuffer buffer) {
1243 RuntimeTypes rti = backend.rti; 1245 RuntimeTypes rti = backend.rti;
1244 TypeChecks typeChecks = rti.getRequiredChecks(); 1246 TypeChecks typeChecks = rti.requiredChecks;
1245 1247
1246 /// Classes that are not instantiated and native classes need a holder 1248 // Add checks to the constructors of instantiated classes.
1247 /// object for their checks, because there will be no class defined for
1248 /// them.
1249
1250 // TODO(9556): Get rid of holders.
1251 //
1252 // - For primitive classes, use the interceptors (e.g JSInt).
1253 //
1254 // - For uninstantiated classes, define the class anyway. It will not need
1255 // fields or a constructor, or any methods, so the class definition will
1256 // be smaller than a holder.
1257
1258 bool needsHolder(ClassElement cls) {
1259 return !neededClasses.contains(cls) ||
1260 rti.isJsNative(cls);
1261 }
1262
1263 /**
1264 * Generates a holder object if it is needed. A holder is a JavaScript
1265 * object literal with a field [builtin$cls] that contains the name of the
1266 * class as a string (just like object constructors do). The is-checks for
1267 * the class are are added to the holder object later.
1268 */
1269 void maybeGenerateHolder(ClassElement cls) {
1270 if (!needsHolder(cls)) return;
1271 String holder = namer.isolateAccess(cls);
1272 String name = namer.getRuntimeTypeName(cls);
1273 buffer.write('$holder$_=$_{builtin\$cls:$_"$name"');
1274 buffer.write('}$N');
1275 }
1276
1277 // Create representation objects for classes that we do not have a class
1278 // definition for (because they are uninstantiated or native).
1279 for (ClassElement cls in rti.allArguments) {
1280 maybeGenerateHolder(cls);
1281 }
1282
1283 // Add checks to the constructors of instantiated classes or to the created
1284 // holder object.
1285 for (ClassElement cls in typeChecks) { 1249 for (ClassElement cls in typeChecks) {
1286 String holder = namer.isolateAccess(cls); 1250 String holder = namer.isolateAccess(backend.getImplementationClass(cls));
1287 for (ClassElement check in typeChecks[cls]) { 1251 for (ClassElement check in typeChecks[cls]) {
1288 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N'); 1252 buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N');
1289 String body = rti.getSupertypeSubstitution(cls, check); 1253 String body = rti.getSupertypeSubstitution(cls, check);
1290 if (body != null) { 1254 if (body != null) {
1291 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N') ; 1255 buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N') ;
1292 } 1256 }
1293 }; 1257 };
1294 } 1258 }
1295 } 1259 }
1296 1260
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
1451 /* Do nothing. */ 1415 /* Do nothing. */
1452 } 1416 }
1453 1417
1454 /// Returns `true` if fields added. 1418 /// Returns `true` if fields added.
1455 bool emitClassFields(ClassElement classElement, 1419 bool emitClassFields(ClassElement classElement,
1456 ClassBuilder builder, 1420 ClassBuilder builder,
1457 String superName, 1421 String superName,
1458 { bool classIsNative: false }) { 1422 { bool classIsNative: false }) {
1459 assert(superName != null); 1423 assert(superName != null);
1460 String separator = ''; 1424 String separator = '';
1461 StringBuffer buffer = new StringBuffer('$superName;'); 1425 String nativeName = namer.getNativeName(classElement);
1426 StringBuffer buffer = new StringBuffer();
1427 if (nativeName != null) {
1428 buffer.write('$nativeName/');
1429 }
1430 buffer.write('$superName;');
1462 int bufferClassLength = buffer.length; 1431 int bufferClassLength = buffer.length;
1463 1432
1464 visitClassFields(classElement, (Element member, 1433 visitClassFields(classElement, (Element member,
1465 String name, 1434 String name,
1466 String accessorName, 1435 String accessorName,
1467 bool needsGetter, 1436 bool needsGetter,
1468 bool needsSetter, 1437 bool needsSetter,
1469 bool needsCheckedSetter) { 1438 bool needsCheckedSetter) {
1470 // Ignore needsCheckedSetter - that is handled below. 1439 // Ignore needsCheckedSetter - that is handled below.
1471 bool needsAccessor = (needsGetter || needsSetter); 1440 bool needsAccessor = (needsGetter || needsSetter);
(...skipping 1139 matching lines...) Expand 10 before | Expand all | Expand 10 after
2611 } 2580 }
2612 2581
2613 /** 2582 /**
2614 * Compute all the classes that must be emitted. 2583 * Compute all the classes that must be emitted.
2615 */ 2584 */
2616 void computeNeededClasses() { 2585 void computeNeededClasses() {
2617 instantiatedClasses = 2586 instantiatedClasses =
2618 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter()) 2587 compiler.codegenWorld.instantiatedClasses.where(computeClassFilter())
2619 .toSet(); 2588 .toSet();
2620 2589
2590 RuntimeTypes rti = backend.rti;
2591
2621 // The set of classes that must be emitted are based on instantiated 2592 // The set of classes that must be emitted are based on instantiated
2622 // classes. 2593 // classes.
2623 neededClasses.addAll(instantiatedClasses); 2594 neededClasses.addAll(instantiatedClasses);
2595 rti.allArguments.forEach((ClassElement c) {
2596 if (!rti.isJsNative(c)) {
2597 neededClasses.add(c);
2598 }
2599 });
2624 2600
2625 // Then add all superclasses of these classes. 2601 // Then add all superclasses of these classes.
2626 for (ClassElement element in neededClasses.toList() /* copy */) { 2602 for (ClassElement element in neededClasses.toList() /* copy */) {
2627 for (ClassElement superclass = element.superclass; 2603 for (ClassElement superclass = element.superclass;
2628 superclass != null; 2604 superclass != null;
2629 superclass = superclass.superclass) { 2605 superclass = superclass.superclass) {
2630 if (neededClasses.contains(superclass)) break; 2606 if (neededClasses.contains(superclass)) break;
2631 neededClasses.add(superclass); 2607 neededClasses.add(superclass);
2632 } 2608 }
2633 } 2609 }
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after
2882 ..addAll(buildLazyInitializerFunctionIfNecessary()) 2858 ..addAll(buildLazyInitializerFunctionIfNecessary())
2883 ..addAll(buildFinishIsolateConstructor()) 2859 ..addAll(buildFinishIsolateConstructor())
2884 ); 2860 );
2885 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration( 2861 jsAst.FunctionDeclaration decl = new jsAst.FunctionDeclaration(
2886 new jsAst.VariableDeclaration('init'), fun); 2862 new jsAst.VariableDeclaration('init'), fun);
2887 buffer.write(jsAst.prettyPrint(decl, compiler).getText()); 2863 buffer.write(jsAst.prettyPrint(decl, compiler).getText());
2888 } 2864 }
2889 2865
2890 String assembleProgram() { 2866 String assembleProgram() {
2891 measure(() { 2867 measure(() {
2892 computeNeededClasses();
2893
2894 // Compute the required type checks to know which classes need a 2868 // Compute the required type checks to know which classes need a
2895 // 'is$' method. 2869 // 'is$' method.
2896 computeRequiredTypeChecks(); 2870 computeRequiredTypeChecks();
2897 2871
2872 computeNeededClasses();
2873
2898 mainBuffer.add(GENERATED_BY); 2874 mainBuffer.add(GENERATED_BY);
2899 addComment(HOOKS_API_USAGE, mainBuffer); 2875 addComment(HOOKS_API_USAGE, mainBuffer);
2900 mainBuffer.add('function ${namer.isolateName}()$_{}\n'); 2876 mainBuffer.add('function ${namer.isolateName}()$_{}\n');
2901 mainBuffer.add('init()$N$n'); 2877 mainBuffer.add('init()$N$n');
2902 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary. 2878 // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary.
2903 isolateProperties = namer.CURRENT_ISOLATE; 2879 isolateProperties = namer.CURRENT_ISOLATE;
2904 mainBuffer.add( 2880 mainBuffer.add(
2905 'var $isolateProperties$_=$_$isolatePropertiesName$N'); 2881 'var $isolateProperties$_=$_$isolatePropertiesName$N');
2906 2882
2907 if (!regularClasses.isEmpty || 2883 if (!regularClasses.isEmpty ||
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
3074 """; 3050 """;
3075 const String HOOKS_API_USAGE = """ 3051 const String HOOKS_API_USAGE = """
3076 // The code supports the following hooks: 3052 // The code supports the following hooks:
3077 // dartPrint(message) - if this function is defined it is called 3053 // dartPrint(message) - if this function is defined it is called
3078 // instead of the Dart [print] method. 3054 // instead of the Dart [print] method.
3079 // dartMainRunner(main) - if this function is defined, the Dart [main] 3055 // dartMainRunner(main) - if this function is defined, the Dart [main]
3080 // method will not be invoked directly. 3056 // method will not be invoked directly.
3081 // Instead, a closure that will invoke [main] is 3057 // Instead, a closure that will invoke [main] is
3082 // passed to [dartMainRunner]. 3058 // passed to [dartMainRunner].
3083 """; 3059 """;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698