203 lines
7.3 KiB
C
203 lines
7.3 KiB
C
#ifndef wren_common_h
|
|
#define wren_common_h
|
|
|
|
// This header contains macros and defines used across the entire Wren
|
|
// implementation. In particular, it contains "configuration" defines that
|
|
// control how Wren works. Some of these are only used while hacking on Wren
|
|
// itself.
|
|
//
|
|
// This header is *not* intended to be included by code outside of Wren itself.
|
|
|
|
// Wren pervasively uses the C99 integer types (uint16_t, etc.) along with some
|
|
// of the associated limit constants (UINT32_MAX, etc.). The constants are not
|
|
// part of standard C++, so aren't included by default by C++ compilers when you
|
|
// include <stdint> unless __STDC_LIMIT_MACROS is defined.
|
|
#define __STDC_LIMIT_MACROS
|
|
#include <stdint.h>
|
|
|
|
// These flags let you control some details of the interpreter's implementation.
|
|
// Usually they trade-off a bit of portability for speed. They default to the
|
|
// most efficient behavior.
|
|
|
|
// If true, then Wren uses a NaN-tagged double for its core value
|
|
// representation. Otherwise, it uses a larger more conventional struct. The
|
|
// former is significantly faster and more compact. The latter is useful for
|
|
// debugging and may be more portable.
|
|
//
|
|
// Defaults to on.
|
|
#ifndef WREN_NAN_TAGGING
|
|
#define WREN_NAN_TAGGING 1
|
|
#endif
|
|
|
|
// If true, the VM's interpreter loop uses computed gotos. See this for more:
|
|
// http://gcc.gnu.org/onlinedocs/gcc-3.1.1/gcc/Labels-as-Values.html
|
|
// Enabling this speeds up the main dispatch loop a bit, but requires compiler
|
|
// support.
|
|
//
|
|
// Defaults to true on supported compilers.
|
|
#ifndef WREN_COMPUTED_GOTO
|
|
#ifdef _MSC_VER
|
|
// No computed gotos in Visual Studio.
|
|
#define WREN_COMPUTED_GOTO 0
|
|
#else
|
|
#define WREN_COMPUTED_GOTO 1
|
|
#endif
|
|
#endif
|
|
|
|
// The VM includes a number of optional modules. You can choose to include
|
|
// these or not. By default, they are all available. To disable one, set the
|
|
// corresponding `WREN_OPT_<name>` define to `0`.
|
|
#ifndef WREN_OPT_META
|
|
#define WREN_OPT_META 1
|
|
#endif
|
|
|
|
#ifndef WREN_OPT_RANDOM
|
|
#define WREN_OPT_RANDOM 1
|
|
#endif
|
|
|
|
// These flags are useful for debugging and hacking on Wren itself. They are not
|
|
// intended to be used for production code. They default to off.
|
|
|
|
// Set this to true to stress test the GC. It will perform a collection before
|
|
// every allocation. This is useful to ensure that memory is always correctly
|
|
// reachable.
|
|
#define WREN_DEBUG_GC_STRESS 0
|
|
|
|
// Set this to true to log memory operations as they occur.
|
|
#define WREN_DEBUG_TRACE_MEMORY 0
|
|
|
|
// Set this to true to log garbage collections as they occur.
|
|
#define WREN_DEBUG_TRACE_GC 0
|
|
|
|
// Set this to true to print out the compiled bytecode of each function.
|
|
#define WREN_DEBUG_DUMP_COMPILED_CODE 0
|
|
|
|
// Set this to trace each instruction as it's executed.
|
|
#define WREN_DEBUG_TRACE_INSTRUCTIONS 0
|
|
|
|
// The maximum number of module-level variables that may be defined at one time.
|
|
// This limitation comes from the 16 bits used for the arguments to
|
|
// `CODE_LOAD_MODULE_VAR` and `CODE_STORE_MODULE_VAR`.
|
|
#define MAX_MODULE_VARS 65536
|
|
|
|
// The maximum number of arguments that can be passed to a method. Note that
|
|
// this limitation is hardcoded in other places in the VM, in particular, the
|
|
// `CODE_CALL_XX` instructions assume a certain maximum number.
|
|
#define MAX_PARAMETERS 16
|
|
|
|
// The maximum name of a method, not including the signature. This is an
|
|
// arbitrary but enforced maximum just so we know how long the method name
|
|
// strings need to be in the parser.
|
|
#define MAX_METHOD_NAME 64
|
|
|
|
// The maximum length of a method signature. Signatures look like:
|
|
//
|
|
// foo // Getter.
|
|
// foo() // No-argument method.
|
|
// foo(_) // One-argument method.
|
|
// foo(_,_) // Two-argument method.
|
|
// init foo() // Constructor initializer.
|
|
//
|
|
// The maximum signature length takes into account the longest method name, the
|
|
// maximum number of parameters with separators between them, "init ", and "()".
|
|
#define MAX_METHOD_SIGNATURE (MAX_METHOD_NAME + (MAX_PARAMETERS * 2) + 6)
|
|
|
|
// The maximum length of an identifier. The only real reason for this limitation
|
|
// is so that error messages mentioning variables can be stack allocated.
|
|
#define MAX_VARIABLE_NAME 64
|
|
|
|
// The maximum number of fields a class can have, including inherited fields.
|
|
// This is explicit in the bytecode since `CODE_CLASS` and `CODE_SUBCLASS` take
|
|
// a single byte for the number of fields. Note that it's 255 and not 256
|
|
// because creating a class takes the *number* of fields, not the *highest
|
|
// field index*.
|
|
#define MAX_FIELDS 255
|
|
|
|
// Use the VM's allocator to allocate an object of [type].
|
|
#define ALLOCATE(vm, type) \
|
|
((type*)wrenReallocate(vm, NULL, 0, sizeof(type)))
|
|
|
|
// Use the VM's allocator to allocate an object of [mainType] containing a
|
|
// flexible array of [count] objects of [arrayType].
|
|
#define ALLOCATE_FLEX(vm, mainType, arrayType, count) \
|
|
((mainType*)wrenReallocate(vm, NULL, 0, \
|
|
sizeof(mainType) + sizeof(arrayType) * (count)))
|
|
|
|
// Use the VM's allocator to allocate an array of [count] elements of [type].
|
|
#define ALLOCATE_ARRAY(vm, type, count) \
|
|
((type*)wrenReallocate(vm, NULL, 0, sizeof(type) * (count)))
|
|
|
|
// Use the VM's allocator to free the previously allocated memory at [pointer].
|
|
#define DEALLOCATE(vm, pointer) wrenReallocate(vm, pointer, 0, 0)
|
|
|
|
// The Microsoft compiler does not support the "inline" modifier when compiling
|
|
// as plain C.
|
|
#if defined( _MSC_VER ) && !defined(__cplusplus)
|
|
#define inline _inline
|
|
#endif
|
|
|
|
// This is used to clearly mark flexible-sized arrays that appear at the end of
|
|
// some dynamically-allocated structs, known as the "struct hack".
|
|
#if __STDC_VERSION__ >= 199901L
|
|
// In C99, a flexible array member is just "[]".
|
|
#define FLEXIBLE_ARRAY
|
|
#else
|
|
// Elsewhere, use a zero-sized array. It's technically undefined behavior,
|
|
// but works reliably in most known compilers.
|
|
#define FLEXIBLE_ARRAY 0
|
|
#endif
|
|
|
|
// Assertions are used to validate program invariants. They indicate things the
|
|
// program expects to be true about its internal state during execution. If an
|
|
// assertion fails, there is a bug in Wren.
|
|
//
|
|
// Assertions add significant overhead, so are only enabled in debug builds.
|
|
#ifdef DEBUG
|
|
|
|
#include <stdio.h>
|
|
|
|
#define ASSERT(condition, message) \
|
|
do \
|
|
{ \
|
|
if (!(condition)) \
|
|
{ \
|
|
fprintf(stderr, "[%s:%d] Assert failed in %s(): %s\n", \
|
|
__FILE__, __LINE__, __func__, message); \
|
|
abort(); \
|
|
} \
|
|
} \
|
|
while(0)
|
|
|
|
// Indicates that we know execution should never reach this point in the
|
|
// program. In debug mode, we assert this fact because it's a bug to get here.
|
|
//
|
|
// In release mode, we use compiler-specific built in functions to tell the
|
|
// compiler the code can't be reached. This avoids "missing return" warnings
|
|
// in some cases and also lets it perform some optimizations by assuming the
|
|
// code is never reached.
|
|
#define UNREACHABLE() \
|
|
do \
|
|
{ \
|
|
fprintf(stderr, "[%s:%d] This code should not be reached in %s()\n", \
|
|
__FILE__, __LINE__, __func__); \
|
|
abort(); \
|
|
} \
|
|
while (0)
|
|
|
|
#else
|
|
|
|
#define ASSERT(condition, message) do {} while (0)
|
|
|
|
// Tell the compiler that this part of the code will never be reached.
|
|
#if defined( _MSC_VER )
|
|
#define UNREACHABLE() __assume(0)
|
|
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
|
|
#define UNREACHABLE() __builtin_unreachable()
|
|
#else
|
|
#define UNREACHABLE()
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif
|