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.compiler.dmd.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 31 extern (C) void* __alloca(int nbytes) 32 { 33 version (D_InlineAsm_X86) 34 { 35 asm 36 { 37 naked ; 38 mov EDX,ECX ; 39 mov EAX,4[ESP] ; // get nbytes 40 push EBX ; 41 push EDI ; 42 push ESI ; 43 } 44 45 version (OSX) 46 { 47 asm 48 { 49 add EAX,15 ; 50 and EAX,0xFFFFFFF0 ; // round up to 16 byte boundary 51 } 52 } 53 else 54 { 55 asm 56 { 57 add EAX,3 ; 58 and EAX,0xFFFFFFFC ; // round up to dword 59 } 60 } 61 62 asm 63 { 64 jnz Abegin ; 65 mov EAX,4 ; // allow zero bytes allocation, 0 rounded to dword is 4.. 66 Abegin: 67 mov ESI,EAX ; // ESI = nbytes 68 neg EAX ; 69 add EAX,ESP ; // EAX is now what the new ESP will be. 70 jae Aoverflow ; 71 } 72 version (Win32) 73 { 74 asm 75 { 76 // We need to be careful about the guard page 77 // Thus, for every 4k page, touch it to cause the OS to load it in. 78 mov ECX,EAX ; // ECX is new location for stack 79 mov EBX,ESI ; // EBX is size to "grow" stack 80 L1: 81 test [ECX+EBX],EBX ; // bring in page 82 sub EBX,0x1000 ; // next 4K page down 83 jae L1 ; // if more pages 84 test [ECX],EBX ; // bring in last page 85 } 86 } 87 version (DOS386) 88 { 89 asm 90 { 91 // is ESP off bottom? 92 cmp EAX,_x386_break ; 93 jbe Aoverflow ; 94 } 95 } 96 version (Unix) 97 { 98 asm 99 { 100 cmp EAX,_pastdata ; 101 jbe Aoverflow ; // Unlikely - ~2 Gbytes under UNIX 102 } 103 } 104 asm 105 { 106 // Copy down to [ESP] the temps on the stack. 107 // The number of temps is (EBP - ESP - locals). 108 mov ECX,EBP ; 109 sub ECX,ESP ; 110 sub ECX,[EDX] ; // ECX = number of temps (bytes) to move. 111 add [EDX],ESI ; // adjust locals by nbytes for next call to alloca() 112 mov ESP,EAX ; // Set up new stack pointer. 113 add EAX,ECX ; // Return value = ESP + temps. 114 mov EDI,ESP ; // Destination of copy of temps. 115 add ESI,ESP ; // Source of copy. 116 shr ECX,2 ; // ECX to count of dwords in temps 117 // Always at least 4 (nbytes, EIP, ESI,and EDI). 118 rep ; 119 movsd ; 120 jmp done ; 121 122 Aoverflow: 123 // Overflowed the stack. Return null 124 xor EAX,EAX ; 125 126 done: 127 pop ESI ; 128 pop EDI ; 129 pop EBX ; 130 ret ; 131 } 132 } 133 else version (D_InlineAsm_X86_64) 134 { 135 asm 136 { 137 naked ; 138 mov RDX,RCX ; 139 mov RAX,RDI ; // get nbytes 140 add RAX,15 ; 141 and AL,0xF0 ; // round up to 16 byte boundary 142 test RAX,RAX ; 143 jnz Abegin ; 144 mov RAX,16 ; // allow zero bytes allocation 145 Abegin: 146 mov RSI,RAX ; // RSI = nbytes 147 neg RAX ; 148 add RAX,RSP ; // RAX is now what the new RSP will be. 149 jae Aoverflow ; 150 } 151 version (Win64) 152 { 153 asm 154 { 155 // We need to be careful about the guard page 156 // Thus, for every 4k page, touch it to cause the OS to load it in. 157 mov RCX,RAX ; // RCX is new location for stack 158 mov RBX,RSI ; // RBX is size to "grow" stack 159 L1: 160 test [RCX+RBX],RBX ; // bring in page 161 sub RBX,0x1000 ; // next 4K page down 162 jae L1 ; // if more pages 163 test [RCX],RBX ; // bring in last page 164 } 165 } 166 version (Unix) 167 { 168 asm 169 { 170 cmp RAX,_pastdata ; 171 jbe Aoverflow ; // Unlikely - ~2 Gbytes under UNIX 172 } 173 } 174 asm 175 { 176 // Copy down to [RSP] the temps on the stack. 177 // The number of temps is (RBP - RSP - locals). 178 mov RCX,RBP ; 179 sub RCX,RSP ; 180 sub RCX,[RDX] ; // RCX = number of temps (bytes) to move. 181 add [RDX],RSI ; // adjust locals by nbytes for next call to alloca() 182 mov RSP,RAX ; // Set up new stack pointer. 183 add RAX,RCX ; // Return value = RSP + temps. 184 mov RDI,RSP ; // Destination of copy of temps. 185 add RSI,RSP ; // Source of copy. 186 shr RCX,3 ; // RCX to count of qwords in temps 187 rep ; 188 movsq ; 189 jmp done ; 190 191 Aoverflow: 192 // Overflowed the stack. Return null 193 xor RAX,RAX ; 194 195 done: 196 ret ; 197 } 198 } 199 else 200 static assert(0); 201 }