FreeBASIC  0.91.0
ast-node-check.bas
Go to the documentation of this file.
1 '' AST bound and null-pointer checking nodes
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 
5 
6 #include once "fb.bi"
7 #include once "fbint.bi"
8 #include once "ir.bi"
9 #include once "rtl.bi"
10 #include once "ast.bi"
11 #include once "lex.bi"
12 
13 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
14 '' Bounds checking (l = index; r = call to checking func(lb, ub))
15 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
16 
17 function astNewBOUNDCHK _
18  ( _
19  byval l as ASTNODE ptr, _
20  byval lb as ASTNODE ptr, _
21  byval ub as ASTNODE ptr, _
22  byval linenum as integer, _
23  byval filename as zstring ptr _
24  ) as ASTNODE ptr
25 
26  dim as ASTNODE ptr n = any
27 
28  '' If one of lbound/ubound is CONST, the other should be too -- either
29  '' both are known at compile-time, or neither is.
30  assert( astIsCONST( lb ) = astIsCONST( ub ) )
31 
32  '' CONST l/ubound?
33  if( astIsCONST( lb ) ) then
34  '' CONST index?
35  if( astIsCONST( l ) ) then
36  '' i < lbound?
37  if( astConstGetInt( l ) < astConstGetInt( lb ) ) then
38  return NULL
39  end if
40  '' i > ubound?
41  if( astConstGetInt( l ) > astConstGetInt( ub ) ) then
42  return NULL
43  end if
44 
45  astDelNode( lb )
46  astDelNode( ub )
47  return l
48  end if
49 
50  '' 0? Delete it so rtlArrayBoundsCheck() will use fb_ArraySngBoundChk()
51  if( astConstGetInt( lb ) = 0 ) then
52  astDelNode( lb )
53  lb = NULL
54  end if
55  end if
56 
57  '' alloc new node
58  n = astNewNode( AST_NODECLASS_BOUNDCHK, l->dtype, l->subtype )
59  function = n
60 
61  n->l = l
62 
63  n->sym = symbAddTempVar( l->dtype, l->subtype )
64 
65  '' check must be done using a function because calling ErrorThrow
66  '' would spill used regs only if it was called, causing wrong
67  '' assumptions after the branches
68  n->r = rtlArrayBoundsCheck( astNewVAR( n->sym ), lb, ub, linenum, filename )
69 
70 end function
71 
72 '':::::
73 function astLoadBOUNDCHK _
74  ( _
75  byval n as ASTNODE ptr _
76  ) as IRVREG ptr
77 
78  dim as ASTNODE ptr l = any, r = any, t = any
79  dim as FBSYMBOL ptr label = any
80  dim as IRVREG ptr vr = any
81 
82  l = n->l
83  r = n->r
84 
85  if( (l = NULL) or (r = NULL) ) then
86  return NULL
87  end if
88 
89  '' assign to a temp, can't reuse the same vreg or registers could
90  '' be spilled as IR can't handle inter-blocks
91  t = astNewASSIGN( astNewVAR( n->sym ), l )
92  astLoad( t )
93  astDelNode( t )
94 
95  vr = astLoad( r )
96  astDelNode( r )
97 
98  if( ast.doemit ) then
99  '' handler = boundchk( ... ): if handler <> NULL then handler( )
100  label = symbAddLabel( NULL )
101  irEmitBOP( AST_OP_EQ, _
102  vr, _
103  irAllocVRIMM( FB_DATATYPE_INTEGER, NULL, 0 ), _
104  NULL, _
105  label )
106  irEmitJUMPPTR( vr )
107  irEmitLABELNF( label )
108  end if
109 
110  ''
111  '' re-load, see above
112  t = astNewVAR( n->sym )
113  function = astLoad( t )
114  astDelNode( t )
115 
116 end function
117 
118 function astBuildBOUNDCHK _
119  ( _
120  byval expr as ASTNODE ptr, _
121  byval lb as ASTNODE ptr, _
122  byval ub as ASTNODE ptr _
123  ) as ASTNODE ptr
124  function = astNewBOUNDCHK( expr, lb, ub, lexLineNum( ), env.inf.name )
125 end function
126 
127 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
128 '' null pointer checking (l = index; r = call to checking func)
129 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
130 
131 function astNewPTRCHK _
132  ( _
133  byval l as ASTNODE ptr, _
134  byval linenum as integer, _
135  byval filename as zstring ptr _
136  ) as ASTNODE ptr
137 
138  dim as ASTNODE ptr n = any
139  dim as integer dtype = any
140  dim as FBSYMBOL ptr subtype = any
141 
142  '' constant? don't break OffsetOf() when used with Const's..
143  if( l->class = AST_NODECLASS_CONST ) then
144  return l
145  end if
146 
147  '' alloc new node
148  dtype = astGetFullType( l )
149  subtype = l->subtype
150  n = astNewNode( AST_NODECLASS_PTRCHK, dtype, subtype )
151  function = n
152 
153  n->l = l
154 
155  n->sym = symbAddTempVar( dtype, subtype )
156 
157  '' check must be done using a function, see bounds checking
158  n->r = rtlNullPtrCheck( astNewVAR( n->sym ), linenum, filename )
159 
160 end function
161 
162 '':::::
163 function astLoadPTRCHK _
164  ( _
165  byval n as ASTNODE ptr _
166  ) as IRVREG ptr
167 
168  dim as ASTNODE ptr l = any, r = any, t = any
169  dim as FBSYMBOL ptr label = any
170  dim as IRVREG ptr vr = any
171 
172  l = n->l
173  r = n->r
174 
175  if( (l = NULL) or (r = NULL) ) then
176  return NULL
177  end if
178 
179  '' assign to a temp, can't reuse the same vreg or registers could
180  '' be spilled as IR can't handle inter-blocks
181  t = astNewASSIGN( astNewVAR( n->sym ), l )
182  astLoad( t )
183  astDelNode( t )
184 
185  ''
186  vr = astLoad( r )
187  astDelNode( r )
188 
189  if( ast.doemit ) then
190  '' handler = ptrchk( ... ): if handler <> NULL then handler( )
191  label = symbAddLabel( NULL )
192  irEmitBOP( AST_OP_EQ, _
193  vr, _
194  irAllocVRIMM( FB_DATATYPE_INTEGER, NULL, 0 ), _
195  NULL, _
196  label )
197  irEmitJUMPPTR( vr )
198  irEmitLABELNF( label )
199  end if
200 
201  '' re-load, see above
202  t = astNewVAR( n->sym )
203  function = astLoad( t )
204  astDelNode( t )
205 
206 end function
207 
208 function astBuildPTRCHK( byval expr as ASTNODE ptr ) as ASTNODE ptr
209  function = astNewPTRCHK( expr, lexLineNum( ), env.inf.name )
210 end function
211