Alistair Grant uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-AlistairGrant.2455.mcz ==================== Summary ==================== Name: VMMaker.oscog-AlistairGrant.2455 Author: AlistairGrant Time: 14 October 2018, 8:59:01.383815 pm UUID: 9e8e4134-b30b-4734-9477-95d556650155 Ancestors: VMMaker.oscog-eem.2454 VMClass strlen, strncpy and getenv Pharo stores UTF8 encoded strings in ByteArrays (ByteString, strictly speaking, expects to only store characters that can be represented as a single byte in UTF8). ByteArrays are also used within the simulator to represent buffers allocated by the simulator. As such, the strings may either be the length of the ByteArray or less than the ByteArray size and null terminated. These changes extend strlen: and strncpy:_:_: to handle ByteArrays and add some tests (tests for strings in the object memory are todo). InterpreterPrimitives>>primitiveGetenv: returned nil rather than 0 in the simulator when a variable that isn't defined is requested. =============== Diff against VMMaker.oscog-eem.2454 =============== Item was changed: ----- Method: InterpreterPrimitives>>primitiveGetenv (in category 'other primitives') ----- primitiveGetenv "Access to environment variables via getenv. No putenv or setenv as yet." | key var result | <export: true> <var: #key type: #'char *'> <var: #var type: #'char *'> sHEAFn ~= 0 ifTrue: "secHasEnvironmentAccess" [self sHEAFn ifFalse: [^self primitiveFailFor: PrimErrInappropriate]]. key := self cStringOrNullFor: self stackTop. key = 0 ifTrue: [self successful ifTrue: [^self primitiveFailFor: PrimErrBadArgument]. ^self primitiveFailFor: primFailCode]. + var := (self getenv: (self cCode: [key] inSmalltalk: [key allButLast])) ifNil: [0]. - var := self getenv: (self cCode: [key] inSmalltalk: [key allButLast]). self free: key. var ~= 0 ifTrue: [result := objectMemory stringForCString: var. result ifNil: [^self primitiveFailFor: PrimErrNoMemory]]. self assert: primFailCode = 0. self pop: 2 thenPush: (var = 0 ifTrue: [objectMemory nilObject] ifFalse: [result])! Item was changed: ----- Method: VMClass>>strlen: (in category 'C library simulation') ----- strlen: aCString "Simulate strlen(3)" <doNotGenerate> | len | aCString isString ifTrue: [^aCString size]. + aCString class == ByteArray ifTrue: [ + "ByteArrays may be 0 terminated or the correct length (in the simulator)" + len := 0. + [(len = aCString size or: [(aCString at: len+1) = 0]) ifTrue: [^len]. + len := len + 1] repeat]. + "Must be an address" len := 0. [(self byteAt: aCString + len) = 0 ifTrue: [^len]. len := len + 1] repeat! Item was changed: ----- Method: VMClass>>strncpy:_:_: (in category 'C library simulation') ----- strncpy: aString _: bString _: n <doNotGenerate> "implementation of strncpy(3)" + + | getBlock setBlock count | + + count := n. + aString isString ifTrue: [setBlock := [ :idx :ch | aString at: idx put: ch asCharacter]]. + aString class == ByteArray ifTrue: + [setBlock := [ :idx :ch | aString at: idx put: ch]]. + aString isInteger ifTrue: [setBlock := [ :idx :ch | self byteAt: aString + idx - 1 put: ch]]. + bString isString ifTrue: [ + getBlock := [ :idx | (bString at: idx) asInteger ]. + count := count min: bString size]. + bString class == ByteArray ifTrue: [ + getBlock := [ :idx | bString at: idx]. + count := count min: bString size]. + bString isInteger ifTrue: [getBlock := [ :idx | self byteAt: bString + idx - 1]]. + bString class == CArray ifTrue: + [getBlock := [ :idx | bString at: idx - 1]]. + self assert: getBlock ~= nil. + self assert: setBlock ~= nil. + 1 to: count do: [ :i | | v | + v := getBlock value: i. + setBlock value: i value: v. + v = 0 ifTrue: [^aString] ]. - aString isString - ifTrue: - [1 to: n do: - [:i| | v | - v := bString isString - ifTrue: [bString at: i] - ifFalse: [Character value: (self byteAt: bString + i - 1)]. - aString at: i put: v. - v asInteger = 0 ifTrue: [^aString]]] - ifFalse: - [1 to: n do: - [:i| | v | - v := bString isString - ifTrue: [(bString at: i) asInteger] - ifFalse: [self byteAt: bString + i - 1]. - self byteAt: aString + i - 1 put: v. - v = 0 ifTrue: [^aString]]]. ^aString! Item was added: + TestCase subclass: #VMClassTests + instanceVariableNames: 'testString vmclass' + classVariableNames: '' + poolDictionaries: '' + category: 'VMMaker-Tests'! Item was added: + ----- Method: VMClassTests>>initialize (in category 'initialize-release') ----- + initialize + + super initialize. + testString := 'hello world'.! Item was added: + ----- Method: VMClassTests>>setUp (in category 'running') ----- + setUp + + super setUp. + vmclass := VMClass new. + ! Item was added: + ----- Method: VMClassTests>>testStrlen (in category 'tests') ----- + testStrlen + + | testByteArray | + + "Instances of String must be the correct length" + self assert: (vmclass strlen: testString) equals: testString size. + + "Instances of ByteArray can optionally have trailing nulls" + testByteArray := testString asByteArray. + self assert: (vmclass strlen: testByteArray) equals: testString size. + testByteArray := testByteArray, (ByteArray new: 3). + self assert: (vmclass strlen: testByteArray) equals: testString size. + ! Item was added: + ----- Method: VMClassTests>>testStrncpy (in category 'tests') ----- + testStrncpy + + | stringA byteArrayA | + + stringA := String new: 5. + vmclass strncpy: stringA _: testString _: stringA size. + self assert: stringA equals: 'hello'. + + stringA := String new: testString size + 3. + vmclass strncpy: stringA _: testString _: stringA size. + self assert: stringA equals: (testString, (String new: 3)). + + byteArrayA := ByteArray new: 5. + vmclass strncpy: byteArrayA _: testString _: byteArrayA size. + self assert: byteArrayA equals: 'hello' asByteArray. + + byteArrayA := ByteArray new: testString size + 3. + vmclass strncpy: byteArrayA _: testString _: byteArrayA size. + self assert: byteArrayA equals: (testString, (String new: 3)) asByteArray. + + ! |
Hi Alistair, support code like this should be tuned for simulation speed. Don't bother with the asserts: (asserts belong in code that will be translated to C, or tests), and try and use and ifTrue:ifFalse: style rather than foo isBar ifTrue: []. foo isBaz ifTrue: [], to reduce the number of types comparisons done. On Mon, Oct 15, 2018 at 11:18 AM <[hidden email]> wrote:
_,,,^..^,,,_ best, Eliot |
In reply to this post by commits-2
Hi Alistair, also var := (self getenv: (self cCode: [key] inSmalltalk: [key allButLast])) ifNil: [0]. doesn't make sense to me. In C nil == 0. So ifNil: [0] is a no-op in C. Either the genenv: simulation should answer 0 or it should answer nil. But we shouldn't fix the primitive two handle incorrect simulation; we should instead implement the simulated getenv: to match what the primitive expects. Make sense? On Mon, Oct 15, 2018 at 11:18 AM <[hidden email]> wrote:
_,,,^..^,,,_ best, Eliot |
Hi Eliot, On Mon, 15 Oct 2018 at 21:58, Eliot Miranda <[hidden email]> wrote: > > > Hi Alistair, > > also > var := (self getenv: (self cCode: [key] inSmalltalk: [key allButLast])) ifNil: [0]. > doesn't make sense to me. In C nil == 0. So ifNil: [0] is a no-op in C. Either the genenv: simulation should answer 0 or it should answer nil. But we shouldn't fix the primitive two handle incorrect simulation; we should instead implement the simulated getenv: to match what the primitive expects. Make sense? Sorry I didn't get to this last night. On Mon, 15 Oct 2018 at 21:55, Eliot Miranda <[hidden email]> wrote: > > support code like this should be tuned for simulation speed. Don't bother with the asserts: (asserts belong in code that will be translated to C, or tests), and try and use and ifTrue:ifFalse: style rather than foo isBar ifTrue: []. foo isBaz ifTrue: [], to reduce the number of types comparisons done. Done. Thanks for your feedback, Alistair |
> On Oct 15, 2018, at 11:21 PM, Alistair Grant <[hidden email]> wrote: > > > Hi Eliot, > >> On Mon, 15 Oct 2018 at 21:58, Eliot Miranda <[hidden email]> wrote: >> >> >> Hi Alistair, >> >> also >> var := (self getenv: (self cCode: [key] inSmalltalk: [key allButLast])) ifNil: [0]. >> doesn't make sense to me. In C nil == 0. So ifNil: [0] is a no-op in C. Either the genenv: simulation should answer 0 or it should answer nil. But we shouldn't fix the primitive two handle incorrect simulation; we should instead implement the simulated getenv: to match what the primitive expects. Make sense? > > Sorry I didn't get to this last night. No probs. It was < 5 mins work. >> On Mon, 15 Oct 2018 at 21:55, Eliot Miranda <[hidden email]> wrote: >> >> support code like this should be tuned for simulation speed. Don't bother with the asserts: (asserts belong in code that will be translated to C, or tests), and try and use and ifTrue:ifFalse: style rather than foo isBar ifTrue: []. foo isBaz ifTrue: [], to reduce the number of types comparisons done. > > Done. Thanks! > Thanks for your feedback, Please don’t hesitate to question and critique my work too!! > Alistair |
Free forum by Nabble | Edit this page |