]> git.llucax.com Git - software/dgc/naive.git/blob - gc/arch.d
Compare pointers explicitly against null using is and !is
[software/dgc/naive.git] / gc / arch.d
1 /**
2  * Architecture (and compiler) dependent functions.
3  *
4  * This is a support module for the Naive Garbage Collector. All the code that
5  * depends on the architecture (or compiler) is in this module.
6  *
7  * See_Also:  gc module
8  * Copyright: Public Domain
9  * License:   Public Domain
10  * Authors:   Leandro Lucarella <llucax@gmail.com>
11  */
12
13 module gc.arch;
14
15
16 package:
17
18 /**
19  * Small hack to define the string alias if not defined
20  *
21  * Tango doesn't define this alias in object.d, but Phobos (both 1 and 2)
22  * does.
23  */
24 /*
25  * XXX: this (more general approach) doesn't work:
26  *
27  * static if (!is(string))
28  *    private alias char[] string;
29  *
30  * See: http://d.puremagic.com/issues/show_bug.cgi?id=2848
31  */
32 version (Tango)
33     private alias char[] string;
34
35
36 version (D_Ddoc)
37 {
38
39     /**
40      * Push the registers into the stack.
41      *
42      * Note that this function should be used as a string mixin because if
43      * a regular function call would be done, the stack would be unwound at
44      * function exit and the register will not longer be in the stack.
45      *
46      * A pointer to the top of the stack is stored in a variable with the name
47      * 'sp_name' (which is expected to be a void*).
48      *
49      * Example:
50      * -----------------------------------------------------------------------
51      *  void some_function()
52      *  {
53      *      void* sp;
54      *      mixin(push_registers("sp"));
55      *      // Do something
56      *      mixin(pop_registers("sp"));
57      *  }
58      * -----------------------------------------------------------------------
59      *
60      * See_Also: pop_registers()
61      *
62      */
63     string push_registers(string sp_name);
64
65     /**
66      * Pop the registers out the stack.
67      *
68      * Note that this function should be used as a string mixin (see
69      * push_registers() for more details).
70      *
71      * A pointer to the top of the stack can be obtained from a variable with
72      * the name 'sp_name' (which is expected to be a void*).
73      *
74      * See_Also: push_registers()
75      */
76     string pop_registers(string sp_name);
77
78 }
79
80
81 // Implementation(s)
82
83 version (GNU)
84 {
85
86     /*
87      * GCC has an intrinsic function that does the job of pushing the
88      * registers into the stack, we use that function if available because it
89      * should work in all GCC supported architectures.
90      *
91      * Nothing needs to be done to pop the registers from the stack.
92      */
93
94     string push_registers(string sp_name)
95     {
96         return "
97             __builtin_unwind_init();
98             " ~ sp_name ~ " = &" ~ sp_name ~ ";
99         ";
100     }
101
102     string pop_registers(string sp_name)
103     {
104         return "";
105     }
106
107 }
108 else version (X86)
109 {
110
111     /*
112      * For X86 PUSHAD/POPAD are not used because they are too susceptible to
113      * compiler optimizations (like omitting the frame pointer).
114      *
115      * This method should work safely with all optimizations because it doesn't
116      * work behind the compilers back.
117      */
118
119     string push_registers(string sp_name)
120     {
121         return "
122             size_t eax, ecx, edx, ebx, ebp, esi, edi;
123             asm
124             {
125                 mov eax[EBP], EAX;
126                 mov ecx[EBP], ECX;
127                 mov edx[EBP], EDX;
128                 mov ebx[EBP], EBX;
129                 mov ebp[EBP], EBP;
130                 mov esi[EBP], ESI;
131                 mov edi[EBP], EDI;
132                 mov " ~ sp_name ~ "[EBP],  ESP;
133             }
134         ";
135     }
136
137     string pop_registers(string sp_name)
138     {
139         return "";
140     }
141
142 }
143 else version (X86_64)
144 {
145
146     /*
147      * See X86 comment above, X86_64 uses the same trick.
148      */
149
150     string push_registers(string sp_name)
151     {
152         return "
153             size_t rax, rbx, rcx, rdx, rbp, rsi, rdi,
154                    r10, r11, r12, r13, r14, r15;
155             asm
156             {
157                 movq rax[RBP], RAX;
158                 movq rbx[RBP], RBX;
159                 movq rcx[RBP], RCX;
160                 movq rdx[RBP], RDX;
161                 movq rbp[RBP], RBP;
162                 movq rsi[RBP], RSI;
163                 movq rdi[RBP], RDI;
164                 movq r10[RBP], R10;
165                 movq r11[RBP], R11;
166                 movq r12[RBP], R12;
167                 movq r13[RBP], R13;
168                 movq r14[RBP], R14;
169                 movq r15[RBP], R15;
170                 movq " ~ sp_name ~ "[RBP],  RSP;
171             }
172         ";
173     }
174
175     string pop_registers(string sp_name)
176     {
177         return "";
178     }
179
180 }
181 else // Unknown compiler/architecture
182 {
183
184     static assert(false, "Don't know how to push registers into the stack "
185                          "for this compiler/architecture");
186
187 }
188
189 // vim: set et sw=4 sts=4 :