]> gitweb.factorcode.org Git - factor.git/blob - vm/os-windows.cpp
Squashed commit of the following:
[factor.git] / vm / os-windows.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 HMODULE hFactorDll;
7
8 void factor_vm::init_ffi()
9 {
10         hFactorDll = GetModuleHandle(FACTOR_DLL);
11         if(!hFactorDll)
12                 fatal_error("GetModuleHandle() failed", 0);
13 }
14
15 void factor_vm::ffi_dlopen(dll *dll)
16 {
17         dll->handle = LoadLibraryEx((WCHAR *)alien_offset(dll->path), NULL, 0);
18 }
19
20 void *factor_vm::ffi_dlsym(dll *dll, symbol_char *symbol)
21 {
22         return (void *)GetProcAddress(dll ? (HMODULE)dll->handle : hFactorDll, symbol);
23 }
24
25 void factor_vm::ffi_dlclose(dll *dll)
26 {
27         FreeLibrary((HMODULE)dll->handle);
28         dll->handle = NULL;
29 }
30
31 BOOL factor_vm::windows_stat(vm_char *path)
32 {
33         BY_HANDLE_FILE_INFORMATION bhfi;
34         HANDLE h = CreateFileW(path,
35                         GENERIC_READ,
36                         FILE_SHARE_READ,
37                         NULL,
38                         OPEN_EXISTING,
39                         FILE_FLAG_BACKUP_SEMANTICS,
40                         NULL);
41
42         if(h == INVALID_HANDLE_VALUE)
43         {
44                 // FindFirstFile is the only call that can stat c:\pagefile.sys
45                 WIN32_FIND_DATA st;
46                 HANDLE h;
47
48                 if(INVALID_HANDLE_VALUE == (h = FindFirstFile(path, &st)))
49                         return false;
50                 FindClose(h);
51                 return true;
52         }
53         BOOL ret = GetFileInformationByHandle(h, &bhfi);
54         CloseHandle(h);
55         return ret;
56 }
57
58 void factor_vm::windows_image_path(vm_char *full_path, vm_char *temp_path, unsigned int length)
59 {
60         wcsncpy(temp_path, full_path, length - 1);
61         size_t full_path_len = wcslen(full_path);
62         if (full_path_len < length - 1)
63                 wcsncat(temp_path, L".image", length - full_path_len - 1);
64         temp_path[length - 1] = 0;
65 }
66
67 /* You must free() this yourself. */
68 const vm_char *factor_vm::default_image_path()
69 {
70         vm_char full_path[MAX_UNICODE_PATH];
71         vm_char *ptr;
72         vm_char temp_path[MAX_UNICODE_PATH];
73
74         if(!GetModuleFileName(NULL, full_path, MAX_UNICODE_PATH))
75                 fatal_error("GetModuleFileName() failed", 0);
76
77         if((ptr = wcsrchr(full_path, '.')))
78                 *ptr = 0;
79
80         wcsncpy(temp_path, full_path, MAX_UNICODE_PATH - 1);
81         size_t full_path_len = wcslen(full_path);
82         if (full_path_len < MAX_UNICODE_PATH - 1)
83                 wcsncat(temp_path, L".image", MAX_UNICODE_PATH - full_path_len - 1);
84         temp_path[MAX_UNICODE_PATH - 1] = 0;
85
86         return safe_strdup(temp_path);
87 }
88
89 /* You must free() this yourself. */
90 const vm_char *factor_vm::vm_executable_path()
91 {
92         vm_char full_path[MAX_UNICODE_PATH];
93         if(!GetModuleFileName(NULL, full_path, MAX_UNICODE_PATH))
94                 fatal_error("GetModuleFileName() failed", 0);
95         return safe_strdup(full_path);
96 }
97
98 void factor_vm::primitive_existsp()
99 {
100         vm_char *path = untag_check<byte_array>(ctx->pop())->data<vm_char>();
101         ctx->push(tag_boolean(windows_stat(path)));
102 }
103
104 segment::segment(cell size_, bool executable_p)
105 {
106         size = size_;
107
108         char *mem;
109         DWORD ignore;
110
111         if((mem = (char *)VirtualAlloc(NULL, getpagesize() * 2 + size,
112                 MEM_COMMIT, executable_p ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE)) == 0)
113                 out_of_memory();
114
115         if (!VirtualProtect(mem, getpagesize(), PAGE_NOACCESS, &ignore))
116                 fatal_error("Cannot allocate low guard page", (cell)mem);
117
118         if (!VirtualProtect(mem + size + getpagesize(),
119                 getpagesize(), PAGE_NOACCESS, &ignore))
120                 fatal_error("Cannot allocate high guard page", (cell)mem);
121
122         start = (cell)mem + getpagesize();
123         end = start + size;
124 }
125
126 segment::~segment()
127 {
128         SYSTEM_INFO si;
129         GetSystemInfo(&si);
130         if(!VirtualFree((void*)(start - si.dwPageSize), 0, MEM_RELEASE))
131                 fatal_error("Segment deallocation failed",0);
132 }
133
134 long getpagesize()
135 {
136         static long g_pagesize = 0;
137         if(!g_pagesize)
138         {
139                 SYSTEM_INFO system_info;
140                 GetSystemInfo (&system_info);
141                 g_pagesize = system_info.dwPageSize;
142         }
143         return g_pagesize;
144 }
145
146 void factor_vm::move_file(const vm_char *path1, const vm_char *path2)
147 {
148         if(MoveFileEx((path1),(path2),MOVEFILE_REPLACE_EXISTING) == false)
149                 general_error(ERROR_IO,tag_fixnum(GetLastError()),false_object);
150 }
151
152 void factor_vm::init_signals() {}
153
154 THREADHANDLE start_thread(void *(*start_routine)(void *), void *args)
155 {
156         return (void *)CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, args, 0, 0);
157 }
158
159 u64 nano_count()
160 {
161         static double scale_factor;
162
163         static u32 hi = 0;
164         static u32 lo = 0;
165
166         LARGE_INTEGER count;
167         BOOL ret = QueryPerformanceCounter(&count);
168         if(ret == 0)
169                 fatal_error("QueryPerformanceCounter", 0);
170
171         if(scale_factor == 0.0)
172         {
173                 LARGE_INTEGER frequency;
174                 BOOL ret = QueryPerformanceFrequency(&frequency);
175                 if(ret == 0)
176                         fatal_error("QueryPerformanceFrequency", 0);
177                 scale_factor = (1000000000.0 / frequency.QuadPart);
178         }
179
180 #ifdef FACTOR_64
181         hi = count.HighPart;
182 #else
183         /* On VirtualBox, QueryPerformanceCounter does not increment
184         the high part every time the low part overflows.  Workaround. */
185         if(lo > count.LowPart)
186                 hi++;
187 #endif
188         lo = count.LowPart;
189
190         return (u64)((((u64)hi << 32) | (u64)lo) * scale_factor);
191 }
192
193 void sleep_nanos(u64 nsec)
194 {
195         Sleep((DWORD)(nsec/1000000));
196 }
197
198 LONG factor_vm::exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c, void *dispatch)
199 {
200         c->ESP = (cell)fix_callstack_top((stack_frame *)c->ESP);
201         ctx->callstack_top = (stack_frame *)c->ESP;
202
203         switch (e->ExceptionCode)
204         {
205         case EXCEPTION_ACCESS_VIOLATION:
206                 signal_fault_addr = e->ExceptionInformation[1];
207                 c->EIP = (cell)factor::memory_signal_handler_impl;
208                 break;
209
210         case STATUS_FLOAT_DENORMAL_OPERAND:
211         case STATUS_FLOAT_DIVIDE_BY_ZERO:
212         case STATUS_FLOAT_INEXACT_RESULT:
213         case STATUS_FLOAT_INVALID_OPERATION:
214         case STATUS_FLOAT_OVERFLOW:
215         case STATUS_FLOAT_STACK_CHECK:
216         case STATUS_FLOAT_UNDERFLOW:
217         case STATUS_FLOAT_MULTIPLE_FAULTS:
218         case STATUS_FLOAT_MULTIPLE_TRAPS:
219 #ifdef FACTOR_64
220                 signal_fpu_status = fpu_status(MXCSR(c));
221 #else
222                 signal_fpu_status = fpu_status(X87SW(c) | MXCSR(c));
223
224                 /* This seems to have no effect */
225                 X87SW(c) = 0;
226 #endif
227                 MXCSR(c) &= 0xffffffc0;
228                 c->EIP = (cell)factor::fp_signal_handler_impl;
229                 break;
230         default:
231                 signal_number = e->ExceptionCode;
232                 c->EIP = (cell)factor::misc_signal_handler_impl;
233                 break;
234         }
235
236         return 0;
237 }
238
239 VM_C_API LONG exception_handler(PEXCEPTION_RECORD e, void *frame, PCONTEXT c, void *dispatch)
240 {
241         return current_vm()->exception_handler(e,frame,c,dispatch);
242 }
243
244 void factor_vm::open_console() {}
245
246 }