]> git.llucax.com Git - software/druntime.git/blob - src/compiler/dmd/alloca.d
First commit of the D Runtime Project. This includes a fully functional runtime...
[software/druntime.git] / src / compiler / dmd / alloca.d
1 /*_ _alloca.d
2  * Copyright (C) 1990-2003 by Digital Mars, www.digitalmars.com
3  * All Rights Reserved
4  * Written by Walter Bright
5  */
6
7 module rt.alloca;
8
9 /+
10 #if DOS386
11 extern size_t _x386_break;
12 #else
13 extern size_t _pastdata;
14 #endif
15 +/
16
17 /*******************************************
18  * Allocate data from the caller's stack frame.
19  * This is a 'magic' function that needs help from the compiler to
20  * work right, do not change its name, do not call it from other compilers.
21  * Input:
22  *      nbytes  number of bytes to allocate
23  *      ECX     address of variable with # of bytes in locals
24  *              This is adjusted upon return to reflect the additional
25  *              size of the stack frame.
26  * Returns:
27  *      EAX     allocated data, null if stack overflows
28  */
29
30 extern (C) void* __alloca(int nbytes)
31 {
32     asm
33     {
34         naked                   ;
35         mov     EDX,ECX         ;
36         mov     EAX,4[ESP]      ; // get nbytes
37         push    EBX             ;
38         push    EDI             ;
39         push    ESI             ;
40         add     EAX,3           ;
41         and     EAX,0xFFFFFFFC  ; // round up to dword
42         jnz     Abegin          ;
43         mov     EAX,4           ; // allow zero bytes allocation, 0 rounded to dword is 4..
44     Abegin:
45         mov     ESI,EAX         ; // ESI = nbytes
46         neg     EAX             ;
47         add     EAX,ESP         ; // EAX is now what the new ESP will be.
48         jae     Aoverflow       ;
49     }
50     version (Windows)
51     {
52     asm
53     {
54         // We need to be careful about the guard page
55         // Thus, for every 4k page, touch it to cause the OS to load it in.
56         mov     ECX,EAX         ; // ECX is new location for stack
57         mov     EBX,ESI         ; // EBX is size to "grow" stack
58     L1:
59         test    [ECX+EBX],EBX   ; // bring in page
60         sub     EBX,0x1000      ; // next 4K page down
61         jae     L1              ; // if more pages
62         test    [ECX],EBX       ; // bring in last page
63     }
64     }
65     version (DOS386)
66     {
67     asm
68     {
69         // is ESP off bottom?
70         cmp     EAX,_x386_break ;
71         jbe     Aoverflow       ;
72     }
73     }
74     version (Unix)
75     {
76     asm
77     {
78         cmp     EAX,_pastdata   ;
79         jbe     Aoverflow       ; // Unlikely - ~2 Gbytes under UNIX
80     }
81     }
82     asm
83     {
84         // Copy down to [ESP] the temps on the stack.
85         // The number of temps is (EBP - ESP - locals).
86         mov     ECX,EBP         ;
87         sub     ECX,ESP         ;
88         sub     ECX,[EDX]       ; // ECX = number of temps (bytes) to move.
89         add     [EDX],ESI       ; // adjust locals by nbytes for next call to alloca()
90         mov     ESP,EAX         ; // Set up new stack pointer.
91         add     EAX,ECX         ; // Return value = ESP + temps.
92         mov     EDI,ESP         ; // Destination of copy of temps.
93         add     ESI,ESP         ; // Source of copy.
94         shr     ECX,2           ; // ECX to count of dwords in temps
95                                   // Always at least 4 (nbytes, EIP, ESI,and EDI).
96         rep                     ;
97         movsd                   ;
98         jmp     done            ;
99
100     Aoverflow:
101         // Overflowed the stack.  Return null
102         xor     EAX,EAX         ;
103
104     done:
105         pop     ESI             ;
106         pop     EDI             ;
107         pop     EBX             ;
108         ret                     ;
109     }
110 }