/** * Contains druntime startup and shutdown routines. * * Copyright: Copyright Digital Mars 2000 - 2018. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly * Source: $(DRUNTIMESRC rt/_dmain2.d) */ module rt.dmain2; import core.atomic;import core.internal.parseoptions : rt_parseOption;import core.stdc.errno : errno;import core.stdc.stdio : fflush, fprintf, fwrite, stderr, stdout;import core.stdc.stdlib : alloca, EXIT_FAILURE, EXIT_SUCCESS, free, malloc, realloc;import core.stdc.string : strerror;import rt.config : rt_cmdline_enabled, rt_configOption;import rt.memory;import rt.sections; version (Windows){ import core.stdc.stdio : fileno; import core.stdc.wchar_ : wcslen; import core.sys.windows.basetsd : HANDLE; import core.sys.windows.shellapi : CommandLineToArgvW; import core.sys.windows.winbase : FreeLibrary, GetCommandLineW, GetProcAddress, IsDebuggerPresent, LoadLibraryW, LocalFree, WriteFile; import core.sys.windows.wincon : CONSOLE_SCREEN_BUFFER_INFO, GetConsoleOutputCP, GetConsoleScreenBufferInfo; import core.sys.windows.winnls : CP_UTF8, MultiByteToWideChar, WideCharToMultiByte; import core.sys.windows.winnt : WCHAR; import core.sys.windows.winuser : MB_ICONERROR, MessageBoxW; pragma(lib, "shell32.lib"); // needed for CommandLineToArgvW import core.stdc.stdio : _get_osfhandle;}else version (Posix){ import core.stdc.string : strlen;} version (DigitalMars) version (AArch64) version = UseMalloc; // cuz alloca() is not implemented yet // not sure why we can't define this in one place, but this is to keep this// module from importing core.runtime.struct UnitTestResult{ size_t executed; size_t passed; bool runMain; bool summarize;} extern (C) void _d_monitor_staticctor() @nogc nothrow;extern (C) void _d_monitor_staticdtor() @nogc nothrow;extern (C) void _d_critical_init() @nogc nothrow;extern (C) void _d_critical_term() @nogc nothrow;extern (C) void gc_init();extern (C) void gc_term();extern (C) void thread_init() @nogc nothrow;extern (C) void thread_term() @nogc nothrow;extern (C) void rt_moduleCtor();extern (C) void rt_moduleTlsCtor();extern (C) void rt_moduleDtor();extern (C) void rt_moduleTlsDtor();extern (C) void thread_joinAll();extern (C) UnitTestResult runModuleUnitTests();extern (C) void _d_initMonoTime() @nogc nothrow; version (CRuntime_Microsoft){ extern(C) void init_msvc();} /* To get out-of-band access to the args[] passed to main(). */ __gshared string[] _d_args = null; extern (C) string[] rt_args(){ return _d_args;} // This variable is only ever set by a debugger on initialization so it should// be fine to leave it as __gshared.extern (C) __gshared bool rt_trapExceptions = true; alias ExceptionHandler = void delegate(Throwable); /** * Keep track of how often rt_init/rt_term were called. */private shared size_t _initCount; /********************************************** * Initialize druntime. * If a C program wishes to call D code, and there's no D main(), then it * must call rt_init() and rt_term(). */extern (C) int rt_init(){ /* @@BUG 11380 @@ Need to synchronize rt_init/rt_term calls for version (Shared) druntime, because multiple C threads might initialize different D libraries without knowing about the shared druntime. Also we need to attach any thread that calls rt_init. */ if (atomicOp!"+="(_initCount, 1) > 1) return 1; version (CRuntime_Microsoft) init_msvc(); _d_monitor_staticctor(); _d_critical_init(); try { initSections(); // this initializes mono time before anything else to allow usage // in other druntime systems. _d_initMonoTime(); thread_init(); // TODO: fixme - calls GC.addRange -> Initializes GC initStaticDataGC(); rt_moduleCtor(); rt_moduleTlsCtor(); return 1; } catch (Throwable t) { atomicStore!(MemoryOrder.raw)(_initCount, 0); _d_print_throwable(t); } _d_critical_term(); _d_monitor_staticdtor(); return 0;} /********************************************** * Terminate use of druntime. */extern (C) int rt_term(){ if (atomicLoad!(MemoryOrder.raw)(_initCount) == 0) return 0; // was never initialized if (atomicOp!"-="(_initCount, 1)) return 1; try { rt_moduleTlsDtor(); thread_joinAll(); rt_moduleDtor(); gc_term(); thread_term(); return 1; } catch (Throwable t) { _d_print_throwable(t); } finally { finiSections(); _d_critical_term(); _d_monitor_staticdtor(); } return 0;} /** * Indicates whether druntime has been or is being initialized. */bool isRuntimeInitialized() @nogc nothrow { return atomicLoad!(MemoryOrder.raw)(_initCount) != 0;} /********************************************** * Trace handler */alias TraceHandler = Throwable.TraceInfo function(void* ptr);private __gshared TraceHandler traceHandler = null;private __gshared Throwable.TraceDeallocator traceDeallocator = null; /** * Overrides the default trace hander with a user-supplied version. * * Params: * h = The new trace handler. Set to null to use the default handler. * d = The new dealloactor to use. */extern (C) void rt_setTraceHandler(TraceHandler h, Throwable.TraceDeallocator d = null){ traceHandler = h; traceDeallocator = d;} /** * Return the current trace handler */extern (C) TraceHandler rt_getTraceHandler(){ return traceHandler;} extern (C) Throwable.TraceDeallocator rt_getTraceDeallocator(){ return traceDeallocator;} /** * This function will be called when an exception is constructed. The * user-supplied trace handler will be called if one has been supplied, * otherwise no trace will be generated. * * Params: * ptr = A pointer to the location from which to generate the trace, or null * if the trace should be generated from within the trace handler * itself. * * Returns: * An object describing the current calling context or null if no handler is * supplied. */extern (C) Throwable.TraceInfo _d_traceContext(void* ptr = null){ if (traceHandler is null) return null; return traceHandler(ptr);} /*********************************** * Provide out-of-band access to the original C argc/argv * passed to this program via main(argc,argv). */ struct CArgs{ int argc; char** argv;} __gshared CArgs _cArgs; extern (C) CArgs rt_cArgs() @nogc{ return _cArgs;} /// Type of the D main() function (`_Dmain`).private alias MainFunc = extern(C) int function(char[][] args); /** * Sets up the D char[][] command-line args, initializes druntime, * runs embedded unittests and then runs the given D main() function, * optionally catching and printing any unhandled exceptions. */extern (C) int _d_run_main(int argc, char** argv, MainFunc mainFunc){ // Set up _cArgs and array of D char[] slices, then forward to _d_run_main2 // Remember the original C argc/argv _cArgs.argc = argc; _cArgs.argv = argv; version (Windows) { /* Because we want args[] to be UTF-8, and Windows doesn't guarantee that, * we ignore argc/argv and go get the Windows command line again as UTF-16. * Then, reparse into wargc/wargs, and then use Windows API to convert * to UTF-8. */ const wCommandLine = GetCommandLineW(); immutable size_t wCommandLineLength = wcslen(wCommandLine); int wargc; auto wargs = CommandLineToArgvW(wCommandLine, &wargc); // assert(wargc == argc); /* argc can be broken by Unicode arguments */ // Allocate args[] on the stack - use wargc version (UseMalloc) { char[][] args = (cast(char[]*) malloc(wargc * (char[]).sizeof))[0 .. wargc]; if (wargc) assert(args.ptr); scope (exit) free(args.ptr); } else char[][] args = (cast(char[]*) alloca(wargc * (char[]).sizeof))[0 .. wargc]; // This is required because WideCharToMultiByte requires int as input. assert(wCommandLineLength <= cast(size_t) int.max, "Wide char command line length must not exceed int.max"); immutable size_t totalArgsLength = WideCharToMultiByte(CP_UTF8, 0, wCommandLine, cast(int)wCommandLineLength, null, 0, null, null); { version (UseMalloc) { char* totalArgsBuff = cast(char*) malloc(totalArgsLength); if (totalArgsLength) assert(totalArgsBuff); scope (exit) free(totalArgsBuff); } else char* totalArgsBuff = cast(char*) alloca(totalArgsLength); size_t j = 0; foreach (i; 0 .. wargc) { immutable size_t wlen = wcslen(wargs[i]); assert(wlen <= cast(size_t) int.max, "wlen cannot exceed int.max"); immutable int len = WideCharToMultiByte(CP_UTF8, 0, &wargs[i][0], cast(int) wlen, null, 0, null, null); args[i] = totalArgsBuff[j .. j + len]; if (len == 0) continue; j += len; assert(j <= totalArgsLength); WideCharToMultiByte(CP_UTF8, 0, &wargs[i][0], cast(int) wlen, &args[i][0], len, null, null); } } LocalFree(wargs); wargs = null; wargc = 0; } else version (Posix) { // Allocate args[] on the stack version (UseMalloc) { char[][] args = (cast(char[]*) malloc(argc * (char[]).sizeof))[0 .. argc]; if (argc) assert(args.ptr); scope (exit) free(args.ptr); } else char[][] args = (cast(char[]*) alloca(argc * (char[]).sizeof))[0 .. argc]; size_t totalArgsLength = 0; foreach (i, ref arg; args) { arg = argv[i][0 .. strlen(argv[i])]; totalArgsLength += arg.length; } } else static assert(0); return _d_run_main2(args, totalArgsLength, mainFunc);} /** * Windows-specific version for wide command-line arguments, e.g., * from a wmain/wWinMain C entry point. * This wide version uses the specified arguments, unlike narrow * _d_run_main which uses the actual (wide) process arguments instead. */version (Windows)extern (C) int _d_wrun_main(int argc, wchar** wargv, MainFunc mainFunc){ // Allocate args[] on the stack char[][] args = (cast(char[]*) alloca(argc * (char[]).sizeof))[0 .. argc]; // 1st pass: compute each argument's length as UTF-16 and UTF-8 size_t totalArgsLength = 0; foreach (i; 0 .. argc) { const warg = wargv[i]; const size_t wlen = wcslen(warg) + 1; // incl. terminating null assert(wlen <= cast(size_t) int.max, "wlen cannot exceed int.max"); const int len = WideCharToMultiByte(CP_UTF8, 0, warg, cast(int) wlen, null, 0, null, null); args[i] = (cast(char*) wlen)[0 .. len]; // args[i].ptr = wlen, args[i].length = len totalArgsLength += len; } // Allocate a single buffer for all (null-terminated) argument strings in UTF-8 on the stack char* utf8Buffer = cast(char*) alloca(totalArgsLength); // 2nd pass: convert to UTF-8 and finalize `args` char* utf8 = utf8Buffer; foreach (i; 0 .. argc) { const wlen = cast(int) args[i].ptr; const len = cast(int) args[i].length; WideCharToMultiByte(CP_UTF8, 0, wargv[i], wlen, utf8, len, null, null); args[i] = utf8[0 .. len-1]; // excl. terminating null utf8 += len; } // Set C argc/argv; argv is a new stack-allocated array of UTF-8 C strings char*[] argv = (cast(char**) alloca(argc * (char*).sizeof))[0 .. argc]; foreach (i, ref arg; argv) arg = args[i].ptr; _cArgs.argc = argc; _cArgs.argv = argv.ptr; totalArgsLength -= argc; // excl. null terminator per arg return _d_run_main2(args, totalArgsLength, mainFunc);} private extern (C) int _d_run_main2(char[][] args, size_t totalArgsLength, MainFunc mainFunc){ int result; version (FreeBSD) version (D_InlineAsm_X86) { /* * FreeBSD/i386 sets the FPU precision mode to 53 bit double. * Make it 64 bit extended. */ ushort fpucw; asm { fstsw fpucw; or fpucw, 0b11_00_111111; // 11: use 64 bit extended-precision // 111111: mask all FP exceptions fldcw fpucw; } } version (CRuntime_Microsoft) { // enable full precision for reals version (D_InlineAsm_X86_64) { asm { push RAX; fstcw word ptr [RSP]; or [RSP], 0b11_00_111111; // 11: use 64 bit extended-precision // 111111: mask all FP exceptions fldcw word ptr [RSP]; pop RAX; } } else version (D_InlineAsm_X86) { asm { push EAX; fstcw word ptr [ESP]; or [ESP], 0b11_00_111111; // 11: use 64 bit extended-precision // 111111: mask all FP exceptions fldcw word ptr [ESP]; pop EAX; } } else version (GNU_InlineAsm) { size_t fpu_cw; asm { "fstcw %0" : "=m" (fpu_cw); } fpu_cw |= 0b11_00_111111; // 11: use 64 bit extended-precision // 111111: mask all FP exceptions asm { "fldcw %0" : "=m" (fpu_cw); } } } /* Create a copy of args[] on the stack to be used for main, so that rt_args() * cannot be modified by the user. * Note that when this function returns, _d_args will refer to garbage. */ { _d_args = cast(string[]) args; auto length = args.length * (char[]).sizeof + totalArgsLength; version (UseMalloc) { auto buff = cast(char[]*) malloc(length); if (length) assert(buff); //scope (exit) buff; } else auto buff = cast(char[]*) alloca(length); char[][] argsCopy = buff[0 .. args.length]; auto argBuff = cast(char*) (buff + args.length); size_t j = 0; bool parseOpts = rt_cmdline_enabled!(); foreach (arg; args) { // Do not pass Druntime options to the program if (parseOpts && arg.length >= 6 && arg[0 .. 6] == "--DRT-") continue; // https://issues.dlang.org/show_bug.cgi?id=20459 if (arg == "--") parseOpts = false; argsCopy[j++] = (argBuff[0 .. arg.length] = arg[]); argBuff += arg.length; } args = argsCopy[0..j]; } auto useExceptionTrap = parseExceptionOptions(); version (Windows) { if (IsDebuggerPresent()) useExceptionTrap = false; }Lines 1–500 of 725. Load more
/** * Contains druntime startup and shutdown routines. * * Copyright: Copyright Digital Mars 2000 - 2018. * License: Distributed under the * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). * (See accompanying file LICENSE) * Authors: Walter Bright, Sean Kelly * Source: $(DRUNTIMESRC rt/_dmain2.d) */ module rt.dmain2; import core.atomic; import core.internal.parseoptions : rt_parseOption; import core.stdc.errno : errno; import core.stdc.stdio : fflush, fprintf, fwrite, stderr, stdout; import core.stdc.stdlib : alloca, EXIT_FAILURE, EXIT_SUCCESS, free, malloc, realloc; import core.stdc.string : strerror; import rt.config : rt_cmdline_enabled, rt_configOption; import rt.memory; import rt.sections; version (Windows) { import core.stdc.stdio : fileno; import core.stdc.wchar_ : wcslen; import core.sys.windows.basetsd : HANDLE; import core.sys.windows.shellapi : CommandLineToArgvW; import core.sys.windows.winbase : FreeLibrary, GetCommandLineW, GetProcAddress, IsDebuggerPresent, LoadLibraryW, LocalFree, WriteFile; import core.sys.windows.wincon : CONSOLE_SCREEN_BUFFER_INFO, GetConsoleOutputCP, GetConsoleScreenBufferInfo; import core.sys.windows.winnls : CP_UTF8, MultiByteToWideChar, WideCharToMultiByte; import core.sys.windows.winnt : WCHAR; import core.sys.windows.winuser : MB_ICONERROR, MessageBoxW; pragma(lib, "shell32.lib"); // needed for CommandLineToArgvW import core.stdc.stdio : _get_osfhandle; } else version (Posix) { import core.stdc.string : strlen; } version (DigitalMars) version (AArch64) version = UseMalloc; // cuz alloca() is not implemented yet // not sure why we can't define this in one place, but this is to keep this // module from importing core.runtime. struct UnitTestResult { size_t executed; size_t passed; bool runMain; bool summarize; } extern (C) void _d_monitor_staticctor() @nogc nothrow; extern (C) void _d_monitor_staticdtor() @nogc nothrow; extern (C) void _d_critical_init() @nogc nothrow; extern (C) void _d_critical_term() @nogc nothrow; extern (C) void gc_init(); extern (C) void gc_term(); extern (C) void thread_init() @nogc nothrow; extern (C) void thread_term() @nogc nothrow; extern (C) void rt_moduleCtor(); extern (C) void rt_moduleTlsCtor(); extern (C) void rt_moduleDtor(); extern (C) void rt_moduleTlsDtor(); extern (C) void thread_joinAll(); extern (C) UnitTestResult runModuleUnitTests(); extern (C) void _d_initMonoTime() @nogc nothrow; version (CRuntime_Microsoft) { extern(C) void init_msvc(); } /* To get out-of-band access to the args[] passed to main(). */ __gshared string[] _d_args = null; extern (C) string[] rt_args() { return _d_args; } // This variable is only ever set by a debugger on initialization so it should // be fine to leave it as __gshared. extern (C) __gshared bool rt_trapExceptions = true; alias ExceptionHandler = void delegate(Throwable); /** * Keep track of how often rt_init/rt_term were called. */ private shared size_t _initCount; /********************************************** * Initialize druntime. * If a C program wishes to call D code, and there's no D main(), then it * must call rt_init() and rt_term(). */ extern (C) int rt_init() { /* @@BUG 11380 @@ Need to synchronize rt_init/rt_term calls for version (Shared) druntime, because multiple C threads might initialize different D libraries without knowing about the shared druntime. Also we need to attach any thread that calls rt_init. */ if (atomicOp!"+="(_initCount, 1) > 1) return 1; version (CRuntime_Microsoft) init_msvc(); _d_monitor_staticctor(); _d_critical_init(); try { initSections(); // this initializes mono time before anything else to allow usage // in other druntime systems. _d_initMonoTime(); thread_init(); // TODO: fixme - calls GC.addRange -> Initializes GC initStaticDataGC(); rt_moduleCtor(); rt_moduleTlsCtor(); return 1; } catch (Throwable t) { atomicStore!(MemoryOrder.raw)(_initCount, 0); _d_print_throwable(t); } _d_critical_term(); _d_monitor_staticdtor(); return 0; } /********************************************** * Terminate use of druntime. */ extern (C) int rt_term() { if (atomicLoad!(MemoryOrder.raw)(_initCount) == 0) return 0; // was never initialized if (atomicOp!"-="(_initCount, 1)) return 1; try { rt_moduleTlsDtor(); thread_joinAll(); rt_moduleDtor(); gc_term(); thread_term(); return 1; } catch (Throwable t) { _d_print_throwable(t); } finally { finiSections(); _d_critical_term(); _d_monitor_staticdtor(); } return 0; } /** * Indicates whether druntime has been or is being initialized. */ bool isRuntimeInitialized() @nogc nothrow { return atomicLoad!(MemoryOrder.raw)(_initCount) != 0; } /********************************************** * Trace handler */ alias TraceHandler = Throwable.TraceInfo function(void* ptr); private __gshared TraceHandler traceHandler = null; private __gshared Throwable.TraceDeallocator traceDeallocator = null; /** * Overrides the default trace hander with a user-supplied version. * * Params: * h = The new trace handler. Set to null to use the default handler. * d = The new dealloactor to use. */ extern (C) void rt_setTraceHandler(TraceHandler h, Throwable.TraceDeallocator d = null) { traceHandler = h; traceDeallocator = d; } /** * Return the current trace handler */ extern (C) TraceHandler rt_getTraceHandler() { return traceHandler; } extern (C) Throwable.TraceDeallocator rt_getTraceDeallocator() { return traceDeallocator; } /** * This function will be called when an exception is constructed. The * user-supplied trace handler will be called if one has been supplied, * otherwise no trace will be generated. * * Params: * ptr = A pointer to the location from which to generate the trace, or null * if the trace should be generated from within the trace handler * itself. * * Returns: * An object describing the current calling context or null if no handler is * supplied. */ extern (C) Throwable.TraceInfo _d_traceContext(void* ptr = null) { if (traceHandler is null) return null; return traceHandler(ptr); } /*********************************** * Provide out-of-band access to the original C argc/argv * passed to this program via main(argc,argv). */ struct CArgs { int argc; char** argv; } __gshared CArgs _cArgs; extern (C) CArgs rt_cArgs() @nogc { return _cArgs; } /// Type of the D main() function (`_Dmain`). private alias MainFunc = extern(C) int function(char[][] args); /** * Sets up the D char[][] command-line args, initializes druntime, * runs embedded unittests and then runs the given D main() function, * optionally catching and printing any unhandled exceptions. */ extern (C) int _d_run_main(int argc, char** argv, MainFunc mainFunc) { // Set up _cArgs and array of D char[] slices, then forward to _d_run_main2 // Remember the original C argc/argv _cArgs.argc = argc; _cArgs.argv = argv; version (Windows) { /* Because we want args[] to be UTF-8, and Windows doesn't guarantee that, * we ignore argc/argv and go get the Windows command line again as UTF-16. * Then, reparse into wargc/wargs, and then use Windows API to convert * to UTF-8. */ const wCommandLine = GetCommandLineW(); immutable size_t wCommandLineLength = wcslen(wCommandLine); int wargc; auto wargs = CommandLineToArgvW(wCommandLine, &wargc); // assert(wargc == argc); /* argc can be broken by Unicode arguments */ // Allocate args[] on the stack - use wargc version (UseMalloc) { char[][] args = (cast(char[]*) malloc(wargc * (char[]).sizeof))[0 .. wargc]; if (wargc) assert(args.ptr); scope (exit) free(args.ptr); } else char[][] args = (cast(char[]*) alloca(wargc * (char[]).sizeof))[0 .. wargc]; // This is required because WideCharToMultiByte requires int as input. assert(wCommandLineLength <= cast(size_t) int.max, "Wide char command line length must not exceed int.max"); immutable size_t totalArgsLength = WideCharToMultiByte(CP_UTF8, 0, wCommandLine, cast(int)wCommandLineLength, null, 0, null, null); { version (UseMalloc) { char* totalArgsBuff = cast(char*) malloc(totalArgsLength); if (totalArgsLength) assert(totalArgsBuff); scope (exit) free(totalArgsBuff); } else char* totalArgsBuff = cast(char*) alloca(totalArgsLength); size_t j = 0; foreach (i; 0 .. wargc) { immutable size_t wlen = wcslen(wargs[i]); assert(wlen <= cast(size_t) int.max, "wlen cannot exceed int.max"); immutable int len = WideCharToMultiByte(CP_UTF8, 0, &wargs[i][0], cast(int) wlen, null, 0, null, null); args[i] = totalArgsBuff[j .. j + len]; if (len == 0) continue; j += len; assert(j <= totalArgsLength); WideCharToMultiByte(CP_UTF8, 0, &wargs[i][0], cast(int) wlen, &args[i][0], len, null, null); } } LocalFree(wargs); wargs = null; wargc = 0; } else version (Posix) { // Allocate args[] on the stack version (UseMalloc) { char[][] args = (cast(char[]*) malloc(argc * (char[]).sizeof))[0 .. argc]; if (argc) assert(args.ptr); scope (exit) free(args.ptr); } else char[][] args = (cast(char[]*) alloca(argc * (char[]).sizeof))[0 .. argc]; size_t totalArgsLength = 0; foreach (i, ref arg; args) { arg = argv[i][0 .. strlen(argv[i])]; totalArgsLength += arg.length; } } else static assert(0); return _d_run_main2(args, totalArgsLength, mainFunc); } /** * Windows-specific version for wide command-line arguments, e.g., * from a wmain/wWinMain C entry point. * This wide version uses the specified arguments, unlike narrow * _d_run_main which uses the actual (wide) process arguments instead. */ version (Windows) extern (C) int _d_wrun_main(int argc, wchar** wargv, MainFunc mainFunc) { // Allocate args[] on the stack char[][] args = (cast(char[]*) alloca(argc * (char[]).sizeof))[0 .. argc]; // 1st pass: compute each argument's length as UTF-16 and UTF-8 size_t totalArgsLength = 0; foreach (i; 0 .. argc) { const warg = wargv[i]; const size_t wlen = wcslen(warg) + 1; // incl. terminating null assert(wlen <= cast(size_t) int.max, "wlen cannot exceed int.max"); const int len = WideCharToMultiByte(CP_UTF8, 0, warg, cast(int) wlen, null, 0, null, null); args[i] = (cast(char*) wlen)[0 .. len]; // args[i].ptr = wlen, args[i].length = len totalArgsLength += len; } // Allocate a single buffer for all (null-terminated) argument strings in UTF-8 on the stack char* utf8Buffer = cast(char*) alloca(totalArgsLength); // 2nd pass: convert to UTF-8 and finalize `args` char* utf8 = utf8Buffer; foreach (i; 0 .. argc) { const wlen = cast(int) args[i].ptr; const len = cast(int) args[i].length; WideCharToMultiByte(CP_UTF8, 0, wargv[i], wlen, utf8, len, null, null); args[i] = utf8[0 .. len-1]; // excl. terminating null utf8 += len; } // Set C argc/argv; argv is a new stack-allocated array of UTF-8 C strings char*[] argv = (cast(char**) alloca(argc * (char*).sizeof))[0 .. argc]; foreach (i, ref arg; argv) arg = args[i].ptr; _cArgs.argc = argc; _cArgs.argv = argv.ptr; totalArgsLength -= argc; // excl. null terminator per arg return _d_run_main2(args, totalArgsLength, mainFunc); } private extern (C) int _d_run_main2(char[][] args, size_t totalArgsLength, MainFunc mainFunc) { int result; version (FreeBSD) version (D_InlineAsm_X86) { /* * FreeBSD/i386 sets the FPU precision mode to 53 bit double. * Make it 64 bit extended. */ ushort fpucw; asm { fstsw fpucw; or fpucw, 0b11_00_111111; // 11: use 64 bit extended-precision // 111111: mask all FP exceptions fldcw fpucw; } } version (CRuntime_Microsoft) { // enable full precision for reals version (D_InlineAsm_X86_64) { asm { push RAX; fstcw word ptr [RSP]; or [RSP], 0b11_00_111111; // 11: use 64 bit extended-precision // 111111: mask all FP exceptions fldcw word ptr [RSP]; pop RAX; } } else version (D_InlineAsm_X86) { asm { push EAX; fstcw word ptr [ESP]; or [ESP], 0b11_00_111111; // 11: use 64 bit extended-precision // 111111: mask all FP exceptions fldcw word ptr [ESP]; pop EAX; } } else version (GNU_InlineAsm) { size_t fpu_cw; asm { "fstcw %0" : "=m" (fpu_cw); } fpu_cw |= 0b11_00_111111; // 11: use 64 bit extended-precision // 111111: mask all FP exceptions asm { "fldcw %0" : "=m" (fpu_cw); } } } /* Create a copy of args[] on the stack to be used for main, so that rt_args() * cannot be modified by the user. * Note that when this function returns, _d_args will refer to garbage. */ { _d_args = cast(string[]) args; auto length = args.length * (char[]).sizeof + totalArgsLength; version (UseMalloc) { auto buff = cast(char[]*) malloc(length); if (length) assert(buff); //scope (exit) buff; } else auto buff = cast(char[]*) alloca(length); char[][] argsCopy = buff[0 .. args.length]; auto argBuff = cast(char*) (buff + args.length); size_t j = 0; bool parseOpts = rt_cmdline_enabled!(); foreach (arg; args) { // Do not pass Druntime options to the program if (parseOpts && arg.length >= 6 && arg[0 .. 6] == "--DRT-") continue; // https://issues.dlang.org/show_bug.cgi?id=20459 if (arg == "--") parseOpts = false; argsCopy[j++] = (argBuff[0 .. arg.length] = arg[]); argBuff += arg.length; } args = argsCopy[0..j]; } auto useExceptionTrap = parseExceptionOptions(); version (Windows) { if (IsDebuggerPresent()) useExceptionTrap = false; }