| 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 7f5bc4a0d6e014f6f34a9f94ab6d13ef9749ca8e..09e1d7ecfa5a284a5e1021071dd602c91bedcdcc 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
|
| @@ -1798,7 +1798,7 @@ function(newConstructor, oldConstructor, superclass) {
|
| /// top-level). [globalFunctionsAccess] is a reference to
|
| /// [embeddedNames.GLOBAL_FUNCTIONS].
|
| jsAst.Fun buildIncrementalAddMethod() {
|
| - return js(r'''
|
| + return js(r"""
|
| function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
|
| var arrayOrFunction = originalDescriptor[name];
|
| var method;
|
| @@ -1813,32 +1813,57 @@ function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
|
| 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;
|
| + if (stub === method || !existingStub || !stub.$getterStub) {
|
| + // Not replacing an existing getter stub.
|
| + holder[property] = stub;
|
| continue;
|
| }
|
| if (!stub.$getterStub) {
|
| - var error = new Error("Unexpected stub.");
|
| + 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;
|
| +
|
| + // Existing getter stubs need special treatment as they may already have
|
| + // been called and produced a closure.
|
| + this.pendingStubs = this.pendingStubs || [];
|
| + // It isn't safe to invoke the stub yet.
|
| + this.pendingStubs.push((function(holder, stub, existingStub, existing,
|
| + method) {
|
| + return function() {
|
| + var receiver = isStatic ? holder : new holder.constructor();
|
| + // Invoke the existing stub to obtain the tear-off closure.
|
| + existingStub = existingStub.call(receiver);
|
| + // Invoke the new stub to create a tear-off closure we can use as a
|
| + // prototype.
|
| + stub = stub.call(receiver);
|
| +
|
| + var newProto = stub.constructor.prototype;
|
| + var existingProto = existingStub.constructor.prototype;
|
| + for (var stubProperty in newProto) {
|
| + if (!Object.prototype.hasOwnProperty.call(newProto, stubProperty))
|
| + continue;
|
| + existingProto[stubProperty] = newProto[stubProperty];
|
| + }
|
| +
|
| + // Update all the existing stub's references to [existing] to
|
| + // [method]. Instance tear-offs are call-by-name, so this isn't
|
| + // necessary for those.
|
| + if (!isStatic) return;
|
| + for (var reference in existingStub) {
|
| + if (existingStub[reference] === existing) {
|
| + existingStub[reference] = method;
|
| + }
|
| + }
|
| }
|
| - }
|
| + })(holder, stub, existingStub, existing, 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
|
|
|