Browse Source

Merge pull request #1112 from amber-smalltalk/gh-631

Method change propagation only takes care of changed method
Herbert Vojčík 10 years ago
parent
commit
5548ecb627
3 changed files with 25 additions and 17 deletions
  1. 2 3
      src/Kernel-Classes.js
  2. 0 1
      src/Kernel-Classes.st
  3. 23 13
      support/boot.js

+ 2 - 3
src/Kernel-Classes.js

@@ -2770,7 +2770,6 @@ return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 $recv(aCompiledMethod)._protocol_(aString);
 $recv(aBehavior)._addCompiledMethod_(aCompiledMethod);
-self._setupClass_(aBehavior);
 return aCompiledMethod;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"installMethod:forClass:protocol:",{aCompiledMethod:aCompiledMethod,aBehavior:aBehavior,aString:aString},$globals.ClassBuilder)});
@@ -2778,10 +2777,10 @@ return aCompiledMethod;
 },
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aCompiledMethod", "aBehavior", "aString"],
-source: "installMethod: aCompiledMethod forClass: aBehavior protocol: aString\x0a\x09aCompiledMethod protocol: aString.\x0a\x09aBehavior addCompiledMethod: aCompiledMethod.\x0a\x09self setupClass: aBehavior.\x0a\x09^ aCompiledMethod",
+source: "installMethod: aCompiledMethod forClass: aBehavior protocol: aString\x0a\x09aCompiledMethod protocol: aString.\x0a\x09aBehavior addCompiledMethod: aCompiledMethod.\x0a\x09^ aCompiledMethod",
 referencedClasses: [],
 //>>excludeEnd("ide");
-messageSends: ["protocol:", "addCompiledMethod:", "setupClass:"]
+messageSends: ["protocol:", "addCompiledMethod:"]
 }),
 $globals.ClassBuilder);
 

+ 0 - 1
src/Kernel-Classes.st

@@ -703,7 +703,6 @@ copyClass: aClass to: anotherClass
 installMethod: aCompiledMethod forClass: aBehavior protocol: aString
 	aCompiledMethod protocol: aString.
 	aBehavior addCompiledMethod: aCompiledMethod.
-	self setupClass: aBehavior.
 	^ aCompiledMethod
 ! !
 

+ 23 - 13
support/boot.js

@@ -237,18 +237,20 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 		 metaclasses. */
 
 		st.init = function(klass) {
-			st.initClass(klass);
+			initClass(klass);
 			if(klass.klass && !klass.meta) {
-				st.initClass(klass.klass);
+				initClass(klass.klass);
 			}
 		};
 
-		st.initClass = function(klass) {
+		function initClass(klass) {
 			if(klass.wrapped) {
 				copySuperclass(klass);
 				dnu.installHandlers(klass);
 			}
-		};
+		}
+
+		this.initClass = initClass;
 
 		function copySuperclass(klass, superclass) {
 			var inheritedMethods = Object.create(null);
@@ -315,7 +317,7 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 
 		var org = brikz.ensure("organize");
 		var root = brikz.ensure("root");
-		brikz.ensure("classInit");
+		var classInit = brikz.ensure("classInit");
 		var nil = root.nil;
 		var rootAsClass = root.rootAsClass;
 		var SmalltalkObject = root.Object;
@@ -536,7 +538,7 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 			// The fn property changed. We need to add back the klass property to the prototype
 			wireKlass(klass);
 
-			st.initClass(klass);
+			classInit.initClass(klass);
 		};
 
 		/* Create an alias for an existing class */
@@ -573,7 +575,6 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 		var SmalltalkObject = brikz.ensure("root").Object;
 		brikz.ensure("selectorConversion");
 		brikz.ensure("classes");
-		brikz.ensure("classInit");
 
 		function SmalltalkMethod() {}
 		inherits(SmalltalkMethod, SmalltalkObject);
@@ -625,7 +626,7 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 			// Therefore we populate the organizer here too
 			org.addOrganizationElement(klass, method.protocol);
 
-			propagateMethodChange(klass);
+			propagateMethodChange(klass, method);
 
 			var usedSelectors = method.messageSends;
 			var dnuHandlers = [];
@@ -643,20 +644,29 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 			}
 		};
 
-		function propagateMethodChange(klass) {
+		function propagateMethodChange(klass, method) {
 			// If already initialized (else it will be done later anyway),
 			// re-initialize all subclasses to ensure the method change
 			// propagation (for wrapped classes, not using the prototype
 			// chain).
 
-			//TODO: optimize, only one method need to be updated, not all of them
 			if (stInit.initialized()) {
 				st.allSubclasses(klass).forEach(function (subclass) {
-					st.initClass(subclass);
+					initMethodInClass(subclass, method);
 				});
 			}
 		}
 
+		function initMethodInClass (klass, method) {
+			if (klass.wrapped && !klass.methods[method.selector]) {
+				var jsSelector = method.jsSelector;
+				manip.installMethod({
+					jsSelector: jsSelector,
+					fn: klass.superclass.fn.prototype[jsSelector]
+				}, klass);
+			}
+		}
+
 		st.removeMethod = function(method, klass) {
 			if (klass !== method.methodClass) {
 				throw new Error(
@@ -670,8 +680,8 @@ define("amber/boot", [ 'require', './browser-compatibility' ], function (require
 			delete klass.fn.prototype[method.jsSelector];
 			delete klass.methods[method.selector];
 
-			st.initClass(klass);
-			propagateMethodChange(klass);
+			initMethodInClass(klass, method);
+			propagateMethodChange(klass, method);
 
 			// Do *not* delete protocols from here.
 			// This is handled by #removeCompiledMethod