FreeBASIC  0.91.0
rtl-system-thread.bas
Go to the documentation of this file.
1 '' threadcall AST transform
2 ''
3 '' chng: oct/2011 written [jofers]
4 
5 #include once "fb.bi"
6 #include once "fbint.bi"
7 #include once "ast.bi"
8 #include once "rtl.bi"
9 
10 declare function hThreadCallPushType _
11  ( _
12  byval funcexpr as ASTNODE ptr, _
13  byval tctype as integer, _
14  byval stype as FBSYMBOL ptr _
15  ) as integer
16 
17 function hThreadCallMapType _
18  ( _
19  byval sym as FBSYMBOL ptr, _
20  byval udt as integer = FALSE _
21  ) as integer
22 
23  function = -1
24 
25  dim as FB_DATATYPE dtype = symbGetType( sym )
26  dim as FBSYMBOL ptr subtype = symbGetSubType( sym )
27 
28  '' arrays not supported inside udts
29  if( symbIsArray( sym ) ) then
30  return iif( udt, -1, FB_THREADCALL_PTR )
31  end if
32 
33  if( typeIsPtr( dtype ) ) then
34  return FB_THREADCALL_PTR
35  end if
36 
37  select case( dtype )
38  case FB_DATATYPE_STRING
39  function = iif( udt, -1, FB_THREADCALL_PTR )
40  case FB_DATATYPE_STRUCT
41  '' restrictions to simplify life
42  if( symbGetUDTIsUnion( subtype ) or symbGetUDTHasAnonUnion( subtype ) ) then
43  exit function
44  end if
45  if symbGetUDTAlign( subtype ) <> 0 then
46  exit function
47  end if
48 
49  '' FB transforms type with 1 element to that element's type
50  dim as FBSYMBOL ptr first = symbUdtGetFirstField( subtype )
51  '' no second field?
52  if( symbUdtGetNextField( first ) = NULL ) then
53  function = hThreadCallMapType( first, TRUE )
54  else
55  function = FB_THREADCALL_STRUCT
56  end if
57  case FB_DATATYPE_BYTE, FB_DATATYPE_CHAR, FB_DATATYPE_UBYTE, _
58  FB_DATATYPE_SHORT, FB_DATATYPE_WCHAR, FB_DATATYPE_USHORT, _
59  FB_DATATYPE_INTEGER, FB_DATATYPE_ENUM, FB_DATATYPE_UINT, _
60  FB_DATATYPE_LONGINT, FB_DATATYPE_ULONGINT, _
61  FB_DATATYPE_SINGLE, FB_DATATYPE_DOUBLE
62  select case as const( typeGetSizeType( dtype ) )
63  case FB_SIZETYPE_INT8 : function = FB_THREADCALL_INT8
64  case FB_SIZETYPE_UINT8 : function = FB_THREADCALL_UINT8
65  case FB_SIZETYPE_INT16 : function = FB_THREADCALL_INT16
66  case FB_SIZETYPE_UINT16 : function = FB_THREADCALL_UINT16
67  case FB_SIZETYPE_INT32 : function = FB_THREADCALL_INT32
68  case FB_SIZETYPE_UINT32 : function = FB_THREADCALL_UINT32
69  case FB_SIZETYPE_INT64 : function = FB_THREADCALL_INT64
70  case FB_SIZETYPE_UINT64 : function = FB_THREADCALL_UINT64
71  case FB_SIZETYPE_FLOAT32 : function = FB_THREADCALL_FLOAT32
72  case FB_SIZETYPE_FLOAT64 : function = FB_THREADCALL_FLOAT64
73  case else : assert( FALSE )
74  end select
75  case else
76  exit function
77  end select
78 
79 end function
80 
81 function hThreadCallPushStruct _
82  ( _
83  byval funcexpr as ASTNODE ptr, _
84  byval struct as FBSYMBOL ptr _
85  ) as integer
86 
87  dim as FBSYMBOL ptr fld = any
88  dim as integer count = any
89 
90  '' count number of elements
91  count = 0
92  fld = symbUdtGetFirstField( struct )
93  do
94  count += 1
95  fld = symbUdtGetNextField( fld )
96  loop while( fld )
97 
98  '' push number of elements
99  if( astNewArg( funcexpr, astNewCONSTi( count ) ) = NULL ) then
100  exit function
101  end if
102 
103  '' push each element
104  fld = symbUdtGetFirstField( struct )
105  do
106  if( hThreadCallPushType( funcexpr, _
107  hThreadCallMapType( fld, TRUE ), _
108  symbGetSubType( fld ) ) = FALSE ) then
109  exit function
110  end if
111  fld = symbUdtGetNextField( fld )
112  loop while( fld )
113 
114  function = TRUE
115 end function
116 
117 '':::::
118 function hThreadCallPushType _
119  ( _
120  byval funcexpr as ASTNODE ptr, _
121  byval tctype as integer, _
122  byval stype as FBSYMBOL ptr _
123  ) as integer
124 
125  function = false
126 
127  '' Unsupported datatype
128  if( tctype = -1 ) then
129  errReport( FB_ERRMSG_UNSUPPORTEDFUNCTION )
130  exit function
131  end if
132 
133  '' push argument on stack
134  dim as ASTNODE ptr typeexpr
135  typeexpr = astNewCONSTi( tctype )
136  if( astNewARG( funcexpr, typeexpr ) = NULL ) then
137  exit function
138  end if
139 
140  '' push type info to the stack
141  if( tctype = FB_THREADCALL_STRUCT ) then
142  if( hThreadCallPushStruct( funcexpr, stype ) = FALSE ) then
143  exit function
144  end if
145  end if
146 
147  function = true
148 end function
149 
150 function hGetExprRef( byval expr as ASTNODE ptr ) as ASTNODE ptr
151  dim as FBSYMBOL ptr tmpvar = any, subtype = any
152  dim as integer dtype = any
153 
154  if( astIsVAR( expr ) ) then
155  '' already a variable? just get the address
156  '' @expr
157  function = astNewADDROF( expr )
158  else
159  '' copy expression to a variable, and get the address
160  tmpvar = symbAddTempVar( astGetDataType( expr ), astGetSubType( expr ) )
161 
162  '' tmpvar = expr
163  astAdd( astNewASSIGN( astNewVAR( tmpvar ), expr, AST_OPOPT_DONTCHKPTR ) )
164 
165  '' @tmpvar
166  function = astNewADDROF( astNewVAR( tmpvar ) )
167  end if
168 end function
169 
170 '':::::
171 function rtlThreadCall(byval callexpr as ASTNODE ptr) as ASTNODE ptr
172 
173  function = NULL
174 
175  dim as FBSYMBOL ptr proc, param
176  dim as ASTNODE ptr procmodeexpr
177  dim as ASTNODE ptr stacksizeexpr, argsexpr, ptrexpr
178 
179  proc = callexpr->sym
180 
181  '' copy off symbol and all the arguments
182  dim args as integer = callexpr->call.args
183  dim arg as ASTNODE ptr = callexpr->r
184  dim argupper as integer = iif( args=0, 1, args )
185  redim argexpr( 1 to argupper ) as ASTNODE ptr
186  redim argmode( 1 to argupper ) as integer
187  for i as integer = 1 to args
188  if arg = 0 then
189  exit function
190  end if
191  argexpr( args-i+1 ) = astCloneTREE( arg->l )
192  argmode( args-i+1 ) = arg->arg.mode
193  arg = arg->r
194  next i
195 
196  '' delete call
197  astDelTREE( callexpr )
198 
199  '' create new call
200  dim as ASTNODE ptr expr = astNewCall( PROCLOOKUP( THREADCALL ) )
201 
202  '' push function argument
203  if( astNewARG( expr, astBuildProcAddrOf( proc ) ) = NULL ) then
204  exit function
205  end if
206 
207  '' get calling convention
208  dim as integer procmode, procmode_fb
209  procmode_fb = symbGetProcMode( proc )
210  if procmode_fb = FB_FUNCMODE_FBCALL then procmode_fb = env.target.fbcall
211  if( procmode_fb = FB_FUNCMODE_CDECL ) then
212  procmode = FB_THREADCALL_CDECL
213  elseif( ((procmode_fb = FB_FUNCMODE_STDCALL) or _
214  (procmode_fb = FB_FUNCMODE_STDCALL_MS)) _
215  and env.clopt.target = FB_COMPTARGET_WIN32 ) then
216  procmode = FB_THREADCALL_STDCALL
217  else
218  errReport( FB_ERRMSG_UNSUPPORTEDFUNCTION )
219  exit function
220  end if
221 
222  '' push calling convention
223  procmodeexpr = astNewCONSTi( procmode )
224  if( astNewARG( expr, procmodeexpr ) = NULL ) then
225  exit function
226  end if
227 
228  '' push stack size (not in syntax)
229  stacksizeexpr = astNewCONSTi( 0 )
230  if( astNewARG( expr, stacksizeexpr ) = NULL ) then
231  exit function
232  end if
233 
234  '' push number of arguments
235  argsexpr = astNewCONSTi( args )
236  if( astNewARG( expr, argsexpr ) = NULL ) then
237  exit function
238  end if
239 
240  '' push each argument type
241  param = symbGetProcLastParam( proc )
242  for i as integer = 1 to args
243 
244  '' allow byval and byref
245  dim as FB_PARAMMODE mode
246  dim as integer tctype = -1
247  mode = symbGetParamMode( param )
248 
249  tctype = hThreadCallMapType( param )
250  select case mode
251  case FB_PARAMMODE_BYVAL
252  case FB_PARAMMODE_BYREF, FB_PARAMMODE_BYDESC
253  if( tctype <> -1 ) then
254  tctype = FB_THREADCALL_PTR
255  end if
256  case else
257  tctype = -1
258  end select
259 
260  '' push parameter type
261  dim as FBSYMBOL ptr stype = symbGetSubType( param )
262  if hThreadCallPushType( expr, tctype, stype ) = FALSE then
263  exit function
264  end if
265 
266  '' get pointer to argument
267  ptrexpr = hGetExprRef( argexpr( i ) )
268 
269  ''byref
270  dim isstring as integer
271  isstring = typeGetDtOnly( astGetDataType( argexpr( i ) ) )
272  if( mode = FB_PARAMMODE_BYREF and _
273  argmode( i ) <> FB_PARAMMODE_BYVAL and _
274  isstring = FALSE ) then
275  ptrexpr = hGetExprRef( ptrexpr )
276  end if
277 
278  if( ptrexpr = NULL ) then
279  exit function
280  end if
281 
282  '' push pointer to argument
283  if( astNewARG( expr, ptrexpr ) = NULL ) then
284  exit function
285  end if
286 
287  param = symbGetProcPrevParam( proc, param )
288  next
289 
290  function = expr
291 end function
292