| Index: pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
|
| diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
|
| index a575e1ccf67f0a35e3a00bc96319a34bc6c31eff..d97440f5e98ef3855c7ff0295751fa50722725b7 100644
|
| --- a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
|
| +++ b/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
|
| @@ -331,14 +331,13 @@ class OldEmitter implements Emitter {
|
|
|
| var field = generateAccessor(fields[i], accessors, name);
|
| if (#hasIsolateSupport) { fieldNames += "'" + field + "',"; }
|
| - var parameter = "parameter_" + field;
|
| + var parameter = "p_" + field;
|
| str += parameter;
|
| body += ("this." + field + " = " + parameter + ";\n");
|
| }
|
| str += ") {\n" + body + "}\n";
|
| str += name + ".builtin$cls=\"" + name + "\";\n";
|
| - str += "$desc=$collectedClasses." + name + ";\n";
|
| - str += "if($desc instanceof Array) $desc = \$desc[1];\n";
|
| + str += "$desc=$collectedClasses." + name + "[1];\n";
|
| str += name + ".prototype = $desc;\n";
|
| if (typeof defineClass.name != "string") {
|
| str += name + ".name=\"" + name + "\";\n";
|
| @@ -420,25 +419,37 @@ class OldEmitter implements Emitter {
|
|
|
| /** Needs defineClass to be defined. */
|
| jsAst.Expression buildInheritFrom() {
|
| - jsAst.Expression result = js(r'''
|
| + jsAst.Expression result = js(r"""
|
| + // If the browser supports changing the prototype via __proto__, we make
|
| + // use of that feature. Otherwise, we copy the properties into a new
|
| + // constructor.
|
| + (function () {
|
| + var cls = function () {};
|
| + cls.prototype = {'p': {}};
|
| + var object = new cls();
|
| + return object.__proto__ &&
|
| + object.__proto__.p === cls.prototype.p;
|
| + })() ?
|
| + function(constructor, superConstructor) {
|
| + var prototype = constructor.prototype;
|
| + prototype.__proto__ = superConstructor.prototype;
|
| + // Use a function for `true` here, as functions are stored in the
|
| + // hidden class and not as properties in the object.
|
| + prototype.constructor = constructor;
|
| + prototype[#operatorIsPrefix + constructor.name] = constructor;
|
| + return convertToFastObject(prototype);
|
| + } :
|
| function() {
|
| function tmp() {}
|
| - var hasOwnProperty = Object.prototype.hasOwnProperty;
|
| return function (constructor, superConstructor) {
|
| - if (superConstructor == null) {
|
| - // Fix up the the Dart Object class' prototype.
|
| - var prototype = constructor.prototype;
|
| - prototype.constructor = constructor;
|
| - prototype.#isObject = constructor;
|
| - return prototype;
|
| - }
|
| tmp.prototype = superConstructor.prototype;
|
| var object = new tmp();
|
| + convertToSlowObject(object);
|
| var properties = constructor.prototype;
|
| - for (var member in properties) {
|
| - if (hasOwnProperty.call(properties, member)) {
|
| - object[member] = properties[member];
|
| - }
|
| + var members = Object.keys(properties);
|
| + for (var i = 0; i < members.length; i++) {
|
| + var member = members[i];
|
| + object[member] = properties[member];
|
| }
|
| // Use a function for `true` here, as functions are stored in the
|
| // hidden class and not as properties in the object.
|
| @@ -448,8 +459,7 @@ class OldEmitter implements Emitter {
|
| return object;
|
| };
|
| }()
|
| - ''', { 'operatorIsPrefix' : js.string(namer.operatorIsPrefix),
|
| - 'isObject' : namer.operatorIs(compiler.objectClass) });
|
| + """, { 'operatorIsPrefix' : js.string(namer.operatorIsPrefix)});
|
| if (compiler.hasIncrementalSupport) {
|
| result = js(
|
| r'#.inheritFrom = #', [namer.accessIncrementalHelper, result]);
|
| @@ -498,9 +508,11 @@ class OldEmitter implements Emitter {
|
| var mixin = allClasses[mixinClass];
|
| var mixinPrototype = mixin.prototype;
|
| var clsPrototype = allClasses[cls].prototype;
|
| - for (var d in mixinPrototype) {
|
| - if (hasOwnProperty.call(mixinPrototype, d) &&
|
| - !hasOwnProperty.call(clsPrototype, d))
|
| +
|
| + var properties = Object.keys(mixinPrototype);
|
| + for (var i = 0; i < properties.length; i++) {
|
| + var d = properties[i];
|
| + if (!hasOwnProperty.call(clsPrototype, d))
|
| clsPrototype[d] = mixinPrototype[d];
|
| }
|
| }
|
| @@ -511,7 +523,12 @@ class OldEmitter implements Emitter {
|
| // the Object.prototype object, and they show through here, so we check
|
| // that we have a string.
|
| if (!superclass || typeof superclass != "string") {
|
| - inheritFrom(allClasses[cls], null);
|
| + // Inlined special case of InheritFrom here for performance reasons.
|
| + // Fix up the the Dart Object class' prototype.
|
| + var constructor = allClasses[cls];
|
| + var prototype = constructor.prototype;
|
| + prototype.constructor = constructor;
|
| + prototype.#isObject = constructor;
|
| return;
|
| }
|
| finishClass(superclass);
|
| @@ -530,7 +547,8 @@ class OldEmitter implements Emitter {
|
| }''', {'finishedClassesAccess': finishedClassesAccess,
|
| 'needsMixinSupport': needsMixinSupport,
|
| 'hasNativeClasses': hasNativeClasses,
|
| - 'nativeInfoHandler': nativeInfoHandler});
|
| + 'nativeInfoHandler': nativeInfoHandler,
|
| + 'isObject' : namer.operatorIs(compiler.objectClass) });
|
| }
|
|
|
| void emitFinishIsolateConstructorInvocation(CodeOutput output) {
|
| @@ -1014,10 +1032,12 @@ class OldEmitter implements Emitter {
|
| $finishIsolateConstructorName = function (oldIsolate) {
|
| var isolateProperties = oldIsolate.#isolatePropertiesName;
|
| function Isolate() {
|
| - var hasOwnProperty = Object.prototype.hasOwnProperty;
|
| - for (var staticName in isolateProperties)
|
| - if (hasOwnProperty.call(isolateProperties, staticName))
|
| - this[staticName] = isolateProperties[staticName];
|
| +
|
| + var staticNames = Object.keys(isolateProperties);
|
| + for (var i = 0; i < staticNames.length; i++) {
|
| + var staticName = staticNames[i];
|
| + this[staticName] = isolateProperties[staticName];
|
| + }
|
|
|
| // Reset lazy initializers to null.
|
| // When forcing the object to fast mode (below) v8 will consider
|
| @@ -1025,8 +1045,9 @@ class OldEmitter implements Emitter {
|
| // (after the first call to the getter), we would have a map
|
| // transition.
|
| var lazies = init.lazies;
|
| - for (var lazyInit in lazies) {
|
| - this[lazies[lazyInit]] = null;
|
| + var lazyInitializers = lazies ? Object.keys(lazies) : [];
|
| + for (var i = 0; i < lazyInitializers.length; i++) {
|
| + this[lazies[lazyInitializers[i]]] = null;
|
| }
|
|
|
| // Use the newly created object as prototype. In Chrome,
|
| @@ -1037,8 +1058,8 @@ class OldEmitter implements Emitter {
|
| new ForceEfficientMap();
|
|
|
| // Now, after being a fast map we can set the lazies again.
|
| - for (var lazyInit in lazies) {
|
| - var lazyInitName = lazies[lazyInit];
|
| + for (var i = 0; i < lazyInitializers.length; i++) {
|
| + var lazyInitName = lazies[lazyInitializers[i]];
|
| this[lazyInitName] = isolateProperties[lazyInitName];
|
| }
|
| }
|
| @@ -1106,6 +1127,20 @@ class OldEmitter implements Emitter {
|
| output.add(N);
|
| }
|
|
|
| + void emitConvertToSlowObjectFunction(CodeOutput output) {
|
| + jsAst.Statement convertToSlowObject = js.statement(r'''
|
| + function convertToSlowObject(properties) {
|
| + // Add and remove a property to make the object transition into hashmap
|
| + // mode.
|
| + properties.__MAGIC_SLOW_PROPERTY = 1;
|
| + delete properties.__MAGIC_SLOW_PROPERTY;
|
| + return properties;
|
| + }''');
|
| +
|
| + output.addBuffer(jsAst.prettyPrint(convertToSlowObject, compiler));
|
| + output.add(N);
|
| + }
|
| +
|
| void writeLibraryDescriptors(CodeOutput output, LibraryElement library) {
|
| var uri = "";
|
| if (!compiler.enableMinification || backend.mustPreserveUris) {
|
| @@ -1470,6 +1505,8 @@ class OldEmitter implements Emitter {
|
| '${namer.currentIsolate}$_=${_}new ${namer.isolateName}()$N');
|
|
|
| emitConvertToFastObjectFunction(mainOutput);
|
| + emitConvertToSlowObjectFunction(mainOutput);
|
| +
|
| for (String globalObject in Namer.reservedGlobalObjectNames) {
|
| mainOutput.add('$globalObject = convertToFastObject($globalObject)$N');
|
| }
|
|
|