> My main focus has been on adding small bits of code to
> asmcomp/cmmgen.ml for the new functionality. Two of the new
> primitives (Pregionrefs and Pregionsets) need to check the protection
> bits recorded for the region before trying to access it, and somehow
> raise an exception if the access check fails.
>
> I'm currently using the following kludge to make bad region access
> checks fail:
>
> let region_checkaccess exp = function
> | Reg_Read ->
> Cifthenelse(
> Cop(Cand, [region_prot exp; Cconst_int 1]),
> Cconst_pointer 1,
> Cop(Ccheckbound, [Cconst_int 0; Cconst_int 0]))
> | Reg_Write ->
> Cifthenelse(
> Cop(Cand, [region_prot exp; Cconst_int 2]),
> Cconst_pointer 1,
> Cop(Ccheckbound, [Cconst_int 0; Cconst_int 0]))
> (* XXX Bounds check on 0 is a kludge to force exception *)
>
> Is there a better way for me to cause an exception to be thrown at
> this point? Do I need to fall back to a Cextcall to ask someone to
> throw an exception for me? Or could (and should) I actually use
> Craise with arcane knowledge that a certain exception maps to a
> certain integer value?
Using a "checkbound" is perhaps the simplest solution. Otherwise,
some system-wide exceptions such as Invalid_argument are assigned
global symbols and you don't need to guess their integer index inside
their defining module: just emit the C-- code corresponding to
(raise (symbol "Invalid_argument") (string "my message"))
If you're really into high-performance stuff, you could fold the
permission check and the bounds check in one "checkbound" instruction.
Just arrange the "write enable" flag to be (the Caml integer) 0 if
write is allowed, and -1 if it is not. Then, generate something like
(checkbound (or index (write_enable_flag region) (size region)))
Although hacking cmmgen.ml is fun, you could get a more portable
implementation by writing it in ML using unsafe string accesses.
Those will happily work on any char *, not necessarily on well-formed
Caml strings. Something like:
external mmap : ... -> string
type t = { data: string; length: int }
let read_char reg idx =
if idx < 0 || idx >= reg.length
then raise (Invalid_argument "Region.read_char")
else String.unsafe_get reg.data idx
It will be a bit slower, but maybe not too much.
- Xavier Leroy