jitcraft/Platform-Windows.cpp
author David Anderson <dvander@alliedmods.net>
Sat Jul 07 21:30:23 2012 -0700 (2012-07-07)
changeset 59 b7d61ddb3c8d
parent 53 13bd3a8df334
child 69 dfce0539a77d
permissions -rw-r--r--
Rename jc:: to ke::
dvander@28
     1
/* vim: set ts=4 sw=4 tw=99 et:
dvander@28
     2
 *
dvander@28
     3
 * Copyright (C) 2012 David Anderson
dvander@28
     4
 *
dvander@28
     5
 * This file is part of JITCraft.
dvander@28
     6
 *
dvander@28
     7
 * JITCraft is free software: you can redistribute it and/or modify it under
dvander@28
     8
 * the terms of the GNU General Public License as published by the Free
dvander@28
     9
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@28
    10
 * any later version.
dvander@28
    11
 * 
dvander@28
    12
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@28
    13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@28
    14
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@28
    15
 *
dvander@28
    16
 * You should have received a copy of the GNU General Public License along with
dvander@28
    17
 * JITCraft. If not, see http://www.gnu.org/licenses/.
dvander@11
    18
 */
dvander@11
    19
dvander@11
    20
// :TODO: move into utility-style include
dvander@11
    21
#define WIN32_LEAN_AND_MEAN
dvander@11
    22
#include <Windows.h>
dvander@11
    23
#include "Platform.h"
dvander@11
    24
dvander@59
    25
using namespace ke;
dvander@11
    26
dvander@11
    27
static inline DWORD
dvander@11
    28
ToProtBits(OS::Protection prot)
dvander@11
    29
{
dvander@11
    30
    switch (prot) {
dvander@28
    31
      case OS::Prot_ReadWrite:
dvander@11
    32
        return PAGE_READWRITE;
dvander@11
    33
      case OS::Prot_ReadWriteExecute:
dvander@11
    34
        return PAGE_EXECUTE_READWRITE;
dvander@11
    35
      default:
dvander@11
    36
        assert(prot == OS::Prot_ReadExecute);
dvander@11
    37
        return PAGE_EXECUTE_READ;
dvander@11
    38
    }
dvander@11
    39
}
dvander@11
    40
dvander@11
    41
Address
dvander@11
    42
OS::MapMemory(size_t amount, MapMode mode, Protection prot_)
dvander@11
    43
{
dvander@11
    44
    DWORD prot = ToProtBits(prot_);
dvander@11
    45
    DWORD type = MEM_RESERVE;
dvander@11
    46
    if (mode == Map_Commit)
dvander@11
    47
        type |= MEM_COMMIT;
dvander@11
    48
dvander@11
    49
    return (Address)VirtualAlloc(NULL, amount, type, prot);
dvander@11
    50
}
dvander@11
    51
dvander@11
    52
bool
dvander@11
    53
OS::CommitMemory(Address address, size_t amount, Protection prot_)
dvander@11
    54
{
dvander@11
    55
    DWORD prot = ToProtBits(prot_);
dvander@11
    56
    return !!VirtualAlloc(address, amount, MEM_COMMIT, prot);
dvander@11
    57
}
dvander@11
    58
dvander@11
    59
void
dvander@11
    60
OS::UnmapMemory(Address address, size_t size)
dvander@11
    61
{
dvander@11
    62
    VirtualFree(address, 0, MEM_RELEASE);
dvander@11
    63
}
dvander@11
    64
dvander@28
    65
static Address
dvander@53
    66
MapMemoryAt(Address address, size_t amount, OS::MapMode mode, OS::Protection prot_)
dvander@28
    67
{
dvander@28
    68
    DWORD bits = ToProtBits(prot_);
dvander@28
    69
    DWORD flags = MEM_RESERVE;
dvander@53
    70
    if (mode == OS::Map_Commit)
dvander@28
    71
        flags |= MEM_COMMIT;
dvander@28
    72
dvander@28
    73
    Address x = (Address)VirtualAlloc((LPVOID)address, amount, flags, bits);
dvander@28
    74
    if (!x) {
dvander@28
    75
        DWORD err = GetLastError();
dvander@28
    76
        return x;
dvander@28
    77
    }
dvander@28
    78
    return x;
dvander@28
    79
}
dvander@28
    80
dvander@11
    81
OS::AlignableMapping
dvander@11
    82
OS::MapAlignedMemory(size_t amount, size_t alignment, MapMode mode)
dvander@11
    83
{
dvander@11
    84
    Address addr = MapMemory(amount, mode, OS::Prot_ReadWrite);
dvander@11
    85
    if (!addr)
dvander@11
    86
        return AlignableMapping(NULL, alignment, 0);
dvander@11
    87
dvander@11
    88
    if (!IsAligned(addr, alignment)) {
dvander@11
    89
        UnmapMemory(addr, amount);
dvander@11
    90
dvander@11
    91
        // Try to grab the next available aligned address.
dvander@11
    92
        addr = AlignedBase(addr, alignment);
dvander@11
    93
        addr = MapMemoryAt(addr + alignment, amount, mode, OS::Prot_ReadWrite);
dvander@11
    94
        while (!addr) {
dvander@11
    95
            // Try to over-allocate to get the right region. This can race
dvander@11
    96
            // with other threads; we expect this to be rare. If this turns
dvander@11
    97
            // out to be a problem, the API is set up such that we can just
dvander@11
    98
            // return two pointers: the base, and the aligned address into
dvander@11
    99
            // the over-allocated region.
dvander@11
   100
            addr = MapMemory(amount + alignment, mode, OS::Prot_ReadWrite);
dvander@11
   101
            if (!addr)
dvander@11
   102
                return AlignableMapping(NULL, alignment, 0);
dvander@11
   103
            UnmapMemory(addr, amount + alignment);
dvander@11
   104
            addr = AlignedBase(addr, alignment);
dvander@11
   105
            addr = MapMemoryAt(addr + alignment, amount, mode, OS::Prot_ReadWrite);
dvander@11
   106
        }
dvander@11
   107
    }
dvander@11
   108
dvander@11
   109
    return AlignableMapping(addr, alignment, amount);
dvander@11
   110
}
dvander@11
   111
dvander@11
   112
void
dvander@11
   113
OS::UnmapAlignedMemory(Address address, size_t size)
dvander@11
   114
{
dvander@11
   115
    OS::UnmapMemory(address, size);
dvander@11
   116
}