Mercurial > projects > ldc
comparison druntime/src/compiler/ldc/dmain2.d @ 1458:e0b2d67cfe7c
Added druntime (this should be removed once it works).
author | Robert Clipsham <robert@octarineparrot.com> |
---|---|
date | Tue, 02 Jun 2009 17:43:06 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1456:7b218ec1044f | 1458:e0b2d67cfe7c |
---|---|
1 /** | |
2 * Contains main program entry point and support routines. | |
3 * | |
4 * Copyright: Copyright Digital Mars 2000 - 2009. | |
5 * License: <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>. | |
6 * Authors: Walter Bright, Sean Kelly | |
7 * | |
8 * Copyright Digital Mars 2000 - 2009. | |
9 * Distributed under the Boost Software License, Version 1.0. | |
10 * (See accompanying file LICENSE_1_0.txt or copy at | |
11 * http://www.boost.org/LICENSE_1_0.txt) | |
12 */ | |
13 module rt.dmain2; | |
14 | |
15 private | |
16 { | |
17 import rt.memory; | |
18 import rt.util.console; | |
19 import core.stdc.stddef; | |
20 import core.stdc.stdlib; | |
21 import core.stdc.string; | |
22 } | |
23 | |
24 version (Windows) | |
25 { | |
26 private import core.stdc.wchar_; | |
27 | |
28 extern (Windows) alias int function() FARPROC; | |
29 extern (Windows) FARPROC GetProcAddress(void*, in char*); | |
30 extern (Windows) void* LoadLibraryA(in char*); | |
31 extern (Windows) int FreeLibrary(void*); | |
32 extern (Windows) void* LocalFree(void*); | |
33 extern (Windows) wchar_t* GetCommandLineW(); | |
34 extern (Windows) wchar_t** CommandLineToArgvW(wchar_t*, int*); | |
35 extern (Windows) export int WideCharToMultiByte(uint, uint, wchar_t*, int, char*, int, char*, int); | |
36 pragma(lib, "shell32.lib"); // needed for CommandLineToArgvW | |
37 } | |
38 | |
39 extern (C) void _STI_monitor_staticctor(); | |
40 extern (C) void _STD_monitor_staticdtor(); | |
41 extern (C) void _STI_critical_init(); | |
42 extern (C) void _STD_critical_term(); | |
43 extern (C) void gc_init(); | |
44 extern (C) void gc_term(); | |
45 extern (C) void _minit(); | |
46 extern (C) void _moduleCtor(); | |
47 extern (C) void _moduleDtor(); | |
48 extern (C) void thread_joinAll(); | |
49 | |
50 version (OSX) | |
51 { | |
52 // The bottom of the stack | |
53 extern (C) void* __osx_stack_end = cast(void*)0xC0000000; | |
54 } | |
55 | |
56 /*********************************** | |
57 * These are a temporary means of providing a GC hook for DLL use. They may be | |
58 * replaced with some other similar functionality later. | |
59 */ | |
60 extern (C) | |
61 { | |
62 void* gc_getProxy(); | |
63 void gc_setProxy(void* p); | |
64 void gc_clrProxy(); | |
65 | |
66 alias void* function() gcGetFn; | |
67 alias void function(void*) gcSetFn; | |
68 alias void function() gcClrFn; | |
69 } | |
70 | |
71 extern (C) void* rt_loadLibrary(in char[] name) | |
72 { | |
73 version (Windows) | |
74 { | |
75 char[260] temp = void; | |
76 temp[0 .. name.length] = name[]; | |
77 temp[name.length] = cast(char) 0; | |
78 void* ptr = LoadLibraryA(temp.ptr); | |
79 if (ptr is null) | |
80 return ptr; | |
81 gcSetFn gcSet = cast(gcSetFn) GetProcAddress(ptr, "gc_setProxy"); | |
82 if (gcSet !is null) | |
83 gcSet(gc_getProxy()); | |
84 return ptr; | |
85 | |
86 } | |
87 else version (Posix) | |
88 { | |
89 throw new Exception("rt_loadLibrary not yet implemented on Posix."); | |
90 } | |
91 } | |
92 | |
93 extern (C) bool rt_unloadLibrary(void* ptr) | |
94 { | |
95 version (Windows) | |
96 { | |
97 gcClrFn gcClr = cast(gcClrFn) GetProcAddress(ptr, "gc_clrProxy"); | |
98 if (gcClr !is null) | |
99 gcClr(); | |
100 return FreeLibrary(ptr) != 0; | |
101 } | |
102 else version (Posix) | |
103 { | |
104 throw new Exception("rt_unloadLibrary not yet implemented on Posix."); | |
105 } | |
106 } | |
107 | |
108 /*********************************** | |
109 * These functions must be defined for any D program linked | |
110 * against this library. | |
111 */ | |
112 extern (C) void onAssertError(string file, size_t line); | |
113 extern (C) void onAssertErrorMsg(string file, size_t line, string msg); | |
114 extern (C) void onRangeError(string file, size_t line); | |
115 extern (C) void onHiddenFuncError(Object o); | |
116 extern (C) void onSwitchError(string file, size_t line); | |
117 extern (C) bool runModuleUnitTests(); | |
118 | |
119 // this function is called from the utf module | |
120 //extern (C) void onUnicodeError(string msg, size_t idx); | |
121 | |
122 /*********************************** | |
123 * These are internal callbacks for various language errors. | |
124 */ | |
125 extern (C) void _d_assert(string file, uint line) | |
126 { | |
127 onAssertError(file, line); | |
128 } | |
129 | |
130 extern (C) static void _d_assert_msg(string msg, string file, uint line) | |
131 { | |
132 onAssertErrorMsg(file, line, msg); | |
133 } | |
134 | |
135 extern (C) void _d_array_bounds(string file, uint line) | |
136 { | |
137 onRangeError(file, line); | |
138 } | |
139 | |
140 extern (C) void _d_switch_error(string file, uint line) | |
141 { | |
142 onSwitchError(file, line); | |
143 } | |
144 | |
145 extern (C) void _d_hidden_func() | |
146 { | |
147 Object o; | |
148 asm | |
149 { | |
150 mov o, EAX; | |
151 } | |
152 onHiddenFuncError(o); | |
153 } | |
154 | |
155 shared bool _d_isHalting = false; | |
156 | |
157 extern (C) bool rt_isHalting() | |
158 { | |
159 return _d_isHalting; | |
160 } | |
161 | |
162 extern (C) shared bool rt_trapExceptions = true; | |
163 | |
164 void _d_criticalInit() | |
165 { | |
166 version (Posix) | |
167 { | |
168 _STI_monitor_staticctor(); | |
169 _STI_critical_init(); | |
170 } | |
171 } | |
172 | |
173 alias void delegate(Throwable) ExceptionHandler; | |
174 | |
175 extern (C) bool rt_init(ExceptionHandler dg = null) | |
176 { | |
177 _d_criticalInit(); | |
178 | |
179 try | |
180 { | |
181 gc_init(); | |
182 initStaticDataGC(); | |
183 version (Windows) | |
184 _minit(); | |
185 _moduleCtor(); | |
186 runModuleUnitTests(); | |
187 return true; | |
188 } | |
189 catch (Throwable e) | |
190 { | |
191 if (dg) | |
192 dg(e); | |
193 } | |
194 catch | |
195 { | |
196 | |
197 } | |
198 _d_criticalTerm(); | |
199 return false; | |
200 } | |
201 | |
202 void _d_criticalTerm() | |
203 { | |
204 version (Posix) | |
205 { | |
206 _STD_critical_term(); | |
207 _STD_monitor_staticdtor(); | |
208 } | |
209 } | |
210 | |
211 extern (C) bool rt_term(ExceptionHandler dg = null) | |
212 { | |
213 try | |
214 { | |
215 thread_joinAll(); | |
216 _d_isHalting = true; | |
217 _moduleDtor(); | |
218 gc_term(); | |
219 return true; | |
220 } | |
221 catch (Throwable e) | |
222 { | |
223 if (dg) | |
224 dg(e); | |
225 } | |
226 catch | |
227 { | |
228 | |
229 } | |
230 finally | |
231 { | |
232 _d_criticalTerm(); | |
233 } | |
234 return false; | |
235 } | |
236 | |
237 /*********************************** | |
238 * The D main() function supplied by the user's program | |
239 */ | |
240 int main(char[][] args); | |
241 | |
242 /*********************************** | |
243 * Substitutes for the C main() function. | |
244 * It's purpose is to wrap the call to the D main() | |
245 * function and catch any unhandled exceptions. | |
246 */ | |
247 | |
248 extern (C) int main(int argc, char **argv) | |
249 { | |
250 char[][] args; | |
251 int result; | |
252 | |
253 version (OSX) | |
254 { /* OSX does not provide a way to get at the top of the | |
255 * stack, except for the magic value 0xC0000000. | |
256 * But as far as the gc is concerned, argv is at the top | |
257 * of the main thread's stack, so save the address of that. | |
258 */ | |
259 __osx_stack_end = cast(void*)&argv; | |
260 } | |
261 | |
262 version (Posix) | |
263 { | |
264 _STI_monitor_staticctor(); | |
265 _STI_critical_init(); | |
266 } | |
267 | |
268 version (Windows) | |
269 { | |
270 wchar_t* wcbuf = GetCommandLineW(); | |
271 size_t wclen = wcslen(wcbuf); | |
272 int wargc = 0; | |
273 wchar_t** wargs = CommandLineToArgvW(wcbuf, &wargc); | |
274 assert(wargc == argc); | |
275 | |
276 char* cargp = null; | |
277 size_t cargl = WideCharToMultiByte(65001, 0, wcbuf, wclen, null, 0, null, 0); | |
278 | |
279 cargp = cast(char*) alloca(cargl); | |
280 args = ((cast(char[]*) alloca(wargc * (char[]).sizeof)))[0 .. wargc]; | |
281 | |
282 for (size_t i = 0, p = 0; i < wargc; i++) | |
283 { | |
284 int wlen = wcslen(wargs[i]); | |
285 int clen = WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, null, 0, null, 0); | |
286 args[i] = cargp[p .. p+clen]; | |
287 p += clen; assert(p <= cargl); | |
288 WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, &args[i][0], clen, null, 0); | |
289 } | |
290 LocalFree(wargs); | |
291 wargs = null; | |
292 wargc = 0; | |
293 } | |
294 else version (Posix) | |
295 { | |
296 char[]* am = cast(char[]*) malloc(argc * (char[]).sizeof); | |
297 scope(exit) free(am); | |
298 | |
299 for (size_t i = 0; i < argc; i++) | |
300 { | |
301 auto len = strlen(argv[i]); | |
302 am[i] = argv[i][0 .. len]; | |
303 } | |
304 args = am[0 .. argc]; | |
305 } | |
306 | |
307 bool trapExceptions = rt_trapExceptions; | |
308 | |
309 void tryExec(scope void delegate() dg) | |
310 { | |
311 | |
312 if (trapExceptions) | |
313 { | |
314 try | |
315 { | |
316 dg(); | |
317 } | |
318 catch (Throwable e) | |
319 { | |
320 while (e) | |
321 { | |
322 if (e.file) | |
323 { | |
324 // fprintf(stderr, "%.*s(%u): %.*s\n", e.file, e.line, e.msg); | |
325 console (e.classinfo.name)("@")(e.file)("(")(e.line)("): ")(e.msg)("\n"); | |
326 } | |
327 else | |
328 { | |
329 // fprintf(stderr, "%.*s\n", e.toString()); | |
330 console (e.toString)("\n"); | |
331 } | |
332 if (e.info) | |
333 { | |
334 console ("----------------\n"); | |
335 foreach (t; e.info) | |
336 console (t)("\n"); | |
337 } | |
338 if (e.next) | |
339 console ("\n"); | |
340 e = e.next; | |
341 } | |
342 result = EXIT_FAILURE; | |
343 } | |
344 catch (Object o) | |
345 { | |
346 // fprintf(stderr, "%.*s\n", o.toString()); | |
347 console (o.toString)("\n"); | |
348 result = EXIT_FAILURE; | |
349 } | |
350 } | |
351 else | |
352 { | |
353 dg(); | |
354 } | |
355 } | |
356 | |
357 // NOTE: The lifetime of a process is much like the lifetime of an object: | |
358 // it is initialized, then used, then destroyed. If initialization | |
359 // fails, the successive two steps are never reached. However, if | |
360 // initialization succeeds, then cleanup will occur even if the use | |
361 // step fails in some way. Here, the use phase consists of running | |
362 // the user's main function. If main terminates with an exception, | |
363 // the exception is handled and then cleanup begins. An exception | |
364 // thrown during cleanup, however, will abort the cleanup process. | |
365 | |
366 void runMain() | |
367 { | |
368 result = main(args); | |
369 } | |
370 | |
371 void runAll() | |
372 { | |
373 gc_init(); | |
374 initStaticDataGC(); | |
375 version (Windows) | |
376 _minit(); | |
377 _moduleCtor(); | |
378 if (runModuleUnitTests()) | |
379 tryExec(&runMain); | |
380 thread_joinAll(); | |
381 _d_isHalting = true; | |
382 _moduleDtor(); | |
383 gc_term(); | |
384 } | |
385 | |
386 tryExec(&runAll); | |
387 | |
388 version (Posix) | |
389 { | |
390 _STD_critical_term(); | |
391 _STD_monitor_staticdtor(); | |
392 } | |
393 return result; | |
394 } |