| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 dart2js.js_emitter; | 5 part of dart2js.js_emitter; |
| 6 | 6 |
| 7 | 7 |
| 8 class OldEmitter implements Emitter { | 8 class OldEmitter implements Emitter { |
| 9 final Compiler compiler; | 9 final Compiler compiler; |
| 10 final CodeEmitterTask task; | 10 final CodeEmitterTask task; |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 | 324 |
| 325 var str = "function " + name + "("; | 325 var str = "function " + name + "("; |
| 326 var body = ""; | 326 var body = ""; |
| 327 if (#hasIsolateSupport) { var fieldNames = ""; } | 327 if (#hasIsolateSupport) { var fieldNames = ""; } |
| 328 | 328 |
| 329 for (var i = 0; i < fields.length; i++) { | 329 for (var i = 0; i < fields.length; i++) { |
| 330 if(i != 0) str += ", "; | 330 if(i != 0) str += ", "; |
| 331 | 331 |
| 332 var field = generateAccessor(fields[i], accessors, name); | 332 var field = generateAccessor(fields[i], accessors, name); |
| 333 if (#hasIsolateSupport) { fieldNames += "'" + field + "',"; } | 333 if (#hasIsolateSupport) { fieldNames += "'" + field + "',"; } |
| 334 var parameter = "parameter_" + field; | 334 var parameter = "p_" + field; |
| 335 str += parameter; | 335 str += parameter; |
| 336 body += ("this." + field + " = " + parameter + ";\n"); | 336 body += ("this." + field + " = " + parameter + ";\n"); |
| 337 } | 337 } |
| 338 str += ") {\n" + body + "}\n"; | 338 str += ") {\n" + body + "}\n"; |
| 339 str += name + ".builtin$cls=\"" + name + "\";\n"; | 339 str += name + ".builtin$cls=\"" + name + "\";\n"; |
| 340 str += "$desc=$collectedClasses." + name + ";\n"; | 340 str += "$desc=$collectedClasses." + name + "[1];\n"; |
| 341 str += "if($desc instanceof Array) $desc = \$desc[1];\n"; | |
| 342 str += name + ".prototype = $desc;\n"; | 341 str += name + ".prototype = $desc;\n"; |
| 343 if (typeof defineClass.name != "string") { | 342 if (typeof defineClass.name != "string") { |
| 344 str += name + ".name=\"" + name + "\";\n"; | 343 str += name + ".name=\"" + name + "\";\n"; |
| 345 } | 344 } |
| 346 if (#hasIsolateSupport) { | 345 if (#hasIsolateSupport) { |
| 347 str += name + "." + #fieldNamesProperty + "=[" + fieldNames | 346 str += name + "." + #fieldNamesProperty + "=[" + fieldNames |
| 348 + "];\n"; | 347 + "];\n"; |
| 349 } | 348 } |
| 350 str += accessors.join(""); | 349 str += accessors.join(""); |
| 351 | 350 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 classFieldsExtractorAssignment, | 412 classFieldsExtractorAssignment, |
| 414 instanceFromClassIdAssignment, | 413 instanceFromClassIdAssignment, |
| 415 initializeEmptyInstanceAssignment]); | 414 initializeEmptyInstanceAssignment]); |
| 416 } | 415 } |
| 417 | 416 |
| 418 return result; | 417 return result; |
| 419 } | 418 } |
| 420 | 419 |
| 421 /** Needs defineClass to be defined. */ | 420 /** Needs defineClass to be defined. */ |
| 422 jsAst.Expression buildInheritFrom() { | 421 jsAst.Expression buildInheritFrom() { |
| 423 jsAst.Expression result = js(r''' | 422 jsAst.Expression result = js(r""" |
| 423 // If the browser supports changing the prototype via __proto__, we make |
| 424 // use of that feature. Otherwise, we copy the properties into a new |
| 425 // constructor. |
| 426 (function () { |
| 427 var cls = function () {}; |
| 428 cls.prototype = {'p': {}}; |
| 429 var object = new cls(); |
| 430 return object.__proto__ && |
| 431 object.__proto__.p === cls.prototype.p; |
| 432 })() ? |
| 433 function(constructor, superConstructor) { |
| 434 var prototype = constructor.prototype; |
| 435 prototype.__proto__ = superConstructor.prototype; |
| 436 // Use a function for `true` here, as functions are stored in the |
| 437 // hidden class and not as properties in the object. |
| 438 prototype.constructor = constructor; |
| 439 prototype[#operatorIsPrefix + constructor.name] = constructor; |
| 440 return convertToFastObject(prototype); |
| 441 } : |
| 424 function() { | 442 function() { |
| 425 function tmp() {} | 443 function tmp() {} |
| 426 var hasOwnProperty = Object.prototype.hasOwnProperty; | |
| 427 return function (constructor, superConstructor) { | 444 return function (constructor, superConstructor) { |
| 428 if (superConstructor == null) { | |
| 429 // Fix up the the Dart Object class' prototype. | |
| 430 var prototype = constructor.prototype; | |
| 431 prototype.constructor = constructor; | |
| 432 prototype.#isObject = constructor; | |
| 433 return prototype; | |
| 434 } | |
| 435 tmp.prototype = superConstructor.prototype; | 445 tmp.prototype = superConstructor.prototype; |
| 436 var object = new tmp(); | 446 var object = new tmp(); |
| 447 convertToSlowObject(object); |
| 437 var properties = constructor.prototype; | 448 var properties = constructor.prototype; |
| 438 for (var member in properties) { | 449 var members = Object.keys(properties); |
| 439 if (hasOwnProperty.call(properties, member)) { | 450 for (var i = 0; i < members.length; i++) { |
| 440 object[member] = properties[member]; | 451 var member = members[i]; |
| 441 } | 452 object[member] = properties[member]; |
| 442 } | 453 } |
| 443 // Use a function for `true` here, as functions are stored in the | 454 // Use a function for `true` here, as functions are stored in the |
| 444 // hidden class and not as properties in the object. | 455 // hidden class and not as properties in the object. |
| 445 object[#operatorIsPrefix + constructor.name] = constructor; | 456 object[#operatorIsPrefix + constructor.name] = constructor; |
| 446 object.constructor = constructor; | 457 object.constructor = constructor; |
| 447 constructor.prototype = object; | 458 constructor.prototype = object; |
| 448 return object; | 459 return object; |
| 449 }; | 460 }; |
| 450 }() | 461 }() |
| 451 ''', { 'operatorIsPrefix' : js.string(namer.operatorIsPrefix), | 462 """, { 'operatorIsPrefix' : js.string(namer.operatorIsPrefix)}); |
| 452 'isObject' : namer.operatorIs(compiler.objectClass) }); | |
| 453 if (compiler.hasIncrementalSupport) { | 463 if (compiler.hasIncrementalSupport) { |
| 454 result = js( | 464 result = js( |
| 455 r'#.inheritFrom = #', [namer.accessIncrementalHelper, result]); | 465 r'#.inheritFrom = #', [namer.accessIncrementalHelper, result]); |
| 456 } | 466 } |
| 457 return js(r'var inheritFrom = #', [result]); | 467 return js(r'var inheritFrom = #', [result]); |
| 458 } | 468 } |
| 459 | 469 |
| 460 jsAst.Statement buildFinishClass(bool hasNativeClasses) { | 470 jsAst.Statement buildFinishClass(bool hasNativeClasses) { |
| 461 String specProperty = '"${namer.nativeSpecProperty}"'; // "%" | 471 String specProperty = '"${namer.nativeSpecProperty}"'; // "%" |
| 462 | 472 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 491 | 501 |
| 492 if (#needsMixinSupport) { | 502 if (#needsMixinSupport) { |
| 493 if (superclass && superclass.indexOf("+") > 0) { | 503 if (superclass && superclass.indexOf("+") > 0) { |
| 494 var s = superclass.split("+"); | 504 var s = superclass.split("+"); |
| 495 superclass = s[0]; | 505 superclass = s[0]; |
| 496 var mixinClass = s[1]; | 506 var mixinClass = s[1]; |
| 497 finishClass(mixinClass); | 507 finishClass(mixinClass); |
| 498 var mixin = allClasses[mixinClass]; | 508 var mixin = allClasses[mixinClass]; |
| 499 var mixinPrototype = mixin.prototype; | 509 var mixinPrototype = mixin.prototype; |
| 500 var clsPrototype = allClasses[cls].prototype; | 510 var clsPrototype = allClasses[cls].prototype; |
| 501 for (var d in mixinPrototype) { | 511 |
| 502 if (hasOwnProperty.call(mixinPrototype, d) && | 512 var properties = Object.keys(mixinPrototype); |
| 503 !hasOwnProperty.call(clsPrototype, d)) | 513 for (var i = 0; i < properties.length; i++) { |
| 514 var d = properties[i]; |
| 515 if (!hasOwnProperty.call(clsPrototype, d)) |
| 504 clsPrototype[d] = mixinPrototype[d]; | 516 clsPrototype[d] = mixinPrototype[d]; |
| 505 } | 517 } |
| 506 } | 518 } |
| 507 } | 519 } |
| 508 | 520 |
| 509 // The superclass is only false (empty string) for the Dart Object | 521 // The superclass is only false (empty string) for the Dart Object |
| 510 // class. The minifier together with noSuchMethod can put methods on | 522 // class. The minifier together with noSuchMethod can put methods on |
| 511 // the Object.prototype object, and they show through here, so we check | 523 // the Object.prototype object, and they show through here, so we check |
| 512 // that we have a string. | 524 // that we have a string. |
| 513 if (!superclass || typeof superclass != "string") { | 525 if (!superclass || typeof superclass != "string") { |
| 514 inheritFrom(allClasses[cls], null); | 526 // Inlined special case of InheritFrom here for performance reasons. |
| 527 // Fix up the the Dart Object class' prototype. |
| 528 var constructor = allClasses[cls]; |
| 529 var prototype = constructor.prototype; |
| 530 prototype.constructor = constructor; |
| 531 prototype.#isObject = constructor; |
| 515 return; | 532 return; |
| 516 } | 533 } |
| 517 finishClass(superclass); | 534 finishClass(superclass); |
| 518 var superConstructor = allClasses[superclass]; | 535 var superConstructor = allClasses[superclass]; |
| 519 | 536 |
| 520 if (!superConstructor) | 537 if (!superConstructor) |
| 521 superConstructor = existingIsolateProperties[superclass]; | 538 superConstructor = existingIsolateProperties[superclass]; |
| 522 | 539 |
| 523 var constructor = allClasses[cls]; | 540 var constructor = allClasses[cls]; |
| 524 var prototype = inheritFrom(constructor, superConstructor); | 541 var prototype = inheritFrom(constructor, superConstructor); |
| 525 | 542 |
| 526 if (#hasNativeClasses) | 543 if (#hasNativeClasses) |
| 527 if (Object.prototype.hasOwnProperty.call(prototype, $specProperty)) | 544 if (Object.prototype.hasOwnProperty.call(prototype, $specProperty)) |
| 528 #nativeInfoHandler | 545 #nativeInfoHandler |
| 529 } | 546 } |
| 530 }''', {'finishedClassesAccess': finishedClassesAccess, | 547 }''', {'finishedClassesAccess': finishedClassesAccess, |
| 531 'needsMixinSupport': needsMixinSupport, | 548 'needsMixinSupport': needsMixinSupport, |
| 532 'hasNativeClasses': hasNativeClasses, | 549 'hasNativeClasses': hasNativeClasses, |
| 533 'nativeInfoHandler': nativeInfoHandler}); | 550 'nativeInfoHandler': nativeInfoHandler, |
| 551 'isObject' : namer.operatorIs(compiler.objectClass) }); |
| 534 } | 552 } |
| 535 | 553 |
| 536 void emitFinishIsolateConstructorInvocation(CodeOutput output) { | 554 void emitFinishIsolateConstructorInvocation(CodeOutput output) { |
| 537 String isolate = namer.isolateName; | 555 String isolate = namer.isolateName; |
| 538 output.add("$isolate = $finishIsolateConstructorName($isolate)$N"); | 556 output.add("$isolate = $finishIsolateConstructorName($isolate)$N"); |
| 539 } | 557 } |
| 540 | 558 |
| 541 /// In minified mode we want to keep the name for the most common core types. | 559 /// In minified mode we want to keep the name for the most common core types. |
| 542 bool _isNativeTypeNeedingReflectionName(Element element) { | 560 bool _isNativeTypeNeedingReflectionName(Element element) { |
| 543 if (!element.isClass) return false; | 561 if (!element.isClass) return false; |
| (...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1007 | 1025 |
| 1008 // We replace the old Isolate function with a new one that initializes | 1026 // We replace the old Isolate function with a new one that initializes |
| 1009 // all its fields with the initial (and often final) value of all | 1027 // all its fields with the initial (and often final) value of all |
| 1010 // globals. | 1028 // globals. |
| 1011 // | 1029 // |
| 1012 // We also copy over old values like the prototype, and the | 1030 // We also copy over old values like the prototype, and the |
| 1013 // isolateProperties themselves. | 1031 // isolateProperties themselves. |
| 1014 $finishIsolateConstructorName = function (oldIsolate) { | 1032 $finishIsolateConstructorName = function (oldIsolate) { |
| 1015 var isolateProperties = oldIsolate.#isolatePropertiesName; | 1033 var isolateProperties = oldIsolate.#isolatePropertiesName; |
| 1016 function Isolate() { | 1034 function Isolate() { |
| 1017 var hasOwnProperty = Object.prototype.hasOwnProperty; | 1035 |
| 1018 for (var staticName in isolateProperties) | 1036 var staticNames = Object.keys(isolateProperties); |
| 1019 if (hasOwnProperty.call(isolateProperties, staticName)) | 1037 for (var i = 0; i < staticNames.length; i++) { |
| 1020 this[staticName] = isolateProperties[staticName]; | 1038 var staticName = staticNames[i]; |
| 1039 this[staticName] = isolateProperties[staticName]; |
| 1040 } |
| 1021 | 1041 |
| 1022 // Reset lazy initializers to null. | 1042 // Reset lazy initializers to null. |
| 1023 // When forcing the object to fast mode (below) v8 will consider | 1043 // When forcing the object to fast mode (below) v8 will consider |
| 1024 // functions as part the object's map. Since we will change them | 1044 // functions as part the object's map. Since we will change them |
| 1025 // (after the first call to the getter), we would have a map | 1045 // (after the first call to the getter), we would have a map |
| 1026 // transition. | 1046 // transition. |
| 1027 var lazies = init.lazies; | 1047 var lazies = init.lazies; |
| 1028 for (var lazyInit in lazies) { | 1048 var lazyInitializers = lazies ? Object.keys(lazies) : []; |
| 1029 this[lazies[lazyInit]] = null; | 1049 for (var i = 0; i < lazyInitializers.length; i++) { |
| 1050 this[lazies[lazyInitializers[i]]] = null; |
| 1030 } | 1051 } |
| 1031 | 1052 |
| 1032 // Use the newly created object as prototype. In Chrome, | 1053 // Use the newly created object as prototype. In Chrome, |
| 1033 // this creates a hidden class for the object and makes | 1054 // this creates a hidden class for the object and makes |
| 1034 // sure it is fast to access. | 1055 // sure it is fast to access. |
| 1035 function ForceEfficientMap() {} | 1056 function ForceEfficientMap() {} |
| 1036 ForceEfficientMap.prototype = this; | 1057 ForceEfficientMap.prototype = this; |
| 1037 new ForceEfficientMap(); | 1058 new ForceEfficientMap(); |
| 1038 | 1059 |
| 1039 // Now, after being a fast map we can set the lazies again. | 1060 // Now, after being a fast map we can set the lazies again. |
| 1040 for (var lazyInit in lazies) { | 1061 for (var i = 0; i < lazyInitializers.length; i++) { |
| 1041 var lazyInitName = lazies[lazyInit]; | 1062 var lazyInitName = lazies[lazyInitializers[i]]; |
| 1042 this[lazyInitName] = isolateProperties[lazyInitName]; | 1063 this[lazyInitName] = isolateProperties[lazyInitName]; |
| 1043 } | 1064 } |
| 1044 } | 1065 } |
| 1045 Isolate.prototype = oldIsolate.prototype; | 1066 Isolate.prototype = oldIsolate.prototype; |
| 1046 Isolate.prototype.constructor = Isolate; | 1067 Isolate.prototype.constructor = Isolate; |
| 1047 Isolate.#isolatePropertiesName = isolateProperties; | 1068 Isolate.#isolatePropertiesName = isolateProperties; |
| 1048 if (#outputContainsConstantList) { | 1069 if (#outputContainsConstantList) { |
| 1049 Isolate.#makeConstListProperty = oldIsolate.#makeConstListProperty; | 1070 Isolate.#makeConstListProperty = oldIsolate.#makeConstListProperty; |
| 1050 } | 1071 } |
| 1051 if (#hasIncrementalSupport) { | 1072 if (#hasIncrementalSupport) { |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1099 MyClass.prototype = properties; | 1120 MyClass.prototype = properties; |
| 1100 new MyClass(); | 1121 new MyClass(); |
| 1101 #; | 1122 #; |
| 1102 return properties; | 1123 return properties; |
| 1103 }''', [debugCode]); | 1124 }''', [debugCode]); |
| 1104 | 1125 |
| 1105 output.addBuffer(jsAst.prettyPrint(convertToFastObject, compiler)); | 1126 output.addBuffer(jsAst.prettyPrint(convertToFastObject, compiler)); |
| 1106 output.add(N); | 1127 output.add(N); |
| 1107 } | 1128 } |
| 1108 | 1129 |
| 1130 void emitConvertToSlowObjectFunction(CodeOutput output) { |
| 1131 jsAst.Statement convertToSlowObject = js.statement(r''' |
| 1132 function convertToSlowObject(properties) { |
| 1133 // Add and remove a property to make the object transition into hashmap |
| 1134 // mode. |
| 1135 properties.__MAGIC_SLOW_PROPERTY = 1; |
| 1136 delete properties.__MAGIC_SLOW_PROPERTY; |
| 1137 return properties; |
| 1138 }'''); |
| 1139 |
| 1140 output.addBuffer(jsAst.prettyPrint(convertToSlowObject, compiler)); |
| 1141 output.add(N); |
| 1142 } |
| 1143 |
| 1109 void writeLibraryDescriptors(CodeOutput output, LibraryElement library) { | 1144 void writeLibraryDescriptors(CodeOutput output, LibraryElement library) { |
| 1110 var uri = ""; | 1145 var uri = ""; |
| 1111 if (!compiler.enableMinification || backend.mustPreserveUris) { | 1146 if (!compiler.enableMinification || backend.mustPreserveUris) { |
| 1112 uri = library.canonicalUri; | 1147 uri = library.canonicalUri; |
| 1113 if (uri.scheme == 'file' && compiler.outputUri != null) { | 1148 if (uri.scheme == 'file' && compiler.outputUri != null) { |
| 1114 uri = relativize(compiler.outputUri, library.canonicalUri, false); | 1149 uri = relativize(compiler.outputUri, library.canonicalUri, false); |
| 1115 } | 1150 } |
| 1116 } | 1151 } |
| 1117 ClassBuilder descriptor = elementDescriptors[library]; | 1152 ClassBuilder descriptor = elementDescriptors[library]; |
| 1118 if (descriptor == null) { | 1153 if (descriptor == null) { |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1463 isolateProperties = isolatePropertiesName; | 1498 isolateProperties = isolatePropertiesName; |
| 1464 // The following code should not use the short-hand for the | 1499 // The following code should not use the short-hand for the |
| 1465 // initialStatics. | 1500 // initialStatics. |
| 1466 mainOutput.add('${namer.currentIsolate}$_=${_}null$N'); | 1501 mainOutput.add('${namer.currentIsolate}$_=${_}null$N'); |
| 1467 | 1502 |
| 1468 emitFinishIsolateConstructorInvocation(mainOutput); | 1503 emitFinishIsolateConstructorInvocation(mainOutput); |
| 1469 mainOutput.add( | 1504 mainOutput.add( |
| 1470 '${namer.currentIsolate}$_=${_}new ${namer.isolateName}()$N'); | 1505 '${namer.currentIsolate}$_=${_}new ${namer.isolateName}()$N'); |
| 1471 | 1506 |
| 1472 emitConvertToFastObjectFunction(mainOutput); | 1507 emitConvertToFastObjectFunction(mainOutput); |
| 1508 emitConvertToSlowObjectFunction(mainOutput); |
| 1509 |
| 1473 for (String globalObject in Namer.reservedGlobalObjectNames) { | 1510 for (String globalObject in Namer.reservedGlobalObjectNames) { |
| 1474 mainOutput.add('$globalObject = convertToFastObject($globalObject)$N'); | 1511 mainOutput.add('$globalObject = convertToFastObject($globalObject)$N'); |
| 1475 } | 1512 } |
| 1476 if (DEBUG_FAST_OBJECTS) { | 1513 if (DEBUG_FAST_OBJECTS) { |
| 1477 mainOutput.add(r''' | 1514 mainOutput.add(r''' |
| 1478 // The following only works on V8 when run with option | 1515 // The following only works on V8 when run with option |
| 1479 // "--allow-natives-syntax". We use'new Function' because the | 1516 // "--allow-natives-syntax". We use'new Function' because the |
| 1480 // miniparser does not understand V8 native syntax. | 1517 // miniparser does not understand V8 native syntax. |
| 1481 if (typeof print === "function") { | 1518 if (typeof print === "function") { |
| 1482 var HasFastProperties = | 1519 var HasFastProperties = |
| (...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1997 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { | 2034 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { |
| 1998 if (element.isInstanceMember) { | 2035 if (element.isInstanceMember) { |
| 1999 cachedClassBuilders.remove(element.enclosingClass); | 2036 cachedClassBuilders.remove(element.enclosingClass); |
| 2000 | 2037 |
| 2001 nativeEmitter.cachedBuilders.remove(element.enclosingClass); | 2038 nativeEmitter.cachedBuilders.remove(element.enclosingClass); |
| 2002 | 2039 |
| 2003 } | 2040 } |
| 2004 } | 2041 } |
| 2005 } | 2042 } |
| 2006 } | 2043 } |
| OLD | NEW |