Index: dart/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart |
diff --git a/dart/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart b/dart/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart |
index 062c62f807b1d175241b2ee7fa45b306a0c7fc83..1d9acff94d7e02d426ce297a74f38c6e8426136d 100644 |
--- a/dart/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart |
+++ b/dart/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart |
@@ -1452,8 +1452,12 @@ class OldEmitter implements Emitter { |
'this.\$dart_unsafe_eval.patch = function(a) { eval(a) }$N'); |
String schemaChange = |
jsAst.prettyPrint(buildSchemaChangeFunction(), compiler).getText(); |
+ String addMethod = |
+ jsAst.prettyPrint(buildIncrementalAddMethod(), compiler).getText(); |
mainBuffer.add( |
'this.\$dart_unsafe_eval.schemaChange$_=$_$schemaChange$N'); |
+ mainBuffer.add( |
+ 'this.\$dart_unsafe_eval.addMethod$_=$_$addMethod$N'); |
} |
if (isProgramSplit) { |
/// We collect all the global state of the, so it can be passed to the |
@@ -1682,6 +1686,57 @@ function(newConstructor, oldConstructor, superclass) { |
}'''); |
} |
+ /// Used by incremental compilation to patch up an object ([holder]) with a |
+ /// new (or updated) method. [arrayOrFunction] is either the new method, or |
+ /// an array containing the method (see |
+ /// [ContainerBuilder.addMemberMethodFromInfo]). [name] is the name of the |
+ /// new method. [isStatic] tells if method is static (or |
+ /// top-level). [globalFunctionsAccess] is a reference to |
+ /// [embeddedNames.GLOBAL_FUNCTIONS]. |
+ jsAst.Fun buildIncrementalAddMethod() { |
+ return js(r''' |
+function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) { |
+ var arrayOrFunction = originalDescriptor[name]; |
+ var method; |
+ if (arrayOrFunction.constructor === Array) { |
+ var existing = holder[name]; |
+ var array = arrayOrFunction; |
+ var descriptor = Object.create(null); |
+ this.addStubs( |
+ descriptor, arrayOrFunction, name, isStatic, originalDescriptor, []); |
+ method = descriptor[name]; |
+ for (var property in descriptor) { |
+ if (!Object.prototype.hasOwnProperty.call(descriptor, property)) continue; |
+ var stub = descriptor[property]; |
+ var existingStub = holder[property]; |
+ if (stub === method || !existingStub) { |
+ // Not replacing an existing stub. |
+ holder[property] = method; |
+ continue; |
+ } |
+ if (!stub.$getterStub) { |
+ var error = new Error("Unexpected stub."); |
+ error.stub = stub; |
+ throw error; |
+ } |
+ // Invoke the existing stub to obtain the tear-off closure. |
+ existingStub = existingStub(); |
+ // A stub already exist. Update all its references to [existing] to |
+ // [method]. |
+ for (var reference in existingStub) { |
+ if (existingStub[reference] === existing) { |
+ existingStub[reference] = method; |
+ } |
+ } |
+ } |
+ } else { |
+ method = arrayOrFunction; |
+ holder[name] = method; |
+ } |
+ if (isStatic) globalFunctionsAccess[name] = method; |
+}'''); |
+ } |
+ |
/// Returns a map from OutputUnit to a hash of its content. The hash uniquely |
/// identifies the code of the output-unit. It does not include |
/// boilerplate JS code, like the sourcemap directives or the hash |