primitivePerform (prim 83)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

primitivePerform (prim 83)

Stefan Marr

Hi:

From the current implementation, which I find in the interpreter, and from testing on Cog I assume that primitive 83, that is 'perform:', does easily handle an arbitrary number of parameters.

Is that correct, or does for instance Cog do something else? (it does not seem so)

I am just asking, because the number of parameters of the Object>>#perform:with: variants goes only up to three. And, the comment does not mention it. (at least in a recent Pharo image)

Furthermore, I guess, there is an upper limit on the number of arguments with regard to frame size?

Thanks
Stefan

--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: +32 2 629 2974
Fax:   +32 2 629 3525

Reply | Threaded
Open this post in threaded view
|

Re: primitivePerform (prim 83)

Eliot Miranda-2
 
Hi Stefan,

On Wed, Dec 7, 2011 at 4:09 PM, Stefan Marr <[hidden email]> wrote:

Hi:

>From the current implementation, which I find in the interpreter, and from testing on Cog I assume that primitive 83, that is 'perform:', does easily handle an arbitrary number of parameters.

Is that correct, or does for instance Cog do something else? (it does not seem so)

That's correct. The primitive (InterpreterPrimitives>>primitivePerform) is written in terms of argumentCount and so should cope with any number of arguments up to the maximum (15 is the limit in CompiledMethod, 31 in the bytecode set I believe).

I am just asking, because the number of parameters of the Object>>#perform:with: variants goes only up to three. And, the comment does not mention it. (at least in a recent Pharo image)

Furthermore, I guess, there is an upper limit on the number of arguments with regard to frame size?

Not in the StackVM or the Cog VM since these are running on a stack, not in a context, and so there's always plenty of headroom to push args on the stack during a perform.  At least the method/bytecode set's limit on argumentCount is going to bite before the stack size.  Similarly with perform:withArguments:, as long as the number of arguments is <= LargeFrameSize (56 slots?) the primitive will push arguments.  Of course, the number of arguments must match the method that is found, and so the real limits are CompiledMethod's and the bytecode set's.

cheers,


Thanks
Stefan

--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: <a href="tel:%2B32%202%20629%202974" value="+3226292974">+32 2 629 2974
Fax:   <a href="tel:%2B32%202%20629%203525" value="+3226293525">+32 2 629 3525




--
best,
Eliot

Reply | Threaded
Open this post in threaded view
|

Re: primitivePerform (prim 83) | primitivePerformInSuperclass (100)

Stefan Marr

Hi Eliot:

Are there any known issues with primitivePerformInSuperclass?

And, ehm, what is the functionality that is supposed to be supported?

I try with a doit, and everything works fine.
But when it is used in a TestCase, it crashes :-/

"""
Exception Type:  EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x0000000000000000
Crashed Thread:  0  Dispatch queue: com.apple.main-thread

Thread 0 Crashed:  Dispatch queue: com.apple.main-thread
0   org.squeakfoundation.Squeak   0x0004ef5a primitivePerformInSuperclass + 42

Thread 1:  Dispatch queue: com.apple.libdispatch-manager
[...]
"""


With regard to the supported functionality, I would expect it to mirror perform more or less exactly, but the image I use, only knows 'perform: selector withArguments: argArray inSuperclass: lookupClass' which uses an explict array for the arguments.
However, from the doIt, the code below seems to work.
And, well, when I use the debugger, it works of course too...

performSuper: aSymbol
        <primitive: 100>
        ^ self perform: aSymbol withArguments: (Array new: 0) inSuperclass: self class superclass

performSuper: aSymbol with: anObject
        <primitive: 100>
        ^ self perform: aSymbol withArguments: (Array with: anObject) inSuperclass: self class superclass


I also tried to put the code from the doit into a class, and see whether that indirection makes a difference, since I remember that you have some special treatment for doits in Cog, right?

Thanks
Stefan


On 08 Dec 2011, at 03:01, Eliot Miranda wrote:

