On Sun, Oct 26, 2008 at 6:21 AM, Klaus D. Witzel <klaus.witzel@cobss.com> wrote:
On Sun, 26 Oct 2008 13:39:04 +0100, Andreas Raab wrote:

Hi Frederic -

Congrats! You found the first real VM bug in five years or so ;-) I'm not completely sure what the problem is but there is obviously something wrong here. It's easiest to recreate the problem by copying the #/ method and simply do something like:

SmallInteger>>foo: aNumber
       "(SmallInteger>>#foo:) valueWithReceiver: 11 arguments: {2}"
       <primitive: 10>
self halt.
       aNumber isZero ifTrue: [^(ZeroDivide dividend: self) signal].
       (aNumber isMemberOf: SmallInteger)
               ifTrue: [^(Fraction numerator: self denominator: aNumber) reduced]
               ifFalse: [^super / aNumber]

When you run this, you'll see that the debugger shows *two* frames with SmallInteger>>foo: on them. Inspecting the "parent" frame will eventually crash the system since it has a completely bogus stack pointer (-1).

It seems that in a failing primitive method we end up with a bogus activation record in primitiveExecMethodWithArgs (removing the primitive from the above makes it work fine). I'm somewhat at a loss here as to what the problem might be given that the implementations of primPerformWithArgs and primExecWithArgs are so similar but interestingly, the equivalent:

       11 perform: #foo: withArguments:{2}.

works fine with or without the primitive. Somewhere there must be a difference ...

The difference can be this: #primitiveExecuteMethod is called as part of #primitiveResponse, and in turn calls #executeNewMethod which again does #primitiveResponse. If the latter does #primitiveFail, the now *two* activations of #primitiveResponse want to handle the situation - without knowing from each other.

Perhaps #primitiveExecuteMethod should end with an explicit [ ... ^ self success: true] in its true-branch (this is just a thought, I have as yet not looked deeper).

I think you're exactly right.  This fixes it for me.

Thanks!

 
Besides: if #primitiveExecuteMethod would do its own #primitiveFail, it looks like its arguments are no longer on the stack.

/Klaus


Cheers,
  - Andreas

Frederic Pluquet wrote:
Hello,
 I found a fondamental bug in Squeak and Pharo. The next code
 11 / 2  gives the fraction (11/2). It's correct. But the next code
 (SmallInteger>>#/) valueWithReceiver: 11 arguments: {2}
 gives 1 !
 The problem is the method valueWithReceiver:arguements: is used hugely with method wrappers...
 After long time of debugging, I found a point to debug: this method don't have the good behavior with compiled methods having a primitive that fails and executes some code after (as in SmallInteger>>#/ method when the division don't give a whole integer). In fact, when I send this message, the vm executes normally the compiled method but, in place of returns simply the good result, seems to rerun the the compiled method with other arguments (completly wrong) and returns so a wrong result.
 For example, (SmallInteger>>#/) valueWithReceiver: 11 arguments: {2}
 has the following execution trace :
 2 isZero
|  2 = 0
|  returns: false
returns: false
2 isMemberOf: SmallInteger
|  2 class
|  returns: SmallInteger
|  SmallInteger == SmallInteger
|  returns: true
returns: true
Fraction numerator: 101 denominator: 2
|  Fraction new
|  |  Fraction basicNew
|  |  returns: a Fraction instance
|  |  (a Fraction instance) initialize
|  |  returns: a Fraction instance
|  returns: a Fraction instance
|  a Fraction instance setNumerator: 101 denominator: 2
|  |  2 = 0
|  |  returns: false
|  |  101 asInteger
|  |  returns: 101
|  |  2 asInteger
|  |  returns: 2
|  |  2 abs
|  |  |  2 < 0
|  |  |  returns: false
|  |  returns: 2
|  |  2 < 0
|  |  returns: false
|  returns: (101/2)
returns: (101/2)
(101/2) reduced
|  101 = 0
|  returns: false
|  101 gcd: 2
|  |  101 = 0
|  |  returns: false
|  |  2 \\ 101
|  |  returns: 2
|  |  2 = 0
|  |  returns: false
|  |  101 \\ 2
|  |  returns: 1
|  |  1 = 0
|  |  returns: false
|  |  2 \\ 1
|  |  returns: 0
|  |  0 = 0
|  |  returns: true
|  |  1 abs
|  |  |  1 < 0
|  |  |  returns: false
|  |  returns: 1
|  returns: 1
|  101 // 1
|  returns: 101
|  2 // 1
|  returns: 2
|  2 = 1
|  returns: false
|  Fraction numerator: 101 denominator: 2
|  |  Fraction new
|  |  |  Fraction basicNew
|  |  |  returns: a Fraction instance
|  |  |  (a Fraction instance) initialize
|  |  |  returns: a Fraction instance
|  |  returns: a Fraction instance
|  |  (a Fraction instance) setNumerator: 101 denominator: 2
|  |  |  2 = 0
|  |  |  returns: false
|  |  |  101 asInteger
|  |  |  returns: 101
|  |  |  2 asInteger
|  |  |  returns: 2
|  |  |  2 abs
|  |  |  |  2 < 0
|  |  |  |  returns: false
|  |  |  returns: 2
|  |  |  2 < 0
|  |  |  returns: false
|  |  returns: (101/2)
|  returns: (101/2)
returns: (101/2)
2 isZero
|  2 = 0
|  returns: false
returns: false
false isMemberOf: SmallInteger
|  false class
|  returns: False
|  False == SmallInteger
|  returns: false
returns: false
 Please help me to fix this bug. I really need it works fine !
 Fréd
-- Frédéric Pluquet
Université Libre de Bruxelles (ULB)
Assistant
http://www.ulb.ac.be/di/fpluquet
 ------------------------------------------------------------------------







--
"If at first, the idea is not absurd, then there is no hope for it". Albert Einstein