[Pharo-project] Issue 4538 and CompiledMethod equality
Hi guys. I am having a problem with the integration of issue 4538: http://code.google.com/p/pharo/issues/detail?id=4538 I am serializing CompiledMethods with Fuel and then I materialize them. To test they are correct, I use #= So far it was working correctly, but now for the materialized method it says they are not equal. The problem is that #= is failing in (self sameLiteralsAs: aCompiledMethod) And inside that method, it is failing because (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) answers false. So... why literal1 literalEqual: literal2 answers false? from what I can say, having that selector: "literalEqual", then both MUST be equal, because they are. The problem is that it was added: Association >> literalEqual: otherLiteral "Answer true if the receiver and otherLiteral represent the same literal. Variable bindings are literally equals only if identical. This is how variable sharing works, by preserving identity and changing only the value." ^self == otherLiteral So....I am not sure I agree with this change. Any idea how can we deal with this problem? Cheers -- Mariano http://marianopeck.wordpress.com
On 15.09.2011 17:27, Mariano Martinez Peck wrote:
Hi guys. I am having a problem with the integration of issue 4538: http://code.google.com/p/pharo/issues/detail?id=4538
I am serializing CompiledMethods with Fuel and then I materialize them. To test they are correct, I use #= So far it was working correctly, but now for the materialized method it says they are not equal. The problem is that #= is failing in
(self sameLiteralsAs: aCompiledMethod)
And inside that method, it is failing because (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) answers false.
So... why literal1 literalEqual: literal2 answers false? from what I can say, having that selector: "literalEqual", then both MUST be equal, because they are. The problem is that it was added:
Association >> literalEqual: otherLiteral "Answer true if the receiver and otherLiteral represent the same literal. Variable bindings are literally equals only if identical. This is how variable sharing works, by preserving identity and changing only the value." ^self == otherLiteral
So....I am not sure I agree with this change.
Any idea how can we deal with this problem?
Cheers
-- Mariano http://marianopeck.wordpress.com
The change is correct, here's an example: Create a global: Global := 1 Create a method: foo ^Global Serialize method, deserialize Change value of global: Global := 5. foo should return 5, not 1. Unless it's actually the same association as in the SystemDictionary, this will not be true. Cheers, Henry
Ok, I understand. But On Thu, Sep 15, 2011 at 6:05 PM, Henrik Sperre Johansen < henrik.s.johansen@veloxit.no> wrote:
On 15.09.2011 17:27, Mariano Martinez Peck wrote:
Hi guys. I am having a problem with the integration of issue 4538: http://code.google.com/p/pharo/issues/detail?id=4538
I am serializing CompiledMethods with Fuel and then I materialize them. To test they are correct, I use #= So far it was working correctly, but now for the materialized method it says they are not equal. The problem is that #= is failing in
(self sameLiteralsAs: aCompiledMethod)
And inside that method, it is failing because (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) answers false.
So... why literal1 literalEqual: literal2 answers false? from what I can say, having that selector: "literalEqual", then both MUST be equal, because they are. The problem is that it was added:
Association >> literalEqual: otherLiteral "Answer true if the receiver and otherLiteral represent the same literal. Variable bindings are literally equals only if identical. This is how variable sharing works, by preserving identity and changing only the value." ^self == otherLiteral
So....I am not sure I agree with this change.
Any idea how can we deal with this problem?
Cheers
-- Mariano http://marianopeck.wordpress.com
The change is correct, here's an example:
Create a global: Global := 1
Create a method: foo ^Global
Serialize method, deserialize
Change value of global: Global := 5.
foo should return 5, not 1. Unless it's actually the same association as in the SystemDictionary, this will not be true.
I understand that. In fact, in Fuel we use exactly the same association of SystemDictionary for globals. Look this test example: testGlobalVariableMethod | materializedCompiledMethod | Smalltalk globals at: #TestGlobalVariableMethod2 put: false. (self class compileSilently: 'globalVariableForTestingMethod Transcript name. ^ GlobalVariableForTesting.'). materializedCompiledMethod := self materializedCompiledMethod: (self class >> #globalVariableForTestingMethod). Smalltalk globals at: #GlobalVariableForTesting put: true. self assert: (materializedCompiledMethod valueWithReceiver: self arguments: #()). BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal, the one that maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
No, they need to be identical unless you want to break class/global creation, deletion, renaming, obsoletion, and possibly more ... The design decision behind using unique associations is that you can replace the value cheaply without having to find and modify any of its users. Lukas -- Lukas Renggli www.lukas-renggli.ch
On 15. sep. 2011, at 18:45, Mariano Martinez Peck <marianopeck@gmail.com> wrote:
Ok, I understand. But
On Thu, Sep 15, 2011 at 6:05 PM, Henrik Sperre Johansen <henrik.s.johansen@veloxit.no> wrote: On 15.09.2011 17:27, Mariano Martinez Peck wrote:
Hi guys. I am having a problem with the integration of issue 4538: http://code.google.com/p/pharo/issues/detail?id=4538
I am serializing CompiledMethods with Fuel and then I materialize them. To test they are correct, I use #= So far it was working correctly, but now for the materialized method it says they are not equal. The problem is that #= is failing in
(self sameLiteralsAs: aCompiledMethod)
And inside that method, it is failing because (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) answers false.
So... why literal1 literalEqual: literal2 answers false? from what I can say, having that selector: "literalEqual", then both MUST be equal, because they are. The problem is that it was added:
Association >> literalEqual: otherLiteral "Answer true if the receiver and otherLiteral represent the same literal. Variable bindings are literally equals only if identical. This is how variable sharing works, by preserving identity and changing only the value." ^self == otherLiteral
So....I am not sure I agree with this change.
Any idea how can we deal with this problem?
Cheers
-- Mariano http://marianopeck.wordpress.com
The change is correct, here's an example:
Create a global: Global := 1
Create a method: foo ^Global
Serialize method, deserialize
Change value of global: Global := 5.
foo should return 5, not 1. Unless it's actually the same association as in the SystemDictionary, this will not be true.
I understand that. In fact, in Fuel we use exactly the same association of SystemDictionary for globals. Look this test example:
testGlobalVariableMethod
| materializedCompiledMethod | Smalltalk globals at: #TestGlobalVariableMethod2 put: false. (self class compileSilently: 'globalVariableForTestingMethod Transcript name. ^ GlobalVariableForTesting.').
materializedCompiledMethod := self materializedCompiledMethod: (self class >> #globalVariableForTestingMethod). Smalltalk globals at: #GlobalVariableForTesting put: true. self assert: (materializedCompiledMethod valueWithReceiver: self arguments: #()).
BUT, it doesn't mean that Association is always used for globals. Sure they are. CompiledMethod equality is failing because of the last literal, the one that maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal. From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
They do: SomeUnusedClass foo ^nil cm := SomeUnusedClass >> #foo. Smalltalk at: #SomeUnusedClass put: nil. cm class = nil should be true. Cheers, Henry
On Thu, Sep 15, 2011 at 9:45 AM, Mariano Martinez Peck < marianopeck@gmail.com> wrote:
Ok, I understand. But
On Thu, Sep 15, 2011 at 6:05 PM, Henrik Sperre Johansen < henrik.s.johansen@veloxit.no> wrote:
On 15.09.2011 17:27, Mariano Martinez Peck wrote:
Hi guys. I am having a problem with the integration of issue 4538: http://code.google.com/p/pharo/issues/detail?id=4538
I am serializing CompiledMethods with Fuel and then I materialize them. To test they are correct, I use #= So far it was working correctly, but now for the materialized method it says they are not equal. The problem is that #= is failing in
(self sameLiteralsAs: aCompiledMethod)
And inside that method, it is failing because (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) answers false.
So... why literal1 literalEqual: literal2 answers false? from what I can say, having that selector: "literalEqual", then both MUST be equal, because they are. The problem is that it was added:
Association >> literalEqual: otherLiteral "Answer true if the receiver and otherLiteral represent the same literal. Variable bindings are literally equals only if identical. This is how variable sharing works, by preserving identity and changing only the value." ^self == otherLiteral
So....I am not sure I agree with this change.
Any idea how can we deal with this problem?
Cheers
-- Mariano http://marianopeck.wordpress.com
The change is correct, here's an example:
Create a global: Global := 1
Create a method: foo ^Global
Serialize method, deserialize
Change value of global: Global := 5.
foo should return 5, not 1. Unless it's actually the same association as in the SystemDictionary, this will not be true.
I understand that. In fact, in Fuel we use exactly the same association of SystemDictionary for globals. Look this test example:
testGlobalVariableMethod
| materializedCompiledMethod | Smalltalk globals at: #TestGlobalVariableMethod2 put: false. (self class compileSilently: 'globalVariableForTestingMethod Transcript name. ^ GlobalVariableForTesting.').
materializedCompiledMethod := self materializedCompiledMethod: (self class >> #globalVariableForTestingMethod). Smalltalk globals at: #GlobalVariableForTesting put: true. self assert: (materializedCompiledMethod valueWithReceiver: self arguments: #()).
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal, the one that maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method. Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions: 1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class). 2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding. 3. make the compile unique class-side methodClass literals. i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal, the one that maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: hence, originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :) sameLiteralsAs: method "Compare my literals to those of method. This is needed to compare compiled methods." | numLits literal1 literal2 | (numLits := self numLiterals) ~= method numLiterals ifTrue: [ ^ false ]. "The last literal requires special checking instead of using #literalEqual:" 1 to: numLits - 1 do: [ :index | literal1 := self literalAt: index. literal2 := method literalAt: index. (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) ifFalse: [ (index = 1 and: [ #(117 120) includes: self primitive ]) ifTrue: [ literal1 isArray ifTrue: [ (literal2 isArray and: [ literal1 allButLast = literal2 allButLast ]) ifFalse: [ self halt. ^ false ] ] ifFalse: [ "ExternalLibraryFunction" (literal1 analogousCodeTo: literal2) ifFalse: [ self halt. ^ false ] ] ] ifFalse: [ index = (numLits - 1) ifTrue: [ "properties" (self properties analogousCodeTo: method properties) ifFalse: [ self halt. ^ false ] ] ifFalse: [ self halt. ^ false ] ] ] ]. literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ ((literal1 key == literal2 key) and: [literal1 value == literal2 value]).
2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
Mariano So should we intgerate a fix? Stef On Sep 15, 2011, at 11:27 PM, Mariano Martinez Peck wrote:
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal, the one that maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: hence, originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :)
sameLiteralsAs: method "Compare my literals to those of method. This is needed to compare compiled methods."
| numLits literal1 literal2 | (numLits := self numLiterals) ~= method numLiterals ifTrue: [ ^ false ]. "The last literal requires special checking instead of using #literalEqual:" 1 to: numLits - 1 do: [ :index | literal1 := self literalAt: index. literal2 := method literalAt: index. (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) ifFalse: [ (index = 1 and: [ #(117 120) includes: self primitive ]) ifTrue: [ literal1 isArray ifTrue: [ (literal2 isArray and: [ literal1 allButLast = literal2 allButLast ]) ifFalse: [ self halt. ^ false ] ] ifFalse: [ "ExternalLibraryFunction" (literal1 analogousCodeTo: literal2) ifFalse: [ self halt. ^ false ] ] ] ifFalse: [ index = (numLits - 1) ifTrue: [ "properties" (self properties analogousCodeTo: method properties) ifFalse: [ self halt. ^ false ] ] ifFalse: [ self halt. ^ false ] ] ] ]. literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ ((literal1 key == literal2 key) and: [literal1 value == literal2 value]).
2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
I don't really know. I have implemented what Eliot say in the first option and it is working for me. Do you (Henry/Lukas/Nicolas/Eliot) agree to have this first solution and then improve it if necessary ? thanks On Fri, Sep 16, 2011 at 8:12 PM, Stéphane Ducasse <stephane.ducasse@inria.fr
wrote:
Mariano
So should we intgerate a fix?
Stef
On Sep 15, 2011, at 11:27 PM, Mariano Martinez Peck wrote:
BUT, it doesn't mean that Association is always used for globals.
CompiledMethod equality is failing because of the last literal, the one that maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. However,
no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are
right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: hence, originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method
equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal),
comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :)
sameLiteralsAs: method "Compare my literals to those of method. This is needed to compare
compiled methods."
| numLits literal1 literal2 | (numLits := self numLiterals) ~= method numLiterals ifTrue: [ ^ false ]. "The last literal requires special checking instead of using
#literalEqual:"
1 to: numLits - 1 do: [ :index | literal1 := self literalAt: index. literal2 := method literalAt: index. (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) ifFalse: [ (index = 1 and: [ #(117 120) includes: self primitive ]) ifTrue: [ literal1 isArray ifTrue: [ (literal2 isArray and: [ literal1
allButLast = literal2 allButLast ])
ifFalse: [ self halt. ^ false ] ] ifFalse: [ "ExternalLibraryFunction" (literal1 analogousCodeTo: literal2) ifFalse: [ self halt. ^ false ] ] ] ifFalse: [ index = (numLits - 1) ifTrue: [ "properties" (self properties analogousCodeTo: method
properties)
ifFalse: [ self halt. ^ false ] ] ifFalse: [ self halt. ^ false ] ] ] ]. literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ ((literal1 key == literal2 key) and: [literal1 value == literal2
value]).
2. special case comparison of the last literal (the methodClass literal),
insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. i.e. if a
class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be
identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
2011/9/16 Mariano Martinez Peck <marianopeck@gmail.com>:
I don't really know. I have implemented what Eliot say in the first option and it is working for me. Do you (Henry/Lukas/Nicolas/Eliot) agree to have this first solution and then improve it if necessary ?
thanks
I agree on Mariano/Eliot solution. It is a good pragmatic short term workaround. In the long term, I wish I can say goodbye to my new super power, it's a too dangerous power. So I wish the VM would change (along with ClassBuilder and Tools). Nicolas
On Fri, Sep 16, 2011 at 8:12 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Mariano
So should we intgerate a fix?
Stef
On Sep 15, 2011, at 11:27 PM, Mariano Martinez Peck wrote:
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal, the one that maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. Â However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Â Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: Â hence, Â originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :)
sameLiteralsAs: method   "Compare my literals to those of method. This is needed to compare compiled methods."
  | numLits literal1 literal2 |   (numLits := self numLiterals) ~= method numLiterals     ifTrue: [ ^ false ].   "The last literal requires special checking instead of using #literalEqual:"   1 to: numLits - 1 do: [ :index |     literal1 := self literalAt: index.     literal2 := method literalAt: index.     (literal1 == literal2 or: [ literal1 literalEqual: literal2 ])       ifFalse: [         (index = 1 and: [ #(117 120) includes: self primitive ])           ifTrue: [             literal1 isArray               ifTrue: [                 (literal2 isArray and: [ literal1 allButLast = literal2 allButLast ])                   ifFalse: [ self halt. ^ false ] ]               ifFalse: [                 "ExternalLibraryFunction"                 (literal1 analogousCodeTo: literal2)                   ifFalse: [ self halt. ^ false ] ] ]           ifFalse: [             index = (numLits - 1)               ifTrue: [                 "properties"                 (self properties analogousCodeTo: method properties)                   ifFalse: [ self halt. ^ false ] ]               ifFalse: [ self halt. ^ false ] ] ] ].   literal1 := self literalAt: numLits.   literal2 := method literalAt: numLits.   ^ ((literal1 key == literal2 key) and: [literal1 value == literal2 value]).
2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. Â i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
2011/9/16 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
2011/9/16 Mariano Martinez Peck <marianopeck@gmail.com>:
I don't really know. I have implemented what Eliot say in the first option and it is working for me. Do you (Henry/Lukas/Nicolas/Eliot) agree to have this first solution and then improve it if necessary ?
thanks
I agree on Mariano/Eliot solution. It is a good pragmatic short term workaround. In the long term, I wish I can say goodbye to my new super power, it's a too dangerous power. So I wish the VM would change (along with ClassBuilder and Tools).
Nicolas
Or maybe after reading: literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ (literal1 == literal2) or: [literal1 key isNil == literal2 key isNil and: [literal1 value == literal2 value]]. I we are sure that the last literal is always an Association Nicolas
On Fri, Sep 16, 2011 at 8:12 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Mariano
So should we intgerate a fix?
Stef
On Sep 15, 2011, at 11:27 PM, Mariano Martinez Peck wrote:
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal, the one that maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. Â However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Â Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: Â hence, Â originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :)
sameLiteralsAs: method   "Compare my literals to those of method. This is needed to compare compiled methods."
  | numLits literal1 literal2 |   (numLits := self numLiterals) ~= method numLiterals     ifTrue: [ ^ false ].   "The last literal requires special checking instead of using #literalEqual:"   1 to: numLits - 1 do: [ :index |     literal1 := self literalAt: index.     literal2 := method literalAt: index.     (literal1 == literal2 or: [ literal1 literalEqual: literal2 ])       ifFalse: [         (index = 1 and: [ #(117 120) includes: self primitive ])           ifTrue: [             literal1 isArray               ifTrue: [                 (literal2 isArray and: [ literal1 allButLast = literal2 allButLast ])                   ifFalse: [ self halt. ^ false ] ]               ifFalse: [                 "ExternalLibraryFunction"                 (literal1 analogousCodeTo: literal2)                   ifFalse: [ self halt. ^ false ] ] ]           ifFalse: [             index = (numLits - 1)               ifTrue: [                 "properties"                 (self properties analogousCodeTo: method properties)                   ifFalse: [ self halt. ^ false ] ]               ifFalse: [ self halt. ^ false ] ] ] ].   literal1 := self literalAt: numLits.   literal2 := method literalAt: numLits.   ^ ((literal1 key == literal2 key) and: [literal1 value == literal2 value]).
2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. Â i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
On Fri, Sep 16, 2011 at 12:08 PM, Nicolas Cellier < nicolas.cellier.aka.nice@gmail.com> wrote:
2011/9/16 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
2011/9/16 Mariano Martinez Peck <marianopeck@gmail.com>:
I don't really know. I have implemented what Eliot say in the first option and it is working for me. Do you (Henry/Lukas/Nicolas/Eliot) agree to have this first solution and then improve it if necessary ?
thanks
I agree on Mariano/Eliot solution. It is a good pragmatic short term workaround. In the long term, I wish I can say goodbye to my new super power, it's a too dangerous power. So I wish the VM would change (along with ClassBuilder and Tools).
Yes, I agree. It just takes time to get there.
Nicolas
Or maybe after reading:
literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ (literal1 == literal2) or: [literal1 key isNil == literal2 key isNil and: [literal1 value == literal2 value]].
I we are sure that the last literal is always an Association
If it's not then one is playing fast and loose with the system. But if the method doesn't contain a super send then as far as the VM is concerned it doesn't need an association, and that might be the case with, for example, shared inst var accessors in Newspeak. So instead of assuming its an association write it something like ^literal1 class == literal2 class and: [literal1 isVariableBinding ifTrue: [literal1 key = literal2 key and: [literal1 value = literal2 value]] ifFalse: [literal1 = literal2]]
Nicolas
On Fri, Sep 16, 2011 at 8:12 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Mariano
So should we intgerate a fix?
Stef
On Sep 15, 2011, at 11:27 PM, Mariano Martinez Peck wrote:
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal, the
one that
maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: hence, originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :)
sameLiteralsAs: method "Compare my literals to those of method. This is needed to compare compiled methods."
| numLits literal1 literal2 | (numLits := self numLiterals) ~= method numLiterals ifTrue: [ ^ false ]. "The last literal requires special checking instead of using #literalEqual:" 1 to: numLits - 1 do: [ :index | literal1 := self literalAt: index. literal2 := method literalAt: index. (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) ifFalse: [ (index = 1 and: [ #(117 120) includes: self primitive ]) ifTrue: [ literal1 isArray ifTrue: [ (literal2 isArray and: [ literal1 allButLast = literal2 allButLast ]) ifFalse: [ self halt. ^ false ] ] ifFalse: [ "ExternalLibraryFunction" (literal1 analogousCodeTo: literal2) ifFalse: [ self halt. ^ false ] ] ] ifFalse: [ index = (numLits - 1) ifTrue: [ "properties" (self properties analogousCodeTo: method properties) ifFalse: [ self halt. ^ false ] ] ifFalse: [ self halt. ^ false ] ] ] ]. literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ ((literal1 key == literal2 key) and: [literal1 value == literal2 value]).
2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
I dream to rewrite from scratch the classBuilder. But first we should close some pending open work. So going slowler but in a stable manner. Stef
On Fri, Sep 16, 2011 at 12:08 PM, Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com> wrote: 2011/9/16 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
2011/9/16 Mariano Martinez Peck <marianopeck@gmail.com>:
I don't really know. I have implemented what Eliot say in the first option and it is working for me. Do you (Henry/Lukas/Nicolas/Eliot) agree to have this first solution and then improve it if necessary ?
thanks
I agree on Mariano/Eliot solution. It is a good pragmatic short term workaround. In the long term, I wish I can say goodbye to my new super power, it's a too dangerous power. So I wish the VM would change (along with ClassBuilder and Tools).
Yes, I agree. It just takes time to get there.
Nicolas
Or maybe after reading:
literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ (literal1 == literal2) or: [literal1 key isNil == literal2 key isNil and: [literal1 value == literal2 value]].
I we are sure that the last literal is always an Association
If it's not then one is playing fast and loose with the system. But if the method doesn't contain a super send then as far as the VM is concerned it doesn't need an association, and that might be the case with, for example, shared inst var accessors in Newspeak. So instead of assuming its an association write it something like
^literal1 class == literal2 class and: [literal1 isVariableBinding ifTrue: [literal1 key = literal2 key and: [literal1 value = literal2 value]] ifFalse: [literal1 = literal2]]
Nicolas
On Fri, Sep 16, 2011 at 8:12 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Mariano
So should we intgerate a fix?
Stef
On Sep 15, 2011, at 11:27 PM, Mariano Martinez Peck wrote:
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal, the one that maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: hence, originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :)
sameLiteralsAs: method "Compare my literals to those of method. This is needed to compare compiled methods."
| numLits literal1 literal2 | (numLits := self numLiterals) ~= method numLiterals ifTrue: [ ^ false ]. "The last literal requires special checking instead of using #literalEqual:" 1 to: numLits - 1 do: [ :index | literal1 := self literalAt: index. literal2 := method literalAt: index. (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) ifFalse: [ (index = 1 and: [ #(117 120) includes: self primitive ]) ifTrue: [ literal1 isArray ifTrue: [ (literal2 isArray and: [ literal1 allButLast = literal2 allButLast ]) ifFalse: [ self halt. ^ false ] ] ifFalse: [ "ExternalLibraryFunction" (literal1 analogousCodeTo: literal2) ifFalse: [ self halt. ^ false ] ] ] ifFalse: [ index = (numLits - 1) ifTrue: [ "properties" (self properties analogousCodeTo: method properties) ifFalse: [ self halt. ^ false ] ] ifFalse: [ self halt. ^ false ] ] ] ]. literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ ((literal1 key == literal2 key) and: [literal1 value == literal2 value]).
2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
On Fri, Sep 16, 2011 at 12:32 PM, Stéphane Ducasse < stephane.ducasse@inria.fr> wrote:
I dream to rewrite from scratch the classBuilder. But first we should close some pending open work. So going slowler but in a stable manner.
+1000. this is a platform and platforms remain in one place even as they get better and better facilities :)
Stef
On Fri, Sep 16, 2011 at 12:08 PM, Nicolas Cellier <
nicolas.cellier.aka.nice@gmail.com> wrote:
2011/9/16 Nicolas Cellier <nicolas.cellier.aka.nice@gmail.com>:
2011/9/16 Mariano Martinez Peck <marianopeck@gmail.com>:
I don't really know. I have implemented what Eliot say in the first option and it is working for me. Do you (Henry/Lukas/Nicolas/Eliot) agree to have this first solution and then improve it if necessary ?
thanks
I agree on Mariano/Eliot solution. It is a good pragmatic short term workaround. In the long term, I wish I can say goodbye to my new super power, it's a too dangerous power. So I wish the VM would change (along with ClassBuilder and Tools).
Yes, I agree. It just takes time to get there.
Nicolas
Or maybe after reading:
literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ (literal1 == literal2) or: [literal1 key isNil == literal2 key isNil and: [literal1 value == literal2 value]].
I we are sure that the last literal is always an Association
If it's not then one is playing fast and loose with the system. But if the method doesn't contain a super send then as far as the VM is concerned it doesn't need an association, and that might be the case with, for example, shared inst var accessors in Newspeak. So instead of assuming its an association write it something like
^literal1 class == literal2 class and: [literal1 isVariableBinding ifTrue: [literal1 key = literal2 key and: [literal1 value = literal2 value]] ifFalse: [literal1 = literal2]]
Nicolas
On Fri, Sep 16, 2011 at 8:12 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Mariano
So should we intgerate a fix?
Stef
On Sep 15, 2011, at 11:27 PM, Mariano Martinez Peck wrote:
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal, the
one that
maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: hence, originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :)
sameLiteralsAs: method "Compare my literals to those of method. This is needed to compare compiled methods."
| numLits literal1 literal2 | (numLits := self numLiterals) ~= method numLiterals ifTrue: [ ^ false ]. "The last literal requires special checking instead of using #literalEqual:" 1 to: numLits - 1 do: [ :index | literal1 := self literalAt: index. literal2 := method literalAt: index. (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) ifFalse: [ (index = 1 and: [ #(117 120) includes: self primitive ]) ifTrue: [ literal1 isArray ifTrue: [ (literal2 isArray and: [ literal1 allButLast = literal2 allButLast ]) ifFalse: [ self halt. ^ false ] ] ifFalse: [ "ExternalLibraryFunction" (literal1 analogousCodeTo: literal2) ifFalse: [ self halt. ^ false ] ] ] ifFalse: [ index = (numLits - 1) ifTrue: [ "properties" (self properties analogousCodeTo: method properties) ifFalse: [ self halt. ^ false ] ] ifFalse: [ self halt. ^ false ] ] ] ]. literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ ((literal1 key == literal2 key) and: [literal1 value == literal2 value]).
2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- best, Eliot
Or maybe after reading:
literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ (literal1 == literal2) or: [literal1 key isNil == literal2 key isNil and: [literal1 value == literal2 value]].
I we are sure that the last literal is always an Association
If it's not then one is playing fast and loose with the system. But if the method doesn't contain a super send then as far as the VM is concerned it doesn't need an association, and that might be the case with, for example, shared inst var accessors in Newspeak. So instead of assuming its an association write it something like
^literal1 class == literal2 class and: [literal1 isVariableBinding ifTrue: [literal1 key = literal2 key and: [literal1 value = literal2 value]] ifFalse: [literal1 = literal2]]
Thanks. Issue and slice in http://code.google.com/p/pharo/issues/detail?id=4814
Nicolas
On Fri, Sep 16, 2011 at 8:12 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Mariano
So should we intgerate a fix?
Stef
On Sep 15, 2011, at 11:27 PM, Mariano Martinez Peck wrote:
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal, the
one that
maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: hence, originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :)
sameLiteralsAs: method "Compare my literals to those of method. This is needed to compare compiled methods."
| numLits literal1 literal2 | (numLits := self numLiterals) ~= method numLiterals ifTrue: [ ^ false ]. "The last literal requires special checking instead of using #literalEqual:" 1 to: numLits - 1 do: [ :index | literal1 := self literalAt: index. literal2 := method literalAt: index. (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) ifFalse: [ (index = 1 and: [ #(117 120) includes: self primitive ]) ifTrue: [ literal1 isArray ifTrue: [ (literal2 isArray and: [ literal1 allButLast = literal2 allButLast ]) ifFalse: [ self halt. ^ false ] ] ifFalse: [ "ExternalLibraryFunction" (literal1 analogousCodeTo: literal2) ifFalse: [ self halt. ^ false ] ] ] ifFalse: [ index = (numLits - 1) ifTrue: [ "properties" (self properties analogousCodeTo: method properties) ifFalse: [ self halt. ^ false ] ] ifFalse: [ self halt. ^ false ] ] ] ]. literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ ((literal1 key == literal2 key) and: [literal1 value == literal2 value]).
2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
I wanted to write a test (before Stef asked) but I don't know how to clearly copy a CompiledMethod. First I tried CompiledMethodTest >> testEqualityClassSideMethod | method1 method2 | method1 := self class class >> #returnPlusOne:. method2 := method1 veryDeepCopy. self deny: (method1 literalAt: method1 numLiterals) == (method2 literalAt: method2 numLiterals). self assert: method1 = method2. And it doesn't work, the last literal of both CM point are #==. Then I tried: testEqualityClassSideMethod | method1 method2 originalAssociation | method1 := self class class >> #returnPlusOne:. method2 := method1 veryDeepCopy. originalAssociation := method2 literalAt: method2 numLiterals. method2 literalAt: method2 numLiterals put: (Association key: originalAssociation key value: originalAssociation value). method1 literalAt: method1 numLiterals put: (Association key: originalAssociation key value: originalAssociation value). self deny: (method1 literalAt: method1 numLiterals) == (method2 literalAt: method2 numLiterals). self assert: method1 = method2. Again, same problem. So...I don't know how can I copy a CM completly, that means, even use different objects for the last literals. Any ideas? Thanks! On Sat, Sep 17, 2011 at 11:30 AM, Mariano Martinez Peck < marianopeck@gmail.com> wrote:
Or maybe after reading:
literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ (literal1 == literal2) or: [literal1 key isNil == literal2 key isNil and: [literal1 value == literal2 value]].
I we are sure that the last literal is always an Association
If it's not then one is playing fast and loose with the system. But if the method doesn't contain a super send then as far as the VM is concerned it doesn't need an association, and that might be the case with, for example, shared inst var accessors in Newspeak. So instead of assuming its an association write it something like
^literal1 class == literal2 class and: [literal1 isVariableBinding ifTrue: [literal1 key = literal2 key and: [literal1 value = literal2 value]] ifFalse: [literal1 = literal2]]
Thanks. Issue and slice in http://code.google.com/p/pharo/issues/detail?id=4814
Nicolas
On Fri, Sep 16, 2011 at 8:12 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Mariano
So should we intgerate a fix?
Stef
On Sep 15, 2011, at 11:27 PM, Mariano Martinez Peck wrote:
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal, the
one that
maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: hence, originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :)
sameLiteralsAs: method "Compare my literals to those of method. This is needed to compare compiled methods."
| numLits literal1 literal2 | (numLits := self numLiterals) ~= method numLiterals ifTrue: [ ^ false ]. "The last literal requires special checking instead of using #literalEqual:" 1 to: numLits - 1 do: [ :index | literal1 := self literalAt: index. literal2 := method literalAt: index. (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) ifFalse: [ (index = 1 and: [ #(117 120) includes: self primitive ]) ifTrue: [ literal1 isArray ifTrue: [ (literal2 isArray and: [ literal1 allButLast = literal2 allButLast ]) ifFalse: [ self halt. ^ false ] ] ifFalse: [ "ExternalLibraryFunction" (literal1 analogousCodeTo: literal2) ifFalse: [ self halt. ^ false ] ] ] ifFalse: [ index = (numLits - 1) ifTrue: [ "properties" (self properties analogousCodeTo: method properties) ifFalse: [ self halt. ^ false ] ] ifFalse: [ self halt. ^ false ] ] ] ]. literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ ((literal1 key == literal2 key) and: [literal1 value == literal2 value]).
2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
On Sat, Sep 17, 2011 at 8:39 AM, Mariano Martinez Peck < marianopeck@gmail.com> wrote:
I wanted to write a test (before Stef asked) but I don't know how to clearly copy a CompiledMethod. First I tried
CompiledMethodTest >> testEqualityClassSideMethod | method1 method2 | method1 := self class class >> #returnPlusOne:. method2 := method1 veryDeepCopy. self deny: (method1 literalAt: method1 numLiterals) == (method2 literalAt: method2 numLiterals). self assert: method1 = method2.
And it doesn't work, the last literal of both CM point are #==.
Then I tried:
testEqualityClassSideMethod | method1 method2 originalAssociation | method1 := self class class >> #returnPlusOne:. method2 := method1 veryDeepCopy. originalAssociation := method2 literalAt: method2 numLiterals. method2 literalAt: method2 numLiterals put: (Association key: originalAssociation key value: originalAssociation value). method1 literalAt: method1 numLiterals put: (Association key: originalAssociation key value: originalAssociation value). self deny: (method1 literalAt: method1 numLiterals) == (method2 literalAt: method2 numLiterals). self assert: method1 = method2.
Again, same problem.
So...I don't know how can I copy a CM completly, that means, even use different objects for the last literals. Any ideas?
Compile them from source using the same and different source. Generate source with subtle differences etc. e.g. use Behavior>compile:classified:notifying:trailer:ifFail: which answers a compiled method.
Thanks!
On Sat, Sep 17, 2011 at 11:30 AM, Mariano Martinez Peck < marianopeck@gmail.com> wrote:
Or maybe after reading:
literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ (literal1 == literal2) or: [literal1 key isNil == literal2 key isNil and: [literal1 value == literal2 value]].
I we are sure that the last literal is always an Association
If it's not then one is playing fast and loose with the system. But if the method doesn't contain a super send then as far as the VM is concerned it doesn't need an association, and that might be the case with, for example, shared inst var accessors in Newspeak. So instead of assuming its an association write it something like
^literal1 class == literal2 class and: [literal1 isVariableBinding ifTrue: [literal1 key = literal2 key and: [literal1 value = literal2 value]] ifFalse: [literal1 = literal2]]
Thanks. Issue and slice in http://code.google.com/p/pharo/issues/detail?id=4814
Nicolas
On Fri, Sep 16, 2011 at 8:12 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Mariano
So should we intgerate a fix?
Stef
On Sep 15, 2011, at 11:27 PM, Mariano Martinez Peck wrote:
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal,
the one that
maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: hence, originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :)
sameLiteralsAs: method "Compare my literals to those of method. This is needed to compare compiled methods."
| numLits literal1 literal2 | (numLits := self numLiterals) ~= method numLiterals ifTrue: [ ^ false ]. "The last literal requires special checking instead of using #literalEqual:" 1 to: numLits - 1 do: [ :index | literal1 := self literalAt: index. literal2 := method literalAt: index. (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) ifFalse: [ (index = 1 and: [ #(117 120) includes: self primitive ]) ifTrue: [ literal1 isArray ifTrue: [ (literal2 isArray and: [ literal1 allButLast = literal2 allButLast ]) ifFalse: [ self halt. ^ false ] ] ifFalse: [ "ExternalLibraryFunction" (literal1 analogousCodeTo: literal2) ifFalse: [ self halt. ^ false ] ] ] ifFalse: [ index = (numLits - 1) ifTrue: [ "properties" (self properties analogousCodeTo: method properties) ifFalse: [ self halt. ^ false ] ] ifFalse: [ self halt. ^ false ] ] ] ]. literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ ((literal1 key == literal2 key) and: [literal1 value == literal2 value]).
2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
On Sat, Sep 17, 2011 at 9:00 PM, Eliot Miranda <eliot.miranda@gmail.com>wrote:
On Sat, Sep 17, 2011 at 8:39 AM, Mariano Martinez Peck < marianopeck@gmail.com> wrote:
I wanted to write a test (before Stef asked) but I don't know how to clearly copy a CompiledMethod. First I tried
CompiledMethodTest >> testEqualityClassSideMethod | method1 method2 | method1 := self class class >> #returnPlusOne:. method2 := method1 veryDeepCopy. self deny: (method1 literalAt: method1 numLiterals) == (method2 literalAt: method2 numLiterals). self assert: method1 = method2.
And it doesn't work, the last literal of both CM point are #==.
Then I tried:
testEqualityClassSideMethod | method1 method2 originalAssociation | method1 := self class class >> #returnPlusOne:. method2 := method1 veryDeepCopy. originalAssociation := method2 literalAt: method2 numLiterals. method2 literalAt: method2 numLiterals put: (Association key: originalAssociation key value: originalAssociation value). method1 literalAt: method1 numLiterals put: (Association key: originalAssociation key value: originalAssociation value). self deny: (method1 literalAt: method1 numLiterals) == (method2 literalAt: method2 numLiterals). self assert: method1 = method2.
Again, same problem.
So...I don't know how can I copy a CM completly, that means, even use different objects for the last literals. Any ideas?
Compile them from source using the same and different source. Generate source with subtle differences etc. e.g. use Behavior>compile:classified:notifying:trailer:ifFail: which answers a compiled method.
Thanks Eliot for the point :) Two new test: #testEqualityInstanceSideMethod and #testEqualityClassSideMethod. testEqualityClassSideMethod should be failing before http://code.google.com/p/pharo/issues/detail?id=4814 and green after it.
Thanks!
On Sat, Sep 17, 2011 at 11:30 AM, Mariano Martinez Peck < marianopeck@gmail.com> wrote:
Or maybe after reading:
literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ (literal1 == literal2) or: [literal1 key isNil == literal2 key isNil and: [literal1 value == literal2 value]].
I we are sure that the last literal is always an Association
If it's not then one is playing fast and loose with the system. But if the method doesn't contain a super send then as far as the VM is concerned it doesn't need an association, and that might be the case with, for example, shared inst var accessors in Newspeak. So instead of assuming its an association write it something like
^literal1 class == literal2 class and: [literal1 isVariableBinding ifTrue: [literal1 key = literal2 key and: [literal1 value = literal2 value]] ifFalse: [literal1 = literal2]]
Thanks. Issue and slice in http://code.google.com/p/pharo/issues/detail?id=4814
Nicolas
On Fri, Sep 16, 2011 at 8:12 PM, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Mariano
So should we intgerate a fix?
Stef
On Sep 15, 2011, at 11:27 PM, Mariano Martinez Peck wrote:
BUT, it doesn't mean that Association is always used for globals. CompiledMethod equality is failing because of the last literal,
the one that
maps class name (symbol) and point to the real class. So...when I materialize, both CMs have non-identical associations for the last literal, but equal.
As Henrik says the last literals are ideally #== to each other. However, no Squeak dialect makes any attempt to keep the class0side associations equal. Look at a class-side method and you'll see it's last literal is nil->SomeClass class. Now since this association doesn't exist in Smalltalk (unlike last literals on the instance side) the compiler merely creates distinct ones for each class-side method.
Thanks Eliot for that point. In fact, I have just checked and you are right. The tests that are failing for me is those where class side methods are involded. In this case, the last literal of the original CM and the materialized, gives false in #literalEqual: hence, originalCM = materializedCM is false :(
Personally I don't think one can defend the position where method equality is different for instance-side or class-side methods so there must be some solutions:
1. special case comparison of the last literal (the methodClass literal), comparing keys and insisting that the keys be #== and the values be #== (can't just define it as keys #== since all similar class-side methods will be equal irrespective of their actual class).
This one seems the easier and fixes my problem :)
sameLiteralsAs: method "Compare my literals to those of method. This is needed to compare compiled methods."
| numLits literal1 literal2 | (numLits := self numLiterals) ~= method numLiterals ifTrue: [ ^ false ]. "The last literal requires special checking instead of using #literalEqual:" 1 to: numLits - 1 do: [ :index | literal1 := self literalAt: index. literal2 := method literalAt: index. (literal1 == literal2 or: [ literal1 literalEqual: literal2 ]) ifFalse: [ (index = 1 and: [ #(117 120) includes: self primitive ]) ifTrue: [ literal1 isArray ifTrue: [ (literal2 isArray and: [ literal1 allButLast = literal2 allButLast ]) ifFalse: [ self halt. ^ false ] ] ifFalse: [ "ExternalLibraryFunction" (literal1 analogousCodeTo: literal2) ifFalse: [ self halt. ^ false ] ] ] ifFalse: [ index = (numLits - 1) ifTrue: [ "properties" (self properties analogousCodeTo: method properties) ifFalse: [ self halt. ^ false ] ] ifFalse: [ self halt. ^ false ] ] ] ]. literal1 := self literalAt: numLits. literal2 := method literalAt: numLits. ^ ((literal1 key == literal2 key) and: [literal1 value == literal2 value]).
2. special case comparison of the last literal (the methodClass literal), insisting only that the class of the literal be the same if it isVariableBinding.
3. make the compile unique class-side methodClass literals. i.e. if a class already has a class-side method then the compiler or method dictionary insertion code must find that existing association and reuse it
Other ideas?
From my point of view, that literal, the last one does not need to be identical to assume 2 CMs are equal. They just need to be equal.
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
-- Mariano http://marianopeck.wordpress.com
-- best, Eliot
-- Mariano http://marianopeck.wordpress.com
participants (7)
-
Eliot Miranda -
Henrik Johansen -
Henrik Sperre Johansen -
Lukas Renggli -
Mariano Martinez Peck -
Nicolas Cellier -
Stéphane Ducasse