FFI: FFI-Kernel-mt.103.mcz

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

FFI: FFI-Kernel-mt.103.mcz

commits-2
Marcel Taeumel uploaded a new version of FFI-Kernel to project FFI:
http://source.squeak.org/FFI/FFI-Kernel-mt.103.mcz

==================== Summary ====================

Name: FFI-Kernel-mt.103
Author: mt
Time: 10 June 2020, 7:28:24.544848 pm
UUID: dbc84b8b-2a33-ab41-a751-4620a7637ddf
Ancestors: FFI-Kernel-mt.102

When generating accessors for struct fields, honor the contract that 'char*' means (null-terminated) C String, which means that Smalltalk strings can be automatically created. This already happens automatically through the FFI plugin, when an FFI call returns 'char*'.

(Note that the alternative whould be to use ExternalData. You can usually exchange 'char*' or 'string' with 'byte*' or 'uint8_t*' to get such ExternalData to then manually read that data. See http://forum.world.st/FFI-Plugin-Auto-conversion-of-char-return-value-into-String-considered-harmful-tp5118147.html)

=============== Diff against FFI-Kernel-mt.102 ===============

Item was changed:
  ----- Method: ExternalType>>readAlias (in category 'private') -----
  readAlias
 
  ^ String streamContents: [:s |
  referentClass == nil
  ifTrue:[(self isAtomic and:[self isPointerType not])
  ifTrue:[s nextPutAll:'^handle "', self writeFieldArgName, '"']
+ ifFalse:[ | shouldReadCString |
+ (shouldReadCString := self = ExternalType string)
+ ifTrue: [s nextPutAll: '^(']
+ ifFalse: [s nextPutAll: '^'].
+ s nextPutAll: 'ExternalData fromHandle: handle'.
+ self isPointerType ifTrue:[s nextPutAll:' asExternalPointer'].
+ s nextPutAll:' type: '.
+ shouldReadCString
+ ifTrue: [s nextPutAll: 'ExternalType string) fromCString']
+ ifFalse: [s nextPutAll: self asPointerType storeString]]]
- ifFalse:[s nextPutAll:'^ExternalData fromHandle: handle'.
- self isPointerType ifTrue:[s nextPutAll:' asExternalPointer'].
- s nextPutAll:' type: ';
- nextPutAll: self asPointerType storeString]]
  ifFalse:[s nextPutAll:'^', referentClass name,' fromHandle: handle'.
  self isPointerType ifTrue:[s nextPutAll:' asExternalPointer']]]!

Item was changed:
  ----- Method: ExternalType>>readFieldAt: (in category 'private') -----
  readFieldAt: byteOffset
  "Answer a string defining the accessor to an entity of the receiver type starting at the given byte offset.
  Private. Used for field definition only."
  self isPointerType ifTrue:
+ [| accessor shouldReadCString |
- [| accessor |
  self flag: #ffiLongVsInt. "mt: Here short means 'long', which is actually 'int', and long means 'longlong'. Sigh."
  accessor := self pointerSize caseOf: {
  [4] -> [#shortPointerAt:].
  [8] -> [#longPointerAt:] }.
+ shouldReadCString := self = ExternalType string.
  ^String streamContents:
  [:s|
  referentClass
  ifNil:
+ [shouldReadCString
+ ifTrue: [s nextPutAll: '^(']
+ ifFalse: [s nextPutAll: '^'].
+ s nextPutAll: 'ExternalData fromHandle: (handle ', accessor, ' ';
- [s nextPutAll: '^ExternalData fromHandle: (handle ', accessor, ' ';
  print: byteOffset;
+ nextPutAll: ') type: ExternalType '.
+ shouldReadCString
+ ifTrue:
+ [s nextPutAll: 'string) fromCString']
+ ifFalse:
+ [s nextPutAll: self atomicTypeName;
+ nextPutAll: ' asPointerType']]
- nextPutAll: ') type: ExternalType ';
- nextPutAll: self atomicTypeName;
- nextPutAll: ' asPointerType']
  ifNotNil:
  [s nextPutAll: '^';
  print: referentClass;
  nextPutAll: ' fromHandle: (handle ', accessor, ' ';
  print: byteOffset;
  nextPut: $)]]].
 
  self isAtomic ifFalse: "structure type"
  [^String streamContents:[:s|
  s nextPutAll:'^';
  print: referentClass;
  nextPutAll:' fromHandle: (handle structAt: ';
  print: byteOffset;
  nextPutAll:' length: ';
  print: self byteSize;
  nextPutAll:')']].
 
  self isTypeAlias ifTrue: "alias to atomic type"
  [^String streamContents:[:s |
  s nextPutAll:'^';
  print: referentClass;
  nextPutAll:' fromHandle: (handle ';
  nextPutAll: (AtomicSelectors at: self atomicType);
  space; print: byteOffset;
  nextPutAll:')']].
 
  "Atomic non-pointer types"
  ^String streamContents:
  [:s|
  s nextPutAll:'^handle ';
  nextPutAll: (AtomicSelectors at: self atomicType);
  space; print: byteOffset].!

Item was changed:
  ----- Method: ExternalType>>writeAliasWith: (in category 'private') -----
  writeAliasWith: valueName
 
  ^ String streamContents: [:s |
  (referentClass == nil and:[self isAtomic and:[self isPointerType not]])
  ifTrue:[s nextPutAll:'handle := ', valueName, '.']
+ ifFalse:[
+ self = ExternalType string
+ ifTrue: [
+ s nextPutAll: 'self shouldNotImplement. "You cannot write an arbitrary String object into an external address. Maybe we can pad or trim it in the future to only use the memory that has already been allocated. Additionally, this type alias to a char* stores its external address in a byte array. So, locally storing the string in a byte array will not work either, because we cannot discriminate when reading the field again."'; crtab.
+ s nextPutAll: 'handle := ', valueName, ' asByteArray, #[0].']
+ ifFalse: [
+ s nextPutAll:'handle := ', valueName,' getHandle'.
+ self isPointerType ifTrue:[s nextPutAll:' asByteArrayPointer']]]]!
- ifFalse:[s nextPutAll:'handle := ', valueName,' getHandle'.
- self isPointerType ifTrue:[s nextPutAll:' asByteArrayPointer']]]!

Item was changed:
  ----- Method: ExternalType>>writeFieldAt:with: (in category 'private') -----
  writeFieldAt: byteOffset with: valueName
  "Answer a string defining the accessor to an entity of the receiver type starting at the given byte offset.
  Private. Used for field definition only."
  self isPointerType ifTrue:
  [| accessor |
  self flag: #ffiLongVsInt. "mt: Here short means 'long', which is actually 'int', and long means 'longlong'. Sigh."
  accessor := self pointerSize caseOf: {
  [4] -> [#shortPointerAt:].
  [8] -> [#longPointerAt:] }.
+
  ^String streamContents:
  [:s|
+ self = ExternalType string ifTrue:
+ [s nextPutAll: 'self shouldNotImplement. "You should not write a string of abitrary length into an external address. Maybe we can pad or trim it in the future to only use the memory that has already been allocated."']
+ ifFalse:
+ [s nextPutAll:'handle ', accessor, ' ';
+ print: byteOffset;
+ nextPutAll:' put: ';
+ nextPutAll: valueName;
+ nextPutAll:' getHandle.']]].
- s nextPutAll:'handle ', accessor, ' ';
- print: byteOffset;
- nextPutAll:' put: ';
- nextPutAll: valueName;
- nextPutAll:' getHandle.']].
 
  self isAtomic ifFalse:[ "structure type"
  ^String streamContents:[:s|
  s nextPutAll:'handle structAt: ';
  print: byteOffset;
  nextPutAll:' put: ';
  nextPutAll: valueName;
  nextPutAll:' getHandle';
  nextPutAll:' length: ';
  print: self byteSize;
  nextPutAll:'.']].
 
  self isTypeAlias ifTrue:[ "alias to atomic type"
  ^String streamContents:[:s|
  s nextPutAll:'handle ';
  nextPutAll: (AtomicSelectors at: self atomicType);
  space; print: byteOffset;
  nextPutAll:' put: ';
  nextPutAll: valueName;
  nextPutAll: ' getHandle']].
 
  ^String streamContents:[:s|
  s nextPutAll:'handle ';
  nextPutAll: (AtomicSelectors at: self atomicType);
  space; print: byteOffset;
  nextPutAll:' put: ';
  nextPutAll: valueName].!