> Hi Stefan,
>
> On Wed, Dec 7, 2011 at 4:09 PM, Stefan Marr <[hidden email]> wrote:
>
> Hi:
>
> >From the current implementation, which I find in the interpreter, and from testing on Cog I assume that primitive 83, that is 'perform:', does easily handle an arbitrary number of parameters.
>
> Is that correct, or does for instance Cog do something else? (it does not seem so)
>
> That's correct. The primitive (InterpreterPrimitives>>primitivePerform) is written in terms of argumentCount and so should cope with any number of arguments up to the maximum (15 is the limit in CompiledMethod, 31 in the bytecode set I believe).
>
> I am just asking, because the number of parameters of the Object>>#perform:with: variants goes only up to three. And, the comment does not mention it. (at least in a recent Pharo image)
>
> Furthermore, I guess, there is an upper limit on the number of arguments with regard to frame size?
>
> Not in the StackVM or the Cog VM since these are running on a stack, not in a context, and so there's always plenty of headroom to push args on the stack during a perform.  At least the method/bytecode set's limit on argumentCount is going to bite before the stack size.  Similarly with perform:withArguments:, as long as the number of arguments is <= LargeFrameSize (56 slots?) the primitive will push arguments.  Of course, the number of arguments must match the method that is found, and so the real limits are CompiledMethod's and the bytecode set's.
>
> cheers,
>
>
> Thanks
> Stefan
>
> --
> Stefan Marr
> Software Languages Lab
> Vrije Universiteit Brussel
> Pleinlaan 2 / B-1050 Brussels / Belgium
> http://soft.vub.ac.be/~smarr
> Phone: +32 2 629 2974
> Fax:   +32 2 629 3525
>
>
>
>
> --
> best,
> Eliot
>

--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: +32 2 629 2974
Fax:   +32 2 629 3525

Reply | Threaded
Open this post in threaded view
|

Re: primitivePerform (prim 83) | primitivePerformInSuperclass (100)

David T. Lewis
 
On Mon, Dec 12, 2011 at 01:59:11AM +0100, Stefan Marr wrote:
>
> Hi Eliot:
>
> Are there any known issues with primitivePerformInSuperclass?
>
> And, ehm, what is the functionality that is supposed to be supported?
>

I think you are missing some arguments for the primitive in your
#performSuper methods.

See the method comment in Object>>perform:withArguments:inSuperclass:
for a description of the functionality.

primitivePerformInSuperclass has been around for a long time, as the
last real update in the interpreter VM (aside from a recent minor
update for return code handing) is stamped 'di 4/12/1999'.

