1 | #ifndef wren_common_h |
2 | #define wren_common_h |
3 | |
4 | // This header contains macros and defines used across the entire Wren |
5 | // implementation. In particular, it contains "configuration" defines that |
6 | // control how Wren works. Some of these are only used while hacking on Wren |
7 | // itself. |
8 | // |
9 | // This header is *not* intended to be included by code outside of Wren itself. |
10 | |
11 | // Wren pervasively uses the C99 integer types (uint16_t, etc.) along with some |
12 | // of the associated limit constants (UINT32_MAX, etc.). The constants are not |
13 | // part of standard C++, so aren't included by default by C++ compilers when you |
14 | // include <stdint> unless __STDC_LIMIT_MACROS is defined. |
15 | #define __STDC_LIMIT_MACROS |
16 | #include <stdint.h> |
17 | |
18 | // These flags let you control some details of the interpreter's implementation. |
19 | // Usually they trade-off a bit of portability for speed. They default to the |
20 | // most efficient behavior. |
21 | |
22 | // If true, then Wren uses a NaN-tagged double for its core value |
23 | // representation. Otherwise, it uses a larger more conventional struct. The |
24 | // former is significantly faster and more compact. The latter is useful for |
25 | // debugging and may be more portable. |
26 | // |
27 | // Defaults to on. |
28 | #ifndef WREN_NAN_TAGGING |
29 | #define WREN_NAN_TAGGING 1 |
30 | #endif |
31 | |
32 | // If true, the VM's interpreter loop uses computed gotos. See this for more: |
33 | // http://gcc.gnu.org/onlinedocs/gcc-3.1.1/gcc/Labels-as-Values.html |
34 | // Enabling this speeds up the main dispatch loop a bit, but requires compiler |
35 | // support. |
36 | // see https://bullno1.com/blog/switched-goto for alternative |
37 | // Defaults to true on supported compilers. |
38 | #ifndef WREN_COMPUTED_GOTO |
39 | #if defined(_MSC_VER) && !defined(__clang__) |
40 | // No computed gotos in Visual Studio. |
41 | #define WREN_COMPUTED_GOTO 0 |
42 | #else |
43 | #define WREN_COMPUTED_GOTO 1 |
44 | #endif |
45 | #endif |
46 | |
47 | // The VM includes a number of optional modules. You can choose to include |
48 | // these or not. By default, they are all available. To disable one, set the |
49 | // corresponding `WREN_OPT_<name>` define to `0`. |
50 | #ifndef WREN_OPT_META |
51 | #define WREN_OPT_META 1 |
52 | #endif |
53 | |
54 | #ifndef WREN_OPT_RANDOM |
55 | #define WREN_OPT_RANDOM 1 |
56 | #endif |
57 | |
58 | // These flags are useful for debugging and hacking on Wren itself. They are not |
59 | // intended to be used for production code. They default to off. |
60 | |
61 | // Set this to true to stress test the GC. It will perform a collection before |
62 | // every allocation. This is useful to ensure that memory is always correctly |
63 | // reachable. |
64 | #define WREN_DEBUG_GC_STRESS 0 |
65 | |
66 | // Set this to true to log memory operations as they occur. |
67 | #define WREN_DEBUG_TRACE_MEMORY 0 |
68 | |
69 | // Set this to true to log garbage collections as they occur. |
70 | #define WREN_DEBUG_TRACE_GC 0 |
71 | |
72 | // Set this to true to print out the compiled bytecode of each function. |
73 | #define WREN_DEBUG_DUMP_COMPILED_CODE 0 |
74 | |
75 | // Set this to trace each instruction as it's executed. |
76 | #define WREN_DEBUG_TRACE_INSTRUCTIONS 0 |
77 | |
78 | // The maximum number of module-level variables that may be defined at one time. |
79 | // This limitation comes from the 16 bits used for the arguments to |
80 | // `CODE_LOAD_MODULE_VAR` and `CODE_STORE_MODULE_VAR`. |
81 | #define MAX_MODULE_VARS 65536 |
82 | |
83 | // The maximum number of arguments that can be passed to a method. Note that |
84 | // this limitation is hardcoded in other places in the VM, in particular, the |
85 | // `CODE_CALL_XX` instructions assume a certain maximum number. |
86 | #define MAX_PARAMETERS 16 |
87 | |
88 | // The maximum name of a method, not including the signature. This is an |
89 | // arbitrary but enforced maximum just so we know how long the method name |
90 | // strings need to be in the parser. |
91 | #define MAX_METHOD_NAME 64 |
92 | |
93 | // The maximum length of a method signature. Signatures look like: |
94 | // |
95 | // foo // Getter. |
96 | // foo() // No-argument method. |
97 | // foo(_) // One-argument method. |
98 | // foo(_,_) // Two-argument method. |
99 | // init foo() // Constructor initializer. |
100 | // |
101 | // The maximum signature length takes into account the longest method name, the |
102 | // maximum number of parameters with separators between them, "init ", and "()". |
103 | #define MAX_METHOD_SIGNATURE (MAX_METHOD_NAME + (MAX_PARAMETERS * 2) + 6) |
104 | |
105 | // The maximum length of an identifier. The only real reason for this limitation |
106 | // is so that error messages mentioning variables can be stack allocated. |
107 | #define MAX_VARIABLE_NAME 64 |
108 | |
109 | // The maximum number of fields a class can have, including inherited fields. |
110 | // This is explicit in the bytecode since `CODE_CLASS` and `CODE_SUBCLASS` take |
111 | // a single byte for the number of fields. Note that it's 255 and not 256 |
112 | // because creating a class takes the *number* of fields, not the *highest |
113 | // field index*. |
114 | #define MAX_FIELDS 255 |
115 | |
116 | // Use the VM's allocator to allocate an object of [type]. |
117 | #define ALLOCATE(vm, type) \ |
118 | ((type*)wrenReallocate(vm, NULL, 0, sizeof(type))) |
119 | |
120 | // Use the VM's allocator to allocate an object of [mainType] containing a |
121 | // flexible array of [count] objects of [arrayType]. |
122 | #define ALLOCATE_FLEX(vm, mainType, arrayType, count) \ |
123 | ((mainType*)wrenReallocate(vm, NULL, 0, \ |
124 | sizeof(mainType) + sizeof(arrayType) * (count))) |
125 | |
126 | // Use the VM's allocator to allocate an array of [count] elements of [type]. |
127 | #define ALLOCATE_ARRAY(vm, type, count) \ |
128 | ((type*)wrenReallocate(vm, NULL, 0, sizeof(type) * (count))) |
129 | |
130 | // Use the VM's allocator to free the previously allocated memory at [pointer]. |
131 | #define DEALLOCATE(vm, pointer) wrenReallocate(vm, pointer, 0, 0) |
132 | |
133 | // The Microsoft compiler does not support the "inline" modifier when compiling |
134 | // as plain C. |
135 | #if defined( _MSC_VER ) && !defined(__cplusplus) |
136 | #define inline _inline |
137 | #endif |
138 | |
139 | // This is used to clearly mark flexible-sized arrays that appear at the end of |
140 | // some dynamically-allocated structs, known as the "struct hack". |
141 | #if __STDC_VERSION__ >= 199901L |
142 | // In C99, a flexible array member is just "[]". |
143 | #define FLEXIBLE_ARRAY |
144 | #else |
145 | // Elsewhere, use a zero-sized array. It's technically undefined behavior, |
146 | // but works reliably in most known compilers. |
147 | #define FLEXIBLE_ARRAY 0 |
148 | #endif |
149 | |
150 | // Assertions are used to validate program invariants. They indicate things the |
151 | // program expects to be true about its internal state during execution. If an |
152 | // assertion fails, there is a bug in Wren. |
153 | // |
154 | // Assertions add significant overhead, so are only enabled in debug builds. |
155 | #ifdef DEBUG |
156 | |
157 | #include <stdio.h> |
158 | |
159 | #define ASSERT(condition, message) \ |
160 | do \ |
161 | { \ |
162 | if (!(condition)) \ |
163 | { \ |
164 | fprintf(stderr, "[%s:%d] Assert failed in %s(): %s\n", \ |
165 | __FILE__, __LINE__, __func__, message); \ |
166 | abort(); \ |
167 | } \ |
168 | } while (false) |
169 | |
170 | // Indicates that we know execution should never reach this point in the |
171 | // program. In debug mode, we assert this fact because it's a bug to get here. |
172 | // |
173 | // In release mode, we use compiler-specific built in functions to tell the |
174 | // compiler the code can't be reached. This avoids "missing return" warnings |
175 | // in some cases and also lets it perform some optimizations by assuming the |
176 | // code is never reached. |
177 | #define UNREACHABLE() \ |
178 | do \ |
179 | { \ |
180 | fprintf(stderr, "[%s:%d] This code should not be reached in %s()\n", \ |
181 | __FILE__, __LINE__, __func__); \ |
182 | abort(); \ |
183 | } while (false) |
184 | |
185 | #else |
186 | |
187 | #define ASSERT(condition, message) do { } while (false) |
188 | |
189 | // Tell the compiler that this part of the code will never be reached. |
190 | #if defined( _MSC_VER ) |
191 | #define UNREACHABLE() __assume(0) |
192 | #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) |
193 | #define UNREACHABLE() __builtin_unreachable() |
194 | #else |
195 | #define UNREACHABLE() |
196 | #endif |
197 | |
198 | #endif |
199 | |
200 | #endif |
201 | |