]> gitweb.factorcode.org Git - factor.git/blob - vm/os-windows.c
Windows SEH fix
[factor.git] / vm / os-windows.c
1 #include "factor.h"
2
3 /* frees memory allocated by win32 api calls */
4 char *buffer_to_char_string(char *buffer)
5 {
6         int capacity = strlen(buffer);
7         F_STRING *_c_str = allot_string(capacity / CHARS + 1);
8         u8 *c_str = (u8*)(_c_str + 1);
9         strcpy(c_str, buffer);
10         LocalFree(buffer);
11         return (char*)c_str;
12 }
13
14 F_STRING *get_error_message()
15 {
16         DWORD id = GetLastError();
17         return from_char_string(error_message(id));
18 }
19
20 char *error_message(DWORD id)
21 {
22         char *buffer;
23         int index;
24         
25         FormatMessage(
26                 FORMAT_MESSAGE_ALLOCATE_BUFFER |
27                 FORMAT_MESSAGE_FROM_SYSTEM,
28                 NULL,
29                 id,
30                 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
31                 (LPTSTR) &buffer,
32                 0, NULL);
33
34         /* strip whitespace from end */
35         index = strlen(buffer) - 1;
36         while(index >= 0 && isspace(buffer[index]))
37                 buffer[index--] = 0;
38         
39         return buffer_to_char_string(buffer);
40 }
41
42 s64 current_millis(void)
43 {
44         FILETIME t;
45         GetSystemTimeAsFileTime(&t);
46         return (((s64)t.dwLowDateTime | (s64)t.dwHighDateTime<<32) - EPOCH_OFFSET) 
47                 / 10000;
48 }
49
50 void ffi_dlopen (DLL *dll, bool error)
51 {
52         HMODULE module;
53         char *path = to_char_string(untag_string(dll->path),true);
54
55         module = LoadLibrary(path);
56
57         if (!module)
58         {
59                 dll->dll = NULL;
60                 if(error)
61                         general_error(ERROR_FFI, tag_object(get_error_message()),F,true);
62                 else
63                         return;
64         }
65
66         dll->dll = module;
67 }
68
69 void *ffi_dlsym (DLL *dll, F_STRING *symbol, bool error)
70 {
71         void *sym = GetProcAddress(dll ? (HMODULE)dll->dll : GetModuleHandle(NULL),
72                 to_char_string(symbol,true));
73
74         if (!sym)
75         {
76                 if(error)
77                         general_error(ERROR_FFI, tag_object(get_error_message()),F,true);
78                 else
79                         return NULL;
80         }
81
82         return sym;
83 }
84
85 void ffi_dlclose (DLL *dll)
86 {
87         FreeLibrary((HMODULE)dll->dll);
88         dll->dll = NULL;
89 }
90
91 void primitive_stat(void)
92 {
93         F_STRING *path;
94         WIN32_FILE_ATTRIBUTE_DATA st;
95
96         maybe_gc(0);
97         path = untag_string(dpop());
98
99         if(!GetFileAttributesEx(to_char_string(path,true), GetFileExInfoStandard, &st)) 
100         {
101                 dpush(F);
102         } 
103         else 
104         {
105                 CELL dirp = tag_boolean(st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
106                 CELL size = tag_bignum(s48_long_long_to_bignum(
107                         (s64)st.nFileSizeLow | (s64)st.nFileSizeHigh << 32));
108                 CELL mtime = tag_integer((int)
109                         ((*(s64*)&st.ftLastWriteTime - EPOCH_OFFSET) / 10000000));
110                 dpush(make_array_4(dirp,tag_fixnum(0),size,mtime));
111         }
112 }
113
114 void primitive_read_dir(void)
115 {
116         F_STRING *path;
117         HANDLE dir;
118         WIN32_FIND_DATA find_data;
119         F_ARRAY *result;
120         CELL result_count = 0;
121
122         maybe_gc(0);
123
124         result = array(ARRAY_TYPE,100,F);
125
126         path = untag_string(dpop());
127         if (INVALID_HANDLE_VALUE != (dir = FindFirstFile(".\\*", &find_data)))
128         {
129                 do
130                 {
131                         CELL name = tag_object(from_char_string(
132                                 find_data.cFileName));
133
134                         if(result_count == array_capacity(result))
135                         {
136                                 result = resize_array(result,
137                                         result_count * 2,F);
138                         }
139                         
140                         put(AREF(result,result_count),name);
141                         result_count++;
142                 } 
143                 while (FindNextFile(dir, &find_data));
144                 CloseHandle(dir);
145         }
146
147         result = resize_array(result,result_count,F);
148
149         dpush(tag_object(result));
150 }
151
152 void primitive_cwd(void)
153 {
154         char buf[MAX_PATH];
155
156         maybe_gc(0);
157         if(!GetCurrentDirectory(MAX_PATH, buf))
158                 io_error();
159
160         box_char_string(buf);
161 }
162
163 void primitive_cd(void)
164 {
165         maybe_gc(0);
166         SetCurrentDirectory(unbox_char_string());
167 }
168
169 BOUNDED_BLOCK *alloc_bounded_block(CELL size)
170 {
171         SYSTEM_INFO si;
172         char *mem;
173         DWORD ignore;
174
175         GetSystemInfo(&si);
176         if((mem = (char *)VirtualAlloc(NULL, si.dwPageSize*2 + size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == 0)
177                 fatal_error("VirtualAlloc() failed in alloc_bounded_block()",0);
178
179         if (!VirtualProtect(mem, si.dwPageSize, PAGE_NOACCESS, &ignore))
180                 fatal_error("Cannot allocate low guard page", (CELL)mem);
181
182         if (!VirtualProtect(mem+size+si.dwPageSize, si.dwPageSize, PAGE_NOACCESS, &ignore))
183                 fatal_error("Cannot allocate high guard page", (CELL)mem);
184
185         BOUNDED_BLOCK *block = safe_malloc(sizeof(BOUNDED_BLOCK));
186
187         block->start = (int)mem + si.dwPageSize;
188         block->size = size;
189
190         return block;
191 }
192
193 void dealloc_bounded_block(BOUNDED_BLOCK *block)
194 {
195         SYSTEM_INFO si;
196         GetSystemInfo(&si);
197         if(!VirtualFree((void*)(block->start - si.dwPageSize), 0, MEM_RELEASE))
198                 fatal_error("VirtualFree() failed",0);
199         free(block);
200 }
201
202 long getpagesize (void)
203 {
204         static long g_pagesize = 0;
205         if (! g_pagesize)
206         {
207                 SYSTEM_INFO system_info;
208                 GetSystemInfo (&system_info);
209                 g_pagesize = system_info.dwPageSize;
210         }
211         return g_pagesize;
212 }
213
214 const char *default_image_path(void)
215 {
216         return "factor.image";
217 }
218
219 /* SEH support. Proceed with caution. */
220 typedef long exception_handler_t(
221         PEXCEPTION_RECORD rec, void *frame, void *context, void *dispatch);
222
223 typedef struct exception_record
224 {
225         struct exception_record *next_handler;
226         void *handler_func;
227 } exception_record_t;
228
229 void seh_call(void (*func)(), exception_handler_t *handler)
230 {
231         exception_record_t record;
232         asm("mov %%fs:0, %0" : "=r" (record.next_handler));
233         asm("mov %0, %%fs:0" : : "r" (&record));
234         record.handler_func = handler;
235         func();
236         asm("mov %0, %%fs:0" : "=r" (record.next_handler));
237 }
238
239 static long exception_handler(PEXCEPTION_RECORD rec, void *frame, void *ctx, void *dispatch)
240 {
241         memory_protection_error((void*)rec->ExceptionInformation[1], SIGSEGV);
242         return -1; /* unreachable */
243 }
244
245 void run(void)
246 {
247         interpreter();
248 }
249
250 void run_toplevel(void)
251 {
252         seh_call(run, exception_handler);
253 }