This repository has been archived by the owner on Jan 5, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
TFStringType.class.st
139 lines (104 loc) · 3.83 KB
/
TFStringType.class.st
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"
I represent a String type in uffi that gets marshalled to a pointer type in libffi.
I override the marshalling methods to allow reading/writing strings from/to C pointers.
See my superclass for more details.
"
Class {
#name : #TFStringType,
#superclass : #TFDerivedType,
#classVars : [
'AllocatedStrings'
],
#category : #'ThreadedFFI-Types'
}
{ #category : #writting }
TFStringType >> allocateString: aString [
| anExternalAddress |
anExternalAddress := (ExternalAddress fromString: aString utf8Encoded).
self allocatedStrings add: anExternalAddress.
^ anExternalAddress
]
{ #category : #'as yet unclassified' }
TFStringType >> allocatedStrings [
^ AllocatedStrings ifNil: [ AllocatedStrings := Set new ]
]
{ #category : #accessing }
TFStringType >> basicType [
^ TFBasicType pointer
]
{ #category : #writting }
TFStringType >> callbackReadValue: anExternalAddress [
^ (self readValue: anExternalAddress) readStringUTF8
]
{ #category : #marshalling }
TFStringType >> emitFreeIfNeededOfIndex: argIndex argumentsArrayTempName: argumentsArrayTempName withBuilder: anIRBuilder [
"I will send the message #freeValueIfNeeded: to myself with the argument from the argumentArray at the position passed as parameter.
It is important that I do not leave nothing in the stack"
anIRBuilder pushLiteral: self.
anIRBuilder pushTemp: argumentsArrayTempName.
anIRBuilder pushLiteral: argIndex.
anIRBuilder send: #at:.
anIRBuilder send: #freeValueIfNeeded:.
anIRBuilder popTop
]
{ #category : #marshalling }
TFStringType >> emitMarshallFromPrimitive: anIRBuilder [
anIRBuilder send: #readStringUTF8
]
{ #category : #marshalling }
TFStringType >> emitMarshallToPrimitive: anIRBuilder [
anIRBuilder addTemp: #__marshall_temp.
anIRBuilder storeTemp: #__marshall_temp.
anIRBuilder popTop.
anIRBuilder pushLiteral: self.
anIRBuilder pushTemp: #__marshall_temp.
anIRBuilder send: #prepareStringForMarshalling:
]
{ #category : #writting }
TFStringType >> freeValueIfNeeded: aCHeapValueHolder [
| pointer |
aCHeapValueHolder isNull ifTrue: [ ^ self ].
pointer := aCHeapValueHolder pointerAt: 1.
(self allocatedStrings includes: pointer) ifFalse: [ ^ self ].
self allocatedStrings remove: pointer.
pointer isNull ifFalse: [
pointer free ]
]
{ #category : #marshalling }
TFStringType >> marshallToPrimitive: aValue [
^ self prepareStringForMarshalling: aValue
]
{ #category : #writting }
TFStringType >> prepareStringForMarshalling: aStringOrExternalAddress [
"The TFString type supports four possible parameters.
- A String: this is allocated as an external string, encoded and passed the pointer to the allocated space.
- A ByteArray: this will be passed as a pointer to the external call. It should be pinned and dereferenced to get the address.
- An ExternalAddress: this is directly passed to the external call.
- nil: An ExternalAddress null is passed in this case "
"Maybe this code should be implemented delegating to the objects to handle the different cases"
"Handling Strings"
aStringOrExternalAddress isString
ifTrue: [ ^ self allocateString: aStringOrExternalAddress ].
"Handling nil"
aStringOrExternalAddress
ifNil: [ ^ ExternalAddress null ].
"Handling ByteArray"
(aStringOrExternalAddress isKindOf: ByteArray)
ifTrue: [ aStringOrExternalAddress pinInMemory.
^ PointerUtils oopForObject: aStringOrExternalAddress ].
"Handling ExternalAddress"
^ aStringOrExternalAddress
]
{ #category : #writting }
TFStringType >> readValue: anExternalAddress [
^ self basicType readValue: anExternalAddress
]
{ #category : #writting }
TFStringType >> write: aStringOrExternalAddress into: targetAddress [
"If the argument is a aString I have to allocate it and later free it"
| anAddress |
anAddress := self prepareStringForMarshalling: aStringOrExternalAddress.
self basicType
write: anAddress
into: targetAddress
]