Chromium Code Reviews| 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 ce3e760d3db6a388b64dea8705616005e28b727c..fa574947ad0ec5096f2175ff0aa7557c79e5d54e 100644 |
| --- a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart |
| +++ b/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart |
| @@ -381,6 +381,9 @@ class OldEmitter implements Emitter { |
| str += parameter; |
| body += ("this." + field + " = " + parameter + ";\n"); |
| } |
| + if (supportsDirectProtoAccess) { |
| + body += "this." + #deferredAction + "();"; |
| + } |
| str += ") {\n" + body + "}\n"; |
| str += name + ".builtin$cls=\"" + name + "\";\n"; |
| str += "$desc=$collectedClasses." + name + "[1];\n"; |
| @@ -395,7 +398,8 @@ class OldEmitter implements Emitter { |
| str += accessors.join(""); |
| return str; |
| - }''', { 'hasIsolateSupport': hasIsolateSupport, |
| + }''', { 'deferredAction': js.string(namer.deferredAction), |
|
floitsch
2015/03/11 13:59:33
potentially create the string here?
(although mayb
herhut
2015/03/13 12:28:52
I would prefer to leave the fact that it is a call
|
| + 'hasIsolateSupport': hasIsolateSupport, |
| 'fieldNamesProperty': js.string(fieldNamesProperty)}); |
| // Declare a function called "generateAccessor". This is used in |
| @@ -466,12 +470,25 @@ class OldEmitter implements Emitter { |
| /** Needs defineClass to be defined. */ |
| jsAst.Expression buildInheritFrom() { |
| 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. |
| + supportsDirectProtoAccess ? |
| + 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() {} |
| return function (constructor, superConstructor) { |
| tmp.prototype = superConstructor.prototype; |
| var object = new tmp(); |
| - object.x = 0; delete object.x; // Make object slow. |
| + convertToSlowObject(object); |
| var properties = constructor.prototype; |
| var members = Object.keys(properties); |
| for (var i = 0; i < members.length; i++) { |
| @@ -556,25 +573,43 @@ class OldEmitter implements Emitter { |
| var prototype = constructor.prototype; |
| prototype.constructor = constructor; |
| prototype.#isObject = constructor; |
| + prototype.#deferredAction = #markerFun; |
| return; |
| } |
| finishClass(superclass); |
| var superConstructor = allClasses[superclass]; |
| - if (!superConstructor) |
| + if (!superConstructor) { |
| superConstructor = existingIsolateProperties[superclass]; |
| + } |
| var constructor = allClasses[cls]; |
| var prototype = inheritFrom(constructor, superConstructor); |
| - if (#needsNativeSupport) |
| - if (Object.prototype.hasOwnProperty.call(prototype, $specProperty)) |
| - #nativeInfoHandler |
| + if (#needsNativeSupport) { |
| + if (Object.prototype.hasOwnProperty.call(prototype, $specProperty)) { |
| + #nativeInfoHandler; |
| + // As native classes can come into existence without a constructor |
| + // call, we have to ensure that the class has been fully |
| + // initialized. |
| + if (constructor.prototype.#deferredAction) |
| + finishAddStubsHelper(constructor.prototype); |
| + } |
| + } |
| + // Interceptors (or rather their prototypes) are also used without |
| + // first instantiating them first. |
| + if (prototype.#isInterceptorClass && |
| + constructor.prototype.#deferredAction) { |
| + finishAddStubsHelper(constructor.prototype); |
| + } |
| } |
| - }''', {'finishedClassesAccess': finishedClassesAccess, |
| + }''', {'deferredAction': namer.deferredAction, |
| + 'finishedClassesAccess': finishedClassesAccess, |
| + 'markerFun': markerFun, |
| 'needsMixinSupport': needsMixinSupport, |
| 'needsNativeSupport': needsNativeSupport, |
| 'nativeInfoHandler': nativeInfoHandler, |
| + 'isInterceptorClass': namer.operatorIs(backend.jsInterceptorClass), |
| 'isObject' : namer.operatorIs(compiler.objectClass) }); |
| } |
| @@ -1098,6 +1133,20 @@ class OldEmitter implements Emitter { |
| } |
| } |
| + String get markerFun => backend.namer.internalGlobal('markerFun'); |
| + |
| + void emitMarkerFun(CodeOutput output) { |
| + jsAst.Statement markerFunStmt = js.statement(''' |
| + // This function is used to mark the end of the inheritance chain so that |
| + // finishAddStubsHelper knows where to stop searching for deferred work. |
| + // We have to put it at the top level so that we only get one instance of |
| + // it even if we call parseReflectionData multiple times, e.g., due to |
| + // deferred loading. |
| + function #() {}''', markerFun); |
| + output.addBuffer(jsAst.prettyPrint(markerFunStmt, compiler)); |
| + output.add(N); |
| + } |
| + |
| void emitConvertToFastObjectFunction(CodeOutput output) { |
| List<jsAst.Statement> debugCode = <jsAst.Statement>[]; |
| if (DEBUG_FAST_OBJECTS) { |
| @@ -1129,6 +1178,35 @@ 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 emitSupportsDirectProtoAccess(CodeOutput output) { |
| + jsAst.Statement supportsDirectProtoAccess = js.statement(r''' |
| + var supportsDirectProtoAccess = (function () { |
| + var cls = function () {}; |
| + cls.prototype = {'p': {}}; |
| + var object = new cls(); |
| + return object.__proto__ && |
| + object.__proto__.p === cls.prototype.p; |
| + })(); |
| + '''); |
| + |
| + output.addBuffer(jsAst.prettyPrint(supportsDirectProtoAccess, compiler)); |
| + output.add(N); |
| + } |
| + |
| void writeLibraryDescriptors(CodeOutput output, LibraryElement library) { |
| var uri = ""; |
| if (!compiler.enableMinification || backend.mustPreserveUris) { |
| @@ -1357,6 +1435,7 @@ class OldEmitter implements Emitter { |
| // Using a named function here produces easier to read stack traces in |
| // Chrome/V8. |
| mainOutput.add('(function(${namer.currentIsolate})$_{\n'); |
| + emitSupportsDirectProtoAccess(mainOutput); |
| if (compiler.hasIncrementalSupport) { |
| mainOutput.addBuffer(jsAst.prettyPrint(js.statement( |
| """ |
| @@ -1437,12 +1516,10 @@ class OldEmitter implements Emitter { |
| } |
| bool needsNativeSupport = program.needsNativeSupport; |
| - mainOutput |
| - ..addBuffer( |
| - jsAst.prettyPrint( |
| - getReflectionDataParser(this, backend, needsNativeSupport), |
| - compiler)) |
| - ..add(n); |
| + mainOutput.addBuffer( |
| + jsAst.prettyPrint( |
| + getReflectionDataParser(this, backend, needsNativeSupport), |
| + compiler)); |
| // The argument to reflectionDataParser is assigned to a temporary 'dart' |
| // so that 'dart.' will appear as the prefix to dart methods in stack |
| @@ -1503,6 +1580,9 @@ class OldEmitter implements Emitter { |
| '${namer.currentIsolate}$_=${_}new ${namer.isolateName}()$N'); |
| emitConvertToFastObjectFunction(mainOutput); |
| + emitConvertToSlowObjectFunction(mainOutput); |
| + emitMarkerFun(mainOutput); |
| + |
| for (String globalObject in Namer.reservedGlobalObjectNames) { |
| mainOutput.add('$globalObject = convertToFastObject($globalObject)$N'); |
| } |