【お知らせ】プログラミング記事の投稿はQiitaに移行しました。

F#でJIT

今までPythonC#やNode.jsでJITを実装しました。

今回はF#版です。C#版をほとんどそのまま焼き直しただけですが、それだけでは面白くないので、環境を判定して64bitにも対応しました。

open System.Runtime.InteropServices

[<DllImport("kernel32.dll", SetLastError = true)>]
extern nativeint VirtualAlloc(
    nativeint lpAddress, int dwSize,
    int flAllocationType, int flProtect)

[<DllImport("kernel32.dll", SetLastError = true)>]
extern bool VirtualFree(
    nativeint lpAddress, int dwSize, int dwFreeType)

let MEM_COMMIT = 0x1000
let MEM_RELEASE = 0x8000
let PAGE_EXECUTE_READWRITE = 0x40

let codes =
    Array.map (fun x -> byte x) <|
    if Marshal.SizeOf typeof<nativeint> = 4 then
        // 32bit i386
        [| 0x8b; 0x44; 0x24; 0x04;  // mov eax, [esp+4]
           0x03; 0x44; 0x24; 0x08;  // add eax, [esp+8]
           0xc3 |]                  // ret
    else
        // 64bit x86-64
        [| 0x89; 0xc8;              // mov eax, ecx
           0x01; 0xd0;              // add eax, edx
           0xc3 |]                  // ret

let buflen = codes.Length
let p = VirtualAlloc(nativeint 0, buflen,
                     MEM_COMMIT, PAGE_EXECUTE_READWRITE)
Marshal.Copy(codes, 0, p, buflen)

[<UnmanagedFunctionPointer(CallingConvention.Cdecl)>]
type Delg = delegate of int * int -> int
let f = Marshal.GetDelegateForFunctionPointer(
            p, typeof<Delg>) :?> Delg
printfn "f(1, 2) = %d" (f.Invoke(1, 2))

VirtualFree(p, 0, MEM_RELEASE)