File: CODE_SEG.ML

package info (click to toggle)
polyml 5.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 19,692 kB
  • ctags: 17,567
  • sloc: cpp: 37,221; sh: 9,591; asm: 4,120; ansic: 428; makefile: 203; ml: 191; awk: 91; sed: 10
file content (347 lines) | stat: -rw-r--r-- 11,825 bytes parent folder | download | duplicates (2)
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
(*
	Copyright (c) 2000
		Cambridge University Technical Services Limited

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.
	
	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.
	
	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*)

(*
    Title: 	Code vector operations.
    Author: 	Dave Matthews, Cambridge University Computer Laboratory
    Copyright   Cambridge University 1985
*)


(*
   This module constructs and operates on segments for machine code.
  "csegMake" constructs and returns a segment of the specified size with
  give flag codes.
  The segment can be read and written a byte at a time using the "csegGet"
  procedure, and the code can be entered using "csegCall" (this is only used
  if the code is an "early" procedure which must be called by the compiler
  or is a declaration or expression at the outer level. More usually
  "csegAddr" is used to return the address of the segment which is then
  compiled into another procedure as a constant.
  When a procedure has been compiled "csegLock" is called to remove the
  "mutable" bit. The segment then becomes a constant and cannot be
  changed.
  It is used in two ways. Initially the code is assembled into a segment which
  expands as necessary so that there is always room for the code. When the
  code has been completely assembled and we know how much there is, it is
  copied into a segment of the correct size. 
*)


structure CODE_SEG :
(*****************************************************************************)
(*                  CODESEG export signature                                 *)
(*****************************************************************************)
(* We use "int" rather than "short" for the indexes, to try to keep *)
(* the interface complexity in this module. SPF 14/7/94             *)
sig
  type machineWord;    (* added 14/7/94 SPF *)
  type short;   (* added 15/7/94 SPF *)
  type address; (* added 14/7/94 SPF *)
  type cseg;

  val csegMake:          int  -> cseg;
  val csegConvertToCode: cseg -> unit;
  val csegLock:          cseg -> unit;
  val csegGet:           cseg * int -> Word8.word;
  val csegSet:           cseg * int * Word8.word -> unit;
  val csegGetWord:       cseg * int -> machineWord;
  val csegPutWord:       cseg * int * machineWord -> unit;
  val csegCopySeg:       cseg * cseg * int * int -> unit;
  val csegAddr:          cseg -> address;
  val csegPutConstant:	 cseg * int * machineWord * 'a -> unit;
end = 

(*****************************************************************************)
(*                  CODESEG functor body                                     *)
(*****************************************************************************)
struct
  open Address;
  open Misc;
  
  datatype csegStatus =
    Bytes
  | UnlockedCode
  | LockedCode
  
  type cseg = (csegStatus * address) ref;
  
  fun objLength (a : address) : int = Word.toInt (length a);
  
  val expansionFactor = 3; (* Factor by which to increase size of segment *)

  val F_mutable_bytes = Word8.orb (F_mutable, F_bytes);
  val F_mutable_code  = Word8.orb (F_mutable, F_code);

  fun csegMake (size : int) : cseg =
  let
    val vec : address = alloc (toShort size, F_mutable_bytes, toMachineWord 0);
  in
    ref (Bytes, vec)
  end;

  fun csegConvertToCode (r as ref (Bytes, addr)) : unit = 
  let
    val U : unit = setFlags (addr, F_mutable_code);
  in
    r := (UnlockedCode, addr)
  end
   | csegConvertToCode _ = 
       raise InternalError "csegConvertToCode: not a byte segment";
        
  fun csegLock (r as ref (UnlockedCode, addr)) : unit = 
  let
    val U : unit = setFlags (addr, F_code);
  in
    r := (LockedCode, addr)
  end
   | csegLock _ = 
       raise InternalError "csegConvertToCode: not an unlocked code segment";
   
  fun csegAddr (ref (status, addr)) : address =
    if status = Bytes
    then raise InternalError "csegAddr: not a code segment"
    else addr;
    
  (* The old comment said:
        Copies the first "length" words from the start of "fromVec" to the
        "offset" words in "toVec".
     Which is right, except that it copies the first length BYTES, not words,
     even though "offset" is in words!
  *)
  fun csegCopySeg (ref (Bytes, fromAddr), ref (Bytes, toAddr), lengthBytes : int, offsetWords : int) =
  let
    val fromLengthWords : int = objLength fromAddr;
    val toLengthWords   : int = objLength toAddr;
    
    val fromLengthBytes : int = wordSize * fromLengthWords;
    val toLengthBytes   : int = wordSize * toLengthWords;
    val offsetBytes     : int = wordSize * offsetWords
 
    (* Copy the data a byte at a time (rather than a word) because the
       bytes copied might look like bad addresses.
       
       Note: this makes the rather rash assumption that we're copying
       the "code" part of the cseg, not the "constants" part, which *should*
       be copied a word at a time, since otherwise we could have a garbage
       collection while we're half-way through copying a pointer. We need
       to completely redesign this module to fix this problem. SPF 14/7/94.
       
       The redesign is that you shouldn't put ML constants into a codeseg
       without calling csegConvertToCode first. SPF 13/2/97
    *)
    fun copyBytes (fromPtr:int) (toPtr:int) =
      if fromPtr = lengthBytes then ()
      else let
        val byte = loadByte (fromAddr, toShort fromPtr);
      in
        assignByte (toAddr, toShort toPtr, byte);
        copyBytes (fromPtr + 1) (toPtr + 1)
      end
      
    (* must check:
         0 <= lengthBytes <= fromLengthBytes
         0 <= offsetWords
         offsetBytes + lengthBytes <= toLengthBytes
    *)  
    val maxOffsetBytes = toLengthBytes - lengthBytes;
  in
    (* Check the lengths are in the range. *)
    if lengthBytes < 0 orelse fromLengthBytes < lengthBytes 
    then let
      val msg = 
        concat
          [
            "csegCopySeg: Byte length ",
             Int.toString lengthBytes,
             " out of range 0..", 
             Int.toString fromLengthBytes
          ]
    in
      raise InternalError msg
    end
      
    else if offsetBytes < 0 orelse maxOffsetBytes < offsetBytes
    then let
      val msg = 
        concat
          [
            "csegCopySeg: Byte offset ",
             Int.toString offsetBytes,
             " out of range 0..",
             Int.toString maxOffsetBytes
          ]
    in
      raise InternalError msg
    end      
          
    else copyBytes 0 offsetBytes
  end

  | csegCopySeg _ =
    raise InternalError "csegCopySeg: can only copy between byte segements"
  
  (* Returns a value from the vector. *)
  fun csegGet (ref (status, addr), byteIndex : int) : Word8.word =
  let
    val lengthWords = objLength addr;
    val lengthBytes = wordSize * lengthWords;
  in
    if 0 <= byteIndex andalso byteIndex < lengthBytes
    then loadByte (addr, toShort byteIndex)
    else let
      val msg = 
        concat
          [
            "csegGet: Index ",
             Int.toString byteIndex,
             " out of range 0..", 
             Int.toString lengthBytes
          ]
    in
      raise InternalError msg
    end
  end;
       
  fun csegSet (ref (LockedCode, addr), byteIndex:int, value:Word8.word) : unit =
    raise InternalError "csegSet: can't change locked code segement"
   
    | csegSet (r as (ref (status, addr)), byteIndex:int, value:Word8.word) : unit =
  let
    val lengthWords : int = objLength addr;
    val lengthBytes : int = wordSize * lengthWords;
  in
    if byteIndex < 0
      then
      let
        val msg = concat
            [
                "csegSet: Index ",
                Int.toString byteIndex,
                " out of range 0..infinity" 
            ]
      in
        raise InternalError msg
      end
    
    else if byteIndex < lengthBytes then
      assignByte (addr, toShort byteIndex, value)
      
    else if status <> Bytes then
      raise InternalError "csegSet: can't extend code segment"
      
    else let (* length <= byteIndex; construct a new segment*)
      val oldSize : int = lengthWords; (* size in words *)
      val expSize : int = expansionFactor * oldSize;
      
      val wordIndex  : int = byteIndex div wordSize;
      val minSize    : int = wordIndex + 1;
      
      val newSize    : int = Int.max(expSize, minSize);
      
      (* create temporary codeseg (with larger byte-vector) *)
      val newVec = alloc (toShort newSize, F_bytes, toMachineWord 0);
      val newSeg = (Bytes, newVec);
    in
      (* copy the old code into the new codeseg *)
      csegCopySeg (r, ref newSeg, lengthBytes, 0);
      
      (* assign the byte to the new codeseg's byte-vector *)
      assignByte (newVec, toShort byteIndex, value);

      (* update the old segment to point at the new byte-vector *)
      r := newSeg
    end
  end;

  (* Puts in a word at a given word offset. Does not expand the segment. *)
  fun csegPutWord (ref (UnlockedCode, addr), wordIndex:int, value:machineWord) : unit =
  let
    val lengthWords : int = objLength addr;
  in
    if wordIndex < 0 orelse lengthWords <= wordIndex
    then let
      val msg = 
	concat
	  [
            "csegPutWord: Index ",
             Int.toString wordIndex,
             " out of range 0..", 
             Int.toString lengthWords
          ]
    in
      raise InternalError msg
    end
    else assignWord (addr, toShort wordIndex, value)
  end
    | csegPutWord _ =
        raise InternalError "csegPutWord: not an unlocked code segment"
  
  (* Gets a word at a given word offset. Does not expand the segment. *)
  fun csegGetWord (ref (status, addr), wordIndex : int) : machineWord =
  let
    val lengthWords : int = objLength addr;
  in
    if status = Bytes 
      then raise InternalError "csegGetWord: can't load a a word from a byte segment"
    else if wordIndex < 0 orelse lengthWords <= wordIndex
    then let
      val msg = 
	concat
	  [
            "csegGetWord: Index ",
             Int.toString wordIndex,
             " out of range 0..", 
             Int.toString lengthWords
          ]
    in
      raise InternalError msg
    end
    else loadWord (addr, toShort wordIndex)
  end;

  (* csegPutConstant: store a constant into the code.  Exactly how this is
     done is architecture dependent: on the i386 it's simply a store, on
	 other architectures the constant may have to be split between instructions.
	 This means that it has to be done by the RTS so as to be certain that
	 we don't have a garbage collection with an invalid address.  DCJM 2/1/01. *)
  fun csegPutConstant (ref (UnlockedCode, addr), byteIndex:int,
  					   value:machineWord, data: 'a) : unit =
  let
    val lengthWords : int = objLength addr;
    val lengthBytes : int = wordSize * lengthWords;
  in
    if byteIndex < 0 orelse lengthBytes <= byteIndex
    then let
      val msg = 
		concat
		  [
            "csegPutConstant: Index ", Int.toString byteIndex,
             " out of range 0..",  Int.toString lengthWords
          ]
    in
      raise InternalError msg
    end
    else RunCall.run_call4 RuntimeCalls.POLY_SYS_set_code_constant
			(addr, toShort byteIndex, value, data)
  end
    | csegPutConstant _ =
        raise InternalError "csegPutConstant: not an unlocked code segment"

end; (* CODE_SEG *)