As a side note, #primitivePerformInSuperclass is exercised by
MirrorPrimiveTests>>testMirrorPerform which AFIK has no known problems
on Cog. That test fails on an interpreter VM because mirror primitive
support is not yet complete (http://bugs.squeak.org/view.php?id=7429)
but hopefully this will be resolved soon.

Dave

> I try with a doit, and everything works fine.
> But when it is used in a TestCase, it crashes :-/
>
> """
> Exception Type:  EXC_BAD_ACCESS (SIGBUS)
> Exception Codes: KERN_PROTECTION_FAILURE at 0x0000000000000000
> Crashed Thread:  0  Dispatch queue: com.apple.main-thread
>
> Thread 0 Crashed:  Dispatch queue: com.apple.main-thread
> 0   org.squeakfoundation.Squeak   0x0004ef5a primitivePerformInSuperclass + 42
>
> Thread 1:  Dispatch queue: com.apple.libdispatch-manager
> [...]
> """
>
>
> With regard to the supported functionality, I would expect it to mirror perform more or less exactly, but the image I use, only knows 'perform: selector withArguments: argArray inSuperclass: lookupClass' which uses an explict array for the arguments.
> However, from the doIt, the code below seems to work.
> And, well, when I use the debugger, it works of course too...
>
> performSuper: aSymbol
> <primitive: 100>
> ^ self perform: aSymbol withArguments: (Array new: 0) inSuperclass: self class superclass
>
> performSuper: aSymbol with: anObject
> <primitive: 100>
> ^ self perform: aSymbol withArguments: (Array with: anObject) inSuperclass: self class superclass
>
>
> I also tried to put the code from the doit into a class, and see whether that indirection makes a difference, since I remember that you have some special treatment for doits in Cog, right?
>
> Thanks
> Stefan
>
>
> On 08 Dec 2011, at 03:01, Eliot Miranda wrote:
>
> > Hi Stefan,
> >
> > On Wed, Dec 7, 2011 at 4:09 PM, Stefan Marr <[hidden email]> wrote:
> >
> > Hi:
> >
> > >From the current implementation, which I find in the interpreter, and from testing on Cog I assume that primitive 83, that is 'perform:', does easily handle an arbitrary number of parameters.
> >
> > Is that correct, or does for instance Cog do something else? (it does not seem so)
> >
> > That's correct. The primitive (InterpreterPrimitives>>primitivePerform) is written in terms of argumentCount and so should cope with any number of arguments up to the maximum (15 is the limit in CompiledMethod, 31 in the bytecode set I believe).
> >
> > I am just asking, because the number of parameters of the Object>>#perform:with: variants goes only up to three. And, the comment does not mention it. (at least in a recent Pharo image)
> >
> > Furthermore, I guess, there is an upper limit on the number of arguments with regard to frame size?
> >
> > Not in the StackVM or the Cog VM since these are running on a stack, not in a context, and so there's always plenty of headroom to push args on the stack during a perform.  At least the method/bytecode set's limit on argumentCount is going to bite before the stack size.  Similarly with perform:withArguments:, as long as the number of arguments is <= LargeFrameSize (56 slots?) the primitive will push arguments.  Of course, the number of arguments must match the method that is found, and so the real limits are CompiledMethod's and the bytecode set's.
> >
> > cheers,
> >
> >
> > Thanks
> > Stefan
> >
> > --
> > Stefan Marr
> > Software Languages Lab
> > Vrije Universiteit Brussel
> > Pleinlaan 2 / B-1050 Brussels / Belgium
> > http://soft.vub.ac.be/~smarr
> > Phone: +32 2 629 2974
> > Fax:   +32 2 629 3525
> >
> >
> >
> >
> > --
> > best,
> > Eliot
> >
>
> --
> Stefan Marr
> Software Languages Lab
> Vrije Universiteit Brussel
> Pleinlaan 2 / B-1050 Brussels / Belgium
> http://soft.vub.ac.be/~smarr
> Phone: +32 2 629 2974
> Fax:   +32 2 629 3525
Reply | Threaded
Open this post in threaded view
|

Re: primitivePerform (prim 83) | primitivePerformInSuperclass (100)

Eliot Miranda-2
In reply to this post by Stefan Marr
 
Hi Stefan,

    can you mail me your tests?

On Sun, Dec 11, 2011 at 4:59 PM, Stefan Marr <[hidden email]> wrote:

Hi Eliot:

Are there any known issues with primitivePerformInSuperclass?

And, ehm, what is the functionality that is supposed to be supported?

I try with a doit, and everything works fine.
But when it is used in a TestCase, it crashes :-/

"""
Exception Type:  EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x0000000000000000
Crashed Thread:  0  Dispatch queue: com.apple.main-thread

Thread 0 Crashed:  Dispatch queue: com.apple.main-thread
0   org.squeakfoundation.Squeak         0x0004ef5a primitivePerformInSuperclass + 42

Thread 1:  Dispatch queue: com.apple.libdispatch-manager
[...]
"""


With regard to the supported functionality, I would expect it to mirror perform more or less exactly, but the image I use, only knows 'perform: selector withArguments: argArray inSuperclass: lookupClass' which uses an explict array for the arguments.
However, from the doIt, the code below seems to work.
And, well, when I use the debugger, it works of course too...

performSuper: aSymbol
       <primitive: 100>
       ^ self perform: aSymbol withArguments: (Array new: 0) inSuperclass: self class superclass

performSuper: aSymbol with: anObject
       <primitive: 100>
       ^ self perform: aSymbol withArguments: (Array with: anObject) inSuperclass: self class superclass


I also tried to put the code from the doit into a class, and see whether that indirection makes a difference, since I remember that you have some special treatment for doits in Cog, right?

Thanks
Stefan


On 08 Dec 2011, at 03:01, Eliot Miranda wrote:

> Hi Stefan,
>
> On Wed, Dec 7, 2011 at 4:09 PM, Stefan Marr <[hidden email]> wrote:
>
> Hi:
>
> >From the current implementation, which I find in the interpreter, and from testing on Cog I assume that primitive 83, that is 'perform:', does easily handle an arbitrary number of parameters.
>
> Is that correct, or does for instance Cog do something else? (it does not seem so)
>
> That's correct. The primitive (InterpreterPrimitives>>primitivePerform) is written in terms of argumentCount and so should cope with any number of arguments up to the maximum (15 is the limit in CompiledMethod, 31 in the bytecode set I believe).
>
> I am just asking, because the number of parameters of the Object>>#perform:with: variants goes only up to three. And, the comment does not mention it. (at least in a recent Pharo image)
>
> Furthermore, I guess, there is an upper limit on the number of arguments with regard to frame size?
>
> Not in the StackVM or the Cog VM since these are running on a stack, not in a context, and so there's always plenty of headroom to push args on the stack during a perform.  At least the method/bytecode set's limit on argumentCount is going to bite before the stack size.  Similarly with perform:withArguments:, as long as the number of arguments is <= LargeFrameSize (56 slots?) the primitive will push arguments.  Of course, the number of arguments must match the method that is found, and so the real limits are CompiledMethod's and the bytecode set's.
>
> cheers,
>
>
> Thanks
> Stefan
>
> --
> Stefan Marr
> Software Languages Lab
> Vrije Universiteit Brussel
> Pleinlaan 2 / B-1050 Brussels / Belgium
> http://soft.vub.ac.be/~smarr
> Phone: <a href="tel:%2B32%202%20629%202974" value="+3226292974">+32 2 629 2974
> Fax:   <a href="tel:%2B32%202%20629%203525" value="+3226293525">+32 2 629 3525
>
>
>
>
> --
> best,
> Eliot
>

--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: <a href="tel:%2B32%202%20629%202974" value="+3226292974">+32 2 629 2974
Fax:   <a href="tel:%2B32%202%20629%203525" value="+3226293525">+32 2 629 3525




--
best,
Eliot

Reply | Threaded
Open this post in threaded view
|

Re: primitivePerform (prim 83) | primitivePerformInSuperclass (100)

Stefan Marr
In reply to this post by David T. Lewis

Hi Dave,
Hi Eliot:

On 12 Dec 2011, at 02:42, David T. Lewis wrote:

> I think you are missing some arguments for the primitive in your
> #performSuper methods.

Thanks Dave, indeed. Was certainly to late for me yesterday.
I forget the class, in which the lookup is supposed to be started.

Eliot, well, there was another argument, which was probably interpreted as the lookup class but was just a SmallInteger instead. Guess that was causing the crash.

From the RoarVM interpreter I understand that the lookup class is not crosschecked for being a class. I think it did work on the interpreter for me, because my patched DNU handler is 'a bit to robust', and does not exactly what it is supposed to do.


Thanks
Stefan

--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: +32 2 629 2974
Fax:   +32 2 629 3525

Reply | Threaded
Open this post in threaded view
|

Re: primitivePerform (prim 83) | primitivePerformInSuperclass (100)

Eliot Miranda-2
 


On Mon, Dec 12, 2011 at 12:53 AM, Stefan Marr <[hidden email]> wrote:

Hi Dave,
Hi Eliot:

On 12 Dec 2011, at 02:42, David T. Lewis wrote:

> I think you are missing some arguments for the primitive in your
> #performSuper methods.

Thanks Dave, indeed. Was certainly to late for me yesterday.
I forget the class, in which the lookup is supposed to be started.

Eliot, well, there was another argument, which was probably interpreted as the lookup class but was just a SmallInteger instead. Guess that was causing the crash.

If so, that's a bug.  The prim should check.  I'll fix this.  So to reproduce I supply a SmallInteger as the lookup class?  But the folloiwng doesn't crash my VM:

nil perform: #yourself withArguments: #() inSuperclass: 0

So I still need to know how to reproduce this on Cog.


>From the RoarVM interpreter I understand that the lookup class is not crosschecked for being a class. I think it did work on the interpreter for me, because my patched DNU handler is 'a bit to robust', and does not exactly what it is supposed to do.


Thanks
Stefan

--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: <a href="tel:%2B32%202%20629%202974" value="+3226292974">+32 2 629 2974
Fax:   <a href="tel:%2B32%202%20629%203525" value="+3226293525">+32 2 629 3525
--
best,
Eliot

Reply | Threaded
Open this post in threaded view
|

Re: primitivePerform (prim 83) | primitivePerformInSuperclass (100)

Eliot Miranda-2
In reply to this post by Stefan Marr
 
Hi Stefan,

On Mon, Dec 12, 2011 at 12:53 AM, Stefan Marr <[hidden email]> wrote:

Hi Dave,
Hi Eliot:

On 12 Dec 2011, at 02:42, David T. Lewis wrote:

> I think you are missing some arguments for the primitive in your
> #performSuper methods.

Thanks Dave, indeed. Was certainly to late for me yesterday.
I forget the class, in which the lookup is supposed to be started.

Eliot, well, there was another argument, which was probably interpreted as the lookup class but was just a SmallInteger instead. Guess that was causing the crash.

The problem was that you declared a primitive with too few arguments and this interacted badly with the VMs interpreted frame format.  You have a method
Object>performSuper: aSymbol with: anObject 
"Send the selector, aSymbol, to the receiver with anObject as its argument.
Fail if the number of arguments expected by the selector is not one.
Primitive. Optional. See Object documentation whatIsAPrimitive."

<primitive: 100>
^ self perform: aSymbol withArguments: (Array with: anObject) inSuperclass: self class superclass

which only declares two arguments even though primitive 100, perform:withArguments:inSuperclass: requires three.  So when the primitive attempted to access the receiver it actually fetched the field below, which happens to be the interpreted frames' saved ip which is null in this case. So the VM dies trying to follow a null pointer when it tries to fetch the receiver's class (since 0 is not a SmallInteger).

0xbff5d7a4 I OstCompilerTestDomain(OstDomain)>requestSuperExecutionOf:on: 367331552: a(n) OstCompilerTestDomain
0xbff5d7b4:   rcvr/clsr: 0x15e508e0     =a(n) OstCompilerTestDomain
0xbff5d7b0:        arg0: 0x14d482ec     =#xx_omni_x_b
0xbff5d7ac:        arg1: 0x15e508c8     =a(n) OstCompilerTestSubjectSub
0xbff5d7a8:   caller ip: 0x1380fc8e=327220366
0xbff5d7a4:    saved fp: 0xbff5d7c4=-1074407484
0xbff5d7a0:      method: 0x1531683c     0x1531683c 355559484: a(n) CompiledMethod
0xbff5d798:intfrm flags:      0x201=513  numArgs: 2  hasContext: 0  isBlock: 0
0xbff5d79c:     context: 0x1383c004     =nil
0xbff5d794:    saved ip:        0x0 0
0xbff5d790:    receiver: 0x15e508e0     =a(n) OstCompilerTestDomain
0xbff5d78c:        stck: 0x15e508c8     =a(n) OstCompilerTestSubjectSub
0xbff5d788:        stck: 0x14d482ec     =#xx_omni_x_b 


It dies at this line in primitivePerformInSuperclass trying to access the receiver's header:
32747           if (((ccIndex = (((usqInt) (longAt(rcvr))) >> 12) & 31)) == 0) {
32748                   currentClass = (longAt(rcvr - BaseHeaderSize)) & AllButTypeMask;
32749                   goto l1;

Now the VM has support for checking primitive argument counts, and it will fail a primitive if the number of arguments dropped from the stack is incorrect.  But it can only check the number of arguments after the primitive has run.  So alas since the crash happens before the prtimitive has finished you are, in the classic phrase, SOL.  Sorry :)

BTW, the saved ip is the bytecode address at which to resume execution in the interpreter.  The return address of the next frame will be e.g. ceReturnToInterpreter so that when a machine code frame returns to an interpreted frame it returns to a trampoline which then reenters the interpreter and resumes execution at the bytecode pointed to by saved ip.
 
>From the RoarVM interpreter I understand that the lookup class is not crosschecked for being a class. I think it did work on the interpreter for me, because my patched DNU handler is 'a bit to robust', and does not exactly what it is supposed to do.


Thanks
Stefan

--
Stefan Marr
Software Languages Lab
Vrije Universiteit Brussel
Pleinlaan 2 / B-1050 Brussels / Belgium
http://soft.vub.ac.be/~smarr
Phone: <a href="tel:%2B32%202%20629%202974" value="+3226292974">+32 2 629 2974
Fax:   <a href="tel:%2B32%202%20629%203525" value="+3226293525">+32 2 629 3525




--
best,
Eliot