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