Why can't I pass an UninterpretedBytes to a vo

2019-07-11 13:51发布

问题:

I'd like to pass an UninterpretedBytes to an external library, say something like this

MyLibrary>>foo: buf len: len
    <C: int foo(void *buf,unsigned int len)>

MyApplication>>test
    buffer := UninterpretedBytes new: 4.
    ^MyLibrary new foo: buffer len: buffer size.

But this fails in CPointerType>>coerceForArgument:anObject.

I know that I could use buffer gcCopyToHeap but I don't want to.
I want to handle an object in Smalltalk memory with Smalltalk 1-based address and no extra copy nor any other complication.

I find the last lines of CPointerType>>coerceForArgument:anObject suspiscious:

(anObject isString
    or: [self isOopRef and: [anObject class isBits and: [anObject class isVariable]]])
        ifTrue: [^anObject].

self isOopRef means that the CPointerType has been declared as _oopref *.
If I cheat and declare:

MyLibrary>>foo: buf len: len
    <C: int foo(_oopref *buf,unsigned int len)>

then MyApplication new test works as expected, but I don't want to cheat, the prototypes are extracted automatically from C headers and I don't want to patch them manually.

self isOopRef semantically means is a reference to an Object Oriented Pointer.
Every Object can be viewed as an Object Oriented Pointer and can thus be passed by reference to such _oopref *, except immediate objects like SmallInteger SmallDouble Character. There is a guard above in code to check for the case when anObject isImmediate, so at this stage, anObject is definitely an oop.

Such _oopref could be manipulated from within the external C-code, for example thru some Object Engine function oe*(), and this is not limited to arrays of bytes/words/double words!
The guard and: [anObject class isBits and: [anObject class isVariable]] thus makes no sense.

If I modify the last lines of CPointerType>>coerceForArgument:anObject into:

(anObject isString
    or: [self isOopRef or: [anObject class isBits and: [anObject class isVariable]]])
        ifTrue: [^anObject].

Then MyApplication new test works like a charm.
Wasn't it the real intention? Pass either any kind of non immediate object if the prototype specifies a pointer to an oop, or pass a reference to an array of bytes/words/...