I was looking at the following primitiveFileRead because I wanted to extract some code. I do not see why objects should move during the primitive execution... And I do not see why is this check only made in this primitive (and the threadedFFI ones...).
Does someone have a clue?
Thanks, Guille
primitiveFileRead <export: true> | retryCount count startIndex array file elementSize bytesRead | <var: 'file' type: #'SQFile *'> <var: 'count' type: #'size_t'> <var: 'startIndex' type: #'size_t'> <var: 'elementSize' type: #'size_t'>
retryCount := 0. count := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). startIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 1).
[array := interpreterProxy stackValue: 2. file := self fileValueOf: (interpreterProxy stackValue: 3).
(interpreterProxy failed "buffer can be any indexable words or bytes object except CompiledMethod" or: [(interpreterProxy isWordsOrBytes: array) not]) ifTrue: [^interpreterProxy primitiveFailFor: PrimErrBadArgument].
elementSize := (interpreterProxy isWords: array) ifTrue: [4] ifFalse: [1]. (startIndex >= 1 and: [(startIndex + count - 1) <= (interpreterProxy slotSizeOf: array)]) ifFalse: [^interpreterProxy primitiveFailFor: PrimErrBadIndex].
"Note: adjust startIndex for zero-origin indexing" bytesRead := self sqFile: file Read: count * elementSize Into: (self cCoerce: (interpreterProxy firstIndexableField: array) to: #'char *') At: (startIndex - 1) * elementSize. *interpreterProxy primitiveFailureCode = PrimErrObjectMayMove* * and: [(retryCount := retryCount + 1) <= 2] "Two objects, the file and the array can move"*] whileTrue: [interpreterProxy tenuringIncrementalGC; primitiveFailFor: PrimNoErr]. interpreterProxy failed ifFalse: [interpreterProxy pop: 5 "pop rcvr, file, array, startIndex, count" thenPush:(interpreterProxy integerObjectOf: bytesRead // elementSize) "push # of elements read"]
Hi Guillermo,
On Mon, May 13, 2013 at 3:04 AM, Guillermo Polito <guillermopolito@gmail.com
wrote:
I was looking at the following primitiveFileRead because I wanted to extract some code. I do not see why objects should move during the primitive execution... And I do not see why is this check only made in this primitive (and the threadedFFI ones...).
Does someone have a clue?
This is for the threaded VM with the current GC. Imagine sqFileReadIntoAt blocks and the VM does a thread switch to some other thread. At that point the other thread could cause the VM to perform a GC. Andreas came up with the idea of handling this situation by allowing a blocking thread to prevent full GCs that move objects in old space, but not prevent "incremental" GCs which only move objects in young space. So if the thread executing sqFileReadIntoAt is given only old objects it can safely block if it sets a flag preventing full GCs.
In a GC supporting pinning and/or lazy become the blocking thread would instead either pin its buffer or become its buffer into a pinned space, in which case the error below could never occur. But the check is harmless.
does this help?
Thanks, Guille
primitiveFileRead <export: true> | retryCount count startIndex array file elementSize bytesRead | <var: 'file' type: #'SQFile *'> <var: 'count' type: #'size_t'> <var: 'startIndex' type: #'size_t'> <var: 'elementSize' type: #'size_t'>
retryCount := 0. count := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). startIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 1).
[array := interpreterProxy stackValue: 2. file := self fileValueOf: (interpreterProxy stackValue: 3).
(interpreterProxy failed "buffer can be any indexable words or bytes object except CompiledMethod" or: [(interpreterProxy isWordsOrBytes: array) not]) ifTrue: [^interpreterProxy primitiveFailFor: PrimErrBadArgument].
elementSize := (interpreterProxy isWords: array) ifTrue: [4] ifFalse: [1]. (startIndex >= 1 and: [(startIndex + count - 1) <= (interpreterProxy slotSizeOf: array)]) ifFalse: [^interpreterProxy primitiveFailFor: PrimErrBadIndex].
"Note: adjust startIndex for zero-origin indexing" bytesRead := self sqFile: file Read: count * elementSize Into: (self cCoerce: (interpreterProxy firstIndexableField: array) to: #'char *') At: (startIndex - 1) * elementSize. *interpreterProxy primitiveFailureCode = PrimErrObjectMayMove*
- and: [(retryCount := retryCount + 1) <= 2] "Two objects, the file and
the array can move"*] whileTrue: [interpreterProxy tenuringIncrementalGC; primitiveFailFor: PrimNoErr]. interpreterProxy failed ifFalse: [interpreterProxy pop: 5 "pop rcvr, file, array, startIndex, count" thenPush:(interpreterProxy integerObjectOf: bytesRead // elementSize) "push # of elements read"]
Hi!
On Mon, May 13, 2013 at 11:09 PM, Eliot Miranda eliot.miranda@gmail.comwrote:
Hi Guillermo,
On Mon, May 13, 2013 at 3:04 AM, Guillermo Polito < guillermopolito@gmail.com> wrote:
I was looking at the following primitiveFileRead because I wanted to extract some code. I do not see why objects should move during the primitive execution... And I do not see why is this check only made in this primitive (and the threadedFFI ones...).
Does someone have a clue?
This is for the threaded VM with the current GC. Imagine sqFileReadIntoAt blocks and the VM does a thread switch to some other thread. At that point the other thread could cause the VM to perform a GC. Andreas came up with the idea of handling this situation by allowing a blocking thread to prevent full GCs that move objects in old space, but not prevent "incremental" GCs which only move objects in young space. So if the thread executing sqFileReadIntoAt is given only old objects it can safely block if it sets a flag preventing full GCs.
In a GC supporting pinning and/or lazy become the blocking thread would instead either pin its buffer or become its buffer into a pinned space, in which case the error below could never occur. But the check is harmless.
does this help?
Yes, so it is only used in case of a threaded VM, what makes more sense :).
Now I wonder, shouldn't then this check be done in (almost) every primitive?
Tx!! Guille
Thanks, Guille
primitiveFileRead <export: true> | retryCount count startIndex array file elementSize bytesRead | <var: 'file' type: #'SQFile *'> <var: 'count' type: #'size_t'> <var: 'startIndex' type: #'size_t'> <var: 'elementSize' type: #'size_t'>
retryCount := 0. count := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). startIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 1).
[array := interpreterProxy stackValue: 2. file := self fileValueOf: (interpreterProxy stackValue: 3).
(interpreterProxy failed "buffer can be any indexable words or bytes object except CompiledMethod" or: [(interpreterProxy isWordsOrBytes: array) not]) ifTrue: [^interpreterProxy primitiveFailFor: PrimErrBadArgument].
elementSize := (interpreterProxy isWords: array) ifTrue: [4] ifFalse: [1]. (startIndex >= 1 and: [(startIndex + count - 1) <= (interpreterProxy slotSizeOf: array)]) ifFalse: [^interpreterProxy primitiveFailFor: PrimErrBadIndex].
"Note: adjust startIndex for zero-origin indexing" bytesRead := self sqFile: file Read: count * elementSize Into: (self cCoerce: (interpreterProxy firstIndexableField: array) to: #'char *') At: (startIndex - 1) * elementSize. *interpreterProxy primitiveFailureCode = PrimErrObjectMayMove*
- and: [(retryCount := retryCount + 1) <= 2] "Two objects, the file and
the array can move"*] whileTrue: [interpreterProxy tenuringIncrementalGC; primitiveFailFor: PrimNoErr]. interpreterProxy failed ifFalse: [interpreterProxy pop: 5 "pop rcvr, file, array, startIndex, count" thenPush:(interpreterProxy integerObjectOf: bytesRead // elementSize) "push # of elements read"]
-- best, Eliot
On Tue, May 14, 2013 at 5:30 AM, Guillermo Polito <guillermopolito@gmail.com
wrote:
Hi!
On Mon, May 13, 2013 at 11:09 PM, Eliot Miranda eliot.miranda@gmail.comwrote:
Hi Guillermo,
On Mon, May 13, 2013 at 3:04 AM, Guillermo Polito < guillermopolito@gmail.com> wrote:
I was looking at the following primitiveFileRead because I wanted to extract some code. I do not see why objects should move during the primitive execution... And I do not see why is this check only made in this primitive (and the threadedFFI ones...).
Does someone have a clue?
This is for the threaded VM with the current GC. Imagine sqFileReadIntoAt blocks and the VM does a thread switch to some other thread. At that point the other thread could cause the VM to perform a GC. Andreas came up with the idea of handling this situation by allowing a blocking thread to prevent full GCs that move objects in old space, but not prevent "incremental" GCs which only move objects in young space. So if the thread executing sqFileReadIntoAt is given only old objects it can safely block if it sets a flag preventing full GCs.
In a GC supporting pinning and/or lazy become the blocking thread would instead either pin its buffer or become its buffer into a pinned space, in which case the error below could never occur. But the check is harmless.
does this help?
Yes, so it is only used in case of a threaded VM, what makes more sense :).
Now I wonder, shouldn't then this check be done in (almost) every primitive?
I don't think so. Only in primitives that could block while the VM could do other things. So for example, DNS lookup. In fact, the current DNS lookup primitive has its own custom threading scheme sop it can run un the background (not functional on unix). A threaded VM should eliminate the need for such special-case code.
Tx!! Guille
Thanks, Guille
primitiveFileRead <export: true> | retryCount count startIndex array file elementSize bytesRead | <var: 'file' type: #'SQFile *'> <var: 'count' type: #'size_t'> <var: 'startIndex' type: #'size_t'> <var: 'elementSize' type: #'size_t'>
retryCount := 0. count := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0). startIndex := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 1).
[array := interpreterProxy stackValue: 2. file := self fileValueOf: (interpreterProxy stackValue: 3).
(interpreterProxy failed "buffer can be any indexable words or bytes object except CompiledMethod" or: [(interpreterProxy isWordsOrBytes: array) not]) ifTrue: [^interpreterProxy primitiveFailFor: PrimErrBadArgument].
elementSize := (interpreterProxy isWords: array) ifTrue: [4] ifFalse: [1]. (startIndex >= 1 and: [(startIndex + count - 1) <= (interpreterProxy slotSizeOf: array)]) ifFalse: [^interpreterProxy primitiveFailFor: PrimErrBadIndex].
"Note: adjust startIndex for zero-origin indexing" bytesRead := self sqFile: file Read: count * elementSize Into: (self cCoerce: (interpreterProxy firstIndexableField: array) to: #'char *') At: (startIndex - 1) * elementSize. *interpreterProxy primitiveFailureCode = PrimErrObjectMayMove*
- and: [(retryCount := retryCount + 1) <= 2] "Two objects, the file and
the array can move"*] whileTrue: [interpreterProxy tenuringIncrementalGC; primitiveFailFor: PrimNoErr]. interpreterProxy failed ifFalse: [interpreterProxy pop: 5 "pop rcvr, file, array, startIndex, count" thenPush:(interpreterProxy integerObjectOf: bytesRead // elementSize) "push # of elements read"]
-- best, Eliot
vm-dev@lists.squeakfoundation.org