Version 2.15.0-156.0.dev
Merge commit '091338d7a3359f60d0acff7b9972c839b90600ed' into 'dev'
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 2725ad3..3f0ddf0 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -52,8 +52,9 @@
to[key] = from[key];
}
}
+
// Copies the own properties from [from] to [to] if not already present in [to].
-function mixinProperties(from, to) {
+function mixinPropertiesHard(from, to) {
var keys = Object.keys(from);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
@@ -62,6 +63,15 @@
}
}
}
+// Copies the own properties from [from] to [to] (specialized version of
+// `mixinPropertiesHard` when it is known the properties are disjoint).
+function mixinPropertiesEasy(from, to) {
+ if (#legacyJavaScript) {
+ copyProperties(from, to);
+ } else {
+ Object.assign(to, from);
+ }
+}
// Only use direct proto access to construct the prototype chain (instead of
// copying properties) on platforms where we know it works well (Chrome / d8).
@@ -117,8 +127,12 @@
}
// Mixes in the properties of [mixin] into [cls].
-function mixin(cls, mixin) {
- mixinProperties(mixin.prototype, cls.prototype);
+function mixinEasy(cls, mixin) {
+ mixinPropertiesEasy(mixin.prototype, cls.prototype);
+ cls.prototype.constructor = cls;
+}
+function mixinHard(cls, mixin) {
+ mixinPropertiesHard(mixin.prototype, cls.prototype);
cls.prototype.constructor = cls;
}
@@ -374,7 +388,8 @@
return {
inherit: inherit,
inheritMany: inheritMany,
- mixin: mixin,
+ mixin: mixinEasy,
+ mixinHard: mixinHard,
installStaticTearOff: installStaticTearOff,
installInstanceTearOff: installInstanceTearOff,
@@ -777,7 +792,9 @@
'call0selector': js.quoteName(call0Name),
'call1selector': js.quoteName(call1Name),
- 'call2selector': js.quoteName(call2Name)
+ 'call2selector': js.quoteName(call2Name),
+
+ 'legacyJavaScript': _options.features.legacyJavaScript.isEnabled,
});
// We assume emitMainFragment will be the last piece of code we emit.
finalizeCode(mainResourceName, mainCode, holderCode, finalizeHolders: true);
@@ -1211,7 +1228,9 @@
collect(cls);
if (cls.mixinClass != null) {
js.Statement statement = js.js.statement('#(#, #)', [
- locals.find('_mixin', 'hunkHelpers.mixin'),
+ _hasSimpleMixin(cls)
+ ? locals.find('_mixin', 'hunkHelpers.mixin')
+ : locals.find('_mixinHard', 'hunkHelpers.mixinHard'),
classReference(cls),
classReference(cls.mixinClass),
]);
@@ -1264,6 +1283,30 @@
return wrapPhase('inheritance', statements);
}
+ /// Determines if the mixin methods can be applied to a mixin application
+ /// class by a simple copy, or whether the class defines properties that would
+ /// be clobbered by block-copying the mixin's properties, so a slower checking
+ /// copy is needed.
+ bool _hasSimpleMixin(Class cls) {
+ List<Method> allMethods(Class cls) {
+ return [
+ ...cls.methods,
+ ...cls.checkedSetters,
+ ...cls.isChecks,
+ ...cls.callStubs,
+ ...cls.noSuchMethodStubs,
+ ...cls.gettersSetters
+ ];
+ }
+
+ final clsMethods = allMethods(cls);
+ if (clsMethods.isEmpty) return true;
+ // TODO(sra): Compare methods with those of `cls.mixinClass` to see if the
+ // methods (and hence properties) will actually clash. If they are
+ // non-overlapping, a simple copy might still be possible.
+ return false;
+ }
+
/// Emits the setup of method aliases.
///
/// This step consists of simply copying JavaScript functions to their
diff --git a/tools/VERSION b/tools/VERSION
index e72b70a..1cb0e87 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 155
+PRERELEASE 156
PRERELEASE_PATCH 0
\ No newline at end of file